/* Generic symbol file reading for the GNU debugger, GDB.
- Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Cygnus Support, using pieces from other GDB modules.
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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "bfdlink.h"
#include "gdb_assert.h"
#include "block.h"
#include "observer.h"
+#include "exec.h"
+#include "parser-defs.h"
#include <sys/types.h>
#include <fcntl.h>
#include "gdb_stat.h"
#include <ctype.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,
}
}
+/* The arguments to place_section. */
+
+struct place_section_arg
+{
+ struct section_offsets *offsets;
+ CORE_ADDR lowest;
+};
+
+/* Find a unique offset to use for loadable section SECT if
+ the user did not provide an offset. */
+
+void
+place_section (bfd *abfd, asection *sect, void *obj)
+{
+ struct place_section_arg *arg = obj;
+ CORE_ADDR *offsets = arg->offsets->offsets, start_addr;
+ 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)
+ return;
+
+ /* If the user specified an offset, honor it. */
+ if (offsets[sect->index] != 0)
+ return;
+
+ /* Otherwise, let's try to find a place for the section. */
+ start_addr = (arg->lowest + align - 1) & -align;
+
+ do {
+ asection *cur_sec;
+
+ done = 1;
+
+ for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
+ {
+ int indx = cur_sec->index;
+ CORE_ADDR cur_offset;
+
+ /* We don't need to compare against ourself. */
+ 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)
+ continue;
+
+ /* If the section offset is 0, either the section has not been placed
+ yet, or it was the lowest section placed (in which case LOWEST
+ will be past its end). */
+ if (offsets[indx] == 0)
+ continue;
+
+ /* If this section would overlap us, then we must move up. */
+ if (start_addr + bfd_get_section_size (sect) > offsets[indx]
+ && start_addr < offsets[indx] + bfd_get_section_size (cur_sec))
+ {
+ start_addr = offsets[indx] + bfd_get_section_size (cur_sec);
+ start_addr = (start_addr + align - 1) & -align;
+ done = 0;
+ break;
+ }
+
+ /* Otherwise, we appear to be OK. So far. */
+ }
+ }
+ while (!done);
+
+ 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
of how to represent it for fast symbol reading. This is the default
(objfile->section_offsets)->offsets[osp->sectindex] = osp->addr;
}
+ /* For relocatable files, all loadable sections will start at zero.
+ The zero is meaningless, so try to pick arbitrary addresses such
+ that no loadable sections overlap. This algorithm is quadratic,
+ but the number of sections in a single object file is generally
+ small. */
+ 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);
+ }
+
/* Remember the bfd indexes for the .text, .data, .bss and
.rodata sections. */
init_objfile_sect_indices (objfile);
{
if ((have_full_symbols () || have_partial_symbols ())
&& from_tty
- && !query ("Discard symbol table from `%s'? ",
- symfile_objfile->name))
+ && (symfile_objfile
+ ? !query (_("Discard symbol table from `%s'? "),
+ symfile_objfile->name)
+ : !query (_("Discard symbol table? "))))
error (_("Not confirmed."));
free_all_objfiles ();
{
unsigned long file_crc = 0;
int fd;
- char buffer[8*1024];
+ gdb_byte buffer[8*1024];
int count;
fd = open (name, O_RDONLY | O_BINARY);
/* 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
- quoting conventions which are undocumented and have little or
- nothing in common with the way things are quoted (or not quoted)
- elsewhere in GDB, (2) options are used, which are not generally
- used in GDB (perhaps "set mapped on", "set readnow on" would be
- better), (3) the order of options matters, which is contrary to GNU
+ the command is rather bizarre:
+
+ 1. The function buildargv implements various quoting conventions
+ which are undocumented and have little or nothing in common with
+ the way things are quoted (or not quoted) elsewhere in GDB.
+
+ 2. Options are used, which are not generally used in GDB (perhaps
+ "set mapped on", "set readnow on" would be better)
+
+ 3. The order of options matters, which is contrary to GNU
conventions (because it is confusing and inconvenient). */
-/* Note: ezannoni 2000-04-17. This function used to have support for
- rombug (see remote-os9k.c). It consisted of a call to target_link()
- (target.c) to get the address of the text segment from the target,
- and pass that to symbol_file_add(). This is no longer supported. */
void
symbol_file_command (char *args, int from_tty)
{
- char **argv;
- char *name = NULL;
- struct cleanup *cleanups;
- int flags = OBJF_USERLOADED;
-
dont_repeat ();
if (args == NULL)
}
else
{
- if ((argv = buildargv (args)) == NULL)
- {
- nomem (0);
- }
+ char **argv = buildargv (args);
+ int flags = OBJF_USERLOADED;
+ struct cleanup *cleanups;
+ char *name = NULL;
+
+ if (argv == NULL)
+ nomem (0);
+
cleanups = make_cleanup_freeargv (argv);
while (*argv != NULL)
{
error (_("unknown option `%s'"), *argv);
else
{
+ symbol_file_add_main_1 (*argv, from_tty, flags);
name = *argv;
-
- symbol_file_add_main_1 (name, from_tty, flags);
}
+
argv++;
}
if (name == NULL)
- {
- error (_("no symbol file name was specified"));
- }
+ error (_("no symbol file name was specified"));
+
do_cleanups (cleanups);
}
}
/* Set the initial language.
- A better solution would be to record the language in the psymtab when reading
- partial symbols, and then use it (if known) to set the language. This would
- be a win for formats that encode the language in an easily discoverable place,
- such as DWARF. For stabs, we can jump through hoops looking for specially
- named symbols or try to intuit the language from the specific type of stabs
- we find, but we can't do that until later when we read in full symbols.
- FIXME. */
+ FIXME: A better solution would be to record the language in the
+ psymtab when reading partial symbols, and then use it (if known) to
+ set the language. This would be a win for formats that encode the
+ language in an easily discoverable place, such as DWARF. For
+ stabs, we can jump through hoops looking for specially named
+ symbols or try to intuit the language from the specific type of
+ stabs we find, but we can't do that until later when we read in
+ full symbols. */
static void
set_initial_language (void)
if (pst != NULL)
{
if (pst->filename != NULL)
- {
- lang = deduce_language_from_filename (pst->filename);
- }
+ lang = deduce_language_from_filename (pst->filename);
+
if (lang == language_unknown)
{
/* Make C the default language */
lang = language_c;
}
+
set_language (lang);
- expected_language = current_language; /* Don't warn the user */
+ expected_language = current_language; /* Don't warn the user. */
}
}
-/* Open file specified by NAME and hand it off to BFD for preliminary
- analysis. Result is a newly initialized bfd *, which includes a newly
- malloc'd` copy of NAME (tilde-expanded and made absolute).
- In case of trouble, error() is called. */
+/* Open the file specified by NAME and hand it off to BFD for
+ preliminary analysis. Return a newly initialized bfd *, which
+ includes a newly malloc'd` copy of NAME (tilde-expanded and made
+ absolute). In case of trouble, error() is called. */
bfd *
symfile_bfd_open (char *name)
int desc;
char *absolute_name;
-
-
- name = tilde_expand (name); /* Returns 1st new malloc'd copy */
+ name = tilde_expand (name); /* Returns 1st new malloc'd copy. */
/* Look down path for it, allocate 2nd new malloc'd copy. */
- desc = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, name, O_RDONLY | O_BINARY,
- 0, &absolute_name);
+ desc = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, name,
+ O_RDONLY | O_BINARY, 0, &absolute_name);
#if defined(__GO32__) || defined(_WIN32) || defined (__CYGWIN__)
if (desc < 0)
{
make_cleanup (xfree, name);
perror_with_name (name);
}
- xfree (name); /* Free 1st new malloc'd copy */
- name = absolute_name; /* Keep 2nd malloc'd copy in bfd */
- /* It'll be freed in free_objfile(). */
- sym_bfd = bfd_fdopenr (name, gnutarget, desc);
+ /* Free 1st new malloc'd copy, but keep the 2nd malloc'd copy in
+ bfd. It'll be freed in free_objfile(). */
+ xfree (name);
+ name = absolute_name;
+
+ sym_bfd = bfd_fopen (name, gnutarget, FOPEN_RB, desc);
if (!sym_bfd)
{
close (desc);
if (!bfd_check_format (sym_bfd, bfd_object))
{
- /* FIXME: should be checking for errors from bfd_close (for one thing,
- on error it does not free all the storage associated with the
- bfd). */
- bfd_close (sym_bfd); /* This also closes desc */
+ /* FIXME: should be checking for errors from bfd_close (for one
+ thing, on error it does not free all the storage associated
+ with the bfd). */
+ bfd_close (sym_bfd); /* This also closes desc. */
make_cleanup (xfree, name);
error (_("\"%s\": can't read symbols: %s."), name,
bfd_errmsg (bfd_get_error ()));
}
- return (sym_bfd);
+
+ return sym_bfd;
}
-/* Return the section index for the given section name. Return -1 if
- the section was not found. */
+/* Return the section index for SECTION_NAME on OBJFILE. Return -1 if
+ the section was not found. */
+
int
get_section_index (struct objfile *objfile, char *section_name)
{
asection *sect = bfd_get_section_by_name (objfile->obfd, section_name);
+
if (sect)
return sect->index;
else
return -1;
}
-/* Link a new symtab_fns into the global symtab_fns list. Called on gdb
- startup by the _initialize routine in each object file format reader,
- to register information about each format the the reader is prepared
- to handle. */
+/* Link SF into the global symtab_fns list. Called on startup by the
+ _initialize routine in each object file format reader, to register
+ information about each format the the reader is prepared to
+ handle. */
void
add_symtab_fns (struct sym_fns *sf)
symtab_fns = sf;
}
-
-/* Initialize to read symbols from the symbol file sym_bfd. It either
- returns or calls error(). The result is an initialized struct sym_fns
- in the objfile structure, that contains cached information about the
- symbol file. */
+/* Initialize OBJFILE to read symbols from its associated BFD. It
+ either returns or calls error(). The result is an initialized
+ struct sym_fns in the objfile structure, that contains cached
+ information about the symbol file. */
static void
find_sym_fns (struct objfile *objfile)
if (our_flavour == bfd_target_srec_flavour
|| our_flavour == bfd_target_ihex_flavour
|| our_flavour == bfd_target_tekhex_flavour)
- return; /* No symbols. */
+ return; /* No symbols. */
for (sf = symtab_fns; sf != NULL; sf = sf->next)
{
return;
}
}
+
error (_("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown."),
bfd_get_target (objfile->obfd));
}
\f
+
/* This function runs the load command of our current target. */
static void
load_command (char *arg, int from_tty)
{
if (arg == NULL)
- arg = get_exec_file (1);
+ {
+ char *parg;
+ int count = 0;
+
+ parg = arg = get_exec_file (1);
+
+ /* Count how many \ " ' tab space there are in the name. */
+ while ((parg = strpbrk (parg, "\\\"'\t ")))
+ {
+ parg++;
+ count++;
+ }
+
+ if (count)
+ {
+ /* We need to quote this string so buildargv can pull it apart. */
+ char *temp = xmalloc (strlen (arg) + count + 1 );
+ char *ptemp = temp;
+ char *prev;
+
+ make_cleanup (xfree, temp);
+
+ prev = parg = arg;
+ while ((parg = strpbrk (parg, "\\\"'\t ")))
+ {
+ strncpy (ptemp, prev, parg - prev);
+ ptemp += parg - prev;
+ prev = parg++;
+ *ptemp++ = '\\';
+ }
+ strcpy (ptemp, prev);
+
+ arg = temp;
+ }
+ }
+
+ /* 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)
- {
- char *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;
+
+ if (size == 0)
+ return;
- buffer = xmalloc (size);
- old_chain = make_cleanup (xfree, buffer);
+ 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;
- /* 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));
+ buffer = new_request->data;
- bfd_get_section_contents (abfd, asec, buffer, 0, 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;
- 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. */
- char *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);
+ bfd_get_section_contents (abfd, asec, buffer, 0, size);
+}
- if (err != 0)
- error (_("Memory access error while loading section %s."), sect_name);
+/* Clean up an entire memory request vector, including load
+ data and progress records. */
- do_cleanups (old_chain);
- }
+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;
- time_t start_time, end_time; /* Start and end times of download */
+ struct timeval start_time, end_time;
char *filename;
- struct cleanup *old_cleanups;
- char *offptr;
+ 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;
+
+ 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);
+
+ if (argv == NULL)
+ nomem(0);
- 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. */
+ make_cleanup_freeargv (argv);
- /* Parse the input argument - the user can specify a load offset as
- a second argument. */
- filename = xmalloc (strlen (args) + 1);
- old_cleanups = make_cleanup (xfree, filename);
- strcpy (filename, args);
- offptr = strchr (filename, ' ');
- if (offptr != NULL)
+ filename = tilde_expand (argv[0]);
+ make_cleanup (xfree, filename);
+
+ if (argv[1] != NULL)
{
char *endptr;
- cbdata.load_offset = strtoul (offptr, &endptr, 0);
- if (offptr == endptr)
- error (_("Invalid download offset:%s."), offptr);
- *offptr = '\0';
+ cbdata.load_offset = strtoul (argv[1], &endptr, 0);
+
+ /* If the last word was not a valid number then
+ treat it as a file name with spaces in. */
+ if (argv[1] == endptr)
+ error (_("Invalid download offset:%s."), argv[1]);
+
+ if (argv[2] != NULL)
+ error (_("Too many parameters."));
}
- else
- cbdata.load_offset = 0;
/* Open the file for loading. */
loadfile_bfd = bfd_openr (filename, gnutarget);
}
bfd_map_over_sections (loadfile_bfd, add_section_size_callback,
- (void *) &cbdata.total_size);
-
- start_time = time (NULL);
+ (void *) &total_progress.total_size);
bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
- end_time = time (NULL);
+ gettimeofday (&start_time, NULL);
+
+ if (target_write_memory_blocks (cbdata.requests, flash_discard,
+ load_progress) != 0)
+ error (_("Load failed"));
+
+ gettimeofday (&end_time, NULL);
entry = bfd_get_start_address (loadfile_bfd);
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, end_time - start_time);
+ print_transfer_performance (gdb_stdout, total_progress.data_count,
+ total_progress.write_count,
+ &start_time, &end_time);
do_cleanups (old_cleanups);
}
report_transfer_performance (unsigned long data_count, time_t start_time,
time_t end_time)
{
- print_transfer_performance (gdb_stdout, data_count,
- end_time - start_time, 0);
+ struct timeval start, end;
+
+ start.tv_sec = start_time;
+ start.tv_usec = 0;
+ end.tv_sec = end_time;
+ end.tv_usec = 0;
+
+ print_transfer_performance (gdb_stdout, data_count, 0, &start, &end);
}
void
print_transfer_performance (struct ui_file *stream,
unsigned long data_count,
unsigned long write_count,
- unsigned long time_count)
+ const struct timeval *start_time,
+ const struct timeval *end_time)
{
+ unsigned long time_count;
+
+ /* Compute the elapsed time in milliseconds, as a tradeoff between
+ accuracy and overflow. */
+ time_count = (end_time->tv_sec - start_time->tv_sec) * 1000;
+ time_count += (end_time->tv_usec - start_time->tv_usec) / 1000;
+
ui_out_text (uiout, "Transfer rate: ");
if (time_count > 0)
{
ui_out_field_fmt (uiout, "transfer-rate", "%lu",
- (data_count * 8) / time_count);
+ 1000 * (data_count * 8) / time_count);
ui_out_text (uiout, " bits/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++;
+ argv = buildargv (args);
+ make_cleanup_freeargv (argv);
- /* Point arg to the beginning of the argument. */
- arg = args;
+ if (argv == NULL)
+ nomem (0);
- /* Move args pointer over the argument. */
- while ((*args != '\000') && !isspace (*args))
- args++;
-
- /* If there are more arguments, terminate arg and
- proceed past it. */
- if (*args != '\000')
- *args++ = '\000';
-
- /* 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
+ filename, and the second is the address where this file has been
+ loaded. Abort now if this address hasn't been provided by the
+ user. */
+ if (section_index < 1)
+ error (_("The address where %s has been loaded is missing"), filename);
+
/* Print the prompt for the query below. And save the arguments into
a sect_addr_info structure to be passed around to other
functions. We have to split this up into separate print
memcpy (offsets, objfile->section_offsets,
SIZEOF_N_SECTION_OFFSETS (num_offsets));
+ /* Remove any references to this objfile in the global
+ value lists. */
+ preserve_values (objfile);
+
/* Nuke all the state that we will re-read. Much of the following
code which sets things to NULL really is necessary to tell
other parts of GDB that there is nothing currently there. */
{
/* Someday, we should do better than this, by only blowing away
the things that really need to be blown. */
- clear_value_history ();
+
+ /* Clear the "current" symtab first, because it is no longer valid.
+ breakpoint_re_set may try to access the current symtab. */
+ clear_current_source_symtab_and_line ();
+
clear_displays ();
- clear_internalvars ();
breakpoint_re_set ();
set_default_breakpoint (0, 0, 0, 0);
- clear_current_source_symtab_and_line ();
clear_pc_function_cache ();
if (deprecated_target_new_objfile_hook)
deprecated_target_new_objfile_hook (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;
}
static void
read_target_long_array (CORE_ADDR memaddr, unsigned int *myaddr, int len)
{
/* FIXME (alloca): Not safe if array is very large. */
- char *buf = alloca (len * TARGET_LONG_BYTES);
+ gdb_byte *buf = alloca (len * TARGET_LONG_BYTES);
int i;
read_memory (memaddr, buf, len * TARGET_LONG_BYTES);
= (void *) xmalloc (cache_novlys * sizeof (*cache_ovly_table));
cache_ovly_table_base = SYMBOL_VALUE_ADDRESS (ovly_table_msym);
read_target_long_array (cache_ovly_table_base,
- (int *) cache_ovly_table,
+ (unsigned int *) cache_ovly_table,
cache_novlys * 4);
return 1; /* SUCCESS */
{
cache_ovly_region_table_base = SYMBOL_VALUE_ADDRESS (msym);
read_target_long_array (cache_ovly_region_table_base,
- (int *) cache_ovly_region_table,
+ (unsigned int *) cache_ovly_region_table,
cache_novly_regions * 3);
}
else
/* && cache_ovly_table[i][SIZE] == size */ )
{
read_target_long_array (cache_ovly_table_base + i * TARGET_LONG_BYTES,
- (int *) cache_ovly_table[i], 4);
+ (unsigned int *) cache_ovly_table[i], 4);
if (cache_ovly_table[i][VMA] == bfd_section_vma (obfd, bsect)
&& cache_ovly_table[i][LMA] == bfd_section_lma (obfd, bsect)
/* && cache_ovly_table[i][SIZE] == size */ )
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\
c = add_cmd ("load", class_files, load_command, _("\
Dynamically load FILE into the running program, and record its symbols\n\
-for access from GDB."), &cmdlist);
+for access from GDB.\n\
+A load OFFSET may also be given."), &cmdlist);
set_cmd_completer (c, filename_completer);
add_setshow_boolean_cmd ("symbol-reloading", class_support,
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, _("\