sync with FreeBSD
This commit is contained in:
parent
2cd1ca309f
commit
c0855460da
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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++;
|
||||
|
@ -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 ||
|
||||
|
@ -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
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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"); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -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 : "");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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:
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
157
external/cddl/osnet/dist/lib/libdtrace/common/dt_pq.c
vendored
Normal file
157
external/cddl/osnet/dist/lib/libdtrace/common/dt_pq.c
vendored
Normal 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);
|
||||
}
|
51
external/cddl/osnet/dist/lib/libdtrace/common/dt_pq.h
vendored
Normal file
51
external/cddl/osnet/dist/lib/libdtrace/common/dt_pq.h
vendored
Normal 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 */
|
@ -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);
|
||||
|
706
external/cddl/osnet/dist/lib/libdtrace/common/dt_print.c
vendored
Normal file
706
external/cddl/osnet/dist/lib/libdtrace/common/dt_print.c
vendored
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -26,11 +26,7 @@
|
||||
#
|
||||
#ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
if [ $(uname) = "Darwin" ]; then
|
||||
BSDECHO=
|
||||
else
|
||||
BSDECHO=-e
|
||||
fi
|
||||
BSDECHO=-e
|
||||
|
||||
echo ${BSDECHO} "\
|
||||
/*\n\
|
||||
|
@ -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)));
|
||||
}'
|
||||
|
Loading…
Reference in New Issue
Block a user