#include "defs.h"
#include <sys/types.h>
#include <signal.h>
#include "gdb_string.h"
#include <sys/param.h>
#include <fcntl.h>
#include <sys/procfs.h>
#include "elf/external.h"
#include "symtab.h"
#include "bfd.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbcore.h"
#include "command.h"
#include "target.h"
#include "frame.h"
#include "gdb_regex.h"
#include "inferior.h"
#include "environ.h"
#include "language.h"
#include "gdbcmd.h"
#include "solist.h"
struct lm_info
{
int nmappings;
struct lm_mapping
{
CORE_ADDR addr;
CORE_ADDR size;
CORE_ADDR offset;
long flags;
CORE_ADDR gp;
} *mapping;
char *mapname;
char *pathname;
char *membername;
};
static char *solib_break_names[] =
{
"_r_debug_state",
NULL
};
static void aix5_relocate_main_executable (void);
static CORE_ADDR
bfd_lookup_symbol (bfd *abfd, char *symname)
{
long storage_needed;
asymbol *sym;
asymbol **symbol_table;
unsigned int number_of_symbols;
unsigned int i;
struct cleanup *back_to;
CORE_ADDR symaddr = 0;
storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
back_to = make_cleanup (xfree, symbol_table);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
{
sym = *symbol_table++;
if (strcmp (sym->name, symname) == 0)
{
symaddr = sym->value + sym->section->vma;
break;
}
}
do_cleanups (back_to);
}
if (symaddr)
return symaddr;
storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
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++)
{
sym = *symbol_table++;
if (strcmp (sym->name, symname) == 0)
{
symaddr = sym->value + sym->section->vma;
break;
}
}
do_cleanups (back_to);
}
return symaddr;
}
static struct so_list *
build_so_list_from_mapfile (int pid, long match_mask, long match_val)
{
char *mapbuf = NULL;
struct prmap *prmap;
int mapbuf_size;
struct so_list *sos = NULL;
{
int mapbuf_allocation_size = 8192;
char *map_pathname;
int map_fd;
map_pathname = xstrprintf ("/proc/%d/map", pid);
map_fd = open (map_pathname, O_RDONLY);
xfree (map_pathname);
if (map_fd < 0)
return 0;
do
{
if (mapbuf)
{
xfree (mapbuf);
mapbuf_allocation_size *= 2;
lseek (map_fd, 0, SEEK_SET);
}
mapbuf = xmalloc (mapbuf_allocation_size);
mapbuf_size = read (map_fd, mapbuf, mapbuf_allocation_size);
if (mapbuf_size < 0)
{
xfree (mapbuf);
return 0;
}
} while (mapbuf_size == mapbuf_allocation_size);
close (map_fd);
}
for (prmap = (struct prmap *) mapbuf;
(char *) prmap < mapbuf + mapbuf_size;
prmap++)
{
char *mapname, *pathname, *membername;
struct so_list *sop;
int mapidx;
if (prmap->pr_size == 0)
break;
if ((prmap->pr_pathoff == 0 || prmap->pr_pathoff >= mapbuf_size)
&& ((match_mask & MA_KERNTEXT) == 0))
continue;
if ((prmap->pr_mflags & match_mask) != match_val)
continue;
mapname = prmap->pr_mapname;
if (prmap->pr_pathoff == 0)
{
pathname = "";
membername = "";
}
else
{
pathname = mapbuf + prmap->pr_pathoff;
membername = pathname + strlen (pathname) + 1;
}
for (sop = sos; sop != NULL; sop = sop->next)
if (strcmp (pathname, sop->lm_info->pathname) == 0
&& strcmp (membername, sop->lm_info->membername) == 0)
break;
if (sop == NULL)
{
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 (xfree, sop->lm_info->mapname);
sop->lm_info->pathname = xstrdup (pathname);
make_cleanup (xfree, sop->lm_info->pathname);
sop->lm_info->membername = xstrdup (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';
strcpy (sop->so_original_name, sop->so_name);
sop->next = sos;
sos = sop;
}
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;
}
xfree (mapbuf);
return sos;
}
static int
open_symbol_file_object (void *from_ttyp)
{
CORE_ADDR lm, l_name;
char *filename;
int errcode;
int from_tty = *(int *)from_ttyp;
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
struct so_list *sos;
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"));
return 0;
}
symbol_file_command (sos->lm_info->pathname, from_tty);
do_cleanups (old_chain);
aix5_relocate_main_executable ();
return 1;
}
static struct so_list *
aix5_current_sos (void)
{
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
struct so_list *sos;
sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), MA_MAINEXEC, 0);
if (sos)
{
struct so_list *next = sos->next;
sos->next = 0;
while (next)
{
struct so_list *prev = sos;
sos = next;
next = next->next;
sos->next = prev;
}
}
discard_cleanups (old_chain);
return sos;
}
static CORE_ADDR interp_text_sect_low;
static CORE_ADDR interp_text_sect_high;
static CORE_ADDR interp_plt_sect_low;
static CORE_ADDR interp_plt_sect_high;
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)
|| in_plt_section (pc, NULL));
}
static int
enable_break (void)
{
int success = 0;
struct minimal_symbol *msymbol;
char **bkpt_namep;
asection *interp_sect;
remove_solib_event_breakpoints ();
interp_text_sect_low = interp_text_sect_high = 0;
interp_plt_sect_low = interp_plt_sect_high = 0;
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
if (interp_sect)
{
unsigned int interp_sect_size;
char *buf;
CORE_ADDR load_addr;
bfd *tmp_bfd;
CORE_ADDR sym_addr = 0;
interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
buf = alloca (interp_sect_size);
bfd_get_section_contents (exec_bfd, interp_sect,
buf, 0, interp_sect_size);
tmp_bfd = bfd_openr (buf, gnutarget);
if (tmp_bfd == NULL)
goto bkpt_at_symbol;
if (!bfd_check_format (tmp_bfd, bfd_object))
{
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;
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_text_sect_high =
interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_plt_sect_high =
interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
}
for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
{
sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep);
if (sym_addr != 0)
break;
}
bfd_close (tmp_bfd);
if (sym_addr != 0)
{
create_solib_event_breakpoint (load_addr + sym_addr);
return 1;
}
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."));
}
success = 0;
return (success);
}
static void
aix5_special_symbol_handling (void)
{
}
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
aix5_relocate_main_executable (void)
{
struct so_list *so;
struct section_offsets *new_offsets;
int i;
int changed = 0;
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
so = build_so_list_from_mapfile (PIDGET (inferior_ptid),
MA_MAINEXEC, MA_MAINEXEC);
if (so == NULL)
{
warning (_("Could not find main executable in map file"));
do_cleanups (old_chain);
return;
}
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++)
new_offsets->offsets[i] = ANOFFSET (symfile_objfile->section_offsets, 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)
{
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 = mapping->addr
- (bfd_section_vma (obfd, sect->the_bfd_section)
& SECTMAPMASK);
if (increment != ANOFFSET (new_offsets, idx))
{
new_offsets->offsets[idx] = increment;
changed = 1;
}
}
}
}
}
if (changed)
objfile_relocate (symfile_objfile, new_offsets);
do_cleanups (old_chain);
}
static void
aix5_solib_create_inferior_hook (void)
{
aix5_relocate_main_executable ();
if (!enable_break ())
{
warning (_("shared library handler failed to enable breakpoint"));
return;
}
}
static void
aix5_clear_solib (void)
{
}
static void
aix5_free_so (struct so_list *so)
{
xfree (so->lm_info->mapname);
xfree (so->lm_info->pathname);
xfree (so->lm_info->membername);
xfree (so->lm_info);
}
static void
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;
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;
}
}
static CORE_ADDR
aix5_find_global_pointer (CORE_ADDR addr)
{
struct so_list *sos, *so;
CORE_ADDR global_pointer = 0;
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
sos = build_so_list_from_mapfile (PIDGET (inferior_ptid), 0, 0);
for (so = sos; so != NULL; so = so->next)
{
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)
{
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;
}
break;
}
}
do_cleanups (old_chain);
return global_pointer;
}
static void
aix5_find_gate_addresses (CORE_ADDR *start, CORE_ADDR *end)
{
struct so_list *so;
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
so = build_so_list_from_mapfile (PIDGET (inferior_ptid),
MA_KERNTEXT, MA_KERNTEXT);
if (so == NULL)
{
warning (_("Could not find gate page in map file"));
*start = 0;
*end = 0;
do_cleanups (old_chain);
return;
}
*start = so->lm_info->mapping[0].addr;
*end = *start + so->lm_info->mapping[0].size;
do_cleanups (old_chain);
}
extern CORE_ADDR (*native_find_global_pointer) (CORE_ADDR);
extern void (*aix5_find_gate_addresses_hook) (CORE_ADDR *, CORE_ADDR *);
static struct target_so_ops aix5_so_ops;
void
_initialize_aix5_solib (void)
{
aix5_so_ops.relocate_section_addresses = aix5_relocate_section_addresses;
aix5_so_ops.free_so = aix5_free_so;
aix5_so_ops.clear_solib = aix5_clear_solib;
aix5_so_ops.solib_create_inferior_hook = aix5_solib_create_inferior_hook;
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;
current_target_so_ops = &aix5_so_ops;
}