OSDN Git Service

import gdb-1999-11-08 snapshot
[pf3gnuchains/pf3gnuchains4x.git] / gdb / symfile.c
index fcf8326..80f9902 100644 (file)
@@ -45,9 +45,6 @@
 #include "gdb_stat.h"
 #include <ctype.h>
 #include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -66,9 +63,10 @@ extern int hp_cxx_exception_support_initialized;
                               } while (0)
 #endif
 
-int (*ui_load_progress_hook) PARAMS ((char *, unsigned long));
+int (*ui_load_progress_hook) (const char *section, unsigned long num);
 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 */
@@ -83,6 +81,11 @@ struct complaint empty_symtab_complaint =
   "Empty symbol table found for `%s'", 0, 0
 };
 
+struct complaint unknown_option_complaint =
+{
+  "Unknown option `%s' ignored", 0, 0
+};
+
 /* External variables and functions referenced. */
 
 extern int info_verbose;
@@ -460,48 +463,87 @@ find_lowest_section (abfd, sect, obj)
    don't need to do anything special.  It allocates a section_offsets table
    for the objectfile OBJFILE and stuffs ADDR into all of the offsets.  */
 
-struct section_offsets *
-default_symfile_offsets (objfile, addr)
+void
+default_symfile_offsets (objfile, addrs)
      struct objfile *objfile;
-     CORE_ADDR addr;
+     struct section_addr_info *addrs;
 {
-  struct section_offsets *section_offsets;
   int i;
 
   objfile->num_sections = SECT_OFF_MAX;
-  section_offsets = (struct section_offsets *)
+  objfile->section_offsets = (struct section_offsets *)
     obstack_alloc (&objfile->psymbol_obstack, SIZEOF_SECTION_OFFSETS);
-  memset (section_offsets, 0, SIZEOF_SECTION_OFFSETS);
-
-  for (i = 0; i < SECT_OFF_MAX; i++)
-    ANOFFSET (section_offsets, i) = addr;
-
-  return section_offsets;
+  memset (objfile->section_offsets, 0, SIZEOF_SECTION_OFFSETS);
+
+  /* If user explicitly specified values for data and bss, set them here. */
+  
+  if (addrs->text_addr)
+    ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT) = addrs->text_addr;
+  if (addrs->data_addr)
+    ANOFFSET (objfile->section_offsets, SECT_OFF_DATA) = addrs->data_addr;
+  if (addrs->bss_addr)
+    ANOFFSET (objfile->section_offsets, SECT_OFF_BSS)  = addrs->bss_addr;
+    
+  /* Now calculate offsets for other sections. */
+  for (i = 0; i < MAX_SECTIONS && addrs->other[i].name; i++)
+    {
+      struct other_sections *osp ;
+
+      osp = &addrs->other[i] ;
+      if (addrs->other[i].addr == 0)
+       continue;
+#if 0
+      if (strcmp (".text", osp->name) == 0)
+       SECT_OFF_TEXT = osp->sectindex ;
+      else if (strcmp (".data", osp->name) == 0)
+       SECT_OFF_DATA = osp->sectindex ;
+      else if (strcmp (".bss", osp->name) == 0)
+       SECT_OFF_BSS =  osp->sectindex ;
+#endif
+      /* Record all sections in offsets */
+      ANOFFSET (objfile->section_offsets, osp->sectindex) = osp->addr;
+    }
 }
 
 
 /* Process a symbol file, as either the main file or as a dynamically
    loaded file.
 
-   NAME is the file name (which will be tilde-expanded and made
-   absolute herein) (but we don't free or modify NAME itself).
-   FROM_TTY says how verbose to be.  MAINLINE specifies whether this
-   is the main symbol file, or whether it's an extra symbol file such
-   as dynamically loaded code.  If !mainline, ADDR is the address
-   where the text segment was loaded.  If VERBO, the caller has printed
-   a verbose message about the symbol reading (and complaints can be
-   more terse about it).  */
+   OBJFILE is where the symbols are to be read from.
+
+   ADDR is the address where the text segment was loaded, unless the
+   objfile is the main symbol file, in which case it is zero.
+
+   MAINLINE is nonzero if this is the main symbol file, or zero if
+   it's an extra symbol file such as dynamically loaded code.
+
+   VERBO is nonzero if the caller has printed a verbose message about
+   the symbol reading (and complaints can be more terse about it).  */
 
 void
