svn commit: r210425 - head/cddl/contrib/opensolaris/lib/libdtrace/common

Andriy Gapon avg at FreeBSD.org
Fri Jul 23 17:32:48 UTC 2010


Author: avg
Date: Fri Jul 23 17:32:47 2010
New Revision: 210425
URL: http://svn.freebsd.org/changeset/base/210425

Log:
  dtrace: correctly map sections to addresses in elf object modules (amd64)
  
  Unlike for modules with dso type, in elf object modules all the sections
  have virtual address of zero.  So, it is insufficient to add module base
  address to section virtual address (as recorded in section header) to
  get section address in kernel memory.
  Instead, we should apply the same calculations that are performed by
  kernel loaders (in boot code and in kernel) when they lay out sections
  in memory.
  Also, unlike OpenSolaris, the sections are not collapsed into just .text,
  .data and .bss by module loaders, so we need to take additional care
  about other sections.
  
  Note that in-kernel symbol-to-address mapping worked just fine, e.g. fbt
  provider could correctly find the functions, etc.  It's only in userland
  that the mapping in both direction worked incorrectly, e.g. in stack()
  output addresses of functions in kernel modules were not translated to
  their names.
  
  Reviewed by:	rpaulo
  MFC after:	3 weeks

Modified:
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h	Fri Jul 23 17:21:23 2010	(r210424)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h	Fri Jul 23 17:32:47 2010	(r210425)
@@ -137,6 +137,7 @@ typedef struct dt_module {
 	dt_idhash_t *dm_extern;	/* external symbol definitions */
 #if !defined(sun)
 	caddr_t dm_reloc_offset;	/* Symbol relocation offset. */
+	uintptr_t *dm_sec_offsets;
 #endif
 } dt_module_t;
 

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c	Fri Jul 23 17:21:23 2010	(r210424)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c	Fri Jul 23 17:32:47 2010	(r210425)
@@ -83,6 +83,14 @@ dt_module_syminit32(dt_module_t *dmp)
 	uint_t i, n = dmp->dm_nsymelems;
 	uint_t asrsv = 0;
 
+#if defined(__FreeBSD__)
+	GElf_Ehdr ehdr;
+	int is_elf_obj;
+
+	gelf_getehdr(dmp->dm_elf, &ehdr);
+	is_elf_obj = (ehdr.e_type == ET_REL);
+#endif
+
 	for (i = 0; i < n; i++, sym++) {
 		const char *name = base + sym->st_name;
 		uchar_t type = ELF32_ST_TYPE(sym->st_info);
@@ -97,8 +105,12 @@ dt_module_syminit32(dt_module_t *dmp)
 		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
 			asrsv++; /* reserve space in the address map */
 
-#if !defined(sun)
+#if defined(__FreeBSD__)
 			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
+			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
+			    sym->st_shndx < ehdr.e_shnum)
+				sym->st_value +=
+				    dmp->dm_sec_offsets[sym->st_shndx];
 #endif
 		}
 
@@ -117,6 +129,14 @@ dt_module_syminit64(dt_module_t *dmp)
 	uint_t i, n = dmp->dm_nsymelems;
 	uint_t asrsv = 0;
 
+#if defined(__FreeBSD__)
+	GElf_Ehdr ehdr;
+	int is_elf_obj;
+
+	gelf_getehdr(dmp->dm_elf, &ehdr);
+	is_elf_obj = (ehdr.e_type == ET_REL);
+#endif
+
 	for (i = 0; i < n; i++, sym++) {
 		const char *name = base + sym->st_name;
 		uchar_t type = ELF64_ST_TYPE(sym->st_info);
@@ -130,9 +150,12 @@ dt_module_syminit64(dt_module_t *dmp)
 		if (sym->st_value != 0 &&
 		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
 			asrsv++; /* reserve space in the address map */
-
-#if !defined(sun)
+#if defined(__FreeBSD__)
 			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
+			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
+			    sym->st_shndx < ehdr.e_shnum)
+				sym->st_value +=
+				    dmp->dm_sec_offsets[sym->st_shndx];
 #endif
 		}
 
@@ -722,7 +745,12 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_m
 		free(dmp->dm_asmap);
 		dmp->dm_asmap = NULL;
 	}
-
+#if defined(__FreeBSD__)
+	if (dmp->dm_sec_offsets != NULL) {
+		free(dmp->dm_sec_offsets);
+		dmp->dm_sec_offsets = NULL;
+	}
+#endif
 	dmp->dm_symfree = 0;
 	dmp->dm_nsymbuckets = 0;
 	dmp->dm_nsymelems = 0;
@@ -846,9 +874,12 @@ dt_module_update(dtrace_hdl_t *dtp, stru
 	(void) snprintf(fname, sizeof (fname),
 	    "%s/%s/object", OBJFS_ROOT, name);
 #else
+	GElf_Ehdr ehdr;
 	GElf_Phdr ph;
 	char name[MAXPATHLEN];
+	uintptr_t mapbase, alignmask;
 	int i = 0;
+	int is_elf_obj;
 
 	(void) strlcpy(name, k_stat->name, sizeof(name));
 	(void) strlcpy(fname, k_stat->pathname, sizeof(fname));
@@ -893,7 +924,20 @@ dt_module_update(dtrace_hdl_t *dtp, stru
 		dt_module_destroy(dtp, dmp);
 		return;
 	}
-
+#if defined(__FreeBSD__)
+	mapbase = (uintptr_t)k_stat->address;
+	gelf_getehdr(dmp->dm_elf, &ehdr);
+	is_elf_obj = (ehdr.e_type == ET_REL);
+	if (is_elf_obj) {
+		dmp->dm_sec_offsets =
+		    malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets));
+		if (dmp->dm_sec_offsets == NULL) {
+			dt_dprintf("failed to allocate memory\n");
+			dt_module_destroy(dtp, dmp);
+			return;
+		}
+	}
+#endif
 	/*
 	 * Iterate over the section headers locating various sections of
 	 * interest and use their attributes to flesh out the dt_module_t.
@@ -902,7 +946,19 @@ dt_module_update(dtrace_hdl_t *dtp, stru
 		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
 		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
 			continue; /* skip any malformed sections */
-
+#if defined(__FreeBSD__)
+		if (sh.sh_size == 0)
+			continue;
+		if (is_elf_obj && (sh.sh_type == SHT_PROGBITS ||
+		    sh.sh_type == SHT_NOBITS)) {
+			alignmask = sh.sh_addralign - 1;
+			mapbase += alignmask;
+			mapbase &= ~alignmask;
+			sh.sh_addr = mapbase;
+			dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
+			mapbase += sh.sh_size;
+		}
+#endif
 		if (strcmp(s, ".text") == 0) {
 			dmp->dm_text_size = sh.sh_size;
 			dmp->dm_text_va = sh.sh_addr;
@@ -927,6 +983,13 @@ dt_module_update(dtrace_hdl_t *dtp, stru
 #if defined(sun)
 	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
 #else
+	/*
+	 * Include .rodata and special sections into .text.
+	 * This depends on default section layout produced by GNU ld
+	 * for ELF objects and libraries:
+	 * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable]
+	 */
+	dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va;
 #if defined(__i386__)
 	/*
 	 * Find the first load section and figure out the relocation


More information about the svn-src-head mailing list