2004-04-17 Randolph Chung <tausq@debian.org>
[deliverable/binutils-gdb.git] / gdb / solib-aix5.c
index 1eddafe612bf05bc18b4ac1a406a3af1c7113fcf..1a8c9dfeea94d8ae575f0e25eb25decb2803bd82 100644 (file)
@@ -1,6 +1,6 @@
 /* Handle AIX5 shared libraries for GDB, the GNU Debugger.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
-   2000, 2001
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2001
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 /* Link map info to include in an allocated so_list entry */
 
-enum maptype {
-  MT_READONLY = 0,
-  MT_READWRITE = 1,
-  MT_LAST = 2
-};
-
 struct lm_info
   {
-    struct
+    int nmappings;             /* number of mappings */
+    struct lm_mapping
       {
        CORE_ADDR addr;         /* base address */
        CORE_ADDR size;         /* size of mapped object */
        CORE_ADDR offset;       /* offset into mapped object */
        long flags;             /* MA_ protection and attribute flags */
        CORE_ADDR gp;           /* global pointer value */
-      } mapping[MT_LAST];
+      } *mapping;
       char *mapname;           /* name in /proc/pid/object */
       char *pathname;          /* full pathname to object */
       char *membername;                /* member name in archive file */
@@ -105,7 +100,7 @@ static void aix5_relocate_main_executable (void);
 static CORE_ADDR
 bfd_lookup_symbol (bfd *abfd, char *symname)
 {
-  unsigned int storage_needed;
+  long storage_needed;
   asymbol *sym;
   asymbol **symbol_table;
   unsigned int number_of_symbols;
@@ -118,7 +113,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   if (storage_needed > 0)
     {
       symbol_table = (asymbol **) xmalloc (storage_needed);
-      back_to = make_cleanup (free, (PTR) symbol_table);
+      back_to = make_cleanup (xfree, symbol_table);
       number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
 
       for (i = 0; i < number_of_symbols; i++)
@@ -140,15 +135,11 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   /* Look for the symbol in the dynamic string table too.  */
 
   storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
-/* FIXME: This problem should be addressed in BFD.  */
-#define REASONABLE_LIMIT 0x400000
-  if (storage_needed > REASONABLE_LIMIT)
-    storage_needed = REASONABLE_LIMIT;
 
   if (storage_needed > 0)
     {
       symbol_table = (asymbol **) xmalloc (storage_needed);
-      back_to = make_cleanup (free, (PTR) symbol_table);
+      back_to = make_cleanup (xfree, symbol_table);
       number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
 
       for (i = 0; i < number_of_symbols; i++)
@@ -197,13 +188,14 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
 
   {
     int mapbuf_allocation_size = 8192;
-    char map_pathname[64];
+    char *map_pathname;
     int map_fd;
 
     /* Open the map file */
 
-    sprintf (map_pathname, "/proc/%d/map", pid);
+    xasprintf (&map_pathname, "/proc/%d/map", pid);
     map_fd = open (map_pathname, O_RDONLY);
+    xfree (map_pathname);
     if (map_fd < 0)
       return 0;
 
@@ -212,7 +204,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
       {
        if (mapbuf)
          {
-           free (mapbuf);
+           xfree (mapbuf);
            mapbuf_allocation_size *= 2;
            lseek (map_fd, 0, SEEK_SET);
          }
@@ -220,7 +212,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
        mapbuf_size = read (map_fd, mapbuf, mapbuf_allocation_size);
        if (mapbuf_size < 0)
          {
-           free (mapbuf);
+           xfree (mapbuf);
            /* FIXME: This warrants an error or a warning of some sort */
            return 0;
          }
@@ -235,7 +227,7 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
     {
       char *mapname, *pathname, *membername;
       struct so_list *sop;
-      enum maptype maptype;
+      int mapidx;
 
       if (prmap->pr_size == 0)
        break;
@@ -270,18 +262,18 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
 
       if (sop == NULL)
        {
-         sop = xcalloc (sizeof (struct so_list), 1);
-         make_cleanup (free, sop);
-         sop->lm_info = xcalloc (sizeof (struct lm_info), 1);
-         make_cleanup (free, sop->lm_info);
+         sop = xcalloc (1, sizeof (struct so_list));
+         make_cleanup (xfree, sop);
+         sop->lm_info = xcalloc (1, sizeof (struct lm_info));
+         make_cleanup (xfree, sop->lm_info);
          sop->lm_info->mapname = xstrdup (mapname);
-         make_cleanup (free, sop->lm_info->mapname);
+         make_cleanup (xfree, sop->lm_info->mapname);
          /* FIXME: Eliminate the pathname field once length restriction
             is lifted on so_name and so_original_name.  */
          sop->lm_info->pathname = xstrdup (pathname);
-         make_cleanup (free, sop->lm_info->pathname);
+         make_cleanup (xfree, sop->lm_info->pathname);
          sop->lm_info->membername = xstrdup (membername);
-         make_cleanup (free, sop->lm_info->membername);
+         make_cleanup (xfree, sop->lm_info->membername);
 
          strncpy (sop->so_name, pathname, SO_NAME_MAX_PATH_SIZE - 1);
          sop->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
@@ -291,15 +283,19 @@ build_so_list_from_mapfile (int pid, long match_mask, long match_val)
          sos = sop;
        }
 
-      maptype = (prmap->pr_mflags & MA_WRITE) ? MT_READWRITE : MT_READONLY;
-      sop->lm_info->mapping[maptype].addr = (CORE_ADDR) prmap->pr_vaddr;
-      sop->lm_info->mapping[maptype].size = prmap->pr_size;
-      sop->lm_info->mapping[maptype].offset = prmap->pr_off;
-      sop->lm_info->mapping[maptype].flags = prmap->pr_mflags;
-      sop->lm_info->mapping[maptype].gp = (CORE_ADDR) prmap->pr_gp;
+      mapidx = sop->lm_info->nmappings;
+      sop->lm_info->nmappings += 1;
+      sop->lm_info->mapping 
+       = xrealloc (sop->lm_info->mapping,
+                   sop->lm_info->nmappings * sizeof (struct lm_mapping));
+      sop->lm_info->mapping[mapidx].addr = (CORE_ADDR) prmap->pr_vaddr;
+      sop->lm_info->mapping[mapidx].size = prmap->pr_size;
+      sop->lm_info->mapping[mapidx].offset = prmap->pr_off;
+      sop->lm_info->mapping[mapidx].flags = prmap->pr_mflags;
+      sop->lm_info->mapping[mapidx].gp = (CORE_ADDR) prmap->pr_gp;
     }
 
-  free (mapbuf);
+  xfree (mapbuf);
   return sos;
 }
 
@@ -333,7 +329,7 @@ open_symbol_file_object (void *from_ttyp)
   struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
   struct so_list *sos;
 
-  sos = build_so_list_from_mapfile (PIDGET (inferior_pid),
+  sos = build_so_list_from_mapfile (PIDGET (inferior_ptid),
                                     MA_MAINEXEC, MA_MAINEXEC);
 
 
@@ -378,7 +374,7 @@ aix5_current_sos (void)
   struct so_list *sos;
 
   /* Fetch the list of mappings, excluding the main executable. */
-  sos = build_so_list_from_mapfile (PIDGET (inferior_pid), MA_MAINEXEC, 0);
+  sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_MAINEXEC, 0);
 
   /* Reverse the list; it looks nicer when we print it if the mappings
      are in the same order as in the map file.  */
@@ -409,9 +405,8 @@ static CORE_ADDR interp_text_sect_high;
 static CORE_ADDR interp_plt_sect_low;
 static CORE_ADDR interp_plt_sect_high;
 
-/* FIXME: Does this belong here?  (If it does, it ought to be renamed.) */
-int
-in_svr4_dynsym_resolve_code (CORE_ADDR pc)
+static int
+aix5_in_dynsym_resolve_code (CORE_ADDR pc)
 {
   return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
          || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
@@ -496,7 +491,7 @@ enable_break (void)
       load_addr = read_pc () - tmp_bfd->start_address;
 
       /* Record the relocated start and end address of the dynamic linker
-         text and plt section for in_aix5_dynsym_resolve_code.  */
+         text and plt section for aix5_in_dynsym_resolve_code.  */
       interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
       if (interp_sect)
        {
@@ -567,6 +562,133 @@ aix5_special_symbol_handling (void)
   /* Nothing needed (yet) for AIX5. */
 }
 
+/* On AIX5, the /proc/PID/map information is used to determine
+   the relocation offsets needed for relocating the main executable.
+   There is no problem determining which map entries correspond
+   to the main executable, because these will have the MA_MAINEXEC
+   flag set.  The tricky part is determining which sections correspond
+   to which map entries.  To date, the following approaches have
+   been tried:
+
+    - Use the MA_WRITE attribute of pr_mflags to distinguish the read-only
+      mapping from the read/write mapping.  (This assumes that there are
+      only two mappings for the main executable.)  All writable sections
+      are associated with the read/write mapping and all non-writable
+      sections are associated with the read-only mapping.
+
+      This approach worked quite well until we came across executables
+      which didn't have a read-only mapping.  Both mappings had the
+      same attributes represented in pr_mflags and it was impossible
+      to tell them apart.
+
+    - Use the pr_off field (which represents the offset into the
+      executable) to determine the section-to-mapping relationship.
+      Unfortunately, this approach doesn't work either, because the
+      offset value contained in the mapping is rounded down by some
+      moderately large power-of-2 value (4096 is a typical value).
+      A small (e.g. "Hello World") program will appear to have all
+      of its sections belonging to both mappings.
+
+   Also, the following approach has been considered, but dismissed:
+
+    - The section vma values typically look (something) like
+      0x00000001xxxxxxxx or 0x00000002xxxxxxxx.  Furthermore, the
+      0x00000001xxxxxxxx values always belong to one mapping and
+      the 0x00000002xxxxxxxx values always belong to the other.
+      Thus it seems conceivable that GDB could use the bit patterns
+      in the upper portion (for some definition of "upper") in a
+      section's vma to help determine the section-to-mapping
+      relationship.
+
+      This approach was dismissed because there is nothing to prevent
+      the linker from lumping the section vmas together in one large
+      contiguous space and still expecting the dynamic linker to
+      separate them and relocate them independently.  Also, different
+      linkers have been observed to use different patterns for the
+      upper portions of the vma addresses and it isn't clear what the
+      mask ought to be for distinguishing these patterns.
+
+   The current (admittedly inelegant) approach uses a lookup 
+   table which associates section names with the map index that
+   they're permitted to be in.  This is inelegant because we are
+   making the following assumptions:
+
+    1) There will only be two mappings.
+    2) The relevant (i.e. main executable) mappings will always appear
+       in the same order in the map file.
+    3) The sections named in the table will always belong to the
+       indicated mapping.
+    4) The table completely enumerates all possible section names.
+
+   IMO, any of these deficiencies alone will normally be sufficient
+   to disqualify this approach, but I haven't been able to think of
+   a better way to do it.
+   
+   map_index_vs_section_name_okay() is a predicate which returns
+   true iff the section name NAME is associated with the map index
+   IDX in its builtin table.  Of course, there's no guarantee that
+   this association is actually valid...  */
+
+static int
+map_index_vs_section_name_okay (int idx, const char *name)
+{
+  static struct
+    {
+      char *name;
+      int idx;
+    } okay[] =
+    {
+      { ".interp", 0 },
+      { ".hash", 0 },
+      { ".dynsym", 0 },
+      { ".dynstr", 0 },
+      { ".rela.text", 0 },
+      { ".rela.rodata", 0 },
+      { ".rela.data", 0 },
+      { ".rela.ctors", 0 },
+      { ".rela.dtors", 0 },
+      { ".rela.got", 0 },
+      { ".rela.sdata", 0 },
+      { ".rela.IA_64.pltoff", 0 },
+      { ".rel.data", 0 },
+      { ".rel.sdata", 0 },
+      { ".rel.got", 0 },
+      { ".rel.AIX.pfdesc", 0 },
+      { ".rel.IA_64.pltoff", 0 },
+      { ".dynamic", 0 },
+      { ".init", 0 },
+      { ".plt", 0 },
+      { ".text", 0 },
+      { ".fini", 0 },
+      { ".rodata", 0 },
+      { ".IA_64.unwind_info", 0 },
+      { ".IA_64.unwind", 0 },
+      { ".AIX.mustrel", 0 },
+
+      { ".data", 1 },
+      { ".ctors", 1 },
+      { ".dtors", 1 },
+      { ".got", 1 },
+      { ".dynamic", 1},
+      { ".sdata", 1 },
+      { ".IA_64.pltoff", 1 },
+      { ".sbss", 1 },
+      { ".bss", 1 },
+      { ".AIX.pfdesc", 1 }
+    };
+  int i;
+
+  for (i = 0; i < sizeof (okay) / sizeof (okay[0]); i++)
+    {
+      if (strcmp (name, okay[i].name) == 0)
+       return idx == okay[i].idx;
+    }
+
+  warning ("solib-aix5.c: Ignoring section %s when relocating the executable\n",
+           name);
+  return 0;
+}
+
 #define SECTMAPMASK (~ (CORE_ADDR) 0x03ffffff)
 
 static void
@@ -579,7 +701,7 @@ aix5_relocate_main_executable (void)
   struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
 
   /* Fetch the mappings for the main executable from the map file.  */
-  so = build_so_list_from_mapfile (PIDGET (inferior_pid),
+  so = build_so_list_from_mapfile (PIDGET (inferior_ptid),
                                    MA_MAINEXEC, MA_MAINEXEC);
 
   /* Make sure we actually have some mappings to work with.  */
@@ -592,38 +714,40 @@ aix5_relocate_main_executable (void)
 
   /* Allocate the data structure which'll contain the new offsets to
      relocate by.  Initialize it so it contains the current offsets.  */
-  new_offsets = xcalloc (sizeof (struct section_offsets),
-                         symfile_objfile->num_sections);
-  make_cleanup (free, new_offsets);
+  new_offsets = xcalloc (symfile_objfile->num_sections,
+                        sizeof (struct section_offsets));
+  make_cleanup (xfree, new_offsets);
   for (i = 0; i < symfile_objfile->num_sections; i++)
-    ANOFFSET (new_offsets, i) = ANOFFSET (symfile_objfile->section_offsets, i);
+    new_offsets->offsets[i] = ANOFFSET (symfile_objfile->section_offsets, i);
 
   /* Iterate over the mappings in the main executable and compute
      the new offset value as appropriate.  */
-  for (i = 0; i < MT_LAST; i++)
+  for (i = 0; i < so->lm_info->nmappings; i++)
     {
       CORE_ADDR increment = 0;
       struct obj_section *sect;
       bfd *obfd = symfile_objfile->obfd;
+      struct lm_mapping *mapping = &so->lm_info->mapping[i];
 
       ALL_OBJFILE_OSECTIONS (symfile_objfile, sect)
        {
          int flags = bfd_get_section_flags (obfd, sect->the_bfd_section);
          if (flags & SEC_ALLOC)
            {
-             if (((so->lm_info->mapping[i].flags & MA_WRITE) == 0)
-                   == ((flags & SEC_READONLY) != 0))
+             file_ptr filepos = sect->the_bfd_section->filepos;
+             if (map_index_vs_section_name_okay (i,
+                   bfd_get_section_name (obfd, sect->the_bfd_section)))
                {
                  int idx = sect->the_bfd_section->index;
 
                  if (increment == 0)
-                   increment = so->lm_info->mapping[i].addr
+                   increment = mapping->addr
                      - (bfd_section_vma (obfd, sect->the_bfd_section) 
                         & SECTMAPMASK);
 
                  if (increment != ANOFFSET (new_offsets, idx))
                    {
-                     ANOFFSET (new_offsets, idx) = increment;
+                     new_offsets->offsets[idx] = increment;
                      changed = 1;
                    }
                }
@@ -687,10 +811,10 @@ aix5_clear_solib (void)
 static void
 aix5_free_so (struct so_list *so)
 {
-  free (so->lm_info->mapname);
-  free (so->lm_info->pathname);
-  free (so->lm_info->membername);
-  free (so->lm_info);
+  xfree (so->lm_info->mapname);
+  xfree (so->lm_info->pathname);
+  xfree (so->lm_info->membername);
+  xfree (so->lm_info);
 }
 
 static void
@@ -698,11 +822,27 @@ aix5_relocate_section_addresses (struct so_list *so,
                                  struct section_table *sec)
 {
   int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section);
+  file_ptr filepos = sec->the_bfd_section->filepos;
 
   if (flags & SEC_ALLOC)
     {
-      int idx = (flags & SEC_READONLY) ? MT_READONLY : MT_READWRITE;
-      CORE_ADDR addr = so->lm_info->mapping[idx].addr;
+      int idx;
+      CORE_ADDR addr;
+
+      for (idx = 0; idx < so->lm_info->nmappings; idx++)
+       {
+         struct lm_mapping *mapping = &so->lm_info->mapping[idx];
+         if (mapping->offset <= filepos
+             && filepos <= mapping->offset + mapping->size)
+           break;
+       }
+
+      if (idx >= so->lm_info->nmappings)
+       internal_error (__FILE__, __LINE__,
+         "aix_relocate_section_addresses: Can't find mapping for section %s",
+         bfd_get_section_name (sec->bfd, sec->the_bfd_section));
+      
+      addr = so->lm_info->mapping[idx].addr;
 
       sec->addr += addr;
       sec->endaddr += addr;
@@ -718,15 +858,31 @@ aix5_find_global_pointer (CORE_ADDR addr)
   CORE_ADDR global_pointer = 0;
   struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
 
-  sos = build_so_list_from_mapfile (PIDGET (inferior_pid), 0, 0);
+  sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), 0, 0);
 
   for (so = sos; so != NULL; so = so->next)
     {
-      if (so->lm_info->mapping[MT_READONLY].addr <= addr
-          && addr <= so->lm_info->mapping[MT_READONLY].addr
-                      + so->lm_info->mapping[MT_READONLY].size)
+      int idx;
+      for (idx = 0; idx < so->lm_info->nmappings; idx++)
+       if (so->lm_info->mapping[idx].addr <= addr
+           && addr <= so->lm_info->mapping[idx].addr
+                        + so->lm_info->mapping[idx].size)
+         {
+           break;
+         }
+
+      if (idx < so->lm_info->nmappings)
        {
-         global_pointer = so->lm_info->mapping[MT_READWRITE].gp;
+         /* Look for a non-zero global pointer in the current set of
+            mappings.  */
+         for (idx = 0; idx < so->lm_info->nmappings; idx++)
+           if (so->lm_info->mapping[idx].gp != 0)
+             {
+               global_pointer = so->lm_info->mapping[idx].gp;
+               break;
+             }
+         /* Get out regardless of whether we found one or not.  Mappings
+            don't overlap, so it would be pointless to continue.  */
          break;
        }
     }
@@ -746,7 +902,7 @@ aix5_find_gate_addresses (CORE_ADDR *start, CORE_ADDR *end)
   struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
 
   /* Fetch the mappings for the main executable from the map file.  */
-  so = build_so_list_from_mapfile (PIDGET (inferior_pid),
+  so = build_so_list_from_mapfile (PIDGET (inferior_ptid),
                                    MA_KERNTEXT, MA_KERNTEXT);
 
   /* Make sure we actually have some mappings to work with.  */
@@ -763,8 +919,8 @@ aix5_find_gate_addresses (CORE_ADDR *start, CORE_ADDR *end)
      it'll be in the read-only (even though it's execute-only)
      mapping in the lm_info struct.  */
 
-  *start = so->lm_info->mapping[MT_READONLY].addr;
-  *end = *start + so->lm_info->mapping[MT_READONLY].size;
+  *start = so->lm_info->mapping[0].addr;
+  *end = *start + so->lm_info->mapping[0].size;
 
   /* Free up all the space we've allocated.  */
   do_cleanups (old_chain);
@@ -792,6 +948,7 @@ _initialize_aix5_solib (void)
   aix5_so_ops.special_symbol_handling = aix5_special_symbol_handling;
   aix5_so_ops.current_sos = aix5_current_sos;
   aix5_so_ops.open_symbol_file_object = open_symbol_file_object;
+  aix5_so_ops.in_dynsym_resolve_code = aix5_in_dynsym_resolve_code;
 
   native_find_global_pointer = aix5_find_global_pointer;
   aix5_find_gate_addresses_hook = aix5_find_gate_addresses;
@@ -799,4 +956,3 @@ _initialize_aix5_solib (void)
   /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
   current_target_so_ops = &aix5_so_ops;
 }
-
This page took 0.038021 seconds and 4 git commands to generate.