-syms_from_objfile (objfile, addr, mainline, verbo)
+syms_from_objfile (objfile, addrs, mainline, verbo)
      struct objfile *objfile;
-     CORE_ADDR addr;
+     struct section_addr_info *addrs;
      int mainline;
      int verbo;
 {
   struct section_offsets *section_offsets;
-  asection *lowest_sect;
+  asection *lower_sect;
+  asection *sect;
+  CORE_ADDR lower_offset;
+  struct section_addr_info local_addr;
   struct cleanup *old_chain;
+  int i;
+
+  /* If ADDRS is NULL, initialize the local section_addr_info struct and
+     point ADDRS to it.  We now establish the convention that an addr of
+     zero means no load address was specified. */
+
+  if (addrs == NULL)
+    {
+      memset (&local_addr, 0, sizeof (local_addr));
+      addrs = &local_addr;
+    }
 
   init_entry_point_info (objfile);
   find_sym_fns (objfile);
@@ -534,33 +576,113 @@ syms_from_objfile (objfile, addr, mainline, verbo)
 
   /* Convert addr into an offset rather than an absolute address.
      We find the lowest address of a loaded segment in the objfile,
-     and assume that <addr> is where that got loaded.  Due to historical
-     precedent, we warn if that doesn't happen to be a text segment.  */
+     and assume that <addr> is where that got loaded.
 
+     We no longer warn if the lowest section is not a text segment (as
+     happens for the PA64 port.  */
   if (mainline)
     {
-      addr = 0;                        /* No offset from objfile addresses.  */
+      /* No offset from objfile addresses.  */
+      addrs -> text_addr = 0;
+      addrs -> data_addr = 0;
+      addrs -> bss_addr = 0;
     }
   else
     {
-      lowest_sect = bfd_get_section_by_name (objfile->obfd, ".text");
-      if (lowest_sect == NULL)
+      /* Find lowest loadable section to be used as starting point for 
+         continguous sections. FIXME!! won't work without call to find
+        .text first, but this assumes text is lowest section. */
+      lower_sect = bfd_get_section_by_name (objfile->obfd, ".text");
+      if (lower_sect == NULL)
        bfd_map_over_sections (objfile->obfd, find_lowest_section,
-                              (PTR) & lowest_sect);
-
-      if (lowest_sect == NULL)
+                              (PTR) &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, lowest_sect) & SEC_CODE)
+      else if ((bfd_get_section_flags (objfile->obfd, lower_sect) & SEC_CODE)
               == 0)
-       /* FIXME-32x64--assumes bfd_vma fits in long.  */
-       warning ("Lowest section in %s is %s at 0x%lx",
+       warning ("Lowest section in %s is %s at %s",
                 objfile->name,
-                bfd_section_name (objfile->obfd, lowest_sect),
-             (unsigned long) bfd_section_vma (objfile->obfd, lowest_sect));
-
-      if (lowest_sect)
-       addr -= bfd_section_vma (objfile->obfd, lowest_sect);
+                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);
+      else
+       lower_offset = 0;
+       /* Calculate offsets for the loadable sections.
+        FIXME! Sections must be in order of increasing loadable section
+        so that contiguous sections can use the lower-offset!!!
+          Adjust offsets if the segments are not contiguous.
+          If the section is contiguous, its offset should be set to
+        the offset of the highest loadable section lower than it
+        (the loadable section directly below it in memory).
+        this_offset = lower_offset = lower_addr - lower_orig_addr */
+
+      /* FIXME: These sections will not need special treatment because ALL
+        sections are in the other sections table */
+      if (addrs->text_addr != 0)
+       {
+         sect = bfd_get_section_by_name (objfile->obfd, ".text");
+         if (sect)
+           {
+             addrs->text_addr -= bfd_section_vma (objfile->obfd, sect);
+             lower_offset = addrs->text_addr;
+           }
+       }
+      else 
+       /* ??? who's below me? */
+       addrs->text_addr = lower_offset;
+      if (addrs->data_addr != 0)
+       {
+         sect = bfd_get_section_by_name (objfile->obfd, ".data");
+         if (sect)
+           {
+             addrs->data_addr -= bfd_section_vma (objfile->obfd, sect);
+             lower_offset = addrs->data_addr;
+           }
+       }
+      else
+       addrs->data_addr = lower_offset;
+      if (addrs->bss_addr != 0)
+       {
+         sect = bfd_get_section_by_name (objfile->obfd, ".bss");
+         if (sect)
+           {
+             addrs->bss_addr -= bfd_section_vma (objfile->obfd, sect);
+             lower_offset = addrs->bss_addr;
+           }
+       }
+      else
+       addrs->bss_addr = lower_offset;
+  
+       /* Now calculate offsets for other sections. */
+      for (i=0 ; i < MAX_SECTIONS && addrs->other[i].name; i++)
+       {
+        
+         if (addrs->other[i].addr != 0)
+           {
+             sect=bfd_get_section_by_name(objfile->obfd, addrs->other[i].name);
+             if (sect)
+               {
+                 addrs->other[i].addr -= bfd_section_vma (objfile->obfd, sect);
+                 lower_offset = addrs->other[i].addr;
+                 addrs->other[i].sectindex = sect->index ;
+               }
+             else
+               {
+                 warning ("section %s not found in %s", addrs->other[i].name, 
+                          objfile->name);
+                 addrs->other[i].addr = 0;
+               }
+           }
+         else
+           addrs->other[i].addr = lower_offset;
+       }
     }
 
   /* Initialize symbol reading routines for this objfile, allow complaints to
@@ -570,8 +692,7 @@ syms_from_objfile (objfile, addr, mainline, verbo)
   (*objfile->sf->sym_init) (objfile);
   clear_complaints (1, verbo);
 
-  section_offsets = (*objfile->sf->sym_offsets) (objfile, addr);
-  objfile->section_offsets = section_offsets;
+  (*objfile->sf->sym_offsets) (objfile, addrs);
 
 #ifndef IBM6000_TARGET
   /* This is a SVR4/SunOS specific hack, I think.  In any event, it
@@ -587,27 +708,46 @@ syms_from_objfile (objfile, addr, mainline, verbo)
      Section offsets are built similarly, except that they are built
      by adding addr in all cases because there is no clear mapping
      from section_offsets into actual sections.  Note that solib.c
-     has a different algorythm for finding section offsets.
+     has a different algorithm for finding section offsets.
 
      These should probably all be collapsed into some target
      independent form of shared library support.  FIXME.  */
 
