Extend readelf and objdump so that they will display and follow multiple links to separate debug information files.

PR 23843
	* dwarf.h (struct separate_info): New structure for containing
	information on separate debug info files.
	* dwarf.c (struct dwo_info): New structure for containing dwo
	links.
	(first_dwo_info): Chain of dwo_info structures.
	(first_separate_file): Chain of separate_info structures.
	(separate_debug_file, separate_debug_filename): Delete.
	(fetch_alt_indirect_string): Scan all separate debug info files
	for the requested string.
	(add_dwo_info): New function.
	(add_dwo_name): New function.
	(add_dwo_dir): New function.
	(add_dwo_id: New function.
	(free_dwo_info): New function.
	(read_and_display_attr_value): Store DWO data using the new
	functions.
	(load_debug_section_with_follow): If necessary, scan the list of
	separate debug info files for the requested section.
	(add_separate_debug_file): New function.
	(load_separate_debug_info): Call add_separate_debug_file to store
	the information on the newly loaded file.
	(load_dwo_file): Likewise.
	(load_separate_debif_file): Rename to load_separate_debug_files.
	Change return type to boolean.  If following links then attempt to
	load all separate debug info files, not just the first one.
	(free_debug_memory): Release memory in dwo_info and separate_info
	chains.
	* objdump.c (dump_dwarf): Iterate over all loaded debg info files.
	* readelf.c (process_object): Likewise.
	* doc/debug.options.texi: Update descriptions of links and
	follow-links options.
	* testsuite/binutils-all/objdump.WK2: Update expected output.
	* testsuite/binutils-all/readelf.k2: Likewise.
	* NEWS: Announce the new feature.
This commit is contained in:
Nick Clifton 2019-02-22 10:36:24 +00:00
parent 83f43c8344
commit 24841daa74
9 changed files with 381 additions and 187 deletions

View File

@ -1,3 +1,41 @@
2019-02-22 Nick Clifton <nickc@redhat.com>
PR 23843
* dwarf.h (struct separate_info): New structure for containing
information on separate debug info files.
* dwarf.c (struct dwo_info): New structure for containing dwo
links.
(first_dwo_info): Chain of dwo_info structures.
(first_separate_file): Chain of separate_info structures.
(separate_debug_file, separate_debug_filename): Delete.
(fetch_alt_indirect_string): Scan all separate debug info files
for the requested string.
(add_dwo_info): New function.
(add_dwo_name): New function.
(add_dwo_dir): New function.
(add_dwo_id: New function.
(free_dwo_info): New function.
(read_and_display_attr_value): Store DWO data using the new
functions.
(load_debug_section_with_follow): If necessary, scan the list of
separate debug info files for the requested section.
(add_separate_debug_file): New function.
(load_separate_debug_info): Call add_separate_debug_file to store
the information on the newly loaded file.
(load_dwo_file): Likewise.
(load_separate_debif_file): Rename to load_separate_debug_files.
Change return type to boolean. If following links then attempt to
load all separate debug info files, not just the first one.
(free_debug_memory): Release memory in dwo_info and separate_info
chains.
* objdump.c (dump_dwarf): Iterate over all loaded debg info files.
* readelf.c (process_object): Likewise.
* doc/debug.options.texi: Update descriptions of links and
follow-links options.
* testsuite/binutils-all/objdump.WK2: Update expected output.
* testsuite/binutils-all/readelf.k2: Likewise.
* NEWS: Announce the new feature.
2019-02-21 Nick Clifton <nickc@redhat.com>
PR 24247

View File

@ -1,5 +1,11 @@
-*- text -*-
* The separate debug info file options of readelf (--debug-dump=links
and --debug-dump=follow) and objdump (--dwarf=links and
--dwarf=follow-links) will now display and/or follow multiple links if
more than one are present in a file. (This usually happens when gcc's
-gsplit-dwarf option is used).
Changes in 2.32:
* The addr2line, c++filt, nm and objdump tools now have a limit on the

View File

@ -45,18 +45,17 @@ output from this option can also be restricted by the use of the
@item k
@itemx =links
Displays the contents of the @samp{.gnu_debuglink} and/or
@samp{.gnu_debugaltlink} sections. Also displays the link to a
separate dwarf object file (dwo), if one is specified by the
@samp{.gnu_debugaltlink} sections. Also displays any links to
separate dwarf object files (dwo), if they are specified by the
DW_AT_GNU_dwo_name or DW_AT_dwo_name attributes in the
@samp{.debug_info} section.
@item K
@itemx =follow-links
Display the contents of any selected debug sections that are found in
a linked, separate debug info file. This can result in multiple
versions of the same debug section being displayed if both the main
file and the separate debug info file contain sections with the same
name.
linked, separate debug info file(s). This can result in multiple
versions of the same debug section being displayed if it exists in
more than one file.
In addition, when displaying DWARF attributes, if a form is found that
references the separate debug info file, then the referenced contents

View File

@ -48,11 +48,26 @@ static debug_info *debug_information = NULL;
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;
@ -96,10 +111,6 @@ static unsigned int *shndx_pool = NULL;
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.
@ -1711,37 +1722,44 @@ add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc)
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>");
section = &debug_displays [separate_debug_str].section;
if (section->start == NULL)
return _("<no .debug_str section>");
if (offset >= section->size)
for (i = first_separate_info; i != NULL; i = i->next)
{
warn (_("DW_FORM_GNU_strp_alt offset too big: %s\n"), dwarf_vmatoa ("x", offset));
return _("<offset is too big>");
struct dwarf_section * section;
const char * ret;
if (! load_debug_section (separate_debug_str, i->handle))
continue;
section = &debug_displays [separate_debug_str].section;
if (section->start == NULL)
continue;
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;
}
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>");
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 *
@ -1770,6 +1788,49 @@ get_AT_name (unsigned long attribute)
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,
@ -2260,18 +2321,17 @@ read_and_display_attr_value (unsigned long attribute,
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;
@ -2282,21 +2342,20 @@ read_and_display_attr_value (unsigned long attribute,
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;
@ -2306,13 +2365,12 @@ read_and_display_attr_value (unsigned long attribute,
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;
@ -2722,30 +2780,47 @@ read_and_display_attr (unsigned long attribute,
}
/* 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;
}
@ -6003,12 +6078,12 @@ display_debug_loc (struct dwarf_section *section, void *file)
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;
@ -6554,6 +6629,7 @@ display_debug_addr (struct dwarf_section *section,
}
/* 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)
@ -9811,6 +9887,17 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
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,
@ -9819,7 +9906,7 @@ load_separate_debug_info (const char * main_filename,
void * func_data)
{
const char * separate_filename;
char * debugfile;
char * debug_filename;
char * canon_dir;
size_t canon_dirlen;
size_t dirlen;
@ -9851,18 +9938,18 @@ load_separate_debug_info (const char * main_filename,
#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);
@ -9870,171 +9957,199 @@ load_separate_debug_info (const char * main_filename,
}
/* 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;
#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", 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)
{
if (do_debug_links)
{
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");
}
bfd_boolean introduced = FALSE;
dwo_info * dwinfo;
const char * dir = NULL;
const char * id = NULL;
/* 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);
for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
{
switch (dwinfo->type)
{
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;
}
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;
}
}
}
}
@ -10042,7 +10157,7 @@ load_separate_debug_file (void * file, const char * filename)
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. */
@ -10053,26 +10168,29 @@ load_separate_debug_file (void * file, const char * filename)
{
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
@ -10105,14 +10223,19 @@ free_debug_memory (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

View File

@ -187,6 +187,15 @@ typedef struct
}
debug_info;
typedef struct separate_info
{
void * handle; /* The pointer returned by open_debug_file(). */
const char * filename;
struct separate_info * next;
} separate_info;
extern separate_info * first_separate_info;
extern unsigned int eh_addr_size;
extern int do_debug_info;
@ -225,7 +234,7 @@ extern void init_dwarf_regnames_riscv (void);
extern bfd_boolean load_debug_section (enum dwarf_section_display_enum, void *);
extern void free_debug_section (enum dwarf_section_display_enum);
extern void * load_separate_debug_file (void *, const char *);
extern bfd_boolean load_separate_debug_files (void *, const char *);
extern void close_debug_file (void *);
extern void * open_debug_file (const char *);

View File

@ -2882,7 +2882,7 @@ dump_dwarf_section (bfd *abfd, asection *section,
static void
dump_dwarf (bfd *abfd)
{
bfd * separates;
bfd_boolean have_separates;
is_relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
@ -2946,12 +2946,19 @@ dump_dwarf (bfd *abfd)
break;
}
separates = load_separate_debug_file (abfd, bfd_get_filename (abfd));
have_separates = load_separate_debug_files (abfd, bfd_get_filename (abfd));
bfd_map_over_sections (abfd, dump_dwarf_section, NULL);
if (separates)
bfd_map_over_sections (separates, dump_dwarf_section, NULL);
if (have_separates)
{
separate_info * i;
for (i = first_separate_info; i != NULL; i = i->next)
bfd_map_over_sections (i->handle, dump_dwarf_section, NULL);
/* The file handles are closed by the call to free_debug_memory() below. */
}
free_debug_memory ();
}

View File

@ -19302,7 +19302,7 @@ open_debug_file (const char * pathname)
static bfd_boolean
process_object (Filedata * filedata)
{
Filedata * separates;
bfd_boolean have_separate_files;
unsigned int i;
bfd_boolean res = TRUE;
@ -19379,19 +19379,26 @@ process_object (Filedata * filedata)
res = FALSE;
if (filedata->file_header.e_shstrndx != SHN_UNDEF)
separates = load_separate_debug_file (filedata, filedata->file_name);
have_separate_files = load_separate_debug_files (filedata, filedata->file_name);
else
separates = NULL;
have_separate_files = FALSE;
if (! process_section_contents (filedata))
res = FALSE;
if (separates)
if (have_separate_files)
{
if (! process_section_headers (separates))
res = FALSE;
else if (! process_section_contents (separates))
res = FALSE;
separate_info * d;
for (d = first_separate_info; d != NULL; d = d->next)
{
if (! process_section_headers (d->handle))
res = FALSE;
else if (! process_section_contents (d->handle))
res = FALSE;
}
/* The file handles are closed by the call to free_debug_memory() below. */
}
if (! process_notes (filedata))

View File

@ -1,6 +1,6 @@
#...
.*debuglink.o: Found separate debug info file:.*linkdebug.debug
#...
Contents of the .debug_str section \(loaded from .*debuglink.o\):
0x00000000 73747269 6e672d31 00737472 696e672d string-1.string-

View File

@ -1,4 +1,9 @@
The \.debug_info section contains a link to a dwo file:
The \.debug_info section contains link\(s\) to dwo file\(s\):
Name: file\.dwo
Directory: /another/path/
ID: (12|dd) (34|cc) (56|bb) (78|aa) (78|aa) (56|bb) (34|cc) (12|dd)
Name: debugfile\.dwo
Directory: /path/to/dwo/files
ID: (12|dd) (34|cc) (56|bb) (78|aa) (78|aa) (56|bb) (34|cc) (12|dd)