Dtrace: Add SUN MDB-like type-aware print() action.

Merge change from illumos:

1694 Add type-aware print() action

This is a very nice feature implemented in upstream Dtrace.
A complete description is available here:
http://dtrace.org/blogs/eschrock/2011/10/26/your-mdb-fell-into-my-dtrace/

This change bumps the DT_VERS_* number to 1.9.0 in
accordance to what is done in illumos.

While here also include some minor cleanups to ease further merging
and appease clang with a fix by Fabian Keil.

Illumos Revisions:	13501:c3a7090dbc16
			13483:f413e6c5d297

Reference:
https://www.illumos.org/issues/1560
https://www.illumos.org/issues/1694

Tested by:	Fabian Keil
Obtained from:	Illumos
MFC after:	1 month
This commit is contained in:
Pedro F. Giffuni 2013-03-25 20:38:09 +00:00
commit 5472787377
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=248708
23 changed files with 1254 additions and 74 deletions

View File

@ -0,0 +1,29 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
BEGIN
{
print(*curpsinfo);
}

View File

@ -0,0 +1,29 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
BEGIN
{
print((void)`p0);
}

View File

@ -0,0 +1,29 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
BEGIN
{
print();
}

View File

@ -0,0 +1,62 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
#pragma D option quiet
typedef struct bar {
int alpha;
} bar_t;
typedef struct foo {
int a[3];
char b[30];
bar_t c[2];
char d[3];
} foo_t;
BEGIN
{
this->f = (foo_t *)alloca(sizeof (foo_t));
this->f->a[0] = 1;
this->f->a[1] = 2;
this->f->a[2] = 3;
this->f->b[0] = 'a';
this->f->b[1] = 'b';
this->f->b[2] = 0;
this->f->c[0].alpha = 5;
this->f->c[1].alpha = 6;
this->f->c[2].alpha = 7;
this->f->d[0] = 4;
this->f->d[1] = 0;
this->f->d[2] = 0;
print(this->f->a);
print(this->f->b);
print(this->f->c);
print(*this->f);
exit(0);
}

View File

@ -0,0 +1,23 @@
int [3] [ 0x1, 0x2, 0x3 ]
char [30] "ab"
bar_t [2] [
bar_t {
int alpha = 0x5
},
bar_t {
int alpha = 0x6
}
]
foo_t {
int [3] a = [ 0x1, 0x2, 0x3 ]
char [30] b = [ "ab" ]
bar_t [2] c = [
bar_t {
int alpha = 0x5
},
bar_t {
int alpha = 0x6
}
]
char [3] d = [ '\004', '\0', '\0' ]
}

View File

@ -0,0 +1,49 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
#pragma D option quiet
typedef struct forward forward_t;
typedef struct foo {
int a:4;
int b:7;
int c:1;
int d:2;
} foo_t;
BEGIN
{
this->s = (foo_t *)alloca(sizeof (foo_t));
this->s->a = 1;
this->s->b = 5;
this->s->c = 0;
this->s->d = 2;
print(*this->s);
exit(0);
}

View File

@ -0,0 +1,6 @@
foo_t {
int a :4 = 0x1
int b :7 = 0x5
int c :1 = 0
int d :2 = 0x2
}

View File

@ -0,0 +1,45 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
#pragma D option quiet
BEGIN
{
i = (int)'a';
printf("\n");
print((char)'a');
print((int)-1);
print((unsigned int)23);
print((short)456);
print((unsigned short)789);
print((long)1234);
print((ulong_t)56789);
print((void *)0x1234);
print("hello");
exit(0);
}

View File

@ -0,0 +1,11 @@
char 'a'
int 0xffffffff
unsigned int 0x17
short 0x1c8
unsigned short 0x315
long 0x4d2
ulong_t 0xddd5
void * 0x1234
string "hello"

View File

@ -0,0 +1,59 @@
/*
* 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 (c) 2011 by Delphix. All rights reserved.
*/
#pragma D option quiet
typedef struct forward forward_t;
typedef struct foo {
int a;
void *b;
struct {
uint64_t alpha;
uint64_t beta;
} c;
ushort_t d;
int e;
forward_t *f;
void (*g)();
} foo_t;
BEGIN
{
this->s = (foo_t *)alloca(sizeof (foo_t));
this->s->a = 1;
this->s->b = (void *)2;
this->s->c.alpha = 3;
this->s->c.beta = 4;
this->s->d = 5;
this->s->e = 6;
this->s->f = (void *)7;
this->s->g = (void *)8;
print(*this->s);
exit(0);
}

View File

@ -0,0 +1,12 @@
foo_t {
int a = 0x1
void *b = 0x2
struct c = {
uint64_t alpha = 0x3
uint64_t beta = 0x4
}
ushort_t d = 0x5
int e = 0x6
forward_t *f = 0x7
int (*)() g = 0x8
}

View File

@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, Joyent Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
@ -679,6 +680,51 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
ap->dtad_kind = DTRACEACT_DIFEXPR;
}
/*
* 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.
*/
static void
dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
dt_node_t *dret;
size_t len;
dt_module_t *dmp;
if (dt_node_is_void(dnp->dn_args)) {
dnerror(dnp->dn_args, D_PRINT_VOID,
"print( ) may not be applied to a void expression\n");
}
if (dt_node_is_dynamic(dnp->dn_args)) {
dnerror(dnp->dn_args, D_PRINT_DYN,
"print( ) may not be applied to a dynamic expression\n");
}
dt_cg(yypcb, dnp->dn_args);
dret = yypcb->pcb_dret;
dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
len = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
sdp->dtsd_strdata = dt_alloc(dtp, len);
if (sdp->dtsd_strdata == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
(void) snprintf(sdp->dtsd_strdata, len, "%s`%ld", dmp->dm_name,
dret->dn_type);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_kind = DTRACEACT_DIFEXPR;
}
static void
dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
@ -1135,6 +1181,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
case DT_ACT_TRACE:
dt_action_trace(dtp, dnp->dn_expr, sdp);
break;
case DT_ACT_PRINT:
dt_action_print(dtp, dnp->dn_expr, sdp);
break;
case DT_ACT_TRACEMEM:
dt_action_tracemem(dtp, dnp->dn_expr, sdp);
break;

