/* dwarf.c -- display DWARF contents of a BFD binary file
- Copyright (C) 2005-2020 Free Software Foundation, Inc.
+ Copyright (C) 2005-2021 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include <elfutils/debuginfod.h>
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
#undef MAX
#undef MIN
#define MAX(a, b) ((a) > (b) ? (a) : (b))
{
dwo_type type;
const char * value;
+ dwarf_vma cu_offset;
struct dwo_info * next;
} dwo_info;
int do_debug_frames_interp;
int do_debug_macinfo;
int do_debug_str;
+int do_debug_str_offsets;
int do_debug_loc;
int do_gdb_index;
int do_trace_info;
int do_debug_cu_index;
int do_wide;
int do_debug_links;
-int do_follow_links;
+int do_follow_links = DEFAULT_FOR_FOLLOW_LINKS;
+bfd_boolean do_checks;
int dwarf_cutoff_level = -1;
unsigned long dwarf_start_die;
/* Read in a LEB128 encoded value starting at address DATA.
If SIGN is true, return a signed LEB128 value.
If LENGTH_RETURN is not NULL, return in it the number of bytes read.
- If STATUS_RETURN in not NULL, return with bit 0 (LSB) set if the
+ If STATUS_RETURN is not NULL, return with bit 0 (LSB) set if the
terminating byte was not found and with bit 1 set if the value
overflows a dwarf_vma.
No bytes will be read at address END or beyond. */
while (data < end)
{
unsigned char byte = *data++;
+ unsigned char lost, mask;
+
num_read++;
- if (shift < sizeof (result) * 8)
+ if (shift < CHAR_BIT * sizeof (result))
{
result |= ((dwarf_vma) (byte & 0x7f)) << shift;
- if ((result >> shift) != (byte & 0x7f))
- /* Overflow. */
- status |= 2;
+ /* These bits overflowed. */
+ lost = byte ^ (result >> shift);
+ /* And this is the mask of possible overflow bits. */
+ mask = 0x7f ^ ((dwarf_vma) 0x7f << shift >> shift);
shift += 7;
}
- else if ((byte & 0x7f) != 0)
+ else
+ {
+ lost = byte;
+ mask = 0x7f;
+ }
+ if ((lost & mask) != (sign && (dwarf_signed_vma) result < 0 ? mask : 0))
status |= 2;
if ((byte & 0x80) == 0)
{
status &= ~1;
- if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+ if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
result |= -((dwarf_vma) 1 << shift);
break;
}
ret = (const unsigned char *)
_("<no NUL byte at end of .debug_str section>");
- return ret;
+ return ret;
}
static const unsigned char *
enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
struct dwarf_section *index_section = &debug_displays [idx_sec_idx].section;
struct dwarf_section *str_section = &debug_displays [str_sec_idx].section;
- dwarf_vma index_offset = idx * offset_size;
+ dwarf_vma index_offset;
dwarf_vma str_offset;
const char * ret;
+ unsigned char *curr = index_section->start;
+ const unsigned char *end = curr + index_section->size;
+ dwarf_vma length;
if (index_section->start == NULL)
return (dwo ? _("<no .debug_str_offsets.dwo section>")
: _("<no .debug_str_offsets section>"));
+ if (str_section->start == NULL)
+ return (dwo ? _("<no .debug_str.dwo section>")
+ : _("<no .debug_str section>"));
+
+ /* FIXME: We should cache the length... */
+ SAFE_BYTE_GET_AND_INC (length, curr, 4, end);
+ if (length == 0xffffffff)
+ {
+ if (offset_size != 8)
+ warn (_("Expected offset size of 8 but given %s"), dwarf_vmatoa ("x", offset_size));
+ SAFE_BYTE_GET_AND_INC (length, curr, 8, end);
+ }
+ else if (offset_size != 4)
+ {
+ warn (_("Expected offset size of 4 but given %s"), dwarf_vmatoa ("x", offset_size));
+ }
+
+ if (length == 0)
+ {
+ /* This is probably an old style .debug_str_offset section which
+ just contains offsets and no header (and the first offset is 0). */
+ curr = index_section->start;
+ length = index_section->size;
+ }
+ else
+ {
+ /* Skip the version and padding bytes.
+ We assume that they are correct. */
+ curr += 4;
+
+ /* FIXME: The code below assumes that there is only one table
+ in the .debug_str_offsets section, so check that now. */
+ if ((offset_size == 4 && curr + length < (end - 8))
+ || (offset_size == 8 && curr + length < (end - 16)))
+ {
+ warn (_("index table size is too small %s vs %s\n"),
+ dwarf_vmatoa ("x", length),
+ dwarf_vmatoa ("x", index_section->size));
+ return _("<table too small>");
+ }
+ }
+
+ index_offset = idx * offset_size;
+
if (this_set != NULL)
index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
- if (index_offset >= index_section->size)
+
+ if (index_offset >= length)
{
- warn (_("DW_FORM_GNU_str_index offset too big: %s\n"),
- dwarf_vmatoa ("x", index_offset));
+ warn (_("DW_FORM_GNU_str_index offset too big: %s vs %s\n"),
+ dwarf_vmatoa ("x", index_offset),
+ dwarf_vmatoa ("x", length));
return _("<index offset is too big>");
}
- if (str_section->start == NULL)
- return (dwo ? _("<no .debug_str.dwo section>")
- : _("<no .debug_str section>"));
-
- str_offset = byte_get (index_section->start + index_offset, offset_size);
+ str_offset = byte_get (curr + index_offset, offset_size);
str_offset -= str_section->address;
if (str_offset >= str_section->size)
{
/* 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_base;
+ 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
-free_abbrevs (void)
+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
{
- abbrev_entry *abbrv;
+ 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 ++;
+}
- for (abbrv = first_abbrev; abbrv;)
+static void
+free_all_abbrevs (void)
+{
+ abbrev_list * list;
+
+ 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;
+
+ for (attr = abbrv->first_attr; attr;)
+ {
+ abbrev_attr *next_attr = attr->next;
+
+ free (attr);
+ attr = next_attr;
+ }
- 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_base, dwarf_vma abbrev_offset)
+{
+ abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
+
+ list->abbrev_base = abbrev_base;
+ 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_base,
+ dwarf_vma abbrev_offset)
+{
+ abbrev_list * list;
+
+ for (list = abbrev_lists; list != NULL; list = list->next)
+ if (list->abbrev_base == abbrev_base
+ && 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.
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;
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)
children = *start++;
- add_abbrev (entry, tag, children);
+ add_abbrev (entry, tag, children, list);
do
{
break;
}
- add_abbrev_attr (attribute, form, implicit_const);
+ add_abbrev_attr (attribute, form, implicit_const, list);
}
while (attribute != 0);
}
return ret;
}
-
+
warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"),
dwarf_vmatoa ("x", offset));
return _("<offset is too big>");
}
static void
-add_dwo_info (const char * field, dwo_type type)
+add_dwo_info (const char * value, dwarf_vma cu_offset, dwo_type type)
{
dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
- dwinfo->type = type;
- dwinfo->value = field;
- dwinfo->next = first_dwo_info;
+ dwinfo->type = type;
+ dwinfo->value = value;
+ dwinfo->cu_offset = cu_offset;
+ dwinfo->next = first_dwo_info;
first_dwo_info = dwinfo;
}
static void
-add_dwo_name (const char * name)
+add_dwo_name (const char * name, dwarf_vma cu_offset)
{
- add_dwo_info (name, DWO_NAME);
+ add_dwo_info (name, cu_offset, DWO_NAME);
}
static void
-add_dwo_dir (const char * dir)
+add_dwo_dir (const char * dir, dwarf_vma cu_offset)
{
- add_dwo_info (dir, DWO_DIR);
+ add_dwo_info (dir, cu_offset, DWO_DIR);
}
static void
-add_dwo_id (const char * id)
+add_dwo_id (const char * id, dwarf_vma cu_offset)
{
- add_dwo_info (id, DWO_ID);
+ add_dwo_info (id, cu_offset, DWO_ID);
}
static void
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;
break;
case DW_FORM_ref8:
+ {
+ dwarf_vma high_bits;
+
+ SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
+ data += 8;
+ if (sizeof (uvalue) > 4)
+ uvalue += high_bits << 32;
+ else if (high_bits != 0)
+ {
+ /* FIXME: What to do ? */
+ return NULL;
+ }
+ break;
+ }
+
case DW_FORM_data8:
+ case DW_FORM_ref_sig8:
data += 8;
break;
case DW_FORM_block:
case DW_FORM_exprloc:
READ_ULEB (uvalue, data, end);
+ data += uvalue;
break;
case DW_FORM_block1:
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;
}
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:
+ case DW_FORM_ref_sig8:
+ /* 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_ref8:
+ 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,
- bfd_boolean is_nested)
+ 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)
+ {
+ /* 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)
{
+ unsigned char * orig_data = data;
dwarf_vma uvalue = 0;
data = skip_attr_bytes (attr->form, data, end, pointer_size,
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 (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);
+ {
+ 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:
printf ("[default]");
return;
}
-
+
switch (form)
{
case DW_FORM_block:
bfd_boolean is_signed =
(level > 0 && level <= MAX_CU_NESTING)
? level_type_signed [level - 1] : FALSE;
-
+
printf ("(");
while (uvalue)
{
return data;
}
+ if (do_wide && ! do_loc)
+ {
+ /* PR 26847: Display the name of the form. */
+ const char * name = get_FORM_name (form);
+
+ /* For convenience we skip the DW_FORM_ prefix to the name. */
+ if (name[0] == 'D')
+ name += 8; /* strlen ("DW_FORM_") */
+ printf ("%c(%s)", delimiter, name);
+ }
+
switch (form)
{
default:
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
- error (_("Internal error: DWARF version is not 2, 3 or 4.\n"));
-
+ error (_("Internal error: DW_FORM_ref_addr is not supported in DWARF version 1.\n"));
break;
case DW_FORM_addr:
{
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));
+ {
+ if (do_wide)
+ /* We have already printed the form name. */
+ printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
+ else
+ printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
+ }
/* FIXME: Follow the reference... */
break;
case DW_FORM_strp:
if (!do_loc)
- printf (_("%c(indirect string, offset: 0x%s): %s"), delimiter,
- dwarf_vmatoa ("x", uvalue),
- fetch_indirect_string (uvalue));
+ {
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf (_("%c(offset: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indirect_string (uvalue));
+ else
+ printf (_("%c(indirect string, offset: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indirect_string (uvalue));
+ }
break;
case DW_FORM_line_strp:
if (!do_loc)
- printf (_("%c(indirect line string, offset: 0x%s): %s"), delimiter,
- dwarf_vmatoa ("x", uvalue),
- fetch_indirect_line_string (uvalue));
+ {
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf (_("%c(offset: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indirect_line_string (uvalue));
+ else
+ printf (_("%c(indirect line string, offset: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indirect_line_string (uvalue));
+ }
break;
case DW_FORM_GNU_str_index:
const char * suffix = strrchr (section->name, '.');
bfd_boolean dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? TRUE : FALSE;
- printf (_("%c(indexed string: 0x%s): %s"), delimiter,
- dwarf_vmatoa ("x", uvalue),
- fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf (_("%c(offset: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+ else
+ printf (_("%c(indexed string: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indexed_string (uvalue, this_set, offset_size, dwo));
}
break;
case DW_FORM_GNU_strp_alt:
if (!do_loc)
{
- printf (_("%c(alt indirect string, offset: 0x%s) %s"), delimiter,
- dwarf_vmatoa ("x", uvalue),
- fetch_alt_indirect_string (uvalue));
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf (_("%c(offset: 0x%s) %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_alt_indirect_string (uvalue));
+ else
+ printf (_("%c(alt indirect string, offset: 0x%s) %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_alt_indirect_string (uvalue));
}
break;
char buf[64];
SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
- printf ("%csignature: 0x%s", delimiter,
- dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf ("%c: 0x%s", delimiter,
+ dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
+ else
+ printf ("%csignature: 0x%s", delimiter,
+ dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
}
data += 8;
break;
case DW_FORM_GNU_addr_index:
if (!do_loc)
- printf (_("%c(addr_index: 0x%s): %s"), delimiter,
- dwarf_vmatoa ("x", uvalue),
- fetch_indexed_value (uvalue * pointer_size, pointer_size));
+ {
+ if (do_wide)
+ /* We have already displayed the form name. */
+ printf (_("%c(index: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indexed_value (uvalue * pointer_size, pointer_size));
+ else
+ printf (_("%c(addr_index: 0x%s): %s"), delimiter,
+ dwarf_vmatoa ("x", uvalue),
+ fetch_indexed_value (uvalue * pointer_size, pointer_size));
+ }
break;
default:
switch (form)
{
case DW_FORM_strp:
- add_dwo_name ((const char *) fetch_indirect_string (uvalue));
+ add_dwo_name ((const char *) fetch_indirect_string (uvalue), cu_offset);
+ break;
+ case DW_FORM_GNU_strp_alt:
+ add_dwo_name ((const char *) fetch_alt_indirect_string (uvalue), cu_offset);
break;
case DW_FORM_GNU_str_index:
- add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
+ add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE), cu_offset);
break;
case DW_FORM_string:
- add_dwo_name ((const char *) orig_data);
+ add_dwo_name ((const char *) orig_data, cu_offset);
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
break;
}
break;
-
+
case DW_AT_comp_dir:
/* FIXME: Also extract a build-id in a CU/TU. */
if (need_dwo_info)
switch (form)
{
case DW_FORM_strp:
- add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
+ add_dwo_dir ((const char *) fetch_indirect_string (uvalue), cu_offset);
+ break;
+ case DW_FORM_GNU_strp_alt:
+ add_dwo_dir (fetch_alt_indirect_string (uvalue), cu_offset);
break;
case DW_FORM_line_strp:
- add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
+ add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue), cu_offset);
break;
case DW_FORM_GNU_str_index:
- add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
+ add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE), cu_offset);
break;
case DW_FORM_string:
- add_dwo_dir ((const char *) orig_data);
+ add_dwo_dir ((const char *) orig_data, cu_offset);
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
break;
}
break;
-
+
case DW_AT_GNU_dwo_id:
if (need_dwo_info)
switch (form)
{
case DW_FORM_data8:
/* FIXME: Record the length of the ID as well ? */
- add_dwo_id ((const char *) (data - 8));
+ add_dwo_id ((const char *) (data - 8), cu_offset);
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
break;
}
break;
-
+
default:
break;
}
&& uvalue < (size_t) (end - start))
{
bfd_boolean is_signed = FALSE;
+ abbrev_entry * type_abbrev;
+ unsigned char * type_data;
+ unsigned long type_cu_offset;
- get_type_signedness (start, start + uvalue, end, pointer_size,
- offset_size, dwarf_version, & is_signed, FALSE);
+ 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;
-
+
case DW_AT_inline:
printf ("\t");
switch (uvalue)
printf ("\t");
display_discr_list (form, uvalue, data, end, level);
break;
-
+
case DW_AT_frame_base:
have_frame_base = 1;
/* Fall through. */
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 ("]");
}
}
printf (_("Contents of the %s section:\n\n"), section->name);
}
}
-
+
/* Process the contents of a .debug_info section.
If do_loc is TRUE then we are scanning for location lists and dwo tags
and we do not want to display anything to the user.
if (!do_loc && dwarf_start_die == 0)
introduce (section, FALSE);
-
- for (section_begin = start, unit = 0; start < end; unit++)
+
+ free_all_abbrevs ();
+ free (cu_abbrev_map);
+ cu_abbrev_map = NULL;
+ next_free_abbrev_map_entry = 0;
+
+ /* 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 abbrev_base;
+ size_t abbrev_size;
+ 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);
+
+ if (compunit.cu_unit_type == DW_UT_split_compile
+ || compunit.cu_unit_type == DW_UT_skeleton)
+ {
+ uint64_t dwo_id;
+ SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end);
+ }
+
+ 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 = find_abbrev_list_by_abbrev_offset (abbrev_base,
+ compunit.cu_abbrev_offset);
+ if (list == NULL)
+ {
+ unsigned char * next;
+
+ list = new_abbrev_list (abbrev_base,
+ 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;
struct cu_tu_set *this_set;
dwarf_vma abbrev_base;
size_t abbrev_size;
+ abbrev_list * list = NULL;
hdrptr = start;
if (compunit.cu_version < 5)
SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
+ bfd_boolean do_dwo_id = FALSE;
+ uint64_t dwo_id = 0;
+ if (compunit.cu_unit_type == DW_UT_split_compile
+ || compunit.cu_unit_type == DW_UT_skeleton)
+ {
+ SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end);
+ do_dwo_id = TRUE;
+ }
+
/* PR 17512: file: 001-108546-0.001:0.1. */
if (compunit.cu_pointer_size < 2 || compunit.cu_pointer_size > 8)
{
if ((do_loc || do_debug_loc || do_debug_ranges)
&& num_debug_info_entries == 0
+ && alloc_num_debug_info_entries > unit
&& ! do_types)
{
debug_information [unit].cu_offset = cu_offset;
dwarf_vmatoa ("x", compunit.cu_length),
offset_size == 8 ? "64-bit" : "32-bit");
printf (_(" Version: %d\n"), compunit.cu_version);
+ if (compunit.cu_version >= 5)
+ printf (_(" Unit Type: %s (%x)\n"),
+ get_DW_UT_name (compunit.cu_unit_type) ?: "???",
+ compunit.cu_unit_type);
printf (_(" Abbrev Offset: 0x%s\n"),
dwarf_vmatoa ("x", compunit.cu_abbrev_offset));
printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
printf (_(" Type Offset: 0x%s\n"),
dwarf_vmatoa ("x", type_offset));
}
+ if (do_dwo_id)
+ printf (_(" DWO ID: 0x%s\n"), dwarf_vmatoa ("x", dwo_id));
if (this_set != NULL)
{
dwarf_vma *offsets = this_set->section_offsets;
}
if (compunit.cu_unit_type != DW_UT_compile
- && compunit.cu_unit_type != DW_UT_type)
+ && compunit.cu_unit_type != DW_UT_partial
+ && compunit.cu_unit_type != DW_UT_type
+ && compunit.cu_unit_type != DW_UT_split_compile
+ && compunit.cu_unit_type != DW_UT_skeleton)
{
warn (_("CU at offset %s contains corrupt or "
"unsupported unit type: %d.\n"),
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"),
(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 (abbrev_base,
+ compunit.cu_abbrev_offset);
+ if (list == NULL)
+ {
+ unsigned char * next;
+
+ list = new_abbrev_list (abbrev_base,
+ 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;
/* 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)
dwarf_vma data_count, datai;
unsigned int namepass, last_entry = 0;
const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");
-
+
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 5)
+ warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
+ table_name, format_count);
+
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
}
READ_ULEB (data_count, data, end);
- if (data == end)
+ if (data_count == 0)
{
- warn (_("%s: Corrupt entry count\n"), table_name);
+ printf (_("\n The %s is empty.\n"), table_name);
return data;
}
-
- if (data_count == 0)
+ else if (data == end)
{
- printf (_("\n The %s is empty.\n"), table_name);
+ warn (_("%s: Corrupt entry count - expected %s but none found\n"),
+ table_name, dwarf_vmatoa ("x", data_count));
return data;
}
+
else if (format_count == 0)
{
warn (_("%s: format count is zero, but the table is not empty\n"),
format_count);
printf (_(" Entry"));
- /* Delay displaying name as the last entry for better screen layout. */
+ /* Delay displaying name as the last entry for better screen layout. */
for (namepass = 0; namepass < 2; namepass++)
{
format = format_start;
unsigned char *datapass = data;
printf (" %d", last_entry++);
- /* Delay displaying name as the last entry for better screen layout. */
+ /* Delay displaying name as the last entry for better screen layout. */
for (namepass = 0; namepass < 2; namepass++)
{
format = format_start;
/* Skip directories format. */
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 1)
+ warn (_("Unexpectedly large number of columns in the directory name table (%u)\n"),
+ format_count);
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
break;
}
- directory_table = (unsigned char **)
- xmalloc (n_directories * sizeof (unsigned char *));
+ if (n_directories == 0)
+ directory_table = NULL;
+ else
+ directory_table = (unsigned char **)
+ xmalloc (n_directories * sizeof (unsigned char *));
for (entryi = 0; entryi < n_directories; entryi++)
{
/* Skip files format. */
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 5)
+ warn (_("Unexpectedly large number of columns in the file name table (%u)\n"),
+ format_count);
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
}
READ_ULEB (n_files, data, end);
- if (data == end)
+ if (data == end && n_files > 0)
{
warn (_("Corrupt file name list\n"));
break;
}
- file_table = (File_Entry *) xcalloc (1, n_files
- * sizeof (File_Entry));
+ if (n_files == 0)
+ file_table = NULL;
+ else
+ file_table = (File_Entry *) xcalloc (1, n_files
+ * sizeof (File_Entry));
for (entryi = 0; entryi < n_files; entryi++)
{
/* Print the Compilation Unit's name and a header. */
if (file_table == NULL)
- ;
+ printf (_("CU: No directory table\n"));
else if (directory_table == NULL)
printf (_("CU: %s:\n"), file_table[0].name);
else
printf ("%s:\n", file_table[0].name);
}
- printf (_("File name Line number Starting address View Stmt\n"));
+ if (n_files > 0)
+ printf (_("File name Line number Starting address View Stmt\n"));
+ else
+ printf (_("CU: Empty file name table\n"));
saved_linfo = linfo;
}
strncpy (newFileName, fileName, fileNameLength + 1);
}
+ /* A row with end_seq set to true has a meaningful address, but
+ the other information in the same row is not significant.
+ In such a row, print line as "-", and don't print
+ view/is_stmt. */
if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH))
{
if (linfo.li_max_ops_per_insn == 1)
- printf ("%-35s %11d %#18" DWARF_VMA_FMT "x",
- newFileName, state_machine_regs.line,
- state_machine_regs.address);
+ {
+ if (xop == -DW_LNE_end_sequence)
+ printf ("%-35s %11s %#18" DWARF_VMA_FMT "x",
+ newFileName, "-",
+ state_machine_regs.address);
+ else
+ printf ("%-35s %11d %#18" DWARF_VMA_FMT "x",
+ newFileName, state_machine_regs.line,
+ state_machine_regs.address);
+ }
else
- printf ("%-35s %11d %#18" DWARF_VMA_FMT "x[%d]",
- newFileName, state_machine_regs.line,
- state_machine_regs.address,
- state_machine_regs.op_index);
+ {
+ if (xop == -DW_LNE_end_sequence)
+ printf ("%-35s %11s %#18" DWARF_VMA_FMT "x[%d]",
+ newFileName, "-",
+ state_machine_regs.address,
+ state_machine_regs.op_index);
+ else
+ printf ("%-35s %11d %#18" DWARF_VMA_FMT "x[%d]",
+ newFileName, state_machine_regs.line,
+ state_machine_regs.address,
+ state_machine_regs.op_index);
+ }
}
else
{
if (linfo.li_max_ops_per_insn == 1)
- printf ("%s %11d %#18" DWARF_VMA_FMT "x",
- newFileName, state_machine_regs.line,
- state_machine_regs.address);
+ {
+ if (xop == -DW_LNE_end_sequence)
+ printf ("%s %11s %#18" DWARF_VMA_FMT "x",
+ newFileName, "-",
+ state_machine_regs.address);
+ else
+ printf ("%s %11d %#18" DWARF_VMA_FMT "x",
+ newFileName, state_machine_regs.line,
+ state_machine_regs.address);
+ }
else
- printf ("%s %11d %#18" DWARF_VMA_FMT "x[%d]",
- newFileName, state_machine_regs.line,
- state_machine_regs.address,
- state_machine_regs.op_index);
+ {
+ if (xop == -DW_LNE_end_sequence)
+ printf ("%s %11s %#18" DWARF_VMA_FMT "x[%d]",
+ newFileName, "-",
+ state_machine_regs.address,
+ state_machine_regs.op_index);
+ else
+ printf ("%s %11d %#18" DWARF_VMA_FMT "x[%d]",
+ newFileName, state_machine_regs.line,
+ state_machine_regs.address,
+ state_machine_regs.op_index);
+ }
}
- if (state_machine_regs.view)
- printf (" %6u", state_machine_regs.view);
- else
- printf (" ");
+ if (xop != -DW_LNE_end_sequence)
+ {
+ if (state_machine_regs.view)
+ printf (" %6u", state_machine_regs.view);
+ else
+ printf (" ");
- if (state_machine_regs.is_stmt)
- printf (" x");
+ if (state_machine_regs.is_stmt)
+ printf (" x");
+ }
putchar ('\n');
state_machine_regs.view++;
load_debug_section_with_follow (str, file);
load_debug_section_with_follow (line, file);
+ load_debug_section_with_follow (str_index, file);
introduce (section, FALSE);
switch (op)
{
+ case DW_MACRO_define:
+ READ_ULEB (lineno, curr, end);
+ string = curr;
+ curr += strnlen ((char *) string, end - string) + 1;
+ printf (_(" DW_MACRO_define - lineno : %d macro : %s\n"),
+ lineno, string);
+ break;
+
+ case DW_MACRO_undef:
+ READ_ULEB (lineno, curr, end);
+ string = curr;
+ curr += strnlen ((char *) string, end - string) + 1;
+ printf (_(" DW_MACRO_undef - lineno : %d macro : %s\n"),
+ lineno, string);
+ break;
+
case DW_MACRO_start_file:
{
unsigned int filenum;
printf (_(" DW_MACRO_end_file\n"));
break;
- case DW_MACRO_define:
- READ_ULEB (lineno, curr, end);
- string = curr;
- curr += strnlen ((char *) string, end - string) + 1;
- printf (_(" DW_MACRO_define - lineno : %d macro : %s\n"),
- lineno, string);
- break;
-
- case DW_MACRO_undef:
- READ_ULEB (lineno, curr, end);
- string = curr;
- curr += strnlen ((char *) string, end - string) + 1;
- printf (_(" DW_MACRO_undef - lineno : %d macro : %s\n"),
- lineno, string);
- break;
-
case DW_MACRO_define_strp:
READ_ULEB (lineno, curr, end);
SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
(unsigned long) offset);
break;
+ case DW_MACRO_define_strx:
+ case DW_MACRO_undef_strx:
+ READ_ULEB (lineno, curr, end);
+ READ_ULEB (offset, curr, end);
+ string = (const unsigned char *)
+ fetch_indexed_string (offset, NULL, offset_size, FALSE);
+ if (op == DW_MACRO_define_strx)
+ printf (" DW_MACRO_define_strx ");
+ else
+ printf (" DW_MACRO_undef_strx ");
+ if (do_wide)
+ printf (_("(with offset %s) "), dwarf_vmatoa ("x", offset));
+ printf (_("lineno : %d macro : %s\n"),
+ lineno, string);
+ break;
+
default:
+ if (op >= DW_MACRO_lo_user && op <= DW_MACRO_hi_user)
+ {
+ printf (_(" <Target Specific macro op: %#x - UNHANDLED"), op);
+ break;
+ }
+
if (extended_ops == NULL || extended_ops[op] == NULL)
{
error (_(" Unknown macro opcode %02x seen\n"), op);
{
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;
+ abbrev_list * list;
+ dwarf_vma offset;
- free_abbrevs ();
-
- last = start;
- start = process_abbrev_section (start, end);
+ offset = start - section->start;
+ list = find_abbrev_list_by_abbrev_offset (0, offset);
+ if (list == NULL)
+ {
+ list = new_abbrev_list (0, 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"));
SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);
- if (vstart && llet == DW_LLE_offset_pair)
+ if (vstart && (llet == DW_LLE_offset_pair
+ || llet == DW_LLE_start_end
+ || llet == DW_LLE_start_length))
{
off = offset + (vstart - *start_ptr);
break;
case DW_LLE_offset_pair:
READ_ULEB (begin, start, section_end);
+ begin += base_address;
READ_ULEB (end, start, section_end);
+ end += base_address;
+ break;
+ case DW_LLE_start_end:
+ SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+ SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
+ break;
+ case DW_LLE_start_length:
+ SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+ READ_ULEB (end, start, section_end);
+ end += begin;
break;
case DW_LLE_base_address:
SAFE_BYTE_GET_AND_INC (base_address, start, pointer_size,
}
if (llet == DW_LLE_end_of_list)
break;
- if (llet != DW_LLE_offset_pair)
+ if (llet != DW_LLE_offset_pair
+ && llet != DW_LLE_start_end
+ && llet != DW_LLE_start_length)
continue;
if (start + 2 > section_end)
READ_ULEB (length, start, section_end);
- print_dwarf_vma (begin + base_address, pointer_size);
- print_dwarf_vma (end + base_address, pointer_size);
+ print_dwarf_vma (begin, pointer_size);
+ print_dwarf_vma (end, pointer_size);
putchar ('(');
need_frame_base = decode_location_expression (start,
display_debug_str_offsets (struct dwarf_section *section,
void *file ATTRIBUTE_UNUSED)
{
+ unsigned long idx;
+
if (section->size == 0)
{
printf (_("\nThe %s section is empty.\n"), section->name);
return 0;
}
- /* TODO: Dump the contents. This is made somewhat difficult by not knowing
- what the offset size is for this section. */
+
+ unsigned char *start = section->start;
+ unsigned char *end = start + section->size;
+ unsigned char *curr = start;
+
+ const char * suffix = strrchr (section->name, '.');
+ bfd_boolean dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? TRUE : FALSE;
+
+ if (dwo)
+ load_debug_section_with_follow (str_dwo, file);
+ else
+ load_debug_section_with_follow (str, file);
+
+ introduce (section, FALSE);
+
+ while (curr < end)
+ {
+ dwarf_vma length;
+ dwarf_vma entry_length;
+
+ SAFE_BYTE_GET_AND_INC (length, curr, 4, end);
+ /* FIXME: We assume that this means 64-bit DWARF is being used. */
+ if (length == 0xffffffff)
+ {
+ SAFE_BYTE_GET (length, curr, 8, end);
+ entry_length = 8;
+ }
+ else
+ entry_length = 4;
+
+ unsigned char *entries_end;
+ if (length == 0)
+ {
+ /* This is probably an old style .debug_str_offset section which
+ just contains offsets and no header (and the first offset is 0). */
+ length = section->size;
+ curr = section->start;
+ entries_end = end;
+
+ printf (_(" Length: %#lx\n"), (unsigned long) length);
+ printf (_(" Index Offset [String]\n"));
+ }
+ else
+ {
+ entries_end = curr + length;
+
+ int version;
+ SAFE_BYTE_GET_AND_INC (version, curr, 2, end);
+ if (version != 5)
+ warn (_("Unexpected version number in str_offset header: %#x\n"), version);
+
+ int padding;
+ SAFE_BYTE_GET_AND_INC (padding, curr, 2, end);
+ if (padding != 0)
+ warn (_("Unexpected value in str_offset header's padding field: %#x\n"), padding);
+
+ printf (_(" Length: %#lx\n"), (unsigned long) length);
+ printf (_(" Version: %#lx\n"), (unsigned long) version);
+ printf (_(" Index Offset [String]\n"));
+ }
+
+ for (idx = 0; curr < entries_end; idx++)
+ {
+ dwarf_vma offset;
+ const unsigned char * string;
+
+ if (curr + entry_length > entries_end)
+ /* Not enough space to read one entry_length, give up. */
+ return 0;
+
+ SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, end);
+ if (dwo)
+ string = (const unsigned char *)
+ fetch_indexed_string (idx, NULL, entry_length, dwo);
+ else
+ string = fetch_indirect_string (offset);
+
+ printf (" %8lu %8s %s\n", idx, dwarf_vmatoa ("x", offset),
+ string);
+ }
+ }
+
return 1;
}
break;
SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish);
-
printf (" %8.8lx ", offset);
if (begin == 0 && end == 0)
if (rlet == DW_RLE_base_address)
continue;
- print_dwarf_vma (begin + base_address, pointer_size);
- print_dwarf_vma (end + base_address, pointer_size);
+ /* Only a DW_RLE_offset_pair needs the base address added. */
+ if (rlet == DW_RLE_offset_pair)
+ {
+ begin += base_address;
+ end += base_address;
+ }
+
+ print_dwarf_vma (begin, pointer_size);
+ print_dwarf_vma (end, pointer_size);
if (begin == end)
fputs (_("(start == end)"), stdout);
num_range_list = 0;
for (i = 0; i < num_debug_info_entries; i++)
- num_range_list += debug_information [i].num_range_lists;
+ {
+ if (debug_information [i].dwarf_version < 5 && is_rnglists)
+ /* Skip .debug_rnglists reference. */
+ continue;
+ if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
+ /* Skip .debug_range reference. */
+ continue;
+ num_range_list += debug_information [i].num_range_lists;
+ }
if (num_range_list == 0)
{
debug_info *debug_info_p = &debug_information[i];
unsigned int j;
+ if (debug_information [i].dwarf_version < 5 && is_rnglists)
+ /* Skip .debug_rnglists reference. */
+ continue;
+ if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
+ /* Skip .debug_range reference. */
+ continue;
+
for (j = 0; j < debug_info_p->num_range_lists; j++)
{
range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
document. */
switch (regno)
{
-#define DECLARE_CSR(NAME,VALUE,CLASS) case VALUE + 4096: name = #NAME; break;
+#define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER) \
+ case VALUE + 4096: name = #NAME; break;
#include "opcode/riscv-opc.h"
#undef DECLARE_CSR
{
case bfd_mach_x86_64:
case bfd_mach_x86_64_intel_syntax:
- case bfd_mach_x86_64_nacl:
case bfd_mach_x64_32:
case bfd_mach_x64_32_intel_syntax:
- case bfd_mach_x64_32_nacl:
init_dwarf_regnames_x86_64 ();
break;
if (*need_col_headers)
{
- static const char *sloc = " LOC";
-
*need_col_headers = 0;
- printf ("%-*s CFA ", eh_addr_size * 2, sloc);
+ printf ("%-*s CFA ", eh_addr_size * 2, " LOC");
for (r = 0; r < *max_regs; r++)
if (fc->col_type[r] != DW_CFA_unreferenced)
unsigned char *entryptr = entry_pool + entry_offset;
- // We need to scan first whether there is a single or multiple
- // entries. TAGNO is -2 for the first entry, it is -1 for the
- // initial tag read of the second entry, then it becomes 0 for the
- // first entry for real printing etc.
+ /* We need to scan first whether there is a single or multiple
+ entries. TAGNO is -2 for the first entry, it is -1 for the
+ initial tag read of the second entry, then it becomes 0 for the
+ first entry for real printing etc. */
int tagno = -2;
/* Initialize it due to a false compiler warning. */
dwarf_vma second_abbrev_tag = -1;
The .gun_debugaltlink section is formatted as:
(c-string) Filename.
(binary) Build-ID. */
-
+
filename = section->start;
filelen = strnlen ((const char *) filename, section->size);
if (filelen == section->size)
return 1;
}
+static int cu_tu_indexes_read = -1; /* Tri-state variable. */
+
/* Load the CU and TU indexes if present. This will build a list of
section sets that we can use to associate a .debug_info.dwo section
with its associated .debug_abbrev.dwo section in a .dwp file. */
static bfd_boolean
load_cu_tu_indexes (void *file)
{
- static int cu_tu_indexes_read = -1; /* Tri-state variable. */
-
/* If we have already loaded (or tried to load) the CU and TU indexes
then do not bother to repeat the task. */
if (cu_tu_indexes_read == -1)
{
cu_tu_indexes_read = TRUE;
-
+
if (load_debug_section_with_follow (dwp_cu_index, file))
if (! process_cu_tu_index (&debug_displays [dwp_cu_index].section, 0))
cu_tu_indexes_read = FALSE;
The CRC value is stored after the filename, aligned up to 4 bytes. */
name = (const char *) section->start;
-
crc_offset = strnlen (name, section->size) + 1;
crc_offset = (crc_offset + 3) & ~3;
if (crc_offset + 4 > section->size)
if (id_len < 0x14)
return NULL;
- build_id_data = calloc (1, sizeof * build_id_data);
- if (build_id_data == NULL)
- return NULL;
-
+ build_id_data = (Build_id_data *) data;
build_id_data->len = id_len;
build_id_data->data = section->start + namelen;
- * (Build_id_data **) data = build_id_data;
-
return name;
}
{
warn (_("Corrupt debuglink section: %s\n"),
xlink->name ? xlink->name : xlink->uncompressed_name);
- return FALSE;
+ return NULL;
}
-
+
/* Attempt to locate the separate file.
This should duplicate the logic in bfd/opncls.c:find_separate_debug_file(). */
canon_dir = lrealpath (main_filename);
-
+
for (canon_dirlen = strlen (canon_dir); canon_dirlen > 0; canon_dirlen--)
if (IS_DIR_SEPARATOR (canon_dir[canon_dirlen - 1]))
break;
{
warn (_("failed to open separate debug file: %s\n"), debug_filename);
free (debug_filename);
- return FALSE;
+ return NULL;
}
/* FIXME: We do not check to see if there are any other separate debug info
char * separate_filename;
void * separate_handle;
- /* FIXME: Skip adding / if dwo_dir ends in /. */
- separate_filename = concat (dir, "/", name, NULL);
+ if (IS_ABSOLUTE_PATH (name))
+ separate_filename = strdup (name);
+ else
+ /* FIXME: Skip adding / if dwo_dir ends in /. */
+ separate_filename = concat (dir, "/", name, NULL);
if (separate_filename == NULL)
{
warn (_("Out of memory allocating dwo filename\n"));
return separate_handle;
}
+/* Load a debuglink section and/or a debugaltlink section, if either are present.
+ Recursively check the loaded files for more of these sections.
+ FIXME: Should also check for DWO_* entries in the newlu loaded files. */
+
+static void
+check_for_and_load_links (void * file, const char * filename)
+{
+ void * handle = NULL;
+
+ if (load_debug_section (gnu_debugaltlink, file))
+ {
+ Build_id_data build_id_data;
+
+ handle = load_separate_debug_info (filename,
+ & debug_displays[gnu_debugaltlink].section,
+ parse_gnu_debugaltlink,
+ check_gnu_debugaltlink,
+ & build_id_data,
+ file);
+ if (handle)
+ {
+ assert (handle == first_separate_info->handle);
+ check_for_and_load_links (first_separate_info->handle,
+ first_separate_info->filename);
+ }
+ }
+
+ if (load_debug_section (gnu_debuglink, file))
+ {
+ unsigned long crc32;
+
+ handle = load_separate_debug_info (filename,
+ & debug_displays[gnu_debuglink].section,
+ parse_gnu_debuglink,
+ check_gnu_debuglink,
+ & crc32,
+ file);
+ if (handle)
+ {
+ assert (handle == first_separate_info->handle);
+ check_for_and_load_links (first_separate_info->handle,
+ first_separate_info->filename);
+ }
+ }
+}
+
/* Load the separate debug info file(s) attached to FILE, if any exist.
Returns TRUE if any were found, FALSE otherwise.
If TRUE is returned then the linked list starting at first_separate_info
{
free_dwo_info ();
- if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
+ if (process_debug_info (& debug_displays[info].section, file, abbrev,
+ TRUE, FALSE))
{
bfd_boolean introduced = FALSE;
dwo_info * dwinfo;
const char * dir = NULL;
const char * id = NULL;
+ const char * name = NULL;
for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
{
+ /* Accumulate NAME, DIR and ID fields. */
switch (dwinfo->type)
{
case DWO_NAME:
+ if (name != NULL)
+ warn (_("Multiple DWO_NAMEs encountered for the same CU\n"));
+ name = dwinfo->value;
+ break;
+
+ case DWO_DIR:
+ /* There can be multiple DW_AT_comp_dir entries in a CU,
+ so do not complain. */
+ dir = dwinfo->value;
+ break;
+
+ case DWO_ID:
+ if (id != NULL)
+ warn (_("multiple DWO_IDs encountered for the same CU\n"));
+ id = dwinfo->value;
+ break;
+
+ default:
+ error (_("Unexpected DWO INFO type"));
+ break;
+ }
+
+ /* If we have reached the end of our list, or we are changing
+ CUs, then display the information that we have accumulated
+ so far. */
+ if (name != NULL
+ && (dwinfo->next == NULL
+ || dwinfo->next->cu_offset != dwinfo->cu_offset))
+ {
if (do_debug_links)
{
if (! introduced)
introduced = TRUE;
}
- printf (_(" Name: %s\n"), dwinfo->value);
+ printf (_(" Name: %s\n"), name);
printf (_(" Directory: %s\n"), dir ? dir : _("<not-found>"));
if (id != NULL)
display_data (printf (_(" ID: ")), (unsigned char *) id, 8);
else
- printf (_(" ID: <unknown>\n"));
+ printf (_(" ID: <not specified>\n"));
printf ("\n\n");
}
if (do_follow_links)
- load_dwo_file (filename, dwinfo->value, dir, id);
- break;
-
- case DWO_DIR:
- dir = dwinfo->value;
- break;
+ load_dwo_file (filename, name, dir, id);
- case DWO_ID:
- id = dwinfo->value;
- break;
-
- default:
- error (_("Unexpected DWO INFO type"));
- break;
+ name = dir = id = NULL;
}
}
}
return FALSE;
/* FIXME: We do not check for the presence of both link sections in the same file. */
- /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks. */
/* FIXME: We do not check for the presence of multiple, same-name debuglink sections. */
/* FIXME: We do not check for the presence of a dwo link as well as a debuglink. */
- if (load_debug_section (gnu_debugaltlink, file))
- {
- Build_id_data * build_id_data;
-
- load_separate_debug_info (filename,
- & debug_displays[gnu_debugaltlink].section,
- parse_gnu_debugaltlink,
- check_gnu_debugaltlink,
- & build_id_data,
- file);
- }
-
- if (load_debug_section (gnu_debuglink, file))
- {
- unsigned long crc32;
-
- load_separate_debug_info (filename,
- & debug_displays[gnu_debuglink].section,
- parse_gnu_debuglink,
- check_gnu_debuglink,
- & crc32,
- file);
- }
-
+ check_for_and_load_links (file, filename);
if (first_separate_info != NULL)
return TRUE;
do_follow_links = 0;
return FALSE;
-}
+}
void
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;
+
+ free (shndx_pool);
+ shndx_pool = NULL;
+ shndx_pool_size = 0;
+ shndx_pool_used = 0;
+ free (cu_sets);
+ cu_sets = NULL;
+ cu_count = 0;
+ free (tu_sets);
+ tu_sets = NULL;
+ tu_count = 0;
+
+ memset (level_type_signed, 0, sizeof level_type_signed);
+ cu_tu_indexes_read = -1;
for (i = 0; i < max; i++)
free_debug_section ((enum dwarf_section_display_enum) i);
if (debug_information != NULL)
{
- if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE)
+ for (i = 0; i < alloc_num_debug_info_entries; i++)
{
- for (i = 0; i < num_debug_info_entries; i++)
+ if (debug_information [i].max_loc_offsets)
{
- if (!debug_information [i].max_loc_offsets)
- {
- free (debug_information [i].loc_offsets);
- free (debug_information [i].have_frame_base);
- }
- if (!debug_information [i].max_range_lists)
- free (debug_information [i].range_lists);
+ free (debug_information [i].loc_offsets);
+ free (debug_information [i].have_frame_base);
}
+ if (debug_information [i].max_range_lists)
+ free (debug_information [i].range_lists);
}
free (debug_information);
debug_information = NULL;
free ((void *) d);
}
first_separate_info = NULL;
-
+
free_dwo_info ();
}
{ "links", & do_debug_links, 1 },
{ "loc", & do_debug_loc, 1 },
{ "macro", & do_debug_macinfo, 1 },
+ { "no-follow-links", & do_follow_links, 0 },
{ "pubnames", & do_debug_pubnames, 1 },
{ "pubtypes", & do_debug_pubtypes, 1 },
/* This entry is for compatibility
{ "ranges", & do_debug_aranges, 1 },
{ "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW },
{ "str", & do_debug_str, 1 },
+ { "str-offsets", & do_debug_str_offsets, 1 },
/* These trace_* sections are used by Itanium VMS. */
{ "trace_abbrev", & do_trace_abbrevs, 1 },
{ "trace_aranges", & do_trace_aranges, 1 },
if (strncmp (p, entry->option, len) == 0
&& (p[len] == ',' || p[len] == '\0'))
{
- * entry->variable |= entry->val;
+ * entry->variable = entry->val;
/* The --debug-dump=frames-interp option also
enables the --debug-dump=frames option. */
case 'g': do_gdb_index = 1; break;
case 'i': do_debug_info = 1; break;
case 'K': do_follow_links = 1; break;
+ case 'N': do_follow_links = 0; break;
case 'k': do_debug_links = 1; break;
case 'l': do_debug_lines |= FLAG_DEBUG_LINES_RAW; break;
case 'L': do_debug_lines |= FLAG_DEBUG_LINES_DECODED; break;
case 'm': do_debug_macinfo = 1; break;
+ case 'O': do_debug_str_offsets = 1; break;
case 'o': do_debug_loc = 1; break;
case 'p': do_debug_pubnames = 1; break;
case 'R': do_debug_ranges = 1; break;
do_debug_cu_index = 1;
do_follow_links = 1;
do_debug_links = 1;
+ do_debug_str_offsets = 1;
}
-#define NO_ABBREVS NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL
-#define ABBREV(N) NULL, NULL, NULL, 0, 0, N, NULL, 0, NULL
+#define NO_ABBREVS NULL, NULL, NULL, 0, 0, 0, NULL, 0
+#define ABBREV(N) NULL, NULL, NULL, 0, 0, N, NULL, 0
/* N.B. The order here must match the order in section_display_enum. */
{ { ".debug_macro.dwo", ".zdebug_macro.dwo", NO_ABBREVS }, display_debug_macro, &do_debug_macinfo, TRUE },
{ { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NO_ABBREVS }, display_debug_macinfo, &do_debug_macinfo, FALSE },
{ { ".debug_str.dwo", ".zdebug_str.dwo", NO_ABBREVS }, display_debug_str, &do_debug_str, TRUE },
- { { ".debug_str_offsets", ".zdebug_str_offsets", NO_ABBREVS }, display_debug_str_offsets, NULL, FALSE },
- { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NO_ABBREVS }, display_debug_str_offsets, NULL, FALSE },
+ { { ".debug_str_offsets", ".zdebug_str_offsets", NO_ABBREVS }, display_debug_str_offsets, &do_debug_str_offsets, TRUE },
+ { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NO_ABBREVS }, display_debug_str_offsets, &do_debug_str_offsets, TRUE },
{ { ".debug_addr", ".zdebug_addr", NO_ABBREVS }, display_debug_addr, &do_debug_addr, TRUE },
{ { ".debug_cu_index", "", NO_ABBREVS }, display_cu_index, &do_debug_cu_index, FALSE },
{ { ".debug_tu_index", "", NO_ABBREVS }, display_cu_index, &do_debug_cu_index, FALSE },