#include "defs.h"
#include "symtab.h"
#include "bfd.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbcore.h"
#include "target.h"
#include "inferior.h"
#include "hppa-tdep.h"
#include "solist.h"
#include "solib-pa64.h"
#undef SOLIB_PA64_DBG
#ifndef PA_SOM_ONLY
#include <dlfcn.h>
#include <elf.h>
#include <elf_hp.h>
struct lm_info {
struct load_module_desc desc;
CORE_ADDR desc_addr;
};
typedef struct
{
CORE_ADDR dld_flags_addr;
LONGEST dld_flags;
struct bfd_section *dyninfo_sect;
int have_read_dld_descriptor;
int is_valid;
CORE_ADDR load_map;
CORE_ADDR load_map_addr;
struct load_module_desc dld_desc;
}
dld_cache_t;
static dld_cache_t dld_cache;
static int
read_dynamic_info (asection *dyninfo_sect, dld_cache_t *dld_cache_p);
static void
pa64_relocate_section_addresses (struct so_list *so,
struct section_table *sec)
{
asection *asec = sec->the_bfd_section;
CORE_ADDR load_offset;
load_offset = bfd_section_vma (so->abfd, asec) - asec->filepos;
if (asec->flags & SEC_CODE)
{
sec->addr += so->lm_info->desc.text_base - load_offset;
sec->endaddr += so->lm_info->desc.text_base - load_offset;
}
else if (asec->flags & SEC_DATA)
{
sec->addr += so->lm_info->desc.data_base - load_offset;
sec->endaddr += so->lm_info->desc.data_base - load_offset;
}
}
static void
pa64_free_so (struct so_list *so)
{
xfree (so->lm_info);
}
static void
pa64_clear_solib (void)
{
}
static void *
pa64_target_read_memory (void *buffer, CORE_ADDR ptr, size_t bufsiz, int ident)
{
if (target_read_memory (ptr, buffer, bufsiz) != 0)
return 0;
return buffer;
}
static int
read_dld_descriptor (void)
{
char *dll_path;
asection *dyninfo_sect;
if (!dld_cache.is_valid)
{
if (symfile_objfile == NULL)
error (_("No object file symbols."));
dyninfo_sect = bfd_get_section_by_name (symfile_objfile->obfd,
".dynamic");
if (!dyninfo_sect)
{
return 0;
}
if (!read_dynamic_info (dyninfo_sect, &dld_cache))
error (_("Unable to read in .dynamic section information."));
}
if (target_read_memory (dld_cache.load_map_addr,
(char *) &dld_cache.load_map,
sizeof (dld_cache.load_map))
!= 0)
{
error (_("Error while reading in load map pointer."));
}
if (dlgetmodinfo (-1,
&dld_cache.dld_desc,
sizeof (dld_cache.dld_desc),
pa64_target_read_memory,
0,
dld_cache.load_map)
== 0)
{
error (_("Error trying to get information about dynamic linker."));
}
dld_cache.have_read_dld_descriptor = 1;
return 1;
}
static int
read_dynamic_info (asection *dyninfo_sect, dld_cache_t *dld_cache_p)
{
char *buf;
char *bufend;
CORE_ADDR dyninfo_addr;
int dyninfo_sect_size;
CORE_ADDR entry_addr;
dyninfo_addr = bfd_section_vma (symfile_objfile->obfd, dyninfo_sect);
dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect);
buf = alloca (dyninfo_sect_size);
if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size))
return 0;
for (bufend = buf + dyninfo_sect_size, entry_addr = dyninfo_addr;
buf < bufend;
buf += sizeof (Elf64_Dyn), entry_addr += sizeof (Elf64_Dyn))
{
Elf64_Dyn *x_dynp = (Elf64_Dyn*)buf;
Elf64_Sxword dyn_tag;
CORE_ADDR dyn_ptr;
char *pbuf;
pbuf = alloca (TARGET_PTR_BIT / HOST_CHAR_BIT);
dyn_tag = bfd_h_get_64 (symfile_objfile->obfd,
(bfd_byte*) &x_dynp->d_tag);
if (dyn_tag == DT_NULL)
break;
else if (dyn_tag == DT_HP_DLD_FLAGS)
{
dld_cache_p->dld_flags_addr = entry_addr + offsetof(Elf64_Dyn, d_un);
if (target_read_memory (dld_cache_p->dld_flags_addr,
(char*) &dld_cache_p->dld_flags,
sizeof (dld_cache_p->dld_flags))
!= 0)
{
error (_("Error while reading in .dynamic section of the program."));
}
}
else if (dyn_tag == DT_HP_LOAD_MAP)
{
if (target_read_memory (entry_addr + offsetof(Elf64_Dyn,
d_un.d_ptr),
(char*) &dld_cache_p->load_map_addr,
sizeof (dld_cache_p->load_map_addr))
!= 0)
{
error (_("Error while reading in .dynamic section of the program."));
}
}
else
{
}
}
dld_cache_p->dyninfo_sect = dyninfo_sect;
if (dld_cache_p->dld_flags_addr != 0 && dld_cache_p->load_map_addr != 0)
dld_cache_p->is_valid = 1;
else
return 0;
return 1;
}
static CORE_ADDR
bfd_lookup_symbol (bfd *abfd, char *symname)
{
unsigned int 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);
}
return (symaddr);
}
static void
pa64_solib_create_inferior_hook (void)
{
struct minimal_symbol *msymbol;
unsigned int dld_flags, status;
asection *shlib_info, *interp_sect;
char buf[4];
struct objfile *objfile;
CORE_ADDR anaddr;
remove_solib_event_breakpoints ();
if (symfile_objfile == NULL)
return;
shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, ".dynamic");
if (!shlib_info)
return;
if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
return;
if (! read_dynamic_info (shlib_info, &dld_cache))
error (_("Unable to read the .dynamic section."));
dld_cache.dld_flags |= DT_HP_DEBUG_PRIVATE;
dld_cache.dld_flags |= DT_HP_DEBUG_CALLBACK;
status = target_write_memory (dld_cache.dld_flags_addr,
(char *) &dld_cache.dld_flags,
sizeof (dld_cache.dld_flags));
if (status != 0)
error (_("Unable to modify dynamic linker flags."));
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)
return;
if (!bfd_check_format (tmp_bfd, bfd_object))
{
warning (_("Unable to grok dynamic linker %s as an object file"), buf);
bfd_close (tmp_bfd);
return;
}
load_addr = read_pc () - tmp_bfd->start_address;
sym_addr = bfd_lookup_symbol (tmp_bfd, "__dld_break");
sym_addr = load_addr + sym_addr + 4;
{
struct breakpoint *b
= create_solib_event_breakpoint (sym_addr);
make_breakpoint_permanent (b);
}
bfd_close (tmp_bfd);
}
}
static void
pa64_special_symbol_handling (void)
{
}
static struct so_list *
pa64_current_sos (void)
{
struct so_list *head = 0;
struct so_list **link_ptr = &head;
int dll_index;
if (! dld_cache.have_read_dld_descriptor)
if (! read_dld_descriptor ())
return NULL;
if ((dld_cache.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
warning (_("The shared libraries were not privately mapped; setting a\n"
"breakpoint in a shared library will not work until you rerun "
"the program.\n"));
for (dll_index = -1; ; dll_index++)
{
struct load_module_desc dll_desc;
char *dll_path;
struct so_list *new;
struct cleanup *old_chain;
if (dll_index == 0)
continue;
if (dlgetmodinfo (dll_index, &dll_desc, sizeof (dll_desc),
pa64_target_read_memory, 0, dld_cache.load_map)
== 0)
break;
dll_path = (char *)dlgetname (&dll_desc, sizeof (dll_desc),
pa64_target_read_memory,
0, dld_cache.load_map);
new = (struct so_list *) xmalloc (sizeof (struct so_list));
memset (new, 0, sizeof (struct so_list));
new->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info));
memset (new->lm_info, 0, sizeof (struct lm_info));
strncpy (new->so_name, dll_path, SO_NAME_MAX_PATH_SIZE - 1);
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (new->so_original_name, new->so_name);
memcpy (&new->lm_info->desc, &dll_desc, sizeof (dll_desc));
#ifdef SOLIB_PA64_DBG
{
struct load_module_desc *d = &new->lm_info->desc;
printf ("\n+ library \"%s\" is described at index %d\n", new->so_name,
dll_index);
printf (" text_base = 0x%llx\n", d->text_base);
printf (" text_size = 0x%llx\n", d->text_size);
printf (" data_base = 0x%llx\n", d->data_base);
printf (" data_size = 0x%llx\n", d->data_size);
printf (" unwind_base = 0x%llx\n", d->unwind_base);
printf (" linkage_ptr = 0x%llx\n", d->linkage_ptr);
printf (" phdr_base = 0x%llx\n", d->phdr_base);
printf (" tls_size = 0x%llx\n", d->tls_size);
printf (" tls_start_addr = 0x%llx\n", d->tls_start_addr);
printf (" unwind_size = 0x%llx\n", d->unwind_size);
printf (" tls_index = 0x%llx\n", d->tls_index);
}
#endif
new->next = NULL;
*link_ptr = new;
link_ptr = &new->next;
}
return head;
}
static int
pa64_open_symbol_file_object (void *from_ttyp)
{
int from_tty = *(int *)from_ttyp;
char buf[4];
struct load_module_desc dll_desc;
char *dll_path;
if (symfile_objfile)
if (!query ("Attempt to reload symbols from process? "))
return 0;
if (! dld_cache.have_read_dld_descriptor)
if (! read_dld_descriptor ())
return 0;
if (dlgetmodinfo (0, &dll_desc, sizeof (dll_desc),
pa64_target_read_memory, 0, dld_cache.load_map) == 0)
return 0;
dll_path = (char *)dlgetname (&dll_desc, sizeof (dll_desc),
pa64_target_read_memory,
0, dld_cache.load_map);
symbol_file_add_main (dll_path, from_tty);
return 1;
}
static int
pa64_in_dynsym_resolve_code (CORE_ADDR pc)
{
asection *shlib_info;
if (symfile_objfile == NULL)
return 0;
if (!dld_cache.have_read_dld_descriptor)
if (!read_dld_descriptor ())
return 0;
return (pc >= dld_cache.dld_desc.text_base
&& pc < dld_cache.dld_desc.text_base + dld_cache.dld_desc.text_size);
}
static CORE_ADDR
pa64_solib_get_got_by_pc (CORE_ADDR addr)
{
struct so_list *so_list = master_so_list ();
CORE_ADDR got_value = 0;
while (so_list)
{
if (so_list->lm_info->desc.text_base <= addr
&& ((so_list->lm_info->desc.text_base
+ so_list->lm_info->desc.text_size)
> addr))
{
got_value = so_list->lm_info->desc.linkage_ptr;
break;
}
so_list = so_list->next;
}
return got_value;
}
static CORE_ADDR
pa64_solib_thread_start_addr (struct so_list *so)
{
return so->lm_info->desc.tls_start_addr;
}
static CORE_ADDR
pa64_solib_get_solib_by_pc (CORE_ADDR addr)
{
struct so_list *so_list = master_so_list ();
CORE_ADDR retval = 0;
while (so_list)
{
if (so_list->lm_info->desc.text_base <= addr
&& ((so_list->lm_info->desc.text_base
+ so_list->lm_info->desc.text_size)
> addr))
{
retval = so_list->lm_info->desc_addr;
break;
}
so_list = so_list->next;
}
return retval;
}
static CORE_ADDR
pa64_solib_get_text_base (struct objfile *objfile)
{
struct so_list *so;
for (so = master_so_list (); so; so = so->next)
if (so->objfile == objfile)
return so->lm_info->desc.text_base;
return 0;
}
static struct target_so_ops pa64_so_ops;
extern initialize_file_ftype _initialize_pa64_solib;
void
_initialize_pa64_solib (void)
{
pa64_so_ops.relocate_section_addresses = pa64_relocate_section_addresses;
pa64_so_ops.free_so = pa64_free_so;
pa64_so_ops.clear_solib = pa64_clear_solib;
pa64_so_ops.solib_create_inferior_hook = pa64_solib_create_inferior_hook;
pa64_so_ops.special_symbol_handling = pa64_special_symbol_handling;
pa64_so_ops.current_sos = pa64_current_sos;
pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object;
pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code;
memset (&dld_cache, 0, sizeof (dld_cache));
}
void pa64_solib_select (struct gdbarch_tdep *tdep)
{
current_target_so_ops = &pa64_so_ops;
tdep->solib_thread_start_addr = pa64_solib_thread_start_addr;
tdep->solib_get_got_by_pc = pa64_solib_get_got_by_pc;
tdep->solib_get_solib_by_pc = pa64_solib_get_solib_by_pc;
tdep->solib_get_text_base = pa64_solib_get_text_base;
}
#else
extern initialize_file_ftype _initialize_pa64_solib;
void
_initialize_pa64_solib (void)
{
}
void pa64_solib_select (struct gdbarch_tdep *tdep)
{
error (_("Cannot select pa64 solib support for this configuration."));
}
#endif