📄 solib.c
字号:
/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. Copyright 1990, 1991, 1992 Free Software Foundation, Inc. This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "defs.h"#include <sys/types.h>#include <signal.h>#include <string.h>#include <link.h>#include <sys/param.h>#include <fcntl.h>#ifndef SVR4_SHARED_LIBS /* SunOS shared libs need the nlist structure. */#include <a.out.h> #endif#include "symtab.h"#include "bfd.h"#include "symfile.h"#include "objfiles.h"#include "gdbcore.h"#include "command.h"#include "target.h"#include "frame.h"#include "regex.h"#include "inferior.h"#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 */#ifndef SVR4_SHARED_LIBS#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 /* SVR4_SHARED_LIBS */#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;char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */#endif /* !SVR4_SHARED_LIBS */struct so_list { 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 objfile *objfile; /* objfile for loaded lib */ struct section_table *sections; struct section_table *sections_end; struct section_table *textsection;};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 */extern intfdmatch PARAMS ((int, int)); /* In libiberty *//* Local function prototypes */static voidspecial_symbol_handling PARAMS ((struct so_list *));static voidsharedlibrary_command PARAMS ((char *, int));static intenable_break PARAMS ((void));static intdisable_break PARAMS ((void));static voidinfo_sharedlibrary_command PARAMS ((char *, int));static intsymbol_add_stub PARAMS ((char *));static struct so_list *find_solib PARAMS ((struct so_list *));static struct link_map *first_link_map_member PARAMS ((void));static CORE_ADDRlocate_base PARAMS ((void));static voidsolib_map_sections PARAMS ((struct so_list *));#ifdef SVR4_SHARED_LIBSstatic intlook_for_base PARAMS ((int, CORE_ADDR));static CORE_ADDRbfd_lookup_symbol PARAMS ((bfd *, char *));#elsestatic voidsolib_add_common_symbols PARAMS ((struct rtc_symb *, struct objfile *));#endif/*LOCAL FUNCTION solib_map_sections -- open bfd and build sections for shared libSYNOPSIS 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 voidsolib_map_sections (so) struct so_list *so;{ char *filename; char *scratch_pathname; int scratch_chan; struct section_table *p; filename = tilde_expand (so -> so_name); make_cleanup (free, filename); scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, &scratch_pathname); if (scratch_chan < 0) { 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++) { /* 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); if (strcmp (p -> sec_ptr -> name, ".text") == 0) { so -> textsection = p; } }}/* Read all dynamically loaded common symbol definitions from the inferior and add them to the minimal symbol table for the shared library objfile. */#ifndef SVR4_SHARED_LIBSstatic voidsolib_add_common_symbols (rtc_symp, objfile) struct rtc_symb *rtc_symp; struct objfile *objfile;{ struct rtc_symb inferior_rtc_symb; struct nlist inferior_rtc_nlist; int len; char *name; char *origname; init_minimal_symbol_collection (); make_cleanup (discard_minimal_symbols, 0); while (rtc_symp) { read_memory ((CORE_ADDR) rtc_symp, (char *) &inferior_rtc_symb, sizeof (inferior_rtc_symb)); read_memory ((CORE_ADDR) inferior_rtc_symb.rtc_sp, (char *) &inferior_rtc_nlist, sizeof(inferior_rtc_nlist)); if (inferior_rtc_nlist.n_type == N_COMM) { /* FIXME: The length of the symbol name is not available, but in the current implementation the common symbol is allocated immediately behind the name of the symbol. */ len = inferior_rtc_nlist.n_value - inferior_rtc_nlist.n_un.n_strx; origname = name = xmalloc (len); read_memory ((CORE_ADDR) inferior_rtc_nlist.n_un.n_name, name, len); /* Don't enter the symbol twice if the target is re-run. */#ifdef NAMES_HAVE_UNDERSCORE if (*name == '_') { name++; }#endif /* FIXME: Do we really want to exclude symbols which happen to match symbols for other locations in the inferior's address space, even when they are in different linkage units? */ if (lookup_minimal_symbol (name, (struct objfile *) NULL) == NULL) { name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value, mst_bss); } free (origname); } rtc_symp = inferior_rtc_symb.rtc_next; } /* Install any minimal symbols that have been collected as the current minimal symbols for this objfile. */ install_minimal_symbols (objfile);}#endif /* SVR4_SHARED_LIBS */#ifdef SVR4_SHARED_LIBS/*LOCAL FUNCTION bfd_lookup_symbol -- lookup the value for a specific symbolSYNOPSIS 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_ADDRbfd_lookup_symbol (abfd, symname) bfd *abfd; char *symname;{ unsigned int storage_needed; asymbol *sym; asymbol **symbol_table; unsigned int number_of_symbols; unsigned int i; struct cleanup *back_to; CORE_ADDR symaddr = 0; storage_needed = get_symtab_upper_bound (abfd); if (storage_needed > 0) { symbol_table = (asymbol **) xmalloc (storage_needed); back_to = make_cleanup (free, (PTR)symbol_table); number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); for (i = 0; i < number_of_symbols; i++) { sym = *symbol_table++; if (strcmp (sym -> name, symname) == 0) { symaddr = sym -> value; break; } } do_cleanups (back_to); } return (symaddr);}/*LOCAL FUNCTION look_for_base -- examine file for each mapped address segmentSYNOPSYS static int look_for_base (int fd, CORE_ADDR baseaddr)DESCRIPTION This function is passed to proc_iterate_over_mappings, which causes it to get called once for each mapped address space, with an open file descriptor for the file mapped to that space, and the base address of that mapped space. Our job is to find the symbol DEBUG_BASE in the file that this fd is open on, if it exists, and if so, initialize the dynamic linker structure base address debug_base. Note that this is a computationally expensive proposition, since we basically have to open a bfd on every call, so we specifically avoid opening the exec file. */static intlook_for_base (fd, baseaddr) int fd; CORE_ADDR baseaddr;{ bfd *interp_bfd; CORE_ADDR address; /* If the fd is -1, then there is no file that corresponds to this mapped memory segment, so skip it. Also, if the fd corresponds to the exec file, skip it as well. */ if ((fd == -1) || fdmatch (fileno ((FILE *)(exec_bfd -> iostream)), fd)) { return (0); } /* Try to open whatever random file this fd corresponds to. Note that we have no way currently to find the filename. Don't gripe about any problems we might have, just fail. */ if ((interp_bfd = bfd_fdopenr ("unnamed", NULL, fd)) == NULL) { return (0); } if (!bfd_check_format (interp_bfd, bfd_object)) { bfd_close (interp_bfd); return (0); } /* Now try to find our DEBUG_BASE symbol in this file, which we at least know to be a valid ELF executable or shared library. */ if ((address = bfd_lookup_symbol (interp_bfd, DEBUG_BASE)) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -