Skip site navigation (1)Skip section navigation (2)
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>