-  if (addr)
+  if (addrs)
     {
       struct obj_section *s;
 
-      for (s = objfile->sections; s < objfile->sections_end; ++s)
+       /* Map section offsets in "addr" back to the object's 
+          sections by comparing the section names with bfd's 
+          section names.  Then adjust the section address by
+          the offset. */ /* for gdb/13815 */
+      ALL_OBJFILE_OSECTIONS (objfile, s)
        {
+         CORE_ADDR s_addr = 0;
+         int i;
+
+         if (strcmp (s->the_bfd_section->name, ".text") == 0)
+           s_addr = addrs->text_addr;
+         else if (strcmp (s->the_bfd_section->name, ".data") == 0)
+           s_addr = addrs->data_addr;
+         else if (strcmp (s->the_bfd_section->name, ".bss") == 0)
+           s_addr = addrs->bss_addr;
+         else 
+           for (i = 0; !s_addr && addrs->other[i].name; i++)
+             if (strcmp (s->the_bfd_section->name, addrs->other[i].name) == 0)
+               s_addr = addrs->other[i].addr; /* end added for gdb/13815 */
          s->addr -= s->offset;
-         s->addr += addr;
+         s->addr += s_addr;
          s->endaddr -= s->offset;
-         s->endaddr += addr;
-         s->offset += addr;
+         s->endaddr += s_addr;
+         s->offset += s_addr;
        }
     }
 #endif /* not IBM6000_TARGET */
 
