sync with FreeBSD

This commit is contained in:
christos 2015-09-24 14:25:29 +00:00
parent 2cd1ca309f
commit c0855460da
48 changed files with 5299 additions and 1542 deletions

View File

@ -20,6 +20,7 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Copyright 2013 Voxer Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -34,6 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libelf.h>
/*
* In Solaris 10 GA, the only mechanism for communicating helper information
@ -53,7 +55,9 @@
*/
static const char *devnamep = "/dev/dtrace/helper";
#ifdef illumos
static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
#endif
static const char *modname; /* Name of this load object */
static int gen; /* DOF helper generation */
@ -83,7 +87,7 @@ dprintf(int debug, const char *fmt, ...)
va_end(ap);
}
#if defined(sun)
#ifdef illumos
#pragma init(dtrace_dof_init)
#else
static void dtrace_dof_init(void) __attribute__ ((constructor));
@ -99,11 +103,10 @@ dtrace_dof_init(void)
Elf32_Ehdr *elf;
#endif
dof_helper_t dh;
#if defined(sun)
Link_map *lmp;
Link_map *lmp = NULL;
#ifdef illumos
Lmid_t lmid;
#else
struct link_map *lmp;
u_long lmid = 0;
#endif
int fd;
@ -120,7 +123,7 @@ dtrace_dof_init(void)
return;
}
#if defined(sun)
#ifdef illumos
if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
dprintf(1, "couldn't discover link map ID\n");
return;
@ -144,6 +147,9 @@ dtrace_dof_init(void)
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
#if defined(__FreeBSD__) || defined(__NetBSD__)
dh.dofhp_pid = getpid();
#endif
if (lmid == 0) {
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
@ -158,7 +164,7 @@ dtrace_dof_init(void)
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
#ifdef illumos
/*
* If the device path wasn't explicitly set, try again with
* the old device path.
@ -172,17 +178,23 @@ dtrace_dof_init(void)
dprintf(1, "failed to open helper device %s", devnamep);
return;
}
#else
return;
#endif
}
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
else
else {
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
#if defined(__FreeBSD__) || defined(__NetBSD__)
gen = dh.dofhp_gen;
#endif
}
(void) close(fd);
}
#if defined(sun)
#ifdef illumos
#pragma fini(dtrace_dof_fini)
#else
static void dtrace_dof_fini(void) __attribute__ ((destructor));
@ -198,7 +210,7 @@ dtrace_dof_fini(void)
return;
}
if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
else
dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);

View File

@ -24,7 +24,10 @@
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <stdlib.h>
#include <strings.h>
@ -32,10 +35,13 @@
#include <unistd.h>
#include <dt_impl.h>
#include <assert.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#else
#include <sys/sysctl.h>
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <libproc_compat.h>
#endif
#endif
#include <limits.h>
@ -208,6 +214,83 @@ dt_aggregate_lquantizedcmp(int64_t *lhs, int64_t *rhs)
return (0);
}
static void
dt_aggregate_llquantize(int64_t *existing, int64_t *new, size_t size)
{
int i;
for (i = 1; i < size / sizeof (int64_t); i++)
existing[i] = existing[i] + new[i];
}
static long double
dt_aggregate_llquantizedsum(int64_t *llquanta)
{
int64_t arg = *llquanta++;
uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(arg);
uint16_t low = DTRACE_LLQUANTIZE_LOW(arg);
uint16_t high = DTRACE_LLQUANTIZE_HIGH(arg);
uint16_t nsteps = DTRACE_LLQUANTIZE_NSTEP(arg);
int bin = 0, order;
int64_t value = 1, next, step;
long double total;
assert(nsteps >= factor);
assert(nsteps % factor == 0);
for (order = 0; order < low; order++)
value *= factor;
total = (long double)llquanta[bin++] * (long double)(value - 1);
next = value * factor;
step = next > nsteps ? next / nsteps : 1;
while (order <= high) {
assert(value < next);
total += (long double)llquanta[bin++] * (long double)(value);
if ((value += step) != next)
continue;
next = value * factor;
step = next > nsteps ? next / nsteps : 1;
order++;
}
return (total + (long double)llquanta[bin] * (long double)value);
}
static int
dt_aggregate_llquantizedcmp(int64_t *lhs, int64_t *rhs)
{
long double lsum = dt_aggregate_llquantizedsum(lhs);
long double rsum = dt_aggregate_llquantizedsum(rhs);
int64_t lzero, rzero;
if (lsum < rsum)
return (DT_LESSTHAN);
if (lsum > rsum)
return (DT_GREATERTHAN);
/*
* If they're both equal, then we will compare based on the weights at
* zero. If the weights at zero are equal, then this will be judged a
* tie and will be resolved based on the key comparison.
*/
lzero = lhs[1];
rzero = rhs[1];
if (lzero < rzero)
return (DT_LESSTHAN);
if (lzero > rzero)
return (DT_GREATERTHAN);
return (0);
}
static int
dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs)
{
@ -251,7 +334,6 @@ dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs)
static void
dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
{
#if 0 /* XXX TBD needs libproc */
uint64_t pid = data[0];
uint64_t *pc = &data[1];
struct ps_prochandle *P;
@ -265,24 +347,16 @@ dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
dt_proc_lock(dtp, P);
#if defined(sun)
if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
#else
if (proc_addr2sym(P, *pc, NULL, 0, &sym) == 0)
#endif
*pc = sym.st_value;
dt_proc_unlock(dtp, P);
dt_proc_release(dtp, P);
#else
printf("XXX %s not implemented\n", __func__);
#endif
}
static void
dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
{
#if 0 /* XXX TBD needs libproc */
uint64_t pid = data[0];
uint64_t *pc = &data[1];
struct ps_prochandle *P;
@ -296,18 +370,11 @@ dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
dt_proc_lock(dtp, P);
#if defined(sun)
if ((map = Paddr_to_map(P, *pc)) != NULL)
#else
if ((map = proc_addr2map(P, *pc)) != NULL)
#endif
*pc = map->pr_vaddr;
dt_proc_unlock(dtp, P);
dt_proc_release(dtp, P);
#else
printf("XXX %s not implemented\n", __func__);
#endif
}
static void
@ -388,7 +455,7 @@ dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
buf->dtbd_cpu = cpu;
#if defined(sun)
#ifdef illumos
if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) {
#else
if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, &buf) == -1) {
@ -415,15 +482,15 @@ dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
return (0);
if (hash->dtah_hash == NULL) {
size_t size1;
size_t size;
hash->dtah_size = DTRACE_AHASHSIZE;
size1 = hash->dtah_size * sizeof (dt_ahashent_t *);
size = hash->dtah_size * sizeof (dt_ahashent_t *);
if ((hash->dtah_hash = malloc(size1)) == NULL)
if ((hash->dtah_hash = malloc(size)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
bzero(hash->dtah_hash, size1);
bzero(hash->dtah_hash, size);
}
for (offs = 0; offs < buf->dtbd_size; ) {
@ -607,6 +674,10 @@ hashnext:
h->dtahe_aggregate = dt_aggregate_lquantize;
break;
case DTRACEAGG_LLQUANTIZE:
h->dtahe_aggregate = dt_aggregate_llquantize;
break;
case DTRACEAGG_COUNT:
case DTRACEAGG_SUM:
case DTRACEAGG_AVG:
@ -671,8 +742,8 @@ dtrace_aggregate_snap(dtrace_hdl_t *dtp)
static int
dt_aggregate_hashcmp(const void *lhs, const void *rhs)
{
dt_ahashent_t *lh = *((dt_ahashent_t **)__UNCONST(lhs));
dt_ahashent_t *rh = *((dt_ahashent_t **)__UNCONST(rhs));
dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
@ -688,8 +759,8 @@ dt_aggregate_hashcmp(const void *lhs, const void *rhs)
static int
dt_aggregate_varcmp(const void *lhs, const void *rhs)
{
dt_ahashent_t *lh = *((dt_ahashent_t **)__UNCONST(lhs));
dt_ahashent_t *rh = *((dt_ahashent_t **)__UNCONST(rhs));
dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
dtrace_aggvarid_t lid, rid;
lid = dt_aggregate_aggvarid(lh);
@ -707,16 +778,16 @@ dt_aggregate_varcmp(const void *lhs, const void *rhs)
static int
dt_aggregate_keycmp(const void *lhs, const void *rhs)
{
dt_ahashent_t *lh = *((dt_ahashent_t **)__UNCONST(lhs));
dt_ahashent_t *rh = *((dt_ahashent_t **)__UNCONST(rhs));
dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
dtrace_recdesc_t *lrec, *rrec;
char *ldata, *rdata;
int rval1, i, j, keypos, nrecs;
int rval, i, j, keypos, nrecs;
if ((rval1 = dt_aggregate_hashcmp(lhs, rhs)) != 0)
return (rval1);
if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
return (rval);
nrecs = lagg->dtagd_nrecs - 1;
assert(nrecs == ragg->dtagd_nrecs - 1);
@ -818,41 +889,22 @@ dt_aggregate_keycmp(const void *lhs, const void *rhs)
static int
dt_aggregate_valcmp(const void *lhs, const void *rhs)
{
dt_ahashent_t *lh = *((dt_ahashent_t **)__UNCONST(lhs));
dt_ahashent_t *rh = *((dt_ahashent_t **)__UNCONST(rhs));
dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
caddr_t ldata = lh->dtahe_data.dtada_data;
caddr_t rdata = rh->dtahe_data.dtada_data;
dtrace_recdesc_t *lrec = NULL, *rrec = NULL;
dtrace_recdesc_t *lrec, *rrec;
int64_t *laddr, *raddr;
int rval, i;
int rval;
if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
return (rval);
assert(lagg->dtagd_nrecs == ragg->dtagd_nrecs);
if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
return (DT_GREATERTHAN);
lrec = &lagg->dtagd_rec[lagg->dtagd_nrecs - 1];
rrec = &ragg->dtagd_rec[ragg->dtagd_nrecs - 1];
if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
return (DT_LESSTHAN);
for (i = 0; i < lagg->dtagd_nrecs; i++) {
lrec = &lagg->dtagd_rec[i];
rrec = &ragg->dtagd_rec[i];
if (lrec->dtrd_offset < rrec->dtrd_offset)
return (DT_LESSTHAN);
if (lrec->dtrd_offset > rrec->dtrd_offset)
return (DT_GREATERTHAN);
if (lrec->dtrd_action < rrec->dtrd_action)
return (DT_LESSTHAN);
if (lrec->dtrd_action > rrec->dtrd_action)
return (DT_GREATERTHAN);
}
assert(lrec->dtrd_action == rrec->dtrd_action);
laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset);
raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset);
@ -874,6 +926,10 @@ dt_aggregate_valcmp(const void *lhs, const void *rhs)
rval = dt_aggregate_lquantizedcmp(laddr, raddr);
break;
case DTRACEAGG_LLQUANTIZE:
rval = dt_aggregate_llquantizedcmp(laddr, raddr);
break;
case DTRACEAGG_COUNT:
case DTRACEAGG_SUM:
case DTRACEAGG_MIN:
@ -975,8 +1031,8 @@ dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs)
static int
dt_aggregate_bundlecmp(const void *lhs, const void *rhs)
{
dt_ahashent_t **lh = *((dt_ahashent_t ***)__UNCONST(lhs));
dt_ahashent_t **rh = *((dt_ahashent_t ***)__UNCONST(rhs));
dt_ahashent_t **lh = *((dt_ahashent_t ***)lhs);
dt_ahashent_t **rh = *((dt_ahashent_t ***)rhs);
int i, rval;
if (dt_keysort) {
@ -1074,7 +1130,6 @@ dt_aggregate_go(dtrace_hdl_t *dtp)
if (dt_status(dtp, i) == -1)
continue;
assert(agp->dtat_ncpus < agp->dtat_ncpu);
agp->dtat_cpus[agp->dtat_ncpus++] = i;
}
@ -1247,6 +1302,231 @@ dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg)
return (0);
}
static int
dt_aggregate_total(dtrace_hdl_t *dtp, boolean_t clear)
{
dt_ahashent_t *h;
dtrace_aggdata_t **total;
dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
dt_aggregate_t *agp = &dtp->dt_aggregate;
dt_ahash_t *hash = &agp->dtat_hash;
uint32_t tflags;
tflags = DTRACE_A_TOTAL | DTRACE_A_HASNEGATIVES | DTRACE_A_HASPOSITIVES;
/*
* If we need to deliver per-aggregation totals, we're going to take
* three passes over the aggregate: one to clear everything out and
* determine our maximum aggregation ID, one to actually total
* everything up, and a final pass to assign the totals to the
* individual elements.
*/
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data;
if ((id = dt_aggregate_aggvarid(h)) > max)
max = id;
aggdata->dtada_total = 0;
aggdata->dtada_flags &= ~tflags;
}
if (clear || max == DTRACE_AGGVARIDNONE)
return (0);
total = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
if (total == NULL)
return (-1);
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
dtrace_recdesc_t *rec;
caddr_t data;
int64_t val, *addr;
rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
data = aggdata->dtada_data;
addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
switch (rec->dtrd_action) {
case DTRACEAGG_STDDEV:
val = dt_stddev((uint64_t *)addr, 1);
break;
case DTRACEAGG_SUM:
case DTRACEAGG_COUNT:
val = *addr;
break;
case DTRACEAGG_AVG:
val = addr[0] ? (addr[1] / addr[0]) : 0;
break;
default:
continue;
}
if (total[agg->dtagd_varid] == NULL) {
total[agg->dtagd_varid] = aggdata;
aggdata->dtada_flags |= DTRACE_A_TOTAL;
} else {
aggdata = total[agg->dtagd_varid];
}
if (val > 0)
aggdata->dtada_flags |= DTRACE_A_HASPOSITIVES;
if (val < 0) {
aggdata->dtada_flags |= DTRACE_A_HASNEGATIVES;
val = -val;
}
if (dtp->dt_options[DTRACEOPT_AGGZOOM] != DTRACEOPT_UNSET) {
val = (int64_t)((long double)val *
(1 / DTRACE_AGGZOOM_MAX));
if (val > aggdata->dtada_total)
aggdata->dtada_total = val;
} else {
aggdata->dtada_total += val;
}
}
/*
* And now one final pass to set everyone's total.
*/
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data, *t;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
if ((t = total[agg->dtagd_varid]) == NULL || aggdata == t)
continue;
aggdata->dtada_total = t->dtada_total;
aggdata->dtada_flags |= (t->dtada_flags & tflags);
}
dt_free(dtp, total);
return (0);
}
static int
dt_aggregate_minmaxbin(dtrace_hdl_t *dtp, boolean_t clear)
{
dt_ahashent_t *h;
dtrace_aggdata_t **minmax;
dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
dt_aggregate_t *agp = &dtp->dt_aggregate;
dt_ahash_t *hash = &agp->dtat_hash;
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data;
if ((id = dt_aggregate_aggvarid(h)) > max)
max = id;
aggdata->dtada_minbin = 0;
aggdata->dtada_maxbin = 0;
aggdata->dtada_flags &= ~DTRACE_A_MINMAXBIN;
}
if (clear || max == DTRACE_AGGVARIDNONE)
return (0);
minmax = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
if (minmax == NULL)
return (-1);
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
dtrace_recdesc_t *rec;
caddr_t data;
int64_t *addr;
int minbin = -1, maxbin = -1, i;
int start = 0, size;
rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
size = rec->dtrd_size / sizeof (int64_t);
data = aggdata->dtada_data;
addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
switch (rec->dtrd_action) {
case DTRACEAGG_LQUANTIZE:
/*
* For lquantize(), we always display the entire range
* of the aggregation when aggpack is set.
*/
start = 1;
minbin = start;
maxbin = size - 1 - start;
break;
case DTRACEAGG_QUANTIZE:
for (i = start; i < size; i++) {
if (!addr[i])
continue;
if (minbin == -1)
minbin = i - start;
maxbin = i - start;
}
if (minbin == -1) {
/*
* If we have no data (e.g., due to a clear()
* or negative increments), we'll use the
* zero bucket as both our min and max.
*/
minbin = maxbin = DTRACE_QUANTIZE_ZEROBUCKET;
}
break;
default:
continue;
}
if (minmax[agg->dtagd_varid] == NULL) {
minmax[agg->dtagd_varid] = aggdata;
aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
aggdata->dtada_minbin = minbin;
aggdata->dtada_maxbin = maxbin;
continue;
}
if (minbin < minmax[agg->dtagd_varid]->dtada_minbin)
minmax[agg->dtagd_varid]->dtada_minbin = minbin;
if (maxbin > minmax[agg->dtagd_varid]->dtada_maxbin)
minmax[agg->dtagd_varid]->dtada_maxbin = maxbin;
}
/*
* And now one final pass to set everyone's minbin and maxbin.
*/
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
dtrace_aggdata_t *aggdata = &h->dtahe_data, *mm;
dtrace_aggdesc_t *agg = aggdata->dtada_desc;
if ((mm = minmax[agg->dtagd_varid]) == NULL || aggdata == mm)
continue;
aggdata->dtada_minbin = mm->dtada_minbin;
aggdata->dtada_maxbin = mm->dtada_maxbin;
aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
}
dt_free(dtp, minmax);
return (0);
}
static int
dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
dtrace_aggregate_f *func, void *arg,
@ -1256,6 +1536,23 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
dt_ahashent_t *h, **sorted;
dt_ahash_t *hash = &agp->dtat_hash;
size_t i, nentries = 0;
int rval = -1;
agp->dtat_flags &= ~(DTRACE_A_TOTAL | DTRACE_A_MINMAXBIN);
if (dtp->dt_options[DTRACEOPT_AGGHIST] != DTRACEOPT_UNSET) {
agp->dtat_flags |= DTRACE_A_TOTAL;
if (dt_aggregate_total(dtp, B_FALSE) != 0)
return (-1);
}
if (dtp->dt_options[DTRACEOPT_AGGPACK] != DTRACEOPT_UNSET) {
agp->dtat_flags |= DTRACE_A_MINMAXBIN;
if (dt_aggregate_minmaxbin(dtp, B_FALSE) != 0)
return (-1);
}
for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
nentries++;
@ -1263,7 +1560,7 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
if (sorted == NULL)
return (-1);
goto out;
for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
sorted[i++] = h;
@ -1287,14 +1584,20 @@ dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
for (i = 0; i < nentries; i++) {
h = sorted[i];
if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) {
dt_free(dtp, sorted);
return (-1);
}
if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
goto out;
}
rval = 0;
out:
if (agp->dtat_flags & DTRACE_A_TOTAL)
(void) dt_aggregate_total(dtp, B_TRUE);
if (agp->dtat_flags & DTRACE_A_MINMAXBIN)
(void) dt_aggregate_minmaxbin(dtp, B_TRUE);
dt_free(dtp, sorted);
return (0);
return (rval);
}
int
@ -1504,9 +1807,9 @@ dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
*/
for (i = 0; i < naggvars; i++) {
if (zaggdata[i].dtahe_size == 0) {
dtrace_aggvarid_t aggvar1;
dtrace_aggvarid_t aggvar;
aggvar1 = aggvars[(i - sortpos + naggvars) % naggvars];
aggvar = aggvars[(i - sortpos + naggvars) % naggvars];
assert(zaggdata[i].dtahe_data.dtada_data == NULL);
for (j = DTRACE_AGGIDNONE + 1; ; j++) {
@ -1516,7 +1819,7 @@ dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
if (dt_aggid_lookup(dtp, j, &agg) != 0)
break;
if (agg->dtagd_varid != aggvar1)
if (agg->dtagd_varid != aggvar)
continue;
/*
@ -1537,7 +1840,7 @@ dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
}
if (zaggdata[i].dtahe_size == 0) {
caddr_t data1;
caddr_t data;
/*
* We couldn't find this aggregation, meaning
@ -1558,8 +1861,8 @@ dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
assert(j < naggvars);
zaggdata[i] = zaggdata[j];
data1 = zaggdata[i].dtahe_data.dtada_data;
assert(data1 != NULL);
data = zaggdata[i].dtahe_data.dtada_data;
assert(data != NULL);
}
}
}
@ -1817,6 +2120,8 @@ dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
{
dt_print_aggdata_t pd;
bzero(&pd, sizeof (pd));
pd.dtpa_dtp = dtp;
pd.dtpa_fp = fp;
pd.dtpa_allunprint = 1;

View File

@ -23,8 +23,10 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <strings.h>
@ -125,7 +127,7 @@ dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
dvp->dtdv_flags |= DIFV_F_MOD;
bzero(&dn, sizeof (dn));
dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type);
dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type, B_FALSE);
dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);
idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
@ -257,10 +259,10 @@ dt_as(dt_pcb_t *pcb)
kbits = ubits = -1u;
break;
default:
xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
dtp->dt_linkmode);
kmask = umask = 0;
kbits = ubits = -1u;
xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
dtp->dt_linkmode);
}
assert(pcb->pcb_difo == NULL);
@ -428,9 +430,12 @@ dt_as(dt_pcb_t *pcb)
if ((idp = dip->di_extern) == NULL)
continue; /* no relocation entry needed */
/*###431 [cc] error: 'kbits' may be used uninitialized in this function [-Werror=maybe-uninitialized]%%%*/
if ((idp->di_flags & kmask) == kbits) {
nodef = knodef;
rp = krp++;
/*###434 [cc] error: 'ubits' may be used uninitialized in this function [-Werror=maybe-uninitialized]%%%*/
/*###434 [cc] error: 'umask' may be used uninitialized in this function [-Werror=maybe-uninitialized]%%%*/
} else if ((idp->di_flags & umask) == ubits) {
nodef = unodef;
rp = urp++;

View File

@ -20,12 +20,11 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* DTrace D Language Compiler
*
@ -85,6 +84,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sysmacros.h>
#include <assert.h>
#include <string.h>
@ -663,19 +663,76 @@ dt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
static void
dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
int ctflib = 0; // XXX: gcc
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE);
const char *act = istrace ? "trace" : "print";
if (dt_node_is_void(dnp->dn_args)) {
dnerror(dnp->dn_args, D_TRACE_VOID,
"trace( ) may not be applied to a void expression\n");
dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID,
"%s( ) may not be applied to a void expression\n", act);
}
if (dt_node_is_dynamic(dnp->dn_args)) {
dnerror(dnp->dn_args, D_TRACE_DYN,
"trace( ) may not be applied to a dynamic expression\n");
if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) {
dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN,
"%s( ) may not be applied to a translated pointer\n", act);
}
if (dnp->dn_args->dn_kind == DT_NODE_AGG) {
dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG,
"%s( ) may not be applied to an aggregation%s\n", act,
istrace ? "" : " -- did you mean printa()?");
}
dt_cg(yypcb, dnp->dn_args);
/*
* The print() action behaves identically to trace(), except that it
* stores the CTF type of the argument (if present) within the DOF for
* the DIFEXPR action. To do this, we set the 'dtsd_strdata' to point
* to the fully-qualified CTF type ID for the result of the DIF
* action. We use the ID instead of the name to handles complex types
* like arrays and function pointers that can't be resolved by
* ctf_type_lookup(). This is later processed by dtrace_dof_create()
* and turned into a reference into the string table so that we can
* get the type information when we process the data after the fact. In
* the case where we are referring to userland CTF data, we also need to
* to identify which ctf container in question we care about and encode
* that within the name.
*/
if (dnp->dn_ident->di_id == DT_ACT_PRINT) {
dt_node_t *dret;
size_t n;
dt_module_t *dmp;
dret = yypcb->pcb_dret;
dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
if (dmp->dm_pid != 0) {
ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp);
assert(ctflib >= 0);
n = snprintf(NULL, 0, "%s`%d`%ld", dmp->dm_name,
ctflib, dret->dn_type) + 1;
} else {
n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name,
dret->dn_type) + 1;
}
sdp->dtsd_strdata = dt_alloc(dtp, n);
if (sdp->dtsd_strdata == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", dmp->dm_name,
dret->dn_type);
if (dmp->dm_pid != 0) {
(void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld",
dmp->dm_name, ctflib, dret->dn_type);
} else {
(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld",
dmp->dm_name, dret->dn_type);
}
}
ap->dtad_difo = dt_as(yypcb);
ap->dtad_kind = DTRACEACT_DIFEXPR;
}
@ -686,7 +743,8 @@ dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
dt_node_t *addr = dnp->dn_args;
dt_node_t *size = dnp->dn_args->dn_list;
dt_node_t *max = dnp->dn_args->dn_list;
dt_node_t *size;
char n[DT_TYPE_NAMELEN];
@ -698,17 +756,37 @@ dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
dt_node_type_name(addr, n, sizeof (n)));
}
if (dt_node_is_posconst(size) == 0) {
dnerror(size, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
if (dt_node_is_posconst(max) == 0) {
dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
"be a non-zero positive integral constant expression\n");
}
if ((size = max->dn_list) != NULL) {
if (size->dn_list != NULL) {
dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "
"mismatch: expected at most 3 args\n");
}
if (!dt_node_is_scalar(size)) {
dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "
"dynamic size (argument #3) must be of "
"scalar type\n");
}
dt_cg(yypcb, size);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_difo->dtdo_rtype = dt_int_rtype;
ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;
ap = dt_stmt_action(dtp, sdp);
}
dt_cg(yypcb, addr);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_kind = DTRACEACT_DIFEXPR;
ap->dtad_kind = DTRACEACT_TRACEMEM;
ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value;
ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;
}
static void
@ -1079,6 +1157,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_PANIC:
dt_action_panic(dtp, dnp->dn_expr, sdp);
break;
case DT_ACT_PRINT:
dt_action_trace(dtp, dnp->dn_expr, sdp);
break;
case DT_ACT_PRINTA:
dt_action_printa(dtp, dnp->dn_expr, sdp);
break;
@ -1372,6 +1453,146 @@ dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
argmax = 5;
}
if (fid->di_id == DTRACEAGG_LLQUANTIZE) {
/*
* For log/linear quantizations, we have between one and five
* arguments in addition to the expression:
*
* arg1 => Factor
* arg2 => Low magnitude
* arg3 => High magnitude
* arg4 => Number of steps per magnitude
* arg5 => Quantization increment value (defaults to 1)
*/
dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list;
uint64_t oarg, order, v;
dt_idsig_t *isp;
int i;
struct {
char *str; /* string identifier */
int badtype; /* error on bad type */
int badval; /* error on bad value */
int mismatch; /* error on bad match */
int shift; /* shift value */
uint16_t value; /* value itself */
} args[] = {
{ "factor", D_LLQUANT_FACTORTYPE,
D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH,
DTRACE_LLQUANTIZE_FACTORSHIFT },
{ "low magnitude", D_LLQUANT_LOWTYPE,
D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH,
DTRACE_LLQUANTIZE_LOWSHIFT },
{ "high magnitude", D_LLQUANT_HIGHTYPE,
D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH,
DTRACE_LLQUANTIZE_HIGHSHIFT },
{ "linear steps per magnitude", D_LLQUANT_NSTEPTYPE,
D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH,
DTRACE_LLQUANTIZE_NSTEPSHIFT },
{ NULL }
};
assert(arg == 0);
for (i = 0; args[i].str != NULL; i++) {
if (llarg->dn_kind != DT_NODE_INT) {
dnerror(llarg, args[i].badtype, "llquantize( ) "
"argument #%d (%s) must be an "
"integer constant\n", i + 1, args[i].str);
}
if ((uint64_t)llarg->dn_value > UINT16_MAX) {
dnerror(llarg, args[i].badval, "llquantize( ) "
"argument #%d (%s) must be an unsigned "
"16-bit quantity\n", i + 1, args[i].str);
}
args[i].value = (uint16_t)llarg->dn_value;
assert(!(arg & ((uint64_t)UINT16_MAX <<
args[i].shift)));
arg |= ((uint64_t)args[i].value << args[i].shift);
llarg = llarg->dn_list;
}
assert(arg != 0);
if (args[0].value < 2) {
dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) "
"factor (argument #1) must be two or more\n");
}
if (args[1].value >= args[2].value) {
dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) "
"high magnitude (argument #3) must be greater "
"than low magnitude (argument #2)\n");
}
if (args[3].value < args[0].value) {
dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) "
"factor (argument #1) must be less than or "
"equal to the number of linear steps per "
"magnitude (argument #4)\n");
}
for (v = args[0].value; v < args[3].value; v *= args[0].value)
continue;
if ((args[3].value % args[0].value) || (v % args[3].value)) {
dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) "
"factor (argument #1) must evenly divide the "
"number of steps per magnitude (argument #4), "
"and the number of steps per magnitude must evenly "
"divide a power of the factor\n");
}
for (i = 0, order = 1; i < args[2].value; i++) {
if (order * args[0].value > order) {
order *= args[0].value;
continue;
}
dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) "
"factor (%d) raised to power of high magnitude "
"(%d) overflows 64-bits\n", args[0].value,
args[2].value);
}
isp = (dt_idsig_t *)aid->di_data;
if (isp->dis_auxinfo == 0) {
/*
* This is the first time we've seen an llquantize()
* for this aggregation; we'll store our argument
* as the auxiliary signature information.
*/
isp->dis_auxinfo = arg;
} else if ((oarg = isp->dis_auxinfo) != arg) {
/*
* If we have seen this llquantize() before and the
* argument doesn't match the original argument, pick
* the original argument apart to concisely report the
* mismatch.
*/
int expected = 0, found = 0;
for (i = 0; expected == found; i++) {
assert(args[i].str != NULL);
expected = (oarg >> args[i].shift) & UINT16_MAX;
found = (arg >> args[i].shift) & UINT16_MAX;
}
dnerror(dnp, args[i - 1].mismatch, "llquantize( ) "
"%s (argument #%d) doesn't match previous "
"declaration: expected %d, found %d\n",
args[i - 1].str, i, expected, found);
}
incr = llarg;
argmax = 6;
}
if (fid->di_id == DTRACEAGG_QUANTIZE) {
incr = dnp->dn_aggfun->dn_args->dn_list;
argmax = 2;
@ -1667,7 +1888,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
char **argv = malloc(sizeof (char *) * (argc + 5));
FILE *ofp = tmpfile();
#if defined(sun)
#ifdef illumos
char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */
#endif
char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */
@ -1677,7 +1898,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
int wstat, estat;
pid_t pid;
#if defined(sun)
#ifdef illumos
off64_t off;
#else
off_t off = 0;
@ -1708,7 +1929,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
(void) fseeko64(ifp, off, SEEK_SET);
}
#if defined(sun)
#ifdef illumos
(void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d", fileno(ifp));
(void) snprintf(opath, sizeof (opath), "/dev/fd/%d", fileno(ofp));
#endif
@ -1719,7 +1940,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
"-D__SUNW_D_VERSION=0x%08x", dtp->dt_vmax);
argv[argc++] = verdef;
#if defined(sun)
#ifdef illumos
switch (dtp->dt_stdcmode) {
case DT_STDC_XA:
case DT_STDC_XT:
@ -1733,7 +1954,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
argv[argc++] = ipath;
argv[argc++] = opath;
#else
argv[argc++] = __UNCONST("-P");
argv[argc++] = "-P";
#endif
argv[argc] = NULL;
@ -1761,7 +1982,7 @@ dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)
}
if (pid == 0) {
#if !defined(sun)
#ifndef illumos
if (isatty(fileno(ifp)) == 0)
lseek(fileno(ifp), off, SEEK_SET);
dup2(fileno(ifp), 0);
@ -2012,25 +2233,23 @@ dt_lib_depend_free(dtrace_hdl_t *dtp)
}
}
/*
* Open all of the .d library files found in the specified directory and
* compile each one in topological order to cache its inlines and translators,
* etc. We silently ignore any missing directories and other files found
* therein. We only fail (and thereby fail dt_load_libs()) if we fail to
* compile a library and the error is something other than #pragma D depends_on.
* Dependency errors are silently ignored to permit a library directory to
* contain libraries which may not be accessible depending on our privileges.
* Open all the .d library files found in the specified directory and
* compile each one of them. We silently ignore any missing directories and
* other files found therein. We only fail (and thereby fail dt_load_libs()) if
* we fail to compile a library and the error is something other than #pragma D
* depends_on. Dependency errors are silently ignored to permit a library
* directory to contain libraries which may not be accessible depending on our
* privileges.
*/
static int
dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
{
struct dirent *dp;
const char *p;
const char *p, *end;
DIR *dirp;
char fname[PATH_MAX];
dtrace_prog_t *pgp;
FILE *fp;
void *rv;
dt_lib_depend_t *dld;
@ -2054,9 +2273,31 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
continue;
}
/*
* Skip files whose name match an already processed library
*/
for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
dld = dt_list_next(dld)) {
end = strrchr(dld->dtld_library, '/');
/* dt_lib_depend_add ensures this */
assert(end != NULL);
if (strcmp(end + 1, dp->d_name) == 0)
break;
}
if (dld != NULL) {
dt_dprintf("skipping library %s, already processed "
"library with the same name: %s", dp->d_name,
dld->dtld_library);
(void) fclose(fp);
continue;
}
dtp->dt_filetag = fname;
if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0)
goto err;
if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) {
(void) fclose(fp);
return (-1); /* preserve dt_errno */
}
rv = dt_compile(dtp, DT_CTX_DPROG,
DTRACE_PROBESPEC_NAME, NULL,
@ -2064,8 +2305,10 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
if (rv != NULL && dtp->dt_errno &&
(dtp->dt_errno != EDT_COMPILER ||
dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND)))
goto err;
dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) {
(void) fclose(fp);
return (-1); /* preserve dt_errno */
}
if (dtp->dt_errno)
dt_dprintf("error parsing library %s: %s\n",
@ -2076,6 +2319,27 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
}
(void) closedir(dirp);
return (0);
}
/*
* Perform a topological sorting of all the libraries found across the entire
* dt_lib_path. Once sorted, compile each one in topological order to cache its
* inlines and translators, etc. We silently ignore any missing directories and
* other files found therein. We only fail (and thereby fail dt_load_libs()) if
* we fail to compile a library and the error is something other than #pragma D
* depends_on. Dependency errors are silently ignored to permit a library
* directory to contain libraries which may not be accessible depending on our
* privileges.
*/
static int
dt_load_libs_sort(dtrace_hdl_t *dtp)
{
dtrace_prog_t *pgp;
FILE *fp;
dt_lib_depend_t *dld;
/*
* Finish building the graph containing the library dependencies
* and perform a topological sort to generate an ordered list
@ -2136,7 +2400,14 @@ dt_load_libs(dtrace_hdl_t *dtp)
dtp->dt_cflags |= DTRACE_C_NOLIBS;
for (dirp = dt_list_next(&dtp->dt_lib_path);
/*
* /usr/lib/dtrace is always at the head of the list. The rest of the
* list is specified in the precedence order the user requested. Process
* everything other than the head first. DTRACE_C_NOLIBS has already
* been spcified so dt_vopen will ensure that there is always one entry
* in dt_lib_path.
*/
for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path));
dirp != NULL; dirp = dt_list_next(dirp)) {
if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
@ -2144,6 +2415,16 @@ dt_load_libs(dtrace_hdl_t *dtp)
}
}
/* Handle /usr/lib/dtrace */
dirp = dt_list_next(&dtp->dt_lib_path);
if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
return (-1); /* errno is set for us */
}
if (dt_load_libs_sort(dtp) < 0)
return (-1); /* errno is set for us */
return (0);
}
@ -2154,7 +2435,7 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
dt_node_t *dnp;
dt_decl_t *ddp;
dt_pcb_t pcb;
void *rv = NULL;
void *rv = NULL; // XXX: gcc
int err;
if ((fp == NULL && s == NULL) || (cflags & ~DTRACE_C_MASK) != 0) {
@ -2165,11 +2446,11 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
if (dt_list_next(&dtp->dt_lib_path) != NULL && dt_load_libs(dtp) != 0)
return (NULL); /* errno is set for us */
(void) ctf_discard(dtp->dt_cdefs->dm_ctfp);
(void) ctf_discard(dtp->dt_ddefs->dm_ctfp);
if (dtp->dt_globals->dh_nelems != 0)
(void) dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL);
(void) dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL);
(void) dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL);
if (dtp->dt_tls->dh_nelems != 0)
(void) dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL);
if (fp && (cflags & DTRACE_C_CPP) && (fp = dt_preproc(dtp, fp)) == NULL)
return (NULL); /* errno is set for us */
@ -2295,7 +2576,8 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,
}
out:
if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 3))
if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL &&
DT_TREEDUMP_PASS(dtp, 3))
dt_node_printr(yypcb->pcb_root, stderr, 0);
if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 ||