View File

@ -25,6 +25,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <stdlib.h>
@ -2193,6 +2194,7 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
rec->dtrd_size == sizeof (uint64_t)) {
/* LINTED - alignment */
tracememsize = *((unsigned long long *)addr);
continue;
}
@ -2300,6 +2302,35 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
goto nextrec;
}
/*
* If this is a DIF expression, and the record has a
* format set, this indicates we have a CTF type name
* associated with the data and we should try to print
* it out by type.
*/
if (act == DTRACEACT_DIFEXPR) {
const char *strdata = dt_strdata_lookup(dtp,
rec->dtrd_format);
if (strdata != NULL) {
n = dtrace_print(dtp, fp, strdata,
addr, rec->dtrd_size);
/*
* dtrace_print() will return -1 on
* error, or return the number of bytes
* consumed. It will return 0 if the
* type couldn't be determined, and we
* should fall through to the normal
* trace method.
*/
if (n < 0)
return (-1);
if (n > 0)
goto nextrec;
}
}
nofmt:
if (act == DTRACEACT_PRINTA) {
dt_print_aggdata_t pd;

View File

@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@ -758,16 +759,23 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
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;

View File

@ -24,11 +24,14 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 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,6 +190,8 @@ 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_PRINT_VOID, /* print() argument has void type */
D_PRINT_DYN, /* print() argument has dynamic type */
D_TRACEMEM_ADDR, /* tracemem() address bad type */
D_TRACEMEM_SIZE, /* tracemem() size bad type */
D_TRACEMEM_ARGS, /* tracemem() illegal number of args */

View File

@ -26,6 +26,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _DT_IMPL_H
@ -253,6 +254,8 @@ 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 */
struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
@ -438,8 +441,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
@ -641,6 +645,9 @@ 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 *,

View File

@ -23,7 +23,9 @@
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <stdlib.h>
#include <strings.h>
@ -34,11 +36,82 @@
#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;
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) {
free(fmt.dtfd_string);
return (dt_set_errno(dtp, errno));
}
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;
@ -132,71 +205,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;
@ -440,3 +465,28 @@ dt_aggid_destroy(dtrace_hdl_t *dtp)
dtp->dt_aggdesc = NULL;
dtp->dt_maxagg = 0;
}
const char *
dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
{
if (idx == 0 || idx > dtp->dt_maxstrdata)
return (NULL);
if (dtp->dt_strdata == NULL)
return (NULL);
return (dtp->dt_strdata[idx - 1]);
}
void
dt_strdata_destroy(dtrace_hdl_t *dtp)
{
int i;
for (i = 0; i < dtp->dt_maxstrdata; i++) {
free(dtp->dt_strdata[i]);
}
free(dtp->dt_strdata);
dtp->dt_strdata = NULL;
}

