Date: Sun, 18 Jan 1998 14:50:26 -0800 From: John Polstra <jdp@polstra.com> To: hackers@FreeBSD.ORG Subject: Patch for dladdr (was: dladdr hax) Message-ID: <199801182250.OAA16054@austin.polstra.com>
next in thread | raw e-mail | index | archive | help
This is a multipart MIME message. --===_0_Sun_Jan_18_14:47:15_PST_1998 Content-Type: text/plain; charset=us-ascii Here are some patches to implement dladdr. The patches are relative to -current as of around Jan 17th. Follow the instructions in each patch. Please back up these files before starting: /usr/lib/crt0.o /usr/libexec/ld.so and make sure you know how to recover on a system with a trashed ld.so. Hint: the programs in /bin are statically linked. :-) This patch is more or less bug-compatible with Solaris, which means it's about as lame as it could possibly be. Somebody please try it with the applications that need dladdr, and tell me whether it does what they want it to do. Thanks, John -- John Polstra jdp@polstra.com John D. Polstra & Co., Inc. Seattle, Washington USA "Self-knowledge is always bad news." -- John Barth --===_0_Sun_Jan_18_14:47:15_PST_1998 Content-Type: text/plain; charset=us-ascii Content-Description: diff.1 Apply this in "/usr/src/include", then do a make install. Index: link.h =================================================================== RCS file: /home/ncvs/src/include/link.h,v retrieving revision 1.17 diff -u -Llink.h -r1.17 link.h --- link.h +++ link.h 1998/01/18 19:35:01 @@ -41,6 +41,8 @@ #ifndef _LINK_H_ #define _LINK_H_ +#include <dlfcn.h> + /* * A `Shared Object Descriptor' describes a shared object that is needed * to complete the link edit process of the object containing it. @@ -158,6 +160,7 @@ #define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ #define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ #define LDSO_VERSION_HAS_DLSYM3 2 /* includes 3-argument dlsym */ +#define LDSO_VERSION_HAS_DLADDR 3 /* includes dladdr in ld_entry */ /* * Entry points into ld.so - user interface to the run-time linker. @@ -171,6 +174,7 @@ const char *(*dlerror) __P((void)); /* NONE */ void (*dlexit) __P((void)); /* HAS_DLEXIT */ void *(*dlsym3) __P((void *, const char *, void *)); /* HAS_DLSYM3 */ + int (*dladdr) __P((void *, Dl_info *)); /* HAS_DLADDR */ }; /* @@ -229,6 +233,7 @@ char *crt_prog; /* Program name (v3) */ char *crt_ldso; /* Link editor name (v4) */ struct ld_entry *crt_ldentry; /* dl*() access (v4) */ + char **crt_argv; /* argument strings (v5) */ }; /* @@ -238,6 +243,7 @@ #define CRT_VERSION_BSD_2 2 #define CRT_VERSION_BSD_3 3 #define CRT_VERSION_BSD_4 4 +#define CRT_VERSION_BSD_5 5 /* * Maximum number of recognized shared object version numbers. --===_0_Sun_Jan_18_14:47:15_PST_1998 Content-Type: text/plain; charset=us-ascii Content-Description: diff.2 Apply this in "/usr/src/lib/csu/i386" and do this: make beforeinstall make make install Index: crt0.c =================================================================== RCS file: /home/ncvs/src/lib/csu/i386/crt0.c,v retrieving revision 1.31 diff -u -Lcrt0.c -r1.31 crt0.c --- crt0.c +++ crt0.c 1998/01/18 19:35:49 @@ -85,7 +85,7 @@ extern struct _dynamic _DYNAMIC; static struct ld_entry *ld_entry; -static void __do_dynamic_link (); +static void __do_dynamic_link(char **argv); #endif /* DYNAMIC */ int _callmain(); @@ -174,7 +174,7 @@ /* sometimes GCC is too smart/stupid for its own good */ x = (caddr_t)&_DYNAMIC; if (x) - __do_dynamic_link(); + __do_dynamic_link(argv); #endif /* DYNAMIC */ asm("eprol:"); @@ -190,7 +190,8 @@ #ifdef DYNAMIC static void -__do_dynamic_link () +__do_dynamic_link(argv) + char **argv; { struct crt_ldso crt; struct exec hdr; @@ -253,14 +254,20 @@ crt.crt_prog = __progname; crt.crt_ldso = ldso; crt.crt_ldentry = NULL; + crt.crt_argv = argv; entry = (int (*)())(crt.crt_ba + sizeof hdr); - ldso_version = (*entry)(CRT_VERSION_BSD_4, &crt); + ldso_version = (*entry)(CRT_VERSION_BSD_5, &crt); ld_entry = crt.crt_ldentry; if (ldso_version == -1 && ld_entry == NULL) { - /* if version 4 not recognised, try version 3 */ - ldso_version = (*entry)(CRT_VERSION_BSD_3, &crt); - ld_entry = _DYNAMIC.d_entry; + /* If version 5 not recognised, try version 4 */ + ldso_version = (*entry)(CRT_VERSION_BSD_4, &crt); + ld_entry = crt.crt_ldentry; + if (ldso_version == -1 && ld_entry == NULL) { + /* if version 4 not recognised, try version 3 */ + ldso_version = (*entry)(CRT_VERSION_BSD_3, &crt); + ld_entry = _DYNAMIC.d_entry; + } } if (ldso_version == -1) { _PUTMSG("ld.so failed"); @@ -334,6 +341,16 @@ return (ld_entry->dlerror)(); } +int +dladdr(addr, dlip) + void *addr; + Dl_info *dlip; +{ + if (ld_entry == NULL || ldso_version < LDSO_VERSION_HAS_DLADDR) + return 0; + return (ld_entry->dladdr)(addr, dlip); +} + /* * Support routines @@ -419,11 +436,18 @@ return NULL; } - const char * dlerror() { return "Service unavailable"; +} + +int +dladdr(addr, dlip) + void *addr; + Dl_info *dlip; +{ + return 0; } #endif /* DYNAMIC */ Index: dlfcn.h =================================================================== RCS file: /home/ncvs/src/lib/csu/i386/dlfcn.h,v retrieving revision 1.5 diff -u -Ldlfcn.h -r1.5 dlfcn.h --- dlfcn.h +++ dlfcn.h 1998/01/18 19:35:55 @@ -50,11 +50,22 @@ */ #define RTLD_NEXT ((void *) -1) +/* + * Structure filled in by dladdr(). + */ +typedef struct dl_info { + const char *dli_fname; /* Pathname of shared object */ + void *dli_fbase; /* Base address of shared object */ + const char *dli_sname; /* Name of nearest symbol */ + void *dli_saddr; /* Address of nearest symbol */ +} Dl_info; + __BEGIN_DECLS void *dlopen __P((const char *, int)); void *dlsym __P((void *, const char *)); const char *dlerror __P((void)); int dlclose __P((void *)); +int dladdr __P((void *, Dl_info *)); __END_DECLS #endif /* !_DLFCN_H_ */ --===_0_Sun_Jan_18_14:47:15_PST_1998 Content-Type: text/plain; charset=us-ascii Content-Description: diff.3 Apply this in "/usr/src/gnu/usr.bin/ld/rtld", then do a make; make install. Index: rtld.c =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/ld/rtld/rtld.c,v retrieving revision 1.51 diff -u -Lrtld.c -r1.51 rtld.c --- rtld.c +++ rtld.c 1998/01/18 22:20:23 @@ -174,6 +174,8 @@ #define RELOC_PCREL_P(s) ((s)->r_pcrel) #endif +#define END_SYM "_end" + static char __main_progname[] = "main"; static char *main_progname = __main_progname; static char us[] = "/usr/libexec/ld.so"; @@ -205,9 +207,10 @@ static const char *__dlerror __P((void)); static void __dlexit __P((void)); static void *__dlsym3 __P((void *, const char *, void *)); +static int __dladdr __P((void *, Dl_info *)); static struct ld_entry ld_entry = { - __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3 + __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3, __dladdr }; void xprintf __P((char *, ...)); @@ -302,11 +305,13 @@ struct so_map *main_map; struct so_map *smp; char *add_paths; + char *main_path; /* Check version */ if (version != CRT_VERSION_BSD_2 && version != CRT_VERSION_BSD_3 && version != CRT_VERSION_BSD_4 && + version != CRT_VERSION_BSD_5 && version != CRT_VERSION_SUN) return -1; @@ -335,6 +340,8 @@ __progname = crtp->crt_ldso; if (version >= CRT_VERSION_BSD_3) main_progname = crtp->crt_prog; + main_path = version >= CRT_VERSION_BSD_5 ? crtp->crt_argv[0] : + main_progname; /* Some buggy versions of crt0.o have crt_ldso filled in as NULL. */ if (__progname == NULL) @@ -363,7 +370,7 @@ anon_open(); /* Make a link map entry for the main program */ - main_map = alloc_link_map(main_progname, + main_map = alloc_link_map(main_path, (struct sod *) NULL, (struct so_map *) NULL, (caddr_t) 0, crtp->crt_dp); LM_PRIVATE(main_map)->spd_refcount++; @@ -453,7 +460,7 @@ (void)close(crtp->crt_ldfd); anon_close(); - return LDSO_VERSION_HAS_DLSYM3; + return LDSO_VERSION_HAS_DLADDR; } void @@ -2022,6 +2029,81 @@ addr += (long)src_map->som_addr; return (void *)addr; +} + +static int +__dladdr __P((void *addr, Dl_info *dlip)) +{ + struct _dynamic *dp; + struct so_map *smp; + char *stringbase; + long numsyms; + int symsize; + int i; + + /* Find the shared object that contains the address. */ + for (smp = link_map_head; smp != NULL; smp = smp->som_next) { + struct so_map *src_map; + struct somap_private *smpp; + struct nzlist *np; + + smpp = LM_PRIVATE(smp); + if (smpp->spd_flags & RTLD_RTLD) + continue; + + if ((void *)smp->som_addr > addr) + continue; + + src_map = smp; + if ((np = lookup(END_SYM, &src_map, 1)) == NULL) + continue; /* No "_end" symbol?! */ + if (addr < (void *)(smp->som_addr + np->nz_value)) + break; + } + if (smp == NULL) { + generror("No shared object contains address"); + return 0; + } + dlip->dli_fname = smp->som_path; + dlip->dli_fbase = smp->som_addr; + dlip->dli_saddr = (void *) 0; + dlip->dli_sname = NULL; + + dp = smp->som_dynamic; + symsize = LD_VERSION_NZLIST_P(dp->d_version) ? + sizeof(struct nzlist) : sizeof(struct nlist); + numsyms = LD_STABSZ(dp) / symsize; + stringbase = LM_STRINGS(smp); + + for (i = 0; i < numsyms; i++) { + struct nzlist *symp = LM_SYMBOL(smp, i); + unsigned long value; + + /* Reject all except definitions. */ + if (symp->nz_type != N_EXT + N_ABS && + symp->nz_type != N_EXT + N_TEXT && + symp->nz_type != N_EXT + N_DATA && + symp->nz_type != N_EXT + N_BSS) + continue; + + /* + * If the symbol is greater than the specified address, or + * if it is further away from addr than the current nearest + * symbol, then reject it. + */ + value = (unsigned long) (smp->som_addr + symp->nz_value); + if (value > (unsigned long) addr || + value < (unsigned long) dlip->dli_saddr) + continue; + + /* Update our idea of the nearest symbol. */ + dlip->dli_sname = stringbase + symp->nz_strx; + dlip->dli_saddr = (void *) value; + + if (dlip->dli_saddr == addr) /* Can't get any closer. */ + break; + } + return 1; } static void * --===_0_Sun_Jan_18_14:47:15_PST_1998--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199801182250.OAA16054>