[binutils-gdb] Add --debug-dir option to readelf and objdumo. Load separate debug info files when disassemblng.

Nick Clifton via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=bfd118583ed69db365265915d1a48eb719e997f5

commit bfd118583ed69db365265915d1a48eb719e997f5
Author: Nick Clifton <[email protected]>
Date:   Fri Apr 17 12:17:27 2026 +0100

    Add --debug-dir option to readelf and objdumo.  Load separate debug info files when disassemblng.

Diff:
---
 binutils/NEWS              |  3 ++
 binutils/doc/binutils.texi |  8 +++++
 binutils/dwarf.c           | 75 +++++++++++++++++++++++-----------------------
 binutils/dwarf.h           |  1 +
 binutils/objdump.c         | 24 ++++++++-------
 binutils/readelf.c         |  7 +++++
 6 files changed, 69 insertions(+), 49 deletions(-)

diff --git a/binutils/NEWS b/binutils/NEWS
index 1a3c25d1fe7..5ac0e8b7811 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Objdump and readelf now have a --debug-dir=<DIR> option which can be used to
+  tell them where to find separate debug info files.
+
 * Add --map-global-vars option to objdump which displays the location and type
   of global variables in object files. This feature was developed by Guillaume
   Vacherias <[email protected]>.
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 8025458b2fa..59ffe548543 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2350,6 +2350,7 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{-WN}|@option{--dwarf=no-follow-links}]
         [@option{-WD}|@option{--dwarf=use-debuginfod}]
         [@option{-WE}|@option{--dwarf=do-not-use-debuginfod}]
+        [@option{--debug-dir=@file{dir}}]
         [@option{--map-global-vars}]
         [@option{-L}|@option{--process-links}]
         [@option{--ctf=}@var{section}]
@@ -2999,6 +3000,9 @@ The @option{off} argument disables colored disassembly.
 @item --dwarf-check
 Enable additional checks for consistency of Dwarf information.
 
+@item --debug-dir=@file{dir}
+Search @file{dir} when looking for separate debug info files.
+
 @include ctf.options.texi
 
 @include sframe.options.texi
@@ -5172,6 +5176,7 @@ readelf [@option{-a}|@option{--all}]
         [@option{-wN}|@option{--debug-dump=no-follow-links}]
         [@option{-wD}|@option{--debug-dump=use-debuginfod}]
         [@option{-wE}|@option{--debug-dump=do-not-use-debuginfod}]
+        [@option{--debug-dir=@file{dir}}]
         [@option{-P}|@option{--process-links}]
         [@option{--dwarf-depth=@var{n}}]
         [@option{--dwarf-start=@var{n}}]
@@ -5477,6 +5482,9 @@ command to @command{ar}, but without using the BFD library.  @xref{ar}.
 @itemx --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=str-offsets,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links,=follow-links]
 @include debug.options.texi
 
+@item --debug-dir=@file{dir}
+Search @file{dir} when looking for separate debug info files.
+
 @item -P
 @itemx --process-links
 Display the contents of non-debug sections found in separate debuginfo
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index fa8dce25d44..42386154b49 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -125,6 +125,8 @@ separate_info * first_separate_info = NULL;
 
 unsigned int eh_addr_size;
 
+const char * separate_debug_info_dir = NULL;
+
 int do_debug_info;
 int do_debug_abbrevs;
 int do_debug_lines;
