Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "bfdlink.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcore.h"
#include "complaints.h"
#include "demangle.h"
#include "inferior.h" /* for write_pc */
+#include "filenames.h" /* for DOSish file names */
#include "gdb-stabs.h"
#include "gdb_obstack.h"
#include "completer.h"
static void add_shared_symbol_files_command (char *, int);
+static void reread_separate_symbols (struct objfile *objfile);
+
static void cashier_psymtab (struct partial_symtab *);
bfd *symfile_bfd_open (char *);
static void info_ext_lang_command (char *args, int from_tty);
+static char *find_separate_debug_file (struct objfile *objfile);
+
static void init_filename_language_table (void);
void _initialize_symfile (void);
(*objfile->sf->sym_read) (objfile, mainline);
- if (!have_partial_symbols () && !have_full_symbols ())
- {
- wrap_here ("");
- printf_filtered ("(no debugging symbols found)...");
- wrap_here ("");
- }
-
/* Don't allow char * to have a typename (else would get caddr_t).
Ditto void *. FIXME: Check whether this is now done by all the
symbol readers themselves (many of them now do), and if so remove
NAME is the file name (which will be tilde-expanded and made
absolute herein) (but we don't free or modify NAME itself).
- FROM_TTY says how verbose to be. MAINLINE specifies whether this
- is the main symbol file, or whether it's an extra symbol file such
- as dynamically loaded code. If !mainline, ADDR is the address
- where the text segment was loaded.
+
+ FROM_TTY says how verbose to be.
+
+ MAINLINE specifies whether this is the main symbol file, or whether
+ it's an extra symbol file such as dynamically loaded code.
+
+ ADDRS, OFFSETS, and NUM_OFFSETS are as described for
+ syms_from_objfile, above. ADDRS is ignored when MAINLINE is
+ non-zero.
Upon success, returns a pointer to the objfile that was added.
Upon failure, jumps back to command level (never returns). */
-
-struct objfile *
-symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs,
- int mainline, int flags)
+static struct objfile *
+symbol_file_add_with_addrs_or_offsets (char *name, int from_tty,
+ struct section_addr_info *addrs,
+ struct section_offsets *offsets,
+ int num_offsets,
+ int mainline, int flags)
{
struct objfile *objfile;
struct partial_symtab *psymtab;
+ char *debugfile;
bfd *abfd;
+ struct section_addr_info orig_addrs;
+
+ if (addrs)
+ orig_addrs = *addrs;
/* Open a bfd for the file, and give user a chance to burp if we'd be
interactively wiping out any existing symbols. */
gdb_flush (gdb_stdout);
}
}
- syms_from_objfile (objfile, addrs, 0, 0, mainline, from_tty);
+ syms_from_objfile (objfile, addrs, offsets, num_offsets,
+ mainline, from_tty);
}
/* We now have at least a partial symbol table. Check to see if the
}
}
+ debugfile = find_separate_debug_file (objfile);
+ if (debugfile)
+ {
+ if (addrs != NULL)
+ {
+ objfile->separate_debug_objfile
+ = symbol_file_add (debugfile, from_tty, &orig_addrs, 0, flags);
+ }
+ else
+ {
+ objfile->separate_debug_objfile
+ = symbol_file_add (debugfile, from_tty, NULL, 0, flags);
+ }
+ objfile->separate_debug_objfile->separate_debug_objfile_backlink
+ = objfile;
+
+ /* Put the separate debug object before the normal one, this is so that
+ usage of the ALL_OBJFILES_SAFE macro will stay safe. */
+ put_objfile_before (objfile->separate_debug_objfile, objfile);
+
+ xfree (debugfile);
+ }
+
+ if (!have_partial_symbols () && !have_full_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
if (from_tty || info_verbose)
{
if (post_add_symbol_hook)
return (objfile);
}
+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file. See symbol_file_add_with_addrs_or_offsets's comments
+ for details. */
+struct objfile *
+symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs,
+ int mainline, int flags)
+{
+ return symbol_file_add_with_addrs_or_offsets (name, from_tty, addrs, 0, 0,
+ mainline, flags);
+}
+
+
/* Call symbol_file_add() with default values and update whatever is
affected by the loading of a new main().
Used when the file is supplied in the gdb command line
#endif
}
+static char *
+get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
+{
+ asection *sect;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ char *contents;
+ int crc_offset;
+ unsigned char *p;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
+
+ if (sect == NULL)
+ return NULL;
+
+ debuglink_size = bfd_section_size (objfile->obfd, sect);
+
+ contents = xmalloc (debuglink_size);
+ bfd_get_section_contents (objfile->obfd, sect, contents,
+ (file_ptr)0, (bfd_size_type)debuglink_size);
+
+ /* Crc value is stored after the filename, aligned up to 4 bytes. */
+ crc_offset = strlen (contents) + 1;
+ crc_offset = (crc_offset + 3) & ~3;
+
+ crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
+
+ *crc32_out = crc32;
+ return contents;
+}
+
+static int
+separate_debug_file_exists (const char *name, unsigned long crc)
+{
+ unsigned long file_crc = 0;
+ int fd;
+ char buffer[8*1024];
+ int count;
+
+ fd = open (name, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return 0;
+
+ while ((count = read (fd, buffer, sizeof (buffer))) > 0)
+ file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+
+ close (fd);
+
+ return crc == file_crc;
+}
+
+static char *debug_file_directory = NULL;
+
+#if ! defined (DEBUG_SUBDIRECTORY)
+#define DEBUG_SUBDIRECTORY ".debug"
+#endif
+
+static char *
+find_separate_debug_file (struct objfile *objfile)
+{
+ asection *sect;
+ char *basename;
+ char *dir;
+ char *debugfile;
+ char *name_copy;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ int i;
+
+ basename = get_debug_link_info (objfile, &crc32);
+
+ if (basename == NULL)
+ return NULL;
+
+ dir = xstrdup (objfile->name);
+
+ /* Strip off the final filename part, leaving the directory name,
+ followed by a slash. Objfile names should always be absolute and
+ tilde-expanded, so there should always be a slash in there
+ somewhere. */
+ for (i = strlen(dir) - 1; i >= 0; i--)
+ {
+ if (IS_DIR_SEPARATOR (dir[i]))
+ break;
+ }
+ gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i]));
+ dir[i+1] = '\0';
+
+ debugfile = alloca (strlen (debug_file_directory) + 1
+ + strlen (dir)
+ + strlen (DEBUG_SUBDIRECTORY)
+ + strlen ("/")
+ + strlen (basename)
+ + 1);
+
+ /* First try in the same directory as the original file. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, DEBUG_SUBDIRECTORY);
+ strcat (debugfile, "/");
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the global debugfile directory. */
+ strcpy (debugfile, debug_file_directory);
+ strcat (debugfile, "/");
+ strcat (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ xfree (basename);
+ xfree (dir);
+ return NULL;
+}
+
+
/* This is the symbol-file command. Read the file, analyze its
symbols, and add a struct symtab to a symtab list. The syntax of
the command is rather bizarre--(1) buildargv implements various
for other targets too. */
write_pc (entry);
- /* FIXME: are we supposed to call symbol_file_add or not? According to
- a comment from remote-mips.c (where a call to symbol_file_add was
- commented out), making the call confuses GDB if more than one file is
- loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c
- does. */
+ /* FIXME: are we supposed to call symbol_file_add or not? According
+ to a comment from remote-mips.c (where a call to symbol_file_add
+ was commented out), making the call confuses GDB if more than one
+ file is loaded in. Some targets do (e.g., remote-vx.c) but
+ others don't (or didn't - perhaphs they have all been deleted). */
print_transfer_performance (gdb_stdout, cbdata.data_count,
cbdata.write_count, end_time - start_time);
error ("Can't find the file sections in `%s': %s",
objfile->name, bfd_errmsg (bfd_get_error ()));
}
+ terminate_minimal_symbol_table (objfile);
/* We use the same section offsets as from last time. I'm not
sure whether that is always correct for shared libraries. */
needs to keep track of (such as _sigtramp, or whatever). */
TARGET_SYMFILE_POSTREAD (objfile);
+
+ reread_separate_symbols (objfile);
}
}
}
if (reread_one)
clear_symtab_users ();
}
+
+
+/* Handle separate debug info for OBJFILE, which has just been
+ re-read:
+ - If we had separate debug info before, but now we don't, get rid
+ of the separated objfile.
+ - If we didn't have separated debug info before, but now we do,
+ read in the new separated debug info file.
+ - If the debug link points to a different file, toss the old one
+ and read the new one.
+ This function does *not* handle the case where objfile is still
+ using the same separate debug info file, but that file's timestamp
+ has changed. That case should be handled by the loop in
+ reread_symbols already. */
+static void
+reread_separate_symbols (struct objfile *objfile)
+{
+ char *debug_file;
+ unsigned long crc32;
+
+ /* Does the updated objfile's debug info live in a
+ separate file? */
+ debug_file = find_separate_debug_file (objfile);
+
+ if (objfile->separate_debug_objfile)
+ {
+ /* There are two cases where we need to get rid of
+ the old separated debug info objfile:
+ - if the new primary objfile doesn't have
+ separated debug info, or
+ - if the new primary objfile has separate debug
+ info, but it's under a different filename.
+
+ If the old and new objfiles both have separate
+ debug info, under the same filename, then we're
+ okay --- if the separated file's contents have
+ changed, we will have caught that when we
+ visited it in this function's outermost
+ loop. */
+ if (! debug_file
+ || strcmp (debug_file, objfile->separate_debug_objfile->name) != 0)
+ free_objfile (objfile->separate_debug_objfile);
+ }
+
+ /* If the new objfile has separate debug info, and we
+ haven't loaded it already, do so now. */
+ if (debug_file
+ && ! objfile->separate_debug_objfile)
+ {
+ /* Use the same section offset table as objfile itself.
+ Preserve the flags from objfile that make sense. */
+ objfile->separate_debug_objfile
+ = (symbol_file_add_with_addrs_or_offsets
+ (debug_file,
+ info_verbose, /* from_tty: Don't override the default. */
+ 0, /* No addr table. */
+ objfile->section_offsets, objfile->num_sections,
+ 0, /* Not mainline. See comments about this above. */
+ objfile->flags & (OBJF_MAPPED | OBJF_REORDERED
+ | OBJF_SHARED | OBJF_READNOW
+ | OBJF_USERLOADED)));
+ objfile->separate_debug_objfile->separate_debug_objfile_backlink
+ = objfile;
+ }
+}
+
+
\f
}
}
+/* Set the output sections and output offsets for section SECTP in
+ ABFD. The relocation code in BFD will read these offsets, so we
+ need to be sure they're initialized. We map each section to itself,
+ with no offset; this means that SECTP->vma will be honored. */
+
+static void
+symfile_dummy_outputs (bfd *abfd, asection *sectp, void *dummy)
+{
+ sectp->output_section = sectp;
+ sectp->output_offset = 0;
+}
+
+/* Relocate the contents of a debug section SECTP in ABFD. The
+ contents are stored in BUF if it is non-NULL, or returned in a
+ malloc'd buffer otherwise.
+
+ For some platforms and debug info formats, shared libraries contain
+ relocations against the debug sections (particularly for DWARF-2;
+ one affected platform is PowerPC GNU/Linux, although it depends on
+ the version of the linker in use). Also, ELF object files naturally
+ have unresolved relocations for their debug sections. We need to apply
+ the relocations in order to get the locations of symbols correct. */
+
+bfd_byte *
+symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf)
+{
+ /* We're only interested in debugging sections with relocation
+ information. */
+ if ((sectp->flags & SEC_RELOC) == 0)
+ return NULL;
+ if ((sectp->flags & SEC_DEBUGGING) == 0)
+ return NULL;
+
+ /* We will handle section offsets properly elsewhere, so relocate as if
+ all sections begin at 0. */
+ bfd_map_over_sections (abfd, symfile_dummy_outputs, NULL);
+
+ return bfd_simple_get_relocated_section_contents (abfd, sectp, buf);
+}
void
_initialize_symfile (void)
"cache.\n",
&setlist),
&showlist);
+
+ debug_file_directory = xstrdup (DEBUGDIR);
+ c = (add_set_cmd
+ ("debug-file-directory", class_support, var_string,
+ (char *) &debug_file_directory,
+ "Set the directory where separate debug symbols are searched for.\n"
+ "Separate debug symbols are first searched for in the same\n"
+ "directory as the binary, then in the `" DEBUG_SUBDIRECTORY
+ "' subdirectory,\n"
+ "and lastly at the path of the directory of the binary with\n"
+ "the global debug-file directory prepended\n",
+ &setlist));
+ add_show_from_set (c, &showlist);
+ set_cmd_completer (c, filename_completer);
+
}