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>

*** 20,29 **** --- 20,32 ---- */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ + /* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <sys/types.h> #include <sys/modctl.h> #include <sys/kobj.h> #include <sys/kobj_impl.h>
*** 416,425 **** --- 419,431 ---- }; dt_module_t * dt_module_create(dtrace_hdl_t *dtp, const char *name) { + long pid; + char *eptr; + dt_ident_t *idp; uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0)
*** 439,448 **** --- 445,480 ---- if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) dmp->dm_ops = &dt_modops_64; else dmp->dm_ops = &dt_modops_32; + /* + * Modules for userland processes are special. They always refer to a + * specific process and have a copy of their CTF data from a specific + * instant in time. Any dt_module_t that begins with 'pid' is a module + * for a specific process, much like how any probe description that + * begins with 'pid' is special. pid123 refers to process 123. A module + * that is just 'pid' refers specifically to pid$target. This is + * generally done as D does not currently allow for macros to be + * evaluated when working with types. + */ + if (strncmp(dmp->dm_name, "pid", 3) == 0) { + errno = 0; + if (dmp->dm_name[3] == '\0') { + idp = dt_idhash_lookup(dtp->dt_macros, "target"); + if (idp != NULL && idp->di_id != 0) + dmp->dm_pid = idp->di_id; + } else { + pid = strtol(dmp->dm_name + 3, &eptr, 10); + if (errno == 0 && *eptr == '\0') + dmp->dm_pid = (pid_t)pid; + else + dt_dprintf("encountered malformed pid " + "module: %s\n", dmp->dm_name); + } + } + return (dmp); } dt_module_t * dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name)
*** 502,517 **** --- 534,706 ---- dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size); return (0); } + typedef struct dt_module_cb_arg { + struct ps_prochandle *dpa_proc; + dtrace_hdl_t *dpa_dtp; + dt_module_t *dpa_dmp; + uint_t dpa_count; + } dt_module_cb_arg_t; + + /* ARGSUSED */ + static int + dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj) + { + ctf_file_t *fp; + dt_module_cb_arg_t *dcp = arg; + + /* Try to grab a ctf container if it exists */ + fp = Pname_to_ctf(dcp->dpa_proc, obj); + if (fp != NULL) + dcp->dpa_count++; + return (0); + } + + /* ARGSUSED */ + static int + dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj) + { + ctf_file_t *fp; + char buf[MAXPATHLEN], *p; + dt_module_cb_arg_t *dcp = arg; + int count = dcp->dpa_count; + Lmid_t lmid; + + fp = Pname_to_ctf(dcp->dpa_proc, obj); + if (fp == NULL) + return (0); + fp = ctf_dup(fp); + if (fp == NULL) + return (0); + dcp->dpa_dmp->dm_libctfp[count] = fp; + /* + * While it'd be nice to simply use objname here, because of our prior + * actions we'll always get a resolved object name to its on disk file. + * Like the pid provider, we need to tell a bit of a lie here. The type + * that the user thinks of is in terms of the libraries they requested, + * eg. libc.so.1, they don't care about the fact that it's + * libc_hwcap.so.1. + */ + (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf)); + if ((p = strrchr(buf, '/')) == NULL) + p = buf; + else + p++; + + /* + * If for some reason we can't find a link map id for this module, which + * would be really quite weird. We instead just say the link map id is + * zero. + */ + if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0) + lmid = 0; + + if (lmid == 0) + dcp->dpa_dmp->dm_libctfn[count] = strdup(p); + else + (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count], + "LM%lx`%s", lmid, p); + if (dcp->dpa_dmp->dm_libctfn[count] == NULL) + return (1); + ctf_setspecific(fp, dcp->dpa_dmp); + dcp->dpa_count++; + return (0); + } + + /* + * We've been asked to load data that belongs to another process. As such we're + * going to pgrab it at this instant, load everything that we might ever care + * about, and then drive on. The reason for this is that the process that we're + * interested in might be changing. As long as we have grabbed it, then this + * can't be a problem for us. + * + * For now, we're actually going to punt on most things and just try to get CTF + * data, nothing else. Basically this is only useful as a source of type + * information, we can't go and do the stacktrace lookups, etc. + */ + static int + dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp) + { + struct ps_prochandle *p; + dt_module_cb_arg_t arg; + + /* + * Note that on success we do not release this hold. We must hold this + * for our life time. + */ + p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE); + if (p == NULL) { + dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + dt_proc_lock(dtp, p); + + arg.dpa_proc = p; + arg.dpa_dtp = dtp; + arg.dpa_dmp = dmp; + arg.dpa_count = 0; + if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) { + dt_dprintf("failed to iterate objects\n"); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + + if (arg.dpa_count == 0) { + dt_dprintf("no ctf data present\n"); + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + + dmp->dm_libctfp = malloc(sizeof (ctf_file_t *) * arg.dpa_count); + if (dmp->dm_libctfp == NULL) { + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_NOMEM)); + } + bzero(dmp->dm_libctfp, sizeof (ctf_file_t *) * arg.dpa_count); + + dmp->dm_libctfn = malloc(sizeof (char *) * arg.dpa_count); + if (dmp->dm_libctfn == NULL) { + free(dmp->dm_libctfp); + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_NOMEM)); + } + bzero(dmp->dm_libctfn, sizeof (char *) * arg.dpa_count); + + dmp->dm_nctflibs = arg.dpa_count; + + arg.dpa_count = 0; + if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) { + dt_proc_unlock(dtp, p); + dt_module_unload(dtp, dmp); + dt_proc_release(dtp, p); + return (dt_set_errno(dtp, EDT_CANTLOAD)); + } + assert(arg.dpa_count == dmp->dm_nctflibs); + dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count, + (int)dmp->dm_pid); + + dt_proc_unlock(dtp, p); + dt_proc_release(dtp, p); + dmp->dm_flags |= DT_DM_LOADED; + + return (0); + } + int dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) { if (dmp->dm_flags & DT_DM_LOADED) return (0); /* module is already loaded */ + if (dmp->dm_pid != 0) + return (dt_module_load_proc(dtp, dmp)); + dmp->dm_ctdata.cts_name = ".SUNW_ctf"; dmp->dm_ctdata.cts_type = SHT_PROGBITS; dmp->dm_ctdata.cts_flags = 0; dmp->dm_ctdata.cts_data = NULL; dmp->dm_ctdata.cts_size = 0;
*** 593,602 **** --- 782,799 ---- dmp->dm_flags |= DT_DM_LOADED; return (0); } + int + dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp) + { + if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0) + return (1); + return (dt_module_getctf(dtp, dmp) != NULL); + } + ctf_file_t * dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp) { const char *parent; dt_module_t *pmp;
*** 666,678 **** --- 863,888 ---- /*ARGSUSED*/ void dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) { + int i; + ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; + if (dmp->dm_libctfp != NULL) { + for (i = 0; i < dmp->dm_nctflibs; i++) { + ctf_close(dmp->dm_libctfp[i]); + free(dmp->dm_libctfn[i]); + } + free(dmp->dm_libctfp); + free(dmp->dm_libctfn); + dmp->dm_libctfp = NULL; + dmp->dm_nctflibs = 0; + } + bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); if (dmp->dm_symbuckets != NULL) {
*** 709,718 **** --- 919,930 ---- } (void) elf_end(dmp->dm_elf); dmp->dm_elf = NULL; + dmp->dm_pid = 0; + dmp->dm_flags &= ~DT_DM_LOADED; } void dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
*** 797,806 **** --- 1009,1046 ---- return ("64-bit"); else return ("32-bit"); } + /* ARGSUSED */ + int + dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp) + { + int i; + + for (i = 0; i < dmp->dm_nctflibs; i++) { + if (dmp->dm_libctfp[i] == fp) + return (i); + } + + return (-1); + } + + /* ARGSUSED */ + ctf_file_t * + dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name) + { + int i; + + for (i = 0; i < dmp->dm_nctflibs; i++) { + if (strcmp(dmp->dm_libctfn[i], name) == 0) + return (dmp->dm_libctfp[i]); + } + + return (NULL); + } + /* * Update our module cache by adding an entry for the specified module 'name'. * We create the dt_module_t and populate it using /system/object/<name>/. */ static void
*** 1138,1149 **** { dtrace_typeinfo_t ti; dt_module_t *dmp; int found = 0; ctf_id_t id; ! uint_t n; int justone; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY && --- 1378,1391 ---- { dtrace_typeinfo_t ti; dt_module_t *dmp; int found = 0; ctf_id_t id; ! uint_t n, i; int justone; + ctf_file_t *fp; + char *buf, *p, *q; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY &&
*** 1154,1164 **** if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ n = 1; justone = 1; - } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; else if (object == DTRACE_OBJ_UMODS) mask = DT_DM_KERNEL; --- 1396,1405 ----
*** 1178,1188 **** /* * If we can't load the CTF container, continue on to the next * module. If our search was scoped to only one module then * return immediately leaving dt_errno unmodified. */ ! if (dt_module_getctf(dtp, dmp) == NULL) { if (justone) return (-1); continue; } --- 1419,1429 ---- /* * If we can't load the CTF container, continue on to the next * module. If our search was scoped to only one module then * return immediately leaving dt_errno unmodified. */ ! if (dt_module_hasctf(dtp, dmp) == 0) { if (justone) return (-1); continue; }
*** 1190,1206 **** * Look up the type in the module's CTF container. If our * match is a forward declaration tag, save this choice in * 'tip' and keep going in the hope that we will locate the * underlying structure definition. Otherwise just return. */ ! if ((id = ctf_lookup_by_name(dmp->dm_ctfp, name)) != CTF_ERR) { tip->dtt_object = dmp->dm_name; ! tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = id; ! ! if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve( ! dmp->dm_ctfp, id)) != CTF_K_FORWARD) return (0); found++; } } --- 1431,1472 ---- * Look up the type in the module's CTF container. If our * match is a forward declaration tag, save this choice in * 'tip' and keep going in the hope that we will locate the * underlying structure definition. Otherwise just return. */ ! if (dmp->dm_pid == 0) { ! id = ctf_lookup_by_name(dmp->dm_ctfp, name); ! fp = dmp->dm_ctfp; ! } else { ! if ((p = strchr(name, '`')) != NULL) { ! buf = strdup(name); ! if (buf == NULL) ! return (dt_set_errno(dtp, EDT_NOMEM)); ! p = strchr(buf, '`'); ! if ((q = strchr(p + 1, '`')) != NULL) ! p = q; ! *p = '\0'; ! fp = dt_module_getctflib(dtp, dmp, buf); ! if (fp == NULL || (id = ctf_lookup_by_name(fp, ! p + 1)) == CTF_ERR) ! id = CTF_ERR; ! free(buf); ! } else { ! for (i = 0; i < dmp->dm_nctflibs; i++) { ! fp = dmp->dm_libctfp[i]; ! id = ctf_lookup_by_name(fp, name); ! if (id != CTF_ERR) ! break; ! } ! } ! } ! if (id != CTF_ERR) { tip->dtt_object = dmp->dm_name; ! tip->dtt_ctfp = fp; tip->dtt_type = id; ! if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) != ! CTF_K_FORWARD) return (0); found++; } }
*** 1218,1227 **** --- 1484,1494 ---- dt_module_t *dmp; tip->dtt_object = NULL; tip->dtt_ctfp = NULL; tip->dtt_type = CTF_ERR; + tip->dtt_flags = 0; if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) return (dt_set_errno(dtp, EDT_NOMOD)); if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {