summaryrefslogtreecommitdiffstats
path: root/cddl
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2010-07-23 17:32:47 +0000
committeravg <avg@FreeBSD.org>2010-07-23 17:32:47 +0000
commit50e1a73d601b113e166d994bff65fb997f547c7e (patch)
tree84bb6df88456e37065778474ca6f68dd4589b2e1 /cddl
parente702b156d5207a8b61360c3cc17e5805301f7b52 (diff)
downloadFreeBSD-src-50e1a73d601b113e166d994bff65fb997f547c7e.zip
FreeBSD-src-50e1a73d601b113e166d994bff65fb997f547c7e.tar.gz
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
Diffstat (limited to 'cddl')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h1
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c75
2 files changed, 70 insertions, 6 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
index 6bcc5bc..a712d24 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -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;
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
index af17501..d33fb95 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
@@ -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_module_t *dmp)
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, struct kld_file_stat *k_stat)
(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, struct kld_file_stat *k_stat)
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, struct kld_file_stat *k_stat)
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, struct kld_file_stat *k_stat)
#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
OpenPOWER on IntegriCloud