View File

@ -19,12 +19,15 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
@ -193,9 +196,6 @@ dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
ssize_t size;
int sreg;
if ((sreg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
type = ctf_type_resolve(ctfp, dnp->dn_type);
kind = ctf_type_kind(ctfp, type);
assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
@ -212,6 +212,7 @@ dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
if ((size = ctf_type_size(ctfp, type)) == 1)
return; /* multiply or divide by one can be omitted */
sreg = dt_regset_alloc(drp);
dt_cg_setx(dlp, sreg, size);
instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -251,9 +252,7 @@ dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
r1 = dnp->dn_left->dn_reg;
if ((r2 = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
r2 = dt_regset_alloc(drp);
/*
* On little-endian architectures, ctm_offset counts from the right so
@ -356,10 +355,9 @@ dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp,
"bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
}
if ((r1 = dt_regset_alloc(drp)) == -1 ||
(r2 = dt_regset_alloc(drp)) == -1 ||
(r3 = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
r1 = dt_regset_alloc(drp);
r2 = dt_regset_alloc(drp);
r3 = dt_regset_alloc(drp);
/*
* Compute shifts and masks. We need to compute "shift" as the amount
@ -407,7 +405,7 @@ static void
dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
{
ctf_encoding_t e;
dif_instr_t instr = 0;
dif_instr_t instr;
size_t size;
int reg;
@ -423,8 +421,7 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
size = dt_node_type_size(src);
if (src->dn_flags & DT_NF_REF) {
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
reg = dt_regset_alloc(drp);
dt_cg_setx(dlp, reg, size);
instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -449,6 +446,7 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst)
instr = DIF_INSTR_STORE(DIF_OP_STX, reg, dst->dn_reg);
break;
default:
instr = 0;
xyerror(D_UNKNOWN, "internal error -- cg cannot store "
"size %lu when passed by value\n", (ulong_t)size);
}
@ -474,30 +472,58 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst,
size_t dstsize = dt_node_type_size(dst);
dif_instr_t instr;
int reg, n;
int rg;
if (dt_node_is_scalar(dst) && (dstsize < srcsize ||
(src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
if (!dt_node_is_scalar(dst))
return; /* not a scalar */
if (dstsize == srcsize &&
((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0)
return; /* not narrowing or changing signed-ness */
if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)
return; /* nothing to do in this case */
if (dstsize < srcsize)
n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
else
n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
rg = dt_regset_alloc(drp);
dt_cg_setx(dlp, reg, n);
if (dstsize > srcsize) {
int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
int s = (dstsize - srcsize) * NBBY;
instr = DIF_INSTR_FMT(DIF_OP_SLL,
src->dn_reg, reg, dst->dn_reg);
dt_cg_setx(dlp, rg, n);
instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {
instr = DIF_INSTR_FMT(DIF_OP_SRA,
dst->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, instr));
} else {
dt_cg_setx(dlp, rg, s);
instr = DIF_INSTR_FMT(DIF_OP_SRA,
dst->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, instr));
dt_cg_setx(dlp, rg, n - s);
instr = DIF_INSTR_FMT(DIF_OP_SRL,
dst->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, instr));
}
} else if (dstsize != sizeof (uint64_t)) {
int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
dt_cg_setx(dlp, rg, n);
instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg);
DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
dt_regset_free(drp, reg);
}
dt_regset_free(drp, rg);
}
/*
@ -523,8 +549,7 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
dt_cg_node(dnp, dlp, drp);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
dtrace_diftype_t t;
@ -538,17 +563,18 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args,
dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
isp->dis_args[i].dn_reg = -1;
if (t.dtdt_flags & DIF_TF_BYREF)
if (t.dtdt_flags & DIF_TF_BYREF) {
op = DIF_OP_PUSHTR;
else
if (t.dtdt_size != 0) {
reg = dt_regset_alloc(drp);
dt_cg_setx(dlp, reg, t.dtdt_size);
} else {
reg = DIF_REG_R0;
}
} else {
op = DIF_OP_PUSHTV;
if (t.dtdt_size != 0) {
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dt_cg_setx(dlp, reg, t.dtdt_size);
} else
reg = DIF_REG_R0;
}
instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -629,9 +655,7 @@ dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op)
dt_cg_node(dnp->dn_child, dlp, drp);
dnp->dn_reg = dnp->dn_child->dn_reg;
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
reg = dt_regset_alloc(drp);
dt_cg_setx(dlp, reg, size);
instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
@ -688,9 +712,7 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp,
dt_cg_node(dnp->dn_child, dlp, drp);
dnp->dn_reg = dnp->dn_child->dn_reg;
if ((nreg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
nreg = dt_regset_alloc(drp);
dt_cg_setx(dlp, nreg, size);
instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -1008,9 +1030,7 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
* set it to the size of our data structure, and then replace
* it with the result of an allocs of the specified size.
*/
if ((r1 = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
r1 = dt_regset_alloc(drp);
dt_cg_setx(dlp, r1,
ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
@ -1054,8 +1074,7 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
* and add r1 to it before storing the result.
*/
if (ctm.ctm_offset != 0) {
if ((r2 = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
r2 = dt_regset_alloc(drp);
/*
* Add the member offset rounded down to the
@ -1142,8 +1161,7 @@ dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
op = DIF_OP_LDTAA;
@ -1273,9 +1291,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
return;
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
reg = dt_regset_alloc(drp);
assert(size < sizeof (uint64_t));
n = sizeof (uint64_t) * NBBY - size * NBBY;
@ -1372,6 +1388,162 @@ dt_cg_func_typeref(dtrace_hdl_t *dtp, dt_node_t *dnp)
typs->dn_value = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type);
}
typedef struct dt_xlmemb {
dt_ident_t *dtxl_idp; /* translated ident */
dt_irlist_t *dtxl_dlp; /* instruction list */
dt_regset_t *dtxl_drp; /* register set */
int dtxl_sreg; /* location of the translation input */
int dtxl_dreg; /* location of our allocated buffer */
} dt_xlmemb_t;
/*ARGSUSED*/
static int
dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
{
dt_xlmemb_t *dx = arg;
dt_ident_t *idp = dx->dtxl_idp;
dt_irlist_t *dlp = dx->dtxl_dlp;
dt_regset_t *drp = dx->dtxl_drp;
dt_node_t *mnp;
dt_xlator_t *dxp;
int reg, treg;
uint32_t instr;
size_t size;
/* Generate code for the translation. */
dxp = idp->di_data;
mnp = dt_xlator_member(dxp, name);
/* If there's no translator for the given member, skip it. */
if (mnp == NULL)
return (0);
dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
dxp->dx_ident->di_id = dx->dtxl_sreg;
dt_cg_node(mnp->dn_membexpr, dlp, drp);
dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
dxp->dx_ident->di_id = 0;
treg = mnp->dn_membexpr->dn_reg;
/* Compute the offset into our buffer and store the result there. */
reg = dt_regset_alloc(drp);
dt_cg_setx(dlp, reg, off / NBBY);
instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,
mnp->dn_membexpr->dn_type);
if (dt_node_is_scalar(mnp->dn_membexpr)) {
/*
* Copying scalars is simple.
*/
switch (size) {
case 1:
instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);
break;
case 2:
instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);
break;
case 4:
instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);
break;
case 8:
instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);
break;
default:
xyerror(D_UNKNOWN, "internal error -- unexpected "
"size: %lu\n", (ulong_t)size);
}
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
} else if (dt_node_is_string(mnp->dn_membexpr)) {
int szreg;
/*
* Use the copys instruction for strings.
*/
szreg = dt_regset_alloc(drp);
dt_cg_setx(dlp, szreg, size);
instr = DIF_INSTR_COPYS(treg, szreg, reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
dt_regset_free(drp, szreg);
} else {
int szreg;
/*
* If it's anything else then we'll just bcopy it.
*/
szreg = dt_regset_alloc(drp);
dt_cg_setx(dlp, szreg, size);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
DIF_REG_R0, treg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
DIF_REG_R0, reg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
DIF_REG_R0, szreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
dt_regset_free(drp, szreg);
}
dt_regset_free(drp, reg);
dt_regset_free(drp, treg);
return (0);
}
/*
* If we're expanding a translated type, we create an appropriately sized
* buffer with alloca() and then translate each member into it.
*/
static int
dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,
dt_regset_t *drp)
{
dt_xlmemb_t dlm;
uint32_t instr;
int dreg;
size_t size;
dreg = dt_regset_alloc(drp);
size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);
/* Call alloca() to create the buffer. */
dt_cg_setx(dlp, dreg, size);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);
dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
/* Generate the translation for each member. */
dlm.dtxl_idp = idp;
dlm.dtxl_dlp = dlp;
dlm.dtxl_drp = drp;
dlm.dtxl_sreg = dnp->dn_reg;
dlm.dtxl_dreg = dreg;
(void) ctf_member_iter(dnp->dn_ident->di_ctfp,
dnp->dn_ident->di_type, dt_cg_xlate_member,
&dlm);
return (dreg);
}
static void
dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
@ -1384,7 +1556,6 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_ident_t *idp;
ssize_t stroff;
uint_t op;
int reg;
switch (dnp->dn_op) {
case DT_TOK_COMMA:
@ -1586,7 +1757,16 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_cg_node(dnp->dn_child, dlp, drp);
dnp->dn_reg = dnp->dn_child->dn_reg;
if (!(dnp->dn_flags & DT_NF_REF)) {
if (dt_node_is_dynamic(dnp->dn_child)) {
int reg;
idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);
assert(idp != NULL);
reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);
dt_regset_free(drp, dnp->dn_child->dn_reg);
dnp->dn_reg = reg;
} else if (!(dnp->dn_flags & DT_NF_REF)) {
uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
/*
@ -1622,10 +1802,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
case DT_TOK_SIZEOF: {
size_t size = dt_node_sizeof(dnp->dn_child);
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
assert(size != 0);
dt_cg_setx(dlp, dnp->dn_reg, size);
break;
@ -1650,8 +1827,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
assert(dxp->dx_ident->di_id != 0);
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
if (dxp->dx_arg == -1) {
instr = DIF_INSTR_MOV(
@ -1735,8 +1911,9 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
}
if (m.ctm_offset != 0) {
if ((reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
int reg;
reg = dt_regset_alloc(drp);
/*
* If the offset is not aligned on a byte boundary, it
@ -1782,8 +1959,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
break;
case DT_TOK_STRING:
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
assert(dnp->dn_kind == DT_NODE_STRING);
stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
@ -1806,8 +1982,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
*/
if (dnp->dn_kind == DT_NODE_VAR &&
(dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
dnp->dn_reg);
dt_irlist_append(dlp,
@ -1848,11 +2023,9 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
instr = DIF_INSTR_CALL(
dnp->dn_ident->di_id, dnp->dn_reg);
dnp->dn_reg = dt_regset_alloc(drp);
instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,
dnp->dn_reg);
dt_irlist_append(dlp,
dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -1880,8 +2053,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
break;
}
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
op = DIF_OP_LDLS;
@ -1911,9 +2083,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dtrace_errmsg(dtp, dtrace_errno(dtp)));
}
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
dt_cg_xsetx(dlp, dnp->dn_ident,
DT_LBL_NONE, dnp->dn_reg, sym.st_value);
@ -1933,9 +2103,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
break;
case DT_TOK_INT:
if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
dnp->dn_reg = dt_regset_alloc(drp);
dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
break;
@ -1949,7 +2117,8 @@ void
dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
{
dif_instr_t instr;
dt_xlator_t *dxp = NULL;
dt_xlator_t *dxp = NULL; // XXX: gcc
dt_ident_t *idp;
if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
@ -1976,9 +2145,9 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
assert(pcb->pcb_dret == NULL);
pcb->pcb_dret = dnp;
if (dt_node_is_dynamic(dnp)) {
if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {
dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
"of dynamic type\n");
"of a translated pointer\n");
}
/*
@ -1994,6 +2163,14 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
}
dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {
int reg = dt_cg_xlate_expand(dnp, idp,
&pcb->pcb_ir, pcb->pcb_regs);
dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
dnp->dn_reg = reg;
}
instr = DIF_INSTR_RET(dnp->dn_reg);
dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
@ -2003,4 +2180,7 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
dxp->dx_ident->di_id = 0;
dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
}
dt_regset_free(pcb->pcb_regs, 0);
dt_regset_assert_free(pcb->pcb_regs);
}

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -254,11 +256,6 @@ dt_decl_spec(ushort_t kind, char *name)
ddp->dd_kind = kind;
ddp->dd_name = name;
if (name != NULL && strchr(name, '`') != NULL) {
xyerror(D_DECL_SCOPE, "D scoping operator may not be used "
"in a type name\n");
}
return (dt_decl_check(ddp));
}
@ -783,7 +780,7 @@ dt_decl_enumerator(char *s, dt_node_t *dnp)
yyintdecimal = 0;
dnp = dt_node_int(value);
dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type);
dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type, B_FALSE);
if ((inp = malloc(sizeof (dt_idnode_t))) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
@ -825,6 +822,8 @@ dt_decl_type(dt_decl_t *ddp, dtrace_typeinfo_t *tip)
char *name;
int rv;
tip->dtt_flags = 0;
/*
* Based on our current #include depth and decl stack depth, determine
* which dynamic CTF module and scope to use when adding any new types.
@ -832,6 +831,9 @@ dt_decl_type(dt_decl_t *ddp, dtrace_typeinfo_t *tip)
dmp = yypcb->pcb_idepth ? dtp->dt_cdefs : dtp->dt_ddefs;
flag = yypcb->pcb_dstack.ds_next ? CTF_ADD_NONROOT : CTF_ADD_ROOT;
if (ddp->dd_attr & DT_DA_USER)
tip->dtt_flags = DTT_FL_USER;
/*
* If we have already cached a CTF type for this decl, then we just
* return the type information for the cached type.

View File

@ -23,12 +23,14 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#ifndef _DT_DECL_H
#define _DT_DECL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <libctf.h>
#include <dtrace.h>
@ -59,6 +61,7 @@ typedef struct dt_decl {
#define DT_DA_RESTRICT 0x0040 /* qualify type as restrict */
#define DT_DA_VOLATILE 0x0080 /* qualify type as volatile */
#define DT_DA_PAREN 0x0100 /* parenthesis tag */
#define DT_DA_USER 0x0200 /* user-land type specifier */
typedef enum dt_dclass {
DT_DC_DEFAULT, /* no storage class specified */

View File

@ -19,12 +19,16 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#include <strings.h>
#include <stdio.h>
@ -171,8 +175,8 @@ dt_dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
intptr, DIF_INSTR_RD(in));
if (intptr < dp->dtdo_intlen) {
(void) fprintf(fp, "\t\t! 0x%" PRIx64,
dp->dtdo_inttab[intptr]);
(void) fprintf(fp, "\t\t! 0x%llx",
(unsigned long long)dp->dtdo_inttab[intptr]);
}
}
@ -212,12 +216,22 @@ dt_dis_pushts(const dtrace_difo_t *dp,
{
static const char *const tnames[] = { "D type", "string" };
uint_t type = DIF_INSTR_TYPE(in);
const char *pad;
(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
if (DIF_INSTR_OP(in) == DIF_OP_PUSHTV) {
(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u",
name, type, DIF_INSTR_RS(in));
pad = "\t\t";
} else {
(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
pad = "\t";
}
if (type < sizeof (tnames) / sizeof (tnames[0]))
(void) fprintf(fp, "\t! DT_TYPE(%u) = %s", type, tnames[type]);
if (type < sizeof (tnames) / sizeof (tnames[0])) {
(void) fprintf(fp, "%s! DT_TYPE(%u) = %s", pad,
type, tnames[type]);
}
}
static void
@ -299,9 +313,10 @@ dt_dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len)
(void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind);
}
if (t->dtdt_flags & DIF_TF_BYREF) {
(void) snprintf(buf, len, "%s (%s) by ref (size %lu)",
kind, ckind, (ulong_t)t->dtdt_size);
if (t->dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF)) {
(void) snprintf(buf, len, "%s (%s) by %sref (size %lu)",
kind, ckind, (t->dtdt_flags & DIF_TF_BYUREF) ? "user " : "",
(ulong_t)t->dtdt_size);
} else {
(void) snprintf(buf, len, "%s (%s) (size %lu)",
kind, ckind, (ulong_t)t->dtdt_size);
@ -318,8 +333,9 @@ dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp,
rtag, "OFFSET", "DATA", "NAME");
for (; len != 0; len--, rp++) {
(void) fprintf(fp, "%-4u %-8" PRIu64 "%-8" PRIu64 "%s\n",
rp->dofr_type, rp->dofr_offset, rp->dofr_data,
(void) fprintf(fp, "%-4u %-8llu %-8llu %s\n",
rp->dofr_type, (unsigned long long)rp->dofr_offset,
(unsigned long long)rp->dofr_data,
&dp->dtdo_strtab[rp->dofr_name]);
}
}
@ -418,7 +434,7 @@ dt_dis(const dtrace_difo_t *dp, FILE *fp)
ulong_t i = 0;
char type[DT_TYPE_NAMELEN];
(void) fprintf(fp, "\nDIFO %p returns %s\n", (const void *)dp,
(void) fprintf(fp, "\nDIFO 0x%p returns %s\n", (void *)dp,
dt_dis_typestr(&dp->dtdo_rtype, type, sizeof (type)));
(void) fprintf(fp, "%-3s %-8s %s\n",

View File

@ -20,19 +20,18 @@
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#endif
#include <strings.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <assert.h>
@ -470,7 +469,7 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
* locally so an alternate symbol is added for the purpose
* of this relocation.
*/
if (pip->pi_rname[0] == '\0')
if (pip->pi_rname == NULL)
dofr.dofr_name = dofpr.dofpr_func;
else
dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);
@ -488,7 +487,7 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
return (0);
}
static void
static int
dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
@ -499,8 +498,12 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
size_t sz;
id_t i;
if (pvp->pv_flags & DT_PROVIDER_IMPL)
return; /* ignore providers that are exported by dtrace(7D) */
if (pvp->pv_flags & DT_PROVIDER_IMPL) {
/*
* ignore providers that are exported by dtrace(7D)
*/
return (0);
}
nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
@ -527,6 +530,9 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);
if (dt_buf_len(&ddo->ddo_probes) == 0)
return (dt_set_errno(dtp, EDT_NOPROBES));
dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
sizeof (uint64_t), 0, sizeof (dof_probe_t),
dt_buf_len(&ddo->ddo_probes));
@ -581,6 +587,8 @@ dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
sizeof (dof_secidx_t) * (nxr + 1));
}
return (0);
}
static int
@ -666,7 +674,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
stp != NULL; stp = dt_list_next(stp), last = edp) {
dtrace_stmtdesc_t *sdp = stp->ds_desc;
dtrace_actdesc_t *ap1 = sdp->dtsd_action;
dtrace_actdesc_t *ap = sdp->dtsd_action;
if (sdp->dtsd_fmtdata != NULL) {
i = dtrace_printf_format(dtp,
@ -677,7 +685,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
if ((edp = sdp->dtsd_ecbdesc) == last)
continue; /* same ecb as previous statement */
for (i = 0, ap1 = edp->dted_action; ap1; ap1 = ap1->dtad_next)
for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next)
i++;
maxacts = MAX(maxacts, i);
@ -718,7 +726,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
dof_stridx_t strndx = 0;
dof_probedesc_t dofp;
dof_ecbdesc_t dofe;
uint_t i1;
uint_t i;
if ((edp = stp->ds_desc->dtsd_ecbdesc) == last)
continue; /* same ecb as previous statement */
@ -751,26 +759,33 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
* Now iterate through the action list generating DIFOs as
* referenced therein and adding action descriptions to 'dofa'.
*/
for (i1 = 0, ap = edp->dted_action;
ap != NULL; ap = ap->dtad_next, i1++) {
for (i = 0, ap = edp->dted_action;
ap != NULL; ap = ap->dtad_next, i++) {
if (ap->dtad_difo != NULL) {
dofa[i1].dofa_difo =
dofa[i].dofa_difo =
dof_add_difo(ddo, ap->dtad_difo);
} else
dofa[i1].dofa_difo = DOF_SECIDX_NONE;
dofa[i].dofa_difo = DOF_SECIDX_NONE;
/*
* If the first action in a statement has format data,
* add the format string to the global string table.
* If the first action in a statement has string data,
* add the string to the global string table. This can
* be due either to a printf() format string
* (dtsd_fmtdata) or a print() type string
* (dtsd_strdata).
*/
if (sdp != NULL && ap == sdp->dtsd_action) {
if (sdp->dtsd_fmtdata != NULL) {
(void) dtrace_printf_format(dtp,
sdp->dtsd_fmtdata, fmt, maxfmt + 1);
strndx = dof_add_string(ddo, fmt);
} else
} else if (sdp->dtsd_strdata != NULL) {
strndx = dof_add_string(ddo,
sdp->dtsd_strdata);
} else {
strndx = 0; /* use dtad_arg instead */
}
if ((next = dt_list_next(next)) != NULL)
sdp = next->ds_desc;
@ -779,22 +794,22 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
}
if (strndx != 0) {
dofa[i1].dofa_arg = strndx;
dofa[i1].dofa_strtab = ddo->ddo_strsec;
dofa[i].dofa_arg = strndx;
dofa[i].dofa_strtab = ddo->ddo_strsec;
} else {
dofa[i1].dofa_arg = ap->dtad_arg;
dofa[i1].dofa_strtab = DOF_SECIDX_NONE;
dofa[i].dofa_arg = ap->dtad_arg;
dofa[i].dofa_strtab = DOF_SECIDX_NONE;
}
dofa[i1].dofa_kind = ap->dtad_kind;
dofa[i1].dofa_ntuple = ap->dtad_ntuple;
dofa[i1].dofa_uarg = ap->dtad_uarg;
dofa[i].dofa_kind = ap->dtad_kind;
dofa[i].dofa_ntuple = ap->dtad_ntuple;
dofa[i].dofa_uarg = ap->dtad_uarg;
}
if (i1 > 0) {
if (i > 0) {
actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC,
sizeof (uint64_t), 0, sizeof (dof_actdesc_t),
sizeof (dof_actdesc_t) * i1);
sizeof (dof_actdesc_t) * i);
}
/*
@ -817,8 +832,10 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
*/
if (flags & DTRACE_D_PROBES) {
for (pvp = dt_list_next(&dtp->dt_provlist);
pvp != NULL; pvp = dt_list_next(pvp))
dof_add_provider(ddo, pvp);
pvp != NULL; pvp = dt_list_next(pvp)) {
if (dof_add_provider(ddo, pvp) != 0)
return (NULL);
}
}
/*
@ -838,7 +855,6 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
*/
h.dofh_secnum = ddo->ddo_nsecs;
ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs);
assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);
h.dofh_loadsz = ssize +
dt_buf_len(&ddo->ddo_ldata) +
@ -864,6 +880,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
sp = dt_buf_ptr(&ddo->ddo_secs);
assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB);
assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);
sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata);
sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs);

View File