-  (*objfile->sf->sym_read) (objfile, section_offsets, mainline);
+  (*objfile->sf->sym_read) (objfile, mainline);
 
   if (!have_partial_symbols () && !have_full_symbols ())
     {
@@ -633,10 +773,10 @@ syms_from_objfile (objfile, addr, mainline, verbo)
 
   discard_cleanups (old_chain);
 
-/* Call this after reading in a new symbol table to give target dependant code
-   a crack at the new symbols.  For instance, this could be used to update the
-   values of target-specific symbols GDB needs to keep track of (such as
-   _sigtramp, or whatever).  */
+  /* Call this after reading in a new symbol table to give target
+     dependant code a crack at the new symbols.  For instance, this
+     could be used to update the values of target-specific symbols GDB
+     needs to keep track of (such as _sigtramp, or whatever).  */
 
   TARGET_SYMFILE_POSTREAD (objfile);
 }
@@ -681,25 +821,16 @@ new_symfile_objfile (objfile, mainline, verbo)
    as dynamically loaded code.  If !mainline, ADDR is the address
    where the text segment was loaded.
 
-   USER_LOADED is TRUE if the add-symbol-file command was how this
-   symbol file came to be processed.
-
-   IS_SOLIB is TRUE if this symbol file represents a solib, as discovered
-   by the target's implementation of the solib package.
-
    Upon success, returns a pointer to the objfile that was added.
    Upon failure, jumps back to command level (never returns). */
 
 struct objfile *
-symbol_file_add (name, from_tty, addr, mainline, mapped, readnow, user_loaded, is_solib)
+symbol_file_add (name, from_tty, addrs, mainline, flags)
      char *name;
      int from_tty;
-     CORE_ADDR addr;
+     struct section_addr_info *addrs;
      int mainline;
-     int mapped;
-     int readnow;
-     int user_loaded;
-     int is_solib;
+     int flags;
 {
   struct objfile *objfile;
   struct partial_symtab *psymtab;
@@ -716,7 +847,7 @@ symbol_file_add (name, from_tty, addr, mainline, mapped, readnow, user_loaded, i
       && !query ("Load new symbol table from \"%s\"? ", name))
     error ("Not confirmed.");
 
-  objfile = allocate_objfile (abfd, mapped, user_loaded, is_solib);
+  objfile = allocate_objfile (abfd, flags);
 
   /* If the objfile uses a mapped symbol file, and we have a psymtab for
      it, then skip reading any symbols at this time. */
@@ -752,7 +883,7 @@ symbol_file_add (name, from_tty, addr, mainline, mapped, readnow, user_loaded, i
              gdb_flush (gdb_stdout);
            }
        }
-      syms_from_objfile (objfile, addr, mainline, from_tty);
+      syms_from_objfile (objfile, addrs, mainline, from_tty);
     }
 
   /* We now have at least a partial symbol table.  Check to see if the
@@ -760,7 +891,7 @@ symbol_file_add (name, from_tty, addr, mainline, mapped, readnow, user_loaded, i
      the gdb startup command line or on a per symbol file basis.  Expand
      all partial symbol tables for this objfile if so. */
 
