diff options
author | Aaron Merey <amerey@redhat.com> | 2025-01-21 16:09:47 -0500 |
---|---|---|
committer | Aaron Merey <amerey@redhat.com> | 2025-01-24 09:57:38 -0500 |
commit | 89c07e295b6485e997e7969052aa2ecf7c811409 (patch) | |
tree | d4b1c159f76df421c65b622bbfdc0dbad92e1a67 /gdb/dwarf2/line-header.c | |
parent | 8ce1af0a1d8ecdefcd97f006a2f584dd6fd36ea6 (diff) | |
download | gdb-users/amerey/download-gdb-index.zip gdb-users/amerey/download-gdb-index.tar.gz gdb-users/amerey/download-gdb-index.tar.bz2 |
gdb/debuginfod: Add .debug_line downloadingusers/amerey/download-gdb-index
ELF/DWARF section downloading allows gdb to download .gdb_index files in
order to defer full debuginfo downloads. However .gdb_index does not
contain any information regarding source filenames. When a gdb command
includes a filename argument (ex. 'break main.c:50'), this results in
the mass downloading of all deferred debuginfo so that gdb can search the
debuginfo for matching source filenames. This can result in unnecessary
downloads.
To improve this, have gdb instead download each debuginfo's .debug_line
(and .debug_line_str if using DWARF5) when executing these commands.
Download full debuginfo only when its .debug_line contains a matching
filename.
Since the combined size of .debug_line and .debug_line_str is only about
1% the size of the corresponding debuginfo, significant time can be saved
by checking these sections before choosing to download an entire debuginfo.
This patch also redirects stdout and stderr of the debuginfod server
used by testsuite/gdb.debuginfod tests to a server_log standard output
file. While adding tests for this patch I ran into an issue where the
test server would block when logging to stderr, presumably because the
stderr buffer filled up and wasn't being read from. Redirecting the
log to a file fixes this and also makes the server log more accessible
when debugging test failures.
Diffstat (limited to 'gdb/dwarf2/line-header.c')
-rw-r--r-- | gdb/dwarf2/line-header.c | 161 |
1 files changed, 112 insertions, 49 deletions
diff --git a/gdb/dwarf2/line-header.c b/gdb/dwarf2/line-header.c index eddb2ef..1d24386 100644 --- a/gdb/dwarf2/line-header.c +++ b/gdb/dwarf2/line-header.c @@ -101,12 +101,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; @@ -115,21 +118,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; @@ -156,7 +165,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; @@ -171,12 +180,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)); @@ -247,28 +268,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; @@ -276,24 +299,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; + line_ptr += bytes_read; - 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; @@ -302,7 +327,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) { @@ -319,13 +344,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; @@ -346,12 +372,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. */ @@ -364,21 +394,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); }); @@ -386,7 +418,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); @@ -394,7 +426,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; @@ -412,9 +444,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); +} |