@ -18,11 +18,18 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <string.h>
#include <strings.h>
#include <dt_impl.h>
@ -36,7 +43,6 @@ static const struct {
{ EDT_VERSREDUCED, "Requested version conflicts with earlier setting" },
{ EDT_CTF, "Unexpected libctf error" },
{ EDT_COMPILER, "Error in D program compilation" },
{ EDT_NOREG, "Insufficient registers to generate code" },
{ EDT_NOTUPREG, "Insufficient tuple registers to generate code" },
{ EDT_NOMEM, "Memory allocation failure" },
{ EDT_INT2BIG, "Integer constant table limit exceeded" },
@ -104,7 +110,9 @@ static const struct {
{ EDT_BADSTACKPC, "Invalid stack program counter size" },
{ EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
{ EDT_OVERSION, "Client requested deprecated version of library" },
{ EDT_ENABLING_ERR, "Failed to enable probe" }
{ EDT_ENABLING_ERR, "Failed to enable probe" },
{ EDT_NOPROBES, "No probe sites found for declared provider" },
{ EDT_CANTLOAD, "Failed to load module" },
};
static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
@ -137,7 +145,7 @@ dtrace_errno(dtrace_hdl_t *dtp)
return (dtp->dt_errno);
}
#if defined(sun)
#ifdef illumos
int
dt_set_errno(dtrace_hdl_t *dtp, int err)
{

View File

@ -24,11 +24,14 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#ifndef _DT_ERRTAGS_H
#define _DT_ERRTAGS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
@ -187,8 +190,14 @@ typedef enum {
D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
D_TRACE_VOID, /* trace() argument has void type */
D_TRACE_DYN, /* trace() argument has dynamic type */
D_TRACE_AGG, /* trace() argument is an aggregation */
D_PRINT_VOID, /* print() argument has void type */
D_PRINT_DYN, /* print() argument has dynamic type */
D_PRINT_AGG, /* print() argument is an aggregation */
D_TRACEMEM_ADDR, /* tracemem() address bad type */
D_TRACEMEM_SIZE, /* tracemem() size bad type */
D_TRACEMEM_ARGS, /* tracemem() illegal number of args */
D_TRACEMEM_DYNSIZE, /* tracemem() dynamic size bad type */
D_STACK_PROTO, /* stack() prototype mismatch */
D_STACK_SIZE, /* stack() size argument bad type */
D_USTACK_FRAMES, /* ustack() frames arg bad type */
@ -236,6 +245,24 @@ typedef enum {
D_LQUANT_MATCHBASE, /* lquantize() mismatch on base */
D_LQUANT_MATCHLIM, /* lquantize() mismatch on limit */
D_LQUANT_MATCHSTEP, /* lquantize() mismatch on step */
D_LLQUANT_FACTORTYPE, /* llquantize() bad magnitude type */
D_LLQUANT_FACTORVAL, /* llquantize() bad magnitude value */
D_LLQUANT_FACTORMATCH, /* llquantize() mismatch on magnitude */
D_LLQUANT_LOWTYPE, /* llquantize() bad low mag type */
D_LLQUANT_LOWVAL, /* llquantize() bad low mag value */
D_LLQUANT_LOWMATCH, /* llquantize() mismatch on low mag */
D_LLQUANT_HIGHTYPE, /* llquantize() bad high mag type */
D_LLQUANT_HIGHVAL, /* llquantize() bad high mag value */
D_LLQUANT_HIGHMATCH, /* llquantize() mismatch on high mag */
D_LLQUANT_NSTEPTYPE, /* llquantize() bad # steps type */
D_LLQUANT_NSTEPVAL, /* llquantize() bad # steps value */
D_LLQUANT_NSTEPMATCH, /* llquantize() mismatch on # steps */
D_LLQUANT_MAGRANGE, /* llquantize() bad magnitude range */
D_LLQUANT_FACTORNSTEPS, /* llquantize() # steps < factor */
D_LLQUANT_FACTOREVEN, /* llquantize() bad # steps/factor */
D_LLQUANT_FACTORSMALL, /* llquantize() magnitude too small */
D_LLQUANT_MAGTOOBIG, /* llquantize() high mag too large */
D_NOREG, /* no available internal registers */
D_PRINTM_ADDR, /* printm() memref bad type */
D_PRINTM_SIZE, /* printm() size bad type */
D_PRINTT_ADDR, /* printt() typeref bad type */

View File

@ -23,8 +23,10 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <dt_impl.h>
@ -34,8 +36,6 @@
#define LINK(l, r) dt_node_link(l, r)
#define DUP(s) strdup(s)
int yylex(void);
%}
%union {
@ -104,6 +104,7 @@ int yylex(void);
%token DT_KEY_TYPEDEF
%token DT_KEY_UNION
%token DT_KEY_UNSIGNED
%token DT_KEY_USERLAND
%token DT_KEY_VOID
%token DT_KEY_VOLATILE
%token DT_KEY_WHILE
@ -206,6 +207,8 @@ int yylex(void);
%type <l_tok> unary_operator
%type <l_tok> struct_or_union
%type <l_str> dtrace_keyword_ident
%%
dtrace_program: d_expression DT_TOK_EOF { return (dt_node_root($1)); }
@ -390,12 +393,18 @@ postfix_expression:
| postfix_expression DT_TOK_DOT DT_TOK_TNAME {
$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_DOT dtrace_keyword_ident {
$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_PTR DT_TOK_IDENT {
$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_PTR DT_TOK_TNAME {
$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_PTR dtrace_keyword_ident {
$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_ADDADD {
$$ = OP1(DT_TOK_POSTINC, $1);
}
@ -410,6 +419,10 @@ postfix_expression:
DT_TOK_TNAME DT_TOK_RPAR {
$$ = dt_node_offsetof($3, $5);
}
| DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
dtrace_keyword_ident DT_TOK_RPAR {
$$ = dt_node_offsetof($3, $5);
}
| DT_TOK_XLATE DT_TOK_LT type_name DT_TOK_GT
DT_TOK_LPAR expression DT_TOK_RPAR {
$$ = OP2(DT_TOK_XLATE, dt_node_type($3), $6);
@ -635,6 +648,7 @@ type_specifier: DT_KEY_VOID { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("void")); }
| DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); }
| DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); }
| DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); }
| DT_KEY_USERLAND { $$ = dt_decl_attr(DT_DA_USER); }
| DT_KEY_STRING {
$$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string"));
}
@ -833,4 +847,15 @@ function_parameters:
| parameter_type_list { $$ = $1; }
;
dtrace_keyword_ident:
DT_KEY_PROBE { $$ = DUP("probe"); }
| DT_KEY_PROVIDER { $$ = DUP("provider"); }
| DT_KEY_SELF { $$ = DUP("self"); }
| DT_KEY_STRING { $$ = DUP("string"); }
| DT_TOK_STRINGOF { $$ = DUP("stringof"); }
| DT_KEY_USERLAND { $$ = DUP("userland"); }
| DT_TOK_XLATE { $$ = DUP("xlate"); }
| DT_KEY_XLATOR { $$ = DUP("translator"); }
;
%%

View File

@ -31,7 +31,7 @@
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
@ -192,13 +192,13 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
str = (char *)alloca(len);
if (err.dteda_action == 0) {
(void) snprintf(where, sizeof(where), "predicate");
(void) sprintf(where, "predicate");
} else {
(void) snprintf(where, sizeof(where), "action #%d", err.dteda_action);
(void) sprintf(where, "action #%d", err.dteda_action);
}
if (err.dteda_offset != -1) {
(void) snprintf(offinfo, sizeof(offinfo), " at DIF offset %d", err.dteda_offset);
(void) sprintf(offinfo, " at DIF offset %d", err.dteda_offset);
} else {
offinfo[0] = 0;
}
@ -207,7 +207,8 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
case DTRACEFLT_BADADDR:
case DTRACEFLT_BADALIGN:
case DTRACEFLT_BADSTACK:
(void) snprintf(details, sizeof(details), " (0x%" PRIx64 ")", err.dteda_addr);
(void) sprintf(details, " (0x%llx)",
(unsigned long long)err.dteda_addr);
break;
default:
@ -333,9 +334,10 @@ dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
size = sizeof (str);
}
(void) snprintf(s, size, "%" PRIu64 "%sdrop%s on CPU %ld\n",
howmany, what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
howmany > 1 ? "s" : "", cpu);
(void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n",
(unsigned long long)howmany,
what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
howmany > 1 ? "s" : "", (int)cpu);
if (dtp->dt_drophdlr == NULL)
return (dt_set_errno(dtp, EDT_DROPABORT));
@ -426,7 +428,8 @@ dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
size = sizeof (str);
}
(void) snprintf(s, size, "%" PRIu64 "%s%s%s\n", nval - oval,
(void) snprintf(s, size, "%llu %s%s%s\n",
(unsigned long long)(nval - oval),
_dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "",
_dt_droptab[i].dtdrt_msg != NULL ?
_dt_droptab[i].dtdrt_msg : "");

View File

@ -22,22 +22,24 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#endif
#include <strings.h>
#include <stdlib.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#if defined(sun)
#ifdef illumos
#include <sys/procfs_isa.h>
#endif
#include <limits.h>
@ -104,7 +106,7 @@ dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
}
}
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
}
/*
@ -163,7 +165,7 @@ dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
if (argc != 0)
isp->dis_args[argc - 1].dn_list = NULL;
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
} else {
dt_idcook_sign(dnp, idp, argc, args,
@ -304,7 +306,7 @@ dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
}
dt_node_type_assign(&isp->dis_args[i],
dtt.dtt_ctfp, dtt.dtt_type);
dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
}
}
@ -391,7 +393,9 @@ dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
dt_node_type_assign(dnp,
prp->pr_argv[ap->dn_value].dtt_ctfp,
prp->pr_argv[ap->dn_value].dtt_type);
prp->pr_argv[ap->dn_value].dtt_type,
prp->pr_argv[ap->dn_value].dtt_flags & DTT_FL_USER ?
B_TRUE : B_FALSE);
} else if ((dxp = dt_xlator_lookup(dtp,
nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
@ -419,7 +423,8 @@ dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
dnp->dn_ident->di_ctfp = xidp->di_ctfp;
dnp->dn_ident->di_type = xidp->di_type;
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
B_FALSE);
} else {
xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
@ -465,7 +470,7 @@ dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
idp->di_ctfp = dtt.dtt_ctfp;
idp->di_type = dtt.dtt_type;
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
}
/*ARGSUSED*/
@ -487,7 +492,7 @@ dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
idp->di_type = dtt.dtt_type;
}
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
}
/*ARGSUSED*/
@ -495,7 +500,7 @@ static void
dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
}
static void

View File

@ -24,12 +24,17 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#ifndef _DT_IMPL_H
#define _DT_IMPL_H
#include <sys/param.h>
#include <sys/objfs.h>
#if !defined(sun)
#ifndef illumos
#include <sys/bitmap.h>
#include <sys/utsname.h>
#include <sys/ioccom.h>
@ -40,6 +45,9 @@
#include <libctf.h>
#include <dtrace.h>
#include <gelf.h>
#ifdef illumos
#include <synch.h>
#endif
#ifdef __cplusplus
extern "C" {
@ -56,6 +64,7 @@ extern "C" {
#include <dt_proc.h>
#include <dt_dof.h>
#include <dt_pcb.h>
#include <dt_pq.h>
struct dt_module; /* see below */
struct dt_pfdict; /* see <dt_printf.h> */
@ -133,15 +142,35 @@ typedef struct dt_module {
GElf_Addr dm_bss_va; /* virtual address of BSS */
GElf_Xword dm_bss_size; /* size in bytes of BSS */
dt_idhash_t *dm_extern; /* external symbol definitions */
#if !defined(sun)
#ifndef illumos
caddr_t dm_reloc_offset; /* Symbol relocation offset. */
uintptr_t *dm_sec_offsets;
#endif
pid_t dm_pid; /* pid for this module */
uint_t dm_nctflibs; /* number of ctf children libraries */
ctf_file_t **dm_libctfp; /* process library ctf pointers */
char **dm_libctfn; /* names of process ctf containers */
} dt_module_t;
#define DT_DM_LOADED 0x1 /* module symbol and type data is loaded */
#define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */
#define DT_DM_PRIMARY 0x4 /* module is a krtld primary kernel object */
#if defined(__FreeBSD__) || defined(__NetBSD__)
/*
* A representation of a FreeBSD kernel module, used when checking module
* dependencies. This differs from dt_module_t, which refers to a KLD in the
* case of kernel probes. Since modules can be identified regardless of whether
* they've been compiled into the kernel, we use them to identify DTrace
* modules.
*/
typedef struct dt_kmodule {
struct dt_kmodule *dkm_next; /* hash table entry */
char *dkm_name; /* string name of module */
dt_module_t *dkm_module; /* corresponding KLD module */
} dt_kmodule_t;
#endif
typedef struct dt_provmod {
char *dp_name; /* name of provider module */
struct dt_provmod *dp_next; /* next module */
@ -179,6 +208,9 @@ typedef struct dt_print_aggdata {
dtrace_aggvarid_t dtpa_id; /* aggregation variable of interest */
FILE *dtpa_fp; /* file pointer */
int dtpa_allunprint; /* print only unprinted aggregations */
int dtpa_agghist; /* print aggregation as histogram */
int dtpa_agghisthdr; /* aggregation histogram hdr printed */
int dtpa_aggpack; /* pack quantized aggregations */
} dt_print_aggdata_t;
typedef struct dt_dirpath {
@ -218,6 +250,9 @@ struct dtrace_hdl {
dt_idhash_t *dt_tls; /* hash table of thread-local identifiers */
dt_list_t dt_modlist; /* linked list of dt_module_t's */
dt_module_t **dt_mods; /* hash table of dt_module_t's */
#if defined(__FreeBSD__) || defined(__NetBSD__)
dt_kmodule_t **dt_kmods; /* hash table of dt_kmodule_t's */
#endif
uint_t dt_modbuckets; /* number of module hash buckets */
uint_t dt_nmods; /* number of modules in hash and list */
dt_provmod_t *dt_provmod; /* linked list of provider modules */
@ -230,6 +265,7 @@ struct dtrace_hdl {
uint_t dt_provbuckets; /* number of provider hash buckets */
uint_t dt_nprovs; /* number of providers in hash and list */
dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */
char **dt_proc_env; /* additional environment variables */
dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */
ctf_id_t dt_type_func; /* cached CTF identifier for function type */
ctf_id_t dt_type_fptr; /* cached CTF identifier for function pointer */
@ -245,8 +281,10 @@ struct dtrace_hdl {
dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
int dt_maxformat; /* max format ID */
void **dt_formats; /* pointer to format array */
int dt_maxstrdata; /* max strdata ID */
char **dt_strdata; /* pointer to strdata array */
dt_aggregate_t dt_aggregate; /* aggregate */
dtrace_bufdesc_t dt_buf; /* staging buffer */
dt_pq_t *dt_bufq; /* CPU-specific data queue */
struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
dt_version_t dt_vmax; /* optional ceiling on program API binding */
dtrace_attribute_t dt_amin; /* optional floor on program attributes */
@ -255,6 +293,9 @@ struct dtrace_hdl {
int dt_cpp_argc; /* count of initialized cpp(1) arguments */
int dt_cpp_args; /* size of dt_cpp_argv[] array */
char *dt_ld_path; /* pathname of ld(1) to invoke if needed */
#if defined(__FreeBSD__) || defined(__NetBSD__)
char *dt_objcopy_path; /* pathname of objcopy(1) to invoke if needed */
#endif
dt_list_t dt_lib_path; /* linked-list forming library search path */
uint_t dt_lazyload; /* boolean: set via -xlazyload */
uint_t dt_droptags; /* boolean: set via -xdroptags */
@ -270,12 +311,13 @@ struct dtrace_hdl {
uint_t dt_linktype; /* dtrace link output file type (see below) */
uint_t dt_xlatemode; /* dtrace translator linking mode (see below) */
uint_t dt_stdcmode; /* dtrace stdc compatibility mode (see below) */
uint_t dt_encoding; /* dtrace output encoding (see below) */
uint_t dt_treedump; /* dtrace tree debug bitmap (see below) */
uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */
int dt_version; /* library version requested by client */
int dt_ctferr; /* error resulting from last CTF failure */
int dt_errno; /* error resulting from last failed operation */
#if !defined(sun)
#ifndef illumos
const char *dt_errfile;
int dt_errline;
#endif
@ -284,7 +326,7 @@ struct dtrace_hdl {
int dt_fterr; /* saved errno from failed open of dt_ftfd */
int dt_cdefs_fd; /* file descriptor for C CTF debugging cache */
int dt_ddefs_fd; /* file descriptor for D CTF debugging cache */
#if defined(sun)
#ifdef illumos
int dt_stdout_fd; /* file descriptor for saved stdout */
#else
FILE *dt_freopen_fp; /* file pointer for freopened stdout */
@ -315,6 +357,11 @@ struct dtrace_hdl {
struct utsname dt_uts; /* uname(2) information for system */
dt_list_t dt_lib_dep; /* scratch linked-list of lib dependencies */
dt_list_t dt_lib_dep_sorted; /* dependency sorted library list */
dtrace_flowkind_t dt_flow; /* flow kind */
const char *dt_prefix; /* recommended flow prefix */
int dt_indent; /* recommended flow indent */
dtrace_epid_t dt_last_epid; /* most recently consumed EPID */
uint64_t dt_last_timestamp; /* most recently consumed timestamp */
};
/*
@ -355,6 +402,14 @@ struct dtrace_hdl {
#define DT_STDC_XS 2 /* K&R C: __STDC__ not defined */
#define DT_STDC_XT 3 /* ISO C + K&R C compat with ISO: __STDC__=0 */
/*
* Values for the dt_encoding property, which is used to force a particular
* character encoding (overriding default behavior and/or automatic detection).
*/
#define DT_ENCODING_UNSET 0
#define DT_ENCODING_ASCII 1
#define DT_ENCODING_UTF8 2
/*
* Macro to test whether a given pass bit is set in the dt_treedump bit-vector.
* If the bit for pass 'p' is set, the D compiler displays the parse tree for
@ -430,8 +485,9 @@ struct dtrace_hdl {
#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
#define DT_ACT_PRINTM DT_ACT(29) /* printm() action */
#define DT_ACT_PRINTT DT_ACT(30) /* printt() action */
#define DT_ACT_PRINT DT_ACT(29) /* print() action */
#define DT_ACT_PRINTM DT_ACT(30) /* printm() action */
#define DT_ACT_PRINTT DT_ACT(31) /* printt() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
@ -449,7 +505,6 @@ enum {
EDT_VERSREDUCED, /* requested API version has been reduced */
EDT_CTF, /* libctf called failed (dt_ctferr has more) */
EDT_COMPILER, /* error in D program compilation */
EDT_NOREG, /* register allocation failure */
EDT_NOTUPREG, /* tuple register allocation failure */
EDT_NOMEM, /* memory allocation failure */
EDT_INT2BIG, /* integer limit exceeded */
@ -517,7 +572,9 @@ enum {
EDT_BADSTACKPC, /* invalid stack program counter size */
EDT_BADAGGVAR, /* invalid aggregation variable identifier */
EDT_OVERSION, /* client is requesting deprecated version */
EDT_ENABLING_ERR /* failed to enable probe */
EDT_ENABLING_ERR, /* failed to enable probe */
EDT_NOPROBES, /* no probes sites for declared provider */
EDT_CANTLOAD /* failed to load a module */
};
/*
@ -560,7 +617,7 @@ extern int dt_version_defined(dt_version_t);
extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *);
extern char *dt_cpp_pop_arg(dtrace_hdl_t *);
#if defined(sun)
#ifdef illumos
extern int dt_set_errno(dtrace_hdl_t *, int);
#else
int _dt_set_errno(dtrace_hdl_t *, int, const char *, int);
@ -570,7 +627,7 @@ void dt_get_errloc(dtrace_hdl_t *, const char **, int *);
extern void dt_set_errmsg(dtrace_hdl_t *, const char *, const char *,
const char *, int, const char *, va_list);
#if defined(sun)
#ifdef illumos
extern int dt_ioctl(dtrace_hdl_t *, int, void *);
#else
extern int dt_ioctl(dtrace_hdl_t *, u_long, void *);
@ -586,7 +643,6 @@ extern void dt_free(dtrace_hdl_t *, void *);
extern void dt_difo_free(dtrace_hdl_t *, dtrace_difo_t *);
extern int dt_gmatch(const char *, const char *);
extern int gmatch(const char *, const char *);
extern char *dt_basename(char *);
extern ulong_t dt_popc(ulong_t);
@ -600,21 +656,16 @@ extern void dt_buffered_destroy(dtrace_hdl_t *);
extern uint64_t dt_stddev(uint64_t *, uint64_t);
#define DT_MUTEX_HELD(x) dt_mutex_held(x)
static inline int
dt_mutex_held(pthread_mutex_t *lock)
{
#if defined(sun)
extern int _mutex_held(struct _lwp_mutex *);
return (_mutex_held((struct _lwp_mutex *)lock));
#else
return (1);
#endif
}
extern int dt_rw_read_held(pthread_rwlock_t *);
extern int dt_rw_write_held(pthread_rwlock_t *);
extern int dt_mutex_held(pthread_mutex_t *);
extern int dt_options_load(dtrace_hdl_t *);
#define DT_RW_READ_HELD(x) dt_rw_read_held(x)
#define DT_RW_WRITE_HELD(x) dt_rw_write_held(x)
#define DT_RW_LOCK_HELD(x) (DT_RW_READ_HELD(x) || DT_RW_WRITE_HELD(x))
#define DT_MUTEX_HELD(x) dt_mutex_held(x)
extern void dt_dprintf(const char *, ...);
extern void dt_setcontext(dtrace_hdl_t *, dtrace_probedesc_t *);
@ -639,10 +690,15 @@ extern void dt_aggid_destroy(dtrace_hdl_t *);
extern void *dt_format_lookup(dtrace_hdl_t *, int);
extern void dt_format_destroy(dtrace_hdl_t *);
extern const char *dt_strdata_lookup(dtrace_hdl_t *, int);
extern void dt_strdata_destroy(dtrace_hdl_t *);
extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_llquantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_agg(const dtrace_aggdata_t *, void *);
extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *);
@ -688,6 +744,11 @@ extern int _dtrace_argmax; /* default maximum probe arguments */
extern const char *_dtrace_libdir; /* default library directory */
extern const char *_dtrace_moddir; /* default kernel module directory */
#if defined(__FreeBSD__) || defined(__NetBSD__)
extern int gmatch(const char *, const char *);
extern int yylex(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -18,12 +18,15 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <string.h>
#include <stdlib.h>
@ -41,11 +44,11 @@
* We need to undefine lex's input and unput macros so that references to these
* call the functions provided at the end of this source file.
*/
#if defined(sun)
#ifdef illumos
#undef input
#undef unput
#else
/*
/*
* Define YY_INPUT for flex since input() can't be re-defined.
*/
#define YY_INPUT(buf,result,max_size) \
@ -60,10 +63,23 @@
buf[n] = *yypcb->pcb_strptr++; \
result = n; \
}
/*
* Do not EOF let tokens to be put back. This does not work with flex.
* On the other hand, leaving current buffer in same state it was when
* last EOF was received guarantees that input() will keep returning EOF
* for all subsequent invocations, which is the effect desired.
*/
#undef unput
#define unput(c) \
do { \
int _c = c; \
if (_c != EOF) \
yyunput(_c, yytext_ptr); \
} while(0)
#endif
static int id_or_type(const char *);
#if defined(sun)
#ifdef illumos
static int input(void);
static void unput(int);
#endif
@ -81,13 +97,17 @@ static void unput(int);
%}
%e 1500 /* maximum nodes */
%p 3700 /* maximum positions */
%p 4900 /* maximum positions */
%n 600 /* maximum states */
%a 3000 /* maximum transitions */
%s S0 S1 S2 S3 S4
RGX_AGG "@"[a-zA-Z_][0-9a-zA-Z_]*
RGX_PSPEC [-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]*
RGX_ALTIDENT [a-zA-Z_][0-9a-zA-Z_]*
RGX_LMID LM[0-9a-fA-F]+`
RGX_MOD_IDENT [a-zA-Z_`][0-9a-z.A-Z_`]*`
RGX_IDENT [a-zA-Z_`][0-9a-zA-Z_`]*
RGX_INT ([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]?
RGX_FP ([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]?
@ -157,6 +177,7 @@ if (yypcb->pcb_token != 0) {
<S0>typedef return (DT_KEY_TYPEDEF);
<S0>union return (DT_KEY_UNION);
<S0>unsigned return (DT_KEY_UNSIGNED);
<S0>userland return (DT_KEY_USERLAND);
<S0>void return (DT_KEY_VOID);
<S0>volatile return (DT_KEY_VOLATILE);
<S0>while return (DT_KEY_WHILE);
@ -268,7 +289,8 @@ if (yypcb->pcb_token != 0) {
* If the macro text is not a string an begins with a
* digit or a +/- sign, process it as an integer token.
*/
if (isdigit((unsigned char)v[0]) || v[0] == '-' || v[0] == '+') {
if (isdigit((unsigned char)v[0]) || v[0] == '-' ||
v[0] == '+') {
if (isdigit((unsigned char)v[0]))
yyintprefix = 0;
else
@ -335,7 +357,9 @@ if (yypcb->pcb_token != 0) {
return (DT_TOK_INT);
}
<S0>{RGX_IDENT} {
<S0>{RGX_IDENT} |
<S0>{RGX_MOD_IDENT}{RGX_IDENT} |
<S0>{RGX_MOD_IDENT} {
return (id_or_type(yytext));
}
@ -717,9 +741,10 @@ yyinit(dt_pcb_t *pcb)
yypcb = pcb;
yylineno = 1;
yypragma = NULL;
#if defined(sun)
#ifdef illumos
yysptr = yysbuf;
#endif
YY_FLUSH_BUFFER;
}
/*
@ -815,7 +840,7 @@ id_or_type(const char *s)
return (ttok);
}
#if defined(sun)
#ifdef illumos
static int
input(void)
{
@ -826,7 +851,7 @@ input(void)
else if (yypcb->pcb_fileptr != NULL)
c = fgetc(yypcb->pcb_fileptr);
else if (yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen)
c = *yypcb->pcb_strptr++;
c = *(unsigned char *)(yypcb->pcb_strptr++);
else
c = EOF;
@ -857,4 +882,4 @@ unput(int c)
*yysptr++ = c;
yytchar = c;
}
#endif
#endif /* illumos */

View File

@ -28,9 +28,14 @@
#define ELF_TARGET_ALL
#include <elf.h>
#ifdef __NetBSD__
#ifdef __x86_64__
#include <i386/elf_machdep.h>
#endif
#endif
#include <sys/types.h>
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#else
#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
@ -38,7 +43,7 @@
#include <unistd.h>
#include <strings.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <limits.h>
@ -47,10 +52,13 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#if defined(sun)
#ifdef illumos
#include <wait.h>
#else
#include <sys/wait.h>
#include <libelf.h>
#include <gelf.h>
#include <sys/mman.h>
#endif
#include <assert.h>
#include <sys/ipc.h>
@ -224,25 +232,29 @@ prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep)
s = &dofs[dofrh->dofr_tgtsec];
for (j = 0; j < nrel; j++) {
#if defined(__arm__)
#if defined(__aarch64__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__ia64__)
#elif defined(__arm__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__i386) || defined(__amd64)
#ifndef __amd64 /* XXX: FIXME */
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
rel->r_info = ELF32_R_INFO(count + dep->de_global,
R_386_32);
#endif
#elif defined(__mips__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__powerpc__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
/*
* Add 4 bytes to hit the low half of this 64-bit
* big-endian address.
*/
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset + 4;
rel->r_info = ELF32_R_INFO(count + dep->de_global,
R_PPC_REL32);
#elif defined(__sparc)
/*
* Add 4 bytes to hit the low half of this 64-bit
@ -277,7 +289,11 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
sym->st_value = 0;
sym->st_size = dof->dofh_filesz;
sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
#ifdef illumos
sym->st_other = 0;
#else
sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
#endif
sym->st_shndx = ESHDR_DOF;
sym++;
@ -318,7 +334,11 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
char *strtab;
int i, j, nrel;
size_t strtabsz = 1;
#ifdef illumos
uint32_t count = 0;
#else
uint64_t count = 0;
#endif
size_t base;
Elf64_Sym *sym;
Elf64_Rela *rel;
@ -414,21 +434,29 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
s = &dofs[dofrh->dofr_tgtsec];
for (j = 0; j < nrel; j++) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#if defined(__arm__)
#if defined(__aarch64__)
/* XXX */
#elif defined(__ia64__)
#elif defined(__arm__)
/* XXX */
#elif defined(__mips__)
/* XXX */
#elif defined(__powerpc__)
/* XXX */
#elif defined(__i386) || defined(__amd64)
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
rel->r_info = ELF64_R_INFO(count + dep->de_global,
R_PPC64_REL64);
#elif defined(__i386) || defined(__amd64)
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
#ifdef illumos
rel->r_info = ELF64_R_INFO(count + dep->de_global,
R_AMD64_64);
#else
#if defined(__amd64)
rel->r_info = ELF64_R_INFO(count + dep->de_global,
R_X86_64_RELATIVE);
#endif
#endif
#elif defined(__sparc)
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
@ -436,7 +464,6 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
R_SPARC_64);
#else
#error unknown ISA
#endif
#endif
sym->st_name = base + dofr[j].dofr_name - 1;
@ -460,7 +487,11 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
sym->st_value = 0;
sym->st_size = dof->dofh_filesz;
sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
#ifdef illumos
sym->st_other = 0;
#else
sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
#endif
sym->st_shndx = ESHDR_DOF;
sym++;
@ -498,7 +529,7 @@ dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
int ret = 0;
uint_t nshdr;
memset(&de, 0, sizeof(de));
memset(&de, 0, sizeof(de)); // XXX: gcc
if (prepare_elf32(dtp, dof, &de) != 0)
return (-1); /* errno is set for us */
@ -521,14 +552,12 @@ dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
#else
elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
#endif
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__NetBSD__)
elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
elf_file.ehdr.e_type = ET_REL;
#if defined(__arm__)
elf_file.ehdr.e_machine = EM_ARM;
#elif defined(__ia64__)
elf_file.ehdr.e_machine = EM_IA_64;
#elif defined(__mips__)
elf_file.ehdr.e_machine = EM_MIPS;
#elif defined(__powerpc__)
@ -647,7 +676,7 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
int ret = 0;
uint_t nshdr;
memset(&de, 0, sizeof(de));
memset(&de, 0, sizeof(de)); // XXX: gcc
if (prepare_elf64(dtp, dof, &de) != 0)
return (-1); /* errno is set for us */
@ -670,18 +699,16 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
#else
elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
#endif
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__NetBSD__)
elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
elf_file.ehdr.e_type = ET_REL;
#if defined(__arm__)
elf_file.ehdr.e_machine = EM_ARM;
#elif defined(__ia64__)
elf_file.ehdr.e_machine = EM_IA_64;
#elif defined(__mips__)
elf_file.ehdr.e_machine = EM_MIPS;
#elif defined(__powerpc__)
elf_file.ehdr.e_machine = EM_PPC;
#elif defined(__powerpc64__)
elf_file.ehdr.e_machine = EM_PPC64;
#elif defined(__sparc)
elf_file.ehdr.e_machine = EM_SPARCV9;
#elif defined(__i386) || defined(__amd64)
@ -775,21 +802,32 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
static int
dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
GElf_Sym *sym)
GElf_Sym *sym, int uses_funcdesc, Elf *elf)
{
int i, ret = -1;
Elf64_Addr symval;
Elf_Scn *opd_scn;
Elf_Data *opd_desc;
GElf_Sym s;
for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) {
if (GELF_ST_TYPE(sym->st_info) == STT_FUNC &&
shn == sym->st_shndx &&
sym->st_value <= addr &&
addr < sym->st_value + sym->st_size) {
if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
return (0);
if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
symval = sym->st_value;
if (uses_funcdesc) {
opd_scn = elf_getscn(elf, sym->st_shndx);
opd_desc = elf_rawdata(opd_scn, NULL);
symval =
*(uint64_t*)((char *)opd_desc->d_buf + symval);
}
if ((uses_funcdesc || shn == sym->st_shndx) &&
symval <= addr &&
addr < symval + sym->st_size) {
if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
return (0);
ret = 0;
s = *sym;
ret = 0;
s = *sym;
}
}
}
@ -798,7 +836,7 @@ dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
return (ret);
}
#if defined(__arm__)
#if defined(__aarch64__)
/* XXX */
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
@ -807,7 +845,7 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
return (0);
}
#elif defined(__ia64__)
#elif defined(__arm__)
/* XXX */
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
@ -826,12 +864,84 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
return (0);
}
#elif defined(__powerpc__)
/* The sentinel is 'xor r3,r3,r3'. */
#define DT_OP_XOR_R3 0x7c631a78
#define DT_OP_NOP 0x60000000
#define DT_OP_BLR 0x4e800020
/* This captures all forms of branching to address. */
#define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000)
#define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01))
/* XXX */
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
{
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
uint32_t *ip;
if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
return (-1);
/*LINTED*/
ip = (uint32_t *)(p + rela->r_offset);
/*
* We only know about some specific relocation types.
*/
if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24)
return (-1);
/*
* We may have already processed this object file in an earlier linker
* invocation. Check to see if the present instruction sequence matches
* the one we would install below.
*/
if (isenabled) {
if (ip[0] == DT_OP_XOR_R3) {
(*off) += sizeof (ip[0]);
return (0);
}
} else {
if (ip[0] == DT_OP_NOP) {
(*off) += sizeof (ip[0]);
return (0);
}
}
/*
* We only expect branch to address instructions.
*/
if (!DT_IS_BRANCH(ip[0])) {
dt_dprintf("found %x instead of a branch instruction at %llx\n",
ip[0], (u_longlong_t)rela->r_offset);
return (-1);
}
if (isenabled) {
/*
* It would necessarily indicate incorrect usage if an is-
* enabled probe were tail-called so flag that as an error.
* It's also potentially (very) tricky to handle gracefully,
* but could be done if this were a desired use scenario.
*/
if (!DT_IS_BL(ip[0])) {
dt_dprintf("tail call to is-enabled probe at %llx\n",
(u_longlong_t)rela->r_offset);
return (-1);
}
ip[0] = DT_OP_XOR_R3;
(*off) += sizeof (ip[0]);
} else {
if (DT_IS_BL(ip[0]))
ip[0] = DT_OP_NOP;
else
ip[0] = DT_OP_BLR;
}
return (0);
}
@ -993,11 +1103,9 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
* these types have the same values on both 32-bit and 64-bit
* x86 architectures.
*/
#ifndef __amd64 /* XXX: FIXME */
if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
GELF_R_TYPE(rela->r_info) != R_386_PLT32)
return (-1);
#endif
/*
* We may have already processed this object file in an earlier linker
@ -1124,7 +1232,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
dt_provider_t *pvp;
dt_probe_t *prp;
uint32_t off, eclass, emachine1, emachine2;
size_t symsize, nsym, isym, istr, len;
size_t symsize, nsym = 0, isym, istr, len;
key_t objkey;
dt_link_pair_t *pair, *bufs = NULL;
dt_strtab_t *strtab;
@ -1158,9 +1266,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
if (dtp->dt_oflags & DTRACE_O_LP64) {
eclass = ELFCLASS64;
#if defined(__ia64__)
emachine1 = emachine2 = EM_IA_64;
#elif defined(__mips__)
#if defined(__mips__)
emachine1 = emachine2 = EM_MIPS;
#elif defined(__powerpc__)
emachine1 = emachine2 = EM_PPC64;
@ -1181,7 +1287,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
#elif defined(__sparc)
emachine1 = EM_SPARC;
emachine2 = EM_SPARC32PLUS;
#elif defined(__i386) || defined(__amd64) || defined(__ia64__)
#elif defined(__i386) || defined(__amd64)
emachine1 = emachine2 = EM_386;
#endif
symsize = sizeof (Elf32_Sym);
@ -1307,7 +1413,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
continue;
if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
shdr_rel.sh_info, &fsym) != 0) {
shdr_rel.sh_info, &fsym,
(emachine1 == EM_PPC64), elf) != 0) {
dt_strtab_destroy(strtab);
goto err;
}
@ -1468,7 +1575,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
p = strhyphenate(p + 3); /* strlen("___") */
if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
shdr_rel.sh_info, &fsym) != 0)
shdr_rel.sh_info, &fsym,
(emachine1 == EM_PPC64), elf) != 0)
goto err;
if (fsym.st_name > data_str->d_size)
@ -1498,8 +1606,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
(void) gelf_update_sym(data_sym, isym, &dsym);
r = (char *)data_str->d_buf + istr;
istr += 1 + snprintf(r, data_str->d_size -
(istr - (size_t)data_str->d_buf), dt_symfmt,
istr += 1 + sprintf(r, dt_symfmt,
dt_symprefix, objkey, s);
isym++;
assert(isym <= nsym);
@ -1526,14 +1633,36 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
off = rela.r_offset - fsym.st_value;
if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
&rela, &off) != 0) {
&rela, &off) != 0)
goto err;
}
if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) {
return (dt_link_error(dtp, elf, fd, bufs,
"failed to allocate space for probe"));
}
#ifndef illumos
/*
* Our linker doesn't understand the SUNW_IGNORE ndx and
* will try to use this relocation when we build the
* final executable. Since we are done processing this
* relocation, mark it as inexistant and let libelf
* remove it from the file.
* If this wasn't done, we would have garbage added to
* the executable file as the symbol is going to be
* change from UND to ABS.
*/
if (shdr_rel.sh_type == SHT_RELA) {
rela.r_offset = 0;
rela.r_info = 0;
rela.r_addend = 0;
(void) gelf_update_rela(data_rel, i, &rela);
} else {
GElf_Rel rel;
rel.r_offset = 0;
rel.r_info = 0;
(void) gelf_update_rel(data_rel, i, &rel);
}
#endif
mod = 1;
(void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
@ -1545,13 +1674,13 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* already been processed by an earlier link
* invocation.
*/
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#ifndef illumos
#define SHN_SUNW_IGNORE SHN_ABS
#endif
if (rsym.st_shndx != SHN_SUNW_IGNORE) {
rsym.st_shndx = SHN_SUNW_IGNORE;
(void) gelf_update_sym(data_sym, ndx, &rsym);
}
#endif
}
}
@ -1561,6 +1690,9 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
(void) elf_end(elf);
(void) close(fd);
#ifndef illumos
if (nsym > 0)
#endif
while ((pair = bufs) != NULL) {
bufs = pair->dlp_next;
dt_free(dtp, pair->dlp_str);
@ -1579,7 +1711,7 @@ int
dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
const char *file, int objc, char *const objv[])
{
#if !defined(sun)
#ifndef illumos
char tfile[PATH_MAX];
#endif
char drti[PATH_MAX];
@ -1589,9 +1721,19 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
size_t len;
int eprobes = 0, ret = 0;
#if !defined(sun)
/* XXX Should get a temp file name here. */
snprintf(tfile, sizeof(tfile), "%s.tmp", file);
#ifndef illumos
if (access(file, R_OK) == 0) {
fprintf(stderr, "dtrace: target object (%s) already exists. "
"Please remove the target\ndtrace: object and rebuild all "
"the source objects if you wish to run the DTrace\n"
"dtrace: linking process again\n", file);
/*
* Several build infrastructures run DTrace twice (e.g.
* postgres) and we don't want the build to fail. Return
* 0 here since this isn't really a fatal error.
*/
return (0);
}
#endif
/*
@ -1655,7 +1797,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL)
return (-1); /* errno is set for us */
#if defined(sun)
#ifdef illumos
/*
* Create a temporary file and then unlink it if we're going to
* combine it with drti.o later. We can still refer to it in child
@ -1666,9 +1808,11 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
"failed to open %s: %s", file, strerror(errno)));
}
#else
if ((fd = open(tfile, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1)
snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1)
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to open %s: %s", tfile, strerror(errno)));
"failed to create temporary file %s: %s",
tfile, strerror(errno)));
#endif
/*
@ -1699,7 +1843,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
}
#if defined(sun)
#ifdef illumos
if (!dtp->dt_lazyload)
(void) unlink(file);
#endif
@ -1709,13 +1853,20 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
else
status = dump_elf32(dtp, dof, fd);
#ifdef illumos
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
if (status != 0)
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to write %s: %s", tfile,
strerror(dtrace_errno(dtp))));
#endif
if (!dtp->dt_lazyload) {
#if defined(sun)
#ifdef illumos
const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
if (dtp->dt_oflags & DTRACE_O_LP64) {
@ -1734,63 +1885,92 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
#else
const char *fmt = "%s -o %s -r %s %s";
dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
#if defined(__amd64__)
/*
* Arches which default to 64-bit need to explicitly use
* the 32-bit library path.
*/
int use_32 = !(dtp->dt_oflags & DTRACE_O_LP64);
#else
/*
* Arches which are 32-bit only just use the normal
* library path.
*/
int use_32 = 0;
#endif
(void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o",
use_32 ? "32":"");
(void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path);
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
drti) + 1;
cmd = alloca(len);
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, drti);
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile,
drti);
#endif
if ((status = system(cmd)) == -1) {
ret = dt_link_error(dtp, NULL, -1, NULL,
ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to run %s: %s", dtp->dt_ld_path,
strerror(errno));
goto done;
}
(void) close(fd); /* release temporary file */
if (WIFSIGNALED(status)) {
ret = dt_link_error(dtp, NULL, -1, NULL,
ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to link %s: %s failed due to signal %d",
file, dtp->dt_ld_path, WTERMSIG(status));
goto done;
}
if (WEXITSTATUS(status) != 0) {
ret = dt_link_error(dtp, NULL, -1, NULL,
ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to link %s: %s exited with status %d\n",
file, dtp->dt_ld_path, WEXITSTATUS(status));
goto done;
}
(void) close(fd); /* release temporary file */
#if defined(__FreeBSD__) || defined(__NetBSD__)
/*
* Now that we've linked drti.o, reduce the global __SUNW_dof
* symbol to a local symbol. This is needed to so that multiple
* generated object files (for different providers, for
* instance) can be linked together. This is accomplished using
* the -Blocal flag with Sun's linker, but GNU ld doesn't appear
* to have an equivalent option.
*/
asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path,
file);
if ((status = system(cmd)) == -1) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to run %s: %s", dtp->dt_objcopy_path,
strerror(errno));
free(cmd);
goto done;
}
free(cmd);
if (WIFSIGNALED(status)) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to link %s: %s failed due to signal %d",
file, dtp->dt_objcopy_path, WTERMSIG(status));
goto done;
}
if (WEXITSTATUS(status) != 0) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to link %s: %s exited with status %d\n",
file, dtp->dt_objcopy_path, WEXITSTATUS(status));
goto done;
}
#endif
} else {
#if defined(__FreeBSD__) || defined(__NetBSD__)
if (rename(tfile, file) != 0) {
ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to rename %s to %s: %s", tfile, file,
strerror(errno));
goto done;
}
#endif
(void) close(fd);
}
done:
dtrace_dof_destroy(dtp, dof);
#if !defined(sun)
unlink(tfile);
#if defined(__FreeBSD__) || defined(__NetBSD__)
if (!dtp->dt_lazyload)
(void) unlink(tfile);
#endif
return (ret);
}

