/* Handle AIX5 shared libraries for GDB, the GNU Debugger.
- Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
- 2000, 2001
- Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2007 Free Software Foundation, Inc.
This file is part of GDB.
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"
/* 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 */
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;
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++)
/* 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++)
{
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);
+ map_pathname = xstrprintf ("/proc/%d/map", pid);
map_fd = open (map_pathname, O_RDONLY);
+ xfree (map_pathname);
if (map_fd < 0)
return 0;
{
if (mapbuf)
{
- free (mapbuf);
+ xfree (mapbuf);
mapbuf_allocation_size *= 2;
lseek (map_fd, 0, SEEK_SET);
}
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;
}
{
char *mapname, *pathname, *membername;
struct so_list *sop;
- enum maptype maptype;
+ int mapidx;
if (prmap->pr_size == 0)
break;
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';
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;
}
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);
if (sos == NULL)
{
- warning ("Could not find name of main executable in map file");
+ warning (_("Could not find name of main executable in map file"));
return 0;
}
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. */
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)
/* Make sure the dynamic linker's really a useful object. */
if (!bfd_check_format (tmp_bfd, bfd_object))
{
- warning ("Unable to grok dynamic linker %s as an object file", buf);
+ warning (_("Unable to grok dynamic linker %s as an object file"), buf);
bfd_close (tmp_bfd);
goto bkpt_at_symbol;
}
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)
{
/* For whatever reason we couldn't set a breakpoint in the dynamic
linker. Warn and drop into the old code. */
bkpt_at_symbol:
- warning ("Unable to find dynamic linker breakpoint function.\nGDB will be unable to debug shared library initializers\nand track explicitly loaded dynamic code.");
+ warning (_("Unable to find dynamic linker breakpoint function.\nGDB will be unable to debug shared library initializers\nand track explicitly loaded dynamic code."));
}
/* Nothing good happened. */
/* 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 (_("Ignoring section %s when relocating the executable."),
+ name);
+ return 0;
+}
+
#define SECTMAPMASK (~ (CORE_ADDR) 0x03ffffff)
static 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. */
if (so == NULL)
{
- warning ("Could not find main executable in map file");
+ warning (_("Could not find main executable in map file"));
do_cleanups (old_chain);
return;
}
/* 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;
}
}
SYNOPSIS
- void aix5_solib_create_inferior_hook()
+ void aix5_solib_create_inferior_hook ()
DESCRIPTION
if (!enable_break ())
{
- warning ("shared library handler failed to enable breakpoint");
+ warning (_("shared library handler failed to enable breakpoint"));
return;
}
}
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
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;
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;
}
}
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. */
if (so == NULL)
{
- warning ("Could not find gate page in map file");
+ warning (_("Could not find gate page in map file"));
*start = 0;
*end = 0;
do_cleanups (old_chain);
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);
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;
/* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
current_target_so_ops = &aix5_so_ops;
}
-