/* Generic symbol file reading for the GNU debugger, GDB.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Cygnus Support, using pieces from other GDB modules.
#include "exec.h"
#include "parser-defs.h"
#include "varobj.h"
+#include "elf-bfd.h"
+#include "solib.h"
#include <sys/types.h>
#include <fcntl.h>
static void simple_free_overlay_region_table (void);
#endif
-static void set_initial_language (void);
-
static void load_command (char *, int);
static void symbol_file_add_main_1 (char *args, int from_tty, int flags);
offsets[sect->index] = start_addr;
arg->lowest = start_addr + bfd_get_section_size (sect);
-
- exec_set_section_address (bfd_get_filename (abfd), sect->index, start_addr);
}
/* Parse the user's idea of an offset for dynamic linking, into our idea
continue;
bfd_set_section_vma (abfd, cur_sec, offsets[cur_sec->index]);
+ exec_set_section_address (bfd_get_filename (abfd), cur_sec->index,
+ offsets[cur_sec->index]);
offsets[cur_sec->index] = 0;
}
}
bfd_map_over_sections (objfile->obfd, find_lowest_section,
&lower_sect);
if (lower_sect == NULL)
- warning (_("no loadable sections found in added symbol-file %s"),
- objfile->name);
- else
- if ((bfd_get_section_flags (objfile->obfd, lower_sect) & SEC_CODE) == 0)
- warning (_("Lowest section in %s is %s at %s"),
- objfile->name,
- bfd_section_name (objfile->obfd, lower_sect),
- paddr (bfd_section_vma (objfile->obfd, lower_sect)));
- if (lower_sect != NULL)
- lower_offset = bfd_section_vma (objfile->obfd, lower_sect);
+ {
+ warning (_("no loadable sections found in added symbol-file %s"),
+ objfile->name);
+ lower_offset = 0;
+ }
else
- lower_offset = 0;
+ lower_offset = bfd_section_vma (objfile->obfd, lower_sect);
/* Calculate offsets for the loadable sections.
FIXME! Sections must be in order of increasing loadable section
{
struct objfile *objfile;
struct partial_symtab *psymtab;
- char *debugfile;
+ char *debugfile = NULL;
struct section_addr_info *orig_addrs = NULL;
struct cleanup *my_cleanups;
const char *name = bfd_get_filename (abfd);
}
}
- debugfile = find_separate_debug_file (objfile);
+ /* If the file has its own symbol tables it has no separate debug info.
+ `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS.
+ `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */
+ if (objfile->psymtabs == NULL)
+ debugfile = find_separate_debug_file (objfile);
if (debugfile)
{
if (addrs != NULL)
storage has just been released, we'd better wipe the solib
descriptors as well.
*/
-#if defined(SOLIB_RESTART)
- SOLIB_RESTART ();
-#endif
+ no_shared_libraries (NULL, from_tty);
symfile_objfile = NULL;
if (from_tty)
printf_unfiltered (_("No symbol file now.\n"));
}
+struct build_id
+ {
+ size_t size;
+ gdb_byte data[1];
+ };
+
+/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */
+
+static struct build_id *
+build_id_bfd_get (bfd *abfd)
+{
+ struct build_id *retval;
+
+ if (!bfd_check_format (abfd, bfd_object)
+ || bfd_get_flavour (abfd) != bfd_target_elf_flavour
+ || elf_tdata (abfd)->build_id == NULL)
+ return NULL;
+
+ retval = xmalloc (sizeof *retval - 1 + elf_tdata (abfd)->build_id_size);
+ retval->size = elf_tdata (abfd)->build_id_size;
+ memcpy (retval->data, elf_tdata (abfd)->build_id, retval->size);
+
+ return retval;
+}
+
+/* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */
+
+static int
+build_id_verify (const char *filename, struct build_id *check)
+{
+ bfd *abfd;
+ struct build_id *found = NULL;
+ int retval = 0;
+
+ /* We expect to be silent on the non-existing files. */
+ abfd = bfd_openr (filename, gnutarget);
+ if (abfd == NULL)
+ return 0;
+
+ found = build_id_bfd_get (abfd);
+
+ if (found == NULL)
+ warning (_("File \"%s\" has no build-id, file skipped"), filename);
+ else if (found->size != check->size
+ || memcmp (found->data, check->data, found->size) != 0)
+ warning (_("File \"%s\" has a different build-id, file skipped"), filename);
+ else
+ retval = 1;
+
+ if (!bfd_close (abfd))
+ warning (_("cannot close \"%s\": %s"), filename,
+ bfd_errmsg (bfd_get_error ()));
+ return retval;
+}
+
+static char *
+build_id_to_debug_filename (struct build_id *build_id)
+{
+ char *link, *s, *retval = NULL;
+ gdb_byte *data = build_id->data;
+ size_t size = build_id->size;
+
+ /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */
+ link = xmalloc (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1
+ + 2 * size + (sizeof ".debug" - 1) + 1);
+ s = link + sprintf (link, "%s/.build-id/", debug_file_directory);
+ if (size > 0)
+ {
+ size--;
+ s += sprintf (s, "%02x", (unsigned) *data++);
+ }
+ if (size > 0)
+ *s++ = '/';
+ while (size-- > 0)
+ s += sprintf (s, "%02x", (unsigned) *data++);
+ strcpy (s, ".debug");
+
+ /* lrealpath() is expensive even for the usually non-existent files. */
+ if (access (link, F_OK) == 0)
+ retval = lrealpath (link);
+ xfree (link);
+
+ if (retval != NULL && !build_id_verify (retval, build_id))
+ {
+ xfree (retval);
+ retval = NULL;
+ }
+
+ return retval;
+}
+
static char *
get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
{
bfd_size_type debuglink_size;
unsigned long crc32;
int i;
+ struct build_id *build_id;
+
+ build_id = build_id_bfd_get (objfile->obfd);
+ if (build_id != NULL)
+ {
+ char *build_id_name;
+
+ build_id_name = build_id_to_debug_filename (build_id);
+ free (build_id);
+ /* Prevent looping on a stripped .debug file. */
+ if (build_id_name != NULL && strcmp (build_id_name, objfile->name) == 0)
+ {
+ warning (_("\"%s\": separate debug info file has no debug info"),
+ build_id_name);
+ xfree (build_id_name);
+ }
+ else if (build_id_name != NULL)
+ return build_id_name;
+ }
basename = get_debug_link_info (objfile, &crc32);
stabs we find, but we can't do that until later when we read in
full symbols. */
-static void
+void
set_initial_language (void)
{
struct partial_symtab *pst;
entered on the command line. */
section_addrs->other[sec_num].name = sec;
section_addrs->other[sec_num].addr = addr;
- printf_unfiltered ("\t%s_addr = %s\n",
- sec, hex_string ((unsigned long)addr));
+ printf_unfiltered ("\t%s_addr = %s\n", sec, paddress (addr));
sec_num++;
/* The object's sections are initialized when a
/* We need to do this whenever any symbols go away. */
make_cleanup (clear_symtab_users_cleanup, 0 /*ignore*/);
+ if (exec_bfd != NULL && strcmp (bfd_get_filename (objfile->obfd),
+ bfd_get_filename (exec_bfd)) == 0)
+ {
+ /* Reload EXEC_BFD without asking anything. */
+
+ exec_file_attach (bfd_get_filename (objfile->obfd), 0);
+ }
+
/* Clean up any state BFD has sitting around. We don't need
to close the descriptor but BFD lacks a way of closing the
BFD without closing the descriptor. */
sizeof (objfile->msymbol_hash));
memset (&objfile->msymbol_demangled_hash, 0,
sizeof (objfile->msymbol_demangled_hash));
- objfile->fundamental_types = NULL;
clear_objfile_data (objfile);
if (objfile->sf != NULL)
{
objfile->mtime = new_modtime;
reread_one = 1;
reread_separate_symbols (objfile);
+ init_entry_point_info (objfile);
}
}
}
add_filename_language (".f", language_fortran);
add_filename_language (".F", language_fortran);
add_filename_language (".s", language_asm);
+ add_filename_language (".sx", language_asm);
add_filename_language (".S", language_asm);
add_filename_language (".pas", language_pascal);
add_filename_language (".p", language_pascal);
return (psymtab);
}
\f
-/* Add a symbol with a long value to a psymtab.
- Since one arg is a struct, we pass in a ptr and deref it (sigh).
- Return the partial symbol that has been added. */
-
-/* NOTE: carlton/2003-09-11: The reason why we return the partial
- symbol is so that callers can get access to the symbol's demangled
- name, which they don't have any cheap way to determine otherwise.
- (Currenly, dwarf2read.c is the only file who uses that information,
- though it's possible that other readers might in the future.)
- Elena wasn't thrilled about that, and I don't blame her, but we
- couldn't come up with a better way to get that information. If
- it's needed in other situations, we could consider breaking up
- SYMBOL_SET_NAMES to provide access to the demangled name lookup
- cache. */
-
-const struct partial_symbol *
-add_psymbol_to_list (char *name, int namelength, domain_enum domain,
- enum address_class class,
- struct psymbol_allocation_list *list, long val, /* Value as a long */
- CORE_ADDR coreaddr, /* Value as a CORE_ADDR */
- enum language language, struct objfile *objfile)
+/* Helper function, initialises partial symbol structure and stashes
+ it into objfile's bcache. Note that our caching mechanism will
+ use all fields of struct partial_symbol to determine hash value of the
+ structure. In other words, having two symbols with the same name but
+ different domain (or address) is possible and correct. */
+
+static struct partial_symbol *
+add_psymbol_to_bcache (char *name, int namelength, domain_enum domain,
+ enum address_class class,
+ long val, /* Value as a long */
+ CORE_ADDR coreaddr, /* Value as a CORE_ADDR */
+ enum language language, struct objfile *objfile,
+ int *added)
{
- struct partial_symbol *psym;
- char *buf = alloca (namelength + 1);
+ char *buf = name;
/* psymbol is static so that there will be no uninitialized gaps in the
structure which might contain random data, causing cache misses in
bcache. */
static struct partial_symbol psymbol;
-
- /* Create local copy of the partial symbol */
- memcpy (buf, name, namelength);
- buf[namelength] = '\0';
+
+ if (name[namelength] != '\0')
+ {
+ buf = alloca (namelength + 1);
+ /* Create local copy of the partial symbol */
+ memcpy (buf, name, namelength);
+ buf[namelength] = '\0';
+ }
/* val and coreaddr are mutually exclusive, one of them *will* be zero */
if (val != 0)
{
SYMBOL_SET_NAMES (&psymbol, buf, namelength, objfile);
/* Stash the partial symbol away in the cache */
- psym = deprecated_bcache (&psymbol, sizeof (struct partial_symbol),
- objfile->psymbol_cache);
+ return deprecated_bcache_added (&psymbol, sizeof (struct partial_symbol),
+ objfile->psymbol_cache, added);
+}
- /* Save pointer to partial symbol in psymtab, growing symtab if needed. */
+/* Helper function, adds partial symbol to the given partial symbol
+ list. */
+
+static void
+append_psymbol_to_list (struct psymbol_allocation_list *list,
+ struct partial_symbol *psym,
+ struct objfile *objfile)
+{
if (list->next >= list->list + list->size)
- {
- extend_psymbol_list (list, objfile);
- }
+ extend_psymbol_list (list, objfile);
*list->next++ = psym;
OBJSTAT (objfile, n_psyms++);
+}
+
+/* Add a symbol with a long value to a psymtab.
+ Since one arg is a struct, we pass in a ptr and deref it (sigh).
+ Return the partial symbol that has been added. */
+
+/* NOTE: carlton/2003-09-11: The reason why we return the partial
+ symbol is so that callers can get access to the symbol's demangled
+ name, which they don't have any cheap way to determine otherwise.
+ (Currenly, dwarf2read.c is the only file who uses that information,
+ though it's possible that other readers might in the future.)
+ Elena wasn't thrilled about that, and I don't blame her, but we
+ couldn't come up with a better way to get that information. If
+ it's needed in other situations, we could consider breaking up
+ SYMBOL_SET_NAMES to provide access to the demangled name lookup
+ cache. */
+
+const struct partial_symbol *
+add_psymbol_to_list (char *name, int namelength, domain_enum domain,
+ enum address_class class,
+ struct psymbol_allocation_list *list,
+ long val, /* Value as a long */
+ CORE_ADDR coreaddr, /* Value as a CORE_ADDR */
+ enum language language, struct objfile *objfile)
+{
+ struct partial_symbol *psym;
+ int added;
+
+ /* Stash the partial symbol away in the cache */
+ psym = add_psymbol_to_bcache (name, namelength, domain, class,
+ val, coreaddr, language, objfile, &added);
+
+ /* Do not duplicate global partial symbols. */
+ if (list == &objfile->global_psymbols
+ && !added)
+ return psym;
+
+ /* Save pointer to partial symbol in psymtab, growing symtab if needed. */
+ append_psymbol_to_list (list, psym, objfile);
return psym;
}
name = bfd_section_name (objfile->obfd, osect->the_bfd_section);
printf_filtered ("Section %s, loaded at ", name);
- deprecated_print_address_numeric (lma, 1, gdb_stdout);
+ fputs_filtered (paddress (lma), gdb_stdout);
puts_filtered (" - ");
- deprecated_print_address_numeric (lma + size, 1, gdb_stdout);
+ fputs_filtered (paddress (lma + size), gdb_stdout);
printf_filtered (", mapped at ");
- deprecated_print_address_numeric (vma, 1, gdb_stdout);
+ fputs_filtered (paddress (vma), gdb_stdout);
puts_filtered (" - ");
- deprecated_print_address_numeric (vma + size, 1, gdb_stdout);
+ fputs_filtered (paddress (vma + size), gdb_stdout);
puts_filtered ("\n");
nmapped++;
xfree (data);
}
+
+/* Given:
+ - DATA, containing segment addresses from the object file ABFD, and
+ the mapping from ABFD's sections onto the segments that own them,
+ and
+ - SEGMENT_BASES[0 .. NUM_SEGMENT_BASES - 1], holding the actual
+ segment addresses reported by the target,
+ store the appropriate offsets for each section in OFFSETS.
+
+ If there are fewer entries in SEGMENT_BASES than there are segments
+ in DATA, then apply SEGMENT_BASES' last entry to all the segments.
+
+ If there are more entries, then ignore the extra. The target may
+ not be able to distinguish between an empty data segment and a
+ missing data segment; a missing text segment is less plausible. */
int
symfile_map_offsets_to_segments (bfd *abfd, struct symfile_segment_data *data,
struct section_offsets *offsets,
int i;
asection *sect;
+ /* It doesn't make sense to call this function unless you have some
+ segment base addresses. */
+ gdb_assert (segment_bases > 0);
+
/* If we do not have segment mappings for the object file, we
can not relocate it by segments. */
gdb_assert (data != NULL);
gdb_assert (data->num_segments > 0);
- /* If more offsets are provided than we have segments, make sure the
- excess offsets are all the same as the last segment's offset.
- This allows "Text=X;Data=X" for files which have only a single
- segment. */
- if (num_segment_bases > data->num_segments)
- for (i = data->num_segments; i < num_segment_bases; i++)
- if (segment_bases[i] != segment_bases[data->num_segments - 1])
- return 0;
-
for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
{
- CORE_ADDR vma;
int which = data->segment_info[i];
+ gdb_assert (0 <= which && which <= data->num_segments);
+
+ /* Don't bother computing offsets for sections that aren't
+ loaded as part of any segment. */
+ if (! which)
+ continue;
+
+ /* Use the last SEGMENT_BASES entry as the address of any extra
+ segments mentioned in DATA->segment_info. */
if (which > num_segment_bases)
- offsets->offsets[i] = segment_bases[num_segment_bases - 1];
- else if (which > 0)
- offsets->offsets[i] = segment_bases[which - 1];
- else
- continue;
+ which = num_segment_bases;
- offsets->offsets[i] -= data->segment_bases[which - 1];
+ offsets->offsets[i] = (segment_bases[which - 1]
+ - data->segment_bases[which - 1]);
}
return 1;