📄 dyn_load.c
字号:
/* * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1997 by Silicon Graphics. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * * Original author: Bill Janssen * Heavily modified by Hans Boehm and others *//* * This is incredibly OS specific code for tracking down data sections in * dynamic libraries. There appears to be no way of doing this quickly * without groveling through undocumented data structures. We would argue * that this is a bug in the design of the dlopen interface. THIS CODE * MAY BREAK IN FUTURE OS RELEASES. If this matters to you, don't hesitate * to let your vendor know ... * * None of this is safe with dlclose and incremental collection. * But then not much of anything is safe in the presence of dlclose. */#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \ && !defined(_GNU_SOURCE) /* Can't test LINUX, since this must be defined before other includes */# define _GNU_SOURCE#endif#if !defined(MACOS) && !defined(_WIN32_WCE)# include <sys/types.h>#endif#include "private/gc_priv.h"/* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */# if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \ && defined(dlopen) && !defined(GC_USE_LD_WRAP) /* To support threads in Solaris, gc.h interposes on dlopen by */ /* defining "dlopen" to be "GC_dlopen", which is implemented below. */ /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */ /* real system dlopen() in their implementation. We first remove */ /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */# undef dlopen# define GC_must_restore_redefined_dlopen# else# undef GC_must_restore_redefined_dlopen# endif/* A user-supplied routine that is called to determine if a DSO must be scanned by the gc. */static int (*GC_has_static_roots)(const char *, void *, size_t);#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \ && !defined(PCR)#if !defined(SOLARISDL) && !defined(IRIX5) && \ !defined(MSWIN32) && !defined(MSWINCE) && \ !(defined(ALPHA) && defined(OSF1)) && \ !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ !defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \ !(defined(FREEBSD) && defined(__ELF__)) && \ !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \ !defined(DARWIN) && !defined(CYGWIN32) --> We only know how to find data segments of dynamic libraries for the --> above. Additional SVR4 variants might not be too --> hard to add.#endif#include <stdio.h>#ifdef SOLARISDL# include <sys/elf.h># include <dlfcn.h># include <link.h>#endif#if defined(NETBSD)# include <machine/elf_machdep.h># define ELFSIZE ARCH_ELFSIZE#endif#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \ (defined(NETBSD) && defined(__ELF__)) || defined(HURD)# include <stddef.h># include <elf.h># include <link.h>#endif/* Newer versions of GNU/Linux define this macro. We * define it similarly for any ELF systems that don't. */# ifndef ElfW# if defined(FREEBSD)# if __ELF_WORD_SIZE == 32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# elif defined(NETBSD)# if ELFSIZE == 32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# else# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# endif# endif#if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)#ifdef LINT Elf32_Dyn _DYNAMIC;#endifstatic struct link_map *GC_FirstDLOpenedLinkMap(){ extern ElfW(Dyn) _DYNAMIC; ElfW(Dyn) *dp; struct r_debug *r; static struct link_map * cachedResult = 0; static ElfW(Dyn) *dynStructureAddr = 0; /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */# ifdef SUNOS53_SHARED_LIB /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */ /* up properly in dynamically linked .so's. This means we have */ /* to use its value in the set of original object files loaded */ /* at program startup. */ if( dynStructureAddr == 0 ) { void* startupSyms = dlopen(0, RTLD_LAZY); dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC"); }# else dynStructureAddr = &_DYNAMIC;# endif if( dynStructureAddr == 0) { return(0); } if( cachedResult == 0 ) { int tag; for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) { if( tag == DT_DEBUG ) { struct link_map *lm = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */ break; } } } return cachedResult;}#endif /* SOLARISDL ... *//* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */# if defined(GC_must_restore_redefined_dlopen)# define dlopen GC_dlopen# endif# if defined(SOLARISDL)/* Add dynamic library data sections to the root set. */# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS) --> fix mutual exclusion with dlopen# endif# ifndef USE_PROC_FOR_LIBRARIESvoid GC_register_dynamic_libraries(){ struct link_map *lm = GC_FirstDLOpenedLinkMap(); for (lm = GC_FirstDLOpenedLinkMap(); lm != (struct link_map *) 0; lm = lm->l_next) { ElfW(Ehdr) * e; ElfW(Phdr) * p; unsigned long offset; char * start; register int i; e = (ElfW(Ehdr) *) lm->l_addr; p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff)); offset = ((unsigned long)(lm->l_addr)); for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) { switch( p->p_type ) { case PT_LOAD: { if( !(p->p_flags & PF_W) ) break; start = ((char *)(p->p_vaddr)) + offset; GC_add_roots_inner( start, start + p->p_memsz, TRUE ); } break; default: break; } } }}# endif /* !USE_PROC ... */# endif /* SOLARISDL */#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \ (defined(NETBSD) && defined(__ELF__)) || defined(HURD)#ifdef USE_PROC_FOR_LIBRARIES#include <string.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#define MAPS_BUF_SIZE (32*1024)extern ssize_t GC_repeat_read(int fd, char *buf, size_t count); /* Repeatedly read until buffer is filled, or EOF is encountered */ /* Defined in os_dep.c. */char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end, char **prot, unsigned int *maj_dev, char **mapping_name);char *GC_get_maps(void); /* From os_dep.c */word GC_register_map_entries(char *maps){ char *prot; char *buf_ptr = maps; int count; ptr_t start, end; unsigned int maj_dev; ptr_t least_ha, greatest_ha; unsigned i; ptr_t datastart = (ptr_t)(DATASTART); /* Compute heap bounds. FIXME: Should work if heap and roots are */ /* interleaved? */ least_ha = (ptr_t)(word)(-1); greatest_ha = 0; for (i = 0; i < GC_n_heap_sects; ++i) { ptr_t sect_start = GC_heap_sects[i].hs_start; ptr_t sect_end = sect_start + GC_heap_sects[i].hs_bytes; if (sect_start < least_ha) least_ha = sect_start; if (sect_end > greatest_ha) greatest_ha = sect_end; } if (greatest_ha < (ptr_t)GC_scratch_last_end_ptr) greatest_ha = (ptr_t)GC_scratch_last_end_ptr; for (;;) { buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0); if (buf_ptr == NULL) return 1; if (prot[1] == 'w') { /* This is a writable mapping. Add it to */ /* the root set unless it is already otherwise */ /* accounted for. */ if (start <= GC_stackbottom && end >= GC_stackbottom) { /* Stack mapping; discard */ continue; }# ifdef THREADS /* This may fail, since a thread may already be */ /* unregistered, but its thread stack may still be there. */ /* That can fail because the stack may disappear while */ /* we're marking. Thus the marker is, and has to be */ /* prepared to recover from segmentation faults. */ if (GC_segment_is_thread_stack(start, end)) continue; /* FIXME: REDIRECT_MALLOC actually works with threads on */ /* LINUX/IA64 if we omit this check. The problem is that */ /* thread stacks contain pointers to dynamic thread */ /* vectors, which may be reused due to thread caching. */ /* Currently they may not be marked if the thread is */ /* still live. */ /* For dead threads, we trace the whole stack, which is */ /* very suboptimal for performance reasons. */# endif /* We no longer exclude the main data segment. */ if (start < least_ha && end > least_ha) { end = least_ha; } if (start < greatest_ha && end > greatest_ha) { start = greatest_ha; } if (start >= least_ha && end <= greatest_ha) continue; GC_add_roots_inner((char *)start, (char *)end, TRUE); } } return 1;}void GC_register_dynamic_libraries(){ if (!GC_register_map_entries(GC_get_maps())) ABORT("Failed to read /proc for library registration.");}/* We now take care of the main data segment ourselves: */GC_bool GC_register_main_static_data(){ return FALSE;} # define HAVE_REGISTER_MAIN_STATIC_DATA#endif /* USE_PROC_FOR_LIBRARIES */#if !defined(USE_PROC_FOR_LIBRARIES)/* The following is the preferred way to walk dynamic libraries *//* For glibc 2.2.4+. Unfortunately, it doesn't work for older *//* versions. Thanks to Jakub Jelinek for most of the code. */# if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) /* We have the header files for a glibc that includes dl_iterate_phdr. *//* It may still not be available in the library on the target system. *//* Thus we also treat it as a weak symbol. */#define HAVE_DL_ITERATE_PHDRstatic int GC_register_dynlib_callback(info, size, ptr) struct dl_phdr_info * info; size_t size; void * ptr;{ const ElfW(Phdr) * p; char * start; register int i; /* Make sure struct dl_phdr_info is at least as big as we need. */ if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + sizeof (info->dlpi_phnum)) return -1; p = info->dlpi_phdr; for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) { switch( p->p_type ) { case PT_LOAD: { if( !(p->p_flags & PF_W) ) break; start = ((char *)(p->p_vaddr)) + info->dlpi_addr; if (GC_has_static_roots && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz)) break; GC_add_roots_inner(start, start + p->p_memsz, TRUE); } break; default: break; } } * (int *)ptr = 1; /* Signal that we were called */ return 0;} /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */#pragma weak dl_iterate_phdrGC_bool GC_register_dynamic_libraries_dl_iterate_phdr(){ if (dl_iterate_phdr) { int did_something = 0; dl_iterate_phdr(GC_register_dynlib_callback, &did_something); if (!did_something) { /* dl_iterate_phdr may forget the static data segment in */ /* statically linked executables. */ GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);# if defined(DATASTART2) GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);# endif } return TRUE; } else { return FALSE; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -