Author: markj
Date: Thu Sep 11 01:04:56 2014
New Revision: 271413
URL: http://svnweb.freebsd.org/changeset/base/271413

Log:
  Use the linker to perform relocations in the SUNW_dof section rather than
  doing them in drti during startup. This fixes a number of problems with
  using USDT probes in stripped executables and shared libraries, and with
  USDT probes in static functions.
  
  Reviewed by:  rpaulo
  MFC after:    1 month
  Sponsored by: EMC / Isilon Storage Division
  Phabric:      D751

Modified:
  head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c   Thu Sep 11 
00:10:54 2014        (r271412)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c   Thu Sep 11 
01:04:56 2014        (r271413)
@@ -90,36 +90,6 @@ dprintf(int debug, const char *fmt, ...)
        va_end(ap);
 }
 
-#if !defined(sun)
-static void
-fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
-    dof_sec_t *sec, int *fixedprobes, char *dofstrtab)
-{
-       GElf_Sym sym;
-       char *s;
-       unsigned char *funcname;
-       dof_probe_t *prb;
-       int j = 0;
-       int ndx;
-
-       while (gelf_getsym(data, j++, &sym) != NULL) {
-               prb = (dof_probe_t *)(void *)(buf + sec->dofs_offset);
-
-               for (ndx = nprobes; ndx; ndx--, prb += 1) {
-                       funcname = dofstrtab + prb->dofpr_func;
-                       s = elf_strptr(e, idx, sym.st_name);
-                       if (strcmp(s, funcname) == 0) {
-                               dprintf(1, "fixing %s() symbol\n", s);
-                               prb->dofpr_addr = sym.st_value;
-                               (*fixedprobes)++;
-                       }
-               }
-               if (*fixedprobes == nprobes)
-                       break;
-       }
-}
-#endif
-
 #if defined(sun)
 #pragma init(dtrace_dof_init)
 #else
@@ -145,9 +115,6 @@ dtrace_dof_init(void)
        Lmid_t lmid;
 #else
        u_long lmid = 0;
-       dof_sec_t *sec, *secstart, *dofstrtab, *dofprobes;
-       dof_provider_t *dofprovider;
-       size_t i;
 #endif
        int fd;
        const char *p;
@@ -157,12 +124,9 @@ dtrace_dof_init(void)
        Elf_Data *symtabdata = NULL, *dynsymdata = NULL, *dofdata = NULL;
        dof_hdr_t *dof_next = NULL;
        GElf_Shdr shdr;
-       int efd, nprobes;
+       int efd;
        char *s;
-       char *dofstrtabraw;
        size_t shstridx, symtabidx = 0, dynsymidx = 0;
-       unsigned char *buf;
-       int fixedprobes;
 #endif
 
        if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
@@ -183,7 +147,6 @@ dtrace_dof_init(void)
        }
 #endif
 
-
        if ((modname = strrchr(lmp->l_name, '/')) == NULL)
                modname = lmp->l_name;
        else
