/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger.
- Copyright 1990, 91, 92, 93, 94, 95, 96, 98, 1999, 2000
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+ 2001
Free Software Foundation, Inc.
This file is part of GDB.
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#define _SYSCALL32 /* for Sparc64 cross Sparc32 */
#include "defs.h"
+#include "regcache.h"
#include <sys/types.h>
#ifndef SVR4_SHARED_LIBS
/* SunOS shared libs need the nlist structure. */
#include <a.out.h>
+#include <link.h>
#else
#include "elf/external.h"
-#endif
-
-#ifdef HAVE_LINK_H
-#include <link.h>
+#include "elf/common.h"
#endif
#include "symtab.h"
#include "solist.h"
#include "solib-svr4.h"
+#ifndef SVR4_FETCH_LINK_MAP_OFFSETS
+#define SVR4_FETCH_LINK_MAP_OFFSETS() fetch_link_map_offsets ()
+#endif
+
+static struct link_map_offsets *default_svr4_fetch_link_map_offsets (void);
+static struct link_map_offsets *(*fetch_link_map_offsets)(void) =
+ default_svr4_fetch_link_map_offsets;
+
+/* legacy_svr4_fetch_link_map_offsets_hook is a pointer to a function
+ which is used to fetch link map offsets. It will only be set
+ by solib-legacy.c, if at all. */
+struct link_map_offsets *(*legacy_svr4_fetch_link_map_offsets_hook)(void) = 0;
+
/* Link map info to include in an allocated so_list entry */
struct lm_info
"_r_debug_state",
"_dl_debug_state",
"rtld_db_dlactivity",
+ "_rtld_debug_state",
NULL
};
#endif
/* Fetch (and possibly build) an appropriate link_map_offsets structure
- for native targets using struct definitions from link.h. */
-
-struct link_map_offsets *
+ for native targets using struct definitions from link.h.
+
+ Note: For non-native targets (i.e. cross-debugging situations),
+ you need to define a target specific fetch_link_map_offsets()
+ function and call set_solib_svr4_fetch_link_map_offsets () to
+ register this function. */
+
+static struct link_map_offsets *
default_svr4_fetch_link_map_offsets (void)
{
-#ifdef HAVE_LINK_H
- static struct link_map_offsets lmo;
- static struct link_map_offsets *lmp = 0;
-#if defined (HAVE_STRUCT_LINK_MAP32)
- static struct link_map_offsets lmo32;
- static struct link_map_offsets *lmp32 = 0;
-#endif
-
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
-#endif
-#define fieldsize(TYPE, MEMBER) (sizeof (((TYPE *)0)->MEMBER))
-
- if (lmp == 0)
- {
- lmp = &lmo;
-
-#ifdef SVR4_SHARED_LIBS
- lmo.r_debug_size = sizeof (struct r_debug);
-
- lmo.r_map_offset = offsetof (struct r_debug, r_map);
- lmo.r_map_size = fieldsize (struct r_debug, r_map);
-
- lmo.link_map_size = sizeof (struct link_map);
-
- lmo.l_addr_offset = offsetof (struct link_map, l_addr);
- lmo.l_addr_size = fieldsize (struct link_map, l_addr);
-
- lmo.l_next_offset = offsetof (struct link_map, l_next);
- lmo.l_next_size = fieldsize (struct link_map, l_next);
-
- lmo.l_prev_offset = offsetof (struct link_map, l_prev);
- lmo.l_prev_size = fieldsize (struct link_map, l_prev);
-
- lmo.l_name_offset = offsetof (struct link_map, l_name);
- lmo.l_name_size = fieldsize (struct link_map, l_name);
-#else /* !SVR4_SHARED_LIBS */
- lmo.link_map_size = sizeof (struct link_map);
-
- lmo.l_addr_offset = offsetof (struct link_map, lm_addr);
- lmo.l_addr_size = fieldsize (struct link_map, lm_addr);
-
- lmo.l_next_offset = offsetof (struct link_map, lm_next);
- lmo.l_next_size = fieldsize (struct link_map, lm_next);
-
- lmo.l_name_offset = offsetof (struct link_map, lm_name);
- lmo.l_name_size = fieldsize (struct link_map, lm_name);
-#endif /* SVR4_SHARED_LIBS */
- }
-
-#if defined (HAVE_STRUCT_LINK_MAP32)
- if (lmp32 == 0)
+ if (legacy_svr4_fetch_link_map_offsets_hook)
+ return legacy_svr4_fetch_link_map_offsets_hook ();
+ else
{
- lmp32 = &lmo32;
-
- lmo32.r_debug_size = sizeof (struct r_debug32);
-
- lmo32.r_map_offset = offsetof (struct r_debug32, r_map);
- lmo32.r_map_size = fieldsize (struct r_debug32, r_map);
-
- lmo32.link_map_size = sizeof (struct link_map32);
-
- lmo32.l_addr_offset = offsetof (struct link_map32, l_addr);
- lmo32.l_addr_size = fieldsize (struct link_map32, l_addr);
-
- lmo32.l_next_offset = offsetof (struct link_map32, l_next);
- lmo32.l_next_size = fieldsize (struct link_map32, l_next);
-
- lmo32.l_prev_offset = offsetof (struct link_map32, l_prev);
- lmo32.l_prev_size = fieldsize (struct link_map32, l_prev);
-
- lmo32.l_name_offset = offsetof (struct link_map32, l_name);
- lmo32.l_name_size = fieldsize (struct link_map32, l_name);
+ internal_error (__FILE__, __LINE__,
+"default_svr4_fetch_link_map_offsets called without legacy link_map support enabled.");
+ return 0;
}
-#endif /* defined (HAVE_STRUCT_LINK_MAP32) */
-
-#if defined (HAVE_STRUCT_LINK_MAP32)
- if (bfd_get_arch_size (exec_bfd) == 32)
- return lmp32;
- else
-#endif
- return lmp;
-
-#else
-
- internal_error ("default_svr4_fetch_link_map_offsets called without HAVE_LINK_H defined.");
- return 0;
-
-#endif /* HAVE_LINK_H */
}
/* Macro to extract an address from a solib structure.
{
struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
- return extract_address (so->lm_info->lm + lmo->l_addr_offset, lmo->l_addr_size);
+ return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lmo->l_addr_offset,
+ lmo->l_addr_size);
}
static CORE_ADDR
#endif /* !SVR4_SHARED_LIBS */
-
static CORE_ADDR debug_base; /* Base of dynamic linker structures */
static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
static int match_main (char *);
-/* If non-zero, this is a prefix that will be added to the front of the name
- shared libraries with an absolute filename for loading. */
-static char *solib_absolute_prefix = NULL;
-
-/* If non-empty, this is a search path for loading non-absolute shared library
- symbol files. This takes precedence over the environment variables PATH
- and LD_LIBRARY_PATH. */
-static char *solib_search_path = NULL;
-
-
#ifndef SVR4_SHARED_LIBS
/* Allocate the runtime common object file. */
memset (objfile, 0, sizeof (struct objfile));
objfile->md = NULL;
obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0,
- xmalloc, free);
+ xmalloc, xfree);
obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc,
- free);
+ xfree);
obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc,
- free);
+ xfree);
obstack_specify_allocation (&objfile->type_obstack, 0, 0, xmalloc,
- free);
+ xfree);
objfile->name = mstrsave (objfile->md, "rt_common");
/* Add this file onto the tail of the linked list of other such files. */
{
obstack_free (&rt_common_objfile->symbol_obstack, 0);
obstack_specify_allocation (&rt_common_objfile->symbol_obstack, 0, 0,
- xmalloc, free);
+ xmalloc, xfree);
rt_common_objfile->minimal_symbol_count = 0;
rt_common_objfile->msymbols = NULL;
}
prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value,
mst_bss, rt_common_objfile);
- free (name);
+ xfree (name);
}
rtc_symp = SOLIB_EXTRACT_ADDRESS (inferior_rtc_symb.rtc_next);
}
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
- back_to = make_cleanup (free, (PTR) symbol_table);
+ back_to = make_cleanup (xfree, (PTR) symbol_table);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
- back_to = make_cleanup (free, (PTR) symbol_table);
+ back_to = make_cleanup (xfree, (PTR) symbol_table);
number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
#else /* SVR4_SHARED_LIBS */
struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
char *r_map_buf = xmalloc (lmo->r_map_size);
- struct cleanup *cleanups = make_cleanup (free, r_map_buf);
+ struct cleanup *cleanups = make_cleanup (xfree, r_map_buf);
read_memory (debug_base + lmo->r_map_offset, r_map_buf, lmo->r_map_size);
int from_tty = *(int *)from_ttyp;
struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
char *l_name_buf = xmalloc (lmo->l_name_size);
- struct cleanup *cleanups = make_cleanup (free, l_name_buf);
+ struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
if (symfile_objfile)
if (!query ("Attempt to reload symbols from process? "))
return 0;
}
- make_cleanup (free, filename);
+ make_cleanup (xfree, filename);
/* Have a pathname: read the symbol file. */
- symbol_file_command (filename, from_tty);
+ symbol_file_add_main (filename, from_tty);
return 1;
}
#else
static int
-open_symbol_file_object (int *from_ttyp)
+open_symbol_file_object (void *from_ttyp)
{
return 1;
}
struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
struct so_list *new
= (struct so_list *) xmalloc (sizeof (struct so_list));
- struct cleanup *old_chain = make_cleanup (free, new);
+ struct cleanup *old_chain = make_cleanup (xfree, new);
memset (new, 0, sizeof (*new));
new->lm_info = xmalloc (sizeof (struct lm_info));
- make_cleanup (free, new->lm_info);
+ make_cleanup (xfree, new->lm_info);
new->lm_info->lm = xmalloc (lmo->link_map_size);
- make_cleanup (free, new->lm_info->lm);
+ make_cleanup (xfree, new->lm_info->lm);
memset (new->lm_info->lm, 0, lmo->link_map_size);
read_memory (lm, new->lm_info->lm, lmo->link_map_size);
{
strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
- free (buffer);
+ xfree (buffer);
strcpy (new->so_original_name, new->so_name);
}
}
-#ifdef SVR4_SHARED_LIBS
-
/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
-
+#ifdef SVR4_SHARED_LIBS
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
-in_svr4_dynsym_resolve_code (CORE_ADDR pc)
+static 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)
|| in_plt_section (pc, NULL));
}
-#endif
+#else /* !SVR4_SHARED_LIBS */
+static int
+svr4_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ return 0;
+}
+#endif /* SVR4_SHARED_LIBS */
/*
unsigned int interp_sect_size;
char *buf;
CORE_ADDR load_addr;
- bfd *tmp_bfd;
+ bfd *tmp_bfd = NULL;
+ int tmp_fd = -1;
+ char *tmp_pathname = NULL;
CORE_ADDR sym_addr = 0;
/* Read the contents of the .interp section into a local buffer;
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_fd = solib_open (buf, &tmp_pathname);
+ if (tmp_fd >= 0)
+ tmp_bfd = bfd_fdopenr (tmp_pathname, gnutarget, tmp_fd);
+
if (tmp_bfd == NULL)
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_svr4_dynsym_resolve_code. */
+ text and plt section for svr4_in_dynsym_resolve_code. */
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
#endif /* !SVR4_SHARED_LIBS */
}
+/* Relocate the main executable. This function should be called upon
+ stopping the inferior process at the entry point to the program.
+ The entry point from BFD is compared to the PC and if they are
+ different, the main executable is relocated by the proper amount.
+
+ As written it will only attempt to relocate executables which
+ lack interpreter sections. It seems likely that only dynamic
+ linker executables will get relocated, though it should work
+ properly for a position-independent static executable as well. */
+
+static void
+svr4_relocate_main_executable (void)
+{
+ asection *interp_sect;
+ CORE_ADDR pc = read_pc ();
+
+ /* Decide if the objfile needs to be relocated. As indicated above,
+ we will only be here when execution is stopped at the beginning
+ of the program. Relocation is necessary if the address at which
+ we are presently stopped differs from the start address stored in
+ the executable AND there's no interpreter section. The condition
+ regarding the interpreter section is very important because if
+ there *is* an interpreter section, execution will begin there
+ instead. When there is an interpreter section, the start address
+ is (presumably) used by the interpreter at some point to start
+ execution of the program.
+
+ If there is an interpreter, it is normal for it to be set to an
+ arbitrary address at the outset. The job of finding it is
+ handled in enable_break().
+
+ So, to summarize, relocations are necessary when there is no
+ interpreter section and the start address obtained from the
+ executable is different from the address at which GDB is
+ currently stopped.
+
+ [ The astute reader will note that we also test to make sure that
+ the executable in question has the DYNAMIC flag set. It is my
+ opinion that this test is unnecessary (undesirable even). It
+ was added to avoid inadvertent relocation of an executable
+ whose e_type member in the ELF header is not ET_DYN. There may
+ be a time in the future when it is desirable to do relocations
+ on other types of files as well in which case this condition
+ should either be removed or modified to accomodate the new file
+ type. (E.g, an ET_EXEC executable which has been built to be
+ position-independent could safely be relocated by the OS if
+ desired. It is true that this violates the ABI, but the ABI
+ has been known to be bent from time to time.) - Kevin, Nov 2000. ]
+ */
+
+ interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+ if (interp_sect == NULL
+ && (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
+ && bfd_get_start_address (exec_bfd) != pc)
+ {
+ struct cleanup *old_chain;
+ struct section_offsets *new_offsets;
+ int i, changed;
+ CORE_ADDR displacement;
+
+ /* It is necessary to relocate the objfile. The amount to
+ relocate by is simply the address at which we are stopped
+ minus the starting address from the executable.
+
+ We relocate all of the sections by the same amount. This
+ behavior is mandated by recent editions of the System V ABI.
+ According to the System V Application Binary Interface,
+ Edition 4.1, page 5-5:
+
+ ... Though the system chooses virtual addresses for
+ individual processes, it maintains the segments' relative
+ positions. Because position-independent code uses relative
+ addressesing between segments, the difference between
+ virtual addresses in memory must match the difference
+ between virtual addresses in the file. The difference
+ between the virtual address of any segment in memory and
+ the corresponding virtual address in the file is thus a
+ single constant value for any one executable or shared
+ object in a given process. This difference is the base
+ address. One use of the base address is to relocate the
+ memory image of the program during dynamic linking.
+
+ The same language also appears in Edition 4.0 of the System V
+ ABI and is left unspecified in some of the earlier editions. */
+
+ displacement = pc - bfd_get_start_address (exec_bfd);
+ changed = 0;
+
+ new_offsets = xcalloc (sizeof (struct section_offsets),
+ symfile_objfile->num_sections);
+ old_chain = make_cleanup (xfree, new_offsets);
+
+ for (i = 0; i < symfile_objfile->num_sections; i++)
+ {
+ if (displacement != ANOFFSET (symfile_objfile->section_offsets, i))
+ changed = 1;
+ new_offsets->offsets[i] = displacement;
+ }
+
+ if (changed)
+ objfile_relocate (symfile_objfile, new_offsets);
+
+ do_cleanups (old_chain);
+ }
+}
+
/*
GLOBAL FUNCTION
Also, what if child has exit()ed? Must exit loop somehow.
*/
-void
+static void
svr4_solib_create_inferior_hook (void)
{
+ /* Relocate the main executable if necessary. */
+ svr4_relocate_main_executable ();
+
/* If we are using the BKPT_AT_SYMBOL code, then we don't need the base
yet. In fact, in the case of a SunOS4 executable being run on
Solaris, we can't get it yet. current_sos will get it when it needs
static void
svr4_free_so (struct so_list *so)
{
- free (so->lm_info->lm);
- free (so->lm_info);
+ xfree (so->lm_info->lm);
+ xfree (so->lm_info);
+}
+
+static void
+svr4_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ sec->addr += LM_ADDR (so);
+ sec->endaddr += LM_ADDR (so);
+}
+
+void
+set_solib_svr4_fetch_link_map_offsets (struct link_map_offsets *(*flmo) (void))
+{
+ fetch_link_map_offsets = flmo;
+}
+
+static void
+init_fetch_link_map_offsets (void)
+{
+ set_solib_svr4_fetch_link_map_offsets (default_svr4_fetch_link_map_offsets);
}
static struct target_so_ops svr4_so_ops;
void
_initialize_svr4_solib (void)
{
- svr4_so_ops.lm_addr = LM_ADDR;
+ register_gdbarch_swap (&fetch_link_map_offsets,
+ sizeof (fetch_link_map_offsets),
+ init_fetch_link_map_offsets);
+
+ svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
svr4_so_ops.free_so = svr4_free_so;
svr4_so_ops.clear_solib = svr4_clear_solib;
svr4_so_ops.solib_create_inferior_hook = svr4_solib_create_inferior_hook;
svr4_so_ops.special_symbol_handling = svr4_special_symbol_handling;
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;
/* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */
current_target_so_ops = &svr4_so_ops;