Move more code to line-header.c

This moves some more code out of read.c and into line-header.c.
dwarf_decode_line_header is split into two -- the part remaining in
read.c handles interfacing to the dwarf2_cu; while the part in
line-header.c (more or less) purely handles the actual decoding.

gdb/ChangeLog
2020-03-26  Tom Tromey  <tom@tromey.com>

	* dwarf2/line-header.h (dwarf_decode_line_header): Declare.
	* dwarf2/read.c
	(dwarf2_statement_list_fits_in_line_number_section_complaint):
	Move to line-header.c.
	(read_checked_initial_length_and_offset, read_formatted_entries):
	Likewise.
	(dwarf_decode_line_header): Split into two.
	* dwarf2/line-header.c
	(dwarf2_statement_list_fits_in_line_number_section_complaint):
	Move from read.c.
	(read_checked_initial_length_and_offset, read_formatted_entries):
	Likewise.
	(dwarf_decode_line_header): New function, split from read.c.
This commit is contained in:
Tom Tromey 2020-03-26 09:28:08 -06:00
parent 86c0bb4c57
commit 0df7ad3a67
4 changed files with 368 additions and 329 deletions

View File

@ -1,3 +1,19 @@
2020-03-26 Tom Tromey <tom@tromey.com>
* dwarf2/line-header.h (dwarf_decode_line_header): Declare.
* dwarf2/read.c
(dwarf2_statement_list_fits_in_line_number_section_complaint):
Move to line-header.c.
(read_checked_initial_length_and_offset, read_formatted_entries):
Likewise.
(dwarf_decode_line_header): Split into two.
* dwarf2/line-header.c
(dwarf2_statement_list_fits_in_line_number_section_complaint):
Move from read.c.
(read_checked_initial_length_and_offset, read_formatted_entries):
Likewise.
(dwarf_decode_line_header): New function, split from read.c.
2020-03-26 Tom Tromey <tom@tromey.com>
* dwarf2/read.h (struct dwarf2_per_objfile) <read_line_string>:

View File