@@ -209,9 +172,9 @@ dtrace_dof_init(void)
                } else if (shdr.sh_type == SHT_DYNSYM) {
                        dynsymidx = shdr.sh_link;
                        dynsymdata = elf_getdata(scn, NULL);
-               } else if (shdr.sh_type == SHT_PROGBITS) {
+               } else if (shdr.sh_type == SHT_SUNW_dof) {
                        s = elf_strptr(e, shstridx, shdr.sh_name);
-                       if  (s && strcmp(s, ".SUNW_dof") == 0) {
+                       if  (s != NULL && strcmp(s, ".SUNW_dof") == 0) {
                                dofdata = elf_getdata(scn, NULL);
                                dof = dofdata->d_buf;
                        }
@@ -225,7 +188,6 @@ dtrace_dof_init(void)
        }
 
        while ((char *) dof < (char *) dofdata->d_buf + dofdata->d_size) {
-               fixedprobes = 0;
                dof_next = (void *) ((char *) dof + dof->dofh_filesz);
 #endif
 
@@ -273,76 +235,6 @@ dtrace_dof_init(void)
                return;
 #endif
        }
-#if !defined(sun)
-       /*
-        * We need to fix the base address of each probe since this wasn't
-        * done by ld(1). (ld(1) needs to grow support for parsing the
-        * SUNW_dof section).
-        *
-        * The complexity of this is not that great. The first for loop
-        * iterates over the sections inside the DOF file. There are usually
-        * 10 sections here. We asume the STRTAB section comes first and the
-        * PROBES section comes after. Since we are only interested in fixing
-        * data inside the PROBES section we quit the for loop after processing
-        * the PROBES section. It's usually the case that the first section
-        * is the STRTAB section and the second section is the PROBES section,
-        * so this for loop is not meaningful when doing complexity analysis.
-        *
-        * After finding the probes section, we iterate over the symbols
-        * in the symtab section. When we find a symbol name that matches
-        * the probe function name, we fix it. If we have fixed all the
-        * probes, we exit all the loops and we are done.
-        * The number of probes is given by the variable 'nprobes' and this
-        * depends entirely on the user, but some optimizations were done.
-        *
-        * We are assuming the number of probes is less than the number of
-        * symbols (libc can have 4k symbols, for example).
-        */
-       secstart = sec = (dof_sec_t *)(dof + 1);
-       buf = (char *)dof;
-       for (i = 0; i < dof->dofh_secnum; i++, sec++) {
-               if (sec->dofs_type != DOF_SECT_PROVIDER)
-                       continue;
-
-               dofprovider = (void *) (buf + sec->dofs_offset);
-               dofstrtab = secstart + dofprovider->dofpv_strtab;
-               dofprobes = secstart + dofprovider->dofpv_probes;
-
-               if (dofstrtab->dofs_type != DOF_SECT_STRTAB) {
-                       fprintf(stderr, "WARNING: expected STRTAB section, but 
got %d\n",
-                                       dofstrtab->dofs_type);
-                       break;
-               }
-               if (dofprobes->dofs_type != DOF_SECT_PROBES) {
-                       fprintf(stderr, "WARNING: expected PROBES section, but 
got %d\n",
-                           dofprobes->dofs_type);
-                       break;
-               }
-
-               dprintf(1, "found provider %p\n", dofprovider);
-               dofstrtabraw = (char *)(buf + dofstrtab->dofs_offset);
-               nprobes = dofprobes->dofs_size / dofprobes->dofs_entsize;
-               fixsymbol(e, symtabdata, symtabidx, nprobes, buf, dofprobes, 
&fixedprobes,
-                               dofstrtabraw);
-               if (fixedprobes != nprobes) {
-                       /*
-                        * If we haven't fixed all the probes using the
-                        * symtab section, look inside the dynsym
-                        * section.
-                        */
-                       fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, 
dofprobes,
-                                       &fixedprobes, dofstrtabraw);
-               }
-               if (fixedprobes != nprobes) {
-                       fprintf(stderr, "WARNING: number of probes "
-                           "fixed does not match the number of "
-                           "defined probes (%d != %d, "
-                           "respectively)\n", fixedprobes, nprobes);
-                       fprintf(stderr, "WARNING: some probes might "
-                           "not fire or your program might crash\n");
-               }
-       }
-#endif
        if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
                dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
        else {

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c        Thu Sep 
11 00:10:54 2014        (r271412)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c        Thu Sep 
11 01:04:56 2014        (r271413)
@@ -322,7 +322,11 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
        char *strtab;
        int i, j, nrel;
        size_t strtabsz = 1;
+#if defined(sun)
        uint32_t count = 0;
+#else
+       uint64_t count = 0;
+#endif
        size_t base;
        Elf64_Sym *sym;
        Elf64_Rela *rel;
@@ -418,7 +422,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
                s = &dofs[dofrh->dofr_tgtsec];
 
                for (j = 0; j < nrel; j++) {
-#ifdef DOODAD
 #if defined(__arm__)
 /* XXX */
 #elif defined(__mips__)
@@ -431,8 +434,13 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 #elif defined(__i386) || defined(__amd64)
                        rel->r_offset = s->dofs_offset +
                            dofr[j].dofr_offset;
+#if defined(sun)
                        rel->r_info = ELF64_R_INFO(count + dep->de_global,
                            R_AMD64_64);
+#else
+                       rel->r_info = ELF64_R_INFO(count + dep->de_global,
+                           R_X86_64_RELATIVE);
+#endif
 #elif defined(__sparc)
                        rel->r_offset = s->dofs_offset +
                            dofr[j].dofr_offset;
@@ -441,7 +449,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 #else
 #error unknown ISA
 #endif
-#endif
 
                        sym->st_name = base + dofr[j].dofr_name - 1;
                        sym->st_value = 0;
@@ -704,7 +711,11 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_
 
        shp = &elf_file.shdr[ESHDR_DOF];
        shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */
+#if defined(sun)
        shp->sh_flags = SHF_ALLOC;
+#else
+       shp->sh_flags = SHF_WRITE | SHF_ALLOC;
+#endif
        shp->sh_type = SHT_SUNW_dof;
        shp->sh_offset = off;
        shp->sh_size = dof->dofh_filesz;
@@ -1662,19 +1673,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
 {
 #if !defined(sun)
        char tfile[PATH_MAX];
-       Elf *e;
-       Elf_Scn *scn;
-       Elf_Data *data;
-       GElf_Shdr shdr;
-       int efd;
-       size_t stridx;
-       unsigned char *buf;
-       char *s;
-       int loc;
-       GElf_Ehdr ehdr;
-       Elf_Scn *scn0;
-       GElf_Shdr shdr0;
-       uint64_t off, rc;
 #endif
        char drti[PATH_MAX];
        dof_hdr_t *dof;
@@ -1810,21 +1808,22 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
                (void) unlink(file);
 #endif
 
-#if defined(sun)
        if (dtp->dt_oflags & DTRACE_O_LP64)
                status = dump_elf64(dtp, dof, fd);
        else
                status = dump_elf32(dtp, dof, fd);
 
+#if defined(sun)
        if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
                return (dt_link_error(dtp, NULL, -1, NULL,
                    "failed to write %s: %s", file, strerror(errno)));
        }
 #else
-       /* We don't write the ELF header, just the DOF section */
-       if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
+       (void)close(fd);
+       if (status != 0)
                return (dt_link_error(dtp, NULL, -1, NULL,
-                   "failed to write %s: %s", tfile, strerror(errno)));
+                   "failed to write %s: %s", tfile,
+                   strerror(dtrace_errno(dtp))));
 #endif
 
        if (!dtp->dt_lazyload) {
@@ -1846,7 +1845,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
 
                (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
 #else
-               const char *fmt = "%s -o %s -r %s";
+               const char *fmt = "%s -o %s -r %s %s";
 
 #if defined(__amd64__)
                /*
@@ -1868,10 +1867,9 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
                len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
                    drti) + 1;
 
-               len *= 2;
                cmd = alloca(len);
 
-               (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
+               (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile,
                    drti);
 #endif
                if ((status = system(cmd)) == -1) {
@@ -1894,85 +1892,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
                            file, dtp->dt_ld_path, WEXITSTATUS(status));
                        goto done;
                }
-#if !defined(sun)
-               /*
-                * FreeBSD's ld(1) is not instructed to interpret and add
-                * correctly the SUNW_dof section present in tfile.
-                * We use libelf to add this section manually and hope the next
-                * ld invocation won't remove it.
-                */
-               elf_version(EV_CURRENT);
-               if ((efd = open(file, O_RDWR, 0)) < 0) {
-                       ret = dt_link_error(dtp, NULL, -1, NULL,
-                           "failed to open file %s: %s",
-                           file, strerror(errno));
-                       goto done;
-               }
-               if ((e = elf_begin(efd, ELF_C_RDWR, NULL)) == NULL) {
-                       close(efd);
-                       ret = dt_link_error(dtp, NULL, -1, NULL,
-                           "failed to open elf file: %s",
-                           elf_errmsg(elf_errno()));
-                       goto done;
-               }
-               /*
-                * Add the string '.SUWN_dof' to the shstrtab section.
-                */
-               elf_getshdrstrndx(e, &stridx);
-               scn = elf_getscn(e, stridx);
-               gelf_getshdr(scn, &shdr);
-               data = elf_newdata(scn);
-               data->d_off = shdr.sh_size;
-               data->d_buf = ".SUNW_dof";
-               data->d_size = 10;
-               data->d_type = ELF_T_BYTE;
-               loc = shdr.sh_size;
-               shdr.sh_size += data->d_size;
-               gelf_update_shdr(scn, &shdr);
-               /*
-                * Construct the .SUNW_dof section.
-                */
-               scn = elf_newscn(e);
-               data = elf_newdata(scn);
-               buf = mmap(NULL, dof->dofh_filesz, PROT_READ, MAP_SHARED,
-                   fd, 0);
-               if (buf == MAP_FAILED) {
-                       ret = dt_link_error(dtp, NULL, -1, NULL,
-                           "failed to mmap buffer %s", strerror(errno));
-                       elf_end(e);
-                       close(efd);
-                       goto done;
-               }
-               data->d_buf = buf;
-               data->d_align = 4;
-               data->d_size = dof->dofh_filesz;
-               data->d_version = EV_CURRENT;
-               gelf_getshdr(scn, &shdr);
-               shdr.sh_name = loc;
-               shdr.sh_flags = SHF_ALLOC;
-               /*
-                * Actually this should be SHT_SUNW_dof, but FreeBSD's ld(1)
-                * will remove this 'unknown' section when we try to create an
-                * executable using the object we are modifying, so we stop
-                * playing by the rules and use SHT_PROGBITS.
-                * Also, note that our drti has modifications to handle this.
-                */
-               shdr.sh_type = SHT_PROGBITS;
-               shdr.sh_addralign = 4;
-               gelf_update_shdr(scn, &shdr);
-               if (elf_update(e, ELF_C_WRITE) < 0) {
-                       ret = dt_link_error(dtp, NULL, -1, NULL,
-                           "failed to add the SUNW_dof section: %s",
-                           elf_errmsg(elf_errno()));
-                       munmap(buf, dof->dofh_filesz);
-                       elf_end(e);
-                       close(efd);
-                       goto done;
-               }
-               munmap(buf, dof->dofh_filesz);
-               elf_end(e);
-               close(efd);
-#endif
                (void) close(fd); /* release temporary file */
        } else {
                (void) close(fd);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to