View File

@ -38,8 +38,8 @@ typedef struct dt_list {
struct dt_list *dl_next;
} dt_list_t;
#define dt_list_prev(elem) ((void *)(((dt_list_t *)__UNCONST(elem))->dl_prev))
#define dt_list_next(elem) ((void *)(((dt_list_t *)__UNCONST(elem))->dl_next))
#define dt_list_prev(elem) ((void *)(((dt_list_t *)(elem))->dl_prev))
#define dt_list_next(elem) ((void *)(((dt_list_t *)(elem))->dl_next))
extern void dt_list_append(dt_list_t *, void *);
extern void dt_list_prepend(dt_list_t *, void *);

View File

@ -23,7 +23,9 @@
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <stdlib.h>
#include <strings.h>
@ -34,11 +36,83 @@
#include <dt_impl.h>
#include <dt_printf.h>
static int
dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
{
int maxformat, rval;
dtrace_fmtdesc_t fmt;
void *result;
if (rec->dtrd_format == 0)
return (0);
if (rec->dtrd_format <= *max &&
(*data)[rec->dtrd_format - 1] != NULL) {
return (0);
}
bzero(&fmt, sizeof (fmt));
fmt.dtfd_format = rec->dtrd_format;
fmt.dtfd_string = NULL;
fmt.dtfd_length = 0;
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
return (dt_set_errno(dtp, errno));
if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
rval = dt_set_errno(dtp, errno);
free(fmt.dtfd_string);
return (rval);
}
while (rec->dtrd_format > (maxformat = *max)) {
int new_max = maxformat ? (maxformat << 1) : 1;
size_t nsize = new_max * sizeof (void *);
size_t osize = maxformat * sizeof (void *);
void **new_data = dt_zalloc(dtp, nsize);
if (new_data == NULL) {
dt_free(dtp, fmt.dtfd_string);
return (dt_set_errno(dtp, EDT_NOMEM));
}
bcopy(*data, new_data, osize);
free(*data);
*data = new_data;
*max = new_max;
}
switch (rec->dtrd_action) {
case DTRACEACT_DIFEXPR:
result = fmt.dtfd_string;
break;
case DTRACEACT_PRINTA:
result = dtrace_printa_create(dtp, fmt.dtfd_string);
dt_free(dtp, fmt.dtfd_string);
break;
default:
result = dtrace_printf_create(dtp, fmt.dtfd_string);
dt_free(dtp, fmt.dtfd_string);
break;
}
if (result == NULL)
return (-1);
(*data)[rec->dtrd_format - 1] = result;
return (0);
}
static int
dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
{
dtrace_id_t max;
int rval, i, maxformat;
int rval, i;
dtrace_eprobedesc_t *enabled, *nenabled;
dtrace_probedesc_t *probe;
@ -82,7 +156,7 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
enabled->dtepd_epid = id;
enabled->dtepd_nrecs = 1;
#if defined(sun)
#ifdef illumos
if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
#else
if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
@ -106,7 +180,7 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
if ((enabled = nenabled) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
#if defined(sun)
#ifdef illumos
rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
#else
rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
@ -132,71 +206,23 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
}
for (i = 0; i < enabled->dtepd_nrecs; i++) {
dtrace_fmtdesc_t fmt;
dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
continue;
if (rec->dtrd_format == 0)
continue;
if (rec->dtrd_format <= dtp->dt_maxformat &&
dtp->dt_formats[rec->dtrd_format - 1] != NULL)
continue;
bzero(&fmt, sizeof (fmt));
fmt.dtfd_format = rec->dtrd_format;
fmt.dtfd_string = NULL;
fmt.dtfd_length = 0;
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
rval = dt_set_errno(dtp, errno);
goto err;
}
if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
rval = dt_set_errno(dtp, EDT_NOMEM);
goto err;
}
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
rval = dt_set_errno(dtp, errno);
free(fmt.dtfd_string);
goto err;
}
while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
int new_max = maxformat ? (maxformat << 1) : 1;
size_t nsize = new_max * sizeof (void *);
size_t osize = maxformat * sizeof (void *);
void **new_formats = malloc(nsize);
if (new_formats == NULL) {
rval = dt_set_errno(dtp, EDT_NOMEM);
free(fmt.dtfd_string);
if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
&dtp->dt_maxformat) != 0) {
rval = -1;
goto err;
}
} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
if (dt_strdata_add(dtp, rec,
(void ***)&dtp->dt_strdata,
&dtp->dt_maxstrdata) != 0) {
rval = -1;
goto err;
}
bzero(new_formats, nsize);
bcopy(dtp->dt_formats, new_formats, osize);
free(dtp->dt_formats);
dtp->dt_formats = new_formats;
dtp->dt_maxformat = new_max;
}
dtp->dt_formats[rec->dtrd_format - 1] =
rec->dtrd_action == DTRACEACT_PRINTA ?
dtrace_printa_create(dtp, fmt.dtfd_string) :
dtrace_printf_create(dtp, fmt.dtfd_string);
free(fmt.dtfd_string);
if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
rval = -1; /* dt_errno is set for us */
goto err;
}
}
dtp->dt_pdesc[id] = probe;
@ -330,7 +356,7 @@ dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
agg->dtagd_id = id;
agg->dtagd_nrecs = 1;
#if defined(sun)
#ifdef illumos
if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
#else
if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
@ -353,7 +379,7 @@ dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
if ((agg = nagg) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
#if defined(sun)
#ifdef illumos
rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
#else
rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
@ -440,3 +466,28 @@ dt_aggid_destroy(dtrace_hdl_t *dtp)
dtp->dt_aggdesc = NULL;
dtp->dt_maxagg = 0;
}
const char *
dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
{
if (idx == 0 || idx > dtp->dt_maxstrdata)
return (NULL);
if (dtp->dt_strdata == NULL)
return (NULL);
return (dtp->dt_strdata[idx - 1]);
}
void
dt_strdata_destroy(dtrace_hdl_t *dtp)
{
int i;
for (i = 0; i < dtp->dt_maxstrdata; i++) {
free(dtp->dt_strdata[i]);
}
free(dtp->dt_strdata);
dtp->dt_strdata = NULL;
}

View File