@ -18,6 +18,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "dwarf2/comp-unit.h"
#include "dwarf2/leb.h"
#include "dwarf2/line-header.h"
#include "dwarf2/read.h"
#include "complaints.h"
@ -112,3 +114,336 @@ line_header::file_full_name (int file, const char *comp_dir) const
else
return file_file_name (file);
}
static void
dwarf2_statement_list_fits_in_line_number_section_complaint (void)
{
complaint (_("statement list doesn't fit in .debug_line section"));
}
/* Cover function for read_initial_length.
Returns the length of the object at BUF, and stores the size of the
initial length in *BYTES_READ and stores the size that offsets will be in
*OFFSET_SIZE.
If the initial length size is not equivalent to that specified in
CU_HEADER then issue a complaint.
This is useful when reading non-comp-unit headers. */
static LONGEST
read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf,
const struct comp_unit_head *cu_header,
unsigned int *bytes_read,
unsigned int *offset_size)
{
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->initial_length_size != *bytes_read)
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
*offset_size = (*bytes_read == 4) ? 4 : 8;
return length;
}
/* 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. */
static void
read_formatted_entries (struct dwarf2_per_objfile *dwarf2_per_objfile,
bfd *abfd, const gdb_byte **bufp,
struct line_header *lh,
const struct comp_unit_head *cu_header,
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 *format_header_data;
unsigned int bytes_read;
format_count = read_1_byte (abfd, buf);
buf += 1;
format_header_data = buf;
for (formati = 0; formati < format_count; formati++)
{
read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
}
data_count = read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
for (datai = 0; datai < data_count; datai++)
{
const gdb_byte *format = format_header_data;
struct file_entry fe;
for (formati = 0; formati < format_count; formati++)
{
ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
gdb::optional<const char *> string;
gdb::optional<unsigned int> uint;
switch (form)
{
case DW_FORM_string:
string.emplace (read_direct_string (abfd, buf, &bytes_read));
buf += bytes_read;
break;
case DW_FORM_line_strp:
string.emplace
(dwarf2_per_objfile->read_line_string (buf,
cu_header,
&bytes_read));
buf += bytes_read;
break;
case DW_FORM_data1:
uint.emplace (read_1_byte (abfd, buf));
buf += 1;
break;
case DW_FORM_data2:
uint.emplace (read_2_bytes (abfd, buf));
buf += 2;
break;
case DW_FORM_data4:
uint.emplace (read_4_bytes (abfd, buf));
buf += 4;
break;
case DW_FORM_data8:
uint.emplace (read_8_bytes (abfd, buf));
buf += 8;
break;
case DW_FORM_data16:
/* This is used for MD5, but file_entry does not record MD5s. */
buf += 16;
break;
case DW_FORM_udata:
uint.emplace (read_unsigned_leb128 (abfd, buf, &bytes_read));
buf += bytes_read;
break;
case DW_FORM_block:
/* It is valid only for DW_LNCT_timestamp which is ignored by
current GDB. */
break;
}
switch (content_type)
{
case DW_LNCT_path:
if (string.has_value ())
fe.name = *string;
break;
case DW_LNCT_directory_index:
if (uint.has_value ())
fe.d_index = (dir_index) *uint;
break;
case DW_LNCT_timestamp:
if (uint.has_value ())
fe.mod_time = *uint;
break;
case DW_LNCT_size:
if (uint.has_value ())
fe.length = *uint;
break;
case DW_LNCT_MD5:
break;
default:
complaint (_("Unknown format content type %s"),
pulongest (content_type));
}
}
callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
}
*bufp = buf;
}
/* See line-header.h. */
line_header_up
dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
struct dwarf2_per_objfile *dwarf2_per_objfile,
struct dwarf2_section_info *section,
const struct comp_unit_head *cu_header)
{
const gdb_byte *line_ptr;
unsigned int bytes_read, offset_size;
int i;
const char *cur_dir, *cur_file;
bfd *abfd = section->get_bfd_owner ();
/* 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)
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
return 0;
}
line_header_up lh (new line_header ());
lh->sect_off = sect_off;
lh->offset_in_dwz = is_dwz;
line_ptr = section->buffer + to_underlying (sect_off);
/* Read in the header. */
lh->total_length =
read_checked_initial_length_and_offset (abfd, line_ptr, cu_header,
&bytes_read, &offset_size);
line_ptr += bytes_read;
const gdb_byte *start_here = line_ptr;
if (line_ptr + lh->total_length > (section->buffer + section->size))
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
return 0;
}
lh->statement_program_end = start_here + lh->total_length;
lh->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
if (lh->version > 5)
{
/* 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;
}
if (lh->version >= 5)
{
gdb_byte segment_selector_size;
/* Skip address size. */
read_1_byte (abfd, line_ptr);
line_ptr += 1;
segment_selector_size = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (segment_selector_size != 0)
{
complaint (_("unsupported segment selector size %u "
"in .debug_line section"),
segment_selector_size);
return NULL;
}
}
lh->header_length = read_offset (abfd, line_ptr, offset_size);
line_ptr += offset_size;
lh->statement_program_start = line_ptr + lh->header_length;
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (lh->version >= 4)
{
lh->maximum_ops_per_instruction = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
else
lh->maximum_ops_per_instruction = 1;
if (lh->maximum_ops_per_instruction == 0)
{
lh->maximum_ops_per_instruction = 1;
complaint (_("invalid maximum_ops_per_instruction "
"in `.debug_line' section"));
}
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. */
for (i = 1; i < lh->opcode_base; ++i)
{
lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
if (lh->version >= 5)
{
/* Read directory table. */
read_formatted_entries (dwarf2_per_objfile, abfd, &line_ptr, lh.get (),
cu_header,
[] (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 (dwarf2_per_objfile, abfd, &line_ptr, lh.get (),
cu_header,
[] (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);
});
}
else
{
/* Read directory table. */
while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
lh->add_include_dir (cur_dir);
}
line_ptr += bytes_read;
/* Read file name table. */
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
unsigned int mod_time, length;
dir_index d_index;
line_ptr += bytes_read;
d_index = (dir_index) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
lh->add_file_name (cur_file, d_index, mod_time, length);
}
line_ptr += bytes_read;
}
if (line_ptr > (section->buffer + section->size))
complaint (_("line number info header doesn't "
"fit in `.debug_line' section"));
return lh;
}

View File

