/* Handle SVR4 shared libraries for GDB, the GNU Debugger.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
- 2001, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcore.h"
#include "target.h"
#include "inferior.h"
+#include "regcache.h"
#include "gdbthread.h"
+#include "observer.h"
#include "gdb_assert.h"
}
static int
-HAS_LM_DYNAMIC_FROM_LINK_MAP ()
+HAS_LM_DYNAMIC_FROM_LINK_MAP (void)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
/* Assume that everything is a library if the dynamic loader was loaded
late by a static executable. */
- if (bfd_get_section_by_name (exec_bfd, ".dynamic") == NULL)
+ if (exec_bfd && bfd_get_section_by_name (exec_bfd, ".dynamic") == NULL)
return 0;
return extract_typed_address (so->lm_info->lm + lmo->l_prev_offset,
ptr_type) == 0;
}
-static CORE_ADDR debug_base; /* Base of dynamic linker structures */
+/* Per pspace SVR4 specific data. */
-/* Validity flag for debug_loader_offset. */
-static int debug_loader_offset_p;
+struct svr4_info
+{
+ CORE_ADDR debug_base; /* Base of dynamic linker structures */
+
+ /* Validity flag for debug_loader_offset. */
+ int debug_loader_offset_p;
+
+ /* Load address for the dynamic linker, inferred. */
+ CORE_ADDR debug_loader_offset;
+
+ /* Name of the dynamic linker, valid if debug_loader_offset_p. */
+ char *debug_loader_name;
+
+ /* Load map address for the main executable. */
+ CORE_ADDR main_lm_addr;
+
+ CORE_ADDR interp_text_sect_low;
+ CORE_ADDR interp_text_sect_high;
+ CORE_ADDR interp_plt_sect_low;
+ CORE_ADDR interp_plt_sect_high;
+};
+
+/* Per-program-space data key. */
+static const struct program_space_data *solib_svr4_pspace_data;
+
+static void
+svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
+{
+ struct svr4_info *info;
+
+ info = program_space_data (pspace, solib_svr4_pspace_data);
+ xfree (info);
+}
-/* Load address for the dynamic linker, inferred. */
-static CORE_ADDR debug_loader_offset;
+/* Get the current svr4 data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct svr4_info *
+get_svr4_info (void)
+{
+ struct svr4_info *info;
-/* Name of the dynamic linker, valid if debug_loader_offset_p. */
-static char *debug_loader_name;
+ info = program_space_data (current_program_space, solib_svr4_pspace_data);
+ if (info != NULL)
+ return info;
-/* Load map address for the main executable. */
-static CORE_ADDR main_lm_addr;
+ info = XZALLOC (struct svr4_info);
+ set_program_space_data (current_program_space, solib_svr4_pspace_data, info);
+ return info;
+}
/* Local function prototypes */
static gdb_byte *
read_program_header (int type, int *p_sect_size, int *p_arch_size)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
CORE_ADDR at_phdr, at_phent, at_phnum;
int arch_size, sect_size;
CORE_ADDR sect_addr;
(gdb_byte *)&phdr, sizeof (phdr)))
return 0;
- if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type)
+ if (extract_unsigned_integer ((gdb_byte *)phdr.p_type,
+ 4, byte_order) == type)
break;
}
return 0;
/* Retrieve address and size. */
- sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 4);
- sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 4);
+ sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,
+ 4, byte_order);
+ sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz,
+ 4, byte_order);
}
else
{
(gdb_byte *)&phdr, sizeof (phdr)))
return 0;
- if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type)
+ if (extract_unsigned_integer ((gdb_byte *)phdr.p_type,
+ 4, byte_order) == type)
break;
}
return 0;
/* Retrieve address and size. */
- sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 8);
- sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 8);
+ sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,
+ 8, byte_order);
+ sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz,
+ 8, byte_order);
}
/* Read in requested program header. */
if (abfd == NULL)
return 0;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return 0;
+
arch_size = bfd_get_arch_size (abfd);
if (arch_size == -1)
- return 0;
+ return 0;
/* Find the start address of the .dynamic section. */
sect = bfd_get_section_by_name (abfd, ".dynamic");
static int
scan_dyntag_auxv (int dyntag, CORE_ADDR *ptr)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
int sect_size, arch_size, step;
long dyn_tag;
CORE_ADDR dyn_ptr;
if (arch_size == 32)
{
Elf32_External_Dyn *dynp = (Elf32_External_Dyn *) buf;
- dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 4);
- dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 4);
+ dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag,
+ 4, byte_order);
+ dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr,
+ 4, byte_order);
}
else
{
Elf64_External_Dyn *dynp = (Elf64_External_Dyn *) buf;
- dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 8);
- dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 8);
+ dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag,
+ 8, byte_order);
+ dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr,
+ 8, byte_order);
}
if (dyn_tag == DT_NULL)
break;
SYNOPSIS
- CORE_ADDR locate_base (void)
+ CORE_ADDR locate_base (struct svr4_info *)
DESCRIPTION
*/
static CORE_ADDR
-locate_base (void)
+locate_base (struct svr4_info *info)
{
/* Check to see if we have a currently valid address, and if so, avoid
doing all this work again and just return the cached address. If
section for ELF executables. There's no point in doing any of this
though if we don't have some link map offsets to work with. */
- if (debug_base == 0 && svr4_have_link_map_offsets ())
- {
- if (exec_bfd != NULL
- && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
- debug_base = elf_locate_base ();
- }
- return (debug_base);
+ if (info->debug_base == 0 && svr4_have_link_map_offsets ())
+ info->debug_base = elf_locate_base ();
+ return info->debug_base;
}
/* Find the first element in the inferior's dynamic link map, and
RT_CONSISTENT. */
static CORE_ADDR
-solib_svr4_r_map (void)
+solib_svr4_r_map (struct svr4_info *info)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
- return read_memory_typed_address (debug_base + lmo->r_map_offset, ptr_type);
+ return read_memory_typed_address (info->debug_base + lmo->r_map_offset,
+ ptr_type);
}
/* Find r_brk from the inferior's debug base. */
static CORE_ADDR
-solib_svr4_r_brk (void)
+solib_svr4_r_brk (struct svr4_info *info)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
- return read_memory_typed_address (debug_base + lmo->r_brk_offset, ptr_type);
+ return read_memory_typed_address (info->debug_base + lmo->r_brk_offset,
+ ptr_type);
}
/* Find the link map for the dynamic linker (if it is not in the
normal list of loaded shared objects). */
static CORE_ADDR
-solib_svr4_r_ldsomap (void)
+solib_svr4_r_ldsomap (struct svr4_info *info)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
ULONGEST version;
/* Check version, and return zero if `struct r_debug' doesn't have
the r_ldsomap member. */
- version = read_memory_unsigned_integer (debug_base + lmo->r_version_offset,
- lmo->r_version_size);
+ version
+ = read_memory_unsigned_integer (info->debug_base + lmo->r_version_offset,
+ lmo->r_version_size, byte_order);
if (version < 2 || lmo->r_ldsomap_offset == -1)
return 0;
- return read_memory_typed_address (debug_base + lmo->r_ldsomap_offset,
+ return read_memory_typed_address (info->debug_base + lmo->r_ldsomap_offset,
ptr_type);
}
+/* On Solaris systems with some versions of the dynamic linker,
+ ld.so's l_name pointer points to the SONAME in the string table
+ rather than into writable memory. So that GDB can find shared
+ libraries when loading a core file generated by gcore, ensure that
+ memory areas containing the l_name string are saved in the core
+ file. */
+
+static int
+svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
+{
+ struct svr4_info *info;
+ CORE_ADDR ldsomap;
+ struct so_list *new;
+ struct cleanup *old_chain;
+ struct link_map_offsets *lmo;
+ CORE_ADDR lm_name;
+
+ info = get_svr4_info ();
+
+ info->debug_base = 0;
+ locate_base (info);
+ if (!info->debug_base)
+ return 0;
+
+ ldsomap = solib_svr4_r_ldsomap (info);
+ if (!ldsomap)
+ return 0;
+
+ lmo = svr4_fetch_link_map_offsets ();
+ new = XZALLOC (struct so_list);
+ old_chain = make_cleanup (xfree, new);
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ make_cleanup (xfree, new->lm_info);
+ new->lm_info->l_addr = (CORE_ADDR)-1;
+ new->lm_info->lm_addr = ldsomap;
+ new->lm_info->lm = xzalloc (lmo->link_map_size);
+ make_cleanup (xfree, new->lm_info->lm);
+ read_memory (ldsomap, new->lm_info->lm, lmo->link_map_size);
+ lm_name = LM_NAME (new);
+ do_cleanups (old_chain);
+
+ return (lm_name >= vaddr && lm_name < vaddr + size);
+}
+
/*
LOCAL FUNCTION
int l_name_size = TYPE_LENGTH (ptr_type);
gdb_byte *l_name_buf = xmalloc (l_name_size);
struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
+ struct svr4_info *info = get_svr4_info ();
if (symfile_objfile)
- if (!query ("Attempt to reload symbols from process? "))
+ if (!query (_("Attempt to reload symbols from process? ")))
return 0;
/* Always locate the debug struct, in case it has moved. */
- debug_base = 0;
- if (locate_base () == 0)
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
return 0; /* failed somehow... */
/* First link map member should be the executable. */
- lm = solib_svr4_r_map ();
+ lm = solib_svr4_r_map (info);
if (lm == 0)
return 0; /* failed somehow... */
static struct so_list *
svr4_default_sos (void)
{
+ struct svr4_info *info = get_svr4_info ();
+
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- if (debug_loader_offset_p)
+ if (info->debug_loader_offset_p)
{
struct so_list *new = XZALLOC (struct so_list);
/* Nothing will ever check the cached copy of the link
map if we set l_addr. */
- new->lm_info->l_addr = debug_loader_offset;
+ new->lm_info->l_addr = info->debug_loader_offset;
new->lm_info->lm_addr = 0;
new->lm_info->lm = NULL;
- strncpy (new->so_name, debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
+ strncpy (new->so_name, info->debug_loader_name,
+ SO_NAME_MAX_PATH_SIZE - 1);
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (new->so_original_name, new->so_name);
struct so_list *head = 0;
struct so_list **link_ptr = &head;
CORE_ADDR ldsomap = 0;
+ struct svr4_info *info;
+
+ info = get_svr4_info ();
/* Always locate the debug struct, in case it has moved. */
- debug_base = 0;
- locate_base ();
+ info->debug_base = 0;
+ locate_base (info);
/* If we can't find the dynamic linker's base structure, this
must not be a dynamically linked executable. Hmm. */
- if (! debug_base)
+ if (! info->debug_base)
return svr4_default_sos ();
/* Walk the inferior's link map list, and build our list of
`struct so_list' nodes. */
- lm = solib_svr4_r_map ();
+ lm = solib_svr4_r_map (info);
while (lm)
{
decide when to ignore it. */
if (IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0)
{
- main_lm_addr = new->lm_info->lm_addr;
+ info->main_lm_addr = new->lm_info->lm_addr;
free_so (new);
}
else
symbol information for the dynamic linker is quite crucial
for skipping dynamic linker resolver code. */
if (lm == 0 && ldsomap == 0)
- lm = ldsomap = solib_svr4_r_ldsomap ();
+ lm = ldsomap = solib_svr4_r_ldsomap (info);
discard_cleanups (old_chain);
}
svr4_fetch_objfile_link_map (struct objfile *objfile)
{
struct so_list *so;
+ struct svr4_info *info = get_svr4_info ();
/* Cause svr4_current_sos() to be run if it hasn't been already. */
- if (main_lm_addr == 0)
+ if (info->main_lm_addr == 0)
solib_add (NULL, 0, ¤t_target, auto_solib_add);
/* svr4_current_sos() will set main_lm_addr for the main executable. */
if (objfile == symfile_objfile)
- return main_lm_addr;
+ return info->main_lm_addr;
/* The other link map addresses may be found by examining the list
of shared libraries. */
/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
-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;
int
svr4_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)
+ struct svr4_info *info = get_svr4_info ();
+
+ return ((pc >= info->interp_text_sect_low
+ && pc < info->interp_text_sect_high)
+ || (pc >= info->interp_plt_sect_low
+ && pc < info->interp_plt_sect_high)
|| in_plt_section (pc, NULL));
}
*/
static int
-enable_break (void)
+enable_break (struct svr4_info *info, int from_tty)
{
struct minimal_symbol *msymbol;
char **bkpt_namep;
may have changed since the last time we ran the program. */
remove_solib_event_breakpoints ();
- interp_text_sect_low = interp_text_sect_high = 0;
- interp_plt_sect_low = interp_plt_sect_high = 0;
+ info->interp_text_sect_low = info->interp_text_sect_high = 0;
+ info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
mean r_brk has already been relocated. Assume the dynamic linker
is the object containing r_brk. */
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ solib_add (NULL, from_tty, ¤t_target, auto_solib_add);
sym_addr = 0;
- if (debug_base && solib_svr4_r_map () != 0)
- sym_addr = solib_svr4_r_brk ();
+ if (info->debug_base && solib_svr4_r_map (info) != 0)
+ sym_addr = solib_svr4_r_brk (info);
if (sym_addr != 0)
{
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->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);
+ info->interp_text_sect_high =
+ info->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 =
+ info->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);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (sym_addr);
+ create_solib_event_breakpoint (target_gdbarch, sym_addr);
return 1;
}
}
fallback method because it has actually been working well in
most cases. */
if (!load_addr_found)
- load_addr = (read_pc ()
- - exec_entry_point (tmp_bfd, tmp_bfd_target));
+ {
+ struct regcache *regcache
+ = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
+ load_addr = (regcache_read_pc (regcache)
+ - exec_entry_point (tmp_bfd, tmp_bfd_target));
+ }
if (!loader_found_in_list)
{
- debug_loader_name = xstrdup (interp_name);
- debug_loader_offset_p = 1;
- debug_loader_offset = load_addr;
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ info->debug_loader_name = xstrdup (interp_name);
+ info->debug_loader_offset_p = 1;
+ info->debug_loader_offset = load_addr;
+ solib_add (NULL, from_tty, ¤t_target, auto_solib_add);
}
/* Record the relocated start and end address of the dynamic linker
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->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);
+ info->interp_text_sect_high =
+ info->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 =
+ info->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);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
/* Now try to set a breakpoint in the dynamic linker. */
if (sym_addr != 0)
{
- create_solib_event_breakpoint (load_addr + sym_addr);
+ create_solib_event_breakpoint (target_gdbarch, load_addr + sym_addr);
xfree (interp_name);
return 1;
}
msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile);
if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
{
- create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol));
+ sym_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
+ sym_addr,
+ ¤t_target);
+ create_solib_event_breakpoint (target_gdbarch, sym_addr);
return 1;
}
}
msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile);
if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
{
- create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol));
+ sym_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
+ sym_addr,
+ ¤t_target);
+ create_solib_event_breakpoint (target_gdbarch, sym_addr);
return 1;
}
}
svr4_relocate_main_executable (void)
{
asection *interp_sect;
- CORE_ADDR pc = read_pc ();
+ struct regcache *regcache
+ = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
+ CORE_ADDR pc = regcache_read_pc (regcache);
/* Decide if the objfile needs to be relocated. As indicated above,
we will only be here when execution is stopped at the beginning
SYNOPSIS
- void svr4_solib_create_inferior_hook ()
+ void svr4_solib_create_inferior_hook (int from_tty)
DESCRIPTION
*/
static void
-svr4_solib_create_inferior_hook (void)
+svr4_solib_create_inferior_hook (int from_tty)
{
struct inferior *inf;
struct thread_info *tp;
+ struct svr4_info *info;
+
+ info = get_svr4_info ();
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
if (!svr4_have_link_map_offsets ())
return;
- if (!enable_break ())
+ if (!enable_break (info, from_tty))
return;
#if defined(_SCO_DS)
static void
svr4_clear_solib (void)
{
- debug_base = 0;
- debug_loader_offset_p = 0;
- debug_loader_offset = 0;
- xfree (debug_loader_name);
- debug_loader_name = NULL;
- main_lm_addr = 0;
+ struct svr4_info *info;
+
+ info = get_svr4_info ();
+ info->debug_base = 0;
+ info->debug_loader_offset_p = 0;
+ info->debug_loader_offset = 0;
+ xfree (info->debug_loader_name);
+ info->debug_loader_name = NULL;
}
static void
static void
svr4_relocate_section_addresses (struct so_list *so,
- struct section_table *sec)
+ struct target_section *sec)
{
sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so,
sec->bfd));
_initialize_svr4_solib (void)
{
solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init);
+ solib_svr4_pspace_data
+ = register_program_space_data_with_cleanup (svr4_pspace_data_cleanup);
svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
svr4_so_ops.free_so = svr4_free_so;
svr4_so_ops.current_sos = svr4_current_sos;
svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
+ svr4_so_ops.bfd_open = solib_bfd_open;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
+ svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
}