@ -18,17 +18,16 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#ifndef ELFSIZE
#define ELFSIZE ARCH_ELFSIZE
#endif
#include <sys/types.h>
#if defined(sun)
#ifdef illumos
#include <sys/modctl.h>
#include <sys/kobj.h>
#include <sys/kobj_impl.h>
@ -38,12 +37,12 @@
#else
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#endif
#include <unistd.h>
#if defined(sun)
#ifdef illumos
#include <project.h>
#endif
#include <strings.h>
@ -53,8 +52,9 @@
#include <assert.h>
#include <errno.h>
#include <dirent.h>
#if !defined(sun)
#ifndef illumos
#include <fcntl.h>
#include <libproc_compat.h>
#endif
#include <dt_strtab.h>
@ -83,12 +83,21 @@ dt_module_syminit32(dt_module_t *dmp)
#if STT_NUM != (STT_TLS + 1)
#error "STT_NUM has grown. update dt_module_syminit32()"
#endif
Elf32_Sym *sym = dmp->dm_symtab.cts_data;
const char *base = dmp->dm_strtab.cts_data;
size_t ss_size = dmp->dm_strtab.cts_size;
uint_t i, n = dmp->dm_nsymelems;
uint_t asrsv = 0;
#if defined(__FreeBSD__) || defined(__NetBSD__)
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);
@ -103,8 +112,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__) || defined(__NetBSD__)
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
}
@ -120,12 +133,21 @@ dt_module_syminit64(dt_module_t *dmp)
#if STT_NUM != (STT_TLS + 1)
#error "STT_NUM has grown. update dt_module_syminit64()"
#endif
Elf64_Sym *sym = dmp->dm_symtab.cts_data;
const char *base = dmp->dm_strtab.cts_data;
size_t ss_size = dmp->dm_strtab.cts_size;
uint_t i, n = dmp->dm_nsymelems;
uint_t asrsv = 0;
#if defined(__FreeBSD__) || defined(__NetBSD__)
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);
@ -139,9 +161,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__) || defined(__NetBSD__)
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
}
@ -442,6 +467,9 @@ static const dt_modops_t dt_modops_64 = {
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;
@ -465,6 +493,32 @@ dt_module_create(dtrace_hdl_t *dtp, const char *name)
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);
}
@ -489,6 +543,22 @@ dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
return (ctfp ? ctf_getspecific(ctfp) : NULL);
}
#if defined(__FreeBSD__) || defined(__NetBSD__)
dt_kmodule_t *
dt_kmodule_lookup(dtrace_hdl_t *dtp, const char *name)
{
uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
dt_kmodule_t *dkmp;
for (dkmp = dtp->dt_kmods[h]; dkmp != NULL; dkmp = dkmp->dkm_next) {
if (strcmp(dkmp->dkm_name, name) == 0)
return (dkmp);
}
return (NULL);
}
#endif
static int
dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
{
@ -498,7 +568,7 @@ dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
Elf_Data *dp;
Elf_Scn *sp;
if (elf_getshstrndx(dmp->dm_elf, &shstrs) == 0)
if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1)
return (dt_set_errno(dtp, EDT_NOTLOADED));
for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
@ -519,7 +589,7 @@ dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
return (0);
#if defined(sun)
#ifdef illumos
ctsp->cts_data = dp->d_buf;
#else
if ((ctsp->cts_data = malloc(dp->d_size)) == NULL)
@ -534,12 +604,169 @@ dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
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%x`%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;
@ -625,6 +852,14 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
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)
{
@ -698,10 +933,12 @@ err:
void
dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
int i;
ctf_close(dmp->dm_ctfp);
dmp->dm_ctfp = NULL;
#if !defined(sun)
#ifndef illumos
if (dmp->dm_ctdata.cts_data != NULL) {
free(dmp->dm_ctdata.cts_data);
}
@ -713,6 +950,17 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
}
#endif
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));
@ -731,7 +979,12 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
free(dmp->dm_asmap);
dmp->dm_asmap = NULL;
}
#if defined(__FreeBSD__) || defined(__NetBSD__)
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;
@ -753,16 +1006,33 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
(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)
{
uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
dt_module_t **dmpp = &dtp->dt_mods[h];
dt_list_delete(&dtp->dt_modlist, dmp);
assert(dtp->dt_nmods != 0);
dtp->dt_nmods--;
/*
* Now remove this module from its hash chain. We expect to always
* find the module on its hash chain, so in this loop we assert that
* we don't run off the end of the list.
*/
while (*dmpp != dmp) {
dmpp = &((*dmpp)->dm_next);
assert(*dmpp != NULL);
}
*dmpp = dmp->dm_next;
dt_module_unload(dtp, dmp);
free(dmp);
}
@ -826,6 +1096,34 @@ dt_module_modelname(dt_module_t *dmp)
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>/.
@ -833,12 +1131,23 @@ dt_module_modelname(dt_module_t *dmp)
* On FreeBSD, the module name is passed as the full module file name,
* including the path.
*/
#ifndef __NetBSD__
static void
#ifdef illumos
dt_module_update(dtrace_hdl_t *dtp, const char *name)
#elif defined(__FreeBSD__)
dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
#endif
{
char fname[MAXPATHLEN];
struct stat64 st;
int fd, err, bits;
#if defined(__FreeBSD__)
struct module_stat ms;
dt_kmodule_t *dkmp;
uint_t h;
int modid;
#endif
dt_module_t *dmp;
const char *s;
@ -847,43 +1156,19 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
Elf_Data *dp;
Elf_Scn *sp;
#if defined(sun)
#ifdef illumos
(void) snprintf(fname, sizeof (fname),
"%s/%s/object", OBJFS_ROOT, name);
#else
#if 0
#elif defined(__FreeBSD__)
GElf_Ehdr ehdr;
GElf_Phdr ph;
int i;
#endif
int mib_osrel[2] = { CTL_KERN, KERN_OSRELEASE };
int mib_mach[2] = { CTL_HW, HW_MACHINE };
char osrel[64];
char machine[64];
size_t len;
char name[MAXPATHLEN];
uintptr_t mapbase, alignmask;
int i = 0;
int is_elf_obj;
if (strcmp("netbsd",name) == 0) {
/* want the kernel */
strncpy(fname, "/netbsd", sizeof(fname));
} else {
/* build stand module path from system */
len = sizeof(osrel);
if (sysctl(mib_osrel, 2, osrel, &len, NULL, 0) == -1) {
dt_dprintf("sysctl osrel failed: %s\n",
strerror(errno));
return;
}
len = sizeof(machine);
if (sysctl(mib_mach, 2, machine, &len, NULL, 0) == -1) {
dt_dprintf("sysctl machine failed: %s\n",
strerror(errno));
return;
}
(void) snprintf(fname, sizeof (fname),
"/stand/%s/%s/modules/%s/%s.kmod", machine, osrel, name, name);
}
(void) strlcpy(name, k_stat->name, sizeof(name));
(void) strlcpy(fname, k_stat->pathname, sizeof(fname));
#endif
if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
@ -904,7 +1189,7 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
(void) close(fd);
if (dmp->dm_elf == NULL || err == -1 ||
elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) {
elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
dt_dprintf("failed to load %s: %s\n",
fname, elf_errmsg(elf_errno()));
dt_module_destroy(dtp, dmp);
@ -925,7 +1210,20 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
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.
@ -934,7 +1232,19 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
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 (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
alignmask = sh.sh_addralign - 1;
mapbase += alignmask;
mapbase &= ~alignmask;
sh.sh_addr = mapbase;
if (is_elf_obj)
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;
@ -956,11 +1266,17 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
}
dmp->dm_flags |= DT_DM_KERNEL;
#if defined(sun)
#ifdef illumos
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__)
#if 0 /* XXX TBD needs module support */
/*
* Find the first load section and figure out the relocation
* offset for the symbols. The kernel module will not need
@ -973,15 +1289,42 @@ dt_module_update(dtrace_hdl_t *dtp, const char *name)
}
}
#endif
#endif
#endif
#endif /* illumos */
if (dmp->dm_info.objfs_info_primary)
dmp->dm_flags |= DT_DM_PRIMARY;
#if defined(__FreeBSD__)
ms.version = sizeof(ms);
for (modid = kldfirstmod(k_stat->id); modid > 0;
modid = modnext(modid)) {
if (modstat(modid, &ms) != 0) {
dt_dprintf("modstat failed for id %d in %s: %s\n",
modid, k_stat->name, strerror(errno));
continue;
}
if (dt_kmodule_lookup(dtp, ms.name) != NULL)
continue;
dkmp = malloc(sizeof (*dkmp));
if (dkmp == NULL) {
dt_dprintf("failed to allocate memory\n");
dt_module_destroy(dtp, dmp);
return;
}
h = dt_strtab_hash(ms.name, NULL) % dtp->dt_modbuckets;
dkmp->dkm_next = dtp->dt_kmods[h];
dkmp->dkm_name = strdup(ms.name);
dkmp->dkm_module = dmp;
dtp->dt_kmods[h] = dkmp;
}
#endif
dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
}
#endif
/*
* Unload all the loaded modules and then refresh the module cache with the
@ -991,10 +1334,9 @@ void
dtrace_update(dtrace_hdl_t *dtp)
{
dt_module_t *dmp;
#if defined(sun)
#ifdef illumos
DIR *dirp;
#endif
#if defined(__FreeBSD__)
#elif defined(__FreeBSD__)
int fileid;
#endif
@ -1002,7 +1344,7 @@ dtrace_update(dtrace_hdl_t *dtp)
dmp != NULL; dmp = dt_list_next(dmp))
dt_module_unload(dtp, dmp);
#if defined(sun)
#ifdef illumos
/*
* Open /system/object and attempt to create a libdtrace module for
* each kernel module that is loaded on the current system.
@ -1029,9 +1371,6 @@ dtrace_update(dtrace_hdl_t *dtp)
if (kldstat(fileid, &k_stat) == 0)
dt_module_update(dtp, &k_stat);
}
#else
/* XXX just the kernel for now */
dt_module_update(dtp, "netbsd");
#endif
/*
@ -1045,11 +1384,11 @@ dtrace_update(dtrace_hdl_t *dtp)
dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
#if defined(sun)
#ifdef illumos
dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
#endif
dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
#if defined(sun)
#ifdef illumos
dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
#endif
dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
@ -1248,9 +1587,11 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
dtrace_typeinfo_t ti;
dt_module_t *dmp;
int found = 0;
ctf_id_t id;
uint_t n;
ctf_id_t id = CTF_ERR; // XXX: gcc
uint_t n, i;
int justone;
ctf_file_t *fp = NULL; // XXX: gcc
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 */
@ -1265,7 +1606,6 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
return (-1); /* dt_errno is set for us */
n = 1;
justone = 1;
} else {
if (object == DTRACE_OBJ_KMODS)
mask = bits = DT_DM_KERNEL;
@ -1289,7 +1629,7 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
* 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 (dt_module_hasctf(dtp, dmp) == 0) {
if (justone)
return (-1);
continue;
@ -1301,13 +1641,38 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
* '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) {
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 = dmp->dm_ctfp;
tip->dtt_ctfp = fp;
tip->dtt_type = id;
if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve(
dmp->dm_ctfp, id)) != CTF_K_FORWARD)
if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) !=
CTF_K_FORWARD)
return (0);
found++;
@ -1329,6 +1694,7 @@ dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
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));

View File

@ -23,12 +23,13 @@
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#ifndef _DT_MODULE_H
#define _DT_MODULE_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dt_impl.h>
#ifdef __cplusplus
@ -43,11 +44,20 @@ extern void dt_module_destroy(dtrace_hdl_t *, dt_module_t *);
extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *);
#if defined(__FreeBSD__) || defined(__NetBSD__)
extern dt_kmodule_t *dt_kmodule_lookup(dtrace_hdl_t *, const char *);
#endif
extern int dt_module_hasctf(dtrace_hdl_t *, dt_module_t *);
extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *);
extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *,
const char *, const dtrace_typeinfo_t *);
extern const char *dt_module_modelname(dt_module_t *);
extern int dt_module_getlibid(dtrace_hdl_t *, dt_module_t *,
const ctf_file_t *);
extern ctf_file_t *dt_module_getctflib(dtrace_hdl_t *, dt_module_t *,
const char *);
#ifdef __cplusplus
}

View File

@ -20,22 +20,25 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#if defined(sun)
#ifdef illumos
#include <sys/modctl.h>
#include <sys/systeminfo.h>
#else
#include <sys/param.h>
#include <sys/module.h>
#include <sys/linker.h>
#endif
#include <sys/resource.h>
#include <libelf.h>
#include <strings.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <limits.h>
@ -56,7 +59,7 @@
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_provider.h>
#if !defined(sun)
#ifndef illumos
#include <sys/sysctl.h>
#include <string.h>
#endif
@ -93,7 +96,7 @@
/*
* The version number should be increased for every customer visible release
* of Solaris. The major number should be incremented when a fundamental
* of DTrace. The major number should be incremented when a fundamental
* change has been made that would affect all consumers, and would reflect
* sweeping changes to DTrace or the D language. The minor number should be
* incremented when a change is introduced that could break scripts that had
@ -116,8 +119,19 @@
#define DT_VERS_1_6 DT_VERSION_NUMBER(1, 6, 0)
#define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1)
#define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2)
#define DT_VERS_LATEST DT_VERS_1_6_2
#define DT_VERS_STRING "Sun D 1.6.2"
#define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3)
#define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0)
#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1)
#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0)
#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1)
#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
#define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1)
#define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0)
#define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0)
#define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0)
#define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1)
#define DT_VERS_LATEST DT_VERS_1_12_1
#define DT_VERS_STRING "Sun D 1.12.1"
const dt_version_t _dtrace_versions[] = {
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@ -132,17 +146,29 @@ const dt_version_t _dtrace_versions[] = {
DT_VERS_1_6, /* D API 1.6 */
DT_VERS_1_6_1, /* D API 1.6.1 */
DT_VERS_1_6_2, /* D API 1.6.2 */
DT_VERS_1_6_3, /* D API 1.6.3 */
DT_VERS_1_7, /* D API 1.7 */
DT_VERS_1_7_1, /* D API 1.7.1 */
DT_VERS_1_8, /* D API 1.8 */
DT_VERS_1_8_1, /* D API 1.8.1 */
DT_VERS_1_9, /* D API 1.9 */
DT_VERS_1_9_1, /* D API 1.9.1 */
DT_VERS_1_10, /* D API 1.10 */
DT_VERS_1_11, /* D API 1.11 */
DT_VERS_1_12, /* D API 1.12 */
DT_VERS_1_12_1, /* D API 1.12.1 */
0
};
/*
* Global variables that are formatted on FreeBSD based on the kernel file name.
*/
#if !defined(sun)
#ifndef illumos
static char curthread_str[MAXPATHLEN];
static char intmtx_str[MAXPATHLEN];
static char threadmtx_str[MAXPATHLEN];
static char rwlock_str[MAXPATHLEN];
static char sxlock_str[MAXPATHLEN];
#endif
/*
@ -219,7 +245,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD,
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
DTRACE_CLASS_COMMON }, DT_VERS_1_0,
#if defined(sun)
#ifdef illumos
&dt_idops_type, "genunix`kthread_t *" },
#else
&dt_idops_type, curthread_str },
@ -261,6 +287,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "uint64_t(uint64_t)" },
{ "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3,
&dt_idops_func, "uint16_t(uint16_t)" },
{ "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10,
&dt_idops_func, "file_t *(int)" },
{ "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "gid_t" },
{ "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0,
@ -268,13 +296,13 @@ static const dt_ident_t _dtrace_globals[] = {
{ "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "int(const char *, const char *, [int])" },
{ "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN,
#if defined(sun)
#ifdef illumos
DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" },
#else
DT_VERS_1_5, &dt_idops_func, "string(in_addr_t *)" },
#endif
{ "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN,
#if defined(sun)
#ifdef illumos
DT_VERS_1_5, &dt_idops_func, "string(in6_addr_t *)" },
#else
DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" },
@ -283,12 +311,15 @@ static const dt_ident_t _dtrace_globals[] = {
DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
{ "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint_t" },
#if defined(sun)
{ "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11,
&dt_idops_func, "string(const char *, const char *)" },
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "stack(...)" },
#endif
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "string(int64_t)" },
&dt_idops_func, "string(int64_t, [int])" },
{ "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN,
DT_VERS_1_7, &dt_idops_func,
"void(@, int32_t, int32_t, int32_t, int32_t, ...)" },
{ "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, int32_t, int32_t, ...)" },
@ -296,6 +327,10 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(@)" },
{ "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "uintptr_t *(void *, size_t)" },
#ifndef illumos
{ "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "string(void *, char, size_t)" },
#endif
{ "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
{ "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
@ -306,7 +341,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "msgsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGSIZE,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "size_t(mblk_t *)" },
#if defined(sun)
#ifdef illumos
{ "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, "int(genunix`kmutex_t *)" },
@ -347,6 +382,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_type, "pid_t" },
{ "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "pid_t" },
{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9,
&dt_idops_func, "void(@)" },
{ "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, ...)" },
{ "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
@ -375,7 +412,7 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "int()" },
{ "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "int(const char *, const char *, [int])" },
#if defined(sun)
#ifdef illumos
{ "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, "int(genunix`krwlock_t *)" },
@ -427,10 +464,23 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "string(const char *, const char *)" },
{ "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "string(const char *, const char *)" },
{ "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11,
&dt_idops_func, "int64_t(const char *, [int])" },
{ "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "string(const char *, int, [int])" },
{ "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
#ifndef illumos
{ "sx_isexclusive", DT_IDENT_FUNC, 0, DIF_SUBR_SX_ISEXCLUSIVE,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, sxlock_str },
{ "sx_shared_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_SHARED_HELD,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, sxlock_str },
{ "sx_exclusive_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_EXCLUSIVE_HELD,
DT_ATTR_EVOLCMN, DT_VERS_1_0,
&dt_idops_func, sxlock_str },
#endif
{ "sym", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" },
{ "system", DT_IDENT_ACTFUNC, 0, DT_ACT_SYSTEM, DT_ATTR_STABCMN, DT_VERS_1_0,
@ -442,26 +492,27 @@ static const dt_ident_t _dtrace_globals[] = {
{ "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint64_t" },
{ "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8,
&dt_idops_func, "string(const char *)" },
{ "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8,
&dt_idops_func, "string(const char *)" },
{ "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
{ "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, size_t)" },
&dt_idops_func, "void(@, size_t, ...)" },
{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void(...)" },
{ "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "uintptr_t *(void *, size_t, string, size_t)" },
#if defined(sun)
{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_type, "uint64_t" },
{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
{ "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uid_t" },
#if defined(sun)
{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
@ -473,17 +524,22 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_type, "uint32_t" },
{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
{ "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint64_t" },
{ "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "int64_t" },
#if defined(sun)
#ifdef illumos
{ "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME,
DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
#endif
#ifndef illumos
{ "cpu", DT_IDENT_SCALAR, 0, DIF_VAR_CPU,
DT_ATTR_STABCMN, DT_VERS_1_6_3, &dt_idops_type, "int" },
#endif
{ NULL, 0, 0, 0, { 0, 0, 0 }, 0, NULL, NULL }
};
@ -723,18 +779,20 @@ const dtrace_pattr_t _dtrace_prvdesc = {
{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
};
#if defined(sun)
#ifdef illumos
const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */
const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */
#else
const char *_dtrace_defcpp = "cpp"; /* default cpp(1) to invoke */
const char *_dtrace_defld = "ld"; /* default ld(1) to invoke */
const char *_dtrace_defobjcopy = "objcopy"; /* default objcopy(1) to invoke */
#endif
const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */
#if defined(sun)
#ifdef illumos
const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */
#else
const char *_dtrace_libdir32 = "/usr/lib32/dtrace";
const char *_dtrace_provdir = "/dev/dtrace"; /* provider directory */
#endif
@ -749,9 +807,7 @@ int _dtrace_argmax = 32; /* default maximum number of probe arguments */
int _dtrace_debug = 0; /* debug messages enabled (off) */
const char *const _dtrace_version = DT_VERS_STRING; /* API version string */
#if defined(sun)
int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */
#endif
typedef struct dt_fdlist {
int *df_fds; /* array of provider driver file descriptors */
@ -759,7 +815,7 @@ typedef struct dt_fdlist {
uint_t df_size; /* size of df_fds[] */
} dt_fdlist_t;
#if defined(sun)
#ifdef illumos
#pragma init(_dtrace_init)
#else
void _dtrace_init(void) __attribute__ ((constructor));
@ -769,18 +825,14 @@ _dtrace_init(void)
{
_dtrace_debug = getenv("DTRACE_DEBUG") != NULL;
#if defined(sun)
for (; _dtrace_rdvers > 0; _dtrace_rdvers--) {
if (rd_init(_dtrace_rdvers) == RD_OK)
break;
}
#endif
#if defined(__i386__)
#if 0 /* XXX TBD - no NetBSD equivalent? */
/* make long doubles 64 bits -sson */
(void) fpsetprec(FP_PE);
#endif
#endif
}
static dtrace_hdl_t *
@ -799,7 +851,7 @@ dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp)
dt_provmod_t *prov;
char path[PATH_MAX];
int fd;
#if defined(sun)
#ifdef illumos
struct dirent *dp, *ep;
DIR *dirp;
@ -846,7 +898,7 @@ dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp)
}
(void) closedir(dirp);
#else
#else /* !illumos */
char *p;
char *p1;
char *p_providers = NULL;
@ -931,7 +983,7 @@ dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp)
}
if (p_providers != NULL)
free(p_providers);
#endif
#endif /* illumos */
}
static void
@ -948,7 +1000,7 @@ dt_provmod_destroy(dt_provmod_t **provmod)
*provmod = NULL;
}
#if defined(sun)
#ifdef illumos
static const char *
dt_get_sysinfo(int cmd, char *buf, size_t len)
{
@ -987,7 +1039,7 @@ dt_vopen(int version, int flags, int *errp,
dt_fdlist_t df = { NULL, 0, 0 };
#if defined(sun)
#if defined(__FreeBSD__)
char isadef[32], utsdef[32];
char s1[64], s2[64];
#endif
@ -1052,8 +1104,18 @@ dt_vopen(int version, int flags, int *errp,
dtfd = open("/dev/dtrace/dtrace", O_RDWR);
err = errno; /* save errno from opening dtfd */
#if defined(sun)
#if defined(__FreeBSD__)
/*
* Automatically load the 'dtraceall' module if we couldn't open the
* char device.
*/
if (err == ENOENT && modfind("dtraceall") < 0) {
kldload("dtraceall"); /* ignore the error */
dtfd = open("/dev/dtrace/dtrace", O_RDWR);
err = errno;
}
#endif
#ifdef illumos
ftfd = open("/dev/dtrace/provider/fasttrap", O_RDWR);
#else
ftfd = open("/dev/dtrace/fasttrap", O_RDWR);
@ -1095,24 +1157,32 @@ alloc:
bzero(dtp, sizeof (dtrace_hdl_t));
dtp->dt_oflags = flags;
#ifdef illumos
dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
#else
dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
#endif
dtp->dt_linkmode = DT_LINK_KERNEL;
dtp->dt_linktype = DT_LTYP_ELF;
dtp->dt_xlatemode = DT_XL_STATIC;
dtp->dt_stdcmode = DT_STDC_XA;
dtp->dt_encoding = DT_ENCODING_UNSET;
dtp->dt_version = version;
dtp->dt_fd = dtfd;
dtp->dt_ftfd = ftfd;
dtp->dt_fterr = fterr;
dtp->dt_cdefs_fd = -1;
dtp->dt_ddefs_fd = -1;
#if defined(sun)
#ifdef illumos
dtp->dt_stdout_fd = -1;
#else
dtp->dt_freopen_fp = NULL;
#endif
dtp->dt_modbuckets = _dtrace_strbuckets;
dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *));
#if defined(__FreeBSD__) || defined(__NetBSD__)
dtp->dt_kmods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *));
#endif
dtp->dt_provbuckets = _dtrace_strbuckets;
dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *));
dt_proc_hash_create(dtp);
@ -1122,6 +1192,9 @@ alloc:
dtp->dt_cpp_argc = 1;
dtp->dt_cpp_args = 1;
dtp->dt_ld_path = strdup(_dtrace_defld);
#if defined(__FreeBSD__) || defined(__NetBSD__)
dtp->dt_objcopy_path = strdup(_dtrace_defobjcopy);
#endif
dtp->dt_provmod = provmod;
dtp->dt_vector = vector;
dtp->dt_varg = arg;
@ -1130,6 +1203,10 @@ alloc:
if (dtp->dt_mods == NULL || dtp->dt_provs == NULL ||
dtp->dt_procs == NULL || dtp->dt_ld_path == NULL ||
#if defined(__FreeBSD__) || defined(__NetBSD__)
dtp->dt_kmods == NULL ||
dtp->dt_objcopy_path == NULL ||
#endif
dtp->dt_cpp_path == NULL || dtp->dt_cpp_argv == NULL)
return (set_open_errno(dtp, errp, EDT_NOMEM));
@ -1138,7 +1215,7 @@ alloc:
dtp->dt_cpp_argv[0] = (char *)strbasename(dtp->dt_cpp_path);
#if defined(sun)
#ifdef illumos
(void) snprintf(isadef, sizeof (isadef), "-D__SUNW_D_%u",
(uint_t)(sizeof (void *) * NBBY));
@ -1178,7 +1255,7 @@ alloc:
return (set_open_errno(dtp, errp, EDT_NOMEM));
#endif
#if defined(sun)
#ifdef illumos
#ifdef __x86
/*
* On x86 systems, __i386 is defined for <sys/isa_defs.h> for 32-bit
@ -1218,12 +1295,10 @@ alloc:
* 'kern.bootfile' sysctl value tells us exactly which file is being
* used as the kernel.
*/
#if !defined(sun)
#ifndef illumos
{
char *p;
#if 0 /* XXX debug */
char bootfile[MAXPATHLEN];
int i;
char *p;
size_t len = sizeof(bootfile);
/* This call shouldn't fail, but use a default just in case. */
@ -1234,17 +1309,15 @@ alloc:
p++;
else
p = bootfile;
#else
p = "netbsd";
#endif
/*
* Format the global variables based on the kernel module name.
*/
snprintf(curthread_str, sizeof(curthread_str), "%s`struct lwp *",p);
snprintf(intmtx_str, sizeof(intmtx_str), "int(%s`struct kmutex *)",p);
snprintf(threadmtx_str, sizeof(threadmtx_str), "struct lwp *(%s`struct kmutex *)",p);
snprintf(curthread_str, sizeof(curthread_str), "%s`struct thread *",p);
snprintf(intmtx_str, sizeof(intmtx_str), "int(%s`struct mtx *)",p);
snprintf(threadmtx_str, sizeof(threadmtx_str), "struct thread *(%s`struct mtx *)",p);
snprintf(rwlock_str, sizeof(rwlock_str), "int(%s`struct rwlock *)",p);
snprintf(sxlock_str, sizeof(sxlock_str), "int(%s`struct sxlock *)",p);
}
#endif
@ -1514,8 +1587,19 @@ alloc:
* compile, and to provide better error reporting (because the full
* reporting of compiler errors requires dtrace_open() to succeed).
*/
#if defined(__FreeBSD__) || defined(__NetBSD__)
#ifdef __LP64__
if ((dtp->dt_oflags & DTRACE_O_ILP32) != 0) {
if (dtrace_setopt(dtp, "libdir", _dtrace_libdir32) != 0)
return (set_open_errno(dtp, errp, dtp->dt_errno));
}
#endif
if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
return (set_open_errno(dtp, errp, dtp->dt_errno));
#else
if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
return (set_open_errno(dtp, errp, dtp->dt_errno));
#endif
return (dtp);
}
@ -1542,6 +1626,10 @@ dtrace_close(dtrace_hdl_t *dtp)
dtrace_prog_t *pgp;
dt_xlator_t *dxp;
dt_dirpath_t *dirp;
#if defined(__FreeBSD__) || defined(__NetBSD__)
dt_kmodule_t *dkm;
uint_t h;
#endif
int i;
if (dtp->dt_procs != NULL)
@ -1569,6 +1657,15 @@ dtrace_close(dtrace_hdl_t *dtp)
if (dtp->dt_tls != NULL)
dt_idhash_destroy(dtp->dt_tls);
#if defined(__FreeBSD__) || defined(__NetBSD__)
for (h = 0; h < dtp->dt_modbuckets; h++)
while ((dkm = dtp->dt_kmods[h]) != NULL) {
dtp->dt_kmods[h] = dkm->dkm_next;
free(dkm->dkm_name);
free(dkm);
}
#endif
while ((dmp = dt_list_next(&dtp->dt_modlist)) != NULL)
dt_module_destroy(dtp, dmp);
@ -1583,7 +1680,7 @@ dtrace_close(dtrace_hdl_t *dtp)
(void) close(dtp->dt_cdefs_fd);
if (dtp->dt_ddefs_fd != -1)
(void) close(dtp->dt_ddefs_fd);
#if defined(sun)
#ifdef illumos
if (dtp->dt_stdout_fd != -1)
(void) close(dtp->dt_stdout_fd);
#else
@ -1594,9 +1691,9 @@ dtrace_close(dtrace_hdl_t *dtp)
dt_epid_destroy(dtp);
dt_aggid_destroy(dtp);
dt_format_destroy(dtp);
dt_strdata_destroy(dtp);
dt_buffered_destroy(dtp);
dt_aggregate_destroy(dtp);
free(dtp->dt_buf.dtbd_data);
dt_pfdict_destroy(dtp);
dt_provmod_destroy(&dtp->dt_provmod);
dt_dof_fini(dtp);
@ -1613,8 +1710,14 @@ dtrace_close(dtrace_hdl_t *dtp)
free(dtp->dt_cpp_argv);
free(dtp->dt_cpp_path);
free(dtp->dt_ld_path);
#if defined(__FreeBSD__) || defined(__NetBSD__)
free(dtp->dt_objcopy_path);
#endif
free(dtp->dt_mods);
#if defined(__FreeBSD__) || defined(__NetBSD__)
free(dtp->dt_kmods);
#endif
free(dtp->dt_provs);
free(dtp);
}

View File

@ -24,7 +24,10 @@
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <sys/resource.h>
#include <sys/mman.h>
@ -35,7 +38,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <errno.h>
@ -277,6 +280,28 @@ dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (0);
}
#if defined(__FreeBSD__) || defined(__NetBSD__)
static int
dt_opt_objcopy_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
char *objcopy;
if (arg == NULL)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
if (dtp->dt_pcb != NULL)
return (dt_set_errno(dtp, EDT_BADOPTCTX));
if ((objcopy = strdup(arg)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
free(dtp->dt_objcopy_path);
dtp->dt_objcopy_path = objcopy;
return (0);
}
#endif
/*ARGSUSED*/
static int
dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@ -334,6 +359,23 @@ dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (0);
}
/*ARGSUSED*/
static int
dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
if (arg == NULL)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
if (strcmp(arg, "ascii") == 0)
dtp->dt_encoding = DT_ENCODING_ASCII;
else if (strcmp(arg, "utf8") == 0)
dtp->dt_encoding = DT_ENCODING_UTF8;
else
return (dt_set_errno(dtp, EDT_BADOPTVAL));
return (0);
}
/*ARGSUSED*/
static int
dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@ -368,6 +410,61 @@ dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (0);
}
static int
dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
char **p;
char *var;
int i;
/*
* We can't effectively set environment variables from #pragma lines
* since the processes have already been spawned.
*/
if (dtp->dt_pcb != NULL)
return (dt_set_errno(dtp, EDT_BADOPTCTX));
if (arg == NULL)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
if (!option && strchr(arg, '=') != NULL)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
continue;
for (p = dtp->dt_proc_env; *p != NULL; p++) {
var = strchr(*p, '=');
if (var == NULL)
var = *p + strlen(*p);
if (strncmp(*p, arg, var - *p) == 0) {
dt_free(dtp, *p);
*p = dtp->dt_proc_env[i - 1];
dtp->dt_proc_env[i - 1] = NULL;
i--;
}
}
if (option) {
if ((var = strdup(arg)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
dt_free(dtp, var);
return (dt_set_errno(dtp, EDT_NOMEM));
}
bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
dt_free(dtp, dtp->dt_proc_env);
dtp->dt_proc_env = p;
dtp->dt_proc_env[i - 1] = var;
dtp->dt_proc_env[i] = NULL;
}
return (0);
}
/*ARGSUSED*/
static int
dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@ -411,7 +508,6 @@ dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (0);
}
/*ARGSUSED*/
static int
dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@ -786,7 +882,7 @@ int
dt_options_load(dtrace_hdl_t *dtp)
{
dof_hdr_t hdr, *dof;
dof_sec_t *sec = NULL;
dof_sec_t *sec = NULL; // XXX: gcc
size_t offs;
int i;
@ -797,7 +893,7 @@ dt_options_load(dtrace_hdl_t *dtp)
bzero(&hdr, sizeof (dof_hdr_t));
hdr.dofh_loadsz = sizeof (dof_hdr_t);
#if defined(sun)
#ifdef illumos
if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
#else
dof = &hdr;
@ -815,7 +911,7 @@ dt_options_load(dtrace_hdl_t *dtp)
for (i = 0; i < DTRACEOPT_MAX; i++)
dtp->dt_options[i] = DTRACEOPT_UNSET;
#if defined(sun)
#ifdef illumos
if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
#else
if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
@ -848,30 +944,6 @@ dt_options_load(dtrace_hdl_t *dtp)
return (0);
}
/*ARGSUSED*/
static int
dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
dtrace_optval_t size;
void *p;
if (arg == NULL || dt_optval_parse(arg, &size) != 0)
return (dt_set_errno(dtp, EDT_BADOPTVAL));
if (size > SIZE_MAX)
size = SIZE_MAX;
if ((p = dt_zalloc(dtp, size)) == NULL) {
do {
size /= 2;
} while ((p = dt_zalloc(dtp, size)) == NULL);
}
dt_free(dtp, p);
return (0);
}
typedef struct dt_option {
const char *o_name;
int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
@ -896,6 +968,7 @@ static const dt_option_t _dtrace_ctoptions[] = {
{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
{ "droptags", dt_opt_droptags },
{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
{ "encoding", dt_opt_encoding },
{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
{ "evaltime", dt_opt_evaltime },
{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
@ -909,9 +982,12 @@ static const dt_option_t _dtrace_ctoptions[] = {
{ "linkmode", dt_opt_linkmode },
{ "linktype", dt_opt_linktype },
{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
#if defined(__FreeBSD__) || defined(__NetBSD__)
{ "objcopypath", dt_opt_objcopy_path },
#endif
{ "pgmax", dt_opt_pgmax },
{ "preallocate", dt_opt_preallocate },
{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
{ "setenv", dt_opt_setenv, 1 },
{ "stdc", dt_opt_stdc },
{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
{ "syslibdir", dt_opt_syslibdir },
@ -920,6 +996,7 @@ static const dt_option_t _dtrace_ctoptions[] = {
{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
{ "unsetenv", dt_opt_setenv, 0 },
{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
{ "version", dt_opt_version },
{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
@ -947,6 +1024,7 @@ static const dt_option_t _dtrace_rtoptions[] = {
{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
{ NULL, NULL, 0 }
};
@ -954,11 +1032,14 @@ static const dt_option_t _dtrace_rtoptions[] = {
* Dynamic run-time options.
*/
static const dt_option_t _dtrace_drtoptions[] = {
{ "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
{ "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
{ "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },

View File

@ -22,7 +22,8 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2013, Joyent Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@ -96,11 +97,12 @@
*/
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <setjmp.h>
#include <strings.h>
#include <assert.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <stdlib.h>
@ -195,7 +197,7 @@ dt_type_lookup(const char *s, dtrace_typeinfo_t *tip)
{
static const char delimiters[] = " \t\n\r\v\f*`";
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
const char *p, *q, *end, *obj;
const char *p, *q, *r, *end, *obj;
for (p = s, end = s + strlen(s); *p != '\0'; p = q) {
while (isspace((unsigned char)*p))
@ -223,8 +225,23 @@ dt_type_lookup(const char *s, dtrace_typeinfo_t *tip)
bcopy(s, type, (size_t)(p - s));
bcopy(q + 1, type + (size_t)(p - s), strlen(q + 1) + 1);
if (strchr(q + 1, '`') != NULL)
return (dt_set_errno(dtp, EDT_BADSCOPE));
/*
* There may be at most three delimeters. The second
* delimeter is usually used to distinguish the type
* within a given module, however, there could be a link
* map id on the scene in which case that delimeter
* would be the third. We determine presence of the lmid
* if it rouglhly meets the from LM[0-9]
*/
if ((r = strchr(q + 1, '`')) != NULL &&
((r = strchr(r + 1, '`')) != NULL)) {
if (strchr(r + 1, '`') != NULL)
return (dt_set_errno(dtp,
EDT_BADSCOPE));
if (q[1] != 'L' || q[2] != 'M')
return (dt_set_errno(dtp,
EDT_BADSCOPE));
}
return (dtrace_lookup_by_type(dtp, object, type, tip));
}
@ -254,6 +271,7 @@ dt_type_pointer(dtrace_typeinfo_t *tip)
ctf_file_t *ctfp = tip->dtt_ctfp;
ctf_id_t type = tip->dtt_type;
ctf_id_t base = ctf_type_resolve(ctfp, type);
uint_t bflags = tip->dtt_flags;
dt_module_t *dmp;
ctf_id_t ptr;
@ -285,6 +303,7 @@ dt_type_pointer(dtrace_typeinfo_t *tip)
tip->dtt_object = dmp->dm_name;
tip->dtt_ctfp = dmp->dm_ctfp;
tip->dtt_type = ptr;
tip->dtt_flags = bflags;
return (0);
}
@ -388,7 +407,7 @@ void
dt_node_promote(dt_node_t *lp, dt_node_t *rp, dt_node_t *dnp)
{
dt_type_promote(lp, rp, &dnp->dn_ctfp, &dnp->dn_type);
dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type);
dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type, B_FALSE);
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
}
@ -404,8 +423,8 @@ dt_node_name(const dt_node_t *dnp, char *buf, size_t len)
switch (dnp->dn_kind) {
case DT_NODE_INT:
(void) snprintf(buf, len, "integer constant 0x%" PRIx64,
dnp->dn_value);
(void) snprintf(buf, len, "integer constant 0x%llx",
(unsigned long long)dnp->dn_value);
break;
case DT_NODE_STRING:
s = strchr2esc(dnp->dn_string, strlen(dnp->dn_string));
@ -657,7 +676,8 @@ dt_node_attr_assign(dt_node_t *dnp, dtrace_attribute_t attr)
}
void
dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type)
dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
boolean_t user)
{
ctf_id_t base = ctf_type_resolve(fp, type);
uint_t kind = ctf_type_kind(fp, base);
@ -689,6 +709,9 @@ dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type)
type == DT_DYN_TYPE(yypcb->pcb_hdl))
dnp->dn_flags |= DT_NF_REF;
if (user)
dnp->dn_flags |= DT_NF_USERLAND;
dnp->dn_flags |= DT_NF_COOKED;
dnp->dn_ctfp = fp;
dnp->dn_type = type;
@ -725,12 +748,34 @@ dt_node_type_name(const dt_node_t *dnp, char *buf, size_t len)
size_t
dt_node_type_size(const dt_node_t *dnp)
{
ctf_id_t base;
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
if (dnp->dn_kind == DT_NODE_STRING)
return (strlen(dnp->dn_string) + 1);
if (dt_node_is_dynamic(dnp) && dnp->dn_ident != NULL)
return (dt_ident_size(dnp->dn_ident));
base = ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type);
if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_FORWARD)
return (0);
/*
* Here we have a 32-bit user pointer that is being used with a 64-bit
* kernel. When we're using it and its tagged as a userland reference --
* then we need to keep it as a 32-bit pointer. However, if we are
* referring to it as a kernel address, eg. being used after a copyin()
* then we need to make sure that we actually return the kernel's size
* of a pointer, 8 bytes.
*/
if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_POINTER &&
ctf_getmodel(dnp->dn_ctfp) == CTF_MODEL_ILP32 &&
!(dnp->dn_flags & DT_NF_USERLAND) &&
dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
return (8);
return (ctf_type_size(dnp->dn_ctfp, dnp->dn_type));
}
@ -1008,7 +1053,7 @@ dt_node_is_ptrcompat(const dt_node_t *lp, const dt_node_t *rp,
ctf_id_t lref = CTF_ERR, rref = CTF_ERR;
int lp_is_void, rp_is_void, lp_is_int, rp_is_int, compat;
uint_t lkind, rkind;
uint_t lkind = 0, rkind = 0; // XXX: gcc
ctf_encoding_t e;
ctf_arinfo_t r;
@ -1039,12 +1084,10 @@ dt_node_is_ptrcompat(const dt_node_t *lp, const dt_node_t *rp,
* then resolve the referenced type as well (assuming the base type
* is CTF_K_POINTER or CTF_K_ARRAY). Otherwise [lr]ref = CTF_ERR.
*/
lbase = ctf_type_resolve(lfp, lp->dn_type);
lkind = ctf_type_kind(lfp, lbase);
rbase = ctf_type_resolve(rfp, rp->dn_type);
rkind = ctf_type_kind(rfp, rbase);
if (!lp_is_int) {
lbase = ctf_type_resolve(lfp, lp->dn_type);
lkind = ctf_type_kind(lfp, lbase);
if (lkind == CTF_K_POINTER) {
lref = ctf_type_resolve(lfp,
ctf_type_reference(lfp, lbase));
@ -1055,6 +1098,9 @@ dt_node_is_ptrcompat(const dt_node_t *lp, const dt_node_t *rp,
}
if (!rp_is_int) {
rbase = ctf_type_resolve(rfp, rp->dn_type);
rkind = ctf_type_kind(rfp, rbase);
if (rkind == CTF_K_POINTER) {
rref = ctf_type_resolve(rfp,
ctf_type_reference(rfp, rbase));
@ -1079,8 +1125,7 @@ dt_node_is_ptrcompat(const dt_node_t *lp, const dt_node_t *rp,
rkind = lkind;
rref = lref;
rfp = lfp;
} else
return 0;
}
lp_is_void = ctf_type_encoding(lfp, lref, &e) == 0 && IS_VOID(e);
rp_is_void = ctf_type_encoding(rfp, rref, &e) == 0 && IS_VOID(e);
@ -1217,7 +1262,7 @@ dt_node_int(uintmax_t value)
if (value <= dtp->dt_ints[i].did_limit) {
dt_node_type_assign(dnp,
dtp->dt_ints[i].did_ctfp,
dtp->dt_ints[i].did_type);
dtp->dt_ints[i].did_type, B_FALSE);
/*
* If a prefix character is present in macro text, add
@ -1234,8 +1279,8 @@ dt_node_int(uintmax_t value)
}
}
xyerror(D_INT_OFLOW, "integer constant 0x%" PRIx64
"cannot be represented in any built-in integral type\n", value);
xyerror(D_INT_OFLOW, "integer constant 0x%llx cannot be represented "
"in any built-in integral type\n", (u_longlong_t)value);
/*NOTREACHED*/
return (NULL); /* keep gcc happy */
}
@ -1252,7 +1297,7 @@ dt_node_string(char *string)
dnp = dt_node_alloc(DT_NODE_STRING);
dnp->dn_op = DT_TOK_STRING;
dnp->dn_string = string;
dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp));
dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp), B_FALSE);
return (dnp);
}
@ -1328,7 +1373,8 @@ dt_node_type(dt_decl_t *ddp)
dnp = dt_node_alloc(DT_NODE_TYPE);
dnp->dn_op = DT_TOK_IDENT;
dnp->dn_string = name;
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags);
if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp ||
dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp)
@ -1572,7 +1618,8 @@ dt_node_decl(void)
bzero(&idn, sizeof (dt_node_t));
if (idp != NULL && idp->di_type != CTF_ERR)
dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type);
dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type,
B_FALSE);
else if (idp != NULL)
(void) dt_ident_cook(&idn, idp, NULL);
@ -1782,7 +1829,7 @@ dt_node_offsetof(dt_decl_t *ddp, char *s)
}
bzero(&dn, sizeof (dn));
dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type);
dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type, B_FALSE);
if (dn.dn_flags & DT_NF_BITFIELD) {
xyerror(D_OFFSETOF_BITFIELD,
@ -1838,7 +1885,8 @@ dt_node_op1(int op, dt_node_t *cp)
}
dt_node_type_assign(cp, dtp->dt_ddefs->dm_ctfp,
ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"));
ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
B_FALSE);
cp->dn_kind = DT_NODE_INT;
cp->dn_op = DT_TOK_INT;
@ -1855,6 +1903,38 @@ dt_node_op1(int op, dt_node_t *cp)
return (dnp);
}
/*
* If an integer constant is being cast to another integer type, we can
* perform the cast as part of integer constant folding in this pass. We must
* take action when the integer is being cast to a smaller type or if it is
* changing signed-ness. If so, we first shift rp's bits bits high (losing
* excess bits if narrowing) and then shift them down with either a logical
* shift (unsigned) or arithmetic shift (signed).
*/
static void
dt_cast(dt_node_t *lp, dt_node_t *rp)
{
size_t srcsize = dt_node_type_size(rp);
size_t dstsize = dt_node_type_size(lp);
if (dstsize < srcsize) {
int n = (sizeof (uint64_t) - dstsize) * NBBY;
rp->dn_value <<= n;
rp->dn_value >>= n;
} else if (dstsize > srcsize) {
int n = (sizeof (uint64_t) - srcsize) * NBBY;
int s = (dstsize - srcsize) * NBBY;
rp->dn_value <<= n;
if (rp->dn_flags & DT_NF_SIGNED) {
rp->dn_value = (intmax_t)rp->dn_value >> s;
rp->dn_value >>= n - s;
} else {
rp->dn_value >>= n;
}
}
}
dt_node_t *
dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
{
@ -1884,17 +1964,17 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
case DT_TOK_LOR:
dnp->dn_value = l || r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_LXOR:
dnp->dn_value = (l != 0) ^ (r != 0);
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_LAND:
dnp->dn_value = l && r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_BOR:
dnp->dn_value = l | r;
@ -1911,12 +1991,12 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
case DT_TOK_EQU:
dnp->dn_value = l == r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_NEQ:
dnp->dn_value = l != r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_LT:
dt_node_promote(lp, rp, dnp);
@ -1925,7 +2005,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
else
dnp->dn_value = l < r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_LE:
dt_node_promote(lp, rp, dnp);
@ -1934,7 +2014,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
else
dnp->dn_value = l <= r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_GT:
dt_node_promote(lp, rp, dnp);
@ -1943,7 +2023,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
else
dnp->dn_value = l > r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_GE:
dt_node_promote(lp, rp, dnp);
@ -1952,7 +2032,7 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
else
dnp->dn_value = l >= r;
dt_node_type_assign(dnp,
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
break;
case DT_TOK_LSH:
dnp->dn_value = l << r;
@ -2004,32 +2084,9 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
}
}
/*
* If an integer constant is being cast to another integer type, we can
* perform the cast as part of integer constant folding in this pass.
* We must take action when the integer is being cast to a smaller type
* or if it is changing signed-ness. If so, we first shift rp's bits
* bits high (losing excess bits if narrowing) and then shift them down
* with either a logical shift (unsigned) or arithmetic shift (signed).
*/
if (op == DT_TOK_LPAR && rp->dn_kind == DT_NODE_INT &&
dt_node_is_integer(lp)) {
size_t srcsize = dt_node_type_size(rp);
size_t dstsize = dt_node_type_size(lp);
if ((dstsize < srcsize) || ((lp->dn_flags & DT_NF_SIGNED) ^
(rp->dn_flags & DT_NF_SIGNED))) {
int n = dstsize < srcsize ?
(sizeof (uint64_t) * NBBY - dstsize * NBBY) :
(sizeof (uint64_t) * NBBY - srcsize * NBBY);
rp->dn_value <<= n;
if (lp->dn_flags & DT_NF_SIGNED)
rp->dn_value = (intmax_t)rp->dn_value >> n;
else
rp->dn_value = rp->dn_value >> n;
}
dt_cast(lp, rp);
dt_node_type_propagate(lp, rp);
dt_node_attr_assign(rp, dt_attr_min(lp->dn_attr, rp->dn_attr));
dt_node_free(lp);
@ -2216,7 +2273,7 @@ dt_node_inline(dt_node_t *expr)
* until we have successfully cooked the right-hand expression, below.
*/
dnp = dt_node_alloc(DT_NODE_INLINE);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
dt_node_attr_assign(dnp, _dtrace_defattr);
if (dt_node_is_void(dnp)) {
@ -2371,7 +2428,8 @@ dt_node_member(dt_decl_t *ddp, char *name, dt_node_t *expr)
dnp->dn_membexpr = expr;
if (ddp != NULL)
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
dtt.dtt_flags);
return (dnp);
}
@ -2402,10 +2460,10 @@ dt_node_xlator(dt_decl_t *ddp, dt_decl_t *sdp, char *name, dt_node_t *members)
}
bzero(&sn, sizeof (sn));
dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type);
dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type, B_FALSE);
bzero(&dn, sizeof (dn));
dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type);
dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type, B_FALSE);
if (dt_xlator_lookup(dtp, &sn, &dn, DT_XLATE_EXACT) != NULL) {
xyerror(D_XLATE_REDECL,
@ -2651,7 +2709,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
attr = dt_ident_cook(dnp, idp, NULL);
else {
dt_node_type_assign(dnp,
DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
attr = idp->di_attr;
}
@ -2727,7 +2785,8 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
dnp->dn_ident = idp;
dnp->dn_flags |= DT_NF_LVALUE;
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
dtt.dtt_flags);
dt_node_attr_assign(dnp, _dtrace_symattr);
if (uref) {
@ -2775,7 +2834,7 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
attr = dt_ident_cook(dnp, idp, NULL);
else {
dt_node_type_assign(dnp,
DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
attr = idp->di_attr;
}
@ -2878,7 +2937,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
xyerror(D_TYPE_ERR, "failed to lookup int64_t\n");
dt_ident_type_assign(cp->dn_ident, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type,
dtt.dtt_flags);
}
if (cp->dn_kind == DT_NODE_VAR)
@ -2888,14 +2948,15 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
case DT_TOK_DEREF:
/*
* If the deref operator is applied to a translated pointer,
* we can just set our output type to the base translation.
* we set our output type to the output of the translation.
*/
if ((idp = dt_node_resolve(cp, DT_IDENT_XLPTR)) != NULL) {
dt_xlator_t *dxp = idp->di_data;
dnp->dn_ident = &dxp->dx_souid;
dt_node_type_assign(dnp,
DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type,
cp->dn_flags & DT_NF_USERLAND);
break;
}
@ -2915,7 +2976,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
"cannot dereference non-pointer type\n");
}
dt_node_type_assign(dnp, cp->dn_ctfp, type);
dt_node_type_assign(dnp, cp->dn_ctfp, type,
cp->dn_flags & DT_NF_USERLAND);
base = ctf_type_resolve(cp->dn_ctfp, type);
kind = ctf_type_kind(cp->dn_ctfp, base);
@ -2972,7 +3034,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
xyerror(D_OP_SCALAR, "operator %s requires an operand "
"of scalar type\n", opstr(dnp->dn_op));
}
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
B_FALSE);
break;
case DT_TOK_ADDROF:
@ -3005,10 +3068,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
dt_node_type_name(cp, n, sizeof (n)));
}
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
if (cp->dn_flags & DT_NF_USERLAND)
dnp->dn_flags |= DT_NF_USERLAND;
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
cp->dn_flags & DT_NF_USERLAND);
break;
case DT_TOK_SIZEOF:
@ -3023,7 +3084,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
}
dt_node_type_assign(dnp, dtp->dt_ddefs->dm_ctfp,
ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"));
ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
B_FALSE);
break;
case DT_TOK_STRINGOF:
@ -3033,7 +3095,8 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
"cannot apply stringof to a value of type %s\n",
dt_node_type_name(cp, n, sizeof (n)));
}
dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp));
dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp),
cp->dn_flags & DT_NF_USERLAND);
break;
case DT_TOK_PREINC:
@ -3071,6 +3134,31 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags)
return (dnp);
}
static void
dt_assign_common(dt_node_t *dnp)
{
dt_node_t *lp = dnp->dn_left;
dt_node_t *rp = dnp->dn_right;
int op = dnp->dn_op;
if (rp->dn_kind == DT_NODE_INT)
dt_cast(lp, rp);
if (!(lp->dn_flags & DT_NF_LVALUE)) {
xyerror(D_OP_LVAL, "operator %s requires modifiable "
"lvalue as an operand\n", opstr(op));
/* see K&R[A7.17] */
}
if (!(lp->dn_flags & DT_NF_WRITABLE)) {
xyerror(D_OP_WRITE, "operator %s can only be applied "
"to a writable variable\n", opstr(op));
}
dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
}
static dt_node_t *
dt_cook_op2(dt_node_t *dnp, uint_t idflags)
{
@ -3080,15 +3168,14 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
int op = dnp->dn_op;
ctf_membinfo_t m;
ctf_file_t *ctfp = NULL;
ctf_id_t type = 0;
int kind, val, uref;
ctf_file_t *ctfp;
ctf_id_t type;
int kind, val, uref = 0; // XXX: gcc
dt_ident_t *idp;
char n1[DT_TYPE_NAMELEN];
char n2[DT_TYPE_NAMELEN];
uref = 0;
/*
* The expression E1[E2] is identical by definition to *((E1)+(E2)) so
* we convert "[" to "+" and glue on "*" at the end (see K&R[A7.3.1])
@ -3202,7 +3289,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
"of scalar type\n", opstr(op));
}
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
B_FALSE);
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
break;
@ -3246,7 +3334,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
rp->dn_op = DT_TOK_INT;
rp->dn_value = (intmax_t)val;
dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type);
dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type,
B_FALSE);
dt_node_attr_assign(rp, _dtrace_symattr);
}
@ -3278,7 +3367,8 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
dt_node_type_name(rp, n2, sizeof (n2)));
}
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
B_FALSE);
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
break;
@ -3326,7 +3416,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
dt_node_type_name(rp, n2, sizeof (n2)));
}
dt_node_type_assign(dnp, ctfp, type);
dt_node_type_assign(dnp, ctfp, type, B_FALSE);
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
if (uref)
@ -3467,7 +3557,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
*/
if (lp->dn_kind == DT_NODE_VAR &&
dt_ident_unref(lp->dn_ident)) {
dt_node_type_assign(lp, ctfp, type);
dt_node_type_assign(lp, ctfp, type, B_FALSE);
dt_ident_type_assign(lp->dn_ident, ctfp, type);
if (uref) {
@ -3550,19 +3640,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags)
}
}
asgn_common:
if (!(lp->dn_flags & DT_NF_LVALUE)) {
xyerror(D_OP_LVAL, "operator %s requires modifiable "
"lvalue as an operand\n", opstr(op));
/* see K&R[A7.17] */
}
if (!(lp->dn_flags & DT_NF_WRITABLE)) {
xyerror(D_OP_WRITE, "operator %s can only be applied "
"to a writable variable\n", opstr(op));
}
dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
dt_assign_common(dnp);
break;
case DT_TOK_PTR:
@ -3693,7 +3771,7 @@ asgn_common:
type = ctf_type_resolve(ctfp, m.ctm_type);
kind = ctf_type_kind(ctfp, type);
dt_node_type_assign(dnp, ctfp, m.ctm_type);
dt_node_type_assign(dnp, ctfp, m.ctm_type, B_FALSE);
dt_node_attr_assign(dnp, lp->dn_attr);
if (op == DT_TOK_PTR && (kind != CTF_K_ARRAY ||
@ -3819,7 +3897,8 @@ asgn_common:
}
dnp->dn_ident = dt_xlator_ident(dxp, lp->dn_ctfp, lp->dn_type);
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
B_FALSE);
dt_node_attr_assign(dnp,
dt_attr_min(rp->dn_attr, dnp->dn_ident->di_attr));
break;
@ -3867,6 +3946,14 @@ asgn_common:
dt_node_type_propagate(lp, dnp); /* see K&R[A7.5] */
dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
/*
* If it's a pointer then should be able to (attempt to)
* assign to it.
*/
if (lkind == CTF_K_POINTER)
dnp->dn_flags |= DT_NF_WRITABLE;
break;
}
@ -3976,7 +4063,7 @@ dt_cook_op3(dt_node_t *dnp, uint_t idflags)
"used in a conditional context\n");
}
dt_node_type_assign(dnp, ctfp, type);
dt_node_type_assign(dnp, ctfp, type, B_FALSE);
dt_node_attr_assign(dnp, dt_attr_min(dnp->dn_expr->dn_attr,
dt_attr_min(lp->dn_attr, rp->dn_attr)));
@ -4009,7 +4096,8 @@ dt_cook_aggregation(dt_node_t *dnp, uint_t idflags)
dt_node_attr_assign(dnp, dt_ident_cook(dnp,
dnp->dn_ident, &dnp->dn_aggtup));
} else {
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
B_FALSE);
dt_node_attr_assign(dnp, dnp->dn_ident->di_attr);
}
@ -4211,7 +4299,8 @@ dt_cook_xlator(dt_node_t *dnp, uint_t idflags)
}
(void) dt_node_cook(mnp, DT_IDFLG_REF);
dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type);
dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type,
B_FALSE);
attr = dt_attr_min(attr, mnp->dn_attr);
if (dt_node_is_argcompat(mnp, mnp->dn_membexpr) == 0) {
@ -4230,7 +4319,7 @@ dt_cook_xlator(dt_node_t *dnp, uint_t idflags)
dxp->dx_souid.di_attr = attr;
dxp->dx_ptrid.di_attr = attr;
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
dt_node_attr_assign(dnp, _dtrace_defattr);
return (dnp);
@ -4523,7 +4612,9 @@ dt_node_diftype(dtrace_hdl_t *dtp, const dt_node_t *dnp, dtrace_diftype_t *tp)
ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type));
}
tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ? DIF_TF_BYREF : 0;
tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ?
(dnp->dn_flags & DT_NF_USERLAND) ? DIF_TF_BYUREF :
DIF_TF_BYREF : 0;
tp->dtdt_pad = 0;
tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type);
}
@ -4573,8 +4664,8 @@ dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
break;
case DT_NODE_INT:
(void) fprintf(fp, "INT 0x%" PRIx64 "(%s)\n",
dnp->dn_value, buf);
(void) fprintf(fp, "INT 0x%llx (%s)\n",
(unsigned long long)dnp->dn_value, buf);
break;
case DT_NODE_STRING:

