/* Generic symbol file reading for the GNU debugger, GDB.
- Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998
- Free Software Foundation, Inc.
+ Copyright 1990-1996, 1998, 2000 Free Software Foundation, Inc.
Contributed by Cygnus Support, using pieces from other GDB modules.
This file is part of GDB.
} while (0)
#endif
-int (*ui_load_progress_hook) PARAMS ((char *, unsigned long));
+int (*ui_load_progress_hook) (const char *section, unsigned long num);
+void (*show_load_progress) (const char *section,
+ unsigned long section_sent,
+ unsigned long section_size,
+ unsigned long total_sent,
+ unsigned long total_size);
void (*pre_add_symbol_hook) PARAMS ((char *));
void (*post_add_symbol_hook) PARAMS ((void));
+void (*target_new_objfile_hook) PARAMS ((struct objfile *));
/* Global variables owned by this file */
int readnow_symbol_files; /* Read full symbols immediately */
new_symfile_objfile (objfile, mainline, from_tty);
- target_new_objfile (objfile);
+ if (target_new_objfile_hook)
+ target_new_objfile_hook (objfile);
return (objfile);
}
to worry about finding it, and (b) On VMS, fork() is very slow and so
we don't want to run a subprocess. On the other hand, I'm not sure how
performance compares. */
-#define GENERIC_LOAD_CHUNK 256
-#define VALIDATE_DOWNLOAD 0
+
+static int download_write_size = 512;
+static int validate_download = 0;
+
void
-generic_load (filename, from_tty)
- char *filename;
- int from_tty;
+generic_load (char *args, int from_tty)
{
- struct cleanup *old_cleanups;
asection *s;
bfd *loadfile_bfd;
time_t start_time, end_time; /* Start and end times of download */
unsigned long data_count = 0; /* Number of bytes transferred to memory */
- int n;
- unsigned long load_offset = 0; /* offset to add to vma for each section */
- char buf[GENERIC_LOAD_CHUNK + 8];
-#if VALIDATE_DOWNLOAD
- char verify_buffer[GENERIC_LOAD_CHUNK + 8];
-#endif
-
- /* enable user to specify address for downloading as 2nd arg to load */
- n = sscanf (filename, "%s 0x%lx", buf, &load_offset);
- if (n > 1)
- filename = buf;
+ unsigned long write_count = 0; /* Number of writes needed. */
+ unsigned long load_offset; /* offset to add to vma for each section */
+ char *filename;
+ struct cleanup *old_cleanups;
+ char *offptr;
+ CORE_ADDR total_size = 0;
+ CORE_ADDR total_sent = 0;
+
+ /* Parse the input argument - the user can specify a load offset as
+ a second argument. */
+ filename = xmalloc (strlen (args) + 1);
+ old_cleanups = make_cleanup (free, filename);
+ strcpy (filename, args);
+ offptr = strchr (filename, ' ');
+ if (offptr != NULL)
+ {
+ char *endptr;
+ load_offset = strtoul (offptr, &endptr, 0);
+ if (offptr == endptr)
+ error ("Invalid download offset:%s\n", offptr);
+ *offptr = '\0';
+ }
else
load_offset = 0;
+ /* Open the file for loading. */
loadfile_bfd = bfd_openr (filename, gnutarget);
if (loadfile_bfd == NULL)
{
perror_with_name (filename);
return;
}
+
/* 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). */
- old_cleanups = make_cleanup ((make_cleanup_func) bfd_close, loadfile_bfd);
+ make_cleanup ((make_cleanup_func) bfd_close, loadfile_bfd);
if (!bfd_check_format (loadfile_bfd, bfd_object))
{
bfd_errmsg (bfd_get_error ()));
}
+ for (s = loadfile_bfd->sections; s; s = s->next)
+ if (s->flags & SEC_LOAD)
+ total_size += bfd_get_section_size_before_reloc (s);
+
start_time = time (NULL);
for (s = loadfile_bfd->sections; s; s = s->next)
{
if (s->flags & SEC_LOAD)
{
- bfd_size_type size;
-
- size = bfd_get_section_size_before_reloc (s);
+ CORE_ADDR size = bfd_get_section_size_before_reloc (s);
if (size > 0)
{
char *buffer;
struct cleanup *old_chain;
- bfd_vma lma;
- unsigned long l = size;
+ CORE_ADDR lma = s->lma + load_offset;
+ CORE_ADDR block_size;
int err;
- char *sect;
- unsigned long sent;
- unsigned long len;
+ const char *sect_name = bfd_get_section_name (loadfile_bfd, s);
+ CORE_ADDR sent;
- l = l > GENERIC_LOAD_CHUNK ? GENERIC_LOAD_CHUNK : l;
+ if (download_write_size > 0 && size > download_write_size)
+ block_size = download_write_size;
+ else
+ block_size = size;
buffer = xmalloc (size);
old_chain = make_cleanup (free, buffer);
- lma = s->lma;
- lma += load_offset;
-
/* Is this really necessary? I guess it gives the user something
to look at during a long download. */
- printf_filtered ("Loading section %s, size 0x%lx lma ",
- bfd_get_section_name (loadfile_bfd, s),
- (unsigned long) size);
- print_address_numeric (lma, 1, gdb_stdout);
- printf_filtered ("\n");
+#ifdef UI_OUT
+ ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
+ sect_name, paddr_nz (size), paddr_nz (lma));
+#else
+ fprintf_unfiltered (gdb_stdout,
+ "Loading section %s, size 0x%s lma 0x%s\n",
+ sect_name, paddr_nz (size), paddr_nz (lma));
+#endif
bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size);
- sect = (char *) bfd_get_section_name (loadfile_bfd, s);
sent = 0;
do
{
- len = (size - sent) < l ? (size - sent) : l;
- sent += len;
- err = target_write_memory (lma, buffer, len);
- if (ui_load_progress_hook)
- if (ui_load_progress_hook (sect, sent))
- error ("Canceled the download");
-#if VALIDATE_DOWNLOAD
- /* Broken memories and broken monitors manifest themselves
- here when bring new computers to life.
- This doubles already slow downloads.
- */
+ CORE_ADDR len;
+ CORE_ADDR 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;
- {
- target_read_memory (lma, verify_buffer, len);
- if (0 != bcmp (buffer, verify_buffer, len))
- error ("Download verify failed at %08x",
- (unsigned long) lma);
- }
-
-#endif
+ 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 (free, 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);
+ }
data_count += len;
lma += len;
buffer += len;
- } /* od */
- while (err == 0 && sent < size);
+ write_count += 1;
+ sent += len;
+ total_sent += len;
+ if (quit_flag
+ || (ui_load_progress_hook != NULL
+ && ui_load_progress_hook (sect_name, sent)))
+ error ("Canceled the download");
+
+ if (show_load_progress != NULL)
+ show_load_progress (sect_name, sent, size, total_sent, total_size);
+ }
+ while (sent < size);
if (err != 0)
- error ("Memory access error while loading section %s.",
- bfd_get_section_name (loadfile_bfd, s));
+ error ("Memory access error while loading section %s.", sect_name);
do_cleanups (old_chain);
}
end_time = time (NULL);
{
- unsigned long entry;
+ CORE_ADDR entry;
entry = bfd_get_start_address (loadfile_bfd);
- printf_filtered ("Start address 0x%lx , load size %ld\n", entry, data_count);
+#ifdef UI_OUT
+ 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", "%ld" , data_count);
+ ui_out_text (uiout, "\n");
+
+#else
+ fprintf_unfiltered (gdb_stdout,
+ "Start address 0x%s , load size %ld\n",
+ paddr_nz (entry), data_count);
+#endif
/* We were doing this in remote-mips.c, I suspect it is right
for other targets too. */
write_pc (entry);
loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c
does. */
- report_transfer_performance (data_count, start_time, end_time);
+ print_transfer_performance (gdb_stdout, data_count, write_count,
+ end_time - start_time);
do_cleanups (old_cleanups);
}
/* Report how fast the transfer went. */
+/* DEPRECATED: cagney/1999-10-18: report_transfer_performance is being
+ replaced by print_transfer_performance (with a very different
+ function signature). */
+
void
report_transfer_performance (data_count, start_time, end_time)
unsigned long data_count;
time_t start_time, end_time;
{
- printf_filtered ("Transfer rate: ");
- if (end_time != start_time)
- printf_filtered ("%ld bits/sec",
- (data_count * 8) / (end_time - start_time));
+ print_transfer_performance (gdb_stdout, data_count, end_time - start_time, 0);
+}
+
+void
+print_transfer_performance (struct ui_file *stream,
+ unsigned long data_count,
+ unsigned long write_count,
+ unsigned long time_count)
+{
+#ifdef UI_OUT
+ ui_out_text (uiout, "Transfer rate: ");
+ if (time_count > 0)
+ {
+ ui_out_field_fmt (uiout, "transfer-rate", "%ld",
+ (data_count * 8) / time_count);
+ ui_out_text (uiout, " bits/sec");
+ }
else
- printf_filtered ("%ld bits in <1 sec", (data_count * 8));
- printf_filtered (".\n");
+ {
+ ui_out_field_fmt (uiout, "transferred-bits", "%ld", (data_count * 8));
+ ui_out_text (uiout, " bits in <1 sec");
+ }
+ if (write_count > 0)
+ {
+ ui_out_text (uiout, ", ");
+ ui_out_field_fmt (uiout, "write-rate", "%ld", data_count / write_count);
+ ui_out_text (uiout, " bytes/write");
+ }
+ ui_out_text (uiout, ".\n");
+#else
+ fprintf_unfiltered (stream, "Transfer rate: ");
+ if (time_count > 0)
+ fprintf_unfiltered (stream, "%ld bits/sec", (data_count * 8) / time_count);
+ else
+ fprintf_unfiltered (stream, "%ld bits in <1 sec", (data_count * 8));
+ if (write_count > 0)
+ fprintf_unfiltered (stream, ", %ld bytes/write", data_count / write_count);
+ fprintf_unfiltered (stream, ".\n");
+#endif
}
/* This function allows the addition of incrementally linked object files.
/* Make a copy of the string that we can safely write into. */
- args = strdup (args);
+ args = xstrdup (args);
make_cleanup (free, args);
/* Ensure section_addrs is initialized */
text data or bss section. This is redundent but
eventually, none will be given special treatment */
{
- section_addrs.other[sec_num].name = strdup (sec);
+ section_addrs.other[sec_num].name = xstrdup (sec);
make_cleanup (free, section_addrs.other[sec_num].name);
section_addrs.other[sec_num++].addr = addr;
printf_filtered ("\t%s_addr = %s\n",
sizeof (objfile->static_psymbols));
/* Free the obstacks for non-reusable objfiles */
- obstack_free (&objfile->psymbol_cache.cache, 0);
- memset (&objfile->psymbol_cache, 0,
- sizeof (objfile->psymbol_cache));
+ free_bcache (&objfile->psymbol_cache);
obstack_free (&objfile->psymbol_obstack, 0);
obstack_free (&objfile->symbol_obstack, 0);
obstack_free (&objfile->type_obstack, 0);
current_source_symtab = 0;
current_source_line = 0;
clear_pc_function_cache ();
- target_new_objfile (NULL);
+ if (target_new_objfile_hook)
+ target_new_objfile_hook (NULL);
}
/* clear_symtab_users_once:
add_info ("extensions", info_ext_lang_command,
"All filename extensions associated with a source language.");
+
+ add_show_from_set
+ (add_set_cmd ("download-write-size", class_obscure,
+ var_integer, (char *) &download_write_size,
+ "Set the write size used when downloading a program.\n"
+ "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.\n",
+ &setlist),
+ &showlist);
}