Here's a patch that is supposed to do the right thing for dtrace.
Perhaps I should have put the new code under __amd64__, but I decided to go more
"generic" and check for module's ELF type (ET_REL).

Reviews and testing are welcome!

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

-- 
Andriy Gapon
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"

Reply via email to