View File

@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@ -119,8 +120,9 @@
#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_LATEST DT_VERS_1_8_1
#define DT_VERS_STRING "Sun D 1.8.1"
#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
#define DT_VERS_LATEST DT_VERS_1_9
#define DT_VERS_STRING "Sun D 1.9"
const dt_version_t _dtrace_versions[] = {
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@ -140,6 +142,7 @@ const dt_version_t _dtrace_versions[] = {
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 */
0
};
@ -357,6 +360,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,
@ -1622,6 +1627,7 @@ 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);

View File

@ -0,0 +1,648 @@
/*
* 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.
*/
/*
* 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 {
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.
*/
#ifdef _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.
*/
#ifdef _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", (u_longlong_t)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(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 printed as a fixed-size integer. This is used both for
* pointers and functions.
*/
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);
dt_print_hex(fp, addr, size);
}
/*
* 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(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;
int value = 0;
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;
/*
* 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.
*/
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';
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.
*/
dmp = dt_module_lookup_by_name(dtp, object);
if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
id) == CTF_ERR) {
return (0);
}
/* setup the print structure and kick off the main print routine */
pa.pa_addr = addr;
pa.pa_ctfp = dt_module_getctf(dtp, dmp);
pa.pa_nest = 0;
pa.pa_depth = 0;
pa.pa_file = fp;
(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
return (len);
}

View File

@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <unistd.h>
@ -352,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);

View File

@ -154,6 +154,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 */
@ -245,6 +246,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
*/

View File

@ -32,6 +32,7 @@ SRCS= dt_aggregate.c \
dt_pcb.c \
dt_pid.c \
dt_pragma.c \
dt_print.c \
dt_printf.c \
dt_proc.c \
dt_program.c \

View File

@ -10209,12 +10209,14 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
case DTRACEACT_PRINTA:
case DTRACEACT_SYSTEM:
case DTRACEACT_FREOPEN:
case DTRACEACT_DIFEXPR:
/*
* We know that our arg is a string -- turn it into a
* format.
*/
if (arg == 0) {
ASSERT(desc->dtad_kind == DTRACEACT_PRINTA);
ASSERT(desc->dtad_kind == DTRACEACT_PRINTA ||
desc->dtad_kind == DTRACEACT_DIFEXPR);
format = 0;
} else {
ASSERT(arg != 0);
@ -10227,7 +10229,6 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
/*FALLTHROUGH*/
case DTRACEACT_LIBACT:
case DTRACEACT_DIFEXPR:
case DTRACEACT_TRACEMEM:
case DTRACEACT_TRACEMEM_DYNSIZE:
if (dp == NULL)
@ -12272,15 +12273,20 @@ dtrace_dof_actdesc(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate,
(uintptr_t)sec->dofs_offset + offs);
kind = (dtrace_actkind_t)desc->dofa_kind;
if (DTRACEACT_ISPRINTFLIKE(kind) &&
if ((DTRACEACT_ISPRINTFLIKE(kind) &&
(kind != DTRACEACT_PRINTA ||
desc->dofa_strtab != DOF_SECIDX_NONE)) ||
(kind == DTRACEACT_DIFEXPR &&
desc->dofa_strtab != DOF_SECIDX_NONE)) {
dof_sec_t *strtab;
char *str, *fmt;
uint64_t i;
/*
* printf()-like actions must have a format string.
* The argument to these actions is an index into the
* DOF string table. For printf()-like actions, this
* is the format string. For print(), this is the
* CTF type of the expression result.
*/
if ((strtab = dtrace_dof_sect(dof,
DOF_SECT_STRTAB, desc->dofa_strtab)) == NULL)