mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
3 Commits
gdb-17-bra
...
users/amer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ae1349aac | ||
|
|
af1c8a8d9a | ||
|
|
0f5116cb49 |
@@ -307,16 +307,23 @@ cli_ui_out::do_progress_notify (const std::string &msg,
|
||||
|
||||
if (info.state == progress_update::START)
|
||||
{
|
||||
std::string prefix;
|
||||
if (cur_prefix_state == prefix_state_t::NEWLINE_NEEDED)
|
||||
{
|
||||
prefix = "\n";
|
||||
cur_prefix_state = prefix_state_t::NEWLINE_PRINTED;
|
||||
}
|
||||
|
||||
if (stream->isatty ()
|
||||
&& current_ui->input_interactive_p ()
|
||||
&& chars_per_line >= MIN_CHARS_PER_LINE)
|
||||
{
|
||||
gdb_printf (stream, "%s\n", msg.c_str ());
|
||||
gdb_printf (stream, "%s\n", (prefix + msg).c_str ());
|
||||
info.state = progress_update::BAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdb_printf (stream, "%s...\n", msg.c_str ());
|
||||
gdb_printf (stream, "%s...\n", (prefix + msg).c_str ());
|
||||
info.state = progress_update::WORKING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1362,6 +1362,10 @@ complete_line_internal_1 (completion_tracker &tracker,
|
||||
{
|
||||
/* We've recognized a full command. */
|
||||
|
||||
/* Disable pagination since responding to the pagination prompt
|
||||
overwrites rl_line_buffer. */
|
||||
scoped_restore pag_restore = make_scoped_restore (&pagination_enabled, false);
|
||||
|
||||
if (p == tmp_command + point)
|
||||
{
|
||||
/* There is no non-whitespace in the line beyond the
|
||||
@@ -1461,7 +1465,8 @@ complete_line_internal_1 (completion_tracker &tracker,
|
||||
}
|
||||
|
||||
/* Wrapper around complete_line_internal_1 to handle
|
||||
MAX_COMPLETIONS_REACHED_ERROR. */
|
||||
MAX_COMPLETIONS_REACHED_ERROR and possible progress update
|
||||
interactions. */
|
||||
|
||||
static void
|
||||
complete_line_internal (completion_tracker &tracker,
|
||||
@@ -1469,6 +1474,11 @@ complete_line_internal (completion_tracker &tracker,
|
||||
const char *line_buffer, int point,
|
||||
complete_line_internal_reason reason)
|
||||
{
|
||||
scoped_restore restore_prefix_state
|
||||
= make_scoped_restore
|
||||
(&cur_prefix_state,
|
||||
ui_out::progress_update::prefix_state::NEWLINE_NEEDED);
|
||||
|
||||
try
|
||||
{
|
||||
complete_line_internal_1 (tracker, text, line_buffer, point, reason);
|
||||
@@ -1478,6 +1488,12 @@ complete_line_internal (completion_tracker &tracker,
|
||||
if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
|
||||
throw;
|
||||
}
|
||||
|
||||
/* If progress update messages printed, then the text being completed
|
||||
needs to be printed again. */
|
||||
if (cur_prefix_state
|
||||
== ui_out::progress_update::prefix_state::NEWLINE_PRINTED)
|
||||
rl_forced_update_display ();
|
||||
}
|
||||
|
||||
/* See completer.h. */
|
||||
|
||||
@@ -1622,6 +1622,19 @@ set_comp_unit (struct objfile *objfile, struct comp_unit *unit)
|
||||
return dwarf2_frame_bfd_data.set (abfd, unit);
|
||||
}
|
||||
|
||||
/* See frame.h. */
|
||||
|
||||
void
|
||||
dwarf2_clear_frame_data (struct objfile *objfile)
|
||||
{
|
||||
bfd *abfd = objfile->obfd.get ();
|
||||
|
||||
if (gdb_bfd_requires_relocations (abfd))
|
||||
dwarf2_frame_objfile_data.clear (objfile);
|
||||
else
|
||||
dwarf2_frame_bfd_data.clear (abfd);
|
||||
}
|
||||
|
||||
/* Find the FDE for *PC. Return a pointer to the FDE, and store the
|
||||
initial location associated with it into *PC. */
|
||||
|
||||
|
||||
@@ -237,6 +237,10 @@ void dwarf2_append_unwinders (struct gdbarch *gdbarch);
|
||||
extern const struct frame_base *
|
||||
dwarf2_frame_base_sniffer (const frame_info_ptr &this_frame);
|
||||
|
||||
/* Delete OBJFILEs comp_unit. */
|
||||
|
||||
extern void dwarf2_clear_frame_data (struct objfile * objfile);
|
||||
|
||||
/* Compute the DWARF CFA for a frame. */
|
||||
|
||||
CORE_ADDR dwarf2_frame_cfa (const frame_info_ptr &this_frame);
|
||||
|
||||
@@ -245,6 +245,33 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
|
||||
return {};
|
||||
}
|
||||
|
||||
/* See index-cache.h. */
|
||||
|
||||
gdb::array_view<const gdb_byte>
|
||||
index_cache::lookup_gdb_index_debuginfod (const char *index_path,
|
||||
std::unique_ptr<index_cache_resource> *resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Try to map that file. */
|
||||
index_cache_resource_mmap *mmap_resource
|
||||
= new index_cache_resource_mmap (index_path);
|
||||
|
||||
/* Hand the resource to the caller. */
|
||||
resource->reset (mmap_resource);
|
||||
|
||||
return gdb::array_view<const gdb_byte>
|
||||
((const gdb_byte *) mmap_resource->mapping.get (),
|
||||
mmap_resource->mapping.size ());
|
||||
}
|
||||
catch (const gdb_exception_error &except)
|
||||
{
|
||||
warning (_("Unable to read %s: %s"), index_path, except.what ());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#else /* !HAVE_SYS_MMAN_H */
|
||||
|
||||
/* See dwarf-index-cache.h. This is a no-op on unsupported systems. */
|
||||
@@ -256,6 +283,12 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
|
||||
return {};
|
||||
}
|
||||
|
||||
gdb::array_view<const gdb_byte>
|
||||
index_cache::lookup_gdb_index_debuginfod (const char *index_path,
|
||||
std::unique_ptr<index_cache_resource> *resource)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See dwarf-index-cache.h. */
|
||||
|
||||
@@ -93,6 +93,19 @@ public:
|
||||
lookup_gdb_index (const bfd_build_id *build_id,
|
||||
std::unique_ptr<index_cache_resource> *resource);
|
||||
|
||||
/* Look for an index file located at INDEX_PATH in the debuginfod cache.
|
||||
Unlike lookup_gdb_index, this function does not exit early if the
|
||||
index cache has not been enabled.
|
||||
|
||||
If found, return the contents as an array_view and store the underlying
|
||||
resources (allocated memory, mapped file, etc) in RESOURCE. The returned
|
||||
array_view is valid as long as RESOURCE is not destroyed.
|
||||
|
||||
If no matching index file is found, return an empty array view. */
|
||||
gdb::array_view<const gdb_byte>
|
||||
lookup_gdb_index_debuginfod (const char *index_path,
|
||||
std::unique_ptr<index_cache_resource> *resource);
|
||||
|
||||
/* Return the number of cache hits. */
|
||||
unsigned int n_hits () const
|
||||
{ return m_n_hits; }
|
||||
|
||||
@@ -102,12 +102,15 @@ read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf,
|
||||
{
|
||||
LONGEST length = read_initial_length (abfd, buf, bytes_read);
|
||||
|
||||
gdb_assert (cu_header->initial_length_size == 4
|
||||
|| cu_header->initial_length_size == 8
|
||||
|| cu_header->initial_length_size == 12);
|
||||
if (cu_header != nullptr)
|
||||
{
|
||||
gdb_assert (cu_header->initial_length_size == 4
|
||||
|| cu_header->initial_length_size == 8
|
||||
|| cu_header->initial_length_size == 12);
|
||||
|
||||
if (cu_header->initial_length_size != *bytes_read)
|
||||
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
||||
if (cu_header->initial_length_size != *bytes_read)
|
||||
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
||||
}
|
||||
|
||||
*offset_size = (*bytes_read == 4) ? 4 : 8;
|
||||
return length;
|
||||
@@ -116,21 +119,27 @@ read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf,
|
||||
/* Read directory or file name entry format, starting with byte of
|
||||
format count entries, ULEB128 pairs of entry formats, ULEB128 of
|
||||
entries count and the entries themselves in the described entry
|
||||
format. */
|
||||
format.
|
||||
|
||||
.debug_line and .debug_line_str sections are stored in LINE_BUFP
|
||||
and LINE_STR_DATA respectively. */
|
||||
|
||||
static void
|
||||
read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
const gdb_byte **bufp, struct line_header *lh,
|
||||
unsigned int offset_size,
|
||||
void (*callback) (struct line_header *lh,
|
||||
const char *name,
|
||||
dir_index d_index,
|
||||
unsigned int mod_time,
|
||||
unsigned int length))
|
||||
read_formatted_entries
|
||||
(bfd *abfd, const gdb_byte **line_bufp,
|
||||
const gdb::array_view<const gdb_byte> line_str_data,
|
||||
struct line_header *lh,
|
||||
unsigned int offset_size,
|
||||
void (*callback) (struct line_header *lh,
|
||||
const char *name,
|
||||
dir_index d_index,
|
||||
unsigned int mod_time,
|
||||
unsigned int length))
|
||||
{
|
||||
gdb_byte format_count, formati;
|
||||
ULONGEST data_count, datai;
|
||||
const gdb_byte *buf = *bufp;
|
||||
const gdb_byte *buf = *line_bufp;
|
||||
const gdb_byte *str_buf = line_str_data.data ();
|
||||
const gdb_byte *format_header_data;
|
||||
unsigned int bytes_read;
|
||||
|
||||
@@ -157,7 +166,7 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
|
||||
format += bytes_read;
|
||||
|
||||
ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
|
||||
ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
|
||||
format += bytes_read;
|
||||
|
||||
std::optional<const char *> string;
|
||||
@@ -172,12 +181,24 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
|
||||
case DW_FORM_line_strp:
|
||||
{
|
||||
const char *str
|
||||
= per_objfile->read_line_string (buf, offset_size);
|
||||
if (line_str_data.empty ())
|
||||
warning (_("Dwarf Error: DW_FORM_line_strp used without " \
|
||||
"required section"));
|
||||
|
||||
if (line_str_data.size () <= offset_size)
|
||||
warning (_("Dwarf Error: DW_FORM_line_strp pointing outside " \
|
||||
"of section .debug_line_str"));
|
||||
|
||||
ULONGEST str_offset = read_offset (abfd, buf, offset_size);
|
||||
const char *str;
|
||||
if (str_buf[str_offset] == '\0')
|
||||
str = nullptr;
|
||||
else
|
||||
str = (const char *) (str_buf + str_offset);
|
||||
string.emplace (str);
|
||||
buf += offset_size;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_FORM_data1:
|
||||
uint.emplace (read_1_byte (abfd, buf));
|
||||
@@ -248,28 +269,30 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
*line_bufp = buf;
|
||||
}
|
||||
|
||||
/* See line-header.h. */
|
||||
|
||||
line_header_up
|
||||
dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
struct dwarf2_section_info *section,
|
||||
const struct comp_unit_head *cu_header,
|
||||
const char *comp_dir)
|
||||
dwarf_decode_line_header (bfd *abfd,
|
||||
gdb::array_view<const gdb_byte> line_data,
|
||||
gdb::array_view<const gdb_byte> line_str_data,
|
||||
const gdb_byte **debug_line_ptr,
|
||||
bool is_dwz,
|
||||
const struct comp_unit_head *cu_header,
|
||||
const char *comp_dir)
|
||||
{
|
||||
const gdb_byte *line_ptr;
|
||||
const gdb_byte *line_ptr, *buf;
|
||||
unsigned int bytes_read, offset_size;
|
||||
int i;
|
||||
const char *cur_dir, *cur_file;
|
||||
|
||||
bfd *abfd = section->get_bfd_owner ();
|
||||
buf = *debug_line_ptr;
|
||||
|
||||
/* Make sure that at least there's room for the total_length field.
|
||||
That could be 12 bytes long, but we're just going to fudge that. */
|
||||
if (to_underlying (sect_off) + 4 >= section->size)
|
||||
if (buf + 4 >= line_data.data () + line_data.size ())
|
||||
{
|
||||
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
||||
return 0;
|
||||
@@ -277,24 +300,26 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
|
||||
line_header_up lh (new line_header (comp_dir));
|
||||
|
||||
lh->sect_off = sect_off;
|
||||
lh->sect_off = (sect_offset) (buf - line_data.data ());
|
||||
lh->offset_in_dwz = is_dwz;
|
||||
|
||||
line_ptr = section->buffer + to_underlying (sect_off);
|
||||
line_ptr = buf;
|
||||
|
||||
/* Read in the header. */
|
||||
LONGEST unit_length
|
||||
= read_checked_initial_length_and_offset (abfd, line_ptr, cu_header,
|
||||
= read_checked_initial_length_and_offset (abfd, buf, cu_header,
|
||||
&bytes_read, &offset_size);
|
||||
|
||||
line_ptr += bytes_read;
|
||||
|
||||
const gdb_byte *start_here = line_ptr;
|
||||
|
||||
if (line_ptr + unit_length > (section->buffer + section->size))
|
||||
if (line_ptr + unit_length > buf + line_data.size ())
|
||||
{
|
||||
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const gdb_byte *start_here = line_ptr;
|
||||
|
||||
lh->statement_program_end = start_here + unit_length;
|
||||
lh->version = read_2_bytes (abfd, line_ptr);
|
||||
line_ptr += 2;
|
||||
@@ -303,7 +328,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
/* This is a version we don't understand. The format could have
|
||||
changed in ways we don't handle properly so just punt. */
|
||||
complaint (_("unsupported version in .debug_line section"));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (lh->version >= 5)
|
||||
{
|
||||
@@ -320,13 +345,14 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
complaint (_("unsupported segment selector size %u "
|
||||
"in .debug_line section"),
|
||||
segment_selector_size);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LONGEST header_length = read_offset (abfd, line_ptr, offset_size);
|
||||
line_ptr += offset_size;
|
||||
lh->statement_program_start = line_ptr + header_length;
|
||||
|
||||
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
@@ -347,12 +373,16 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
|
||||
lh->default_is_stmt = read_1_byte (abfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
lh->line_base = read_1_signed_byte (abfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
lh->line_range = read_1_byte (abfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
lh->opcode_base = read_1_byte (abfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
lh->standard_opcode_lengths.reset (new unsigned char[lh->opcode_base]);
|
||||
|
||||
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
|
||||
@@ -365,21 +395,23 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
if (lh->version >= 5)
|
||||
{
|
||||
/* Read directory table. */
|
||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
||||
offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
read_formatted_entries
|
||||
(abfd, &line_ptr, line_str_data,
|
||||
lh.get (), offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
{
|
||||
header->add_include_dir (name);
|
||||
});
|
||||
|
||||
/* Read file name table. */
|
||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
||||
offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
read_formatted_entries
|
||||
(abfd, &line_ptr, line_str_data,
|
||||
lh.get (), offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
{
|
||||
header->add_file_name (name, d_index, mod_time, length);
|
||||
});
|
||||
@@ -387,7 +419,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
else
|
||||
{
|
||||
/* Read directory table. */
|
||||
while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
|
||||
while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != nullptr)
|
||||
{
|
||||
line_ptr += bytes_read;
|
||||
lh->add_include_dir (cur_dir);
|
||||
@@ -395,7 +427,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
line_ptr += bytes_read;
|
||||
|
||||
/* Read file name table. */
|
||||
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
|
||||
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != nullptr)
|
||||
{
|
||||
unsigned int mod_time, length;
|
||||
dir_index d_index;
|
||||
@@ -413,9 +445,40 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
line_ptr += bytes_read;
|
||||
}
|
||||
|
||||
if (line_ptr > (section->buffer + section->size))
|
||||
if (line_ptr > (buf + line_data.size ()))
|
||||
complaint (_("line number info header doesn't "
|
||||
"fit in `.debug_line' section"));
|
||||
|
||||
*debug_line_ptr += unit_length + offset_size;
|
||||
return lh;
|
||||
}
|
||||
|
||||
line_header_up
|
||||
dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
struct dwarf2_section_info *section,
|
||||
const struct comp_unit_head *cu_header,
|
||||
const char *comp_dir)
|
||||
{
|
||||
struct objfile *objfile = per_objfile->objfile;
|
||||
struct dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
||||
|
||||
/* Read .debug_line. */
|
||||
dwarf2_section_info *line_sec = &per_bfd->line;
|
||||
bfd_size_type line_size = line_sec->get_size (objfile);
|
||||
|
||||
gdb::array_view<const gdb_byte> line (line_sec->buffer, line_size);
|
||||
|
||||
/* Read .debug_line_str. */
|
||||
dwarf2_section_info *line_str_sec = &per_bfd->line_str;
|
||||
bfd_size_type line_str_size = line_str_sec->get_size (objfile);
|
||||
|
||||
gdb::array_view<const gdb_byte> line_str (line_str_sec->buffer,
|
||||
line_str_size);
|
||||
|
||||
const gdb_byte *line_ptr = line.data () + to_underlying (sect_off);
|
||||
|
||||
return dwarf_decode_line_header
|
||||
(per_bfd->obfd, line, line_str, &line_ptr,
|
||||
is_dwz, cu_header, comp_dir);
|
||||
}
|
||||
|
||||
@@ -217,4 +217,14 @@ extern line_header_up dwarf_decode_line_header
|
||||
struct dwarf2_section_info *section, const struct comp_unit_head *cu_header,
|
||||
const char *comp_dir);
|
||||
|
||||
/* Like above but the .debug_line and .debug_line_str are stored in
|
||||
LINE_DATA and LINE_STR_DATA. *DEBUG_LINE_PTR should point to a
|
||||
statement program header within LINE_DATA. */
|
||||
|
||||
extern line_header_up dwarf_decode_line_header
|
||||
(bfd *abfd, gdb::array_view<const gdb_byte> line_data,
|
||||
gdb::array_view<const gdb_byte> line_str_data,
|
||||
const gdb_byte **debug_line_ptr, bool is_dwz,
|
||||
const comp_unit_head *cu_header, const char *comp_dir);
|
||||
|
||||
#endif /* DWARF2_LINE_HEADER_H */
|
||||
|
||||
@@ -44,4 +44,11 @@ extern bool dwarf2_initialize_objfile
|
||||
|
||||
extern void dwarf2_build_frame_info (struct objfile *);
|
||||
|
||||
/* Query debuginfod for the .gdb_index associated with OBJFILE. If
|
||||
successful, create an objfile to hold the .gdb_index information
|
||||
and act as a placeholder until the full debuginfo needs to be
|
||||
downloaded. */
|
||||
|
||||
extern bool dwarf2_has_separate_index (struct objfile *);
|
||||
|
||||
#endif /* DWARF2_PUBLIC_H */
|
||||
|
||||
@@ -131,6 +131,9 @@ struct mapped_gdb_index final : public mapped_index_base
|
||||
}
|
||||
};
|
||||
|
||||
struct mapped_debug_line;
|
||||
typedef std::unique_ptr<mapped_debug_line> mapped_debug_line_up;
|
||||
|
||||
struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
||||
{
|
||||
/* This dumps minimal information about the index.
|
||||
@@ -139,6 +142,8 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
||||
gdb.dwarf2/gdb-index.exp testcase. */
|
||||
void dump (struct objfile *objfile) override;
|
||||
|
||||
/* Calls do_expand_symtabs_matching and triggers debuginfo downloading
|
||||
if necessary. */
|
||||
bool expand_symtabs_matching
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||
@@ -147,8 +152,101 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
||||
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
||||
block_search_flags search_flags,
|
||||
domain_search_flags domain) override;
|
||||
|
||||
/* Expand symtabs matching a given symbol or file. */
|
||||
bool do_expand_symtabs_matching
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||
const lookup_name_info *lookup_name,
|
||||
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
||||
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
||||
block_search_flags search_flags,
|
||||
domain_search_flags domain);
|
||||
|
||||
/* If OBJFILE's debuginfo download has been deferred, use a mapped_debug_line
|
||||
to generate filenames.
|
||||
|
||||
Otherwise call dwarf2_base_index_functions::map_symbol_filenames. */
|
||||
|
||||
void map_symbol_filenames (struct objfile *objfile,
|
||||
gdb::function_view<symbol_filename_ftype> fun,
|
||||
bool need_fullname) override;
|
||||
|
||||
/* Calls dwarf2_base_index_functions::expand_all_symtabs and downloads
|
||||
debuginfo if necessary. */
|
||||
void expand_all_symtabs (struct objfile *objfile) override;
|
||||
|
||||
/* Calls dwarf2_base_index_functions::find_last_source_symtab and downloads
|
||||
debuginfo if necessary. */
|
||||
struct symtab *find_last_source_symtab (struct objfile *objfile) override;
|
||||
|
||||
/* Filename information related to this .gdb_index. */
|
||||
mapped_debug_line_up mdl;
|
||||
|
||||
/* Return true if any of the filenames in this .gdb_index's .debug_line
|
||||
mapping match FILE_MATCHER. Initializes the mapping if necessary. */
|
||||
bool filename_in_debug_line
|
||||
(objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher);
|
||||
};
|
||||
|
||||
void
|
||||
dwarf2_gdb_index::expand_all_symtabs (struct objfile *objfile)
|
||||
{
|
||||
try
|
||||
{
|
||||
dwarf2_base_index_functions::expand_all_symtabs (objfile);
|
||||
}
|
||||
catch (const gdb_exception &e)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
exception_print (gdb_stderr, e);
|
||||
else
|
||||
read_full_dwarf_from_debuginfod (objfile, this);
|
||||
}
|
||||
}
|
||||
|
||||
struct symtab *
|
||||
dwarf2_gdb_index::find_last_source_symtab (struct objfile *objfile)
|
||||
{
|
||||
try
|
||||
{
|
||||
return dwarf2_base_index_functions::find_last_source_symtab (objfile);
|
||||
}
|
||||
catch (const gdb_exception &e)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
exception_print (gdb_stderr, e);
|
||||
else
|
||||
read_full_dwarf_from_debuginfod (objfile, this);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_gdb_index::map_symbol_filenames
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<symbol_filename_ftype> fun,
|
||||
bool need_fullname)
|
||||
{
|
||||
try
|
||||
{
|
||||
dwarf2_base_index_functions::map_symbol_filenames (objfile, fun,
|
||||
need_fullname);
|
||||
}
|
||||
catch (const gdb_exception &e)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
exception_print (gdb_stderr, e);
|
||||
else
|
||||
{
|
||||
if (mdl == nullptr)
|
||||
mdl.reset (new mapped_debug_line (objfile));
|
||||
mdl->map_filenames (fun, need_fullname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This dumps minimal information about the index.
|
||||
It is called via "mt print objfiles".
|
||||
One use is to verify .gdb_index has been loaded by the
|
||||
@@ -264,7 +362,7 @@ dw2_expand_marked_cus
|
||||
}
|
||||
|
||||
bool
|
||||
dwarf2_gdb_index::expand_symtabs_matching
|
||||
dwarf2_gdb_index::do_expand_symtabs_matching
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||
const lookup_name_info *lookup_name,
|
||||
@@ -312,6 +410,53 @@ dwarf2_gdb_index::expand_symtabs_matching
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
dwarf2_gdb_index::filename_in_debug_line
|
||||
(objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||
{
|
||||
if (mdl == nullptr)
|
||||
mdl.reset (new mapped_debug_line (objfile));
|
||||
|
||||
return mdl->contains_matching_filename (file_matcher);
|
||||
}
|
||||
|
||||
bool
|
||||
dwarf2_gdb_index::expand_symtabs_matching
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||
const lookup_name_info *lookup_name,
|
||||
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
||||
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
||||
block_search_flags search_flags,
|
||||
domain_search_flags domain)
|
||||
{
|
||||
if ((objfile->flags & OBJF_READNEVER) != 0)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
return do_expand_symtabs_matching (objfile, file_matcher, lookup_name,
|
||||
symbol_matcher, expansion_notify,
|
||||
search_flags, domain);
|
||||
}
|
||||
catch (const gdb_exception &e)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
{
|
||||
exception_print (gdb_stderr, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_matcher != nullptr
|
||||
&& !filename_in_debug_line (objfile, file_matcher))
|
||||
return true;
|
||||
|
||||
read_full_dwarf_from_debuginfod (objfile, this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
quick_symbol_functions_up
|
||||
mapped_gdb_index::make_quick_functions () const
|
||||
{
|
||||
@@ -647,28 +792,32 @@ dwarf2_read_gdb_index
|
||||
|
||||
/* If there is a .dwz file, read it so we can get its CU list as
|
||||
well. */
|
||||
dwz = dwarf2_get_dwz_file (per_bfd);
|
||||
if (dwz != NULL)
|
||||
if (get_gdb_index_contents_dwz != nullptr)
|
||||
{
|
||||
mapped_gdb_index dwz_map;
|
||||
const gdb_byte *dwz_types_ignore;
|
||||
offset_type dwz_types_elements_ignore;
|
||||
dwz = dwarf2_get_dwz_file (per_bfd);
|
||||
|
||||
gdb::array_view<const gdb_byte> dwz_index_content
|
||||
= get_gdb_index_contents_dwz (objfile, dwz);
|
||||
|
||||
if (dwz_index_content.empty ())
|
||||
return 0;
|
||||
|
||||
if (!read_gdb_index_from_buffer (bfd_get_filename (dwz->dwz_bfd.get ()),
|
||||
1, dwz_index_content, &dwz_map,
|
||||
&dwz_list, &dwz_list_elements,
|
||||
&dwz_types_ignore,
|
||||
&dwz_types_elements_ignore))
|
||||
if (dwz != nullptr)
|
||||
{
|
||||
warning (_("could not read '.gdb_index' section from %s; skipping"),
|
||||
bfd_get_filename (dwz->dwz_bfd.get ()));
|
||||
return 0;
|
||||
gdb::array_view<const gdb_byte> dwz_index_content
|
||||
= get_gdb_index_contents_dwz (objfile, dwz);
|
||||
|
||||
if (dwz_index_content.empty ())
|
||||
return 0;
|
||||
|
||||
if (!read_gdb_index_from_buffer (bfd_get_filename
|
||||
(dwz->dwz_bfd.get ()),
|
||||
1, dwz_index_content, &dwz_map,
|
||||
&dwz_list, &dwz_list_elements,
|
||||
&dwz_types_ignore,
|
||||
&dwz_types_elements_ignore))
|
||||
{
|
||||
warning (_("could not read '.gdb_index' section from %s; skipping"),
|
||||
bfd_get_filename (dwz->dwz_bfd.get ()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "dwarf2/attribute.h"
|
||||
#include "dwarf2/comp-unit-head.h"
|
||||
#include "dwarf2/cu.h"
|
||||
#include "dwarf2/frame.h"
|
||||
#include "dwarf2/index-cache.h"
|
||||
#include "dwarf2/index-common.h"
|
||||
#include "dwarf2/leb.h"
|
||||
@@ -80,6 +81,7 @@
|
||||
#include <optional>
|
||||
#include "gdbsupport/underlying.h"
|
||||
#include "gdbsupport/hash_enum.h"
|
||||
#include "gdbsupport/scoped_mmap.h"
|
||||
#include "filename-seen-cache.h"
|
||||
#include "producer.h"
|
||||
#include <fcntl.h>
|
||||
@@ -95,6 +97,8 @@
|
||||
#include "split-name.h"
|
||||
#include "gdbsupport/thread-pool.h"
|
||||
#include "run-on-main-thread.h"
|
||||
#include "inferior.h"
|
||||
#include "debuginfod-support.h"
|
||||
|
||||
/* When == 1, print basic high level tracing messages.
|
||||
When > 1, be more verbose.
|
||||
@@ -1960,6 +1964,213 @@ dw2_get_file_names (dwarf2_per_cu_data *this_cu,
|
||||
return this_cu->file_names;
|
||||
}
|
||||
|
||||
#if !HAVE_SYS_MMAN_H
|
||||
|
||||
bool
|
||||
mapped_debug_line::contains_matching_filename
|
||||
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
gdb::array_view<const gdb_byte>
|
||||
mapped_debug_line::read_debug_line_separate
|
||||
(const char *filename, std::unique_ptr<index_cache_resource> *resource)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
mapped_debug_line::read_debug_line_from_debuginfod (objfile *objfile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
mapped_debug_line::map_filenames
|
||||
(gdb::function_view<symbol_filename_ftype> fun,
|
||||
bool need_fullname)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#else /* !HAVE_SYS_MMAN_H */
|
||||
|
||||
struct line_resource_mmap final : public index_cache_resource
|
||||
{
|
||||
/* Try to mmap FILENAME. Throw an exception on failure, including if the
|
||||
file doesn't exist. */
|
||||
line_resource_mmap (const char *filename)
|
||||
: mapping (mmap_file (filename))
|
||||
{}
|
||||
|
||||
scoped_mmap mapping;
|
||||
};
|
||||
|
||||
/* See read.h. */
|
||||
|
||||
bool
|
||||
mapped_debug_line::contains_matching_filename
|
||||
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||
{
|
||||
for (line_header_up &lh : line_headers)
|
||||
for (file_entry &fe : lh->file_names ())
|
||||
{
|
||||
const char *filename = fe.name;
|
||||
|
||||
if (file_matcher (fe.name, false))
|
||||
return true;
|
||||
|
||||
bool basename_match = file_matcher (lbasename (fe.name), true);
|
||||
|
||||
if (!basenames_may_differ && !basename_match)
|
||||
continue;
|
||||
|
||||
/* DW_AT_comp_dir is not explicitly mentioned in the .debug_line
|
||||
until DWARF5. Since we don't have access to the CU at this
|
||||
point we just check for a partial match on the filename.
|
||||
If there is a match, the full debuginfo will be downloaded
|
||||
ane the match will be re-evalute with DW_AT_comp_dir. */
|
||||
if (lh->version < 5 && fe.d_index == 0)
|
||||
return basename_match;
|
||||
|
||||
const char *dirname = fe.include_dir (&*lh);
|
||||
std::string fullname;
|
||||
|
||||
if (dirname == nullptr || IS_ABSOLUTE_PATH (filename))
|
||||
fullname = filename;
|
||||
else
|
||||
fullname = std::string (dirname) + SLASH_STRING + filename;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> rewritten
|
||||
= rewrite_source_path (fullname.c_str ());
|
||||
if (rewritten != nullptr)
|
||||
fullname = rewritten.release ();
|
||||
|
||||
if (file_matcher (fullname.c_str (), false))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* See read.h. */
|
||||
|
||||
void
|
||||
mapped_debug_line::map_filenames
|
||||
(gdb::function_view<symbol_filename_ftype> fun,
|
||||
bool need_fullname)
|
||||
{
|
||||
for (line_header_up &lh : line_headers)
|
||||
for (file_entry &fe : lh->file_names ())
|
||||
{
|
||||
const char *filename = fe.name;
|
||||
|
||||
if (!need_fullname)
|
||||
{
|
||||
fun (filename, nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *dirname = fe.include_dir (&*lh);
|
||||
std::string fullname;
|
||||
|
||||
if (dirname == nullptr || IS_ABSOLUTE_PATH (filename))
|
||||
fullname = filename;
|
||||
else
|
||||
fullname = std::string (dirname) + SLASH_STRING + filename;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> rewritten
|
||||
= rewrite_source_path (fullname.c_str ());
|
||||
if (rewritten != nullptr)
|
||||
fullname = rewritten.release ();
|
||||
|
||||
fun (filename, fullname.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
/* See read.h. */
|
||||
|
||||
gdb::array_view<const gdb_byte>
|
||||
mapped_debug_line::read_debug_line_separate
|
||||
(const char *filename, std::unique_ptr<index_cache_resource> *resource)
|
||||
{
|
||||
if (filename == nullptr)
|
||||
return {};
|
||||
|
||||
try
|
||||
{
|
||||
line_resource_mmap *mmap_resource
|
||||
= new line_resource_mmap (filename);
|
||||
|
||||
resource->reset (mmap_resource);
|
||||
|
||||
return gdb::array_view<const gdb_byte>
|
||||
((const gdb_byte *) mmap_resource->mapping.get (),
|
||||
mmap_resource->mapping.size ());
|
||||
}
|
||||
catch (const gdb_exception &except)
|
||||
{
|
||||
exception_print (gdb_stderr, except);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/* See read.h. */
|
||||
|
||||
bool
|
||||
mapped_debug_line::read_debug_line_from_debuginfod (objfile *objfile)
|
||||
{
|
||||
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||
if (build_id == nullptr)
|
||||
return false;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> line_path;
|
||||
scoped_fd line_fd = debuginfod_section_query (build_id->data,
|
||||
build_id->size,
|
||||
bfd_get_filename
|
||||
(objfile->obfd.get ()),
|
||||
".debug_line",
|
||||
&line_path);
|
||||
|
||||
if (line_fd.get () < 0)
|
||||
return false;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> line_str_path;
|
||||
scoped_fd line_str_fd = debuginfod_section_query (build_id->data,
|
||||
build_id->size,
|
||||
bfd_get_filename
|
||||
(objfile->obfd.get ()),
|
||||
".debug_line_str",
|
||||
&line_str_path);
|
||||
|
||||
line_data = read_debug_line_separate (line_path.get (), &line_resource);
|
||||
line_str_data = read_debug_line_separate (line_str_path.get (),
|
||||
&line_str_resource);
|
||||
|
||||
const gdb_byte *line_ptr = line_data.data ();
|
||||
|
||||
while (line_ptr < line_data.data () + line_data.size ())
|
||||
{
|
||||
line_header_up lh
|
||||
= dwarf_decode_line_header (objfile->obfd.get (),
|
||||
line_data, line_str_data,
|
||||
&line_ptr, false,
|
||||
nullptr, nullptr);
|
||||
line_headers.emplace_back (std::move (lh));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* !HAVE_SYS_MMAN_H */
|
||||
|
||||
mapped_debug_line::mapped_debug_line (objfile *objfile)
|
||||
{
|
||||
if (!read_debug_line_from_debuginfod (objfile))
|
||||
line_headers.clear ();
|
||||
}
|
||||
|
||||
/* A helper for the "quick" functions which computes and caches the
|
||||
real path for a given file name from the line table. */
|
||||
|
||||
@@ -3016,7 +3227,7 @@ dwarf2_base_index_functions::find_per_cu (dwarf2_per_bfd *per_bfd,
|
||||
}
|
||||
|
||||
struct compunit_symtab *
|
||||
dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||
dwarf2_base_index_functions::do_find_pc_sect_compunit_symtab
|
||||
(struct objfile *objfile,
|
||||
struct bound_minimal_symbol msymbol,
|
||||
CORE_ADDR pc,
|
||||
@@ -3047,6 +3258,32 @@ dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||
return result;
|
||||
}
|
||||
|
||||
struct compunit_symtab *
|
||||
dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||
(struct objfile *objfile,
|
||||
struct bound_minimal_symbol msymbol,
|
||||
CORE_ADDR pc,
|
||||
struct obj_section *section,
|
||||
int warn_if_readin)
|
||||
{
|
||||
if ((objfile->flags & OBJF_READNEVER) != 0)
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
return do_find_pc_sect_compunit_symtab (objfile, msymbol, pc,
|
||||
section, warn_if_readin);
|
||||
}
|
||||
catch (const gdb_exception &e)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
exception_print (gdb_stderr, e);
|
||||
else
|
||||
read_full_dwarf_from_debuginfod (objfile, this);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_base_index_functions::map_symbol_filenames
|
||||
(struct objfile *objfile,
|
||||
@@ -3203,6 +3440,30 @@ get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz)
|
||||
return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res);
|
||||
}
|
||||
|
||||
/* Query debuginfod for the .gdb_index matching OBJFILE's build-id. Return the
|
||||
contents if successful. */
|
||||
|
||||
static gdb::array_view<const gdb_byte>
|
||||
get_gdb_index_contents_from_debuginfod (objfile *objfile, dwarf2_per_bfd *per_bfd)
|
||||
{
|
||||
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||
if (build_id == nullptr)
|
||||
return {};
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> index_path;
|
||||
scoped_fd fd = debuginfod_section_query (build_id->data, build_id->size,
|
||||
bfd_get_filename
|
||||
(objfile->obfd.get ()),
|
||||
".gdb_index",
|
||||
&index_path);
|
||||
if (fd.get () < 0)
|
||||
return {};
|
||||
|
||||
return global_index_cache.lookup_gdb_index_debuginfod
|
||||
(index_path.get (), &per_bfd->index_cache_res);
|
||||
}
|
||||
|
||||
|
||||
static void start_debug_info_reader (dwarf2_per_objfile *);
|
||||
|
||||
/* See dwarf2/public.h. */
|
||||
@@ -3212,11 +3473,13 @@ dwarf2_initialize_objfile (struct objfile *objfile,
|
||||
const struct dwarf2_debug_sections *names,
|
||||
bool can_copy)
|
||||
{
|
||||
if (!dwarf2_has_info (objfile, names, can_copy))
|
||||
if (!dwarf2_has_info (objfile, names, can_copy)
|
||||
&& (objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
return false;
|
||||
|
||||
dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
|
||||
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
||||
bool separate_index = false;
|
||||
|
||||
dwarf_read_debug_printf ("called");
|
||||
|
||||
@@ -3252,6 +3515,15 @@ dwarf2_initialize_objfile (struct objfile *objfile,
|
||||
dwarf_read_debug_printf ("found gdb index from cache");
|
||||
global_index_cache.hit ();
|
||||
}
|
||||
/* Try to read just a separately downloaded gdb index. */
|
||||
else if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) != 0
|
||||
&& dwarf2_read_gdb_index (per_objfile,
|
||||
get_gdb_index_contents_from_debuginfod,
|
||||
nullptr))
|
||||
{
|
||||
dwarf_read_debug_printf ("found .gdb_index from debuginfod");
|
||||
separate_index = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
global_index_cache.miss ();
|
||||
@@ -3263,11 +3535,92 @@ dwarf2_initialize_objfile (struct objfile *objfile,
|
||||
if (dwarf_synchronous)
|
||||
per_bfd->index_table->wait_completely ();
|
||||
objfile->qf.push_front (per_bfd->index_table->make_quick_functions ());
|
||||
|
||||
if (separate_index)
|
||||
objfile->qf.begin ()->get ()->from_separate_index = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* See read.h. */
|
||||
|
||||
void
|
||||
read_full_dwarf_from_debuginfod (struct objfile *objfile,
|
||||
dwarf2_base_index_functions *fncs)
|
||||
{
|
||||
gdb_assert ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) != 0);
|
||||
|
||||
SCOPE_EXIT { objfile->remove_deferred_status (); };
|
||||
|
||||
const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||
if (build_id == nullptr)
|
||||
return;
|
||||
|
||||
const char *filename = bfd_get_filename (objfile->obfd.get ());
|
||||
gdb::unique_xmalloc_ptr<char> symfile_path;
|
||||
scoped_fd fd;
|
||||
|
||||
fd = debuginfod_debuginfo_query (build_id->data, build_id->size,
|
||||
filename, &symfile_path);
|
||||
if (fd.get () < 0)
|
||||
return;
|
||||
|
||||
/* Separate debuginfo successfully retrieved from server. */
|
||||
gdb_bfd_ref_ptr debug_bfd = symfile_bfd_open (symfile_path.get ());
|
||||
if (debug_bfd == nullptr
|
||||
|| !build_id_verify (debug_bfd.get (), build_id->size, build_id->data))
|
||||
{
|
||||
warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear frame data so it can be recalculated using DWARF. */
|
||||
dwarf2_clear_frame_data (objfile);
|
||||
|
||||
/* This may also trigger a dwz download. */
|
||||
symbol_file_add_separate (debug_bfd, symfile_path.get (),
|
||||
current_inferior ()->symfile_flags, objfile);
|
||||
}
|
||||
|
||||
/* See public.h. */
|
||||
|
||||
bool
|
||||
dwarf2_has_separate_index (struct objfile *objfile)
|
||||
{
|
||||
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) != 0)
|
||||
return true;
|
||||
if ((objfile->flags & OBJF_MAINLINE) != 0)
|
||||
return false;
|
||||
if (!IS_DIR_SEPARATOR (*objfile_filename (objfile)))
|
||||
return false;
|
||||
|
||||
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||
|
||||
if (build_id == nullptr)
|
||||
return false;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> index_path;
|
||||
scoped_fd fd = debuginfod_section_query (build_id->data,
|
||||
build_id->size,
|
||||
bfd_get_filename
|
||||
(objfile->obfd.get ()),
|
||||
".gdb_index",
|
||||
&index_path);
|
||||
|
||||
if (fd.get () < 0)
|
||||
return false;
|
||||
|
||||
/* We found a separate .gdb_index file so a separate debuginfo file
|
||||
should exist, but we don't want to download it until necessary.
|
||||
Attach the index to this objfile and defer the debuginfo download
|
||||
until gdb needs to expand symtabs referenced by the index. */
|
||||
objfile->flags |= OBJF_DOWNLOAD_DEFERRED;
|
||||
dwarf2_initialize_objfile (objfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Find the base address of the compilation unit for range lists and
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gdbsupport/hash_enum.h"
|
||||
#include "gdbsupport/function-view.h"
|
||||
#include "gdbsupport/packed.h"
|
||||
#include "dwarf2/line-header.h"
|
||||
|
||||
/* Hold 'maintenance (set|show) dwarf' commands. */
|
||||
extern struct cmd_list_element *set_dwarf_cmdlist;
|
||||
@@ -860,6 +861,10 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
|
||||
CORE_ADDR pc, struct obj_section *section, int warn_if_readin)
|
||||
override;
|
||||
|
||||
struct compunit_symtab *do_find_pc_sect_compunit_symtab
|
||||
(struct objfile *objfile, struct bound_minimal_symbol msymbol,
|
||||
CORE_ADDR pc, struct obj_section *section, int warn_if_readin);
|
||||
|
||||
struct compunit_symtab *find_compunit_symtab_by_address
|
||||
(struct objfile *objfile, CORE_ADDR address) override
|
||||
{
|
||||
@@ -932,4 +937,46 @@ extern void create_all_units (dwarf2_per_objfile *per_objfile);
|
||||
|
||||
extern htab_up create_quick_file_names_table (unsigned int nr_initial_entries);
|
||||
|
||||
/* If OBJFILE contains information from a separately downloaded .gdb_index,
|
||||
attempt to download the full debuginfo. */
|
||||
|
||||
extern void read_full_dwarf_from_debuginfod (struct objfile *,
|
||||
dwarf2_base_index_functions *);
|
||||
|
||||
struct mapped_debug_line
|
||||
{
|
||||
mapped_debug_line (objfile *objfile);
|
||||
|
||||
/* Return true if any of the mapped .debug_line's filenames match
|
||||
FILE_MATCHER. */
|
||||
|
||||
bool contains_matching_filename
|
||||
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher);
|
||||
|
||||
/* Call FUN with each filename in this mapped .debug_line. Include
|
||||
each file's fullname if NEED_FULLNAME is true. */
|
||||
|
||||
void map_filenames (gdb::function_view<symbol_filename_ftype> fun,
|
||||
bool need_fullname);
|
||||
|
||||
private:
|
||||
std::vector<line_header_up> line_headers;
|
||||
|
||||
gdb::array_view<const gdb_byte> line_data;
|
||||
gdb::array_view<const gdb_byte> line_str_data;
|
||||
|
||||
std::unique_ptr<index_cache_resource> line_resource;
|
||||
std::unique_ptr<index_cache_resource> line_str_resource;
|
||||
|
||||
/* Download the .debug_line and .debug_line_str associated with OBJFILE
|
||||
and populate line_headers. */
|
||||
|
||||
bool read_debug_line_from_debuginfod (objfile *objfile);
|
||||
|
||||
/* Initialize line_data and line_str_data with the .debug_line and
|
||||
.debug_line_str downloaded read_debug_line_from_debuginfod. */
|
||||
|
||||
gdb::array_view<const gdb_byte> read_debug_line_separate
|
||||
(const char *filename, std::unique_ptr<index_cache_resource> *resource);
|
||||
};
|
||||
#endif /* DWARF2READ_H */
|
||||
|
||||
@@ -54,7 +54,8 @@ dwarf2_section_info::get_bfd_owner () const
|
||||
section = get_containing_section ();
|
||||
gdb_assert (!section->is_virtual);
|
||||
}
|
||||
gdb_assert (section->s.section != nullptr);
|
||||
if (section->s.section == nullptr)
|
||||
error (_("Can't find owner of DWARF section."));
|
||||
return section->s.section->owner;
|
||||
}
|
||||
|
||||
|
||||
@@ -1217,7 +1217,8 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
|
||||
&& objfile->separate_debug_objfile_backlink == NULL)
|
||||
{
|
||||
if (objfile->find_and_add_separate_symbol_file (symfile_flags))
|
||||
gdb_assert (objfile->separate_debug_objfile != nullptr);
|
||||
gdb_assert (objfile->separate_debug_objfile != nullptr
|
||||
|| (objfile->flags & OBJF_DOWNLOAD_DEFERRED) != 0);
|
||||
else
|
||||
has_dwarf2 = false;
|
||||
}
|
||||
|
||||
27
gdb/frame.c
27
gdb/frame.c
@@ -1777,14 +1777,10 @@ restore_selected_frame (frame_id frame_id, int frame_level)
|
||||
selected_frame = nullptr;
|
||||
}
|
||||
|
||||
/* Lookup the frame_info object for the selected frame FRAME_ID /
|
||||
FRAME_LEVEL and cache the result.
|
||||
|
||||
If FRAME_LEVEL > 0 and the originally selected frame isn't found,
|
||||
warn and select the innermost (current) frame. */
|
||||
/* See lookup_selected_frame. */
|
||||
|
||||
static void
|
||||
lookup_selected_frame (struct frame_id a_frame_id, int frame_level)
|
||||
lookup_selected_frame_1 (struct frame_id &a_frame_id, int frame_level)
|
||||
{
|
||||
frame_info_ptr frame = NULL;
|
||||
int count;
|
||||
@@ -1856,6 +1852,25 @@ lookup_selected_frame (struct frame_id a_frame_id, int frame_level)
|
||||
}
|
||||
}
|
||||
|
||||
/* Lookup the frame_info object for the selected frame FRAME_ID /
|
||||
FRAME_LEVEL and cache the result.
|
||||
|
||||
If FRAME_LEVEL > 0 and the originally selected frame isn't found,
|
||||
warn and select the innermost (current) frame. */
|
||||
|
||||
static void
|
||||
lookup_selected_frame (struct frame_id a_frame_id, int frame_level)
|
||||
{
|
||||
lookup_selected_frame_1 (selected_frame_id, selected_frame_level);
|
||||
|
||||
/* It is possible for lookup_selected_frame_1 to cause a new objfile
|
||||
to be loaded. However some objfile observers may choose to clear
|
||||
selected_frame when an objfile is loaded. Work around this by
|
||||
calling lookup_selected_frame_1 again if the first call failed. */
|
||||
if (selected_frame == nullptr)
|
||||
lookup_selected_frame_1 (selected_frame_id, selected_frame_level);
|
||||
}
|
||||
|
||||
bool
|
||||
has_stack_frames ()
|
||||
{
|
||||
|
||||
@@ -1240,11 +1240,10 @@ jit_breakpoint_re_set (void)
|
||||
static void
|
||||
jit_inferior_exit_hook (struct inferior *inf)
|
||||
{
|
||||
for (objfile *objf : current_program_space->objfiles_safe ())
|
||||
current_program_space->unlink_objfiles_if ([&] (const objfile *objf)
|
||||
{
|
||||
if (objf->jited_data != nullptr && objf->jited_data->addr != 0)
|
||||
objf->unlink ();
|
||||
}
|
||||
return (objf->jited_data != nullptr) && (objf->jited_data->addr != 0);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -278,7 +278,14 @@ mi_ui_out::do_progress_notify (const std::string &msg, const char *unit,
|
||||
|
||||
if (info.state == progress_update::START)
|
||||
{
|
||||
gdb_printf ("%s...\n", msg.c_str ());
|
||||
std::string prefix;
|
||||
if (cur_prefix_state == prefix_state_t::NEWLINE_NEEDED)
|
||||
{
|
||||
prefix = "\n";
|
||||
cur_prefix_state = prefix_state_t::NEWLINE_PRINTED;
|
||||
}
|
||||
|
||||
gdb_printf ("%s...\n", (prefix + msg).c_str ());
|
||||
info.state = progress_update::WORKING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ enum objfile_flag : unsigned
|
||||
/* User requested that we do not read this objfile's symbolic
|
||||
information. */
|
||||
OBJF_READNEVER = 1 << 6,
|
||||
|
||||
/* A separate .gdb_index has been downloaded for this objfile.
|
||||
Debuginfo for this objfile can be downloaded when required. */
|
||||
OBJF_DOWNLOAD_DEFERRED = 1 << 7,
|
||||
};
|
||||
|
||||
DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags);
|
||||
|
||||
@@ -470,6 +470,12 @@ objfile::unlink ()
|
||||
current_program_space->remove_objfile (this);
|
||||
}
|
||||
|
||||
qf_safe_range
|
||||
objfile::qf_safe ()
|
||||
{
|
||||
return qf_safe_range (qf_range (qf.begin (), qf.end ()));
|
||||
}
|
||||
|
||||
/* Free all separate debug objfile of OBJFILE, but don't free OBJFILE
|
||||
itself. */
|
||||
|
||||
@@ -793,14 +799,12 @@ have_full_symbols (void)
|
||||
void
|
||||
objfile_purge_solibs (void)
|
||||
{
|
||||
for (objfile *objf : current_program_space->objfiles_safe ())
|
||||
current_program_space->unlink_objfiles_if ([&] (const objfile *objf)
|
||||
{
|
||||
/* We assume that the solib package has been purged already, or will
|
||||
be soon. */
|
||||
|
||||
if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED))
|
||||
objf->unlink ();
|
||||
}
|
||||
return !(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -370,6 +370,12 @@ private:
|
||||
|
||||
typedef iterator_range<separate_debug_iterator> separate_debug_range;
|
||||
|
||||
/* See objfile::qf_safe. */
|
||||
|
||||
using qf_list = std::forward_list<quick_symbol_functions_up>;
|
||||
using qf_range = iterator_range<qf_list::iterator>;
|
||||
using qf_safe_range = basic_safe_range<qf_range>;
|
||||
|
||||
/* Sections in an objfile. The section offsets are stored in the
|
||||
OBJFILE. */
|
||||
|
||||
@@ -622,6 +628,26 @@ public:
|
||||
domain_search_flags domain,
|
||||
bool *symbol_found_p);
|
||||
|
||||
/* Indicate that the acquisition of this objfile's separate debug objfile
|
||||
is no longer deferred. Used when the debug objfile has been acquired
|
||||
or could not be found. */
|
||||
void remove_deferred_status ()
|
||||
{
|
||||
flags &= ~OBJF_DOWNLOAD_DEFERRED;
|
||||
|
||||
/* Remove quick_symbol_functions derived from a separately downloaded
|
||||
index. If available the separate debug objfile's index will be used
|
||||
instead, since that objfile actually contains the symbols and CUs
|
||||
referenced in the index.
|
||||
|
||||
No more than one element of qf should have from_separate_index set
|
||||
to true. */
|
||||
qf.remove_if ([&] (const quick_symbol_functions_up &qf_up)
|
||||
{
|
||||
return qf_up->from_separate_index;
|
||||
});
|
||||
}
|
||||
|
||||
/* Return the relocation offset applied to SECTION. */
|
||||
CORE_ADDR section_offset (bfd_section *section) const
|
||||
{
|
||||
@@ -767,8 +793,15 @@ public:
|
||||
const struct sym_fns *sf = nullptr;
|
||||
|
||||
/* The "quick" (aka partial) symbol functions for this symbol
|
||||
reader. */
|
||||
std::forward_list<quick_symbol_functions_up> qf;
|
||||
reader. Many quick_symbol_functions methods may result
|
||||
in the deletion of a quick_symbol_functions from this
|
||||
qf_list. It is recommended that qf_safe be used to iterate
|
||||
over the qf_list. */
|
||||
qf_list qf;
|
||||
|
||||
/* Returns an iterable object that allows for safe deletion during
|
||||
iteration. See gdbsupport/safe-iterator.h. */
|
||||
qf_safe_range qf_safe ();
|
||||
|
||||
/* Per objfile data-pointers required by other GDB modules. */
|
||||
|
||||
|
||||
@@ -141,19 +141,19 @@ program_space::free_all_objfiles ()
|
||||
|
||||
void
|
||||
program_space::add_objfile (std::unique_ptr<objfile> &&objfile,
|
||||
struct objfile *before)
|
||||
struct objfile *after)
|
||||
{
|
||||
if (before == nullptr)
|
||||
if (after == nullptr)
|
||||
objfiles_list.push_back (std::move (objfile));
|
||||
else
|
||||
{
|
||||
auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
|
||||
[=] (const std::unique_ptr<::objfile> &objf)
|
||||
{
|
||||
return objf.get () == before;
|
||||
return objf.get () == after;
|
||||
});
|
||||
gdb_assert (iter != objfiles_list.end ());
|
||||
objfiles_list.insert (iter, std::move (objfile));
|
||||
objfiles_list.insert (++iter, std::move (objfile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,17 @@ program_space::remove_objfile (struct objfile *objfile)
|
||||
|
||||
/* See progspace.h. */
|
||||
|
||||
void
|
||||
program_space::unlink_objfiles_if
|
||||
(gdb::function_view<bool (const objfile *objfile)> predicate)
|
||||
{
|
||||
for (auto &it : objfiles_safe ())
|
||||
if (predicate (it.get ()))
|
||||
it->unlink ();
|
||||
}
|
||||
|
||||
/* See progspace.h. */
|
||||
|
||||
struct objfile *
|
||||
program_space::objfile_for_address (CORE_ADDR address)
|
||||
{
|
||||
|
||||
@@ -250,28 +250,32 @@ struct program_space
|
||||
unwrapping_objfile_iterator (objfiles_list.end ()));
|
||||
}
|
||||
|
||||
using objfiles_safe_range = basic_safe_range<objfiles_range>;
|
||||
using objfiles_it_range = iterator_range<objfile_list::iterator>;
|
||||
using objfiles_safe_reverse_range
|
||||
= basic_safe_reverse_range<objfiles_it_range>;
|
||||
|
||||
/* An iterable object that can be used to iterate over all objfiles.
|
||||
The basic use is in a foreach, like:
|
||||
|
||||
for (objfile *objf : pspace->objfiles_safe ()) { ... }
|
||||
|
||||
This variant uses a basic_safe_iterator so that objfiles can be
|
||||
deleted during iteration. */
|
||||
objfiles_safe_range objfiles_safe ()
|
||||
This variant uses a basic_safe_reverse_iterator so that objfiles
|
||||
can be deleted during iteration.
|
||||
|
||||
The use of a reverse iterator helps ensure that separate debug
|
||||
objfiles are deleted before their parent objfile. This prevents
|
||||
iterator invalidation due to the deletion of a parent objfile. */
|
||||
objfiles_safe_reverse_range objfiles_safe ()
|
||||
{
|
||||
return objfiles_safe_range
|
||||
(objfiles_range
|
||||
(unwrapping_objfile_iterator (objfiles_list.begin ()),
|
||||
unwrapping_objfile_iterator (objfiles_list.end ())));
|
||||
return objfiles_safe_reverse_range
|
||||
(objfiles_it_range (objfiles_list.begin (), objfiles_list.end ()));
|
||||
}
|
||||
|
||||
/* Add OBJFILE to the list of objfiles, putting it just before
|
||||
BEFORE. If BEFORE is nullptr, it will go at the end of the
|
||||
/* Add OBJFILE to the list of objfiles, putting it just after
|
||||
AFTER. If AFTER is nullptr, it will go at the end of the
|
||||
list. */
|
||||
void add_objfile (std::unique_ptr<objfile> &&objfile,
|
||||
struct objfile *before);
|
||||
struct objfile *after);
|
||||
|
||||
/* Remove OBJFILE from the list of objfiles. */
|
||||
void remove_objfile (struct objfile *objfile);
|
||||
@@ -286,6 +290,11 @@ struct program_space
|
||||
/* Free all the objfiles associated with this program space. */
|
||||
void free_all_objfiles ();
|
||||
|
||||
/* Unlink all objfiles associated with this program space for which
|
||||
PREDICATE evaluates to true. */
|
||||
void unlink_objfiles_if
|
||||
(gdb::function_view<bool (const objfile *objfile)> predicate);
|
||||
|
||||
/* Return the objfile containing ADDRESS, or nullptr if the address
|
||||
is outside all objfiles in this progspace. */
|
||||
struct objfile *objfile_for_address (CORE_ADDR address);
|
||||
|
||||
@@ -191,6 +191,10 @@ struct quick_symbol_functions
|
||||
virtual void compute_main_name (struct objfile *objfile)
|
||||
{
|
||||
}
|
||||
|
||||
/* True if this quick_symbol_functions is derived from a separately
|
||||
downloaded index. */
|
||||
bool from_separate_index = false;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<quick_symbol_functions> quick_symbol_functions_up;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "cli/cli-style.h"
|
||||
#include "build-id.h"
|
||||
#include "debuginfod-support.h"
|
||||
#include "dwarf2/public.h"
|
||||
|
||||
/* We need to save a pointer to the real symbol functions.
|
||||
Plus, the debug versions are malloc'd because we have to NULL out the
|
||||
@@ -85,7 +86,7 @@ objfile::has_partial_symbols ()
|
||||
them, then that is an indication that they are in fact available. Without
|
||||
this function the symbols may have been already read in but they also may
|
||||
not be present in this objfile. */
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
retval = iter->has_symbols (this);
|
||||
if (retval)
|
||||
@@ -108,7 +109,7 @@ objfile::has_unexpanded_symtabs ()
|
||||
objfile_debug_name (this));
|
||||
|
||||
bool result = false;
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
if (iter->has_unexpanded_symtabs (this))
|
||||
{
|
||||
@@ -133,7 +134,7 @@ objfile::find_last_source_symtab ()
|
||||
gdb_printf (gdb_stdlog, "qf->find_last_source_symtab (%s)\n",
|
||||
objfile_debug_name (this));
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
retval = iter->find_last_source_symtab (this);
|
||||
if (retval != nullptr)
|
||||
@@ -166,7 +167,7 @@ objfile::forget_cached_source_info ()
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->forget_cached_source_info (this);
|
||||
}
|
||||
|
||||
@@ -213,7 +214,7 @@ objfile::map_symtabs_matching_filename
|
||||
return result;
|
||||
};
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
if (!iter->expand_symtabs_matching (this,
|
||||
match_one_filename,
|
||||
@@ -276,7 +277,7 @@ objfile::lookup_symbol (block_enum kind, const lookup_name_info &name,
|
||||
return true;
|
||||
};
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
if (!iter->expand_symtabs_matching (this,
|
||||
nullptr,
|
||||
@@ -306,7 +307,7 @@ objfile::print_stats (bool print_bcache)
|
||||
gdb_printf (gdb_stdlog, "qf->print_stats (%s, %d)\n",
|
||||
objfile_debug_name (this), print_bcache);
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->print_stats (this, print_bcache);
|
||||
}
|
||||
|
||||
@@ -317,7 +318,7 @@ objfile::dump ()
|
||||
gdb_printf (gdb_stdlog, "qf->dump (%s)\n",
|
||||
objfile_debug_name (this));
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->dump (this);
|
||||
}
|
||||
|
||||
@@ -332,7 +333,7 @@ objfile::expand_symtabs_for_function (const char *func_name)
|
||||
lookup_name_info base_lookup (func_name, symbol_name_match_type::FULL);
|
||||
lookup_name_info lookup_name = base_lookup.make_ignore_params ();
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->expand_symtabs_matching (this,
|
||||
nullptr,
|
||||
&lookup_name,
|
||||
@@ -350,7 +351,7 @@ objfile::expand_all_symtabs ()
|
||||
gdb_printf (gdb_stdlog, "qf->expand_all_symtabs (%s)\n",
|
||||
objfile_debug_name (this));
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->expand_all_symtabs (this);
|
||||
}
|
||||
|
||||
@@ -368,7 +369,7 @@ objfile::expand_symtabs_with_fullname (const char *fullname)
|
||||
return filename_cmp (basenames ? basename : fullname, filename) == 0;
|
||||
};
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->expand_symtabs_matching (this,
|
||||
file_matcher,
|
||||
nullptr,
|
||||
@@ -400,7 +401,7 @@ objfile::expand_symtabs_matching
|
||||
host_address_to_string (&expansion_notify),
|
||||
domain_name (domain).c_str ());
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
if (!iter->expand_symtabs_matching (this, file_matcher, lookup_name,
|
||||
symbol_matcher, expansion_notify,
|
||||
search_flags, domain))
|
||||
@@ -425,7 +426,7 @@ objfile::find_pc_sect_compunit_symtab (struct bound_minimal_symbol msymbol,
|
||||
host_address_to_string (section),
|
||||
warn_if_readin);
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
retval = iter->find_pc_sect_compunit_symtab (this, msymbol, pc, section,
|
||||
warn_if_readin);
|
||||
@@ -453,7 +454,7 @@ objfile::map_symbol_filenames (gdb::function_view<symbol_filename_ftype> fun,
|
||||
objfile_debug_name (this),
|
||||
need_fullname);
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->map_symbol_filenames (this, fun, need_fullname);
|
||||
}
|
||||
|
||||
@@ -465,7 +466,7 @@ objfile::compute_main_name ()
|
||||
"qf->compute_main_name (%s)\n",
|
||||
objfile_debug_name (this));
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
iter->compute_main_name (this);
|
||||
}
|
||||
|
||||
@@ -479,7 +480,7 @@ objfile::find_compunit_symtab_by_address (CORE_ADDR address)
|
||||
hex_string (address));
|
||||
|
||||
struct compunit_symtab *result = NULL;
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
result = iter->find_compunit_symtab_by_address (this, address);
|
||||
if (result != nullptr)
|
||||
@@ -504,7 +505,7 @@ objfile::lookup_global_symbol_language (const char *name,
|
||||
enum language result = language_unknown;
|
||||
*symbol_found_p = false;
|
||||
|
||||
for (const auto &iter : qf)
|
||||
for (const auto &iter : qf_safe ())
|
||||
{
|
||||
result = iter->lookup_global_symbol_language (this, name, domain,
|
||||
symbol_found_p);
|
||||
@@ -611,6 +612,16 @@ objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
|
||||
= simple_find_and_open_separate_symbol_file
|
||||
(this, find_separate_debug_file_by_debuglink, &warnings);
|
||||
|
||||
/* Attempt to download only an index from the separate debug info.
|
||||
As with debuginfod_find_and_open_separate_symbol_file, only attempt
|
||||
this once. */
|
||||
if (debug_bfd == nullptr && attempt == 0
|
||||
&& dwarf2_has_separate_index (this))
|
||||
{
|
||||
has_dwarf2 = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only try debuginfod on the first attempt. Sure, we could imagine
|
||||
an extension that somehow adds the required debug info to the
|
||||
debuginfod server but, at least for now, we don't support this
|
||||
|
||||
@@ -989,6 +989,10 @@ syms_from_objfile (struct objfile *objfile,
|
||||
static void
|
||||
finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
|
||||
{
|
||||
struct objfile *parent = objfile->separate_debug_objfile_backlink;
|
||||
bool was_deferred
|
||||
= (parent != nullptr) && ((parent->flags & OBJF_DOWNLOAD_DEFERRED) != 0);
|
||||
|
||||
/* If this is the main symbol file we have to clean up all users of the
|
||||
old main symbol file. Otherwise it is sufficient to fixup all the
|
||||
breakpoints that may have been redefined by this symbol file. */
|
||||
@@ -999,7 +1003,7 @@ finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
|
||||
|
||||
clear_symtab_users (add_flags);
|
||||
}
|
||||
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0)
|
||||
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0 && !was_deferred)
|
||||
{
|
||||
breakpoint_re_set ();
|
||||
}
|
||||
@@ -1120,6 +1124,12 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
|
||||
if (objfile->sf != nullptr)
|
||||
finish_new_objfile (objfile, add_flags);
|
||||
|
||||
/* Remove deferred status now in case any observers trigger symtab
|
||||
expansion. Otherwise gdb might try to read parent for psymbols
|
||||
when it should read the separate debug objfile instead. */
|
||||
if (parent != nullptr && ((parent->flags & OBJF_DOWNLOAD_DEFERRED) != 0))
|
||||
parent->remove_deferred_status ();
|
||||
|
||||
gdb::observers::new_objfile.notify (objfile);
|
||||
|
||||
return objfile;
|
||||
|
||||
18
gdb/symtab.c
18
gdb/symtab.c
@@ -2957,14 +2957,30 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
|
||||
if (best_cust != NULL)
|
||||
return best_cust;
|
||||
|
||||
int warn_if_readin = 1;
|
||||
|
||||
/* Not found in symtabs, search the "quick" symtabs (e.g. psymtabs). */
|
||||
|
||||
for (objfile *objf : current_program_space->objfiles ())
|
||||
{
|
||||
bool was_deferred = (objf->flags & OBJF_DOWNLOAD_DEFERRED) != 0;
|
||||
|
||||
struct compunit_symtab *result
|
||||
= objf->find_pc_sect_compunit_symtab (msymbol, pc, section, 1);
|
||||
= objf->find_pc_sect_compunit_symtab (msymbol, pc, section,
|
||||
warn_if_readin);
|
||||
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
/* If OBJF's separate debug info was just acquired, disable
|
||||
warn_if_readin for the next iteration of this loop. This prevents
|
||||
a spurious warning in case an observer already triggered expansion
|
||||
of the separate debug objfile's symtabs. */
|
||||
if (was_deferred && objf->separate_debug_objfile != nullptr
|
||||
&& (objf->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||
warn_if_readin = 0;
|
||||
else if (warn_if_readin == 0)
|
||||
warn_if_readin = 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
43
gdb/testsuite/gdb.debuginfod/libsection1.c
Normal file
43
gdb/testsuite/gdb.debuginfod/libsection1.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2023-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern void libsection2_test ();
|
||||
extern void *libsection2_thread_test (void *);
|
||||
|
||||
static volatile int flag = 0;
|
||||
|
||||
void
|
||||
libsection1_test ()
|
||||
{
|
||||
pthread_t thr;
|
||||
|
||||
printf ("In libsection1\n");
|
||||
libsection2_test ();
|
||||
|
||||
pthread_create (&thr, NULL, libsection2_thread_test, (void *) &flag);
|
||||
|
||||
/* Give the new thread a chance to actually enter libsection2_thread_test. */
|
||||
while (!flag)
|
||||
;
|
||||
|
||||
printf ("Cancelling thread\n");
|
||||
pthread_cancel (thr);
|
||||
}
|
||||
37
gdb/testsuite/gdb.debuginfod/libsection2.c
Normal file
37
gdb/testsuite/gdb.debuginfod/libsection2.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2023-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
void
|
||||
libsection2_test ()
|
||||
{
|
||||
printf ("In libsection2\n");
|
||||
}
|
||||
|
||||
void *
|
||||
libsection2_thread_test (void *arg)
|
||||
{
|
||||
int *flag = (int *) arg;
|
||||
printf ("In thread test\n");
|
||||
|
||||
while (1)
|
||||
*flag = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
29
gdb/testsuite/gdb.debuginfod/section.c
Normal file
29
gdb/testsuite/gdb.debuginfod/section.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2023-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern void libsection1_test ();
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
libsection1_test ();
|
||||
printf ("in section exec\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
184
gdb/testsuite/gdb.debuginfod/section.exp
Normal file
184
gdb/testsuite/gdb.debuginfod/section.exp
Normal file
@@ -0,0 +1,184 @@
|
||||
# Copyright 2023-2024 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Test debuginfod functionality
|
||||
|
||||
standard_testfile
|
||||
|
||||
load_lib debuginfod-support.exp
|
||||
load_lib completion-support.exp
|
||||
|
||||
clean_restart
|
||||
require allow_debuginfod_tests
|
||||
require allow_debuginfod_section_downloads
|
||||
|
||||
# BINFILE calls a function from LIB_SL1.
|
||||
set libfile1 "libsection1"
|
||||
set libsrc1 $srcdir/$subdir/$libfile1.c
|
||||
set lib_sl1 [standard_output_file $libfile1.sl]
|
||||
|
||||
# LIB_SL1 calls functions from LIB_SL2.
|
||||
set libfile2 "libsection2"
|
||||
set libsrc2 $srcdir/$subdir/$libfile2.c
|
||||
set lib_sl2 [standard_output_file $libfile2.sl]
|
||||
|
||||
# Build LIB_SL2, LIB_SL1 and BINFILE.
|
||||
if { [build_executable "build $libfile2" $lib_sl2 $libsrc2 \
|
||||
{debug build-id shlib}] != 0 } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [build_executable "build $libfile1" $lib_sl1 $libsrc1 \
|
||||
[list debug build-id shlib_pthreads shlib=$lib_sl2]] != 0 } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [build_executable "build executable" $binfile $srcfile \
|
||||
[list debug build-id shlib=$lib_sl1 shlib=$lib_sl2]] != 0 } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Make sure libsection1 and libsection2 contain .gdb_index.
|
||||
if { [ensure_gdb_index $lib_sl1 "" "libsection1"] != 1 } {
|
||||
untested "failed to add .gdb_index to $libfile1"
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [ensure_gdb_index $lib_sl2 "" "libsection2"] != 1 } {
|
||||
untested "failed to add .gdb_index to $libfile2"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Strip solib debuginfo into separate files.
|
||||
if { [gdb_gnu_strip_debug $lib_sl1 ""] != 0} {
|
||||
fail "strip $lib_sl1 debuginfo"
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [gdb_gnu_strip_debug $lib_sl2 ""] != 0} {
|
||||
fail "strip $lib_sl2 debuginfo"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Move debuginfo files into directory that debuginfod will serve from.
|
||||
set debugdir [standard_output_file "debug"]
|
||||
set debuginfo_sl1 [standard_output_file $libfile1.sl.debug]
|
||||
set debuginfo_sl2 [standard_output_file $libfile2.sl.debug]
|
||||
|
||||
file mkdir $debugdir
|
||||
file rename -force $debuginfo_sl1 $debugdir
|
||||
file rename -force $debuginfo_sl2 $debugdir
|
||||
|
||||
# Restart GDB and clear the debuginfod client cache. Then load BINFILE into
|
||||
# GDB and start running it. Match output with pattern RES and use TESTNAME
|
||||
# as the test name.
|
||||
proc_with_prefix clean_restart_with_prompt { binfile testname } {
|
||||
global cache
|
||||
|
||||
# Delete client cache so debuginfo downloads again.
|
||||
file delete -force $cache
|
||||
clean_restart
|
||||
|
||||
gdb_test_no_output "set debuginfod enabled on" \
|
||||
"clean_restart enable $testname"
|
||||
gdb_load $binfile
|
||||
|
||||
runto_main
|
||||
}
|
||||
|
||||
# Tests with no debuginfod server running.
|
||||
proc_with_prefix no_url { } {
|
||||
global binfile libfile1 libfile2
|
||||
|
||||
gdb_load $binfile
|
||||
if {![runto_main]} {
|
||||
return
|
||||
}
|
||||
|
||||
# Check that no section is downloaded and no debuginfo is found.
|
||||
gdb_test "info sharedlibrary" ".*Yes \\(\\*\\).*$libfile1.*" \
|
||||
"found no url lib1"
|
||||
gdb_test "info sharedlibrary" ".*Yes \\(\\*\\).*$libfile2.*" \
|
||||
"found no url lib2"
|
||||
}
|
||||
|
||||
# Tests with a debuginfod server running.
|
||||
proc_with_prefix local_url { } {
|
||||
global binfile
|
||||
global libsrc1 lib_sl1 libfile1
|
||||
global libsrc2 lib_sl2 libfile2
|
||||
global debugdir db
|
||||
|
||||
set url [start_debuginfod $db $debugdir]
|
||||
if { $url == "" } {
|
||||
unresolved "failed to start debuginfod server"
|
||||
return
|
||||
}
|
||||
|
||||
# Point GDB to the server.
|
||||
setenv DEBUGINFOD_URLS $url
|
||||
|
||||
clean_restart_with_prompt $binfile "index"
|
||||
|
||||
# Download debuginfo when stepping into a function.
|
||||
set res ".*separate debug info for $lib_sl1.*\"In ${libfile1}\\\\n\".*"
|
||||
gdb_test "step" $res "step"
|
||||
|
||||
clean_restart_with_prompt $binfile "break"
|
||||
|
||||
# Download debuginfo when setting a breakpoint.
|
||||
set res "Download.*separate debug info for $lib_sl2.*"
|
||||
gdb_test "br libsection2_test" $res "break set"
|
||||
|
||||
# Hit the breakpoint.
|
||||
set res ".*Breakpoint 2, libsection2_test.*\"In ${libfile2}\\\\n\".*"
|
||||
gdb_test "c" $res "break continue"
|
||||
|
||||
clean_restart_with_prompt $binfile "line 1"
|
||||
|
||||
# List source file using .debug_line download.
|
||||
set res ".*\.debug_line.*$lib_sl1.*21.*extern void libsection2_test.*"
|
||||
gdb_test "list $libsrc1:21" $res "line 1 list"
|
||||
|
||||
clean_restart_with_prompt $binfile "line 2"
|
||||
|
||||
# Set breakpoint using .debug_line download.
|
||||
set res ".*section \.debug_line for $lib_sl1.*Breakpoint 2 at.*$libsrc1.*"
|
||||
gdb_test "br $libsrc1:41" $res "line 2 br"
|
||||
|
||||
# Continue to breakpoint.
|
||||
set res "Breakpoint 2, libsection1_test.*\"Cancelling thread\\\\n\".*"
|
||||
gdb_test "c" $res "line 2 continue"
|
||||
|
||||
# Check that download progress message is correctly formatted
|
||||
# when printing threads.
|
||||
set res ".*separate debug info for $lib_sl2\.\.\.\r\n.* 2 Thread.*"
|
||||
gdb_test "info thr" $res "line thread"
|
||||
|
||||
clean_restart_with_prompt $binfile "autocomplete"
|
||||
|
||||
# Download debuginfo during autocompletion.
|
||||
test_gdb_complete_tab_unique "br lib" ".*Downloading separate debug.*" ""
|
||||
}
|
||||
|
||||
# Create CACHE and DB directories ready for debuginfod to use.
|
||||
prepare_for_debuginfod cache db
|
||||
|
||||
with_debuginfod_env $cache {
|
||||
no_url
|
||||
local_url
|
||||
}
|
||||
|
||||
stop_debuginfod
|
||||
@@ -135,7 +135,7 @@ gdb_test "p main" "= {<text variable, no debug info>} $hex <main>" \
|
||||
gdb_py_test_silent_cmd "python objfile.add_separate_debug_file(\"${binfile}\")" \
|
||||
"Add separate debug file file" 1
|
||||
|
||||
gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[0\]" \
|
||||
gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[1\]" \
|
||||
"Get separate debug info objfile" 1
|
||||
|
||||
gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \
|
||||
|
||||
@@ -113,6 +113,8 @@ proc with_debuginfod_env { cache body } {
|
||||
proc start_debuginfod { db debugdir } {
|
||||
global debuginfod_spawn_id spawn_id
|
||||
|
||||
set logfile [standard_output_file "server_log"]
|
||||
|
||||
# Find an unused port.
|
||||
set port 7999
|
||||
set found false
|
||||
@@ -127,7 +129,8 @@ proc start_debuginfod { db debugdir } {
|
||||
set old_spawn_id $spawn_id
|
||||
}
|
||||
|
||||
spawn debuginfod -vvvv -d $db -p $port -F $debugdir
|
||||
spawn sh -c "debuginfod -vvvv -d $db -p $port -F $debugdir 2>&1 \
|
||||
| tee $logfile"
|
||||
set debuginfod_spawn_id $spawn_id
|
||||
|
||||
if { [info exists old_spawn_id] } {
|
||||
@@ -194,3 +197,23 @@ proc stop_debuginfod { } {
|
||||
unset debuginfod_spawn_id
|
||||
}
|
||||
}
|
||||
|
||||
# Return true if gdb is configured to download ELF/DWARF sections from
|
||||
# debuginfod servers. Otherwise return false.
|
||||
proc allow_debuginfod_section_downloads { } {
|
||||
set cmd "maint set debuginfod download-sections on"
|
||||
set msg "enable section downloads"
|
||||
|
||||
gdb_test_multiple $cmd $msg {
|
||||
-re -wrap ".*not compiled into GDB.*" {
|
||||
return false
|
||||
}
|
||||
-re -wrap "^" {
|
||||
return true
|
||||
}
|
||||
-re -wrap "" {
|
||||
fail "$gdb_test_name (unexpected output)"
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9438,10 +9438,14 @@ proc get_index_type { objfile { testname "" } } {
|
||||
# STYLE controls which style of index to add, if needed. The empty
|
||||
# string (the default) means .gdb_index; "-dwarf-5" means .debug_names.
|
||||
|
||||
proc ensure_gdb_index { binfile {style ""} } {
|
||||
proc ensure_gdb_index { binfile {style ""} {testname_prefix ""} } {
|
||||
set testfile [file tail $binfile]
|
||||
|
||||
set test "check if index present"
|
||||
|
||||
if { $testname_prefix != "" } {
|
||||
set test "$testname_prefix $test"
|
||||
}
|
||||
|
||||
set index_type [get_index_type $testfile $test]
|
||||
|
||||
if { $index_type eq "gdb" || $index_type eq "dwarf5" } {
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/* Current state of newline prefixing for progress update messages. */
|
||||
prefix_state_t cur_prefix_state = prefix_state_t::NEWLINE_OFF;
|
||||
|
||||
namespace {
|
||||
|
||||
/* A header of a ui_out_table. */
|
||||
|
||||
20
gdb/ui-out.h
20
gdb/ui-out.h
@@ -296,6 +296,21 @@ class ui_out
|
||||
BAR
|
||||
};
|
||||
|
||||
/* Used to communicate the status of a newline prefix for the next progress
|
||||
update message. */
|
||||
enum prefix_state
|
||||
{
|
||||
/* Do not modify the next progress update message. */
|
||||
NEWLINE_OFF,
|
||||
|
||||
/* The next progress update message should include a newline prefix. */
|
||||
NEWLINE_NEEDED,
|
||||
|
||||
/* A newline prefix was included in a debuginfod progress update
|
||||
message. */
|
||||
NEWLINE_PRINTED
|
||||
};
|
||||
|
||||
/* SHOULD_PRINT indicates whether something should be printed for a tty. */
|
||||
progress_update ()
|
||||
{
|
||||
@@ -393,6 +408,11 @@ protected:
|
||||
ui_out_level *current_level () const;
|
||||
};
|
||||
|
||||
typedef ui_out::progress_update::prefix_state prefix_state_t;
|
||||
|
||||
/* Current state of the newline prefix. */
|
||||
extern prefix_state_t cur_prefix_state;
|
||||
|
||||
/* Start a new tuple or list on construction, and end it on
|
||||
destruction. Normally this is used via the typedefs
|
||||
ui_out_emit_tuple and ui_out_emit_list. */
|
||||
|
||||
@@ -136,4 +136,119 @@ private:
|
||||
Range m_range;
|
||||
};
|
||||
|
||||
/* A reverse basic_safe_iterator. See basic_safe_iterator for intended use. */
|
||||
|
||||
template<typename Iterator>
|
||||
class basic_safe_reverse_iterator
|
||||
{
|
||||
public:
|
||||
typedef basic_safe_reverse_iterator self_type;
|
||||
typedef typename Iterator::value_type value_type;
|
||||
typedef typename Iterator::reference reference;
|
||||
typedef typename Iterator::pointer pointer;
|
||||
typedef typename Iterator::iterator_category iterator_category;
|
||||
typedef typename Iterator::difference_type difference_type;
|
||||
|
||||
/* Construct the iterator using ARG, and construct the end iterator
|
||||
using ARG2. ARG and ARG2 should be forward iterators, typically
|
||||
from begin and end methods, respectively.
|
||||
|
||||
For example if ARG1 is created with container.begin and ARG2 is
|
||||
is created with container.end, then the basic_safe_reverse_iterator
|
||||
will traverse from the last element in the container to the first
|
||||
element in the container. */
|
||||
template<typename Arg>
|
||||
explicit basic_safe_reverse_iterator (Arg &&arg, Arg &&arg2)
|
||||
: m_begin (std::forward<Arg> (arg)),
|
||||
m_end (std::forward<Arg> (arg2)),
|
||||
m_it (m_end),
|
||||
m_next (m_end)
|
||||
{
|
||||
/* M_IT and M_NEXT are initialized as one-past-end. Set M_IT to point
|
||||
to the last element and set M_NEXT to point to the second last element,
|
||||
if such elements exist. */
|
||||
if (m_it != m_begin)
|
||||
{
|
||||
--m_it;
|
||||
|
||||
if (m_it != m_begin)
|
||||
{
|
||||
--m_next;
|
||||
--m_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typename std::invoke_result<decltype(&Iterator::operator*), Iterator>::type
|
||||
operator* () const
|
||||
{ return *m_it; }
|
||||
|
||||
self_type &operator++ ()
|
||||
{
|
||||
m_it = m_next;
|
||||
|
||||
if (m_it != m_end)
|
||||
{
|
||||
/* Use M_BEGIN only if we sure that it is valid. */
|
||||
if (m_it == m_begin)
|
||||
m_next = m_end;
|
||||
else
|
||||
--m_next;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator== (const self_type &other) const
|
||||
{ return m_it == other.m_it; }
|
||||
|
||||
bool operator!= (const self_type &other) const
|
||||
{ return m_it != other.m_it; }
|
||||
|
||||
private:
|
||||
/* The first element. */
|
||||
Iterator m_begin {};
|
||||
|
||||
/* A one-past-end iterator. */
|
||||
Iterator m_end {};
|
||||
|
||||
/* The current element. */
|
||||
Iterator m_it {};
|
||||
|
||||
/* The next element. Always one element ahead of M_IT. */
|
||||
Iterator m_next {};
|
||||
};
|
||||
|
||||
/* A range adapter that wraps a forward range, and then returns
|
||||
safe reverse iterators wrapping the original range's iterators. */
|
||||
|
||||
template<typename Range>
|
||||
class basic_safe_reverse_range
|
||||
{
|
||||
public:
|
||||
|
||||
typedef basic_safe_reverse_iterator<typename Range::iterator> iterator;
|
||||
|
||||
/* RANGE must be a forward range. basic_safe_reverse_iterators
|
||||
will be used to traverse the forward range from the last element
|
||||
to the first. */
|
||||
explicit basic_safe_reverse_range (Range range)
|
||||
: m_range (range)
|
||||
{
|
||||
}
|
||||
|
||||
iterator begin ()
|
||||
{
|
||||
return iterator (m_range.begin (), m_range.end ());
|
||||
}
|
||||
|
||||
iterator end ()
|
||||
{
|
||||
return iterator (m_range.end (), m_range.end ());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Range m_range;
|
||||
};
|
||||
#endif /* COMMON_SAFE_ITERATOR_H */
|
||||
|
||||
Reference in New Issue
Block a user