diff options
author | Fred Fish <fnf@specifix.com> | 1991-12-16 20:57:28 +0000 |
---|---|---|
committer | Fred Fish <fnf@specifix.com> | 1991-12-16 20:57:28 +0000 |
commit | f8b76e70b7a1cb376bc4ac8ac071fff5c7cf6acd (patch) | |
tree | bfb5400a70021ef29b9b687b2b44bb926ed51c47 /gdb/solib.c | |
parent | 01d4cbef85c08a2f983cd4f83f4bbadc9f4ed320 (diff) | |
download | gdb-f8b76e70b7a1cb376bc4ac8ac071fff5c7cf6acd.zip gdb-f8b76e70b7a1cb376bc4ac8ac071fff5c7cf6acd.tar.gz gdb-f8b76e70b7a1cb376bc4ac8ac071fff5c7cf6acd.tar.bz2 |
Numerous small changes and a complete reorganization of solib.c, to support
SVR4 shared libraries in a manner very close to the original SunOS support.
See the ChangeLog for details.
Diffstat (limited to 'gdb/solib.c')
-rw-r--r-- | gdb/solib.c | 1275 |
1 files changed, 952 insertions, 323 deletions
diff --git a/gdb/solib.c b/gdb/solib.c index 6995e50..b1c78a4 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1990 Free Software Foundation, Inc. - +/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. + Copyright 1990, 1991 Free Software Foundation, Inc. + This file is part of GDB. This program is free software; you can redistribute it and/or modify @@ -16,17 +17,16 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* -** symbol definitions -*/ + #include <sys/types.h> +#include <signal.h> #include <string.h> #include <link.h> #include <sys/param.h> #include <fcntl.h> #include <stdio.h> + #include "defs.h" -#include "param.h" #include "symtab.h" #include "gdbcore.h" #include "command.h" @@ -35,183 +35,510 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "regex.h" #include "inferior.h" -extern char *getenv(); +extern char *getenv (); +extern char *elf_interpreter (); /* Interpreter name from exec file */ +extern char *re_comp (); + +#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */ + +/* On SVR4 systems, for the initial implementation, use main() as the + "startup mapping complete" breakpoint address. The models for SunOS + and SVR4 dynamic linking debugger support are different in that SunOS + hits one breakpoint when all mapping is complete while using the SVR4 + debugger support takes two breakpoint hits for each file mapped, and + there is no way to know when the "last" one is hit. Both these + mechanisms should be tied to a "breakpoint service routine" that + gets automatically executed whenever one of the breakpoints indicating + a change in mapping is hit. This is a future enhancement. (FIXME) */ + +#define BKPT_AT_MAIN 1 + +/* local data declarations */ + +#ifdef sun + +#define DEBUG_BASE "_DYNAMIC" +#define LM_ADDR(so) ((so) -> lm.lm_addr) +#define LM_NEXT(so) ((so) -> lm.lm_next) +#define LM_NAME(so) ((so) -> lm.lm_name) +static struct link_dynamic dynamic_copy; +static struct link_dynamic_2 ld_2_copy; +static struct ld_debug debug_copy; +static CORE_ADDR debug_addr; +static CORE_ADDR flag_addr; + +#else /* !sun */ + +#define DEBUG_BASE "_r_debug" +#define LM_ADDR(so) ((so) -> lm.l_addr) +#define LM_NEXT(so) ((so) -> lm.l_next) +#define LM_NAME(so) ((so) -> lm.l_name) +static struct r_debug debug_copy; +static CORE_ADDR shlib_base; /* Base address of shared library */ +char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ +extern CORE_ADDR proc_base_address (); +extern int proc_address_to_fd (); + +#endif /* sun */ -/* -** local data declarations -*/ -#define MAX_PATH_SIZE 256 struct so_list { - struct link_map inferior_lm; /* inferior link map */ - struct link_map *inferior_lm_add; - long ld_text; - char inferior_so_name[MAX_PATH_SIZE]; /* Shared Object Library Name */ - struct so_list *next; /* Next Structure */ - char symbols_loaded; /* Flag: loaded? */ - char from_tty; /* Flag: print msgs? */ - bfd *so_bfd; - struct section_table *sections; - struct section_table *sections_end; + struct so_list *next; /* next structure in linked list */ + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + bfd *so_bfd; /* bfd for so_name */ + struct section_table *sections; + struct section_table *sections_end; }; -static struct so_list *so_list_head = 0; +static struct so_list *so_list_head; /* List of known shared objects */ +static CORE_ADDR debug_base; /* Base of dynamic linker structures */ +static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ + /* -** Build a section map for a shared library, record its text size in -** the so_list structure and set up the text section of the shared lib. -*/ + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + static void -solib_map_sections(so) -struct so_list *so; +solib_map_sections (so) + struct so_list *so; { char *filename; char *scratch_pathname; int scratch_chan; struct section_table *p; - filename = tilde_expand (so->inferior_so_name); + filename = tilde_expand (so -> so_name); make_cleanup (free, filename); scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, - &scratch_pathname); + &scratch_pathname); if (scratch_chan < 0) - scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, O_RDONLY, 0, - &scratch_pathname); + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } if (scratch_chan < 0) - perror_with_name (filename); - - so->so_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan); - if (!so->so_bfd) - error ("Could not open `%s' as an executable file: %s", - scratch_pathname, bfd_errmsg (bfd_error)); - if (!bfd_check_format (so->so_bfd, bfd_object)) - error ("\"%s\": not in executable format: %s.", - scratch_pathname, bfd_errmsg (bfd_error)); - if (build_section_table (so->so_bfd, &so->sections, &so->sections_end)) - error ("Can't find the file sections in `%s': %s", - exec_bfd->filename, bfd_errmsg (bfd_error)); - - for (p = so->sections; p < so->sections_end; p++) - { - if (strcmp (bfd_section_name (so->so_bfd, p->sec_ptr), ".text") == 0) + { + perror_with_name (filename); + } + + so -> so_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan); + if (!so -> so_bfd) + { + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_error)); + } + if (!bfd_check_format (so -> so_bfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_error)); + } + if (build_section_table (so -> so_bfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + exec_bfd -> filename, bfd_errmsg (bfd_error)); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the base address to which the object was actually + mapped. */ + p -> addr += (CORE_ADDR) LM_ADDR (so); + p -> endaddr += (CORE_ADDR) LM_ADDR (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + } +} + +/* + +LOCAL FUNCTION + + bfd_lookup_symbol -- lookup the value for a specific symbol + +SYNOPSIS + + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) + +DESCRIPTION + + 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). + + FIXME: See if there is a less "expensive" way of doing this. + Also see if there is already another bfd or gdb function + that specifically does this, and if so, use it. +*/ + +static CORE_ADDR +DEFUN (bfd_lookup_symbol, (abfd, symname), + bfd *abfd AND + 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; + enum misc_function_type mf_type; + + storage_needed = get_symtab_upper_bound (abfd); + + if (storage_needed > 0) + { + symbol_table = (asymbol **) bfd_xmalloc (storage_needed); + back_to = make_cleanup (free, symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) { - /* Determine length of text section and relocate it. */ - so->ld_text = p->endaddr - p->addr; - p->addr += (CORE_ADDR)so->inferior_lm.lm_addr; - p->endaddr += (CORE_ADDR)so->inferior_lm.lm_addr; + sym = *symbol_table++; + if (strcmp (sym -> name, symname) == 0) + { + symaddr = sym -> value; + break; + } } - else - /* All other sections are ignored for now. */ - p->addr = p->endaddr = 0; + do_cleanups (back_to); } + return (symaddr); } -/*=======================================================================*/ - -/* find_solib -** -**Description: -** -** This module contains the routine which finds the names of any loaded -** "images" in the current process. The argument in must be NULL on the -** first call, and then the returned value must be passed in on -** subsequent calls. This provides the capability to "step" down the -** list of loaded objects. On the last object, a NULL value is returned. -** The arg and return value are "struct link_map" pointers, as defined -** in <link.h>. -** -** NOTE: This only works under SunOS4.0. -*/ +/* + +LOCAL FUNCTION + + locate_base -- locate the base address of dynamic linker structs + +SYNOPSIS + + CORE_ADDR locate_base (void) + +DESCRIPTION + + For both the SunOS and SVR4 shared library implementations, if the + inferior executable has been linked dynamically, there is a single + address somewhere in the inferior's data space which is the key to + locating all of the dynamic linker's runtime structures, and this + address is the value of the symbol defined by the macro DEBUG_BASE. + The job of this function is to find and return that address, or to + return 0 if there is no such address (the executable is statically + linked for example). + + For SunOS, the job is almost trivial, since the dynamic linker and + all of it's structures are statically linked to the executable at + link time. Thus the symbol for the address we are looking for has + already been added to the misc function vector at the time the symbol + file's symbols were read. + + The SVR4 version is much more complicated because the dynamic linker + and it's structures are located in the shared library itself, which + gets run as the executable's "interpreter" by the kernel. Because + of this complexity, we cache the value we find and return that value + on subsequent invocations, if it is non-zero. + + First we must decide if we are stopped at the entry point of the + shared C library, which is set to be the entry point of the dynamic + linker code (the function _rt_boot() to be precise), or at the entry + point given in the inferior's exec file (for statically linked + executables). + + If we are not stopped at the inferior's exec file entry point then + we are either stopped at the interpreter's entry point or somewhere + else (I.E. totally lost). Use the /proc interface to get an open + file descriptor on the file that is mapped at the current stop_pc + value and try to open a bfd for it. + +FIXME + + The SVR4 strategy does NOT work when gdb is attaching to an existing + process because the stop_pc is not in the library code, so we can't + use the /proc interface to get an open fd for the library. So we + need to rethink the method for finding the debugger interface struct. + + For SunOS we could look around in the executable code to find + DEBUG_BASE, if it isn't in the symbol table. It's not that hard to + find. Then we can debug stripped executables using shared library + symbols. + + */ + +static CORE_ADDR +locate_base () +{ + CORE_ADDR address; + +#ifdef sun + + int i; + + i = lookup_misc_func (DEBUG_BASE); + if (i >= 0 && misc_function_vector[i].address != 0) + { + address = misc_function_vector[i].address; + } + +#else /* !sun */ + + int stop_pc_fd; /* File descriptor for mapped file */ + int interp_fd; /* File descriptor for interpreter */ + char *interp_name; /* Name of interpreter */ + char *full_interp_name; /* Full pathname of interpreter */ + bfd *interp_bfd; + CORE_ADDR interp_base; + + if (debug_base > 0) + { + /* We have a currently valid address, so avoid doing all the work + again. */ + return (debug_base); + } + if (bfd_get_start_address (exec_bfd) == stop_pc) + { + /* We are stopped at the entry point to the exec file, so there + are no shared libs to deal with. */ + return (0); + } + if ((stop_pc_fd = proc_address_to_fd (stop_pc)) < 0) + { + /* We are stopped at an address for which we can't seem to get an open + file descriptor from the /proc interface. We should already have + printed a suitable warning message. */ + return (0); + } + if ((interp_name = elf_interpreter (exec_bfd)) == NULL) + { + /* There is no interpreter specified in the exec file, thus this is + not a normal dynamically linked file. */ + return (0); + } + if ((interp_fd = openp (getenv ("PATH"), 1, interp_name, O_RDONLY, 0, + &full_interp_name)) < 0) + { + /* We can't find and open the interpreter. This is a problem. */ + return (0); + } + if (!fdmatch (stop_pc_fd, interp_fd)) + { + /* The file for the mapped region is not the interpreter, something + is strange... */ + close (stop_pc_fd); + close (interp_fd); + free (full_interp_name); + return (0); + } + interp_bfd = bfd_fdopenr (full_interp_name, NULL, interp_fd); + if (!interp_bfd) + { + warning ("Could not open `%s' as an executable file: %s", + full_interp_name, bfd_errmsg (bfd_error)); + return (0); + } + if (!bfd_check_format (interp_bfd, bfd_object)) + { + warning ("\"%s\": not in executable format: %s.", + full_interp_name, bfd_errmsg (bfd_error)); + return (0); + } + + /* Lookup the unrelocated value of the symbol that defines the location + of the debugger interface structure for the dynamic linker in the shared + library. Then find the base address of the text segment in the + inferior's mapped in dynamic library, which gives the relocation to + apply to find the actual mapped address of the debugger interface + structure. */ + + if ((address = bfd_lookup_symbol (interp_bfd, DEBUG_BASE)) == 0) + { + warning ("can't find symbol %s in shared library", DEBUG_BASE); + return (0); + } + if ((interp_base = proc_base_address (stop_pc)) == 0) + { + warning ("can't find base address for shared library text segment"); + return (0); + } + shlib_base = interp_base; + address += interp_base; + + if ((interp_base + bfd_get_start_address (interp_bfd)) != stop_pc) + { + /* We are not stopped at the entry point to the dynamic linker, + so grumble and skip startup shared library processing. */ + warning ("not stopped at entry point of dynamic linker"); + warning ("shared library processing suppressed"); + return (0); + } + + bfd_close (interp_bfd); + +#endif /* sun */ + + return (address); + +} -struct so_list *find_solib(so_list_ptr) -struct so_list *so_list_ptr; /* so_list_head position ptr */ +static struct link_map * +first_link_map_member () { -struct so_list *so_list_next = 0; -struct link_map *inferior_lm = 0; -struct link_dynamic inferior_dynamic_cpy; -struct link_dynamic_2 inferior_ld_2_cpy; -struct so_list *new; -int i; - - if (!so_list_ptr) { - if (!(so_list_next = so_list_head)) { - i = lookup_misc_func ("_DYNAMIC"); - if (i >= 0) { - read_memory(misc_function_vector[i].address, - &inferior_dynamic_cpy, - sizeof(struct link_dynamic)); - if (inferior_dynamic_cpy.ld_version == 3) { - read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, - &inferior_ld_2_cpy, - sizeof(struct link_dynamic_2)); - inferior_lm = inferior_ld_2_cpy.ld_loaded; - } - } - } - } else { - /* - ** Advance to next local abbreviated load_map structure - */ - if (!(inferior_lm = so_list_ptr->inferior_lm.lm_next)) { - /* See if any were added, but be quiet if we can't read - from the target any more. */ - int status; - - status = target_read_memory ( - (CORE_ADDR)so_list_ptr->inferior_lm_add, - (char *)&so_list_ptr->inferior_lm, - sizeof(struct link_map)); - if (status == 0) - inferior_lm = so_list_ptr->inferior_lm.lm_next; - else - inferior_lm = 0; - } - so_list_next = so_list_ptr->next; - } - if ((!so_list_next) && inferior_lm) { - /* - ** Get Next LM Structure from inferior image and build - ** an local abbreviated load_map structure - */ - new = (struct so_list *) xmalloc(sizeof(struct so_list)); - new->inferior_lm_add = inferior_lm; - read_memory((CORE_ADDR)inferior_lm, - &new->inferior_lm, - sizeof(struct link_map)); - - read_memory((CORE_ADDR)new->inferior_lm.lm_name, - new->inferior_so_name, - MAX_PATH_SIZE - 1); - new->inferior_so_name[MAX_PATH_SIZE - 1] = 0; - /* Zero everything after the first terminating null */ - strncpy(new->inferior_so_name, new->inferior_so_name, MAX_PATH_SIZE); - -#if 0 - /* This doesn't work for core files, so instead get ld_text - using solib_map_sections (below). */ - read_memory((CORE_ADDR)new->inferior_lm.lm_ld, - &inferior_dynamic_cpy, - sizeof(struct link_dynamic)); - read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, - &inferior_ld_2_cpy, - sizeof(struct link_dynamic_2)); - new->ld_text = inferior_ld_2_cpy.ld_text; + struct link_map *lm = NULL; + +#ifdef sun + + read_memory (debug_base, &dynamic_copy, sizeof (dynamic_copy)); + if (dynamic_copy.ld_version >= 2) + { + /* It is a version that we can deal with, so read in the secondary + structure and find the address of the link map list from it. */ + read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, &ld_2_copy, + sizeof (struct link_dynamic_2)); + lm = ld_2_copy.ld_loaded; + } + +#else + + read_memory (debug_base, &debug_copy, sizeof (struct r_debug)); + lm = debug_copy.r_map; + #endif - new->next = 0; - new->symbols_loaded = 0; - new->so_bfd = NULL; - new->sections = NULL; - if (so_list_ptr) - so_list_ptr->next = new; - else - so_list_head = new; + return (lm); +} + +/* + +GLOBAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. - solib_map_sections (new); + The arg and return value are "struct link_map" pointers, as defined + in <link.h>. + */ - so_list_next = new; - } - return(so_list_next); +struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct link_map *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* We have not already read in the dynamic linking structures + from the inferior, lookup the address of the base structure. */ + debug_base = locate_base (); + if (debug_base > 0) + { + /* Read the base structure in and find the address of the first + link map list member. */ + lm = first_link_map_member (); + } + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + if ((lm = LM_NEXT (so_list_ptr)) == NULL) + { + /* We have hit the end of the list, so check to see if any were + added, but be quiet if we can't read from the target any more. */ + int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr, + (char *) &(so_list_ptr -> lm), + sizeof (struct link_map)); + if (status == 0) + { + lm = LM_NEXT (so_list_ptr); + } + else + { + lm = NULL; + } + } + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + (void) memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + read_memory ((CORE_ADDR) lm, &(new -> lm), sizeof (struct link_map)); + /* For the SVR4 version, there is one entry that has no name + (for the inferior executable) since it is not a shared object. */ + if (LM_NAME (new) != 0) + { + read_memory((CORE_ADDR) LM_NAME (new), new -> so_name, + MAX_PATH_SIZE - 1); + new -> so_name[MAX_PATH_SIZE - 1] = 0; + solib_map_sections (new); + } + } + return (so_list_next); } /* A small stub to get us past the arg-passing pinhole of catch_errors. */ @@ -220,15 +547,27 @@ static int symbol_add_stub (arg) char *arg; { - register struct so_list *so = (struct so_list *)arg; /* catch_errs bogon */ - - symbol_file_add (so->inferior_so_name, so->from_tty, - (unsigned int)so->inferior_lm.lm_addr, 0); - return 1; + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + symbol_file_add (so -> so_name, so -> from_tty, + (unsigned int) LM_ADDR (so), 0); + return (1); } -/* The real work of adding a shared library file to the symtab and - the section list. */ +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ void solib_add (arg_string, from_tty, target) @@ -236,226 +575,516 @@ solib_add (arg_string, from_tty, target) int from_tty; struct target_ops *target; { - register struct so_list *so = 0; /* link map state variable */ - char *val; - int count, old; - struct section_table *sec; - - if (arg_string == 0) - re_comp ("."); - else if (val = (char *) re_comp (arg_string)) { - error ("Invalid regexp: %s", val); - } - + register struct so_list *so = NULL; /* link map state variable */ + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + /* Getting new symbols may change our opinion about what is frameless. */ reinit_frame_cache (); - - if (from_tty) { - printf_filtered ("Shared libraries"); - if (arg_string) - printf_filtered (" matching regular expresion \"%s\"", arg_string); - printf_filtered (":\n"); - } - dont_repeat(); - - while (so = find_solib(so)) { - if (re_exec(so->inferior_so_name)) { - if (so->symbols_loaded) { + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name)) + { + if (so -> symbols_loaded) + { if (from_tty) - printf("Symbols already loaded for %s\n", so->inferior_so_name); - } else { - so->symbols_loaded = 1; - so->from_tty = from_tty; - catch_errors (symbol_add_stub, (char *)so, - "Error while reading shared library symbols:\n"); - } - } - } - + { + printf ("Symbols already loaded for %s\n", so -> so_name); + } + } + else + { + so -> symbols_loaded = 1; + so -> from_tty = from_tty; + catch_errors (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n"); + } + } + } + /* Now add the shared library sections to the section table of the specified target, if any. */ - if (target) { - /* Count how many new section_table entries there are. */ - so = 0; - count = 0; - while (0 != (so = find_solib (so))) { - count += so->sections_end - so->sections; - } - - if (count) { - /* Reallocate the target's section table including the new size. */ - if (target->sections) { - old = target->sections_end - target->sections; - target->sections = (struct section_table *) - realloc ((char *)target->sections, - (sizeof (struct section_table)) * (count + old)); - } else { - old = 0; - target->sections = (struct section_table *) - malloc ((sizeof (struct section_table)) * count); - } - target->sections_end = target->sections + (count + old); - - /* Add these section table entries to the target's table. */ - while (0 != (so = find_solib (so))) { - count = so->sections_end - so->sections; - bcopy (so->sections, (char *)(target->sections + old), - (sizeof (struct section_table)) * count); - old += count; - } - } - } + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + /* Reallocate the target's section table including the new size. */ + if (target -> sections) + { + old = target -> sections_end - target -> sections; + target -> sections = (struct section_table *) + realloc ((char *)target -> sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> sections = (struct section_table *) + malloc ((sizeof (struct section_table)) * count); + } + target -> sections_end = target -> sections + (count + old); + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + bcopy (so -> sections, (char *)(target -> sections + old), + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } } -/*=======================================================================*/ +/* -static void solib_info() -{ -register struct so_list *so = 0; /* link map state variable */ +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION - while (so = find_solib(so)) { - if (so == so_list_head) { - printf(" Address Range Syms Read Shared Object Library\n"); + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command () +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if (!header_done) + { + printf("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + printf ("%-12s", local_hex_string_custom (LM_ADDR (so), "08")); + printf ("%-12s", local_hex_string_custom (so -> lmend, "08")); + printf ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf ("%s\n", so -> so_name); } - printf(" 0x%08x - 0x%08x %s %s\n", - so->inferior_lm.lm_addr, - so->inferior_lm.lm_addr + so->ld_text - 1, - (so->symbols_loaded ? "Yes" : "No "), - so->inferior_so_name); } - if (!so_list_head) { - printf("No shared libraries loaded at this time.\n"); + if (so_list_head == NULL) + { + printf ("No shared libraries loaded at this time.\n"); } } /* -** Called by Insert Breakpoint to see if Address is Shared Library Address -*/ + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + int solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + int -solib_address(address) +solib_address (address) CORE_ADDR address; { -register struct so_list *so = 0; /* link map state variable */ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if ((address >= (CORE_ADDR) LM_ADDR (so)) && + (address < (CORE_ADDR) so -> lmend)) + { + return (1); + } + } + } + return (0); +} + +/* Called by free_all_symtabs */ - while (so = find_solib(so)) { - if ((address >= (CORE_ADDR) so->inferior_lm.lm_addr) && - (address < (CORE_ADDR) so->inferior_lm.lm_addr + so->ld_text)) - return 1; +void +clear_solib() +{ + struct so_list *next; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free (so_list_head -> sections); + } + if (so_list_head -> so_bfd) + { + bfd_close (so_list_head -> so_bfd); + } + next = so_list_head -> next; + free(so_list_head); + so_list_head = next; } - return 0; + debug_base = 0; } /* -** Called by free_all_symtabs + +LOCAL FUNCTION + + disable_break -- remove the "mapping changed" breakpoint + +SYNOPSIS + + static int disable_break () + +DESCRIPTION + + Removes the breakpoint that gets hit when the dynamic linker + completes a mapping change. + */ -void -clear_solib() + +static int +disable_break () { -struct so_list *next; - - while (so_list_head) { - if (so_list_head->sections) - free (so_list_head->sections); - if (so_list_head->so_bfd) - bfd_close (so_list_head->so_bfd); - next = so_list_head->next; - free(so_list_head); - so_list_head = next; - } + int status = 1; + +#ifdef sun + + /* FIXME: maybe we should add the common symbols from the ldd_cp chain + to the misc_function_vector ? */ + + int in_debugger = 0; + + /* Set `in_debugger' to zero now. */ + + write_memory (flag_addr, &in_debugger, sizeof (in_debugger)); + + /* Read the debugger structure from the inferior to retrieve the + address of the breakpoint and the original contents of the + breakpoint address. Remove the breakpoint by writing the original + contents back. */ + + read_memory (debug_addr, &debug_copy, sizeof (debug_copy)); + breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr; + write_memory (breakpoint_addr, &debug_copy.ldd_bp_inst, + sizeof (debug_copy.ldd_bp_inst)); + +#else /* !sun */ + + /* Note that breakpoint address and original contents are in our address + space, so we just need to write the original contents back. */ + + if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + status = 0; + } + +#endif /* sun */ + + /* For the SVR4 version, we always know the breakpoint address. For the + SunOS version we don't know it until the above code is executed. + Grumble if we are stopped anywhere besides the breakpoint address. */ + + if (stop_pc != breakpoint_addr) + { + warning ("stopped at unknown breakpoint while handling shared libraries"); + } + + return (status); } -/* Called by child_create_inferior when the inferior is stopped at its - first instruction. */ +/* -void -solib_create_inferior_hook() +LOCAL FUNCTION + + enable_break -- arrange for dynamic linker to hit breakpoint + +SYNOPSIS + + int enable_break (void) + +DESCRIPTION + + Both the SunOS and the SVR4 dynamic linkers have, as part of their + debugger interface, support for arranging for the inferior to hit + a breakpoint after mapping in the shared libraries. This function + enables that breakpoint. + + For SunOS, there is a special flag location (in_debugger) which we + set to 1. When the dynamic linker sees this flag set, it will set + a breakpoint at a location known only to itself, after saving the + original contents of that place and the breakpoint address itself, + in it's own internal structures. When we resume the inferior, it + will eventually take a SIGTRAP when it runs into the breakpoint. + We handle this (in a different place) by restoring the contents of + the breakpointed location (which is only known after it stops), + chasing around to locate the shared libraries that have been + loaded, then resuming. + + For SVR4, the debugger interface structure contains a member (r_brk) + which is statically initialized at the time the shared library is + built, to the offset of a function (_r_debug_state) which is guaran- + teed to be called once before mapping in a library, and again when + the mapping is complete. At the time we are examining this member, + it contains only the unrelocated offset of the function, so we have + to do our own relocation. Later, when the dynamic linker actually + runs, it relocates r_brk to be the actual address of _r_debug_state(). + + The debugger interface structure also contains an enumeration which + is set to either RT_ADD or RT_DELETE prior to changing the mapping, + depending upon whether or not the library is being mapped or unmapped, + and then set to RT_CONSISTENT after the library is mapped/unmapped. +*/ + +static int +enable_break () { - struct link_dynamic inferior_dynamic_cpy; - CORE_ADDR inferior_debug_addr; - struct ld_debug inferior_debug_cpy; - int in_debugger; - CORE_ADDR in_debugger_addr; - CORE_ADDR breakpoint_addr; - int i, j; - /* FIXME: We should look around in the executable code to find _DYNAMIC, - if it isn't in the symbol table. It's not that hard to find... - Then we can debug stripped executables using shared library symbols. */ - i = lookup_misc_func ("_DYNAMIC"); - if (i < 0) /* Can't find shared lib ptr. */ - return; - if (misc_function_vector[i].address == 0) /* statically linked program */ - return; + int j; + +#ifdef sun + int in_debugger; + /* Get link_dynamic structure */ - j = target_read_memory(misc_function_vector[i].address, - &inferior_dynamic_cpy, - sizeof(struct link_dynamic)); - if (j) /* unreadable */ - return; + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return (0); + } /* Calc address of debugger interface structure */ - inferior_debug_addr = (CORE_ADDR)inferior_dynamic_cpy.ldd; + + debug_addr = (CORE_ADDR) dynamic_copy.ldd; + /* Calc address of `in_debugger' member of debugger interface structure */ - in_debugger_addr = inferior_debug_addr + (CORE_ADDR)((char *)&inferior_debug_cpy.ldd_in_debugger - (char *)&inferior_debug_cpy); + + flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger - + (char *) &debug_copy); + /* Write a value of 1 to this member. */ + in_debugger = 1; - write_memory(in_debugger_addr, &in_debugger, sizeof(in_debugger)); - /* Now run the target. Seeing `in_debugger' set, it will set a - breakpoint at some convenient place, remember the original contents - of that place, and eventually take a SIGTRAP when it runs into the - breakpoint. We handle this by restoring the contents of the - breakpointed location (which is only known after it stops), - chasing around to locate the shared libraries that have been - loaded, then resuming. */ + write_memory (flag_addr, &in_debugger, sizeof (in_debugger)); + +#else /* !sun */ + +#ifdef BKPT_AT_MAIN + + int i; + + i = lookup_misc_func ("main"); + if (i >= 0 && misc_function_vector[i].address != 0) + { + breakpoint_addr = misc_function_vector[i].address; + } + else + { + return (0); + } + + if (target_insert_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + return (0); + } + +#else /* !BKPT_AT_MAIN */ + + struct symtab_and_line sal; + + /* Read the debugger interface structure directly. */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set breakpoint at the debugger interface stub routine that will + be called just prior to each mapping change and again after the + mapping change is complete. Set up the (nonexistent) handler to + deal with hitting these breakpoints. (FIXME). */ + + warning ("'%s': line %d: missing SVR4 support code", __FILE__, __LINE__); + +#endif /* BKPT_AT_MAIN */ + +#endif /* sun */ + + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + + For both SunOS shared libraries, and SVR4 shared libraries, we + can arrange to cooperate with the dynamic linker to discover the + names of shared libraries that are dynamically linked, and the + base addresses to which they are linked. + + This function is responsible for discovering those names and + addresses, and saving sufficient information about them to allow + their symbols to be read at a later time. + +FIXME + + Between enable_break() and disable_break(), this code does not + properly handle hitting breakpoints which the user might have + set in the startup code or in the dynamic linker itself. Proper + handling will probably have to wait until the implementation is + changed to use the "breakpoint handler function" method. + + Also, what if child has exit()ed? Must exit loop somehow. + */ + +void +solib_create_inferior_hook() +{ + CORE_ADDR debug_addr; + int in_debugger; + CORE_ADDR in_debugger_addr; + CORE_ADDR breakpoint_addr; + int i, j; + + if ((debug_base = locate_base ()) == 0) + { + /* Can't find the symbol or the executable is statically linked. */ + return; + } + + if (!enable_break ()) + { + warning ("shared library handler failed to enable breakpoint"); + return; + } + + /* Now run the target. It will eventually hit the breakpoint, at + which point all of the libraries will have been mapped in and we + can go groveling around in the dynamic linker structures to find + out what we need to know about them. */ clear_proceed_status (); stop_soon_quietly = 1; - target_resume (0, 0); - wait_for_inferior (); - while (stop_signal != SIGTRAP) + stop_signal = 0; + do { - /* FIXME, what if child has exit()ed? Must exit loop somehow */ target_resume (0, stop_signal); wait_for_inferior (); } + while (stop_signal != SIGTRAP); stop_soon_quietly = 0; + + /* We are now either at the "mapping complete" breakpoint (or somewhere + else, a condition we aren't prepared to deal with anyway), so adjust + the PC as necessary after a breakpoint, disable the breakpoint, and + add any shared libraries that were mapped in. */ - /* Set `in_debugger' to zero now. WHY, is this needed? */ - in_debugger = 0; - write_memory(in_debugger_addr, &in_debugger, sizeof(in_debugger)); - read_memory(inferior_debug_addr, &inferior_debug_cpy, sizeof(inferior_debug_cpy)); - /* FIXME: maybe we should add the common symbols from the ldd_cp chain - * to the misc_function_vector ? - */ - breakpoint_addr = (CORE_ADDR)inferior_debug_cpy.ldd_bp_addr; - if (stop_pc - DECR_PC_AFTER_BREAK == breakpoint_addr) - { - write_memory(breakpoint_addr, &inferior_debug_cpy.ldd_bp_inst, sizeof(inferior_debug_cpy.ldd_bp_inst)); - if (DECR_PC_AFTER_BREAK) - { - stop_pc -= DECR_PC_AFTER_BREAK; - write_register (PC_REGNUM, stop_pc); - } - } - solib_add ((char *)0, 0, (struct target_ops *)0); + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + } + + if (!disable_break ()) + { + warning ("shared library handler failed to disable breakpoint"); + } + + solib_add ((char *) 0, 0, (struct target_ops *) 0); } +/* + +GLOBAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + void sharedlibrary_command (args, from_tty) +char *args; +int from_tty; { - solib_add (args, from_tty, (struct target_ops *)0); + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); } void _initialize_solib() { - - add_com("sharedlibrary", class_files, sharedlibrary_command, + + add_com ("sharedlibrary", class_files, sharedlibrary_command, "Load shared object library symbols for files matching REGEXP."); - add_info("sharedlibrary", solib_info, - "Status of loaded shared object libraries"); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); } |