diff options
-rw-r--r-- | gdb/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/dwarf2read.c | 187 |
2 files changed, 177 insertions, 16 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8ae0ed2..2c5fb08 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,11 @@ 2004-03-09 Daniel Jacobowitz <drow@mvista.com> + * dwarf2read.c (skip_leb128, peek_die_abbrev, skip_one_die) + (skip_children): New functions. + (locate_pdi_sibling): Call skip_children. + +2004-03-09 Daniel Jacobowitz <drow@mvista.com> + * arm-tdep.c (arm_use_struct_convention): Look through typedefs. * gdbtypes.c (check_typedef): Update comments. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index ffc18e5..ffc76c8 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -734,6 +734,8 @@ static unsigned long read_unsigned_leb128 (bfd *, char *, unsigned int *); static long read_signed_leb128 (bfd *, char *, unsigned int *); +static char *skip_leb128 (bfd *, char *); + static void set_cu_language (unsigned int, struct dwarf2_cu *); static struct attribute *dwarf2_attr (struct die_info *, unsigned int, @@ -937,6 +939,9 @@ static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); +static char *skip_one_die (char *info_ptr, struct abbrev_info *abbrev, + struct dwarf2_cu *cu); + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ @@ -1765,8 +1770,154 @@ add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr, return info_ptr; } -/* Locate ORIG_PDI's sibling; INFO_PTR should point to the next DIE - after ORIG_PDI. */ +/* Read the initial uleb128 in the die at INFO_PTR in compilation unit CU. + Return the corresponding abbrev, or NULL if the number is zero (indicating + an empty DIE). In either case *BYTES_READ will be set to the length of + the initial number. */ + +static struct abbrev_info * +peek_die_abbrev (char *info_ptr, int *bytes_read, struct dwarf2_cu *cu) +{ + bfd *abfd = cu->objfile->obfd; + unsigned int abbrev_number; + struct abbrev_info *abbrev; + + abbrev_number = read_unsigned_leb128 (abfd, info_ptr, bytes_read); + + if (abbrev_number == 0) + return NULL; + + abbrev = dwarf2_lookup_abbrev (abbrev_number, cu); + if (!abbrev) + { + error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number, + bfd_get_filename (abfd)); + } + + return abbrev; +} + +/* Scan the debug information for CU starting at INFO_PTR. Returns a + pointer to the end of a series of DIEs, terminated by an empty + DIE. Any children of the skipped DIEs will also be skipped. */ + +static char * +skip_children (char *info_ptr, struct dwarf2_cu *cu) +{ + struct abbrev_info *abbrev; + unsigned int bytes_read; + + while (1) + { + abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu); + if (abbrev == NULL) + return info_ptr + bytes_read; + else + info_ptr = skip_one_die (info_ptr + bytes_read, abbrev, cu); + } +} + +/* Scan the debug information for CU starting at INFO_PTR. INFO_PTR + should point just after the initial uleb128 of a DIE, and the + abbrev corresponding to that skipped uleb128 should be passed in + ABBREV. Returns a pointer to this DIE's sibling, skipping any + children. */ + +static char * +skip_one_die (char *info_ptr, struct abbrev_info *abbrev, + struct dwarf2_cu *cu) +{ + unsigned int bytes_read; + struct attribute attr; + bfd *abfd = cu->objfile->obfd; + unsigned int form, i; + + for (i = 0; i < abbrev->num_attrs; i++) + { + /* The only abbrev we care about is DW_AT_sibling. */ + if (abbrev->attrs[i].name == DW_AT_sibling) + { + read_attribute (&attr, &abbrev->attrs[i], + abfd, info_ptr, cu); + if (attr.form == DW_FORM_ref_addr) + complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling"); + else + return dwarf_info_buffer + dwarf2_get_ref_die_offset (&attr, cu); + } + + /* If it isn't DW_AT_sibling, skip this attribute. */ + form = abbrev->attrs[i].form; + skip_attribute: + switch (form) + { + case DW_FORM_addr: + case DW_FORM_ref_addr: + info_ptr += cu->header.addr_size; + break; + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_flag: + info_ptr += 1; + break; + case DW_FORM_data2: + case DW_FORM_ref2: + info_ptr += 2; + break; + case DW_FORM_data4: + case DW_FORM_ref4: + info_ptr += 4; + break; + case DW_FORM_data8: + case DW_FORM_ref8: + info_ptr += 8; + break; + case DW_FORM_string: + read_string (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_strp: + info_ptr += cu->header.offset_size; + break; + case DW_FORM_block: + info_ptr += read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_block1: + info_ptr += 1 + read_1_byte (abfd, info_ptr); + break; + case DW_FORM_block2: + info_ptr += 2 + read_2_bytes (abfd, info_ptr); + break; + case DW_FORM_block4: + info_ptr += 4 + read_4_bytes (abfd, info_ptr); + break; + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + info_ptr = skip_leb128 (abfd, info_ptr); + break; + case DW_FORM_indirect: + form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + /* We need to continue parsing from here, so just go back to + the top. */ + goto skip_attribute; + + default: + error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]", + dwarf_form_name (form), + bfd_get_filename (abfd)); + } + } + + if (abbrev->has_children) + return skip_children (info_ptr, cu); + else + return info_ptr; +} + +/* Locate ORIG_PDI's sibling; INFO_PTR should point to the start of + the next DIE after ORIG_PDI. */ static char * locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr, @@ -1782,21 +1933,9 @@ locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr, if (!orig_pdi->has_children) return info_ptr; - /* Okay, we don't know the sibling, but we have children that we - want to skip. So read children until we run into one without a - tag; return whatever follows it. */ - - while (1) - { - struct partial_die_info pdi; - - info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu); + /* Skip the children the long way. */ - if (pdi.tag == 0) - return info_ptr; - else - info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu); - } + return skip_children (info_ptr, cu); } /* Expand this partial symbol table into a full symbol table. */ @@ -4950,6 +5089,22 @@ read_signed_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) return result; } +/* Return a pointer to just past the end of an LEB128 number in BUF. */ + +static char * +skip_leb128 (bfd *abfd, char *buf) +{ + int byte; + + while (1) + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf++; + if ((byte & 128) == 0) + return buf; + } +} + static void set_cu_language (unsigned int lang, struct dwarf2_cu *cu) { |