-  if (readnow || readnow_symbol_files)
+  if ((flags & OBJF_READNOW) || readnow_symbol_files)
     {
       if (from_tty || info_verbose)
        {
@@ -790,7 +921,8 @@ symbol_file_add (name, from_tty, addr, mainline, mapped, readnow, user_loaded, i
 
   new_symfile_objfile (objfile, mainline, from_tty);
 
-  target_new_objfile (objfile);
+  if (target_new_objfile_hook)
+    target_new_objfile_hook (objfile);
 
   return (objfile);
 }
@@ -814,8 +946,7 @@ symbol_file_command (args, from_tty)
   char *name = NULL;
   CORE_ADDR text_relocation = 0;       /* text_relocation */
   struct cleanup *cleanups;
-  int mapped = 0;
-  int readnow = 0;
+  int flags = OBJF_USERLOADED;
 
   dont_repeat ();
 
@@ -856,11 +987,11 @@ symbol_file_command (args, from_tty)
        {
          if (STREQ (*argv, "-mapped"))
            {
-             mapped = 1;
+             flags |= OBJF_MAPPED;
            }
          else if (STREQ (*argv, "-readnow"))
            {
-             readnow = 1;
+             flags |= OBJF_READNOW;
            }
          else if (**argv == '-')
            {
@@ -884,17 +1015,20 @@ symbol_file_command (args, from_tty)
 
              if (text_relocation == (CORE_ADDR) 0)
                return;
-             else if (text_relocation == (CORE_ADDR) - 1)
+             else if (text_relocation == (CORE_ADDR) -1)
                {
-                 symbol_file_add (name, from_tty, (CORE_ADDR) 0,
-                                  1, mapped, readnow, 1, 0);
+                 symbol_file_add (name, from_tty, NULL, 1, flags);
 #ifdef HPUXHPPA
                  RESET_HP_UX_GLOBALS ();
 #endif
                }
              else
-               symbol_file_add (name, from_tty, (CORE_ADDR) text_relocation,
-                                0, mapped, readnow, 1, 0);
+               {
+                 struct section_addr_info section_addrs;
+                 memset (&section_addrs, 0, sizeof (section_addrs));
+                 section_addrs.text_addr = (CORE_ADDR) text_relocation;
+                 symbol_file_add (name, from_tty, &section_addrs, 0, flags);
+               }
 
              /* Getting new symbols may change our opinion about what is
                 frameless.  */
@@ -1075,42 +1209,52 @@ load_command (arg, from_tty)
    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;
+
+  /* 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))
     {
@@ -1124,72 +1268,78 @@ generic_load (filename, from_tty)
     {
       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");
+             fprintf_unfiltered (gdb_stdout,
+                                 "Loading section %s, size 0x%s lma 0x%s\n",
+                                 sect_name, paddr_nz (size), paddr_nz (lma));
 
              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;
+                 if (quit_flag
+                     || (ui_load_progress_hook != NULL
+                         && ui_load_progress_hook (sect_name, sent)))
+                   error ("Canceled the download");
+               }
+             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);
            }
@@ -1198,9 +1348,11 @@ generic_load (filename, from_tty)
 
   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 %d\n", entry, data_count);
+    fprintf_unfiltered (gdb_stdout,
+                       "Start address 0x%s , load size %ld\n",
+                       paddr_nz (entry), data_count);
     /* We were doing this in remote-mips.c, I suspect it is right
        for other targets too.  */
     write_pc (entry);
@@ -1212,25 +1364,40 @@ generic_load (filename, from_tty)
      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 ("%d 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 gdb_file *stream,
+                           unsigned long data_count,
+                           unsigned long write_count,
+                           unsigned long time_count)
+{
+  fprintf_unfiltered (stream, "Transfer rate: ");
+  if (time_count > 0)
+    fprintf_unfiltered (stream, "%ld bits/sec", (data_count * 8) / time_count);
   else
-    printf_filtered ("%d bits in <1 sec", (data_count * 8));
-  printf_filtered (".\n");
+    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");
 }
 
 /* This function allows the addition of incrementally linked object files.
@@ -1244,9 +1411,20 @@ add_symbol_file_command (args, from_tty)
 {
   char *name = NULL;
   CORE_ADDR text_addr;
+  int flags = OBJF_USERLOADED;
   char *arg;
-  int readnow = 0;
-  int mapped = 0;
+  int expecting_option = 0;
+  int option_index = 0;
+  int argcnt = 0;
+  int sec_num = 0;
+  int i;
+  struct
+  {
+    enum { OPT_SECTION } type;
+    char *name;
+    char *value;
+  } opt[SECT_OFF_MAX];
+  struct section_addr_info section_addrs;
 
   dont_repeat ();
 
@@ -1260,9 +1438,12 @@ add_symbol_file_command (args, from_tty)
   args = strdup (args);
   make_cleanup (free, args);
 
+  /* Ensure section_addrs is initialized */
+  memset (&section_addrs, 0, sizeof (section_addrs));
+
   /* Pick off any -option args and the file name. */
 
-  while ((*args != '\000') && (name == NULL))
+  while (*args != '\000')
     {
       while (isspace (*args))
        {
@@ -1279,26 +1460,66 @@ add_symbol_file_command (args, from_tty)
        }
       if (*arg != '-')
        {
-         name = arg;
+         if (expecting_option)
+           {
+             opt[option_index++].value = arg;
+             expecting_option = 0;
+           }
+         else
+           {
+             switch (argcnt)
+               {
+               case 0:
+                 name = arg;
+                 break;
+               case 1: 
+                 opt[option_index].type = OPT_SECTION;
+                 opt[option_index].name = ".text";
+                 opt[option_index++].value = arg;
+                 break;
+               case 2: 
+                 opt[option_index].type = OPT_SECTION;
+                 opt[option_index].name = ".data";
+                 opt[option_index++].value = arg;
+                 break;
+               case 3: 
+                 opt[option_index].type = OPT_SECTION;
+                 opt[option_index].name = ".bss";
+                 opt[option_index++].value = arg;
+                 break;
+               default:
+                 warning ("Too many arguments entered; see \"help add-symbol-file\" for command syntax.");
+               }
+             argcnt++;
+           }
        }
       else if (STREQ (arg, "-mapped"))
        {
-         mapped = 1;
+         flags |= OBJF_MAPPED;
        }
       else if (STREQ (arg, "-readnow"))
        {
-         readnow = 1;
-       }
-      else
-       {
-         error ("unknown option `%s'", arg);
+         flags |= OBJF_READNOW;
        }
+      else if (STREQN (arg, "-T", 2))
+       {
+         if (option_index >= SECT_OFF_MAX)
+           {
+             warning ("Number of options exceeds maximum allowed.");
+           }
+         else
+           {
+             expecting_option = 1;
+             opt[option_index].type = OPT_SECTION;
+             opt[option_index].name = arg + 2;
+           }
+       }
+      else 
+        {
+         error ("Unknown option `%s'", arg);
+        }
     }
 
-  /* After picking off any options and the file name, args should be
-     left pointing at the remainder of the command line, which should
-     be the address expression to evaluate. */
-
   if (name == NULL)
     {
       error ("add-symbol-file takes a file name");
@@ -1306,26 +1527,77 @@ add_symbol_file_command (args, from_tty)
   name = tilde_expand (name);
   make_cleanup (free, name);
 
-  if (*args != '\000')
+  if (option_index > 0)
     {
-      text_addr = parse_and_eval_address (args);
+      /* Print the prompt for the query below.
+        We have to split this up into 3 print statements because
+        local_hex_string returns a local static string. */
+      printf_filtered ("add symbol table from file \"%s\" at\n", name);
+      for (i = 0; i < option_index; i++)
+       {
+         switch (opt[i].type)
+           {
+           case OPT_SECTION:
+             {
+                CORE_ADDR addr;
+                char *val = opt[i].value;
+                char *sec = opt[i].name;
+                val = opt[i].value;
+                if (val[0] == '0' && val[1] == 'x')
+                  addr = strtoul (val+2, NULL, 16);
+                else
+                  addr = strtoul (val, NULL, 10);
+                if (strcmp (sec, ".text") == 0)
+                  section_addrs.text_addr = addr;
+                else if (strcmp (sec, ".data") == 0)
+                  section_addrs.data_addr = addr;
+                else if (strcmp (sec, ".bss") == 0)
+                  section_addrs.bss_addr = addr;
+                /* Add the section to the others even if it is a
+                   text data or bss section. This is redundent but
+                   eventually, none will be given special treatment */
+               {
+                 section_addrs.other[sec_num].name = strdup (sec);
+                 make_cleanup (free, section_addrs.other[sec_num].name);
+                 section_addrs.other[sec_num++].addr = addr;
+                 printf_filtered ("\t%s_addr = %s\n",
+                                  sec, 
+                                  local_hex_string ((unsigned long)addr));
+               }
+                /* The object's sections are initialized when a 
+                   call is made to build_objfile_section_table (objfile).
+                   This happens in reread_symbols. 
+                   At this point, we don't know what file type this is,
+                   so we can't determine what section names are valid.  */
+              }
+              break;
+            default:
+              complain (&unknown_option_complaint, opt[i].name);
+           }
+       }
+      /* Eventually, these hard coded names will be obsolete */
+      /* All the addresses will be on the others section */
     }
   else
     {
-      target_link (name, &text_addr);
-      if (text_addr == (CORE_ADDR) - 1)
-       error ("Don't know how to get text start location for this file");
-    }
-
-  /* FIXME-32x64: Assumes text_addr fits in a long.  */
-  if ((from_tty)
-      && (!query ("add symbol table from file \"%s\" at text_addr = %s?\n",
-                 name, local_hex_string ((unsigned long) text_addr))))
+      CORE_ADDR text_addr;
+      target_link (name, &text_addr);  
+      if (text_addr == (CORE_ADDR) -1)
+       error("Don't know how to get text start location for this file");
+      section_addrs.text_addr = text_addr;
+      section_addrs.data_addr = 0;
+      section_addrs.bss_addr = 0;
+      printf_filtered("add symbol table from file \"%s\" at text_addr = %s?\n",
+                     name, local_hex_string ((unsigned long)text_addr));
+    }
+  if (from_tty && (!query ("%s", "")))
     error ("Not confirmed.");
 
-  symbol_file_add (name, from_tty, text_addr, 0, mapped, readnow,
-                  1,           /* user_loaded */
-                  0);          /* We'll guess it's ! is_solib */
+  symbol_file_add (name, from_tty, &section_addrs, 0, flags);
 
   /* Getting new symbols may change our opinion about what is
      frameless.  */
@@ -1386,7 +1658,6 @@ reread_symbols ()
              struct cleanup *old_cleanups;
              struct section_offsets *offsets;
              int num_offsets;
-             int section_offsets_size;
              char *obfd_filename;
 
              printf_filtered ("`%s' has changed; re-reading symbols.\n",
@@ -1425,11 +1696,8 @@ reread_symbols ()
              /* Save the offsets, we will nuke them with the rest of the
                 psymbol_obstack.  */
              num_offsets = objfile->num_sections;
-             section_offsets_size =
-               sizeof (struct section_offsets)
-             + sizeof (objfile->section_offsets->offsets) * num_offsets;
-             offsets = (struct section_offsets *) alloca (section_offsets_size);
-             memcpy (offsets, objfile->section_offsets, section_offsets_size);
+             offsets = (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
+             memcpy (offsets, objfile->section_offsets, SIZEOF_SECTION_OFFSETS);
 
              /* Nuke all the state that we will re-read.  Much of the following
                 code which sets things to NULL really is necessary to tell
@@ -1486,8 +1754,8 @@ reread_symbols ()
              /* We use the same section offsets as from last time.  I'm not
                 sure whether that is always correct for shared libraries.  */
              objfile->section_offsets = (struct section_offsets *)
-               obstack_alloc (&objfile->psymbol_obstack, section_offsets_size);
-             memcpy (objfile->section_offsets, offsets, section_offsets_size);
+               obstack_alloc (&objfile->psymbol_obstack, SIZEOF_SECTION_OFFSETS);
+             memcpy (objfile->section_offsets, offsets, SIZEOF_SECTION_OFFSETS);
              objfile->num_sections = num_offsets;
 
              /* What the hell is sym_new_init for, anyway?  The concept of
@@ -1506,7 +1774,7 @@ reread_symbols ()
              /* The "mainline" parameter is a hideous hack; I think leaving it
                 zero is OK since dbxread.c also does what it needs to do if
                 objfile->global_psymbols.size is 0.  */
-             (*objfile->sf->sym_read) (objfile, objfile->section_offsets, 0);
+             (*objfile->sf->sym_read) (objfile, 0);
              if (!have_partial_symbols () && !have_full_symbols ())
                {
                  wrap_here ("");
@@ -1830,7 +2098,8 @@ clear_symtab_users ()
   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:
@@ -2044,10 +2313,7 @@ again2:
 /* Allocate and partially fill a partial symtab.  It will be
    completely filled at the end of the symbol list.
 
-   SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
-   is the address relative to which its symbols are (incremental) or 0
-   (normal). */
-
+   FILENAME is the name of the symbol-file we are reading from. */
 
 struct partial_symtab *
 start_psymtab_common (objfile, section_offsets,
@@ -2996,9 +3262,13 @@ to execute.", &cmdlist);
   c->completer = filename_completer;
 
   c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command,
-              "Usage: add-symbol-file FILE ADDR\n\
+              "Usage: add-symbol-file FILE ADDR [DATA_ADDR [BSS_ADDR]]\n\
+or:    add-symbol-file FILE -T<SECT> <SECT_ADDR> -T<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.",
+ADDR is the starting address of the file's text.\n\
+The optional arguments, DATA_ADDR and BSS_ADDR, should be specified\n\
+if the data and bss segments are not contiguous with the text.\n\
+For complicated cases, SECT is a section name to be loaded at SECT_ADDR.",
               &cmdlist);
   c->completer = filename_completer;
 
@@ -3057,4 +3327,16 @@ Usage: set extension-language .foo bar",
 
   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);
 }