@ -195,4 +195,18 @@ file_entry::include_dir (const line_header *lh) const
return lh->include_dir_at (d_index);
}
/* Read the statement program header starting at SECT_OFF in SECTION.
Return line_header. Returns nullptr if there is a problem reading
the header, e.g., if it has a version we don't understand.
NOTE: the strings in the include directory and file name tables of
the returned object point into the dwarf line section buffer,
and must not be freed. */
extern line_header_up dwarf_decode_line_header
(sect_offset sect_off, bool is_dwz,
struct dwarf2_per_objfile *dwarf2_per_objfile,
struct dwarf2_section_info *section,
const struct comp_unit_head *cu_header);
#endif /* DWARF2_LINE_HEADER_H */

View File

@ -1239,10 +1239,6 @@ static void read_attribute_reprocess (const struct die_reader_specs *reader,
static CORE_ADDR read_addr_index (struct dwarf2_cu *cu, unsigned int addr_index);
static LONGEST read_checked_initial_length_and_offset
(bfd *, const gdb_byte *, const struct comp_unit_head *,
unsigned int *, unsigned int *);
static sect_offset read_abbrev_offset
(struct dwarf2_per_objfile *dwarf2_per_objfile,
struct dwarf2_section_info *, sect_offset);
@ -1673,12 +1669,6 @@ static void free_line_header_voidp (void *arg);
/* Various complaints about symbol reading that don't abort the process. */
static void
dwarf2_statement_list_fits_in_line_number_section_complaint (void)
{
complaint (_("statement list doesn't fit in .debug_line section"));
}
static void
dwarf2_debug_line_missing_file_complaint (void)
{
@ -18730,33 +18720,6 @@ read_attribute (const struct die_reader_specs *reader,
need_reprocess);
}
/* Cover function for read_initial_length.
Returns the length of the object at BUF, and stores the size of the
initial length in *BYTES_READ and stores the size that offsets will be in
*OFFSET_SIZE.
If the initial length size is not equivalent to that specified in
CU_HEADER then issue a complaint.
This is useful when reading non-comp-unit headers. */
static LONGEST
read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf,
const struct comp_unit_head *cu_header,
unsigned int *bytes_read,
unsigned int *offset_size)
{
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->initial_length_size != *bytes_read)
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
*offset_size = (*bytes_read == 4) ? 4 : 8;
return length;
}
/* Return pointer to string at .debug_str offset STR_OFFSET. */
static const char *
@ -19217,140 +19180,6 @@ get_debug_line_section (struct dwarf2_cu *cu)
return section;
}
/* 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. */
static void
read_formatted_entries (struct dwarf2_per_objfile *dwarf2_per_objfile,
bfd *abfd, const gdb_byte **bufp,
struct line_header *lh,
const struct comp_unit_head *cu_header,
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 *format_header_data;
unsigned int bytes_read;
format_count = read_1_byte (abfd, buf);
buf += 1;
format_header_data = buf;
for (formati = 0; formati < format_count; formati++)
{
read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
}
data_count = read_unsigned_leb128 (abfd, buf, &bytes_read);
buf += bytes_read;
for (datai = 0; datai < data_count; datai++)
{
const gdb_byte *format = format_header_data;
struct file_entry fe;
for (formati = 0; formati < format_count; formati++)
{
ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
gdb::optional<const char *> string;
gdb::optional<unsigned int> uint;
switch (form)
{
case DW_FORM_string:
string.emplace (read_direct_string (abfd, buf, &bytes_read));
buf += bytes_read;
break;
case DW_FORM_line_strp:
string.emplace
(dwarf2_per_objfile->read_line_string (buf,
cu_header,
&bytes_read));
buf += bytes_read;
break;
case DW_FORM_data1:
uint.emplace (read_1_byte (abfd, buf));
buf += 1;
break;
case DW_FORM_data2:
uint.emplace (read_2_bytes (abfd, buf));
buf += 2;
break;
case DW_FORM_data4:
uint.emplace (read_4_bytes (abfd, buf));
buf += 4;
break;
case DW_FORM_data8:
uint.emplace (read_8_bytes (abfd, buf));
buf += 8;
break;
case DW_FORM_data16:
/* This is used for MD5, but file_entry does not record MD5s. */
buf += 16;
break;
case DW_FORM_udata:
uint.emplace (read_unsigned_leb128 (abfd, buf, &bytes_read));
buf += bytes_read;
break;
case DW_FORM_block:
/* It is valid only for DW_LNCT_timestamp which is ignored by
current GDB. */
break;
}
switch (content_type)
{
case DW_LNCT_path:
if (string.has_value ())
fe.name = *string;
break;
case DW_LNCT_directory_index:
if (uint.has_value ())
fe.d_index = (dir_index) *uint;
break;
case DW_LNCT_timestamp:
if (uint.has_value ())
fe.mod_time = *uint;
break;
case DW_LNCT_size:
if (uint.has_value ())
fe.length = *uint;
break;
case DW_LNCT_MD5:
break;
default:
complaint (_("Unknown format content type %s"),
pulongest (content_type));
}
}
callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
}
*bufp = buf;
}
/* Read the statement program header starting at OFFSET in
.debug_line, or .debug_line.dwo. Return a pointer
to a struct line_header, allocated using xmalloc.
@ -19364,12 +19193,7 @@ read_formatted_entries (struct dwarf2_per_objfile *dwarf2_per_objfile,
static line_header_up
dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu)
{
const gdb_byte *line_ptr;
unsigned int bytes_read, offset_size;
int i;
const char *cur_dir, *cur_file;
struct dwarf2_section_info *section;
bfd *abfd;
struct dwarf2_per_objfile *dwarf2_per_objfile
= cu->per_cu->dwarf2_per_objfile;
@ -19384,159 +19208,9 @@ dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu)
return 0;
}
/* We can't do this until we know the section is non-empty.
Only then do we know we have such a section. */
abfd = section->get_bfd_owner ();
/* 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)
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
return 0;
}
line_header_up lh (new line_header ());
lh->sect_off = sect_off;
lh->offset_in_dwz = cu->per_cu->is_dwz;
line_ptr = section->buffer + to_underlying (sect_off);
/* Read in the header. */
lh->total_length =
read_checked_initial_length_and_offset (abfd, line_ptr, &cu->header,
&bytes_read, &offset_size);
line_ptr += bytes_read;
const gdb_byte *start_here = line_ptr;
if (line_ptr + lh->total_length > (section->buffer + section->size))
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
return 0;
}
lh->statement_program_end = start_here + lh->total_length;
lh->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
if (lh->version > 5)
{
/* 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;
}
if (lh->version >= 5)
{
gdb_byte segment_selector_size;
/* Skip address size. */
read_1_byte (abfd, line_ptr);
line_ptr += 1;
segment_selector_size = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (segment_selector_size != 0)
{
complaint (_("unsupported segment selector size %u "
"in .debug_line section"),
segment_selector_size);
return NULL;
}
}
lh->header_length = read_offset (abfd, line_ptr, offset_size);
line_ptr += offset_size;
lh->statement_program_start = line_ptr + lh->header_length;
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (lh->version >= 4)
{
lh->maximum_ops_per_instruction = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
else
lh->maximum_ops_per_instruction = 1;
if (lh->maximum_ops_per_instruction == 0)
{
lh->maximum_ops_per_instruction = 1;
complaint (_("invalid maximum_ops_per_instruction "
"in `.debug_line' section"));
}
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. */
for (i = 1; i < lh->opcode_base; ++i)
{
lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
if (lh->version >= 5)
{
/* Read directory table. */
read_formatted_entries (dwarf2_per_objfile, abfd, &line_ptr, lh.get (),
&cu->header,
[] (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 (dwarf2_per_objfile, abfd, &line_ptr, lh.get (),
&cu->header,
[] (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);
});
}
else
{
/* Read directory table. */
while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
lh->add_include_dir (cur_dir);
}
line_ptr += bytes_read;
/* Read file name table. */
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
unsigned int mod_time, length;
dir_index d_index;
line_ptr += bytes_read;
d_index = (dir_index) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
lh->add_file_name (cur_file, d_index, mod_time, length);
}
line_ptr += bytes_read;
}
if (line_ptr > (section->buffer + section->size))
complaint (_("line number info header doesn't "
"fit in `.debug_line' section"));
return lh;
return dwarf_decode_line_header (sect_off, cu->per_cu->is_dwz,
dwarf2_per_objfile, section,
&cu->header);
}
/* Subroutine of dwarf_decode_lines to simplify it.