@@ -13379,17 +13381,22 @@ load_separate_debug_info (const char *            main_filename,
 #define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
 #endif
 
-  debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1
-				    + canon_dirlen
-				    + strlen (".debug/")
+  unsigned long len = 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);
+    + strlen (separate_filename)
+    + 1;
+
+  if (separate_debug_info_dir)
+    len += strlen (separate_debug_info_dir);
+
+  debug_filename = (char *) malloc (len);
   if (debug_filename == NULL)
     {
       warn (_("Out of memory\n"));
@@ -13398,7 +13405,15 @@ load_separate_debug_info (const char *            main_filename,
       return NULL;
     }
 
-  /* First try in the current directory.  */
+  /* If the user has supplied a debug info directory then try that first.  */
+  if (separate_debug_info_dir != NULL)
+    {
+      sprintf (debug_filename, "%s/%s", separate_debug_info_dir, separate_filename);
+      if (check_func (debug_filename, func_data))
+	goto found;      
+    }
+  
+  /* Next try in the current directory.  */
   sprintf (debug_filename, "%s", separate_filename);
   if (check_func (debug_filename, func_data))
     goto found;
@@ -13425,7 +13440,7 @@ load_separate_debug_info (const char *            main_filename,
     goto found;
 
   /* Try the first extra debug file root.  */
-  sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+  sprintf (debug_filename, "%s/%s%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
   if (check_func (debug_filename, func_data))
     goto found;
 #endif
@@ -13468,37 +13483,19 @@ load_separate_debug_info (const char *            main_filename,
   if (do_debug_links)
     {
       /* Failed to find the file.  */
-      warn (_("could not find separate debug file '%s'\n"),
-	    separate_filename);
-      warn (_("tried: %s\n"), debug_filename);
-
-#ifdef EXTRA_DEBUG_ROOT2
-      sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2,
-	       separate_filename);
-      warn (_("tried: %s\n"), debug_filename);
-#endif
-
+      warn (_("could not find separate debug file '%s'\n"), separate_filename);
+      if (separate_debug_info_dir != NULL)
+	warn (_("tried: %s/%s\n"), separate_debug_info_dir, separate_filename);
+      warn (_("tried: %s\n"), separate_filename);
+      warn (_("tried: .debug/%s\n"), separate_filename);
+      warn (_("tried: %s%s\n"), canon_dir, separate_filename);
 #ifdef EXTRA_DEBUG_ROOT1
-      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);
+      warn (_("tried: %s/%s\n"), EXTRA_DEBUG_ROOT1, separate_filename);
+      warn (_("tried: %s/%s%s\n"), EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+#endif
+#ifdef EXTRA_DEBUG_ROOT2
+      warn (_("tried: %s/%s\n"), EXTRA_DEBUG_ROOT2, separate_filename);
 #endif
-
-      sprintf (debug_filename, "%s.debug/%s", canon_dir,
-	       separate_filename);
-      warn (_("tried: %s\n"), debug_filename);
-
-      sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
-      warn (_("tried: %s\n"), debug_filename);
-
-      sprintf (debug_filename, ".debug/%s", separate_filename);
-      warn (_("tried: %s\n"), debug_filename);
-
-      sprintf (debug_filename, "%s", separate_filename);
       warn (_("tried: %s\n"), debug_filename);
 
 #if HAVE_LIBDEBUGINFOD
@@ -13547,6 +13544,7 @@ load_separate_debug_info (const char *            main_filename,
 
   if (do_debug_links)
     printf (_("\n%s: Found separate debug info file: %s\n"), main_filename, debug_filename);
+
   add_separate_debug_file (debug_filename, debug_handle);
 
   /* Do not free debug_filename - it might be referenced inside
@@ -13906,6 +13904,7 @@ load_separate_debug_files (void * file, const char * filename)
   /* FIXME: We do not check for the presence of a dwo link as well as a debuglink.  */
 
   check_for_and_load_links (file, filename);
+
   if (first_separate_info != NULL)
     return true;
 
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 3ab25933052..e6b51bf368e 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -462,6 +462,7 @@ typedef struct separate_info
 extern separate_info * first_separate_info;
 
 extern unsigned int eh_addr_size;
+extern const char * separate_debug_info_dir;
 
 extern int do_debug_info;
 extern int do_debug_abbrevs;
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 8b6021a20fe..944b81b17e0 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -160,7 +160,6 @@ static enum color_selection
   off;
 #endif
 
-static int dump_any_debugging;
 static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
 
 /* This is reset to false each time we enter the disassembler, and set true
@@ -328,6 +327,8 @@ usage (FILE *stream, int status)
   -WE --dwarf=do-not-use-debuginfod\n\
                            When following links, do not query debuginfod servers\n"));
 #endif
+  fprintf (stream, _("\
+      --debug-dir=<DIR>    Search DIR for debug info files\n"));
   fprintf (stream, _("\
       --map-global-vars    Display memory mapping of global variables\n"));
   fprintf (stream, _("\
@@ -481,6 +482,7 @@ enum option_values
     OPTION_START_ADDRESS,
     OPTION_STOP_ADDRESS,
     OPTION_DWARF,
+    OPTION_DEBUG_DIR,
     OPTION_PREFIX,
     OPTION_PREFIX_STRIP,
     OPTION_INSN_WIDTH,
@@ -514,6 +516,7 @@ static struct option long_options[]=
   {"ctf-parent", required_argument, NULL, OPTION_CTF_PARENT},
   {"ctf-parent-section", required_argument, NULL, OPTION_CTF_PARENT_SECTION},
 #endif
+  {"debug-dir", required_argument, NULL, OPTION_DEBUG_DIR},
   {"debugging", no_argument, NULL, 'g'},
   {"debugging-tags", no_argument, NULL, 'e'},
   {"decompress", no_argument, NULL, 'Z'},
@@ -4402,9 +4405,6 @@ load_debug_section (enum dwarf_section_display_enum debug, void *file)
   asection *sec;
   const char *name;
 
-  if (!dump_any_debugging)
-    return false;
-
   /* If it is already loaded, do nothing.  */
   if (section->start != NULL)
     {
@@ -5742,6 +5742,9 @@ might_need_separate_debug_info (bool is_mainfile)
     return true;
   
   if (process_links || dump_symtab || dump_debugging
+      /* Disassembly benefits from symbol tables, which might
+	 be stored in the separate debug info file.  */
+      || disassemble
       || dump_dwarf_section_info || with_source_code)
     return true;
 
@@ -5765,7 +5768,9 @@ dump_bfd (bfd *abfd, bool is_mainfile)
   /* Load any separate debug information files.  */
   if (byte_get != NULL && might_need_separate_debug_info (is_mainfile))
     {
-      load_separate_debug_files (abfd, bfd_get_filename (abfd));
+      /* Since it is possible that there are no separate debug files,
+	 do not complain if calling load_separate_debug_files returns false.  */
+      (void) load_separate_debug_files (abfd, bfd_get_filename (abfd));
 
       /* If asked to do so, recursively dump the separate files.  */
       if (do_follow_links)
@@ -6386,6 +6391,9 @@ main (int argc, char **argv)
 	case OPTION_DWARF_CHECK:
 	  dwarf_check = true;
 	  break;
+	case OPTION_DEBUG_DIR:
+	  separate_debug_info_dir = optarg;
+	  break;
 #ifdef ENABLE_LIBCTF
 	case OPTION_CTF:
 	  dump_ctf_section_info = true;
@@ -6474,12 +6482,6 @@ main (int argc, char **argv)
   if (!seenflag)
     usage (stderr, 2);
 
-  dump_any_debugging = (dump_debugging
-			|| dump_dwarf_section_info
-			|| dump_global_vars
-			|| process_links
-			|| with_source_code);
-
   if (formats_info)
     exit_status = display_info ();
   else
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 869bb23e48f..7b2c1c9ae88 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -6471,6 +6471,7 @@ enum long_option_values
   OPTION_DWARF_DEPTH,
   OPTION_DWARF_START,
   OPTION_DWARF_CHECK,
+  OPTION_DEBUG_DIR,
   OPTION_CTF_DUMP,
   OPTION_CTF_PARENT,
   OPTION_CTF_SYMBOLS,
@@ -6537,6 +6538,7 @@ static struct option options[] =
   {"dwarf-depth",      required_argument, 0, OPTION_DWARF_DEPTH},
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
+  {"debug-dir",        required_argument, NULL, OPTION_DEBUG_DIR},
 #ifdef ENABLE_LIBCTF
   {"ctf",	       required_argument, 0, OPTION_CTF_DUMP},
   {"ctf-symbols",      required_argument, 0, OPTION_CTF_SYMBOLS},
@@ -6680,6 +6682,8 @@ usage (FILE * stream)
   --dwarf-depth=N        Do not display DIEs at depth N or greater\n"));
   fprintf (stream, _("\
   --dwarf-start=N        Display DIEs starting at offset N\n"));
+  fprintf (stream, _("\
+  --debug-dir=<DIR>      Search DIR for debug info files\n"));
 #ifdef ENABLE_LIBCTF
   fprintf (stream, _("\
   --ctf=<number|name>    Display CTF info from section <number|name>\n"));
@@ -6959,6 +6963,9 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
 	case OPTION_DWARF_CHECK:
 	  dwarf_check = true;
 	  break;
+	case OPTION_DEBUG_DIR:
+	  separate_debug_info_dir = optarg;
+	  break;
 	case OPTION_CTF_DUMP:
 	  request_dump (dumpdata, CTF_DUMP);
 	  break;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.