mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-30 23:40:24 +00:00
* dwarf2read.c (read_cutu_die_from_dwo): New function.
(lookup_dwo_unit): New function. (init_cutu_and_read_dies): Move DWO handling to new functions.
This commit is contained in:
parent
c88ee1f032
commit
b0c7bfa934
@ -1,5 +1,9 @@
|
||||
2013-03-29 Doug Evans <dje@google.com>
|
||||
|
||||
* dwarf2read.c (read_cutu_die_from_dwo): New function.
|
||||
(lookup_dwo_unit): New function.
|
||||
(init_cutu_and_read_dies): Move DWO handling to new functions.
|
||||
|
||||
* dwarf2read.c (struct signatured_type): Tweak comment.
|
||||
(struct dwo_unit): Tweak comment.
|
||||
(create_debug_types_hash_table): Tweak comment. Reformat long line.
|
||||
|
397
gdb/dwarf2read.c
397
gdb/dwarf2read.c
@ -4435,6 +4435,232 @@ init_cu_die_reader (struct die_reader_specs *reader,
|
||||
reader->buffer_end = section->buffer + section->size;
|
||||
}
|
||||
|
||||
/* Subroutine of init_cutu_and_read_dies to simplify it.
|
||||
Read in the rest of a CU/TU top level DIE from DWO_UNIT.
|
||||
There's just a lot of work to do, and init_cutu_and_read_dies is big enough
|
||||
already.
|
||||
|
||||
STUB_COMP_UNIT_DIE is for the stub DIE, we copy over certain attributes
|
||||
from it to the DIE in the DWO. If NULL we are skipping the stub.
|
||||
*RESULT_READER,*RESULT_INFO_PTR,*RESULT_COMP_UNIT_DIE,*RESULT_HAS_CHILDREN
|
||||
are filled in with the info of the DIE from the DWO file.
|
||||
ABBREV_TABLE_PROVIDED is non-zero if the caller of init_cutu_and_read_dies
|
||||
provided an abbrev table to use.
|
||||
The result is non-zero if a valid (non-dummy) DIE was found. */
|
||||
|
||||
static int
|
||||
read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu,
|
||||
struct dwo_unit *dwo_unit,
|
||||
int abbrev_table_provided,
|
||||
struct die_info *stub_comp_unit_die,
|
||||
struct die_reader_specs *result_reader,
|
||||
gdb_byte **result_info_ptr,
|
||||
struct die_info **result_comp_unit_die,
|
||||
int *result_has_children)
|
||||
{
|
||||
struct objfile *objfile = dwarf2_per_objfile->objfile;
|
||||
struct dwarf2_cu *cu = this_cu->cu;
|
||||
struct dwarf2_section_info *section;
|
||||
bfd *abfd;
|
||||
gdb_byte *begin_info_ptr, *info_ptr;
|
||||
const char *comp_dir_string;
|
||||
ULONGEST signature; /* Or dwo_id. */
|
||||
struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges;
|
||||
int i,num_extra_attrs;
|
||||
struct dwarf2_section_info *dwo_abbrev_section;
|
||||
struct attribute *attr;
|
||||
struct die_info *comp_unit_die;
|
||||
|
||||
/* These attributes aren't processed until later:
|
||||
DW_AT_stmt_list, DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges.
|
||||
However, the attribute is found in the stub which we won't have later.
|
||||
In order to not impose this complication on the rest of the code,
|
||||
we read them here and copy them to the DWO CU/TU die. */
|
||||
|
||||
stmt_list = NULL;
|
||||
low_pc = NULL;
|
||||
high_pc = NULL;
|
||||
ranges = NULL;
|
||||
comp_dir = NULL;
|
||||
|
||||
if (stub_comp_unit_die != NULL)
|
||||
{
|
||||
/* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the
|
||||
DWO file. */
|
||||
if (! this_cu->is_debug_types)
|
||||
stmt_list = dwarf2_attr (stub_comp_unit_die, DW_AT_stmt_list, cu);
|
||||
low_pc = dwarf2_attr (stub_comp_unit_die, DW_AT_low_pc, cu);
|
||||
high_pc = dwarf2_attr (stub_comp_unit_die, DW_AT_high_pc, cu);
|
||||
ranges = dwarf2_attr (stub_comp_unit_die, DW_AT_ranges, cu);
|
||||
comp_dir = dwarf2_attr (stub_comp_unit_die, DW_AT_comp_dir, cu);
|
||||
|
||||
/* There should be a DW_AT_addr_base attribute here (if needed).
|
||||
We need the value before we can process DW_FORM_GNU_addr_index. */
|
||||
cu->addr_base = 0;
|
||||
attr = dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_addr_base, cu);
|
||||
if (attr)
|
||||
cu->addr_base = DW_UNSND (attr);
|
||||
|
||||
/* There should be a DW_AT_ranges_base attribute here (if needed).
|
||||
We need the value before we can process DW_AT_ranges. */
|
||||
cu->ranges_base = 0;
|
||||
attr = dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_ranges_base, cu);
|
||||
if (attr)
|
||||
cu->ranges_base = DW_UNSND (attr);
|
||||
}
|
||||
|
||||
/* Set up for reading the DWO CU/TU. */
|
||||
cu->dwo_unit = dwo_unit;
|
||||
section = dwo_unit->section;
|
||||
dwarf2_read_section (objfile, section);
|
||||
abfd = section->asection->owner;
|
||||
begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off;
|
||||
dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev;
|
||||
init_cu_die_reader (result_reader, cu, section, dwo_unit->dwo_file);
|
||||
|
||||
if (this_cu->is_debug_types)
|
||||
{
|
||||
ULONGEST header_signature;
|
||||
cu_offset type_offset_in_tu;
|
||||
struct signatured_type *sig_type = (struct signatured_type *) this_cu;
|
||||
|
||||
info_ptr = read_and_check_type_unit_head (&cu->header, section,
|
||||
dwo_abbrev_section,
|
||||
info_ptr,
|
||||
&header_signature,
|
||||
&type_offset_in_tu);
|
||||
gdb_assert (sig_type->signature == header_signature);
|
||||
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
|
||||
/* For DWOs coming from DWP files, we don't know the CU length
|
||||
nor the type's offset in the TU until now. */
|
||||
dwo_unit->length = get_cu_length (&cu->header);
|
||||
dwo_unit->type_offset_in_tu = type_offset_in_tu;
|
||||
|
||||
/* Establish the type offset that can be used to lookup the type.
|
||||
For DWO files, we don't know it until now. */
|
||||
sig_type->type_offset_in_section.sect_off =
|
||||
dwo_unit->offset.sect_off + dwo_unit->type_offset_in_tu.cu_off;
|
||||
}
|
||||
else
|
||||
{
|
||||
info_ptr = read_and_check_comp_unit_head (&cu->header, section,
|
||||
dwo_abbrev_section,
|
||||
info_ptr, 0);
|
||||
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
|
||||
/* For DWOs coming from DWP files, we don't know the CU length
|
||||
until now. */
|
||||
dwo_unit->length = get_cu_length (&cu->header);
|
||||
}
|
||||
|
||||
/* Replace the CU's original abbrev table with the DWO's. */
|
||||
if (abbrev_table_provided)
|
||||
{
|
||||
/* Don't free the provided abbrev table, the caller of
|
||||
init_cutu_and_read_dies owns it. */
|
||||
dwarf2_read_abbrevs (cu, dwo_abbrev_section);
|
||||
make_cleanup (dwarf2_free_abbrev_table, cu);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarf2_free_abbrev_table (cu);
|
||||
dwarf2_read_abbrevs (cu, dwo_abbrev_section);
|
||||
}
|
||||
|
||||
/* Read in the die, but leave space to copy over the attributes
|
||||
from the stub. This has the benefit of simplifying the rest of
|
||||
the code - all the work to maintain the illusion of a single
|
||||
DW_TAG_{compile,type}_unit DIE is done here. */
|
||||
num_extra_attrs = ((stmt_list != NULL)
|
||||
+ (low_pc != NULL)
|
||||
+ (high_pc != NULL)
|
||||
+ (ranges != NULL)
|
||||
+ (comp_dir != NULL));
|
||||
info_ptr = read_full_die_1 (result_reader, result_comp_unit_die, info_ptr,
|
||||
result_has_children, num_extra_attrs);
|
||||
|
||||
/* Copy over the attributes from the stub to the DIE we just read in. */
|
||||
comp_unit_die = *result_comp_unit_die;
|
||||
i = comp_unit_die->num_attrs;
|
||||
if (stmt_list != NULL)
|
||||
comp_unit_die->attrs[i++] = *stmt_list;
|
||||
if (low_pc != NULL)
|
||||
comp_unit_die->attrs[i++] = *low_pc;
|
||||
if (high_pc != NULL)
|
||||
comp_unit_die->attrs[i++] = *high_pc;
|
||||
if (ranges != NULL)
|
||||
comp_unit_die->attrs[i++] = *ranges;
|
||||
if (comp_dir != NULL)
|
||||
comp_unit_die->attrs[i++] = *comp_dir;
|
||||
comp_unit_die->num_attrs += num_extra_attrs;
|
||||
|
||||
/* Skip dummy compilation units. */
|
||||
if (info_ptr >= begin_info_ptr + dwo_unit->length
|
||||
|| peek_abbrev_code (abfd, info_ptr) == 0)
|
||||
return 0;
|
||||
|
||||
*result_info_ptr = info_ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Subroutine of init_cutu_and_read_dies to simplify it.
|
||||
Look up the DWO unit specified by COMP_UNIT_DIE of THIS_CU.
|
||||
If the specified DWO unit cannot be found an error is thrown. */
|
||||
|
||||
static struct dwo_unit *
|
||||
lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu,
|
||||
struct die_info *comp_unit_die)
|
||||
{
|
||||
struct dwarf2_cu *cu = this_cu->cu;
|
||||
struct attribute *attr;
|
||||
ULONGEST signature;
|
||||
struct dwo_unit *dwo_unit;
|
||||
const char *comp_dir, *dwo_name;
|
||||
|
||||
/* Yeah, we look dwo_name up again, but it simplifies the code. */
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_name, cu);
|
||||
gdb_assert (attr != NULL);
|
||||
dwo_name = DW_STRING (attr);
|
||||
comp_dir = NULL;
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu);
|
||||
if (attr)
|
||||
comp_dir = DW_STRING (attr);
|
||||
|
||||
if (this_cu->is_debug_types)
|
||||
{
|
||||
struct signatured_type *sig_type;
|
||||
|
||||
/* Since this_cu is the first member of struct signatured_type,
|
||||
we can go from a pointer to one to a pointer to the other. */
|
||||
sig_type = (struct signatured_type *) this_cu;
|
||||
signature = sig_type->signature;
|
||||
dwo_unit = lookup_dwo_type_unit (sig_type, dwo_name, comp_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct attribute *attr;
|
||||
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);
|
||||
if (! attr)
|
||||
error (_("Dwarf Error: missing dwo_id for dwo_name %s"
|
||||
" [in module %s]"),
|
||||
dwo_name, this_cu->objfile->name);
|
||||
signature = DW_UNSND (attr);
|
||||
dwo_unit = lookup_dwo_comp_unit (this_cu, dwo_name, comp_dir,
|
||||
signature);
|
||||
}
|
||||
|
||||
if (dwo_unit == NULL)
|
||||
{
|
||||
error (_("Dwarf Error: CU at offset 0x%x references unknown DWO"
|
||||
" with ID %s [in module %s]"),
|
||||
this_cu->offset.sect_off,
|
||||
phex (signature, sizeof (signature)),
|
||||
this_cu->objfile->name);
|
||||
}
|
||||
|
||||
return dwo_unit;
|
||||
}
|
||||
|
||||
/* Initialize a CU (or TU) and read its DIEs.
|
||||
If the CU defers to a DWO file, read the DWO file as well.
|
||||
|
||||
@ -4517,6 +4743,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
|
||||
free_cu_cleanup = make_cleanup (free_heap_comp_unit, cu);
|
||||
}
|
||||
|
||||
/* Get the header. */
|
||||
if (cu->header.first_die_offset.cu_off != 0 && ! rereading_dwo_cu)
|
||||
{
|
||||
/* We already have the header, there's no need to read it in again. */
|
||||
@ -4596,178 +4823,38 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
|
||||
init_cu_die_reader (&reader, cu, section, NULL);
|
||||
info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children);
|
||||
|
||||
/* If we have a DWO stub, process it and then read in the DWO file.
|
||||
Note that if USE_EXISTING_OK != 0, and THIS_CU->cu already contains
|
||||
a DWO CU, that this test will fail. */
|
||||
/* If we are in a DWO stub, process it and then read in the "real" CU/TU
|
||||
from the DWO file.
|
||||
Note that if USE_EXISTING_OK != 0, and THIS_CU->cu already contains a
|
||||
DWO CU, that this test will fail (the attribute will not be present). */
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_name, cu);
|
||||
if (attr)
|
||||
{
|
||||
const char *dwo_name = DW_STRING (attr);
|
||||
const char *comp_dir_string;
|
||||
struct dwo_unit *dwo_unit;
|
||||
ULONGEST signature; /* Or dwo_id. */
|
||||
struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges;
|
||||
int i,num_extra_attrs;
|
||||
struct dwarf2_section_info *dwo_abbrev_section;
|
||||
struct die_info *dwo_comp_unit_die;
|
||||
|
||||
if (has_children)
|
||||
error (_("Dwarf Error: compilation unit with DW_AT_GNU_dwo_name"
|
||||
" has children (offset 0x%x) [in module %s]"),
|
||||
this_cu->offset.sect_off, bfd_get_filename (abfd));
|
||||
|
||||
/* These attributes aren't processed until later:
|
||||
DW_AT_stmt_list, DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges.
|
||||
However, the attribute is found in the stub which we won't have later.
|
||||
In order to not impose this complication on the rest of the code,
|
||||
we read them here and copy them to the DWO CU/TU die. */
|
||||
|
||||
/* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the
|
||||
DWO file. */
|
||||
stmt_list = NULL;
|
||||
if (! this_cu->is_debug_types)
|
||||
stmt_list = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
|
||||
low_pc = dwarf2_attr (comp_unit_die, DW_AT_low_pc, cu);
|
||||
high_pc = dwarf2_attr (comp_unit_die, DW_AT_high_pc, cu);
|
||||
ranges = dwarf2_attr (comp_unit_die, DW_AT_ranges, cu);
|
||||
comp_dir = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu);
|
||||
|
||||
/* There should be a DW_AT_addr_base attribute here (if needed).
|
||||
We need the value before we can process DW_FORM_GNU_addr_index. */
|
||||
cu->addr_base = 0;
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_addr_base, cu);
|
||||
if (attr)
|
||||
cu->addr_base = DW_UNSND (attr);
|
||||
|
||||
/* There should be a DW_AT_ranges_base attribute here (if needed).
|
||||
We need the value before we can process DW_AT_ranges. */
|
||||
cu->ranges_base = 0;
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_ranges_base, cu);
|
||||
if (attr)
|
||||
cu->ranges_base = DW_UNSND (attr);
|
||||
|
||||
if (this_cu->is_debug_types)
|
||||
{
|
||||
gdb_assert (sig_type != NULL);
|
||||
signature = sig_type->signature;
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);
|
||||
if (! attr)
|
||||
error (_("Dwarf Error: missing dwo_id [in module %s]"),
|
||||
dwo_name);
|
||||
signature = DW_UNSND (attr);
|
||||
}
|
||||
|
||||
/* We may need the comp_dir in order to find the DWO file. */
|
||||
comp_dir_string = NULL;
|
||||
if (comp_dir)
|
||||
comp_dir_string = DW_STRING (comp_dir);
|
||||
|
||||
if (this_cu->is_debug_types)
|
||||
dwo_unit = lookup_dwo_type_unit (sig_type, dwo_name, comp_dir_string);
|
||||
else
|
||||
dwo_unit = lookup_dwo_comp_unit (this_cu, dwo_name, comp_dir_string,
|
||||
signature);
|
||||
|
||||
if (dwo_unit == NULL)
|
||||
{
|
||||
error (_("Dwarf Error: CU at offset 0x%x references unknown DWO"
|
||||
" with ID %s [in module %s]"),
|
||||
this_cu->offset.sect_off,
|
||||
phex (signature, sizeof (signature)),
|
||||
objfile->name);
|
||||
}
|
||||
|
||||
/* Set up for reading the DWO CU/TU. */
|
||||
cu->dwo_unit = dwo_unit;
|
||||
section = dwo_unit->section;
|
||||
dwarf2_read_section (objfile, section);
|
||||
begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off;
|
||||
dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev;
|
||||
init_cu_die_reader (&reader, cu, section, dwo_unit->dwo_file);
|
||||
|
||||
if (this_cu->is_debug_types)
|
||||
{
|
||||
ULONGEST signature;
|
||||
cu_offset type_offset_in_tu;
|
||||
|
||||
info_ptr = read_and_check_type_unit_head (&cu->header, section,
|
||||
dwo_abbrev_section,
|
||||
info_ptr,
|
||||
&signature,
|
||||
&type_offset_in_tu);
|
||||
gdb_assert (sig_type->signature == signature);
|
||||
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
|
||||
/* For DWOs coming from DWP files, we don't know the CU length
|
||||
nor the type's offset in the TU until now. */
|
||||
dwo_unit->length = get_cu_length (&cu->header);
|
||||
dwo_unit->type_offset_in_tu = type_offset_in_tu;
|
||||
|
||||
/* Establish the type offset that can be used to lookup the type.
|
||||
For DWO files, we don't know it until now. */
|
||||
sig_type->type_offset_in_section.sect_off =
|
||||
dwo_unit->offset.sect_off + dwo_unit->type_offset_in_tu.cu_off;
|
||||
}
|
||||
else
|
||||
{
|
||||
info_ptr = read_and_check_comp_unit_head (&cu->header, section,
|
||||
dwo_abbrev_section,
|
||||
info_ptr, 0);
|
||||
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
|
||||
/* For DWOs coming from DWP files, we don't know the CU length
|
||||
until now. */
|
||||
dwo_unit->length = get_cu_length (&cu->header);
|
||||
}
|
||||
|
||||
/* Discard the original CU's abbrev table, and read the DWO's. */
|
||||
if (abbrev_table == NULL)
|
||||
{
|
||||
dwarf2_free_abbrev_table (cu);
|
||||
dwarf2_read_abbrevs (cu, dwo_abbrev_section);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarf2_read_abbrevs (cu, dwo_abbrev_section);
|
||||
make_cleanup (dwarf2_free_abbrev_table, cu);
|
||||
}
|
||||
|
||||
/* Read in the die, but leave space to copy over the attributes
|
||||
from the stub. This has the benefit of simplifying the rest of
|
||||
the code - all the real work is done here. */
|
||||
num_extra_attrs = ((stmt_list != NULL)
|
||||
+ (low_pc != NULL)
|
||||
+ (high_pc != NULL)
|
||||
+ (ranges != NULL)
|
||||
+ (comp_dir != NULL));
|
||||
info_ptr = read_full_die_1 (&reader, &comp_unit_die, info_ptr,
|
||||
&has_children, num_extra_attrs);
|
||||
|
||||
/* Copy over the attributes from the stub to the DWO die. */
|
||||
i = comp_unit_die->num_attrs;
|
||||
if (stmt_list != NULL)
|
||||
comp_unit_die->attrs[i++] = *stmt_list;
|
||||
if (low_pc != NULL)
|
||||
comp_unit_die->attrs[i++] = *low_pc;
|
||||
if (high_pc != NULL)
|
||||
comp_unit_die->attrs[i++] = *high_pc;
|
||||
if (ranges != NULL)
|
||||
comp_unit_die->attrs[i++] = *ranges;
|
||||
if (comp_dir != NULL)
|
||||
comp_unit_die->attrs[i++] = *comp_dir;
|
||||
comp_unit_die->num_attrs += num_extra_attrs;
|
||||
|
||||
/* Skip dummy compilation units. */
|
||||
if (info_ptr >= begin_info_ptr + dwo_unit->length
|
||||
|| peek_abbrev_code (abfd, info_ptr) == 0)
|
||||
dwo_unit = lookup_dwo_unit (this_cu, comp_unit_die);
|
||||
if (read_cutu_die_from_dwo (this_cu, dwo_unit,
|
||||
abbrev_table != NULL,
|
||||
comp_unit_die,
|
||||
&reader, &info_ptr,
|
||||
&dwo_comp_unit_die, &has_children) == 0)
|
||||
{
|
||||
/* Dummy die. */
|
||||
do_cleanups (cleanups);
|
||||
return;
|
||||
}
|
||||
comp_unit_die = dwo_comp_unit_die;
|
||||
}
|
||||
|
||||
/* All of the above is setup for this call. Yikes. */
|
||||
die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
|
||||
|
||||
/* Done, clean up. */
|
||||
if (free_cu_cleanup != NULL)
|
||||
{
|
||||
if (keep)
|
||||
|
Loading…
Reference in New Issue
Block a user