Print this page
4474 DTrace Userland CTF Support
4475 DTrace userland Keyword
4476 DTrace tests should be better citizens
4479 pid provider types
4480 dof emulation missing checks
Reviewed by: Bryan Cantrill <bryan@joyent.com>

@@ -21,25 +21,30 @@
 
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #include <assert.h>
 #include <strings.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
 #include <alloca.h>
 #include <libgen.h>
 #include <stddef.h>
+#include <sys/sysmacros.h>
 
 #include <dt_impl.h>
 #include <dt_program.h>
 #include <dt_pid.h>
 #include <dt_string.h>
+#include <dt_module.h>
 
 typedef struct dt_pid_probe {
         dtrace_hdl_t *dpp_dtp;
         dt_pcb_t *dpp_pcb;
         dt_proc_t *dpp_dpr;

@@ -753,5 +758,164 @@
                 (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
         }
 
         return (ret);
 }
+
+/*
+ * libdtrace has a backroom deal with us to ask us for type information on
+ * behalf of pid provider probes when fasttrap doesn't return any type
+ * information. Instead we'll look up the module and see if there is type
+ * information available. However, if there is no type information available due
+ * to a lack of CTF data, then we want to make sure that DTrace still carries on
+ * in face of that. As such we don't have a meaningful exit code about failure.
+ * We emit information about why we failed to the dtrace debug log so someone
+ * can figure it out by asking nicely for DTRACE_DEBUG.
+ */
+void
+dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
+    dtrace_argdesc_t *adp, int *nargs)
+{
+        dt_module_t *dmp;
+        ctf_file_t *fp;
+        ctf_funcinfo_t f;
+        ctf_id_t argv[32];
+        GElf_Sym sym;
+        prsyminfo_t si;
+        struct ps_prochandle *p;
+        int i, args;
+        char buf[DTRACE_ARGTYPELEN];
+        const char *mptr;
+        char *eptr;
+        int ret = 0;
+        int argc = sizeof (argv) / sizeof (ctf_id_t);
+        Lmid_t lmid;
+
+        /* Set up a potential outcome */
+        args = *nargs;
+        *nargs = 0;
+
+        /*
+         * If we don't have an entry or return probe then we can just stop right
+         * now as we don't have arguments for offset probes.
+         */
+        if (strcmp(pdp->dtpd_name, "entry") != 0 &&
+            strcmp(pdp->dtpd_name, "return") != 0)
+                return;
+
+        dmp = dt_module_create(dtp, pdp->dtpd_provider);
+        if (dmp == NULL) {
+                dt_dprintf("failed to find module for %s\n",
+                    pdp->dtpd_provider);
+                return;
+        }
+        if (dt_module_load(dtp, dmp) != 0) {
+                dt_dprintf("failed to load module for %s\n",
+                    pdp->dtpd_provider);
+                return;
+        }
+
+        /*
+         * We may be working with a module that doesn't have ctf. If that's the
+         * case then we just return now and move on with life.
+         */
+        fp = dt_module_getctflib(dtp, dmp, pdp->dtpd_mod);
+        if (fp == NULL) {
+                dt_dprintf("no ctf container for  %s\n",
+                    pdp->dtpd_mod);
+                return;
+        }
+        p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
+        if (p == NULL) {
+                dt_dprintf("failed to grab pid\n");
+                return;
+        }
+        dt_proc_lock(dtp, p);
+
+        /*
+         * Check to see if the D module has a link map ID and separate that out
+         * for properly interrogating libproc.
+         */
+        if ((mptr = strchr(pdp->dtpd_mod, '`')) != NULL) {
+                if (strlen(pdp->dtpd_mod) < 3) {
+                        dt_dprintf("found weird modname with linkmap, "
+                            "aborting: %s\n", pdp->dtpd_mod);
+                        goto out;
+                }
+                if (pdp->dtpd_mod[0] != 'L' || pdp->dtpd_mod[1] != 'M') {
+                        dt_dprintf("missing leading 'LM', "
+                            "aborting: %s\n", pdp->dtpd_mod);
+                        goto out;
+                }
+                errno = 0;
+                lmid = strtol(pdp->dtpd_mod + 2, &eptr, 16);
+                if (errno == ERANGE || eptr != mptr) {
+                        dt_dprintf("failed to parse out lmid, aborting: %s\n",
+                            pdp->dtpd_mod);
+                        goto out;
+                }
+                mptr++;
+        } else {
+                mptr = pdp->dtpd_mod;
+                lmid = 0;
+        }
+
+        if (Pxlookup_by_name(p, lmid, mptr, pdp->dtpd_func,
+            &sym, &si) != 0) {
+                dt_dprintf("failed to find function %s in %s`%s\n",
+                    pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+                goto out;
+        }
+        if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) {
+                dt_dprintf("failed to get ctf information for %s in %s`%s\n",
+                    pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+                goto out;
+        }
+
+        (void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider,
+            pdp->dtpd_mod);
+
+        if (strcmp(pdp->dtpd_name, "return") == 0) {
+                if (args < 2)
+                        goto out;
+
+                bzero(adp, sizeof (dtrace_argdesc_t));
+                adp->dtargd_ndx = 0;
+                adp->dtargd_id = pdp->dtpd_id;
+                adp->dtargd_mapping = adp->dtargd_ndx;
+                /*
+                 * We explicitly leave out the library here, we only care that
+                 * it is some int. We are assuming that there is no ctf
+                 * container in here that is lying about what an int is.
+                 */
+                (void) snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+                    "user %s`%s", pdp->dtpd_provider, "int");
+                adp++;
+                bzero(adp, sizeof (dtrace_argdesc_t));
+                adp->dtargd_ndx = 1;
+                adp->dtargd_id = pdp->dtpd_id;
+                adp->dtargd_mapping = adp->dtargd_ndx;
+                ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+                    "userland ");
+                (void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native +
+                    ret, DTRACE_ARGTYPELEN - ret, buf);
+                *nargs = 2;
+        } else {
+                if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR)
+                        goto out;
+
+                *nargs = MIN(args, f.ctc_argc);
+                for (i = 0; i < *nargs; i++, adp++) {
+                        bzero(adp, sizeof (dtrace_argdesc_t));
+                        adp->dtargd_ndx = i;
+                        adp->dtargd_id = pdp->dtpd_id;
+                        adp->dtargd_mapping = adp->dtargd_ndx;
+                        ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+                            "userland ");
+                        (void) ctf_type_qname(fp, argv[i], adp->dtargd_native +
+                            ret, DTRACE_ARGTYPELEN - ret, buf);
+                }
+        }
+out:
+        dt_proc_unlock(dtp, p);
+        dt_proc_release(dtp, p);
+}