/* Handle PA64 shared libraries for GDB, the GNU Debugger.
- Copyright 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2007-2012 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
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.
-
- HP in their infinite stupidity choose not to use standard ELF dynamic
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* HP in their infinite stupidity choose not to use standard ELF dynamic
linker interfaces. They also choose not to make their ELF dymamic
linker interfaces compatible with the SOM dynamic linker. The
net result is we can not use either of the existing somsolib.c or
same functionality in all their libraries! */
#include "defs.h"
-#include <dlfcn.h>
-#include <elf.h>
-#include <elf_hp.h>
#include "symtab.h"
#include "bfd.h"
#include "symfile.h"
#include "gdbcore.h"
#include "target.h"
#include "inferior.h"
+#include "regcache.h"
#include "hppa-tdep.h"
#include "solist.h"
+#include "solib.h"
#include "solib-pa64.h"
#undef SOLIB_PA64_DBG
-/* If we are building for a SOM-only target, then we don't need this. */
-#ifndef PA_SOM_ONLY
+/* We can build this file only when running natively on 64-bit HP/UX.
+ We check for that by checking for the elf_hp.h header file. */
+#if defined(HAVE_ELF_HP_H) && defined(__LP64__)
+
+/* FIXME: kettenis/20041213: These includes should be eliminated. */
+#include <dlfcn.h>
+#include <elf.h>
+#include <elf_hp.h>
struct lm_info {
struct load_module_desc desc;
CORE_ADDR desc_addr;
};
-/* When adding fields, be sure to clear them in _initialize_pa64_solib. */
+/* When adding fields, be sure to clear them in _initialize_pa64_solib. */
typedef struct
{
CORE_ADDR dld_flags_addr;
static dld_cache_t dld_cache;
-static int
-read_dynamic_info (asection *dyninfo_sect, dld_cache_t *dld_cache_p);
+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)
+ struct target_section *sec)
{
+ asection *asec = sec->the_bfd_section;
+ CORE_ADDR load_offset;
+
+ /* Relocate all the sections based on where they got loaded. */
+
+ 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
This must happen after dld starts running, so we can't do it in
read_dynamic_info. Record the fact that we have loaded the
- descriptor. If the library is archive bound, then return zero, else
- return nonzero. */
+ descriptor. If the library is archive bound or the load map
+ hasn't been setup, then return zero; else return nonzero. */
static int
read_dld_descriptor (void)
if (!dld_cache.is_valid)
{
if (symfile_objfile == NULL)
- error ("No object file symbols.");
+ error (_("No object file symbols."));
dyninfo_sect = bfd_get_section_by_name (symfile_objfile->obfd,
".dynamic");
}
if (!read_dynamic_info (dyninfo_sect, &dld_cache))
- error ("Unable to read in .dynamic section information.");
+ error (_("Unable to read in .dynamic section information."));
}
/* Read the load map pointer. */
sizeof (dld_cache.load_map))
!= 0)
{
- error ("Error while reading in load map pointer.");
+ error (_("Error while reading in load map pointer."));
}
- /* Read in the dld load module descriptor */
+ if (!dld_cache.load_map)
+ return 0;
+
+ /* Read in the dld load module descriptor. */
if (dlgetmodinfo (-1,
&dld_cache.dld_desc,
sizeof (dld_cache.dld_desc),
dld_cache.load_map)
== 0)
{
- error ("Error trying to get information about dynamic linker.");
+ error (_("Error trying to get information about dynamic linker."));
}
/* Indicate that we have loaded the dld descriptor. */
return 0;
/* Scan the .dynamic section and record the items of interest.
- In particular, DT_HP_DLD_FLAGS */
+ In particular, DT_HP_DLD_FLAGS. */
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);
break;
else if (dyn_tag == DT_HP_DLD_FLAGS)
{
- /* Set dld_flags_addr and dld_flags in *dld_cache_p */
+ /* Set dld_flags_addr and dld_flags in *dld_cache_p. */
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.");
+ error (_("Error while reading in "
+ ".dynamic section of the program."));
}
}
else if (dyn_tag == DT_HP_LOAD_MAP)
sizeof (dld_cache_p->load_map_addr))
!= 0)
{
- error ("Error while reading in .dynamic section of the program.");
+ error (_("Error while reading in "
+ ".dynamic section of the program."));
}
}
else
{
- /* tag is not of interest */
+ /* Tag is not of interest. */
}
}
- /* Record other information and set is_valid to 1. */
+ /* Record other information and set is_valid to 1. */
dld_cache_p->dyninfo_sect = dyninfo_sect;
/* Verify that we read in required info. These fields are re-set to zero
return 1;
}
-/*
- bfd_lookup_symbol -- lookup the value for a specific symbol
-
- An expensive way to lookup the value of a single symbol for
- bfd's that are only temporary anyway. This is used by the
- shared library support to find the address of the debugger
- interface structures in the shared library.
-
- Note that 0 is specifically allowed as an error return (no
- such symbol).
- */
+/* Helper function for gdb_bfd_lookup_symbol_from_symtab. */
-static CORE_ADDR
-bfd_lookup_symbol (bfd *abfd, char *symname)
+static int
+cmp_name (asymbol *sym, void *data)
{
- 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)
- {
- /* Bfd symbols are section relative. */
- symaddr = sym->value + sym->section->vma;
- break;
- }
- }
- do_cleanups (back_to);
- }
- return (symaddr);
+ return (strcmp (sym->name, (const char *) data) == 0);
}
-
/* This hook gets called just before the first instruction in the
inferior process is executed.
to tell the dynamic linker that a private copy of the library is
needed (so GDB can set breakpoints in the library).
- We need to set two flag bits in this routine.
-
- DT_HP_DEBUG_PRIVATE to indicate that shared libraries should be
- mapped private.
-
- DT_HP_DEBUG_CALLBACK to indicate that we want the dynamic linker to
- call the breakpoint routine for significant events. */
+ We need to set DT_HP_DEBUG_CALLBACK to indicate that we want the
+ dynamic linker to call the breakpoint routine for significant events.
+ We used to set DT_HP_DEBUG_PRIVATE to indicate that shared libraries
+ should be mapped private. However, this flag can be set using
+ "chatr +dbg enable". Not setting DT_HP_DEBUG_PRIVATE allows debugging
+ with shared libraries mapped shareable. */
static void
-pa64_solib_create_inferior_hook (void)
+pa64_solib_create_inferior_hook (int from_tty)
{
struct minimal_symbol *msymbol;
unsigned int dld_flags, status;
struct objfile *objfile;
CORE_ADDR anaddr;
- /* First, remove all the solib event breakpoints. Their addresses
- may have changed since the last time we ran the program. */
- remove_solib_event_breakpoints ();
-
if (symfile_objfile == NULL)
return;
/* Read in the .dynamic section. */
if (! read_dynamic_info (shlib_info, &dld_cache))
- error ("Unable to read the .dynamic section.");
+ error (_("Unable to read the .dynamic section."));
+
+ /* If the libraries were not mapped private, warn the user. */
+ if ((dld_cache.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
+ warning
+ (_("\
+Private mapping of shared library text was not specified\n\
+by the executable; setting a breakpoint in a shared library which\n\
+is not privately mapped will not work. See the HP-UX 11i v3 chatr\n\
+manpage for methods to privately map shared library text."));
/* Turn on the flags we care about. */
- 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.");
+ error (_("Unable to modify dynamic linker flags."));
/* Now we have to create a shared library breakpoint in the dynamic
linker. This can be somewhat tricky since the symbol is inside
to find any magic formula to find it for Solaris (appears to
be trivial on GNU/Linux). Therefore, we have to try an alternate
mechanism to find the dynamic linker's base address. */
- tmp_bfd = bfd_openr (buf, gnutarget);
+ tmp_bfd = gdb_bfd_openr (buf, gnutarget);
if (tmp_bfd == NULL)
return;
/* 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);
- bfd_close (tmp_bfd);
+ warning (_("Unable to grok dynamic linker %s as an object file"),
+ buf);
+ gdb_bfd_unref (tmp_bfd);
return;
}
/* We find the dynamic linker's base address by examining the
current pc (which point at the entry point for the dynamic
- linker) and subtracting the offset of the entry point.
+ linker) and subtracting the offset of the entry point.
Also note the breakpoint is the second instruction in the
routine. */
- load_addr = read_pc () - tmp_bfd->start_address;
- sym_addr = bfd_lookup_symbol (tmp_bfd, "__dld_break");
+ load_addr = regcache_read_pc (get_current_regcache ())
+ - tmp_bfd->start_address;
+ sym_addr = gdb_bfd_lookup_symbol_from_symtab (tmp_bfd, cmp_name,
+ "__dld_break");
sym_addr = load_addr + sym_addr + 4;
/* Create the shared library breakpoint. */
{
struct breakpoint *b
- = create_solib_event_breakpoint (sym_addr);
+ = create_solib_event_breakpoint (target_gdbarch, sym_addr);
/* The breakpoint is actually hard-coded into the dynamic linker,
so we don't need to actually insert a breakpoint instruction
}
/* We're done with the temporary bfd. */
- bfd_close (tmp_bfd);
+ gdb_bfd_unref (tmp_bfd);
}
}
if (! read_dld_descriptor ())
return NULL;
- /* If the libraries were not mapped private, warn the user. */
- 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++)
+ 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;
+
/* Read in the load module descriptor. */
if (dlgetmodinfo (dll_index, &dll_desc, sizeof (dll_desc),
pa64_target_read_memory, 0, dld_cache.load_map)
pa64_target_read_memory,
0, dld_cache.load_map);
- if (dll_path == NULL)
- dll_path = "";
-
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));
#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);
+ printf (" text_base = %s\n", hex_string (d->text_base));
+ printf (" text_size = %s\n", hex_string (d->text_size));
+ printf (" data_base = %s\n", hex_string (d->data_base));
+ printf (" data_size = %s\n", hex_string (d->data_size));
+ printf (" unwind_base = %s\n", hex_string (d->unwind_base));
+ printf (" linkage_ptr = %s\n", hex_string (d->linkage_ptr));
+ printf (" phdr_base = %s\n", hex_string (d->phdr_base));
+ printf (" tls_size = %s\n", hex_string (d->tls_size));
+ printf (" tls_start_addr = %s\n", hex_string (d->tls_start_addr));
+ printf (" unwind_size = %s\n", hex_string (d->unwind_size));
+ printf (" tls_index = %s\n", hex_string (d->tls_index));
}
#endif
char *dll_path;
if (symfile_objfile)
- if (!query ("Attempt to reload symbols from process? "))
+ if (!query (_("Attempt to reload symbols from process? ")))
return 0;
/* Read in the load map pointer if we have not done so already. */
&& ((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;
+ break;
}
so_list = so_list->next;
}
/* Return the address of the handle of the shared library in which ADDR
- belongs. If ADDR isn't in any known shared library, return zero.
-
- This function is used in hppa_fix_call_dummy in hppa-tdep.c. */
+ belongs. If ADDR isn't in any known shared library, return zero. */
static CORE_ADDR
pa64_solib_get_solib_by_pc (CORE_ADDR addr)
return retval;
}
+/* pa64 libraries do not seem to set the section offsets in a standard (i.e.
+ SVr4) way; the text section offset stored in the file doesn't correspond
+ to the place where the library is actually loaded into memory. Instead,
+ we rely on the dll descriptor to tell us where things were loaded. */
+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; /* -Wmissing-prototypes */
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;
+ pa64_so_ops.bfd_open = solib_bfd_open;
memset (&dld_cache, 0, sizeof (dld_cache));
}
-void pa64_solib_select (struct gdbarch_tdep *tdep)
+void pa64_solib_select (struct gdbarch *gdbarch)
{
- current_target_so_ops = &pa64_so_ops;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ set_solib_ops (gdbarch, &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 /* PA_SOM_ONLY */
+#else /* HAVE_ELF_HP_H */
extern initialize_file_ftype _initialize_pa64_solib; /* -Wmissing-prototypes */
{
}
-void pa64_solib_select (struct gdbarch_tdep *tdep)
+void pa64_solib_select (struct gdbarch *gdbarch)
{
/* For a SOM-only target, there is no pa64 solib support. This is needed
for hppa-hpux-tdep.c to build. */
- error ("Cannot select pa64 solib support for this configuration.\n");
+ error (_("Cannot select pa64 solib support for this configuration."));
}
#endif