/* dwarf.c -- display DWARF contents of a BFD binary file
- Copyright (C) 2005-2018 Free Software Foundation, Inc.
+ Copyright (C) 2005-2019 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "dwarf.h"
#include "gdb/gdb-index.h"
#include "filenames.h"
+#include "safe-ctype.h"
#include <assert.h>
#undef MAX
that the .debug_info section could not be loaded/parsed. */
#define DEBUG_INFO_UNAVAILABLE (unsigned int) -1
-static const char * dwo_name;
-static const char * dwo_dir;
-static const unsigned char * dwo_id;
-static bfd_size_type dwo_id_len;
-static bfd_boolean need_dwo_info;
+/* A .debug_info section can contain multiple links to separate
+ DWO object files. We use these structures to record these links. */
+typedef enum dwo_type
+{
+ DWO_NAME,
+ DWO_DIR,
+ DWO_ID
+} dwo_type;
+
+typedef struct dwo_info
+{
+ dwo_type type;
+ const char * value;
+ struct dwo_info * next;
+} dwo_info;
+
+static dwo_info * first_dwo_info = NULL;
+static bfd_boolean need_dwo_info;
+
+separate_info * first_separate_info = NULL;
unsigned int eh_addr_size;
static unsigned int shndx_pool_size = 0;
static unsigned int shndx_pool_used = 0;
-/* Pointer to a separate file containing extra debug information. */
-static void * separate_debug_file = NULL;
-static const char * separate_debug_filename = NULL;
-
/* For version 2 package files, each set contains an array of section offsets
and an array of section sizes, giving the offset and size of the
contribution from a CU or TU within one of the debug sections.
data += bytes_read;
printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue));
break;
+ case DW_OP_GNU_variable_value:
+ /* FIXME: Strictly speaking for 64-bit DWARF3 files
+ this ought to be an 8-byte wide computation. */
+ if (dwarf_version == -1)
+ {
+ printf (_("(DW_OP_GNU_variable_value in frame info)"));
+ /* No way to tell where the next op is, so just bail. */
+ return need_frame_base;
+ }
+ if (dwarf_version == 2)
+ {
+ SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+ }
+ else
+ {
+ SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+ }
+ printf ("DW_OP_GNU_variable_value: <0x%s>", dwarf_vmatoa ("x", uvalue));
+ break;
/* HP extensions. */
case DW_OP_HP_is_value:
static const char *
fetch_alt_indirect_string (dwarf_vma offset)
{
- struct dwarf_section * section;
- const char * ret;
+ separate_info * i;
if (! do_follow_links)
return "";
- if (separate_debug_file == NULL)
- return _("<following link not possible>");
+ if (first_separate_info == NULL)
+ return _("<no links available>");
- if (! load_debug_section (separate_debug_str, separate_debug_file))
- return _("<could not load separate string section>");
+ for (i = first_separate_info; i != NULL; i = i->next)
+ {
+ struct dwarf_section * section;
+ const char * ret;
- section = &debug_displays [separate_debug_str].section;
- if (section->start == NULL)
- return _("<no .debug_str section>");
+ if (! load_debug_section (separate_debug_str, i->handle))
+ continue;
- if (offset >= section->size)
- {
- warn (_("DW_FORM_GNU_strp_alt offset too big: %s\n"), dwarf_vmatoa ("x", offset));
- return _("<offset is too big>");
- }
+ section = &debug_displays [separate_debug_str].section;
- ret = (const char *) (section->start + offset);
- /* Unfortunately we cannot rely upon the .debug_str section ending with a
- NUL byte. Since our caller is expecting to receive a well formed C
- string we test for the lack of a terminating byte here. */
- if (strnlen ((const char *) ret, section->size - offset)
- == section->size - offset)
- return _("<no NUL byte at end of .debug_str section>");
+ if (section->start == NULL)
+ continue;
- return ret;
+ if (offset >= section->size)
+ continue;
+
+ ret = (const char *) (section->start + offset);
+ /* Unfortunately we cannot rely upon the .debug_str section ending with a
+ NUL byte. Since our caller is expecting to receive a well formed C
+ string we test for the lack of a terminating byte here. */
+ if (strnlen ((const char *) ret, section->size - offset)
+ == section->size - offset)
+ return _("<no NUL byte at end of alt .debug_str section>");
+
+ 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 const char *
return name;
}
+static void
+add_dwo_info (const char * field, dwo_type type)
+{
+ dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
+
+ dwinfo->type = type;
+ dwinfo->value = field;
+ dwinfo->next = first_dwo_info;
+ first_dwo_info = dwinfo;
+}
+
+static void
+add_dwo_name (const char * name)
+{
+ add_dwo_info (name, DWO_NAME);
+}
+
+static void
+add_dwo_dir (const char * dir)
+{
+ add_dwo_info (dir, DWO_DIR);
+}
+
+static void
+add_dwo_id (const char * id)
+{
+ add_dwo_info (id, DWO_ID);
+}
+
+static void
+free_dwo_info (void)
+{
+ dwo_info * dwinfo;
+ dwo_info * next;
+
+ for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next)
+ {
+ next = dwinfo->next;
+ free (dwinfo);
+ }
+ first_dwo_info = NULL;
+}
+
static unsigned char *
read_and_display_attr_value (unsigned long attribute,
unsigned long form,
switch (form)
{
case DW_FORM_strp:
- dwo_name = (const char *) fetch_indirect_string (uvalue);
+ add_dwo_name ((const char *) fetch_indirect_string (uvalue));
break;
case DW_FORM_GNU_str_index:
- dwo_name = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+ add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
break;
case DW_FORM_string:
- dwo_name = (const char *) orig_data;
+ add_dwo_name ((const char *) orig_data);
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
get_FORM_name (form), get_AT_name (attribute));
- dwo_name = _("<unknown>");
break;
}
break;
switch (form)
{
case DW_FORM_strp:
- dwo_dir = (const char *) fetch_indirect_string (uvalue);
+ add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
break;
case DW_FORM_line_strp:
- dwo_dir = (const char *) fetch_indirect_line_string (uvalue);
+ add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
break;
case DW_FORM_GNU_str_index:
- dwo_dir = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+ add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
break;
case DW_FORM_string:
- dwo_dir = (const char *) orig_data;
+ add_dwo_dir ((const char *) orig_data);
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
get_FORM_name (form), get_AT_name (attribute));
- dwo_dir = _("<unknown>");
break;
}
break;
switch (form)
{
case DW_FORM_data8:
- dwo_id = data - 8;
- dwo_id_len = 8;
+ /* FIXME: Record the length of the ID as well ? */
+ add_dwo_id ((const char *) (data - 8));
break;
default:
warn (_("Unsupported form (%s) for attribute %s\n"),
get_FORM_name (form), get_AT_name (attribute));
- dwo_id = NULL;
break;
}
break;
}
/* Like load_debug_section, but if the ordinary call fails, and we are
- following debug links, and we have been able to load a separate debug
- info file, then attempt to load the requested section from the separate
- file. */
+ following debug links, then attempt to load the requested section
+ from one of the separate debug info files. */
static bfd_boolean
load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
- void * data)
+ void * handle)
{
- if (load_debug_section (sec_enum, data))
+ if (load_debug_section (sec_enum, handle))
{
- if (data == separate_debug_file)
- debug_displays[sec_enum].section.filename = separate_debug_filename;
-
- /* FIXME: We should check to see if there is a separate debug info file
- that also contains this section, and if so, issue a warning. */
+ if (debug_displays[sec_enum].section.filename == NULL)
+ {
+ /* See if we can associate a filename with this section. */
+ separate_info * i;
+
+ for (i = first_separate_info; i != NULL; i = i->next)
+ if (i->handle == handle)
+ {
+ debug_displays[sec_enum].section.filename = i->filename;
+ break;
+ }
+ }
+
return TRUE;
}
- if (do_follow_links && separate_debug_file != NULL)
- if (load_debug_section (sec_enum, separate_debug_file))
- {
- debug_displays[sec_enum].section.filename = separate_debug_filename;
- return TRUE;
- }
+ if (do_follow_links)
+ {
+ separate_info * i;
+
+ for (i = first_separate_info; i != NULL; i = i->next)
+ {
+ if (load_debug_section (sec_enum, i->handle))
+ {
+ debug_displays[sec_enum].section.filename = i->filename;
+
+ /* FIXME: We should check to see if any of the remaining debug info
+ files also contain this section, and, umm, do something about it. */
+ return TRUE;
+ }
+ }
+ }
return FALSE;
}
if (! do_loc && do_printing)
/* Show the offset from where the tag was extracted. */
printf (" <%lx>", (unsigned long)(tags - section_begin));
-
tags = read_and_display_attr (attr->attribute,
attr->form,
attr->implicit_const,
unsigned char * end,
const DWARF2_Internal_LineInfo * linfo,
struct dwarf_section * section,
- const char * what)
+ bfd_boolean is_dir)
{
unsigned char *format_start, format_count, *format, formati;
dwarf_vma data_count, datai;
data += bytes_read;
if (data == end)
{
- warn (_("Corrupt %s format table entry\n"), what);
+ if (is_dir)
+ warn (_("Corrupt directory format table entry\n"));
+ else
+ warn (_("Corrupt file name format table entry\n"));
return data;
}
}
data += bytes_read;
if (data == end)
{
- warn (_("Corrupt %s list\n"), what);
+ if (is_dir)
+ warn (_("Corrupt directory list\n"));
+ else
+ warn (_("Corrupt file name list\n"));
return data;
}
if (data_count == 0)
{
- printf (_("\n The %s Table is empty.\n"), what);
+ if (is_dir)
+ printf (_("\n The Directory Table is empty.\n"));
+ else
+ printf (_("\n The File Name Table is empty.\n"));
return data;
}
- printf (_("\n The %s Table (offset 0x%lx):\n"), what,
- (long)(data - start));
+ if (is_dir)
+ printf (_("\n The Directory Table (offset 0x%lx):\n"),
+ (long) (data - start));
+ else
+ printf (_("\n The File Name Table (offset 0x%lx):\n"),
+ (long) (data - start));
printf (_(" Entry"));
/* Delay displaying name as the last entry for better screen layout. */
}
if (data == end)
{
- warn (_("Corrupt %s entries list\n"), what);
+ if (is_dir)
+ warn (_("Corrupt directory entries list\n"));
+ else
+ warn (_("Corrupt file name entries list\n"));
return data;
}
putchar ('\n');
load_debug_section_with_follow (line_str, file);
data = display_formatted_table (data, start, end, &linfo, section,
- _("Directory"));
+ TRUE);
data = display_formatted_table (data, start, end, &linfo, section,
- _("File name"));
+ FALSE);
}
else
{
printf ("%s:\n", file_table[0].name);
}
- printf (_("File name Line number Starting address View\n"));
+ printf (_("File name Line number Starting address View Stmt\n"));
saved_linfo = linfo;
}
}
if (state_machine_regs.view)
- printf (" %6u\n", state_machine_regs.view);
+ printf (" %6u", state_machine_regs.view);
else
- putchar ('\n');
+ printf (" ");
+
+ if (state_machine_regs.is_stmt)
+ printf (" x");
+
+ putchar ('\n');
state_machine_regs.view++;
if (xop == -DW_LNE_end_sequence)
unsigned char *next = start, *vnext = vstart;
unsigned int *array = NULL;
const char *suffix = strrchr (section->name, '.');
- int is_dwo = 0;
+ bfd_boolean is_dwo = FALSE;
int is_loclists = strstr (section->name, "debug_loclists") != NULL;
dwarf_vma expected_start = 0;
if (suffix && strcmp (suffix, ".dwo") == 0)
- is_dwo = 1;
+ is_dwo = TRUE;
bytes = section->size;
static int
comp_addr_base (const void * v0, const void * v1)
{
- debug_info * info0 = (debug_info *) v0;
- debug_info * info1 = (debug_info *) v1;
+ debug_info *info0 = *(debug_info **) v0;
+ debug_info *info1 = *(debug_info **) v1;
return info0->addr_base - info1->addr_base;
}
}
/* Display the .debug_str_offsets and .debug_str_offsets.dwo sections. */
+
static int
display_debug_str_offsets (struct dwarf_section *section,
void *file ATTRIBUTE_UNUSED)
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
NULL, "elr", NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "vg", "ffr",
+ "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7",
+ "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+ "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7",
+ "z8", "z9", "z10", "z11", "z12", "z13", "z14", "z15",
+ "z16", "z17", "z18", "z19", "z20", "z21", "z22", "z23",
+ "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31",
};
void
fc->fde_encoding = *q++;
else if (*p == 'S')
;
+ else if (*p == 'B')
+ ;
else
break;
p++;
unsigned char *start = section->start;
unsigned char *end = start + section->size;
unsigned char *section_start = start;
- Frame_Chunk *chunks = 0, *forward_refs = 0;
- Frame_Chunk *remembered_state = 0;
+ Frame_Chunk *chunks = NULL, *forward_refs = NULL;
+ Frame_Chunk *remembered_state = NULL;
Frame_Chunk *rs;
- int is_eh = strcmp (section->name, ".eh_frame") == 0;
+ bfd_boolean is_eh = strcmp (section->name, ".eh_frame") == 0;
unsigned int length_return;
unsigned int max_regs = 0;
const char *bad_reg = _("bad register: ");
printf ("\n");
+ while (remembered_state != NULL)
+ {
+ rs = remembered_state;
+ remembered_state = rs->next;
+ free (rs->col_type);
+ free (rs->col_offset);
+ rs->next = NULL; /* Paranoia. */
+ free (rs);
+ }
+
+ while (chunks != NULL)
+ {
+ rs = chunks;
+ chunks = rs->next;
+ free (rs->col_type);
+ free (rs->col_offset);
+ rs->next = NULL; /* Paranoia. */
+ free (rs);
+ }
+
+ while (forward_refs != NULL)
+ {
+ rs = forward_refs;
+ forward_refs = rs->next;
+ free (rs->col_type);
+ free (rs->col_offset);
+ rs->next = NULL; /* Paranoia. */
+ free (rs);
+ }
+
return 1;
}
uint32_t augmentation_string_size;
unsigned int i;
unsigned long sec_off;
+ bfd_boolean augmentation_printable;
+ const char *augmentation_string;
unit_start = hdrptr;
augmentation_string_size);
augmentation_string_size += (-augmentation_string_size) & 3;
}
+
printf (_("Augmentation string:"));
+
+ augmentation_printable = TRUE;
+ augmentation_string = (const char *) hdrptr;
+
for (i = 0; i < augmentation_string_size; i++)
{
unsigned char uc;
SAFE_BYTE_GET_AND_INC (uc, hdrptr, 1, unit_end);
printf (" %02x", uc);
+
+ if (uc != 0 && !ISPRINT (uc))
+ augmentation_printable = FALSE;
+ }
+
+ if (augmentation_printable)
+ {
+ printf (" (\"");
+ for (i = 0;
+ i < augmentation_string_size && augmentation_string[i];
+ ++i)
+ putchar (augmentation_string[i]);
+ printf ("\")");
}
- putchar ('\n');
putchar ('\n');
printf (_("CU table:\n"));
SAFE_BYTE_GET (nslots, phdr + 12, 4, limit);
phash = phdr + 16;
- pindex = phash + nslots * 8;
- ppool = pindex + nslots * 4;
-
- /* PR 17531: file: 45d69832. */
- if (pindex < phash || ppool < phdr || (pindex == phash && nslots != 0))
- {
- warn (ngettext ("Section %s is too small for %d slot\n",
- "Section %s is too small for %d slots\n",
- nslots),
- section->name, nslots);
- return 0;
- }
+ pindex = phash + (size_t) nslots * 8;
+ ppool = pindex + (size_t) nslots * 4;
if (do_display)
{
introduce (section, FALSE);
- printf (_(" Version: %d\n"), version);
+ printf (_(" Version: %u\n"), version);
if (version >= 2)
- printf (_(" Number of columns: %d\n"), ncols);
- printf (_(" Number of used entries: %d\n"), nused);
- printf (_(" Number of slots: %d\n\n"), nslots);
+ printf (_(" Number of columns: %u\n"), ncols);
+ printf (_(" Number of used entries: %u\n"), nused);
+ printf (_(" Number of slots: %u\n\n"), nslots);
}
- if (ppool > limit || ppool < phdr)
+ /* PR 17531: file: 45d69832. */
+ if ((size_t) nslots * 8 / 8 != nslots
+ || phash < phdr || phash > limit
+ || pindex < phash || pindex > limit
+ || ppool < pindex || ppool > limit)
{
- warn (_("Section %s too small for %d hash table entries\n"),
+ warn (ngettext ("Section %s is too small for %u slot\n",
+ "Section %s is too small for %u slots\n",
+ nslots),
section->name, nslots);
return 0;
}
unsigned int dw_sect;
unsigned char *ph = phash;
unsigned char *pi = pindex;
- unsigned char *poffsets = ppool + ncols * 4;
- unsigned char *psizes = poffsets + nused * ncols * 4;
- unsigned char *pend = psizes + nused * ncols * 4;
+ unsigned char *poffsets = ppool + (size_t) ncols * 4;
+ unsigned char *psizes = poffsets + (size_t) nused * ncols * 4;
+ unsigned char *pend = psizes + (size_t) nused * ncols * 4;
bfd_boolean is_tu_index;
struct cu_tu_set *this_set = NULL;
unsigned int row;
is_tu_index = strcmp (section->name, ".debug_tu_index") == 0;
/* PR 17531: file: 0dd159bf.
- Check for wraparound with an overlarge ncols value. */
- if (poffsets < ppool || (unsigned int) ((poffsets - ppool) / 4) != ncols)
- {
- warn (_("Overlarge number of columns: %x\n"), ncols);
- return 0;
- }
-
- if (pend > limit)
+ Check for integer overflow (can occur when size_t is 32-bit)
+ with overlarge ncols or nused values. */
+ if ((size_t) ncols * 4 / 4 != ncols
+ || (size_t) nused * ncols * 4 / ((size_t) ncols * 4) != nused
+ || poffsets < ppool || poffsets > limit
+ || psizes < poffsets || psizes > limit
+ || pend < psizes || pend > limit)
{
warn (_("Section %s too small for offset and size tables\n"),
section->name);
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)
return name;
}
+static void
+add_separate_debug_file (const char * filename, void * handle)
+{
+ separate_info * i = xmalloc (sizeof * i);
+
+ i->filename = filename;
+ i->handle = handle;
+ i->next = first_separate_info;
+ first_separate_info = i;
+}
+
static void *
load_separate_debug_info (const char * main_filename,
struct dwarf_section * xlink,
void * func_data)
{
const char * separate_filename;
- char * debugfile;
+ char * debug_filename;
char * canon_dir;
size_t canon_dirlen;
size_t dirlen;
#define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
#endif
- debugfile = (char *) malloc (strlen (DEBUGDIR) + 1
- + canon_dirlen
- + strlen (".debug/")
+ debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1
+ + canon_dirlen
+ + strlen (".debug/")
#ifdef EXTRA_DEBUG_ROOT1
- + strlen (EXTRA_DEBUG_ROOT1)
+ + strlen (EXTRA_DEBUG_ROOT1)
#endif
#ifdef EXTRA_DEBUG_ROOT2
- + strlen (EXTRA_DEBUG_ROOT2)
+ + strlen (EXTRA_DEBUG_ROOT2)
#endif
- + strlen (separate_filename)
- + 1);
- if (debugfile == NULL)
+ + strlen (separate_filename)
+ + 1);
+ if (debug_filename == NULL)
{
warn (_("Out of memory"));
+ free (canon_dir);
return NULL;
}
/* First try in the current directory. */
- sprintf (debugfile, "%s", separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, "%s", separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
/* Then try in a subdirectory called .debug. */
- sprintf (debugfile, ".debug/%s", separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, ".debug/%s", separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
/* Then try in the same directory as the original file. */
- sprintf (debugfile, "%s%s", canon_dir, separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
/* And the .debug subdirectory of that directory. */
- sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
#ifdef EXTRA_DEBUG_ROOT1
/* Try the first extra debug file root. */
- sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
+ if (check_func (debug_filename, func_data))
+ goto found;
+
+ /* Try the first extra debug file root. */
+ sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
#endif
#ifdef EXTRA_DEBUG_ROOT2
/* Try the second extra debug file root. */
- sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
- if (check_func (debugfile, func_data))
+ sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+ if (check_func (debug_filename, func_data))
goto found;
#endif
- /* Then try in the global debugfile directory. */
- strcpy (debugfile, DEBUGDIR);
+ /* Then try in the global debug_filename directory. */
+ strcpy (debug_filename, DEBUGDIR);
dirlen = strlen (DEBUGDIR) - 1;
if (dirlen > 0 && DEBUGDIR[dirlen] != '/')
- strcat (debugfile, "/");
- strcat (debugfile, (const char *) separate_filename);
+ strcat (debug_filename, "/");
+ strcat (debug_filename, (const char *) separate_filename);
- if (check_func (debugfile, func_data))
+ if (check_func (debug_filename, func_data))
goto found;
/* Failed to find the file. */
warn (_("could not find separate debug file '%s'\n"), separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ warn (_("tried: %s\n"), debug_filename);
#ifdef EXTRA_DEBUG_ROOT2
- sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
#endif
#ifdef EXTRA_DEBUG_ROOT1
- sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
+
+ sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
#endif
- sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
- sprintf (debugfile, "%s%s", canon_dir, separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
- sprintf (debugfile, ".debug/%s", separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, ".debug/%s", separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
- sprintf (debugfile, "%s", separate_filename);
- warn (_("tried: %s\n"), debugfile);
+ sprintf (debug_filename, "%s", separate_filename);
+ warn (_("tried: %s\n"), debug_filename);
free (canon_dir);
- free (debugfile);
+ free (debug_filename);
return NULL;
found:
free (canon_dir);
+ void * debug_handle;
+
/* Now open the file.... */
- if ((separate_debug_file = open_debug_file (debugfile)) == NULL)
+ if ((debug_handle = open_debug_file (debug_filename)) == NULL)
{
- warn (_("failed to open separate debug file: %s\n"), debugfile);
- free (debugfile);
+ warn (_("failed to open separate debug file: %s\n"), debug_filename);
+ free (debug_filename);
return FALSE;
}
/* FIXME: We do not check to see if there are any other separate debug info
files that would also match. */
- printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debugfile);
- separate_debug_filename = debugfile;
+ printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debug_filename);
+ add_separate_debug_file (debug_filename, debug_handle);
- /* Do not free debugfile - it might be referenced inside
+ /* Do not free debug_filename - it might be referenced inside
the structure returned by open_debug_file(). */
- return separate_debug_file;
+ return debug_handle;
}
/* Attempt to load a separate dwarf object file. */
static void *
-load_dwo_file (const char * main_filename)
+load_dwo_file (const char * main_filename, const char * name, const char * dir, const char * id ATTRIBUTE_UNUSED)
{
- char * filename;
+ char * separate_filename;
+ void * separate_handle;
/* FIXME: Skip adding / if dwo_dir ends in /. */
- filename = concat (dwo_dir, "/", dwo_name, NULL);
- if (filename == NULL)
+ separate_filename = concat (dir, "/", name, NULL);
+ if (separate_filename == NULL)
{
warn (_("Out of memory allocating dwo filename\n"));
return NULL;
}
- if ((separate_debug_file = open_debug_file (filename)) == NULL)
+ if ((separate_handle = open_debug_file (separate_filename)) == NULL)
{
- warn (_("Unable to load dwo file: %s\n"), filename);
- free (filename);
+ warn (_("Unable to load dwo file: %s\n"), separate_filename);
+ free (separate_filename);
return NULL;
}
/* FIXME: We should check the dwo_id. */
- printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, filename);
- separate_debug_filename = filename;
- return separate_debug_file;
+ printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, separate_filename);
+ add_separate_debug_file (separate_filename, separate_handle);
+ /* Note - separate_filename will be freed in free_debug_memory(). */
+ return separate_handle;
}
-/* Load a separate debug info file, if it exists.
- Returns the data pointer that is the result of calling open_debug_file
- on the separate debug info file, or NULL if there were problems or there
- is no such file. */
+/* 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
+ will be populated with open file handles. */
-void *
-load_separate_debug_file (void * file, const char * filename)
+bfd_boolean
+load_separate_debug_files (void * file, const char * filename)
{
/* Skip this operation if we are not interested in debug links. */
if (! do_follow_links && ! do_debug_links)
- return NULL;
+ return FALSE;
- /* See if there is a dwo link. */
+ /* See if there are any dwo links. */
if (load_debug_section (str, file)
&& load_debug_section (abbrev, file)
&& load_debug_section (info, file))
{
- dwo_name = dwo_dir = NULL;
- dwo_id = NULL;
- dwo_id_len = 0;
+ free_dwo_info ();
if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
{
- if (dwo_name != NULL)
+ bfd_boolean introduced = FALSE;
+ dwo_info * dwinfo;
+ const char * dir = NULL;
+ const char * id = NULL;
+
+ for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
{
- if (do_debug_links)
+ switch (dwinfo->type)
{
- printf (_("The %s section contains a link to a dwo file:\n"),
- debug_displays [info].section.uncompressed_name);
- printf (_(" Name: %s\n"), dwo_name);
- printf (_(" Directory: %s\n"), dwo_dir ? dwo_dir : _("<not-found>"));
- if (dwo_id != NULL)
- display_data (printf (_(" ID: ")), dwo_id, dwo_id_len);
- else
- printf (_(" ID: <unknown>\n"));
- printf ("\n\n");
- }
+ case DWO_NAME:
+ if (do_debug_links)
+ {
+ if (! introduced)
+ {
+ printf (_("The %s section contains link(s) to dwo file(s):\n\n"),
+ debug_displays [info].section.uncompressed_name);
+ introduced = TRUE;
+ }
- /* FIXME: We do not check to see if there are any more dwo links in the file... */
- if (do_follow_links)
- return load_dwo_file (filename);
+ printf (_(" Name: %s\n"), dwinfo->value);
+ 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 ("\n\n");
+ }
+
+ if (do_follow_links)
+ load_dwo_file (filename, dwinfo->value, dir, id);
+ break;
+
+ case DWO_DIR:
+ dir = dwinfo->value;
+ break;
+
+ case DWO_ID:
+ id = dwinfo->value;
+ break;
+
+ default:
+ error (_("Unexpected DWO INFO type"));
+ break;
+ }
}
}
}
if (! do_follow_links)
/* The other debug links will be displayed by display_debug_links()
so we do not need to do any further processing here. */
- return 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. */
{
Build_id_data * build_id_data;
- return load_separate_debug_info (filename,
- & debug_displays[gnu_debugaltlink].section,
- parse_gnu_debugaltlink,
- check_gnu_debugaltlink,
- & build_id_data);
+ load_separate_debug_info (filename,
+ & debug_displays[gnu_debugaltlink].section,
+ parse_gnu_debugaltlink,
+ check_gnu_debugaltlink,
+ & build_id_data);
}
if (load_debug_section (gnu_debuglink, file))
{
unsigned long crc32;
- return load_separate_debug_info (filename,
- & debug_displays[gnu_debuglink].section,
- parse_gnu_debuglink,
- check_gnu_debuglink,
- & crc32);
+ load_separate_debug_info (filename,
+ & debug_displays[gnu_debuglink].section,
+ parse_gnu_debuglink,
+ check_gnu_debuglink,
+ & crc32);
}
+ if (first_separate_info != NULL)
+ return TRUE;
+
do_follow_links = 0;
- return NULL;
+ return FALSE;
}
void
alloc_num_debug_info_entries = num_debug_info_entries = 0;
}
- if (separate_debug_file != NULL)
- {
- close_debug_file (separate_debug_file);
- separate_debug_file = NULL;
+ separate_info * d;
+ separate_info * next;
- free ((void *) separate_debug_filename);
- separate_debug_filename = NULL;
+ for (d = first_separate_info; d != NULL; d = next)
+ {
+ close_debug_file (d->handle);
+ free ((void *) d->filename);
+ next = d->next;
+ free ((void *) d);
}
+ first_separate_info = NULL;
+
+ free_dwo_info ();
}
void