View File

@ -22,12 +22,14 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#ifndef _DT_PARSER_H
#define _DT_PARSER_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/dtrace.h>
@ -223,7 +225,7 @@ extern void dt_node_list_free(dt_node_t **);
extern void dt_node_link_free(dt_node_t **);
extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t);
extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t);
extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t, boolean_t);
extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *);
extern const char *dt_node_type_name(const dt_node_t *, char *, size_t);
extern size_t dt_node_type_size(const dt_node_t *);

View File

@ -23,8 +23,9 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <assert.h>
#include <strings.h>
@ -32,16 +33,27 @@
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#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>
#ifndef illumos
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <libproc_compat.h>
#include <libelf.h>
#include <gelf.h>
#endif
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
@ -65,11 +77,10 @@ typedef struct dt_pid_probe {
* Compose the lmid and object name into the canonical representation. We
* omit the lmid for the default link map for convenience.
*/
#if 0
static void
dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
{
#if defined(sun)
#ifdef illumos
if (lmid == LM_ID_BASE)
(void) strncpy(buf, obj, len);
else
@ -78,7 +89,6 @@ dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
(void) strncpy(buf, obj, len);
#endif
}
#endif
static int
dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
@ -107,11 +117,9 @@ dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
return (1);
}
#if 0
static int
dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
{
#if 0 /* XXX TBD needs libproc */
dtrace_hdl_t *dtp = pp->dpp_dtp;
dt_pcb_t *pcb = pp->dpp_pcb;
dt_proc_t *dpr = pp->dpp_dpr;
@ -124,7 +132,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
int isdash = strcmp("-", func) == 0;
pid_t pid;
#if defined(sun)
#ifdef illumos
pid = Pstatus(pp->dpp_pr)->pr_pid;
#else
pid = proc_getpid(pp->dpp_pr);
@ -148,7 +156,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
pp->dpp_obj);
if (!isdash && gmatch("return", pp->dpp_name)) {
#ifdef DOODAD
if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
pp->dpp_stret) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -156,20 +163,17 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
if (!isdash && gmatch("entry", pp->dpp_name)) {
#ifdef DOODAD
if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
D_PROC_CREATEFAIL, "failed to create entry probe "
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
@ -188,10 +192,8 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
(u_longlong_t)off, func));
}
#ifdef DOODAD
err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
symp, off);
#endif
if (err == DT_PROC_ERR) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -209,7 +211,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
nmatches++;
} else if (glob && !isdash) {
#ifdef DOODAD
if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -217,7 +218,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
"failed to create offset probes in '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
@ -227,10 +227,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
dt_free(dtp, ftp);
return (0);
#else
printf("XXX %s not implemented\n", __func__);
return ENODEV;
#endif
}
static int
@ -271,7 +267,6 @@ dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
static int
dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
{
#if 0 /* XXX TBD needs libproc */
dt_pid_probe_t *pp = arg;
dtrace_hdl_t *dtp = pp->dpp_dtp;
dt_pcb_t *pcb = pp->dpp_pcb;
@ -281,7 +276,7 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
if (obj == NULL)
return (0);
#if defined(sun)
#ifdef illumos
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#endif
@ -290,8 +285,7 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
pp->dpp_obj = obj;
else
pp->dpp_obj++;
#if defined(sun)
#ifdef illumos
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
NULL) == 0)
pp->dpp_stret[0] = sym.st_value;
@ -316,25 +310,10 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
else
pp->dpp_stret[3] = 0;
#else
if (proc_name2sym(pp->dpp_pr, obj, ".stret1", &sym) == 0)
pp->dpp_stret[0] = sym.st_value;
else
pp->dpp_stret[0] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret2", &sym) == 0)
pp->dpp_stret[1] = sym.st_value;
else
pp->dpp_stret[1] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret4", &sym) == 0)
pp->dpp_stret[2] = sym.st_value;
else
pp->dpp_stret[2] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret8", &sym) == 0)
pp->dpp_stret[3] = sym.st_value;
else
pp->dpp_stret[3] = 0;
pp->dpp_stret[0] = 0;
pp->dpp_stret[1] = 0;
pp->dpp_stret[2] = 0;
pp->dpp_stret[3] = 0;
#endif
dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
@ -356,19 +335,15 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
* just fail silently in the hopes that some other object will
* contain the desired symbol.
*/
#if defined(sun)
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
pp->dpp_func, &sym, NULL) != 0) {
#else
if (proc_name2sym(pp->dpp_pr, obj, pp->dpp_func, &sym) != 0) {
#endif
if (strcmp("-", pp->dpp_func) == 0) {
sym.st_name = 0;
sym.st_info =
GELF_ST_INFO(STB_LOCAL, STT_FUNC);
sym.st_other = 0;
sym.st_value = 0;
#if defined(sun)
#ifdef illumos
sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
PR_MODEL_ILP32 ? -1U : -1ULL;
#else
@ -401,16 +376,11 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
return (0);
#endif
#if defined(sun)
(void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
#else
(void) proc_addr2sym(pp->dpp_pr, sym.st_value, pp->dpp_func,
#endif
DTRACE_FUNCNAMELEN, &sym);
return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
} else {
#ifdef DOODAD
uint_t nmatches = pp->dpp_nmatches;
if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
@ -426,14 +396,9 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
return (1);
}
#endif
}
return (0);
#else
printf("XXX %s not implemented\n", __func__);
return ENODEV;
#endif
}
static int
@ -445,7 +410,7 @@ dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
if (gmatch(obj, pp->dpp_mod))
return (dt_pid_per_mod(pp, pmp, obj));
#if defined(sun)
#ifdef illumos
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#else
pp->dpp_lmid = 0;
@ -456,27 +421,29 @@ dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
else
pp->dpp_obj++;
dt_pid_objname(name, sizeof (name), pp->dpp_lmid, obj);
if (gmatch(pp->dpp_obj, pp->dpp_mod))
return (dt_pid_per_mod(pp, pmp, obj));
#ifdef illumos
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#endif
dt_pid_objname(name, sizeof (name), pp->dpp_lmid, pp->dpp_obj);
if (gmatch(name, pp->dpp_mod))
return (dt_pid_per_mod(pp, pmp, obj));
return (0);
}
#endif
#if 0
static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
{
#ifdef DOODAD
char m[MAXPATHLEN];
Lmid_t lmid = PR_LMID_EVERY;
const char *obj;
#endif
const prmap_t *pmp;
#ifdef DOODAD
/*
* Pick apart the link map from the library name.
*/
@ -484,7 +451,7 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
char *end;
if (strncmp(pdp->dtpd_mod, "LM", 2) != 0 ||
!isdigit(pdp->dtpd_mod[2]))
!isdigit((unsigned char)pdp->dtpd_mod[2]))
return (NULL);
lmid = strtoul(&pdp->dtpd_mod[2], &end, 16);
@ -507,23 +474,20 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
else
obj++;
#ifdef illumos
(void) Plmid(P, pmp->pr_vaddr, &lmid);
#endif
dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
#else
pmp = NULL;
#endif
return (pmp);
}
#endif
static int
dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
{
#if 0 /* XXX TBD needs libproc */
dt_pid_probe_t pp;
int ret = 0;
@ -556,13 +520,8 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
pp.dpp_mod = pdp->dtpd_mod;
(void) strcpy(pdp->dtpd_mod, "a.out");
} else if (strisglob(pp.dpp_mod) ||
#if defined(sun)
(aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
#else
(aout = proc_name2map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = proc_name2map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
#endif
aout->pr_vaddr != pmp->pr_vaddr) {
return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
"only the a.out module is valid with the "
@ -581,7 +540,6 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
* to iterate over each module and compare its name against the
* pattern. An empty module name is treated as '*'.
*/
#ifdef DOODAD
if (strisglob(pp.dpp_mod)) {
ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
} else {
@ -602,27 +560,24 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
ret = dt_pid_per_mod(&pp, pmp, obj);
}
}
#endif
return (ret);
#else
printf("XXX %s not implemented\n", __func__);
return ENODEV;
#endif
}
#if 0
static int
dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
{
#if 0 /* XXX TBD needs libproc */
struct ps_prochandle *P = data;
GElf_Sym sym;
#if defined(sun)
prsyminfo_t sip;
#endif
dof_helper_t dh;
GElf_Half e_type;
#if defined(__FreeBSD__) || defined(__NetBSD__)
dof_hdr_t hdr;
size_t sz;
uint64_t dofmax;
void *dof;
#endif
const char *mname;
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
int i, fd = -1;
@ -634,12 +589,8 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
* run the code to instantiate these providers.
*/
for (i = 0; i < 2; i++) {
#if defined(sun)
if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
&sip) != 0) {
#else
if (proc_name2sym(P, oname, syms[i], &sym) != 0) {
#endif
continue;
}
@ -650,25 +601,67 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);
#ifdef DOODAD
if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
dt_dprintf("read of ELF header failed");
continue;
}
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
if (Pread(P, &hdr, sizeof (hdr), sym.st_value) !=
sizeof (hdr)) {
dt_dprintf("read of DOF header failed\n");
continue;
}
sz = sizeof(dofmax);
if (sysctlbyname("kern.dtrace.dof_maxsize", &dofmax, &sz,
NULL, 0) != 0) {
dt_dprintf("failed to read dof_maxsize: %s\n",
strerror(errno));
continue;
}
if (dofmax < hdr.dofh_loadsz) {
dt_dprintf("DOF load size exceeds maximum\n");
continue;
}
if ((dof = malloc(hdr.dofh_loadsz)) == NULL)
return (-1);
if (Pread(P, dof, hdr.dofh_loadsz, sym.st_value) !=
hdr.dofh_loadsz) {
free(dof);
dt_dprintf("read of DOF section failed\n");
continue;
}
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_pid = proc_getpid(P);
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
sip.prs_lmid, mname);
if (fd == -1 &&
(fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("open of helper device failed: %s\n",
strerror(errno));
free(dof);
return (-1); /* errno is set for us */
}
if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
free(dof);
#else
dh.dofhp_dof = sym.st_value;
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
#if defined(sun)
sip.prs_lmid, mname);
#else
0, mname);
#endif
#ifdef DOODAD
if (fd == -1 &&
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
@ -681,42 +674,35 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
#endif
}
#ifdef DOODAD
if (fd != -1)
#if defined(__FreeBSD__) || defined(__NetBSD__)
(void) close(fd);
#else
(void) pr_close(P, fd);
#endif
return (0);
#else
printf("XXX %s not implemented\n", __func__);
return ENODEV;
#endif
}
#endif
static int
dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
{
#if 0 /* XXX TBD needs libproc */
struct ps_prochandle *P = dpr->dpr_proc;
int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#ifdef DOODAD
(void) Pupdate_maps(P);
if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
ret = -1;
(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
"failed to instantiate probes for pid %d: %s",
#if defined(sun)
#ifdef illumos
(int)Pstatus(P)->pr_pid, strerror(errno));
#else
(int)proc_getpid(P), strerror(errno));
#endif
}
#endif
/*
* Put the module name in its canonical form.
@ -724,10 +710,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
(void) dt_pid_fix_mod(pdp, P);
return (ret);
#else
printf("XXX %s not implemented\n", __func__);
return ENODEV;
#endif
}
static pid_t
@ -763,7 +745,6 @@ dt_pid_get_pid(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
int
dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
#if 0 /* XXX TBD needs libproc */
char provname[DTRACE_PROVNAMELEN];
struct ps_prochandle *P;
dt_proc_t *dpr;
@ -838,10 +819,6 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
}
return (err ? -1 : 0);
#else
printf("XXX %s not implemented\n", __func__);
return -1;
#endif
}
int
@ -899,3 +876,163 @@ dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
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;
}
__USE(lmid);
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);
}

View File

@ -24,12 +24,13 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#ifndef _DT_PID_H
#define _DT_PID_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libproc.h>
#include <sys/fasttrap.h>
#include <dt_impl.h>
@ -57,6 +58,9 @@ extern int dt_pid_create_offset_probe(struct ps_prochandle *, dtrace_hdl_t *,
extern int dt_pid_create_glob_offset_probes(struct ps_prochandle *,
dtrace_hdl_t *, fasttrap_probe_spec_t *, const GElf_Sym *, const char *);
extern void dt_pid_get_types(dtrace_hdl_t *, const dtrace_probedesc_t *,
dtrace_argdesc_t *, int *);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,157 @@
/*
* CDDL HEADER START
*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <dtrace.h>
#include <dt_impl.h>
#include <dt_pq.h>
#include <assert.h>
/*
* Create a new priority queue.
*
* size is the maximum number of items that will be stored in the priority
* queue at one time.
*/
dt_pq_t *
dt_pq_init(dtrace_hdl_t *dtp, uint_t size, dt_pq_value_f value_cb, void *cb_arg)
{
dt_pq_t *p;
assert(size > 1);
if ((p = dt_zalloc(dtp, sizeof (dt_pq_t))) == NULL)
return (NULL);
p->dtpq_items = dt_zalloc(dtp, size * sizeof (p->dtpq_items[0]));
if (p->dtpq_items == NULL) {
dt_free(dtp, p);
return (NULL);
}
p->dtpq_hdl = dtp;
p->dtpq_size = size;
p->dtpq_last = 1;
p->dtpq_value = value_cb;
p->dtpq_arg = cb_arg;
return (p);
}
void
dt_pq_fini(dt_pq_t *p)
{
dtrace_hdl_t *dtp = p->dtpq_hdl;
dt_free(dtp, p->dtpq_items);
dt_free(dtp, p);
}
static uint64_t
dt_pq_getvalue(dt_pq_t *p, uint_t index)
{
void *item = p->dtpq_items[index];
return (p->dtpq_value(item, p->dtpq_arg));
}
void
dt_pq_insert(dt_pq_t *p, void *item)
{
uint_t i;
assert(p->dtpq_last < p->dtpq_size);
i = p->dtpq_last++;
p->dtpq_items[i] = item;
while (i > 1 && dt_pq_getvalue(p, i) < dt_pq_getvalue(p, i / 2)) {
void *tmp = p->dtpq_items[i];
p->dtpq_items[i] = p->dtpq_items[i / 2];
p->dtpq_items[i / 2] = tmp;
i /= 2;
}
}
/*
* Return elements from the priority queue. *cookie should be zero when first
* called. Returns NULL when there are no more elements.
*/
void *
dt_pq_walk(dt_pq_t *p, uint_t *cookie)
{
(*cookie)++;
if (*cookie >= p->dtpq_last)
return (NULL);
return (p->dtpq_items[*cookie]);
}
void *
dt_pq_pop(dt_pq_t *p)
{
uint_t i = 1;
void *ret;
assert(p->dtpq_last > 0);
if (p->dtpq_last == 1)
return (NULL);
ret = p->dtpq_items[1];
p->dtpq_last--;
p->dtpq_items[1] = p->dtpq_items[p->dtpq_last];
p->dtpq_items[p->dtpq_last] = NULL;
for (;;) {
uint_t lc = i * 2;
uint_t rc = i * 2 + 1;
uint_t c;
uint64_t v;
void *tmp;
if (lc >= p->dtpq_last)
break;
if (rc >= p->dtpq_last) {
c = lc;
v = dt_pq_getvalue(p, lc);
} else {
uint64_t lv = dt_pq_getvalue(p, lc);
uint64_t rv = dt_pq_getvalue(p, rc);
if (lv < rv) {
c = lc;
v = lv;
} else {
c = rc;
v = rv;
}
}
if (v >= dt_pq_getvalue(p, i))
break;
tmp = p->dtpq_items[i];
p->dtpq_items[i] = p->dtpq_items[c];
p->dtpq_items[c] = tmp;
i = c;
}
return (ret);
}

View File

@ -0,0 +1,51 @@
/*
* CDDL HEADER START
*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#ifndef _DT_PQ_H
#define _DT_PQ_H
#include <dtrace.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t (*dt_pq_value_f)(void *, void *);
typedef struct dt_pq {
dtrace_hdl_t *dtpq_hdl; /* dtrace handle */
void **dtpq_items; /* array of elements */
uint_t dtpq_size; /* count of allocated elements */
uint_t dtpq_last; /* next free slot */
dt_pq_value_f dtpq_value; /* callback to get the value */
void *dtpq_arg; /* callback argument */
} dt_pq_t;
extern dt_pq_t *dt_pq_init(dtrace_hdl_t *, uint_t size, dt_pq_value_f, void *);
extern void dt_pq_fini(dt_pq_t *);
extern void dt_pq_insert(dt_pq_t *, void *);
extern void *dt_pq_pop(dt_pq_t *);
extern void *dt_pq_walk(dt_pq_t *, uint_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PQ_H */

View File

@ -21,19 +21,24 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <strings.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <dt_parser.h>
#include <dt_impl.h>
#include <dt_provider.h>
@ -77,7 +82,7 @@ static void
dt_pragma_attributes(const char *prname, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dtrace_attribute_t attr, *a = NULL;
dtrace_attribute_t attr, *a = NULL; // XXX: gcc
dt_provider_t *pvp;
const char *name, *part;
dt_ident_t *idp;
@ -201,6 +206,29 @@ dt_pragma_binding(const char *prname, dt_node_t *dnp)
dtp->dt_globals->dh_defer = &dt_pragma_apply;
}
static void
dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib,
size_t len)
{
dt_dirpath_t *dirp;
struct stat sbuf;
int found = 0;
for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL;
dirp = dt_list_next(dirp)) {
(void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname);
if (stat(lib, &sbuf) == 0) {
found = 1;
break;
}
}
if (!found)
xyerror(D_PRAGMA_DEPEND,
"failed to find dependency in libpath: %s", lname);
}
/*
* The #pragma depends_on directive can be used to express a dependency on a
* module, provider or library which if not present will cause processing to
@ -211,9 +239,11 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
int found = 0;
int found = 0; // XXX: gcc
dt_lib_depend_t *dld;
char lib[MAXPATHLEN];
size_t plen;
char *provs, *cpy, *tok;
if (cnp == NULL || nnp == NULL ||
cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
@ -221,25 +251,52 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp)
"<class> <name>\n", prname);
}
if (strcmp(cnp->dn_string, "provider") == 0)
found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
else if (strcmp(cnp->dn_string, "module") == 0) {
if (strcmp(cnp->dn_string, "provider") == 0) {
/*
* First try to get the provider list using the
* debug.dtrace.providers sysctl, since that'll work even if
* we're not running as root.
*/
provs = NULL;
if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) ||
((provs = dt_alloc(dtp, plen)) == NULL) ||
sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0))
found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
else {
found = B_FALSE;
for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; )
if (strcmp(tok, nnp->dn_string) == 0) {
found = B_TRUE;
break;
}
if (found == B_FALSE)
found = dt_provider_lookup(dtp,
nnp->dn_string) != NULL;
}
if (provs != NULL)
dt_free(dtp, provs);
} else if (strcmp(cnp->dn_string, "module") == 0) {
dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
#if defined(__FreeBSD__) || defined(__NetBSD__)
if (!found) {
dt_kmodule_t *dkmp = dt_kmodule_lookup(dtp,
nnp->dn_string);
found = dkmp != NULL &&
dt_module_getctf(dtp, dkmp->dkm_module) != NULL;
}
#endif
} else if (strcmp(cnp->dn_string, "library") == 0) {
if (yypcb->pcb_cflags & DTRACE_C_CTL) {
assert(dtp->dt_filetag != NULL);
/*
* We have the file we are working on in dtp->dt_filetag
* so find that node and add the dependency in.
*/
dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
sizeof (lib));
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
lib)) != 0) {
xyerror(D_PRAGMA_DEPEND,
@ -261,8 +318,8 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp)
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
sizeof (lib));
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
lib);
assert(dld != NULL);

View File

