/* 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.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "bfdlink.h"
#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);
int get_section_index (struct objfile *, char *);
-static void find_sym_fns (struct objfile *);
+static struct sym_fns *find_sym_fns (bfd *);
static void decrement_reading_symtab (void *);
static void init_filename_language_table (void);
+static void symfile_find_segment_sections (struct objfile *objfile);
+
void _initialize_symfile (void);
/* List of all available sym_fns. On gdb startup, each object file reader
/* This is where things get really weird... We MUST have valid
indices for the various sect_index_* members or gdb will abort.
So if for example, there is no ".text" section, we have to
- accomodate that. Except when explicitly adding symbol files at
- some address, section_offsets contains nothing but zeros, so it
- doesn't matter which slot in section_offsets the individual
- sect_index_* members index into. So if they are all zero, it is
- safe to just point all the currently uninitialized indices to the
- first slot. */
+ accomodate that. First, check for a file with the standard
+ one or two segments. */
+
+ symfile_find_segment_sections (objfile);
+
+ /* Except when explicitly adding symbol files at some address,
+ section_offsets contains nothing but zeros, so it doesn't matter
+ which slot in section_offsets the individual sect_index_* members
+ index into. So if they are all zero, it is safe to just point
+ all the currently uninitialized indices to the first slot. But
+ beware: if this is the main executable, it may be relocated
+ later, e.g. by the remote qOffsets packet, and then this will
+ be wrong! That's why we try segments first. */
for (i = 0; i < objfile->num_sections; i++)
{
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;
}
}
}
+/* Divide the file into segments, which are individual relocatable units.
+ This is the default version of the sym_fns.sym_segments function for
+ symbol readers that do not have an explicit representation of segments.
+ It assumes that object files do not have segments, and fully linked
+ files have a single segment. */
+
+struct symfile_segment_data *
+default_symfile_segments (bfd *abfd)
+{
+ int num_sections, i;
+ asection *sect;
+ struct symfile_segment_data *data;
+ CORE_ADDR low, high;
+
+ /* Relocatable files contain enough information to position each
+ loadable section independently; they should not be relocated
+ in segments. */
+ if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) == 0)
+ return NULL;
+
+ /* Make sure there is at least one loadable section in the file. */
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ {
+ if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
+ continue;
+
+ break;
+ }
+ if (sect == NULL)
+ return NULL;
+
+ low = bfd_get_section_vma (abfd, sect);
+ high = low + bfd_get_section_size (sect);
+
+ data = XZALLOC (struct symfile_segment_data);
+ data->num_segments = 1;
+ data->segment_bases = XCALLOC (1, CORE_ADDR);
+ data->segment_sizes = XCALLOC (1, CORE_ADDR);
+
+ num_sections = bfd_count_sections (abfd);
+ data->segment_info = XCALLOC (num_sections, int);
+
+ for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ {
+ CORE_ADDR vma;
+
+ if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
+ continue;
+
+ vma = bfd_get_section_vma (abfd, sect);
+ if (vma < low)
+ low = vma;
+ if (vma + bfd_get_section_size (sect) > high)
+ high = vma + bfd_get_section_size (sect);
+
+ data->segment_info[i] = 1;
+ }
+
+ data->segment_bases[0] = low;
+ data->segment_sizes[0] = high - low;
+
+ return data;
+}
+
/* Process a symbol file, as either the main file or as a dynamically
loaded file.
gdb_assert (! (addrs && offsets));
init_entry_point_info (objfile);
- find_sym_fns (objfile);
+ objfile->sf = find_sym_fns (objfile->obfd);
if (objfile->sf == NULL)
return; /* No symbols. */
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;
struct sym_fns in the objfile structure, that contains cached
information about the symbol file. */
-static void
-find_sym_fns (struct objfile *objfile)
+static struct sym_fns *
+find_sym_fns (bfd *abfd)
{
struct sym_fns *sf;
- enum bfd_flavour our_flavour = bfd_get_flavour (objfile->obfd);
- char *our_target = bfd_get_target (objfile->obfd);
+ enum bfd_flavour our_flavour = bfd_get_flavour (abfd);
if (our_flavour == bfd_target_srec_flavour
|| our_flavour == bfd_target_ihex_flavour
|| our_flavour == bfd_target_tekhex_flavour)
- return; /* No symbols. */
+ return NULL; /* No symbols. */
for (sf = symtab_fns; sf != NULL; sf = sf->next)
- {
- if (our_flavour == sf->sym_flavour)
- {
- objfile->sf = sf;
- return;
- }
- }
+ if (our_flavour == sf->sym_flavour)
+ return sf;
error (_("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown."),
- bfd_get_target (objfile->obfd));
+ bfd_get_target (abfd));
}
\f
const struct timeval *start_time,
const struct timeval *end_time)
{
- unsigned long time_count;
+ ULONGEST time_count;
/* Compute the elapsed time in milliseconds, as a tradeoff between
accuracy and overflow. */
ui_out_text (uiout, "Transfer rate: ");
if (time_count > 0)
{
- ui_out_field_fmt (uiout, "transfer-rate", "%lu",
- 1000 * (data_count * 8) / time_count);
- ui_out_text (uiout, " bits/sec");
+ unsigned long rate = ((ULONGEST) data_count * 1000) / time_count;
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate * 8);
+ ui_out_text (uiout, " bits/sec");
+ }
+ else if (rate < 1024)
+ {
+ ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate);
+ ui_out_text (uiout, " bytes/sec");
+ }
+ else
+ {
+ ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate / 1024);
+ ui_out_text (uiout, " KB/sec");
+ }
}
else
{
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->separate_debug_objfile->separate_debug_objfile_backlink
= objfile;
}
+ if (debug_file)
+ xfree (debug_file);
}
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);
enum overlay_debugging_state overlay_debugging = ovly_off;
int overlay_cache_invalid = 0; /* True if need to refresh mapped state */
-/* Target vector for refreshing overlay mapped state */
-static void simple_overlay_update (struct obj_section *);
-void (*target_overlay_update) (struct obj_section *) = simple_overlay_update;
-
/* Function: section_is_overlay (SECTION)
Returns true if SECTION has VMA not equal to LMA, ie.
SECTION is loaded at an address different from where it will "run". */
case ovly_off:
return 0; /* overlay debugging off */
case ovly_auto: /* overlay debugging automatic */
- /* Unles there is a target_overlay_update function,
+ /* Unles there is a gdbarch_overlay_update function,
there's really nothing useful to do here (can't really go auto) */
- if (target_overlay_update)
+ if (gdbarch_overlay_update_p (current_gdbarch))
{
if (overlay_cache_invalid)
{
overlay_cache_invalid = 0;
}
if (osect->ovly_mapped == -1)
- (*target_overlay_update) (osect);
+ gdbarch_overlay_update (current_gdbarch, osect);
}
/* fall thru to manual case */
case ovly_on: /* overlay debugging manual */
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++;
static void
overlay_load_command (char *args, int from_tty)
{
- if (target_overlay_update)
- (*target_overlay_update) (NULL);
+ if (gdbarch_overlay_update_p (current_gdbarch))
+ gdbarch_overlay_update (current_gdbarch, NULL);
else
error (_("This target does not know how to read its overlay state."));
}
This is GDB's default target overlay layer. It works with the
minimal overlay manager supplied as an example by Cygnus. The
- entry point is via a function pointer "target_overlay_update",
+ entry point is via a function pointer "gdbarch_overlay_update",
so targets that use a different runtime overlay manager can
substitute their own overlay_update function and take over the
function pointer.
{
VMA, SIZE, LMA, MAPPED
};
-#define TARGET_LONG_BYTES (TARGET_LONG_BIT / TARGET_CHAR_BIT)
+#define TARGET_LONG_BYTES (gdbarch_long_bit (current_gdbarch) \
+ / TARGET_CHAR_BIT)
/* Throw away the cached copy of _ovly_table */
static void
If a cached entry can't be found or the cache isn't valid, then
re-read the entire cache, and go ahead and update all sections. */
-static void
+void
simple_overlay_update (struct obj_section *osect)
{
struct objfile *objfile;
return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL);
}
+struct symfile_segment_data *
+get_symfile_segment_data (bfd *abfd)
+{
+ struct sym_fns *sf = find_sym_fns (abfd);
+
+ if (sf == NULL)
+ return NULL;
+
+ return sf->sym_segments (abfd);
+}
+
+void
+free_symfile_segment_data (struct symfile_segment_data *data)
+{
+ xfree (data->segment_bases);
+ xfree (data->segment_sizes);
+ xfree (data->segment_info);
+ 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, then verify that all the excess addresses are
+ the same as the last legitimate one, and then ignore them. This
+ allows "TextSeg=X;DataSeg=X" qOffset replies for files which have
+ only a single segment. */
+int
+symfile_map_offsets_to_segments (bfd *abfd, struct symfile_segment_data *data,
+ struct section_offsets *offsets,
+ int num_segment_bases,
+ const CORE_ADDR *segment_bases)
+{
+ 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);
+
+ /* Check any extra SEGMENT_BASES entries. */
+ 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)
+ {
+ 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)
+ which = num_segment_bases;
+
+ offsets->offsets[i] = (segment_bases[which - 1]
+ - data->segment_bases[which - 1]);
+ }
+
+ return 1;
+}
+
+static void
+symfile_find_segment_sections (struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ int i;
+ asection *sect;
+ struct symfile_segment_data *data;
+
+ data = get_symfile_segment_data (objfile->obfd);
+ if (data == NULL)
+ return;
+
+ if (data->num_segments != 1 && data->num_segments != 2)
+ {
+ free_symfile_segment_data (data);
+ return;
+ }
+
+ for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ {
+ CORE_ADDR vma;
+ int which = data->segment_info[i];
+
+ if (which == 1)
+ {
+ if (objfile->sect_index_text == -1)
+ objfile->sect_index_text = sect->index;
+
+ if (objfile->sect_index_rodata == -1)
+ objfile->sect_index_rodata = sect->index;
+ }
+ else if (which == 2)
+ {
+ if (objfile->sect_index_data == -1)
+ objfile->sect_index_data = sect->index;
+
+ if (objfile->sect_index_bss == -1)
+ objfile->sect_index_bss = sect->index;
+ }
+ }
+
+ free_symfile_segment_data (data);
+}
+
void
_initialize_symfile (void)
{