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:
commit
5472787377
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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' ]
|
||||
}
|
@ -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);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
foo_t {
|
||||
int a :4 = 0x1
|
||||
int b :7 = 0x5
|
||||
int c :1 = 0
|
||||
int d :2 = 0x2
|
||||
}
|
@ -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);
|
||||
}
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -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 @@ again:
|
||||
|
||||
if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
|
||||
rec->dtrd_size == sizeof (uint64_t)) {
|
||||
/* LINTED - alignment */
|
||||
tracememsize = *((unsigned long long *)addr);
|
||||
continue;
|
||||
}
|
||||
@ -2300,6 +2302,35 @@ again:
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 *,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
648
cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
Normal file
648
cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user