@ -0,0 +1,706 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/*
* DTrace print() action
*
* This file contains the post-processing logic for the print() action. The
* print action behaves identically to trace() in that it generates a
* DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
* string stored in the DOF string table (similar to printf formats). We
* take the result of the trace action and post-process it in the fashion of
* MDB's ::print dcmd.
*
* This implementation differs from MDB's in the following ways:
*
* - We do not expose any options or flags. The behavior of print() is
* equivalent to "::print -tn".
*
* - MDB will display "holes" in structures (unused padding between
* members).
*
* - When printing arrays of structures, MDB will leave a trailing ','
* after the last element.
*
* - MDB will print time_t types as date and time.
*
* - MDB will detect when an enum is actually the OR of several flags,
* and print it out with the constituent flags separated.
*
* - For large arrays, MDB will print the first few members and then
* print a "..." continuation line.
*
* - MDB will break and wrap arrays at 80 columns.
*
* - MDB prints out floats and doubles by hand, as it must run in kmdb
* context. We're able to leverage the printf() format strings,
* but the result is a slightly different format.
*/
#include <sys/sysmacros.h>
#include <strings.h>
#include <stdlib.h>
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <dt_module.h>
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_impl.h>
/* determines whether the given integer CTF encoding is a character */
#define CTF_IS_CHAR(e) \
(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
/* determines whether the given CTF kind is a struct or union */
#define CTF_IS_STRUCTLIKE(k) \
((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
/*
* Print structure passed down recursively through printing algorithm.
*/
typedef struct dt_printarg {
dtrace_hdl_t *pa_dtp; /* libdtrace handle */
caddr_t pa_addr; /* base address of trace data */
ctf_file_t *pa_ctfp; /* CTF container */
int pa_depth; /* member depth */
int pa_nest; /* nested array depth */
FILE *pa_file; /* output file */
} dt_printarg_t;
static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
/*
* Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
* can't resolve the type.
*/
static void
dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
{
if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
(void) snprintf(buf, buflen, "<%ld>", id);
}
/*
* Print any necessary trailing braces for structures or unions. We don't get
* invoked when a struct or union ends, so we infer the need to print braces
* based on the depth the last time we printed something and the new depth.
*/
static void
dt_print_trailing_braces(dt_printarg_t *pap, int depth)
{
int d;
for (d = pap->pa_depth; d > depth; d--) {
(void) fprintf(pap->pa_file, "%*s}%s",
(d + pap->pa_nest - 1) * 4, "",
d == depth + 1 ? "" : "\n");
}
}
/*
* Print the appropriate amount of indentation given the current depth and
* array nesting.
*/
static void
dt_print_indent(dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "%*s",
(pap->pa_depth + pap->pa_nest) * 4, "");
}
/*
* Print a bitfield. It's worth noting that the D compiler support for
* bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
* various D provider files) will produce incorrect results compared to
* "genunix`user_desc_t".
*/
static void
print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
{
FILE *fp = pap->pa_file;
caddr_t addr = pap->pa_addr + off / NBBY;
uint64_t mask = (1ULL << ep->cte_bits) - 1;
uint64_t value = 0;
size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
uint8_t *buf = (uint8_t *)&value;
uint8_t shift;
/*
* On big-endian machines, we need to adjust the buf pointer to refer
* to the lowest 'size' bytes in 'value', and we need to shift based on
* the offset from the end of the data, not the offset of the start.
*/
#if BYTE_ORDER == _BIG_ENDIAN
buf += sizeof (value) - size;
off += ep->cte_bits;
#endif
bcopy(addr, buf, size);
shift = off % NBBY;
/*
* Offsets are counted from opposite ends on little- and
* big-endian machines.
*/
#if BYTE_ORDER == _BIG_ENDIAN
shift = NBBY - shift;
#endif
/*
* If the bits we want do not begin on a byte boundary, shift the data
* right so that the value is in the lowest 'cte_bits' of 'value'.
*/
if (off % NBBY != 0)
value >>= shift;
value &= mask;
(void) fprintf(fp, "%#llx", (unsigned long long)value);
}
/*
* Dump the contents of memory as a fixed-size integer in hex.
*/
static void
dt_print_hex(FILE *fp, caddr_t addr, size_t size)
{
switch (size) {
case sizeof (uint8_t):
(void) fprintf(fp, "%#x", *(uint8_t *)addr);
break;
case sizeof (uint16_t):
/* LINTED - alignment */
(void) fprintf(fp, "%#x", *(uint16_t *)addr);
break;
case sizeof (uint32_t):
/* LINTED - alignment */
(void) fprintf(fp, "%#x", *(uint32_t *)addr);
break;
case sizeof (uint64_t):
(void) fprintf(fp, "%#llx",
/* LINTED - alignment */
(unsigned long long)*(uint64_t *)addr);
break;
default:
(void) fprintf(fp, "<invalid size %u>", (uint_t)size);
}
}
/*
* Print an integer type. Before dumping the contents via dt_print_hex(), we
* first check the encoding to see if it's part of a bitfield or a character.
*/
static void
dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
ctf_encoding_t e;
size_t size;
caddr_t addr = pap->pa_addr + off / NBBY;
if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
(void) fprintf(fp, "<unknown encoding>");
return;
}
/*
* This comes from MDB - it's not clear under what circumstances this
* would be found.
*/
if (e.cte_format & CTF_INT_VARARGS) {
(void) fprintf(fp, "...");
return;
}
/*
* We print this as a bitfield if the bit encoding indicates it's not
* an even power of two byte size, or is larger than 8 bytes.
*/
size = e.cte_bits / NBBY;
if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
print_bitfield(pap, off, &e);
return;
}
/*
* If this is a character, print it out as such.
*/
if (CTF_IS_CHAR(e)) {
char c = *(char *)addr;
if (isprint((unsigned char)c))
(void) fprintf(fp, "'%c'", c);
else if (c == 0)
(void) fprintf(fp, "'\\0'");
else
(void) fprintf(fp, "'\\%03o'", c);
return;
}
dt_print_hex(fp, addr, size);
}
/*
* Print a floating point (float, double, long double) value.
*/
/* ARGSUSED */
static void
dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
ctf_encoding_t e;
caddr_t addr = pap->pa_addr + off / NBBY;
if (ctf_type_encoding(ctfp, base, &e) == 0) {
if (e.cte_format == CTF_FP_SINGLE &&
e.cte_bits == sizeof (float) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.7e", *((float *)addr));
} else if (e.cte_format == CTF_FP_DOUBLE &&
e.cte_bits == sizeof (double) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.7e", *((double *)addr));
} else if (e.cte_format == CTF_FP_LDOUBLE &&
e.cte_bits == sizeof (long double) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.16LE", *((long double *)addr));
} else {
(void) fprintf(fp, "<unknown encoding>");
}
}
}
/*
* A pointer is generally printed as a fixed-size integer. If we have a
* function pointer, we try to look up its name.
*/
static void
dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
caddr_t addr = pap->pa_addr + off / NBBY;
size_t size = ctf_type_size(ctfp, base);
ctf_id_t bid = ctf_type_reference(ctfp, base);
uint64_t pc;
dtrace_syminfo_t dts;
GElf_Sym sym;
if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) {
dt_print_hex(fp, addr, size);
} else {
/* LINTED - alignment */
pc = *((uint64_t *)addr);
if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {
dt_print_hex(fp, addr, size);
} else {
(void) fprintf(fp, "%s`%s", dts.dts_object,
dts.dts_name);
}
}
}
/*
* Print out an array. This is somewhat complex, as we must manually visit
* each member, and recursively invoke ctf_type_visit() for each member. If
* the members are non-structs, then we print them out directly:
*
* [ 0x14, 0x2e, 0 ]
*
* If they are structs, then we print out the necessary leading and trailing
* braces, to end up with:
*
* [
* type {
* ...
* },
* type {
* ...
* }
* ]
*
* We also use a heuristic to detect whether the array looks like a character
* array. If the encoding indicates it's a character, and we have all
* printable characters followed by a null byte, then we display it as a
* string:
*
* [ "string" ]
*/
static void
dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
caddr_t addr = pap->pa_addr + off / NBBY;
ctf_arinfo_t car;
ssize_t eltsize;
ctf_encoding_t e;
int i;
boolean_t isstring;
int kind;
ctf_id_t rtype;
if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
(void) fprintf(fp, "0x%p", (void *)addr);
return;
}
if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
(rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
(void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
return;
}
/* see if this looks like a string */
isstring = B_FALSE;
if (kind == CTF_K_INTEGER &&
ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
char c;
for (i = 0; i < car.ctr_nelems; i++) {
c = *((char *)addr + eltsize * i);
if (!isprint((unsigned char)c) || c == '\0')
break;
}
if (i != car.ctr_nelems && c == '\0')
isstring = B_TRUE;
}
/*
* As a slight aesthetic optimization, if we are a top-level type, then
* don't bother printing out the brackets. This lets print("foo") look
* like:
*
* string "foo"
*
* As D will internally represent this as a char[256] array.
*/
if (!isstring || pap->pa_depth != 0)
(void) fprintf(fp, "[ ");
if (isstring)
(void) fprintf(fp, "\"");
for (i = 0; i < car.ctr_nelems; i++) {
if (isstring) {
char c = *((char *)addr + eltsize * i);
if (c == '\0')
break;
(void) fprintf(fp, "%c", c);
} else {
/*
* Recursively invoke ctf_type_visit() on each member.
* We setup a new printarg struct with 'pa_nest' set to
* indicate that we are within a nested array.
*/
dt_printarg_t pa = *pap;
pa.pa_nest += pap->pa_depth + 1;
pa.pa_depth = 0;
pa.pa_addr = addr + eltsize * i;
(void) ctf_type_visit(ctfp, car.ctr_contents,
dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
if (i != car.ctr_nelems - 1)
(void) fprintf(fp, ", ");
else if (CTF_IS_STRUCTLIKE(kind))
(void) fprintf(fp, "\n");
}
}
if (isstring)
(void) fprintf(fp, "\"");
if (!isstring || pap->pa_depth != 0) {
if (CTF_IS_STRUCTLIKE(kind))
dt_print_indent(pap);
else
(void) fprintf(fp, " ");
(void) fprintf(fp, "]");
}
}
/*
* This isued by both structs and unions to print the leading brace.
*/
/* ARGSUSED */
static void
dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "{");
}
/*
* For enums, we try to print the enum name, and fall back to the value if it
* can't be determined. We do not do any fancy flag processing like mdb.
*/
/* ARGSUSED */
static void
dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
const char *ename;
ssize_t size;
caddr_t addr = pap->pa_addr + off / NBBY;
int value = 0;
/*
* The C standard says that an enum will be at most the sizeof (int).
* But if all the values are less than that, the compiler can use a
* smaller size. Thanks standards.
*/
size = ctf_type_size(ctfp, base);
switch (size) {
case sizeof (uint8_t):
value = *(uint8_t *)addr;
break;
case sizeof (uint16_t):
value = *(uint16_t *)addr;
break;
case sizeof (int32_t):
value = *(int32_t *)addr;
break;
default:
(void) fprintf(fp, "<invalid enum size %u>", (uint_t)size);
return;
}
if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
(void) fprintf(fp, "%s", ename);
else
(void) fprintf(fp, "%d", value);
}
/*
* Forward declaration. There's not much to do here without the complete
* type information, so just print out this fact and drive on.
*/
/* ARGSUSED */
static void
dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "<forward decl>");
}
typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
static dt_printarg_f *const dt_printfuncs[] = {
dt_print_int, /* CTF_K_INTEGER */
dt_print_float, /* CTF_K_FLOAT */
dt_print_ptr, /* CTF_K_POINTER */
dt_print_array, /* CTF_K_ARRAY */
dt_print_ptr, /* CTF_K_FUNCTION */
dt_print_structlike, /* CTF_K_STRUCT */
dt_print_structlike, /* CTF_K_UNION */
dt_print_enum, /* CTF_K_ENUM */
dt_print_tag /* CTF_K_FORWARD */
};
/*
* Print one member of a structure. This callback is invoked from
* ctf_type_visit() recursively.
*/
static int
dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
void *data)
{
char type[DT_TYPE_NAMELEN];
int kind;
dt_printarg_t *pap = data;
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
boolean_t arraymember;
boolean_t brief;
ctf_encoding_t e;
ctf_id_t rtype;
dt_print_trailing_braces(pap, depth);
/*
* dt_print_trailing_braces() doesn't include the trailing newline; add
* it here if necessary.
*/
if (depth < pap->pa_depth)
(void) fprintf(fp, "\n");
pap->pa_depth = depth;
if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
dt_print_indent(pap);
(void) fprintf(fp, "%s = <invalid type %lu>", name, id);
return (0);
}
dt_print_type_name(ctfp, id, type, sizeof (type));
arraymember = (pap->pa_nest != 0 && depth == 0);
brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
if (!brief) {
/*
* If this is a direct array member and a struct (otherwise
* brief would be true), then print a trailing newline, as the
* array printing code doesn't include it because it might be a
* simple type.
*/
if (arraymember)
(void) fprintf(fp, "\n");
dt_print_indent(pap);
/* always print the type */
(void) fprintf(fp, "%s", type);
if (name[0] != '\0') {
/*
* For aesthetics, we don't include a space between the
* type name and member name if the type is a pointer.
* This will give us "void *foo =" instead of "void *
* foo =". Unions also have the odd behavior that the
* type name is returned as "union ", with a trailing
* space, so we also avoid printing a space if the type
* name already ends with a space.
*/
if (type[strlen(type) - 1] != '*' &&
type[strlen(type) -1] != ' ') {
(void) fprintf(fp, " ");
}
(void) fprintf(fp, "%s", name);
/*
* If this looks like a bitfield, or is an integer not
* aligned on a byte boundary, print the number of
* bits after the name.
*/
if (kind == CTF_K_INTEGER &&
ctf_type_encoding(ctfp, id, &e) == 0) {
ulong_t bits = e.cte_bits;
ulong_t size = bits / NBBY;
if (bits % NBBY != 0 ||
off % NBBY != 0 ||
size > 8 ||
size != ctf_type_size(ctfp, id)) {
(void) fprintf(fp, " :%lu", bits);
}
}
(void) fprintf(fp, " =");
}
(void) fprintf(fp, " ");
}
dt_printfuncs[kind - 1](rtype, off, pap);
/* direct simple array members are not separated by newlines */
if (!brief)
(void) fprintf(fp, "\n");
return (0);
}
/*
* Main print function invoked by dt_consume_cpu().
*/
int
dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
caddr_t addr, size_t len)
{
const char *s;
char *object;
dt_printarg_t pa;
ctf_id_t id;
dt_module_t *dmp;
ctf_file_t *ctfp;
int libid;
/*
* Split the fully-qualified type ID (module`id). This should
* always be the format, but if for some reason we don't find the
* expected value, return 0 to fall back to the generic trace()
* behavior. In the case of userland CTF modules this will actually be
* of the format (module`lib`id). This is due to the fact that those
* modules have multiple CTF containers which `lib` identifies.
*/
for (s = typename; *s != '\0' && *s != '`'; s++)
;
if (*s != '`')
return (0);
object = alloca(s - typename + 1);
bcopy(typename, object, s - typename);
object[s - typename] = '\0';
dmp = dt_module_lookup_by_name(dtp, object);
if (dmp == NULL)
return (0);
if (dmp->dm_pid != 0) {
libid = atoi(s + 1);
s = strchr(s + 1, '`');
if (s == NULL || libid > dmp->dm_nctflibs)
return (0);
ctfp = dmp->dm_libctfp[libid];
} else {
ctfp = dt_module_getctf(dtp, dmp);
}
id = atoi(s + 1);
/*
* Try to get the CTF kind for this id. If something has gone horribly
* wrong and we can't resolve the ID, bail out and let trace() do the
* work.
*/
if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)
return (0);
/* setup the print structure and kick off the main print routine */
pa.pa_dtp = dtp;
pa.pa_addr = addr;
pa.pa_ctfp = ctfp;
pa.pa_nest = 0;
pa.pa_depth = 0;
pa.pa_file = fp;
(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
return (len);
}

View File

