932 lines
27 KiB
Diff
932 lines
27 KiB
Diff
--- binutils.orig/binutils/dwarf.c 2020-10-21 14:15:47.101351869 +0100
|
|
+++ binutils-2.35.1/binutils/dwarf.c 2020-10-21 14:17:44.608585923 +0100
|
|
@@ -1868,7 +1868,7 @@ skip_attr_bytes (unsigned long
|
|
case DW_FORM_ref_addr:
|
|
if (dwarf_version == 2)
|
|
SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
|
|
- else if (dwarf_version == 3 || dwarf_version == 4)
|
|
+ else if (dwarf_version > 2)
|
|
SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
|
|
else
|
|
return NULL;
|
|
@@ -1920,6 +1920,7 @@ skip_attr_bytes (unsigned long
|
|
|
|
case DW_FORM_ref8:
|
|
case DW_FORM_data8:
|
|
+ case DW_FORM_ref_sig8:
|
|
data += 8;
|
|
break;
|
|
|
|
@@ -1934,6 +1935,7 @@ skip_attr_bytes (unsigned long
|
|
case DW_FORM_block:
|
|
case DW_FORM_exprloc:
|
|
READ_ULEB (uvalue, data, end);
|
|
+ data += uvalue;
|
|
break;
|
|
|
|
case DW_FORM_block1:
|
|
@@ -1951,12 +1953,12 @@ skip_attr_bytes (unsigned long
|
|
data += 4 + uvalue;
|
|
break;
|
|
|
|
- case DW_FORM_ref_sig8:
|
|
- data += 8;
|
|
- break;
|
|
-
|
|
case DW_FORM_indirect:
|
|
- /* FIXME: Handle this form. */
|
|
+ READ_ULEB (form, data, end);
|
|
+ if (form == DW_FORM_implicit_const)
|
|
+ SKIP_ULEB (data, end);
|
|
+ return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return);
|
|
+
|
|
default:
|
|
return NULL;
|
|
}
|
|
@@ -1978,7 +1980,7 @@ get_type_signedness (unsigned char *
|
|
dwarf_vma offset_size,
|
|
int dwarf_version,
|
|
bfd_boolean * is_signed,
|
|
- bfd_boolean is_nested)
|
|
+ unsigned int nesting)
|
|
{
|
|
unsigned long abbrev_number;
|
|
abbrev_entry * entry;
|
|
@@ -1997,6 +1999,14 @@ get_type_signedness (unsigned char *
|
|
/* FIXME: Issue a warning ? */
|
|
return;
|
|
|
|
+#define MAX_NESTING 20
|
|
+ if (nesting > MAX_NESTING)
|
|
+ {
|
|
+ /* FIXME: Warn - or is this expected ?
|
|
+ NB/ We need to avoid infinite recursion. */
|
|
+ return;
|
|
+ }
|
|
+
|
|
for (attr = entry->first_attr;
|
|
attr != NULL && attr->attribute;
|
|
attr = attr->next)
|
|
@@ -2019,16 +2029,12 @@ get_type_signedness (unsigned char *
|
|
#endif
|
|
case DW_AT_type:
|
|
/* Recurse. */
|
|
- if (is_nested)
|
|
- {
|
|
- /* FIXME: Warn - or is this expected ?
|
|
- NB/ We need to avoid infinite recursion. */
|
|
- return;
|
|
- }
|
|
if (uvalue >= (size_t) (end - start))
|
|
return;
|
|
- get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
- offset_size, dwarf_version, is_signed, TRUE);
|
|
+ /* We cannot correctly process DW_FORM_ref_addr at the moment. */
|
|
+ if (attr->form != DW_FORM_ref_addr)
|
|
+ get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
+ offset_size, dwarf_version, is_signed, nesting + 1);
|
|
break;
|
|
|
|
case DW_AT_encoding:
|
|
@@ -2206,7 +2212,6 @@ read_and_display_attr_value (unsigned lo
|
|
SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
|
|
else
|
|
error (_("Internal error: DWARF version is not 2, 3 or 4.\n"));
|
|
-
|
|
break;
|
|
|
|
case DW_FORM_addr:
|
|
@@ -2246,8 +2251,8 @@ read_and_display_attr_value (unsigned lo
|
|
uvalue = svalue;
|
|
break;
|
|
|
|
- case DW_FORM_GNU_str_index:
|
|
case DW_FORM_ref_udata:
|
|
+ case DW_FORM_GNU_str_index:
|
|
case DW_FORM_udata:
|
|
case DW_FORM_GNU_addr_index:
|
|
READ_ULEB (uvalue, data, end);
|
|
@@ -2663,8 +2668,10 @@ read_and_display_attr_value (unsigned lo
|
|
{
|
|
bfd_boolean is_signed = FALSE;
|
|
|
|
- get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
- offset_size, dwarf_version, & is_signed, FALSE);
|
|
+ /* We cannot correctly process DW_FORM_ref_addr at the moment. */
|
|
+ if (form != DW_FORM_ref_addr)
|
|
+ get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
+ offset_size, dwarf_version, & is_signed, 0);
|
|
level_type_signed[level] = is_signed;
|
|
}
|
|
break;
|
|
diff -rup binutils.orig/binutils/dwarf.c binutils-2.35.1/binutils/dwarf.c
|
|
--- binutils.orig/binutils/dwarf.c 2020-10-27 16:24:29.489636820 +0000
|
|
+++ binutils-2.35.1/binutils/dwarf.c 2020-10-27 16:24:44.507568083 +0000
|
|
@@ -849,101 +849,204 @@ fetch_indexed_value (dwarf_vma offset, d
|
|
/* FIXME: There are better and more efficient ways to handle
|
|
these structures. For now though, I just want something that
|
|
is simple to implement. */
|
|
+/* Records a single attribute in an abbrev. */
|
|
typedef struct abbrev_attr
|
|
{
|
|
- unsigned long attribute;
|
|
- unsigned long form;
|
|
- bfd_signed_vma implicit_const;
|
|
- struct abbrev_attr *next;
|
|
+ unsigned long attribute;
|
|
+ unsigned long form;
|
|
+ bfd_signed_vma implicit_const;
|
|
+ struct abbrev_attr * next;
|
|
}
|
|
abbrev_attr;
|
|
|
|
+/* Records a single abbrev. */
|
|
typedef struct abbrev_entry
|
|
{
|
|
- unsigned long entry;
|
|
- unsigned long tag;
|
|
- int children;
|
|
- struct abbrev_attr *first_attr;
|
|
- struct abbrev_attr *last_attr;
|
|
- struct abbrev_entry *next;
|
|
+ unsigned long number;
|
|
+ unsigned long tag;
|
|
+ int children;
|
|
+ struct abbrev_attr * first_attr;
|
|
+ struct abbrev_attr * last_attr;
|
|
+ struct abbrev_entry * next;
|
|
}
|
|
abbrev_entry;
|
|
|
|
-static abbrev_entry *first_abbrev = NULL;
|
|
-static abbrev_entry *last_abbrev = NULL;
|
|
+/* Records a set of abbreviations. */
|
|
+typedef struct abbrev_list
|
|
+{
|
|
+ abbrev_entry * first_abbrev;
|
|
+ abbrev_entry * last_abbrev;
|
|
+ dwarf_vma abbrev_offset;
|
|
+ struct abbrev_list * next;
|
|
+ unsigned char * start_of_next_abbrevs;
|
|
+}
|
|
+abbrev_list;
|
|
+
|
|
+/* Records all the abbrevs found so far. */
|
|
+static struct abbrev_list * abbrev_lists = NULL;
|
|
+
|
|
+typedef struct abbrev_map
|
|
+{
|
|
+ dwarf_vma start;
|
|
+ dwarf_vma end;
|
|
+ abbrev_list * list;
|
|
+} abbrev_map;
|
|
+
|
|
+/* Maps between CU offsets and abbrev sets. */
|
|
+static abbrev_map * cu_abbrev_map = NULL;
|
|
+static unsigned long num_abbrev_map_entries = 0;
|
|
+static unsigned long next_free_abbrev_map_entry = 0;
|
|
+
|
|
+#define INITIAL_NUM_ABBREV_MAP_ENTRIES 8
|
|
+#define ABBREV_MAP_ENTRIES_INCREMENT 8
|
|
+
|
|
+static void
|
|
+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
|
|
+{
|
|
+ if (cu_abbrev_map == NULL)
|
|
+ {
|
|
+ num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
|
|
+ cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map));
|
|
+ }
|
|
+ else if (next_free_abbrev_map_entry == num_abbrev_map_entries)
|
|
+ {
|
|
+ num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT;
|
|
+ cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map));
|
|
+ }
|
|
+
|
|
+ cu_abbrev_map[next_free_abbrev_map_entry].start = start;
|
|
+ cu_abbrev_map[next_free_abbrev_map_entry].end = end;
|
|
+ cu_abbrev_map[next_free_abbrev_map_entry].list = list;
|
|
+ next_free_abbrev_map_entry ++;
|
|
+}
|
|
|
|
static void
|
|
-free_abbrevs (void)
|
|
+free_all_abbrevs (void)
|
|
{
|
|
- abbrev_entry *abbrv;
|
|
+ abbrev_list * list;
|
|
|
|
- for (abbrv = first_abbrev; abbrv;)
|
|
+ for (list = abbrev_lists; list != NULL;)
|
|
{
|
|
- abbrev_entry *next_abbrev = abbrv->next;
|
|
- abbrev_attr *attr;
|
|
+ abbrev_list * next = list->next;
|
|
+ abbrev_entry * abbrv;
|
|
|
|
- for (attr = abbrv->first_attr; attr;)
|
|
+ for (abbrv = list->first_abbrev; abbrv != NULL;)
|
|
{
|
|
- abbrev_attr *next_attr = attr->next;
|
|
+ abbrev_entry * next_abbrev = abbrv->next;
|
|
+ abbrev_attr * attr;
|
|
|
|
- free (attr);
|
|
- attr = next_attr;
|
|
+ for (attr = abbrv->first_attr; attr;)
|
|
+ {
|
|
+ abbrev_attr *next_attr = attr->next;
|
|
+
|
|
+ free (attr);
|
|
+ attr = next_attr;
|
|
+ }
|
|
+
|
|
+ free (abbrv);
|
|
+ abbrv = next_abbrev;
|
|
}
|
|
|
|
- free (abbrv);
|
|
- abbrv = next_abbrev;
|
|
+ free (list);
|
|
+ list = next;
|
|
}
|
|
|
|
- last_abbrev = first_abbrev = NULL;
|
|
+ abbrev_lists = NULL;
|
|
+}
|
|
+
|
|
+static abbrev_list *
|
|
+new_abbrev_list (dwarf_vma abbrev_offset)
|
|
+{
|
|
+ abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
|
|
+
|
|
+ list->abbrev_offset = abbrev_offset;
|
|
+
|
|
+ list->next = abbrev_lists;
|
|
+ abbrev_lists = list;
|
|
+
|
|
+ return list;
|
|
+}
|
|
+
|
|
+static abbrev_list *
|
|
+find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_offset)
|
|
+{
|
|
+ abbrev_list * list;
|
|
+
|
|
+ for (list = abbrev_lists; list != NULL; list = list->next)
|
|
+ if (list->abbrev_offset == abbrev_offset)
|
|
+ return list;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Find the abbreviation map for the CU that includes OFFSET.
|
|
+ OFFSET is an absolute offset from the start of the .debug_info section. */
|
|
+/* FIXME: This function is going to slow down readelf & objdump.
|
|
+ Consider using a better algorithm to mitigate this effect. */
|
|
+
|
|
+static abbrev_map *
|
|
+find_abbrev_map_by_offset (dwarf_vma offset)
|
|
+{
|
|
+ unsigned long i;
|
|
+
|
|
+ for (i = 0; i < next_free_abbrev_map_entry; i++)
|
|
+ if (cu_abbrev_map[i].start <= offset
|
|
+ && cu_abbrev_map[i].end > offset)
|
|
+ return cu_abbrev_map + i;
|
|
+
|
|
+ return NULL;
|
|
}
|
|
|
|
static void
|
|
-add_abbrev (unsigned long number, unsigned long tag, int children)
|
|
+add_abbrev (unsigned long number,
|
|
+ unsigned long tag,
|
|
+ int children,
|
|
+ abbrev_list * list)
|
|
{
|
|
- abbrev_entry *entry;
|
|
+ abbrev_entry * entry;
|
|
|
|
- entry = (abbrev_entry *) malloc (sizeof (*entry));
|
|
- if (entry == NULL)
|
|
- /* ugg */
|
|
- return;
|
|
+ entry = (abbrev_entry *) xmalloc (sizeof (*entry));
|
|
|
|
- entry->entry = number;
|
|
+ entry->number = number;
|
|
entry->tag = tag;
|
|
entry->children = children;
|
|
entry->first_attr = NULL;
|
|
entry->last_attr = NULL;
|
|
entry->next = NULL;
|
|
|
|
- if (first_abbrev == NULL)
|
|
- first_abbrev = entry;
|
|
+ assert (list != NULL);
|
|
+
|
|
+ if (list->first_abbrev == NULL)
|
|
+ list->first_abbrev = entry;
|
|
else
|
|
- last_abbrev->next = entry;
|
|
+ list->last_abbrev->next = entry;
|
|
|
|
- last_abbrev = entry;
|
|
+ list->last_abbrev = entry;
|
|
}
|
|
|
|
static void
|
|
-add_abbrev_attr (unsigned long attribute, unsigned long form,
|
|
- bfd_signed_vma implicit_const)
|
|
+add_abbrev_attr (unsigned long attribute,
|
|
+ unsigned long form,
|
|
+ bfd_signed_vma implicit_const,
|
|
+ abbrev_list * list)
|
|
{
|
|
abbrev_attr *attr;
|
|
|
|
- attr = (abbrev_attr *) malloc (sizeof (*attr));
|
|
- if (attr == NULL)
|
|
- /* ugg */
|
|
- return;
|
|
+ attr = (abbrev_attr *) xmalloc (sizeof (*attr));
|
|
|
|
attr->attribute = attribute;
|
|
attr->form = form;
|
|
attr->implicit_const = implicit_const;
|
|
attr->next = NULL;
|
|
|
|
- if (last_abbrev->first_attr == NULL)
|
|
- last_abbrev->first_attr = attr;
|
|
+ assert (list != NULL && list->last_abbrev != NULL);
|
|
+
|
|
+ if (list->last_abbrev->first_attr == NULL)
|
|
+ list->last_abbrev->first_attr = attr;
|
|
else
|
|
- last_abbrev->last_attr->next = attr;
|
|
+ list->last_abbrev->last_attr->next = attr;
|
|
|
|
- last_abbrev->last_attr = attr;
|
|
+ list->last_abbrev->last_attr = attr;
|
|
}
|
|
|
|
/* Processes the (partial) contents of a .debug_abbrev section.
|
|
@@ -952,11 +1055,10 @@ add_abbrev_attr (unsigned long attribute
|
|
an abbreviation set was found. */
|
|
|
|
static unsigned char *
|
|
-process_abbrev_section (unsigned char *start, unsigned char *end)
|
|
+process_abbrev_set (unsigned char * start,
|
|
+ const unsigned char * end,
|
|
+ abbrev_list * list)
|
|
{
|
|
- if (first_abbrev != NULL)
|
|
- return NULL;
|
|
-
|
|
while (start < end)
|
|
{
|
|
unsigned long entry;
|
|
@@ -966,7 +1068,7 @@ process_abbrev_section (unsigned char *s
|
|
|
|
READ_ULEB (entry, start, end);
|
|
|
|
- /* A single zero is supposed to end the section according
|
|
+ /* A single zero is supposed to end the set according
|
|
to the standard. If there's more, then signal that to
|
|
the caller. */
|
|
if (start == end)
|
|
@@ -980,7 +1082,7 @@ process_abbrev_section (unsigned char *s
|
|
|
|
children = *start++;
|
|
|
|
- add_abbrev (entry, tag, children);
|
|
+ add_abbrev (entry, tag, children, list);
|
|
|
|
do
|
|
{
|
|
@@ -1003,7 +1105,7 @@ process_abbrev_section (unsigned char *s
|
|
break;
|
|
}
|
|
|
|
- add_abbrev_attr (attribute, form, implicit_const);
|
|
+ add_abbrev_attr (attribute, form, implicit_const, list);
|
|
}
|
|
while (attribute != 0);
|
|
}
|
|
@@ -1969,36 +2071,123 @@ skip_attr_bytes (unsigned long
|
|
return data;
|
|
}
|
|
|
|
-/* Return IS_SIGNED set to TRUE if the type at
|
|
- DATA can be determined to be a signed type. */
|
|
+/* Given form FORM with value UVALUE, locate and return the abbreviation
|
|
+ associated with it. */
|
|
+
|
|
+static abbrev_entry *
|
|
+get_type_abbrev_from_form (unsigned long form,
|
|
+ unsigned long uvalue,
|
|
+ dwarf_vma cu_offset,
|
|
+ const struct dwarf_section * section,
|
|
+ unsigned long * abbrev_num_return,
|
|
+ unsigned char ** data_return,
|
|
+ unsigned long * cu_offset_return)
|
|
+{
|
|
+ unsigned long abbrev_number;
|
|
+ abbrev_map * map;
|
|
+ abbrev_entry * entry;
|
|
+ unsigned char * data;
|
|
+
|
|
+ if (abbrev_num_return != NULL)
|
|
+ * abbrev_num_return = 0;
|
|
+ if (data_return != NULL)
|
|
+ * data_return = NULL;
|
|
+
|
|
+ switch (form)
|
|
+ {
|
|
+ case DW_FORM_GNU_ref_alt:
|
|
+ /* FIXME: We are unable to handle this form at the moment. */
|
|
+ return NULL;
|
|
+
|
|
+ case DW_FORM_ref_addr:
|
|
+ if (uvalue >= section->size)
|
|
+ {
|
|
+ warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"),
|
|
+ uvalue, (long) section->size, section->name);
|
|
+ return NULL;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DW_FORM_ref1:
|
|
+ case DW_FORM_ref2:
|
|
+ case DW_FORM_ref4:
|
|
+ case DW_FORM_ref_udata:
|
|
+ if (uvalue + cu_offset > section->size)
|
|
+ {
|
|
+ warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"),
|
|
+ uvalue, (long) cu_offset, (long) section->size);
|
|
+ return NULL;
|
|
+ }
|
|
+ uvalue += cu_offset;
|
|
+ break;
|
|
+
|
|
+ /* FIXME: Are there other DW_FORMs that can be used by types ? */
|
|
+
|
|
+ default:
|
|
+ warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ data = (unsigned char *) section->start + uvalue;
|
|
+ map = find_abbrev_map_by_offset (uvalue);
|
|
+
|
|
+ if (map == NULL)
|
|
+ {
|
|
+ warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue);
|
|
+ return NULL;
|
|
+ }
|
|
+ if (map->list == NULL)
|
|
+ {
|
|
+ warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (cu_offset_return != NULL)
|
|
+ {
|
|
+ if (form == DW_FORM_ref_addr)
|
|
+ * cu_offset_return = map->start;
|
|
+ else
|
|
+ * cu_offset_return = cu_offset;
|
|
+ }
|
|
+
|
|
+ READ_ULEB (abbrev_number, data, section->start + section->size);
|
|
+
|
|
+ for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
|
|
+ if (entry->number == abbrev_number)
|
|
+ break;
|
|
+
|
|
+ if (abbrev_num_return != NULL)
|
|
+ * abbrev_num_return = abbrev_number;
|
|
+
|
|
+ if (data_return != NULL)
|
|
+ * data_return = data;
|
|
+
|
|
+ if (entry == NULL)
|
|
+ warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number);
|
|
+
|
|
+ return entry;
|
|
+}
|
|
+
|
|
+/* Return IS_SIGNED set to TRUE if the type using abbreviation ENTRY
|
|
+ can be determined to be a signed type. The data for ENTRY can be
|
|
+ found starting at DATA. */
|
|
|
|
static void
|
|
-get_type_signedness (unsigned char * start,
|
|
+get_type_signedness (abbrev_entry * entry,
|
|
+ const struct dwarf_section * section,
|
|
unsigned char * data,
|
|
unsigned const char * end,
|
|
+ dwarf_vma cu_offset,
|
|
dwarf_vma pointer_size,
|
|
dwarf_vma offset_size,
|
|
int dwarf_version,
|
|
bfd_boolean * is_signed,
|
|
unsigned int nesting)
|
|
{
|
|
- unsigned long abbrev_number;
|
|
- abbrev_entry * entry;
|
|
abbrev_attr * attr;
|
|
|
|
* is_signed = FALSE;
|
|
|
|
- READ_ULEB (abbrev_number, data, end);
|
|
-
|
|
- for (entry = first_abbrev;
|
|
- entry != NULL && entry->entry != abbrev_number;
|
|
- entry = entry->next)
|
|
- continue;
|
|
-
|
|
- if (entry == NULL)
|
|
- /* FIXME: Issue a warning ? */
|
|
- return;
|
|
-
|
|
#define MAX_NESTING 20
|
|
if (nesting > MAX_NESTING)
|
|
{
|
|
@@ -2011,6 +2200,7 @@ get_type_signedness (unsigned char *
|
|
attr != NULL && attr->attribute;
|
|
attr = attr->next)
|
|
{
|
|
+ unsigned char * orig_data = data;
|
|
dwarf_vma uvalue = 0;
|
|
|
|
data = skip_attr_bytes (attr->form, data, end, pointer_size,
|
|
@@ -2020,21 +2210,38 @@ get_type_signedness (unsigned char *
|
|
|
|
switch (attr->attribute)
|
|
{
|
|
-#if 0 /* FIXME: It would be nice to print the name of the type,
|
|
- but this would mean updating a lot of binutils tests. */
|
|
+ case DW_AT_linkage_name:
|
|
case DW_AT_name:
|
|
- if (attr->form == DW_FORM_strp)
|
|
- printf ("%s", fetch_indirect_string (uvalue));
|
|
+ if (do_wide)
|
|
+ {
|
|
+ if (attr->form == DW_FORM_strp)
|
|
+ printf (", %s", fetch_indirect_string (uvalue));
|
|
+ else if (attr->form == DW_FORM_string)
|
|
+ printf (", %s", orig_data);
|
|
+ }
|
|
break;
|
|
-#endif
|
|
+
|
|
case DW_AT_type:
|
|
/* Recurse. */
|
|
- if (uvalue >= (size_t) (end - start))
|
|
- return;
|
|
- /* We cannot correctly process DW_FORM_ref_addr at the moment. */
|
|
- if (attr->form != DW_FORM_ref_addr)
|
|
- get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
- offset_size, dwarf_version, is_signed, nesting + 1);
|
|
+ {
|
|
+ abbrev_entry * type_abbrev;
|
|
+ unsigned char * type_data;
|
|
+ unsigned long type_cu_offset;
|
|
+
|
|
+ type_abbrev = get_type_abbrev_from_form (attr->form,
|
|
+ uvalue,
|
|
+ cu_offset,
|
|
+ section,
|
|
+ NULL /* abbrev num return */,
|
|
+ & type_data,
|
|
+ & type_cu_offset);
|
|
+ if (type_abbrev == NULL)
|
|
+ break;
|
|
+
|
|
+ get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
|
|
+ pointer_size, offset_size, dwarf_version,
|
|
+ is_signed, nesting + 1);
|
|
+ }
|
|
break;
|
|
|
|
case DW_AT_encoding:
|
|
@@ -2276,12 +2483,12 @@ read_and_display_attr_value (unsigned lo
|
|
{
|
|
case DW_FORM_ref_addr:
|
|
if (!do_loc)
|
|
- printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
|
|
+ printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
|
|
break;
|
|
|
|
case DW_FORM_GNU_ref_alt:
|
|
if (!do_loc)
|
|
- printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
|
|
+ printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
|
|
/* FIXME: Follow the reference... */
|
|
break;
|
|
|
|
@@ -2667,11 +2874,18 @@ read_and_display_attr_value (unsigned lo
|
|
&& uvalue < (size_t) (end - start))
|
|
{
|
|
bfd_boolean is_signed = FALSE;
|
|
-
|
|
- /* We cannot correctly process DW_FORM_ref_addr at the moment. */
|
|
- if (form != DW_FORM_ref_addr)
|
|
- get_type_signedness (start, start + uvalue, end, pointer_size,
|
|
- offset_size, dwarf_version, & is_signed, 0);
|
|
+ abbrev_entry * type_abbrev;
|
|
+ unsigned char * type_data;
|
|
+ unsigned long type_cu_offset;
|
|
+
|
|
+ type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset,
|
|
+ section, NULL, & type_data, & type_cu_offset);
|
|
+ if (type_abbrev != NULL)
|
|
+ {
|
|
+ get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
|
|
+ pointer_size, offset_size, dwarf_version,
|
|
+ & is_signed, 0);
|
|
+ }
|
|
level_type_signed[level] = is_signed;
|
|
}
|
|
break;
|
|
@@ -2993,40 +3207,22 @@ read_and_display_attr_value (unsigned lo
|
|
|
|
case DW_AT_import:
|
|
{
|
|
- if (form == DW_FORM_ref_sig8
|
|
- || form == DW_FORM_GNU_ref_alt)
|
|
- break;
|
|
-
|
|
- if (form == DW_FORM_ref1
|
|
- || form == DW_FORM_ref2
|
|
- || form == DW_FORM_ref4
|
|
- || form == DW_FORM_ref_udata)
|
|
- uvalue += cu_offset;
|
|
+ unsigned long abbrev_number;
|
|
+ abbrev_entry *entry;
|
|
|
|
- if (uvalue >= section->size)
|
|
- warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
|
|
- dwarf_vmatoa ("x", uvalue),
|
|
- (unsigned long) (orig_data - section->start));
|
|
+ entry = get_type_abbrev_from_form (form, uvalue, cu_offset,
|
|
+ section, & abbrev_number, NULL, NULL);
|
|
+ if (entry == NULL)
|
|
+ {
|
|
+ if (form != DW_FORM_GNU_ref_alt)
|
|
+ warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
|
|
+ dwarf_vmatoa ("x", uvalue),
|
|
+ (unsigned long) (orig_data - section->start));
|
|
+ }
|
|
else
|
|
{
|
|
- unsigned long abbrev_number;
|
|
- abbrev_entry *entry;
|
|
- unsigned char *p = section->start + uvalue;
|
|
-
|
|
- READ_ULEB (abbrev_number, p, end);
|
|
-
|
|
printf (_("\t[Abbrev Number: %ld"), abbrev_number);
|
|
- /* Don't look up abbrev for DW_FORM_ref_addr, as it very often will
|
|
- use different abbrev table, and we don't track .debug_info chunks
|
|
- yet. */
|
|
- if (form != DW_FORM_ref_addr)
|
|
- {
|
|
- for (entry = first_abbrev; entry != NULL; entry = entry->next)
|
|
- if (entry->entry == abbrev_number)
|
|
- break;
|
|
- if (entry != NULL)
|
|
- printf (" (%s)", get_TAG_name (entry->tag));
|
|
- }
|
|
+ printf (" (%s)", get_TAG_name (entry->tag));
|
|
printf ("]");
|
|
}
|
|
}
|
|
@@ -3245,8 +3441,98 @@ process_debug_info (struct dwarf_section
|
|
|
|
if (!do_loc && dwarf_start_die == 0)
|
|
introduce (section, FALSE);
|
|
+
|
|
+ free_all_abbrevs ();
|
|
+ free (cu_abbrev_map);
|
|
+ cu_abbrev_map = NULL;
|
|
+ next_free_abbrev_map_entry = 0;
|
|
|
|
- for (section_begin = start, unit = 0; start < end; unit++)
|
|
+ /* In order to be able to resolve DW_FORM_ref_attr forms we need
|
|
+ to load *all* of the abbrevs for all CUs in this .debug_info
|
|
+ section. This does effectively mean that we (partially) read
|
|
+ every CU header twice. */
|
|
+ for (section_begin = start; start < end;)
|
|
+ {
|
|
+ DWARF2_Internal_CompUnit compunit;
|
|
+ unsigned char * hdrptr;
|
|
+ dwarf_vma cu_offset;
|
|
+ unsigned int offset_size;
|
|
+ unsigned int initial_length_size;
|
|
+ struct cu_tu_set * this_set;
|
|
+ abbrev_list * list;
|
|
+
|
|
+ hdrptr = start;
|
|
+
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
|
|
+
|
|
+ if (compunit.cu_length == 0xffffffff)
|
|
+ {
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end);
|
|
+ offset_size = 8;
|
|
+ initial_length_size = 12;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ offset_size = 4;
|
|
+ initial_length_size = 4;
|
|
+ }
|
|
+
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end);
|
|
+
|
|
+ cu_offset = start - section_begin;
|
|
+
|
|
+ this_set = find_cu_tu_set_v2 (cu_offset, do_types);
|
|
+
|
|
+ if (compunit.cu_version < 5)
|
|
+ {
|
|
+ compunit.cu_unit_type = DW_UT_compile;
|
|
+ /* Initialize it due to a false compiler warning. */
|
|
+ compunit.cu_pointer_size = -1;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
|
|
+ do_types = (compunit.cu_unit_type == DW_UT_type);
|
|
+
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
|
|
+ }
|
|
+
|
|
+ SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
|
|
+
|
|
+ list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset);
|
|
+ if (list == NULL)
|
|
+ {
|
|
+ dwarf_vma abbrev_base;
|
|
+ size_t abbrev_size;
|
|
+ unsigned char * next;
|
|
+
|
|
+ if (this_set == NULL)
|
|
+ {
|
|
+ abbrev_base = 0;
|
|
+ abbrev_size = debug_displays [abbrev_sec].section.size;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ abbrev_base = this_set->section_offsets [DW_SECT_ABBREV];
|
|
+ abbrev_size = this_set->section_sizes [DW_SECT_ABBREV];
|
|
+ }
|
|
+
|
|
+ list = new_abbrev_list (compunit.cu_abbrev_offset);
|
|
+ next = process_abbrev_set
|
|
+ (((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
+ + abbrev_base + compunit.cu_abbrev_offset),
|
|
+ ((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
+ + abbrev_base + abbrev_size),
|
|
+ list);
|
|
+ list->start_of_next_abbrevs = next;
|
|
+ }
|
|
+
|
|
+ start = section_begin + cu_offset + compunit.cu_length
|
|
+ + initial_length_size;
|
|
+ record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
|
|
+ }
|
|
+
|
|
+ for (start = section_begin, unit = 0; start < end; unit++)
|
|
{
|
|
DWARF2_Internal_CompUnit compunit;
|
|
unsigned char *hdrptr;
|
|
@@ -3262,6 +3548,7 @@ process_debug_info (struct dwarf_section
|
|
struct cu_tu_set *this_set;
|
|
dwarf_vma abbrev_base;
|
|
size_t abbrev_size;
|
|
+ abbrev_list * list = NULL;
|
|
|
|
hdrptr = start;
|
|
|
|
@@ -3434,8 +3721,6 @@ process_debug_info (struct dwarf_section
|
|
continue;
|
|
}
|
|
|
|
- free_abbrevs ();
|
|
-
|
|
/* Process the abbrevs used by this compilation unit. */
|
|
if (compunit.cu_abbrev_offset >= abbrev_size)
|
|
warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
|
|
@@ -3448,11 +3733,22 @@ process_debug_info (struct dwarf_section
|
|
(unsigned long) abbrev_base + abbrev_size,
|
|
(unsigned long) debug_displays [abbrev_sec].section.size);
|
|
else
|
|
- process_abbrev_section
|
|
- (((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
- + abbrev_base + compunit.cu_abbrev_offset),
|
|
- ((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
- + abbrev_base + abbrev_size));
|
|
+ {
|
|
+ list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset);
|
|
+ if (list == NULL)
|
|
+ {
|
|
+ unsigned char * next;
|
|
+
|
|
+ list = new_abbrev_list (compunit.cu_abbrev_offset);
|
|
+ next = process_abbrev_set
|
|
+ (((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
+ + abbrev_base + compunit.cu_abbrev_offset),
|
|
+ ((unsigned char *) debug_displays [abbrev_sec].section.start
|
|
+ + abbrev_base + abbrev_size),
|
|
+ list);
|
|
+ list->start_of_next_abbrevs = next;
|
|
+ }
|
|
+ }
|
|
|
|
level = 0;
|
|
last_level = level;
|
|
@@ -3532,11 +3828,13 @@ process_debug_info (struct dwarf_section
|
|
|
|
/* Scan through the abbreviation list until we reach the
|
|
correct entry. */
|
|
- for (entry = first_abbrev;
|
|
- entry && entry->entry != abbrev_number;
|
|
- entry = entry->next)
|
|
+ if (list == NULL)
|
|
continue;
|
|
|
|
+ for (entry = list->first_abbrev; entry != NULL; entry = entry->next)
|
|
+ if (entry->number == abbrev_number)
|
|
+ break;
|
|
+
|
|
if (entry == NULL)
|
|
{
|
|
if (!do_loc && do_printing)
|
|
@@ -5721,30 +6019,37 @@ display_debug_abbrev (struct dwarf_secti
|
|
{
|
|
abbrev_entry *entry;
|
|
unsigned char *start = section->start;
|
|
- unsigned char *end = start + section->size;
|
|
+ const unsigned char *end = start + section->size;
|
|
|
|
introduce (section, FALSE);
|
|
|
|
do
|
|
{
|
|
- unsigned char *last;
|
|
-
|
|
- free_abbrevs ();
|
|
+ abbrev_list * list;
|
|
+ dwarf_vma offset;
|
|
|
|
- last = start;
|
|
- start = process_abbrev_section (start, end);
|
|
+ offset = start - section->start;
|
|
+ list = find_abbrev_list_by_abbrev_offset (offset);
|
|
+ if (list == NULL)
|
|
+ {
|
|
+ list = new_abbrev_list (offset);
|
|
+ start = process_abbrev_set (start, end, list);
|
|
+ list->start_of_next_abbrevs = start;
|
|
+ }
|
|
+ else
|
|
+ start = list->start_of_next_abbrevs;
|
|
|
|
- if (first_abbrev == NULL)
|
|
+ if (list->first_abbrev == NULL)
|
|
continue;
|
|
|
|
- printf (_(" Number TAG (0x%lx)\n"), (long) (last - section->start));
|
|
+ printf (_(" Number TAG (0x%lx)\n"), (long) offset);
|
|
|
|
- for (entry = first_abbrev; entry; entry = entry->next)
|
|
+ for (entry = list->first_abbrev; entry; entry = entry->next)
|
|
{
|
|
abbrev_attr *attr;
|
|
|
|
printf (" %ld %s [%s]\n",
|
|
- entry->entry,
|
|
+ entry->number,
|
|
get_TAG_name (entry->tag),
|
|
entry->children ? _("has children") : _("no children"));
|
|
|
|
@@ -10776,8 +11081,12 @@ free_debug_memory (void)
|
|
{
|
|
unsigned int i;
|
|
|
|
- free_abbrevs ();
|
|
+ free_all_abbrevs ();
|
|
|
|
+ free (cu_abbrev_map);
|
|
+ cu_abbrev_map = NULL;
|
|
+ next_free_abbrev_map_entry = 0;
|
|
+
|
|
for (i = 0; i < max; i++)
|
|
free_debug_section ((enum dwarf_section_display_enum) i);
|
|
|
|
Only in binutils-2.35.1/binutils: dwarf.c.orig
|