From: Nick Clifton Date: Fri, 22 Feb 2019 10:36:24 +0000 (+0000) Subject: Extend readelf and objdump so that they will display and follow multiple links to... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=24841daa74f092f7c5639ee8f1fb303c7694dee7;p=binutils-gdb.git 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. --- diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 980bc54c3f7..65316ee9ded 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,41 @@ +2019-02-22 Nick Clifton + + 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 PR 24247 diff --git a/binutils/NEWS b/binutils/NEWS index 34fd9ec04a4..5413321b4ba 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -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 diff --git a/binutils/doc/debug.options.texi b/binutils/doc/debug.options.texi index 57945654d2d..7f07388b567 100644 --- a/binutils/doc/debug.options.texi +++ b/binutils/doc/debug.options.texi @@ -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 diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 60e0ef89355..07142af747e 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -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 _(""); + if (first_separate_info == NULL) + return _(""); - if (! load_debug_section (separate_debug_str, separate_debug_file)) - return _(""); + 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 _(""); + 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 _(""); - } + 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 _(""); + 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 _(""); + + return ret; + } + + warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"), + dwarf_vmatoa ("x", offset)); + return _(""); } 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 = _(""); 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 = _(""); 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) + 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 : _("")); - if (dwo_id != NULL) - display_data (printf (_(" ID: ")), dwo_id, dwo_id_len); - else - printf (_(" ID: \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 : _("")); + if (id != NULL) + display_data (printf (_(" ID: ")), (unsigned char *) id, 8); + else + printf (_(" ID: \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 diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 0895f33b4f5..a0287fc0bc5 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -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 *); diff --git a/binutils/objdump.c b/binutils/objdump.c index 7d0c6a4db44..19365b67a01 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -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 (); } diff --git a/binutils/readelf.c b/binutils/readelf.c index 0e3e43cc8ed..38e9f1b3455 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -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)) diff --git a/binutils/testsuite/binutils-all/objdump.WK2 b/binutils/testsuite/binutils-all/objdump.WK2 index 22bcb0dbb0d..c98fdc15b58 100644 --- a/binutils/testsuite/binutils-all/objdump.WK2 +++ b/binutils/testsuite/binutils-all/objdump.WK2 @@ -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- diff --git a/binutils/testsuite/binutils-all/readelf.k2 b/binutils/testsuite/binutils-all/readelf.k2 index 89ee4b45285..e2ea0ad2808 100644 --- a/binutils/testsuite/binutils-all/readelf.k2 +++ b/binutils/testsuite/binutils-all/readelf.k2 @@ -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)