@ -20,11 +20,12 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#else
#define ABS(a) ((a) < 0 ? -(a) : (a))
@ -32,13 +33,18 @@
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <dt_printf.h>
#include <dt_string.h>
@ -156,7 +162,7 @@ static int
pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
{
if (dnp->dn_flags & DT_NF_SIGNED)
pfd->pfd_flags |= DT_PFCONV_SIGNED;
pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i';
else
pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u';
@ -295,9 +301,7 @@ pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
double n = (double)normal;
#if !defined(__arm__) && !defined(__powerpc__) && !defined(__mips__)
long double ldn = (long double)normal;
#endif
switch (size) {
case sizeof (float):
@ -463,7 +467,7 @@ pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format,
* Below, we turn this into the canonical adb/mdb /[yY] format,
* "1973 Dec 3 17:20:00".
*/
#if defined(sun)
#ifdef illumos
(void) ctime_r(&sec, src, sizeof (src));
#else
(void) ctime_r(&sec, src);
@ -505,6 +509,80 @@ pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format,
return (dt_printf(dtp, fp, format, buf));
}
/*ARGSUSED*/
static int
pfprint_port(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
uint16_t port = htons(*((uint16_t *)addr));
char buf[256];
#if defined(illumos) || defined(__FreeBSD__)
struct servent *sv, res;
#endif
#ifdef illumos
if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL)
#elif defined(__FreeBSD__)
if (getservbyport_r(port, NULL, &res, buf, sizeof (buf), &sv) > 0)
return (dt_printf(dtp, fp, format, sv->s_name));
#else
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = port;
if (getnameinfo((const struct sockaddr *)&sin, sizeof(sin), NULL, 0,
buf, sizeof(buf), 0) > 0)
return (dt_printf(dtp, fp, format, buf));
#endif
(void) snprintf(buf, sizeof (buf), "%d", *((uint16_t *)addr));
return (dt_printf(dtp, fp, format, buf));
}
/*ARGSUSED*/
static int
pfprint_inetaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
char *s = alloca(size + 1);
char inetaddr[NS_IN6ADDRSZ];
char buf[1024];
#if defined(illumos) || defined(__FreeBSD__)
struct hostent *host, res;
int e;
#endif
bcopy(addr, s, size);
s[size] = '\0';
if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) {
#ifdef illumos
if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ,
AF_INET, &res, buf, sizeof (buf), &e)) != NULL)
#elif defined(__FreeBSD__)
if (gethostbyaddr_r(inetaddr, NS_INADDRSZ,
AF_INET, &res, buf, sizeof (buf), &host, &e) > 0)
return (dt_printf(dtp, fp, format, host->h_name));
#else
if (getnameinfo((const struct sockaddr *)inetaddr, NS_INADDRSZ,
buf, sizeof(buf), NULL, 0, 0) > 0)
return (dt_printf(dtp, fp, format, buf));
#endif
} else if (inet_pton(AF_INET6, s, inetaddr) != -1) {
#if defined(__FreeBSD__)
if ((host = getipnodebyaddr(inetaddr, NS_IN6ADDRSZ,
AF_INET6, &e)) != NULL)
return (dt_printf(dtp, fp, format, host->h_name));
#else
if (getnameinfo((const struct sockaddr *)inetaddr, NS_INADDRSZ,
buf, sizeof(buf), NULL, 0, 0) > 0)
return (dt_printf(dtp, fp, format, buf));
#endif
}
return (dt_printf(dtp, fp, format, s));
}
/*ARGSUSED*/
static int
pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
@ -609,7 +687,8 @@ static const dt_pfconv_t _dtrace_conversions[] = {
{ "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },
{ "hx", "x", "short", pfcheck_xshort, pfprint_uint },
{ "hX", "X", "short", pfcheck_xshort, pfprint_uint },
{ "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint },
{ "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint },
{ "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr },
{ "k", "s", "stack", pfcheck_stack, pfprint_stack },
{ "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
{ "ld", "d", "long", pfcheck_type, pfprint_sint },
@ -632,12 +711,18 @@ static const dt_pfconv_t _dtrace_conversions[] = {
{ "LG", "G", "long double", pfcheck_type, pfprint_fp },
{ "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint },
{ "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint },
{ "P", "s", "uint16_t", pfcheck_type, pfprint_port },
{ "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr },
{ "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
{ "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
{ "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
#ifdef illumos
{ "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
{ "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
#else
{ "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
{ "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
#endif
{ "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
{ "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
{ "Y", "s", "int64_t", pfcheck_time, pfprint_time },
@ -1012,7 +1097,7 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype);
bzero(&aggnode, sizeof (aggnode));
dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
const dt_pfconv_t *pfc = pfd->pfd_conv;
@ -1020,7 +1105,7 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
int dync = 0;
char vname[64];
dt_node_t *vnp = NULL;
dt_node_t *vnp;
if (pfc == NULL)
continue; /* no checking if argd is just a prefix */
@ -1075,6 +1160,7 @@ dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
sizeof (vname));
vnp = &aggnode;
} else if (dnp == NULL) {
vnp = NULL;
xyerror(D_PRINTF_ARG_PROTO,
"%s( ) prototype mismatch: conversion #%d (%%"
"%s) is missing a corresponding value argument\n",
@ -1266,6 +1352,14 @@ pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
return (dt_print_lquantize(dtp, fp, addr, size, normal));
}
/*ARGSUSED*/
static int
pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
{
return (dt_print_llquantize(dtp, fp, addr, size, normal));
}
static int
dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf,
@ -1273,11 +1367,12 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
{
dt_pfargd_t *pfd = pfv->pfv_argv;
const dtrace_recdesc_t *recp = recs;
const dtrace_aggdata_t *aggdata = NULL;
const dtrace_aggdata_t *aggdata = NULL; // XXX: gcc
dtrace_aggdesc_t *agg;
caddr_t lim = (caddr_t)buf + len, limit;
char format[64] = "%";
int i, aggrec = 0, curagg = -1;
size_t ret;
int i, aggrec = 0, curagg = -1; // XXX: gcc
uint64_t normal;
/*
@ -1308,12 +1403,14 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
int prec = pfd->pfd_prec;
int rval;
const char *start;
char *f = format + 1; /* skip initial '%' */
size_t fmtsz = sizeof(format) - 1;
const dtrace_recdesc_t *rec;
dt_pfprint_f *func;
caddr_t addr;
size_t size;
uint32_t flags = 0;
uint32_t flags = 0; // XXX: gcc
if (pfd->pfd_preflen != 0) {
char *tmp = alloca(pfd->pfd_preflen + 1);
@ -1451,6 +1548,9 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
case DTRACEAGG_LQUANTIZE:
func = pfprint_lquantize;
break;
case DTRACEAGG_LLQUANTIZE:
func = pfprint_llquantize;
break;
case DTRACEACT_MOD:
func = pfprint_mod;
break;
@ -1462,6 +1562,7 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
break;
}
start = f;
if (pfd->pfd_flags & DT_PFCONV_ALT)
*f++ = '#';
if (pfd->pfd_flags & DT_PFCONV_ZPAD)
@ -1474,6 +1575,7 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
*f++ = '\'';
if (pfd->pfd_flags & DT_PFCONV_SPACE)
*f++ = ' ';
fmtsz -= f - start;
/*
* If we're printing a stack and DT_PFCONV_LEFT is set, we
@ -1485,16 +1587,19 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
width = 0;
if (width != 0) {
f += snprintf(f, format + sizeof (format) - f,
"%d", ABS(width));
ret = snprintf(f, fmtsz, "%d", ABS(width));
f += ret;
fmtsz = MAX(0, fmtsz - ret);
}
if (prec > 0) {
f += snprintf(f, format + sizeof (format) - f,
".%d", prec);
ret = snprintf(f, fmtsz, ".%d", prec);
f += ret;
fmtsz = MAX(0, fmtsz - ret);
}
(void) strcpy(f, pfd->pfd_fmt);
if (strlcpy(f, pfd->pfd_fmt, fmtsz) >= fmtsz)
return (dt_set_errno(dtp, EDT_COMPILER));
pfd->pfd_rec = rec;
if (func(dtp, fp, format, pfd, addr, size, normal) < 0)
@ -1576,7 +1681,7 @@ dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
uint_t nrecs, const void *buf, size_t len)
{
#if defined(sun)
#ifdef illumos
char selfbuf[40], restorebuf[40], *filename;
#endif
FILE *nfp;
@ -1589,7 +1694,7 @@ dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
if (rval == -1 || fp == NULL)
return (rval);
#if defined(sun)
#ifdef illumos
if (pfd->pfd_preflen != 0 &&
strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
/*
@ -1671,7 +1776,7 @@ dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
}
(void) fclose(nfp);
#else
#else /* !illumos */
/*
* The 'standard output' (which is not necessarily stdout)
* treatment on FreeBSD is implemented differently than on
@ -1746,7 +1851,7 @@ dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
/* Remember that the output has been redirected to the new file. */
dtp->dt_freopen_fp = nfp;
#endif
#endif /* illumos */
return (rval);
}
@ -1865,10 +1970,10 @@ dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len)
*f++ = '@';
if (width != 0)
f += snprintf(f, format + formatlen - f, "%d", width);
f += snprintf(f, sizeof (format), "%d", width);
if (prec != 0)
f += snprintf(f, format + formatlen - f, ".%d", prec);
f += snprintf(f, sizeof (format), ".%d", prec);
/*
* If the output format is %s, then either %s is the underlying

View File

@ -77,7 +77,7 @@
*/
#include <sys/wait.h>
#if defined(sun)
#ifdef illumos
#include <sys/lwp.h>
#endif
#include <strings.h>
@ -89,105 +89,19 @@
#include <dt_pid.h>
#include <dt_impl.h>
int proc_setflags(struct proc_handle *, int);
int proc_create(const char *file, char * const *, proc_child_func *,
void *, struct proc_handle **);
int proc_detach(struct proc_handle *);
int proc_getflags(struct proc_handle *);
int proc_wait(struct proc_handle *);
pid_t proc_getpid(struct proc_handle *);
int proc_attach(pid_t, int, struct proc_handle **);
int proc_state(struct proc_handle *);
int proc_clearflags(struct proc_handle *, int);
int proc_continue(struct proc_handle *);
/* XXX TBD needs libproc */
/* Stub proc functions for now */
int
proc_setflags(struct proc_handle *phdl, int mask)
{
#ifndef illumos
#include <sys/syscall.h>
#include <libproc_compat.h>
#define SYS_forksys SYS_fork
#endif
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
#define IS_SYS_EXEC(w) (w == SYS_execve)
#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_forksys)
int
proc_create(const char *file, char * const *argv, proc_child_func *pcf,
void *child_arg, struct proc_handle **pphdl)
{
#if !defined(__DECONST) && defined(__UNCONST)
#define __DECONST(a, b) __UNCONST(b)
#endif
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
int
proc_detach(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
int
proc_getflags(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return -1;
}
int
proc_wait(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
pid_t
proc_getpid(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return -1;
}
int
proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
int
proc_state(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return -1;
}
int
proc_clearflags(struct proc_handle *phdl, int mask)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
int
proc_continue(struct proc_handle *phdl)
{
printf("dtrace: XXX %s not implemented\n", __func__);
return EINVAL;
}
#define IS_SYS_EXEC(w) (w == SYS_exec || w == SYS_execve)
#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_fork1 || \
w == SYS_forkall || w == SYS_forksys)
#ifdef DOODAD
static dt_bkpt_t *
dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
{
@ -209,54 +123,62 @@ dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
return (dbp);
}
#endif
static void
dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
{
#if defined(sun)
int state = Pstate(dpr->dpr_proc);
#else
int state = proc_state(dpr->dpr_proc);
#endif
dt_bkpt_t *dbp, *nbp;
__USE(state);
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (delbkpts && dbp->dbp_active &&
state != PS_LOST && state != PS_UNDEAD) {
(void) Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr);
}
#endif
nbp = dt_list_next(dbp);
dt_list_delete(&dpr->dpr_bps, dbp);
dt_free(dpr->dpr_hdl, dbp);
}
}
#ifdef DOODAD
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
#ifdef illumos
const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
#else
unsigned long pc;
#endif
dt_bkpt_t *dbp;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#ifndef illumos
proc_regget(dpr->dpr_proc, REG_PC, &pc);
proc_bkptregadj(&pc);
#endif
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
#ifdef illumos
if (psp->pr_reg[R_PC] == dbp->dbp_addr)
break;
#else
if (pc == dbp->dbp_addr)
break;
#endif
}
if (dbp == NULL) {
dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
#ifdef illumos
(int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
#else
(int)dpr->dpr_pid, pc);
#endif
return;
}
@ -266,7 +188,6 @@ dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
dbp->dbp_func(dtp, dpr, dbp->dbp_data);
(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
#endif
static void
dt_proc_bpenable(dt_proc_t *dpr)
@ -277,12 +198,9 @@ dt_proc_bpenable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
dbp->dbp_addr, &dbp->dbp_instr) == 0)
dbp->dbp_active = B_TRUE;
#endif
}
dt_dprintf("breakpoints enabled\n");
@ -297,12 +215,9 @@ dt_proc_bpdisable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr) == 0)
dbp->dbp_active = B_FALSE;
#endif
}
dt_dprintf("breakpoints disabled\n");
@ -367,7 +282,6 @@ dt_proc_stop(dt_proc_t *dpr, uint8_t why)
}
}
#if defined(sun)
/*ARGSUSED*/
static void
dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
@ -392,6 +306,8 @@ dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
(int)dpr->dpr_pid, evname, rdm.type, rdm.u.state);
switch (rdm.type) {
case RD_NONE:
break;
case RD_DLACTIVITY:
if (rdm.u.state != RD_CONSISTENT)
break;
@ -432,7 +348,12 @@ dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
}
(void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
#ifdef illumos
(dt_bkpt_f *)dt_proc_rdevent, (void *)evname);
#else
/* XXX ugly */
(dt_bkpt_f *)dt_proc_rdevent, __DECONST(void *, evname));
#endif
}
/*
@ -442,25 +363,34 @@ dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
static void
dt_proc_attach(dt_proc_t *dpr, int exec)
{
#ifdef illumos
const pstatus_t *psp = Pstatus(dpr->dpr_proc);
#endif
rd_err_e err;
GElf_Sym sym;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
if (exec) {
#ifdef illumos
if (psp->pr_lwp.pr_errno != 0)
return; /* exec failed: nothing needs to be done */
#endif
dt_proc_bpdestroy(dpr, B_FALSE);
#ifdef illumos
Preset_maps(dpr->dpr_proc);
#endif
}
if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
(err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
#ifdef illumos
dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
#endif
dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
#ifdef illumos
dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
#endif
} else {
dt_dprintf("pid %d: failed to enable rtld events: %s\n",
(int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
@ -502,6 +432,8 @@ dt_proc_attach(dt_proc_t *dpr, int exec)
static void
dt_proc_waitrun(dt_proc_t *dpr)
{
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
struct ps_prochandle *P = dpr->dpr_proc;
const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
@ -551,8 +483,8 @@ dt_proc_waitrun(dt_proc_t *dpr)
}
(void) pthread_mutex_lock(&dpr->dpr_lock);
}
#endif
}
typedef struct dt_proc_control_data {
dtrace_hdl_t *dpcd_hdl; /* DTrace handle */
@ -581,7 +513,7 @@ dt_proc_control(void *arg)
struct ps_prochandle *P = dpr->dpr_proc;
int pid = dpr->dpr_pid;
#if defined(sun)
#ifdef illumos
int pfd = Pctlfd(P);
const long wstop = PCWSTOP;
@ -603,7 +535,7 @@ dt_proc_control(void *arg)
*/
(void) pthread_mutex_lock(&dpr->dpr_lock);
#if defined(sun)
#ifdef illumos
(void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */
(void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */
(void) Punsetflags(P, PR_FORK); /* do not inherit on fork */
@ -615,7 +547,6 @@ dt_proc_control(void *arg)
* We must trace exit from exec() system calls so that if the exec is
* successful, we can reset our breakpoints and re-initialize libproc.
*/
(void) Psysexit(P, SYS_exec, B_TRUE);
(void) Psysexit(P, SYS_execve, B_TRUE);
/*
@ -626,21 +557,22 @@ dt_proc_control(void *arg)
*/
(void) Psysentry(P, SYS_vfork, B_TRUE);
(void) Psysexit(P, SYS_vfork, B_TRUE);
(void) Psysentry(P, SYS_fork1, B_TRUE);
(void) Psysexit(P, SYS_fork1, B_TRUE);
(void) Psysentry(P, SYS_forkall, B_TRUE);
(void) Psysexit(P, SYS_forkall, B_TRUE);
(void) Psysentry(P, SYS_forksys, B_TRUE);
(void) Psysexit(P, SYS_forksys, B_TRUE);
Psync(P); /* enable all /proc changes */
#endif
dt_proc_attach(dpr, B_FALSE); /* enable rtld breakpoints */
/*
* If PR_KLC is set, we created the process; otherwise we grabbed it.
* Check for an appropriate stop request and wait for dt_proc_continue.
*/
#ifdef illumos
if (Pstatus(P)->pr_flags & PR_KLC)
#else
if (proc_getflags(P) & PR_KLC)
#endif
dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
else
dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
@ -649,20 +581,6 @@ dt_proc_control(void *arg)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#else
/*
* If PR_KLC is set, we created the process; otherwise we grabbed it.
* Check for an appropriate stop request and wait for dt_proc_continue.
*/
if (proc_getflags(P) & PR_KLC)
dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
else
dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
if (proc_continue(P) != 0)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
@ -676,19 +594,21 @@ dt_proc_control(void *arg)
* Pwait() (which will return immediately) and do our processing.
*/
while (!dpr->dpr_quit) {
#if defined(sun)
const lwpstatus_t *psp;
#ifdef illumos
if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
continue; /* check dpr_quit and continue waiting */
#else
/* Wait for the process to report status. */
proc_wait(P);
proc_wstatus(P);
if (errno == EINTR)
continue; /* check dpr_quit and continue waiting */
#endif
(void) pthread_mutex_lock(&dpr->dpr_lock);
#if defined(sun)
#ifdef illumos
pwait_locked:
if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
(void) pthread_mutex_unlock(&dpr->dpr_lock);
@ -696,14 +616,13 @@ pwait_locked:
}
#endif
#if defined(sun)
switch (Pstate(P)) {
#else
switch (proc_state(P)) {
#endif
case PS_STOP:
#ifdef DOODAD
#ifdef illumos
psp = &Pstatus(P)->pr_lwp;
#else
psp = proc_getlwpstatus(P);
#endif
dt_dprintf("pid %d: proc stopped showing %d/%d\n",
pid, psp->pr_why, psp->pr_what);
@ -745,11 +664,10 @@ pwait_locked:
else if (psp->pr_why == PR_SYSEXIT &&
IS_SYS_EXEC(psp->pr_what))
dt_proc_attach(dpr, B_TRUE);
#endif
break;
case PS_LOST:
#if defined(sun)
#ifdef illumos
if (Preopen(P) == 0)
goto pwait_locked;
#endif
@ -768,12 +686,10 @@ pwait_locked:
break;
}
#if defined(sun)
if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
}
@ -813,11 +729,7 @@ dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
va_end(ap);
if (dpr->dpr_proc != NULL)
#if defined(sun)
Prelease(dpr->dpr_proc, 0);
#else
proc_detach(dpr->dpr_proc);
#endif
dt_free(dtp, dpr);
(void) dt_set_errno(dtp, EDT_COMPILER);
@ -828,7 +740,7 @@ dt_proc_t *
dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
{
dt_proc_hash_t *dph = dtp->dt_procs;
#if defined(sun)
#ifdef illumos
pid_t pid = Pstatus(P)->pr_pid;
#else
pid_t pid = proc_getpid(P);
@ -866,18 +778,20 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
* an external debugger and we were waiting in dt_proc_waitrun().
* Leave the process in this condition using PRELEASE_HANG.
*/
#if defined(sun)
#ifdef illumos
if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
#else
if (!(proc_getflags(dpr->dpr_proc) & (PR_KLC | PR_RLC))) {
#endif
dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
#if defined(sun)
rflag = PRELEASE_HANG;
#ifdef illumos
} else if (Pstatus(dpr->dpr_proc)->pr_flags & PR_KLC) {
#else
rflag = 0 /* XXX */;
__USE(rflag);
} else if (proc_getflags(dpr->dpr_proc) & PR_KLC) {
#endif
dt_dprintf("killing pid %d\n", (int)dpr->dpr_pid);
rflag = PRELEASE_KILL; /* apply kill-on-last-close */
} else {
dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
rflag = 0; /* apply run-on-last-close */
@ -900,10 +814,12 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
*/
(void) pthread_mutex_lock(&dpr->dpr_lock);
dpr->dpr_quit = B_TRUE;
#if defined(sun)
#ifdef illumos
(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
#elif defined(__FreeBSD__)
pthread_kill(dpr->dpr_tid, SIGTHR);
#else
(void) pthread_kill(dpr->dpr_tid, SIGUSR1);
pthread_cancel(dpr->dpr_tid);
#endif
/*
@ -952,11 +868,7 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
}
dt_list_delete(&dph->dph_lrulist, dpr);
#if defined(sun)
Prelease(dpr->dpr_proc, rflag);
#else
proc_detach(dpr->dpr_proc);
#endif
dt_free(dtp, dpr);
}
@ -976,7 +888,7 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(void) sigfillset(&nset);
(void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */
#if defined(sun)
#ifdef illumos
(void) sigdelset(&nset, SIGCANCEL); /* see dt_proc_destroy() */
#else
(void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */
@ -1008,21 +920,18 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
* small amount of useful information to help figure it out.
*/
if (dpr->dpr_done) {
#if defined(sun)
#ifdef illumos
const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
int stat = prp ? prp->pr_wstat : 0;
#endif
int pid = dpr->dpr_pid;
#if defined(sun)
if (Pstate(dpr->dpr_proc) == PS_LOST) {
#else
if (proc_state(dpr->dpr_proc) == PS_LOST) {
int stat = proc_getwstat(dpr->dpr_proc);
int pid = proc_getpid(dpr->dpr_proc);
#endif
if (proc_state(dpr->dpr_proc) == PS_LOST) {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exec'd "
"set-id or unobservable program\n", pid);
#if defined(sun)
} else if (WIFSIGNALED(stat)) {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process died "
@ -1031,7 +940,6 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exited "
"with status %d\n", pid, WEXITSTATUS(stat));
#endif
}
err = ESRCH; /* cause grab() or create() to fail */
@ -1042,7 +950,8 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(int)dpr->dpr_pid, strerror(err));
}
(void) pthread_mutex_unlock(&dpr->dpr_lock);
if (err == 0)
(void) pthread_mutex_unlock(&dpr->dpr_lock);
(void) pthread_attr_destroy(&a);
return (err);
@ -1062,32 +971,27 @@ dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
(void) pthread_cond_init(&dpr->dpr_cv, NULL);
#if defined(sun)
#ifdef illumos
if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {
#else
if ((err = proc_create(file, argv, pcf, child_arg,
&dpr->dpr_proc)) != 0) {
#endif
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, Pcreate_error(err)));
}
dpr->dpr_hdl = dtp;
#ifdef illumos
dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;
(void) Punsetflags(dpr->dpr_proc, PR_RLC);
(void) Psetflags(dpr->dpr_proc, PR_KLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_RLC);
(void) proc_setflags(dpr->dpr_proc, PR_KLC);
if ((err = proc_create(file, argv, pcf, child_arg, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, strerror(err)));
dpr->dpr_hdl = dtp;
dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
#endif
#if defined(sun)
(void) Punsetflags(dpr->dpr_proc, PR_RLC);
(void) Psetflags(dpr->dpr_proc, PR_KLC);
if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
#else
if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_IDLE) != 0)
#endif
return (NULL); /* dt_proc_error() has been called for us */
dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
@ -1143,27 +1047,20 @@ dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
(void) pthread_cond_init(&dpr->dpr_cv, NULL);
#if defined(sun)
#ifdef illumos
if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
#else
if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) {
#endif
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
}
#else
if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int) pid, strerror(err)));
#endif
dpr->dpr_hdl = dtp;
dpr->dpr_pid = pid;
#if defined(sun)
(void) Punsetflags(dpr->dpr_proc, PR_KLC);
(void) Psetflags(dpr->dpr_proc, PR_RLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_KLC);
(void) proc_setflags(dpr->dpr_proc, PR_RLC);
#endif
/*
* If we are attempting to grab the process without a monitor
@ -1284,12 +1181,13 @@ dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg);
if (P != NULL && idp != NULL && idp->di_id == 0)
#if defined(sun)
if (P != NULL && idp != NULL && idp->di_id == 0) {
#ifdef illumos
idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
#else
idp->di_id = proc_getpid(P); /* $target = created pid */
#endif
}
return (P);
}

View File

@ -44,9 +44,7 @@ typedef struct dt_proc {
dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */
struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */
char dpr_errmsg[BUFSIZ]; /* error message */
#if defined(sun)
rd_agent_t *dpr_rtld; /* rtld handle for librtld_db calls */
#endif
pthread_mutex_t dpr_lock; /* lock for manipulating dpr_hdl */
pthread_cond_t dpr_cv; /* cond for dpr_stop/quit/done */
pid_t dpr_pid; /* pid of process */

View File

@ -20,8 +20,8 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <unistd.h>
@ -30,7 +30,7 @@
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
@ -44,10 +44,12 @@ dt_program_create(dtrace_hdl_t *dtp)
{
dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
if (pgp != NULL)
if (pgp != NULL) {
dt_list_append(&dtp->dt_programs, pgp);
else
} else {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
/*
* By default, programs start with DOF version 1 so that output files
@ -351,6 +353,7 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
if (sdp->dtsd_fmtdata != NULL)
dt_printf_destroy(sdp->dtsd_fmtdata);
dt_free(dtp, sdp->dtsd_strdata);
dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
dt_free(dtp, sdp);
@ -556,6 +559,10 @@ dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
#if defined(__FreeBSD__) || defined(__NetBSD__)
if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
return (dt_set_errno(dtp, errno));
#endif
if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
return (dt_set_errno(dtp, errno));

View File

@ -23,11 +23,12 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#endif
@ -35,7 +36,7 @@
#include <limits.h>
#include <strings.h>
#include <stdlib.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#endif
#include <unistd.h>
@ -45,6 +46,8 @@
#include <dt_module.h>
#include <dt_string.h>
#include <dt_list.h>
#include <dt_pid.h>
#include <dtrace.h>
static dt_provider_t *
dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
@ -272,6 +275,21 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
xc = i;
nc++;
/*
* The pid provider believes in giving the kernel a break. No reason to
* give the kernel all the ctf containers that we're keeping ourselves
* just to get it back from it. So if we're coming from a pid provider
* probe and the kernel gave us no argument information we'll get some
* here. If for some crazy reason the kernel knows about our userland
* types then we just ignore this.
*/
if (xc == 0 && nc == 0 &&
strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
nc = adc;
dt_pid_get_types(dtp, pdp, adv, &nc);
xc = nc;
}
/*
* Now that we have discovered the number of native and translated
* arguments from the argument descriptions, allocate a new probe ident
@ -318,7 +336,8 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
dtt.dtt_type = CTF_ERR;
} else {
dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
dtt.dtt_ctfp, dtt.dtt_type);
dtt.dtt_ctfp, dtt.dtt_type,
dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
}
if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
@ -337,7 +356,7 @@ dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
dtt.dtt_type = CTF_ERR;
} else {
dt_node_type_assign(prp->pr_xargv[i],
dtt.dtt_ctfp, dtt.dtt_type);
dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
}
prp->pr_mapping[i] = adp->dtargd_mapping;
@ -501,6 +520,8 @@ dt_probe_destroy(dt_probe_t *prp)
for (pip = prp->pr_inst; pip != NULL; pip = pip_next) {
pip_next = pip->pi_next;
dt_free(dtp, pip->pi_rname);
dt_free(dtp, pip->pi_fname);
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip->pi_enoffs);
dt_free(dtp, pip);
@ -524,8 +545,9 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
if (strcmp(pip->pi_fname, fname) == 0 &&
((rname == NULL && pip->pi_rname[0] == '\0') ||
(rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
((rname == NULL && pip->pi_rname == NULL) ||
(rname != NULL && pip->pi_rname != NULL &&
strcmp(pip->pi_rname, rname) == 0)))
break;
}
@ -533,28 +555,18 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL)
return (-1);
if ((pip->pi_offs = dt_zalloc(dtp,
sizeof (uint32_t))) == NULL) {
dt_free(dtp, pip);
return (-1);
}
if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL)
goto nomem;
if ((pip->pi_enoffs = dt_zalloc(dtp,
sizeof (uint32_t))) == NULL) {
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip);
return (-1);
}
sizeof (uint32_t))) == NULL)
goto nomem;
(void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname));
if (rname != NULL) {
if (strlen(rname) + 1 > sizeof (pip->pi_rname)) {
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip);
return (dt_set_errno(dtp, EDT_COMPILER));
}
(void) strcpy(pip->pi_rname, rname);
}
if ((pip->pi_fname = strdup(fname)) == NULL)
goto nomem;
if (rname != NULL && (pip->pi_rname = strdup(rname)) == NULL)
goto nomem;
pip->pi_noffs = 0;
pip->pi_maxoffs = 1;
@ -599,6 +611,13 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
(*offs)[(*noffs)++] = offset;
return (0);
nomem:
dt_free(dtp, pip->pi_fname);
dt_free(dtp, pip->pi_enoffs);
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip);
return (dt_set_errno(dtp, EDT_NOMEM));
}
/*
@ -638,7 +657,7 @@ dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
bzero(dnp, sizeof (dt_node_t));
dnp->dn_kind = DT_NODE_TYPE;
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
dt_node_attr_assign(dnp, _dtrace_defattr);
return (dnp);

View File

@ -64,8 +64,8 @@ typedef struct dt_probe_iter {
} dt_probe_iter_t;
typedef struct dt_probe_instance {
char pi_fname[DTRACE_FUNCNAMELEN]; /* function name */
char pi_rname[DTRACE_FUNCNAMELEN + 20]; /* mangled relocation name */
char *pi_fname; /* function name */
char *pi_rname; /* mangled relocation name */
uint32_t *pi_offs; /* offsets into the function */
uint32_t *pi_enoffs; /* is-enabled offsets */
uint_t pi_noffs; /* number of offsets */

View File

@ -19,12 +19,15 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <sys/types.h>
#include <sys/bitmap.h>
@ -33,18 +36,19 @@
#include <stdlib.h>
#include <dt_regset.h>
#include <dt_impl.h>
dt_regset_t *
dt_regset_create(ulong_t size)
dt_regset_create(ulong_t nregs)
{
ulong_t n = BT_BITOUL(size + 1); /* + 1 for %r0 */
ulong_t n = BT_BITOUL(nregs);
dt_regset_t *drp = malloc(sizeof (dt_regset_t));
if (drp == NULL)
return (NULL);
drp->dr_bitmap = malloc(sizeof (ulong_t) * n);
drp->dr_size = size + 1;
drp->dr_size = nregs;
if (drp->dr_bitmap == NULL) {
dt_regset_destroy(drp);
@ -68,6 +72,25 @@ dt_regset_reset(dt_regset_t *drp)
bzero(drp->dr_bitmap, sizeof (ulong_t) * BT_BITOUL(drp->dr_size));
}
void
dt_regset_assert_free(dt_regset_t *drp)
{
int reg;
boolean_t fail = B_FALSE;
for (reg = 0; reg < drp->dr_size; reg++) {
if (BT_TEST(drp->dr_bitmap, reg) != 0) {
dt_dprintf("%%r%d was left allocated\n", reg);
fail = B_TRUE;
}
}
/*
* We set this during dtest runs to check for register leaks.
*/
if (fail && getenv("DTRACE_DEBUG_REGSET") != NULL)
abort();
}
int
dt_regset_alloc(dt_regset_t *drp)
{
@ -95,13 +118,15 @@ dt_regset_alloc(dt_regset_t *drp)
}
}
return (-1); /* no available registers */
xyerror(D_NOREG, "Insufficient registers to generate code");
/*NOTREACHED*/
return (-1);
}
void
dt_regset_free(dt_regset_t *drp, int reg)
{
assert(reg > 0 && reg < drp->dr_size);
assert(reg >= 0 && reg < drp->dr_size);
assert(BT_TEST(drp->dr_bitmap, reg) != 0);
BT_CLEAR(drp->dr_bitmap, reg);
}

View File

@ -19,16 +19,19 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#ifndef _DT_REGSET_H
#define _DT_REGSET_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#ifdef __cplusplus
@ -45,6 +48,7 @@ extern void dt_regset_destroy(dt_regset_t *);
extern void dt_regset_reset(dt_regset_t *);
extern int dt_regset_alloc(dt_regset_t *);
extern void dt_regset_free(dt_regset_t *, int);
extern void dt_regset_assert_free(dt_regset_t *);
#ifdef __cplusplus
}

View File

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,12 +18,10 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <strings.h>
#include <stdlib.h>
@ -33,19 +30,6 @@
#include <dt_string.h>
/*
* Create a copy of string s, but only duplicate the first n bytes.
*/
char *
strndup(const char *s, size_t n)
{
char *s2 = malloc(n + 1);
(void) strncpy(s2, s, n);
s2[n] = '\0';
return (s2);
}
/*
* Transform string s inline, converting each embedded C escape sequence string
* to the corresponding character. For example, the substring "\n" is replaced

View File

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -20,14 +19,12 @@
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _DT_STRING_H
#define _DT_STRING_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <strings.h>
@ -36,7 +33,6 @@
extern "C" {
#endif
extern char *strndup(const char *, size_t);
extern size_t stresc2chr(char *);
extern char *strchr2esc(const char *, size_t);
extern const char *strbasename(const char *);

View File

@ -21,12 +21,14 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Use is subject to license terms.
*/
#if defined(sun)
#ifdef illumos
#include <sys/sysmacros.h>
#endif
#include <sys/isa_defs.h>
#include <strings.h>
#include <unistd.h>
@ -36,19 +38,18 @@
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#if defined(sun)
#ifdef illumos
#include <alloca.h>
#else
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/cpuio.h>
#include <sys/ioctl.h>
#include <libproc_compat.h>
#endif
#include <assert.h>
#include <libgen.h>
#include <limits.h>
#include <paths.h>
#include <stdint.h>
#include <sys/isa_defs.h>
#include <dt_impl.h>
static const struct {
@ -477,7 +478,7 @@ dt_dprintf(const char *format, ...)
}
int
#if defined(sun)
#ifdef illumos
dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg)
#else
dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
@ -485,7 +486,7 @@ dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
{
const dtrace_vector_t *v = dtp->dt_vector;
#if !defined(sun)
#ifndef illumos
/* Avoid sign extension. */
val &= 0xffffffff;
#endif
@ -500,35 +501,21 @@ dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
return (-1);
}
static bool
cpu_online(processorid_t cpu)
{
cpustate_t cs;
int fd, online = false;
if ((fd = open(_PATH_CPUCTL, O_RDONLY)) < 0)
return false;
cs.cs_id = cpu;
if (ioctl(fd, IOC_CPU_GETSTATE, &cs) == 0) {
if (cs.cs_online)
online = true;
}
close(fd);
return online;
}
int
dt_status(dtrace_hdl_t *dtp, processorid_t cpu)
{
const dtrace_vector_t *v = dtp->dt_vector;
if (v == NULL) {
#if defined(sun)
#ifdef illumos
return (p_online(cpu, P_STATUS));
#else
return cpu_online(cpu) ? 1 : -1;
int maxid = 0;
size_t len = sizeof(maxid);
if (sysctlbyname("kern.smp.maxid", &maxid, &len, NULL, 0) != 0)
return (cpu == 0 ? 1 : -1);
else
return (cpu <= maxid ? 1 : -1);
#endif
}
@ -575,9 +562,9 @@ dt_write(dtrace_hdl_t *dtp, int fd, const void *buf, size_t n)
/*
* This function handles all output from libdtrace, as well as the
* dtrace_sprintf() case. If we're here due to dtrace_sprintf(), then
* dt_sprintf_buflen will be non-zero; in this case, we snprintf into the
* dt_sprintf_buflen will be non-zero; in this case, we sprintf into the
* specified buffer and return. Otherwise, if output is buffered (denoted by
* a NULL fp), we snprintf the desired output into the buffered buffer
* a NULL fp), we sprintf the desired output into the buffered buffer
* (expanding the buffer if required). If we don't satisfy either of these
* conditions (that is, if we are to actually generate output), then we call
* fprintf with the specified fp. In this case, we need to deal with one of
@ -597,7 +584,7 @@ dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
va_list ap;
int n;
#if !defined(sun)
#ifndef illumos
/*
* On FreeBSD, check if output is currently being re-directed
* to another file. If so, output to that file instead of the
@ -632,8 +619,8 @@ dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
size_t avail;
/*
* It's not legal to use buffered ouput if there is not a
* handler for buffered output.
* Using buffered output is not allowed if a handler has
* not been installed.
*/
if (dtp->dt_bufhdlr == NULL) {
va_end(ap);
@ -693,6 +680,7 @@ dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
dtp->dt_buffered_offs += needed;
assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0');
va_end(ap);
return (0);
}
@ -747,11 +735,6 @@ dt_zalloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
if (size > 16 * 1024 * 1024) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
else
@ -765,11 +748,6 @@ dt_alloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
if (size > 16 * 1024 * 1024) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
@ -828,15 +806,14 @@ dt_basename(char *str)
ulong_t
dt_popc(ulong_t x)
{
#ifdef _ILP32
#if defined(_ILP32)
x = x - ((x >> 1) & 0x55555555UL);
x = (x & 0x33333333UL) + ((x >> 2) & 0x33333333UL);
x = (x + (x >> 4)) & 0x0F0F0F0FUL;
x = x + (x >> 8);
x = x + (x >> 16);
return (x & 0x3F);
#endif
#ifdef _LP64
#elif defined(_LP64)
x = x - ((x >> 1) & 0x5555555555555555ULL);
x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
@ -844,6 +821,8 @@ dt_popc(ulong_t x)
x = x + (x >> 16);
x = x + (x >> 32);
return (x & 0x7F);
#else
/* This should be a #warning but for now ignore error. Err: "need td_popc() implementation" */
#endif
}
@ -867,6 +846,36 @@ dt_popcb(const ulong_t *bp, ulong_t n)
return (popc + dt_popc(bp[maxw] & ((1UL << maxb) - 1)));
}
#ifdef illumos
struct _rwlock;
struct _lwp_mutex;
int
dt_rw_read_held(pthread_rwlock_t *lock)
{
extern int _rw_read_held(struct _rwlock *);
return (_rw_read_held((struct _rwlock *)lock));
}
int
dt_rw_write_held(pthread_rwlock_t *lock)
{
extern int _rw_write_held(struct _rwlock *);
return (_rw_write_held((struct _rwlock *)lock));
}
#endif
int
dt_mutex_held(pthread_mutex_t *lock)
{
#ifdef illumos
extern int _mutex_held(struct _lwp_mutex *);
return (_mutex_held((struct _lwp_mutex *)lock));
#else
return (1);
#endif
}
static int
dt_string2str(char *s, char *str, int nbytes)
{
@ -910,8 +919,8 @@ dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes)
s = alloca(n);
if (err == 0 && addr != sym.st_value) {
(void) snprintf(s, n, "%s`%s+0x%" PRIx64, dts.dts_object,
dts.dts_name, addr - sym.st_value);
(void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object,
dts.dts_name, (unsigned long long)addr - sym.st_value);
} else if (err == 0) {
(void) snprintf(s, n, "%s`%s",
dts.dts_object, dts.dts_name);
@ -922,10 +931,10 @@ dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes)
* containing module.
*/
if (dtrace_lookup_by_addr(dtp, addr, NULL, &dts) == 0) {
(void) snprintf(s, n, "%s`0x%" PRIx64, dts.dts_object,
addr);
(void) snprintf(s, n, "%s`0x%llx", dts.dts_object,
(unsigned long long)addr);
} else {
(void) snprintf(s, n, "0x%" PRIx64, addr);
(void) snprintf(s, n, "0x%llx", (unsigned long long)addr);
}
}
@ -936,7 +945,6 @@ int
dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
uint64_t addr, char *str, int nbytes)
{
#if 0 /* XXX TBD needs libproc */
char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
struct ps_prochandle *P = NULL;
GElf_Sym sym;
@ -946,45 +954,32 @@ dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
if (P == NULL) {
(void) snprintf(c, sizeof (c), "0x%" PRIx64, addr);
(void) snprintf(c, sizeof (c), "0x%jx", (uintmax_t)addr);
return (dt_string2str(c, str, nbytes));
}
dt_proc_lock(dtp, P);
#if defined(sun)
if (Plookup_by_addr(P, addr, name, sizeof (name), &sym) == 0) {
(void) Pobjname(P, addr, objname, sizeof (objname));
#else
if (proc_addr2sym(P, addr, name, sizeof (name), &sym) == 0) {
(void) proc_objname(P, addr, objname, sizeof (objname));
#endif
obj = dt_basename(objname);
if (addr > sym.st_value) {
(void) snprintf(c, sizeof (c), "%s`%s+0x%" PRIx64,
obj, name, (addr - sym.st_value));
(void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj,
name, (unsigned long long)(addr - sym.st_value));
} else {
(void) snprintf(c, sizeof (c), "%s`%s", obj, name);
}
#if defined(sun)
} else if (Pobjname(P, addr, objname, sizeof (objname)) != 0) {
#else
} else if (proc_objname(P, addr, objname, sizeof (objname)) != 0) {
#endif
(void) snprintf(c, sizeof (c), "%s`0x%" PRIx64,
dt_basename(objname), addr);
(void) snprintf(c, sizeof (c), "%s`0x%jx",
dt_basename(objname), (uintmax_t)addr);
} else {
(void) snprintf(c, sizeof (c), "0x%" PRIx64, addr);
(void) snprintf(c, sizeof (c), "0x%jx", (uintmax_t)addr);
}
dt_proc_unlock(dtp, P);
dt_proc_release(dtp, P);
return (dt_string2str(c, str, nbytes));
#else
printf("XXX %s not implemented\n", __func__);
return 0;
#endif
}

View File

@ -82,7 +82,7 @@ dtrace_sleep(dtrace_hdl_t *dtp)
return; /* sleep duration has already past */
}
#if defined(sun)
#ifdef illumos
tv.tv_sec = (earliest - now) / NANOSEC;
tv.tv_nsec = (earliest - now) % NANOSEC;
@ -184,7 +184,7 @@ dtrace_go(dtrace_hdl_t *dtp)
{
dtrace_enable_io_t args;
void *dof;
int err;
int error, r;
if (dtp->dt_active)
return (dt_set_errno(dtp, EINVAL));
@ -206,11 +206,12 @@ dtrace_go(dtrace_hdl_t *dtp)
args.dof = dof;
args.n_matched = 0;
err = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
r = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
error = errno;
dtrace_dof_destroy(dtp, dof);
if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
return (dt_set_errno(dtp, errno));
if (r == -1 && (error != ENOTTY || dtp->dt_vector == NULL))
return (dt_set_errno(dtp, error));
if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
if (errno == EACCES)
@ -272,7 +273,7 @@ dtrace_work(dtrace_hdl_t *dtp, FILE *fp,
{
int status = dtrace_status(dtp);
dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
dtrace_workstatus_t rval;
dtrace_workstatus_t rval = 0; // XXX: gcc
switch (status) {
case DTRACE_STATUS_EXITED:
@ -294,7 +295,6 @@ dtrace_work(dtrace_hdl_t *dtp, FILE *fp,
break;
case -1:
default:
return (DTRACE_WORKSTATUS_ERROR);
}

View File

@ -23,8 +23,10 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#include <strings.h>
#include <assert.h>
@ -69,7 +71,7 @@ dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
enp->dn_op = DT_TOK_XLATE;
enp->dn_xlator = dxp;
enp->dn_xmember = mnp;
dt_node_type_assign(enp, dxp->dx_dst_ctfp, type);
dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
/*
* For the member itself, we use a DT_NODE_MEMBER as usual with the
@ -83,7 +85,7 @@ dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
mnp->dn_membname = strdup(name);
mnp->dn_membexpr = enp;
dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type);
dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
if (mnp->dn_membname == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
@ -318,7 +320,8 @@ dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
dxp = dt_list_next(dxp)) {
dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type);
dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
B_FALSE);
if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
goto out;

View File

@ -24,16 +24,22 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#ifndef _DTRACE_H
#define _DTRACE_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/dtrace.h>
#include <stdarg.h>
#include <stdio.h>
#include <gelf.h>
#include <libproc.h>
#ifndef illumos
#include <rtld_db.h>
#endif
#ifdef __cplusplus
extern "C" {
@ -149,6 +155,7 @@ typedef struct dtrace_stmtdesc {
dtrace_actdesc_t *dtsd_action_last; /* last action in action list */
void *dtsd_aggdata; /* aggregation data */
void *dtsd_fmtdata; /* type-specific output data */
void *dtsd_strdata; /* type-specific string data */
void (*dtsd_callback)(void); /* callback function for EPID */
void *dtsd_data; /* callback data pointer */
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
@ -240,6 +247,18 @@ extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
/*
* Type-specific output printing
*
* The print() action will associate a string data record that is actually the
* fully-qualified type name of the data traced by the DIFEXPR action. This is
* stored in the same 'format' record from the kernel, but we know by virtue of
* the fact that the action is still DIFEXPR that it is actually a reference to
* plain string data.
*/
extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *,
caddr_t, size_t);
/*
* DTrace Work Interface
*/
@ -338,6 +357,12 @@ extern int dtrace_handle_setopt(dtrace_hdl_t *,
#define DTRACE_A_PERCPU 0x0001
#define DTRACE_A_KEEPDELTA 0x0002
#define DTRACE_A_ANONYMOUS 0x0004
#define DTRACE_A_TOTAL 0x0008
#define DTRACE_A_MINMAXBIN 0x0010
#define DTRACE_A_HASNEGATIVES 0x0020
#define DTRACE_A_HASPOSITIVES 0x0040
#define DTRACE_AGGZOOM_MAX 0.95 /* height of max bar */
#define DTRACE_AGGWALK_ERROR -1 /* error while processing */
#define DTRACE_AGGWALK_NEXT 0 /* proceed to next element */
@ -358,6 +383,10 @@ struct dtrace_aggdata {
caddr_t dtada_delta; /* delta data, if available */
caddr_t *dtada_percpu; /* per CPU data, if avail */
caddr_t *dtada_percpu_delta; /* per CPU delta, if avail */
int64_t dtada_total; /* per agg total, if avail */
uint16_t dtada_minbin; /* minimum bin, if avail */
uint16_t dtada_maxbin; /* maximum bin, if avail */
uint32_t dtada_flags; /* flags */
};
typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *);
@ -477,8 +506,11 @@ typedef struct dtrace_typeinfo {
const char *dtt_object; /* object containing type */
ctf_file_t *dtt_ctfp; /* CTF container handle */
ctf_id_t dtt_type; /* CTF type identifier */
uint_t dtt_flags; /* Misc. flags */
} dtrace_typeinfo_t;
#define DTT_FL_USER 0x1 /* user type */
extern int dtrace_lookup_by_type(dtrace_hdl_t *, const char *, const char *,
dtrace_typeinfo_t *);
@ -522,7 +554,7 @@ extern int dtrace_probe_info(dtrace_hdl_t *,
* entry point to obtain a library handle.
*/
struct dtrace_vector {
#if defined(sun)
#ifdef illumos
int (*dtv_ioctl)(void *, int, void *);
#else
int (*dtv_ioctl)(void *, u_long, void *);
@ -573,7 +605,7 @@ extern int _dtrace_debug;
}
#endif
#if !defined(sun)
#ifndef illumos
#define _SC_CPUID_MAX _SC_NPROCESSORS_CONF
#define _SC_NPROCESSORS_MAX _SC_NPROCESSORS_CONF
#endif

View File

@ -26,11 +26,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
if [ $(uname) = "Darwin" ]; then
BSDECHO=
else
BSDECHO=-e
fi
BSDECHO=-e
echo ${BSDECHO} "\
/*\n\

View File

@ -26,11 +26,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
if [ $(uname) = "Darwin" ]; then
BSDECHO=
else
BSDECHO=-e
fi
BSDECHO=-e
echo ${BSDECHO} "\
/*\n\
@ -48,7 +44,7 @@ dtrace_subrstr(dtrace_hdl_t *dtp, int subr)\n\
{\n\
switch (subr) {"
awk '
nawk '
/^#define[ ]*DIF_SUBR_/ && $2 != "DIF_SUBR_MAX" {
printf("\tcase %s: return (\"%s\");\n", $2, tolower(substr($2, 10)));
}'