/* 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
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 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 "block.h"
#include "observer.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>
#include <time.h>
#include <sys/time.h>
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num);
void (*deprecated_show_load_progress) (const char *section,
unsigned long total_size);
void (*deprecated_pre_add_symbol_hook) (const char *);
void (*deprecated_post_add_symbol_hook) (void);
-void (*deprecated_target_new_objfile_hook) (struct objfile *);
static void clear_symtab_users_cleanup (void *ignore);
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++)
{
int done;
ULONGEST align = ((ULONGEST) 1) << bfd_get_section_alignment (abfd, sect);
- /* We are only interested in loadable sections. */
- if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0)
+ /* We are only interested in allocated sections. */
+ if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
return;
/* If the user specified an offset, honor it. */
if (cur_sec == sect)
continue;
- /* We can only conflict with loadable sections. */
- if ((bfd_get_section_flags (abfd, cur_sec) & SEC_LOAD) == 0)
- continue;
-
- /* We do not expect this to happen; just ignore sections in a
- relocatable file with an assigned VMA. */
- if (bfd_section_vma (abfd, cur_sec) != 0)
+ /* We can only conflict with allocated sections. */
+ if ((bfd_get_section_flags (abfd, cur_sec) & SEC_ALLOC) == 0)
continue;
/* If the section offset is 0, either the section has not been placed
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
if ((bfd_get_file_flags (objfile->obfd) & (EXEC_P | DYNAMIC)) == 0)
{
struct place_section_arg arg;
- arg.offsets = objfile->section_offsets;
- arg.lowest = 0;
- bfd_map_over_sections (objfile->obfd, place_section, &arg);
+ bfd *abfd = objfile->obfd;
+ asection *cur_sec;
+ CORE_ADDR lowest = 0;
+
+ for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
+ /* We do not expect this to happen; just skip this step if the
+ relocatable file has a section with an assigned VMA. */
+ if (bfd_section_vma (abfd, cur_sec) != 0)
+ break;
+
+ if (cur_sec == NULL)
+ {
+ CORE_ADDR *offsets = objfile->section_offsets->offsets;
+
+ /* Pick non-overlapping offsets for sections the user did not
+ place explicitly. */
+ arg.offsets = objfile->section_offsets;
+ arg.lowest = 0;
+ bfd_map_over_sections (objfile->obfd, place_section, &arg);
+
+ /* Correctly filling in the section offsets is not quite
+ enough. Relocatable files have two properties that
+ (most) shared objects do not:
+
+ - Their debug information will contain relocations. Some
+ shared libraries do also, but many do not, so this can not
+ be assumed.
+
+ - If there are multiple code sections they will be loaded
+ at different relative addresses in memory than they are
+ in the objfile, since all sections in the file will start
+ at address zero.
+
+ Because GDB has very limited ability to map from an
+ address in debug info to the correct code section,
+ it relies on adding SECT_OFF_TEXT to things which might be
+ code. If we clear all the section offsets, and set the
+ section VMAs instead, then symfile_relocate_debug_section
+ will return meaningful debug information pointing at the
+ correct sections.
+
+ GDB has too many different data structures for section
+ addresses - a bfd, objfile, and so_list all have section
+ tables, as does exec_ops. Some of these could probably
+ be eliminated. */
+
+ for (cur_sec = abfd->sections; cur_sec != NULL;
+ cur_sec = cur_sec->next)
+ {
+ if ((bfd_get_section_flags (abfd, cur_sec) & SEC_ALLOC) == 0)
+ 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;
+ }
+ }
}
/* Remember the bfd indexes for the .text, .data, .bss and
}
+/* 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)
new_symfile_objfile (objfile, mainline, from_tty);
- if (deprecated_target_new_objfile_hook)
- deprecated_target_new_objfile_hook (objfile);
+ observer_notify_new_objfile (objfile);
bfd_cache_close_all ();
return (objfile);
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)
{
return crc == file_crc;
}
-static char *debug_file_directory = NULL;
+char *debug_file_directory = NULL;
static void
show_debug_file_directory (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
char *dir;
char *debugfile;
char *name_copy;
+ char *canon_name;
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);
return xstrdup (debugfile);
}
+ /* If the file is in the sysroot, try using its base path in the
+ global debugfile directory. */
+ canon_name = lrealpath (dir);
+ if (canon_name
+ && strncmp (canon_name, gdb_sysroot, strlen (gdb_sysroot)) == 0
+ && IS_DIR_SEPARATOR (canon_name[strlen (gdb_sysroot)]))
+ {
+ strcpy (debugfile, debug_file_directory);
+ strcat (debugfile, canon_name + strlen (gdb_sysroot));
+ strcat (debugfile, "/");
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (canon_name);
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+ }
+
+ if (canon_name)
+ xfree (canon_name);
+
xfree (basename);
xfree (dir);
return NULL;
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
}
}
+ /* The user might be reloading because the binary has changed. Take
+ this opportunity to check. */
+ reopen_exec_file ();
+ reread_symbols ();
+
target_load (arg, from_tty);
/* After re-loading the executable, we don't really know which
we don't want to run a subprocess. On the other hand, I'm not sure how
performance compares. */
-static int download_write_size = 512;
-static void
-show_download_write_size (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
-{
- fprintf_filtered (file, _("\
-The write size used when downloading a program is %s.\n"),
- value);
-}
static int validate_download = 0;
/* Callback service function for generic_load (bfd_map_over_sections). */
/* Opaque data for load_section_callback. */
struct load_section_data {
unsigned long load_offset;
+ struct load_progress_data *progress_data;
+ VEC(memory_write_request_s) *requests;
+};
+
+/* Opaque data for load_progress. */
+struct load_progress_data {
+ /* Cumulative data. */
unsigned long write_count;
unsigned long data_count;
bfd_size_type total_size;
};
+/* Opaque data for load_progress for a single section. */
+struct load_progress_section_data {
+ struct load_progress_data *cumulative;
+
+ /* Per-section data. */
+ const char *section_name;
+ ULONGEST section_sent;
+ ULONGEST section_size;
+ CORE_ADDR lma;
+ gdb_byte *buffer;
+};
+
+/* Target write callback routine for progress reporting. */
+
+static void
+load_progress (ULONGEST bytes, void *untyped_arg)
+{
+ struct load_progress_section_data *args = untyped_arg;
+ struct load_progress_data *totals;
+
+ if (args == NULL)
+ /* Writing padding data. No easy way to get at the cumulative
+ stats, so just ignore this. */
+ return;
+
+ totals = args->cumulative;
+
+ if (bytes == 0 && args->section_sent == 0)
+ {
+ /* The write is just starting. Let the user know we've started
+ this section. */
+ ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
+ args->section_name, paddr_nz (args->section_size),
+ paddr_nz (args->lma));
+ return;
+ }
+
+ if (validate_download)
+ {
+ /* Broken memories and broken monitors manifest themselves here
+ when bring new computers to life. This doubles already slow
+ downloads. */
+ /* NOTE: cagney/1999-10-18: A more efficient implementation
+ might add a verify_memory() method to the target vector and
+ then use that. remote.c could implement that method using
+ the ``qCRC'' packet. */
+ gdb_byte *check = xmalloc (bytes);
+ struct cleanup *verify_cleanups = make_cleanup (xfree, check);
+
+ if (target_read_memory (args->lma, check, bytes) != 0)
+ error (_("Download verify read failed at 0x%s"),
+ paddr (args->lma));
+ if (memcmp (args->buffer, check, bytes) != 0)
+ error (_("Download verify compare failed at 0x%s"),
+ paddr (args->lma));
+ do_cleanups (verify_cleanups);
+ }
+ totals->data_count += bytes;
+ args->lma += bytes;
+ args->buffer += bytes;
+ totals->write_count += 1;
+ args->section_sent += bytes;
+ if (quit_flag
+ || (deprecated_ui_load_progress_hook != NULL
+ && deprecated_ui_load_progress_hook (args->section_name,
+ args->section_sent)))
+ error (_("Canceled the download"));
+
+ if (deprecated_show_load_progress != NULL)
+ deprecated_show_load_progress (args->section_name,
+ args->section_sent,
+ args->section_size,
+ totals->data_count,
+ totals->total_size);
+}
+
/* Callback service function for generic_load (bfd_map_over_sections). */
static void
load_section_callback (bfd *abfd, asection *asec, void *data)
{
+ struct memory_write_request *new_request;
struct load_section_data *args = data;
+ struct load_progress_section_data *section_data;
+ bfd_size_type size = bfd_get_section_size (asec);
+ gdb_byte *buffer;
+ const char *sect_name = bfd_get_section_name (abfd, asec);
- if (bfd_get_section_flags (abfd, asec) & SEC_LOAD)
- {
- bfd_size_type size = bfd_get_section_size (asec);
- if (size > 0)
- {
- gdb_byte *buffer;
- struct cleanup *old_chain;
- CORE_ADDR lma = bfd_section_lma (abfd, asec) + args->load_offset;
- bfd_size_type block_size;
- int err;
- const char *sect_name = bfd_get_section_name (abfd, asec);
- bfd_size_type sent;
-
- if (download_write_size > 0 && size > download_write_size)
- block_size = download_write_size;
- else
- block_size = size;
+ if ((bfd_get_section_flags (abfd, asec) & SEC_LOAD) == 0)
+ return;
- buffer = xmalloc (size);
- old_chain = make_cleanup (xfree, buffer);
+ if (size == 0)
+ return;
- /* Is this really necessary? I guess it gives the user something
- to look at during a long download. */
- ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
- sect_name, paddr_nz (size), paddr_nz (lma));
+ new_request = VEC_safe_push (memory_write_request_s,
+ args->requests, NULL);
+ memset (new_request, 0, sizeof (struct memory_write_request));
+ section_data = xcalloc (1, sizeof (struct load_progress_section_data));
+ new_request->begin = bfd_section_lma (abfd, asec) + args->load_offset;
+ new_request->end = new_request->begin + size; /* FIXME Should size be in instead? */
+ new_request->data = xmalloc (size);
+ new_request->baton = section_data;
- bfd_get_section_contents (abfd, asec, buffer, 0, size);
+ buffer = new_request->data;
- sent = 0;
- do
- {
- int len;
- bfd_size_type this_transfer = size - sent;
-
- if (this_transfer >= block_size)
- this_transfer = block_size;
- len = target_write_memory_partial (lma, buffer,
- this_transfer, &err);
- if (err)
- break;
- if (validate_download)
- {
- /* Broken memories and broken monitors manifest
- themselves here when bring new computers to
- life. This doubles already slow downloads. */
- /* NOTE: cagney/1999-10-18: A more efficient
- implementation might add a verify_memory()
- method to the target vector and then use
- that. remote.c could implement that method
- using the ``qCRC'' packet. */
- gdb_byte *check = xmalloc (len);
- struct cleanup *verify_cleanups =
- make_cleanup (xfree, check);
-
- if (target_read_memory (lma, check, len) != 0)
- error (_("Download verify read failed at 0x%s"),
- paddr (lma));
- if (memcmp (buffer, check, len) != 0)
- error (_("Download verify compare failed at 0x%s"),
- paddr (lma));
- do_cleanups (verify_cleanups);
- }
- args->data_count += len;
- lma += len;
- buffer += len;
- args->write_count += 1;
- sent += len;
- if (quit_flag
- || (deprecated_ui_load_progress_hook != NULL
- && deprecated_ui_load_progress_hook (sect_name, sent)))
- error (_("Canceled the download"));
-
- if (deprecated_show_load_progress != NULL)
- deprecated_show_load_progress (sect_name, sent, size,
- args->data_count,
- args->total_size);
- }
- while (sent < size);
+ section_data->cumulative = args->progress_data;
+ section_data->section_name = sect_name;
+ section_data->section_size = size;
+ section_data->lma = new_request->begin;
+ section_data->buffer = buffer;
- if (err != 0)
- error (_("Memory access error while loading section %s."), sect_name);
+ bfd_get_section_contents (abfd, asec, buffer, 0, size);
+}
- do_cleanups (old_chain);
- }
+/* Clean up an entire memory request vector, including load
+ data and progress records. */
+
+static void
+clear_memory_write_data (void *arg)
+{
+ VEC(memory_write_request_s) **vec_p = arg;
+ VEC(memory_write_request_s) *vec = *vec_p;
+ int i;
+ struct memory_write_request *mr;
+
+ for (i = 0; VEC_iterate (memory_write_request_s, vec, i, mr); ++i)
+ {
+ xfree (mr->data);
+ xfree (mr->baton);
}
+ VEC_free (memory_write_request_s, vec);
}
void
generic_load (char *args, int from_tty)
{
- asection *s;
bfd *loadfile_bfd;
struct timeval start_time, end_time;
char *filename;
struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
struct load_section_data cbdata;
+ struct load_progress_data total_progress;
+
CORE_ADDR entry;
char **argv;
- cbdata.load_offset = 0; /* Offset to add to vma for each section. */
- cbdata.write_count = 0; /* Number of writes needed. */
- cbdata.data_count = 0; /* Number of bytes written to target memory. */
- cbdata.total_size = 0; /* Total size of all bfd sectors. */
+ memset (&cbdata, 0, sizeof (cbdata));
+ memset (&total_progress, 0, sizeof (total_progress));
+ cbdata.progress_data = &total_progress;
+
+ make_cleanup (clear_memory_write_data, &cbdata.requests);
argv = buildargv (args);
}
bfd_map_over_sections (loadfile_bfd, add_section_size_callback,
- (void *) &cbdata.total_size);
+ (void *) &total_progress.total_size);
+
+ bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
gettimeofday (&start_time, NULL);
- bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
+ if (target_write_memory_blocks (cbdata.requests, flash_discard,
+ load_progress) != 0)
+ error (_("Load failed"));
gettimeofday (&end_time, NULL);
ui_out_text (uiout, "Start address ");
ui_out_field_fmt (uiout, "address", "0x%s", paddr_nz (entry));
ui_out_text (uiout, ", load size ");
- ui_out_field_fmt (uiout, "load-size", "%lu", cbdata.data_count);
+ ui_out_field_fmt (uiout, "load-size", "%lu", total_progress.data_count);
ui_out_text (uiout, "\n");
/* We were doing this in remote-mips.c, I suspect it is right
for other targets too. */
file is loaded in. Some targets do (e.g., remote-vx.c) but
others don't (or didn't - perhaps they have all been deleted). */
- print_transfer_performance (gdb_stdout, cbdata.data_count,
- cbdata.write_count, &start_time, &end_time);
+ print_transfer_performance (gdb_stdout, total_progress.data_count,
+ total_progress.write_count,
+ &start_time, &end_time);
do_cleanups (old_cleanups);
}
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
{
int i;
int expecting_sec_name = 0;
int expecting_sec_addr = 0;
+ char **argv;
struct sect_opt
{
if (args == NULL)
error (_("add-symbol-file takes a file name and an address"));
- /* Make a copy of the string that we can safely write into. */
- args = xstrdup (args);
-
- while (*args != '\000')
- {
- /* Any leading spaces? */
- while (isspace (*args))
- args++;
-
- /* Point arg to the beginning of the argument. */
- arg = args;
-
- /* Move args pointer over the argument. */
- while ((*args != '\000') && !isspace (*args))
- args++;
+ argv = buildargv (args);
+ make_cleanup_freeargv (argv);
- /* If there are more arguments, terminate arg and
- proceed past it. */
- if (*args != '\000')
- *args++ = '\000';
+ if (argv == NULL)
+ nomem (0);
- /* Now process the argument. */
+ for (arg = argv[0], argcnt = 0; arg != NULL; arg = argv[++argcnt])
+ {
+ /* Process the argument. */
if (argcnt == 0)
{
/* The first argument is the file name. */
to load the program. */
sect_opts[section_index].name = ".text";
sect_opts[section_index].value = arg;
- if (++section_index > num_sect_opts)
+ if (++section_index >= num_sect_opts)
{
num_sect_opts *= 2;
sect_opts = ((struct sect_opt *)
{
sect_opts[section_index].value = arg;
expecting_sec_addr = 0;
- if (++section_index > num_sect_opts)
+ if (++section_index >= num_sect_opts)
{
num_sect_opts *= 2;
sect_opts = ((struct sect_opt *)
error (_("USAGE: add-symbol-file <filename> <textaddress> [-mapped] [-readnow] [-s <secname> <addr>]*"));
}
}
- argcnt++;
}
/* This command takes at least two arguments. The first one is a
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);
}
}
}
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);
symtab->next = objfile->symtabs;
objfile->symtabs = symtab;
- /* FIXME: This should go away. It is only defined for the Z8000,
- and the Z8000 definition of this macro doesn't have anything to
- do with the now-nonexistent EXTRA_SYMTAB_INFO macro, it's just
- here for convenience. */
-#ifdef INIT_EXTRA_SYMTAB_INFO
- INIT_EXTRA_SYMTAB_INFO (symtab);
-#endif
-
return (symtab);
}
breakpoint_re_set ();
set_default_breakpoint (0, 0, 0, 0);
clear_pc_function_cache ();
- if (deprecated_target_new_objfile_hook)
- deprecated_target_new_objfile_hook (NULL);
+ observer_notify_new_objfile (NULL);
+
+ /* Clear globals which might have pointed into a removed objfile.
+ FIXME: It's not clear which of these are supposed to persist
+ between expressions and which ought to be reset each time. */
+ expression_context_block = NULL;
+ innermost_block = NULL;
+
+ /* Varobj may refer to old symbols, perform a cleanup. */
+ varobj_invalidate ();
+
}
static void
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++);
-
- return psym;
}
-/* Add a symbol with a long value to a psymtab. This differs from
- * add_psymbol_to_list above in taking both a mangled and a demangled
- * name. */
+/* 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. */
-void
-add_psymbol_with_dem_name_to_list (char *name, int namelength, char *dem_name,
- int dem_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)
+/* 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;
- char *buf = alloca (namelength + 1);
- /* 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';
- DEPRECATED_SYMBOL_NAME (&psymbol) = deprecated_bcache (buf, namelength + 1,
- objfile->psymbol_cache);
-
- buf = alloca (dem_namelength + 1);
- memcpy (buf, dem_name, dem_namelength);
- buf[dem_namelength] = '\0';
-
- switch (language)
- {
- case language_c:
- case language_cplus:
- SYMBOL_CPLUS_DEMANGLED_NAME (&psymbol) =
- deprecated_bcache (buf, dem_namelength + 1, objfile->psymbol_cache);
- break;
- /* FIXME What should be done for the default case? Ignoring for now. */
- }
-
- /* val and coreaddr are mutually exclusive, one of them *will* be zero */
- if (val != 0)
- {
- SYMBOL_VALUE (&psymbol) = val;
- }
- else
- {
- SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr;
- }
- SYMBOL_SECTION (&psymbol) = 0;
- SYMBOL_LANGUAGE (&psymbol) = language;
- PSYMBOL_DOMAIN (&psymbol) = domain;
- PSYMBOL_CLASS (&psymbol) = class;
- SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language);
+ int added;
/* Stash the partial symbol away in the cache */
- psym = deprecated_bcache (&psymbol, sizeof (struct partial_symbol),
- objfile->psymbol_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. */
- if (list->next >= list->list + list->size)
- {
- extend_psymbol_list (list, objfile);
- }
- *list->next++ = psym;
- OBJSTAT (objfile, n_psyms++);
+ append_psymbol_to_list (list, psym, objfile);
+ return psym;
}
/* Initialize storage for partial symbols. */
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 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 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);
+
+ 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)
{
set_cmd_completer (c, filename_completer);
c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, _("\
+Load symbols from FILE, assuming FILE has been dynamically loaded.\n\
Usage: add-symbol-file FILE ADDR [-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> ...]\n\
-Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
ADDR is the starting address of the file's text.\n\
The optional arguments are section-name section-address pairs and\n\
should be specified if the data and bss segments are not contiguous\n\
add_info ("extensions", info_ext_lang_command,
_("All filename extensions associated with a source language."));
- add_setshow_integer_cmd ("download-write-size", class_obscure,
- &download_write_size, _("\
-Set the write size used when downloading a program."), _("\
-Show the write size used when downloading a program."), _("\
-Only used when downloading a program onto a remote\n\
-target. Specify zero, or a negative value, to disable\n\
-blocked writes. The actual size of each transfer is also\n\
-limited by the size of the target packet and the memory\n\
-cache."),
- NULL,
- show_download_write_size,
- &setlist, &showlist);
-
- debug_file_directory = xstrdup (DEBUGDIR);
add_setshow_optional_filename_cmd ("debug-file-directory", class_support,
&debug_file_directory, _("\
Set the directory where separate debug symbols are searched for."), _("\