[PATCH v2 2/2] cg: transition [u]stack() from action to subroutine
Kris Van Hees <[email protected]>
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <SJ0PR10MB5672351690BDFC2E13664F13C21BA@SJ0PR10MB5672.namprd10.prod.outlook.com> |
In order to allow [u]stack() to be used in expressions, they must be subroutines. An exception is added to allow them to retain their original behaviour as data recording actions as well. The implementation change requires a new internal type to be defined (dt_stack) to hold stack trace data. This patch does not allow [u]stack() to be used in assignments to variables just yet, but it supports all previous uses of [u]stack(). Additional functionality will be added on top of this. Signed-off-by: Kris Van Hees <[email protected]> --- include/dtrace/dif_defines.h | 6 +- libdtrace/dt_cg.c | 350 +++++++++++------- libdtrace/dt_dctx.h | 4 +- libdtrace/dt_open.c | 21 +- libdtrace/dt_options.c | 44 ++- libdtrace/dt_printf.c | 3 +- test/unittest/funcs/tst.subr.d | 13 +- .../printa/err.D_PRINTF_ARG_TYPE.stack.r | 2 +- .../printa/err.D_PRINTF_ARG_TYPE.ustack.r | 2 +- 9 files changed, 289 insertions(+), 156 deletions(-) diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index 9f6e3b55..a18614d2 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -2,7 +2,7 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. * - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. */ /* @@ -210,8 +210,10 @@ #define DIF_SUBR_INET_NTOA6 43 #define DIF_SUBR_D_PATH 44 #define DIF_SUBR_LINK_NTOP 45 +#define DIF_SUBR_STACK 46 +#define DIF_SUBR_USTACK 47 -#define DIF_SUBR_MAX 45 +#define DIF_SUBR_MAX 47 typedef uint32_t dif_instr_t; diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index 51473667..0299ccb1 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -2723,7 +2723,8 @@ dt_cg_stack_arg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_actkind_t kind) * The "kind" argument is either DTRACEACT_STACK or DTRACEACT_USTACK. */ static int -dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actkind_t kind) +dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, + dtrace_actkind_t kind) { dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_irlist_t *dlp = &pcb->pcb_ir; @@ -2743,12 +2744,9 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk /* Handle alignment and reserve space in the output buffer. */ if (reg >= 0) { - uint_t nextoff; - nextoff = (off + (align - 1)) & ~(align - 1); - if (off < nextoff) - emit(dlp, BPF_ALU64_IMM(BPF_ADD, reg, nextoff - off)); - off = nextoff + prefsz + stacksize; + off = ALIGN(off, align); } else { + reg = BPF_REG_9; off = dt_rec_add(dtp, dt_cg_fill_gap, kind, prefsz + stacksize, align, NULL, arg); } @@ -2762,11 +2760,7 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk dt_regset_free_args(drp); /* mov32 %r0, %r0 effectively masks the lower 32 bits. */ emit(dlp, BPF_MOV32_REG(BPF_REG_0, BPF_REG_0)); - - if (reg >= 0) - emit(dlp, BPF_STORE(BPF_DW, reg, 0, BPF_REG_0)); - else - emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0)); + emit(dlp, BPF_STORE(BPF_DW, reg, off, BPF_REG_0)); dt_regset_free(drp, BPF_REG_0); } @@ -2774,14 +2768,8 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk if (dt_regset_xalloc_args(drp) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_access_dctx(BPF_REG_1, dlp, drp, DCTX_CTX); - if (reg >= 0) { - emit(dlp, BPF_MOV_REG(BPF_REG_2, reg)); - if (prefsz) - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, prefsz)); - } else { - emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_9)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, off + prefsz)); - } + emit(dlp, BPF_MOV_REG(BPF_REG_2, reg)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, off + prefsz)); emit(dlp, BPF_MOV_IMM(BPF_REG_3, stacksize)); if (kind == DTRACEACT_USTACK) emit(dlp, BPF_MOV_IMM(BPF_REG_4, BPF_F_USER_STACK)); @@ -2798,11 +2786,7 @@ dt_cg_act_stack_sub(dt_pcb_t *pcb, dt_node_t *dnp, int reg, int off, dtrace_actk emitl(dlp, lbl_valid, BPF_NOP()); - /* Finish. */ - if (reg >= 0) - emit(dlp, BPF_ALU64_IMM(BPF_ADD, reg, prefsz + stacksize)); - - return off; + return prefsz + stacksize; } static void @@ -3909,33 +3893,42 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, dt_irlist_t *dlp, longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG); /* - * Handle actions that can be used as agg keys. - * If we are not an aggregation, dt_cg_node(dnp, ...) - * will alert us there is a problem. + * Some function calls (actions or subroutines) need special + * handling. */ - if (idp->di_kind == DT_IDENT_AGG && - dnp->dn_kind == DT_NODE_FUNC && - dnp->dn_ident != NULL) - switch (dnp->dn_ident->di_id) { - case DT_ACT_STACK: - case DT_ACT_USTACK: - /* If this is a stack()-like function, we can handle it later. */ - dt_cg_push_stack(BPF_REG_FP, dlp, drp); - continue; - case DT_ACT_JSTACK: - dnerror(dnp, D_UNKNOWN, "jstack() is not implemented (yet)\n"); - /* FIXME: Needs implementation */ - case DT_ACT_SYM: - case DT_ACT_MOD: - case DT_ACT_UADDR: - case DT_ACT_UMOD: - case DT_ACT_USYM: - /* Otherwise, use the action's arg, not its "return value". */ - dt_cg_node(dnp->dn_args, dlp, drp); - dt_cg_push_stack(dnp->dn_args->dn_reg, dlp, drp); - dt_regset_free(drp, dnp->dn_args->dn_reg); - continue; + if (dnp->dn_kind == DT_NODE_FUNC) { + dt_ident_t *fidp = dnp->dn_ident; + + assert(fidp != NULL); + + /* + * For subroutines, stack() and ustack() don't need to + * be evaluated until we fill in the data of the tuple. + */ + if (fidp->di_kind == DT_IDENT_FUNC) { + if (fidp->di_id == DIF_SUBR_STACK || + fidp->di_id == DIF_SUBR_USTACK) { + dt_cg_push_stack(BPF_REG_FP, dlp, drp); + continue; + } + } else if (fidp->di_kind == DT_IDENT_ACTFUNC) { + switch (fidp->di_id) { + case DT_ACT_JSTACK: + dnerror(dnp, D_UNKNOWN, "jstack() is not implemented (yet)\n"); + /* FIXME: Needs implementation */ + case DT_ACT_SYM: + case DT_ACT_MOD: + case DT_ACT_UADDR: + case DT_ACT_UMOD: + case DT_ACT_USYM: + /* Otherwise, use the action's arg, not its "return value". */ + dt_cg_node(dnp->dn_args, dlp, drp); + dt_cg_push_stack(dnp->dn_args->dn_reg, dlp, drp); + dt_regset_free(drp, dnp->dn_args->dn_reg); + continue; + } } + } /* Push the component (pointer or value) onto the tuple stack. */ dt_cg_node(dnp, dlp, drp); @@ -3972,7 +3965,6 @@ empty_args: dt_regset_free(drp, BPF_REG_0); /* Reserve space for a uint32_t value at the beginning of the tuple. */ - emit(dlp, BPF_ALU64_IMM(BPF_ADD, treg, sizeof(uint32_t))); tuplesize = sizeof(uint32_t); if ((areg = dt_regset_alloc(drp)) == -1) @@ -3986,53 +3978,62 @@ empty_args: for (dnp = args, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { dtrace_diftype_t t; size_t size; - uint_t nextoff; int is_symmod = 0; - if (dnp->dn_kind == DT_NODE_FUNC && - dnp->dn_ident != NULL) - switch (dnp->dn_ident->di_id) { - case DT_ACT_STACK: - tuplesize = dt_cg_act_stack_sub(yypcb, dnp, treg, tuplesize, DTRACEACT_STACK); - continue; - case DT_ACT_USTACK: - tuplesize = dt_cg_act_stack_sub(yypcb, dnp, treg, tuplesize, DTRACEACT_USTACK); - continue; - case DT_ACT_UADDR: - case DT_ACT_USYM: - case DT_ACT_UMOD: - nextoff = (tuplesize + (8 - 1)) & ~(8 - 1); - if (tuplesize < nextoff) - emit(dlp, BPF_ALU64_IMM(BPF_ADD, treg, nextoff - tuplesize)); - - /* Preface the value with the user process pid. */ - if (dt_regset_xalloc_args(drp) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - dt_regset_xalloc(drp, BPF_REG_0); - emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid)); - dt_regset_free_args(drp); - emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32)); - emit(dlp, BPF_STORE(BPF_DW, treg, 0, BPF_REG_0)); - dt_regset_free(drp, BPF_REG_0); - - /* Then store the value. */ - dt_regset_xalloc(drp, BPF_REG_0); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ)); - emit(dlp, BPF_STORE(BPF_DW, treg, 8, BPF_REG_0)); - dt_regset_free(drp, BPF_REG_0); - - emit(dlp, BPF_ALU64_IMM(BPF_ADD, treg, 16)); - tuplesize = nextoff + 16; - - continue; - case DT_ACT_SYM: - case DT_ACT_MOD: - is_symmod = 1; - size = 8; - dt_regset_xalloc(drp, BPF_REG_0); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ)); - break; + if (dnp->dn_kind == DT_NODE_FUNC) { + dt_ident_t *fidp = dnp->dn_ident; + + if (fidp->di_kind == DT_IDENT_FUNC) { + switch (fidp->di_id) { + case DIF_SUBR_STACK: + tuplesize += dt_cg_act_stack_sub( + yypcb, dnp, treg, + tuplesize, + DTRACEACT_STACK); + continue; + case DIF_SUBR_USTACK: + tuplesize += dt_cg_act_stack_sub( + yypcb, dnp, treg, + tuplesize, + DTRACEACT_USTACK); + continue; + } + } else if (fidp->di_kind == DT_IDENT_ACTFUNC) { + switch (fidp->di_id) { + case DT_ACT_UADDR: + case DT_ACT_USYM: + case DT_ACT_UMOD: + tuplesize = ALIGN(tuplesize, 8); + + /* Preface the value with the user process pid. */ + if (dt_regset_xalloc_args(drp) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dt_regset_xalloc(drp, BPF_REG_0); + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid)); + dt_regset_free_args(drp); + emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32)); + emit(dlp, BPF_STORE(BPF_DW, treg, tuplesize, BPF_REG_0)); + dt_regset_free(drp, BPF_REG_0); + + /* Then store the value. */ + dt_regset_xalloc(drp, BPF_REG_0); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ)); + emit(dlp, BPF_STORE(BPF_DW, treg, tuplesize + 8, BPF_REG_0)); + dt_regset_free(drp, BPF_REG_0); + + tuplesize += 16; + + continue; + case DT_ACT_SYM: + case DT_ACT_MOD: + is_symmod = 1; + size = 8; + dt_regset_xalloc(drp, BPF_REG_0); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ)); + break; + } } + } if (!is_symmod) { dt_node_diftype(dtp, dnp, &t); @@ -4052,15 +4053,12 @@ empty_args: } if (dt_node_is_scalar(dnp) || dt_node_is_float(dnp) || is_symmod) { - nextoff = (tuplesize + (size - 1)) & ~(size - 1); - if (tuplesize < nextoff) - emit(dlp, BPF_ALU64_IMM(BPF_ADD, treg, nextoff - tuplesize)); + tuplesize = ALIGN(tuplesize, size); - emit(dlp, BPF_STOREX(size, treg, 0, BPF_REG_0)); + emit(dlp, BPF_STOREX(size, treg, tuplesize, BPF_REG_0)); dt_regset_free(drp, BPF_REG_0); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, treg, size)); - tuplesize = nextoff + size; + tuplesize += size; } else if (dt_node_is_string(dnp)) { uint_t lbl_valid = dt_irlist_label(dlp); @@ -4068,6 +4066,7 @@ empty_args: longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); emit(dlp, BPF_MOV_REG(BPF_REG_1, treg)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, tuplesize)); emit(dlp, BPF_MOV_IMM(BPF_REG_2, size + 1)); emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); dt_cg_tstring_free(yypcb, dnp); @@ -4081,7 +4080,7 @@ empty_args: DT_ISIMM, 128 + i); emitl(dlp, lbl_valid, - BPF_ALU64_IMM(BPF_ADD, treg, size + 1)); + BPF_NOP()); tuplesize += size + 1; } else if (t.dtdt_flags & DIF_TF_BYREF) { uint_t lbl_valid = dt_irlist_label(dlp); @@ -4090,6 +4089,7 @@ empty_args: longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); emit(dlp, BPF_MOV_REG(BPF_REG_1, treg)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, tuplesize)); emit(dlp, BPF_MOV_IMM(BPF_REG_2, size)); emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); dt_regset_free(drp, BPF_REG_0); @@ -4102,7 +4102,7 @@ empty_args: DT_ISIMM, 0); emitl(dlp, lbl_valid, - BPF_ALU64_IMM(BPF_ADD, treg, size)); + BPF_NOP()); tuplesize += size; } else assert(0); /* We shouldn't be able to get here. */ @@ -4128,10 +4128,10 @@ empty_args: dt_regset_xalloc(drp, BPF_REG_0); emite(dlp, BPF_CALL_FUNC(idp->di_id), idp); dt_regset_free_args(drp); - emit(dlp, BPF_STORE(BPF_DW, treg, 0, BPF_REG_0)); + emit(dlp, BPF_STORE(BPF_DW, treg, tuplesize, BPF_REG_0)); dt_regset_free(drp, BPF_REG_0); } else - emit(dlp, BPF_STORE_IMM(BPF_DW, treg, 0, 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, treg, tuplesize, 0)); /* Account for the optional TLS key (or 0). */ tuplesize += sizeof(uint64_t); @@ -6324,6 +6324,42 @@ dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) TRACE_REGSET(" subr-strchr:End "); } +static void +dt_cg_subr_stack_common(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, + dtrace_actkind_t kind) +{ + dtrace_hdl_t *dtp = yypcb->pcb_hdl; + + if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + + /* + * Collect the stack in the static buffer (because it is an invariant + * for a probe firing), and return a pointer to it. + */ + dt_cg_access_dctx(dnp->dn_reg, dlp, drp, DCTX_MEM); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, DMEM_STACK(dtp))); + + /* Call the stack helper function to collect the stack. */ + dt_cg_act_stack_sub(yypcb, dnp, dnp->dn_reg, 0, kind); +} + +static void +dt_cg_subr_stack(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) +{ + TRACE_REGSET(" subr-stack:Begin"); + dt_cg_subr_stack_common(dnp, dlp, drp, DTRACEACT_STACK); + TRACE_REGSET(" subr-stack:End "); +} + +static void +dt_cg_subr_ustack(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) +{ + TRACE_REGSET(" subr-ustack:Begin"); + dt_cg_subr_stack_common(dnp, dlp, drp, DTRACEACT_USTACK); + TRACE_REGSET(" subr-ustack:End "); +} + static void dt_cg_subr_strrchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { @@ -6953,6 +6989,8 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, + [DIF_SUBR_STACK] = &dt_cg_subr_stack, + [DIF_SUBR_USTACK] = &dt_cg_subr_ustack, }; static void @@ -8692,43 +8730,50 @@ dt_cg_agg(dt_pcb_t *pcb, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) uint64_t arg = 0; dt_ident_t *idp = knp->dn_ident; - if (knp->dn_kind == DT_NODE_FUNC && idp != NULL && - idp->di_kind == DT_IDENT_ACTFUNC) { - size = 16; + if (knp->dn_kind == DT_NODE_FUNC && idp != NULL) { alignment = 8; - switch (idp->di_id) { - case DT_ACT_USTACK: - arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_USTACK); - kind = DTRACEACT_USTACK; - size = 8 + 8 * DTRACE_STACK_NFRAMES(arg); - break; - case DT_ACT_JSTACK: - kind = DTRACEACT_JSTACK; - break; - case DT_ACT_USYM: - kind = DTRACEACT_USYM; - break; - case DT_ACT_UMOD: - kind = DTRACEACT_UMOD; - break; - case DT_ACT_UADDR: - kind = DTRACEACT_UADDR; - break; - case DT_ACT_STACK: - arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_STACK); - kind = DTRACEACT_STACK; - size = 8 * arg; - break; - case DT_ACT_SYM: - kind = DTRACEACT_SYM; - size = 8; - break; - case DT_ACT_MOD: - kind = DTRACEACT_MOD; - size = 8; - break; + + if (idp->di_kind == DT_IDENT_FUNC) { + switch (idp->di_id) { + case DIF_SUBR_USTACK: + arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_USTACK); + kind = DTRACEACT_USTACK; + size = 8 + 8 * DTRACE_STACK_NFRAMES(arg); + goto add_rec; + case DIF_SUBR_STACK: + arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_STACK); + kind = DTRACEACT_STACK; + size = 8 * arg; + goto add_rec; + } + } else if (idp->di_kind == DT_IDENT_ACTFUNC) { + size = 16; + switch (idp->di_id) { + case DT_ACT_JSTACK: + kind = DTRACEACT_JSTACK; + goto add_rec; + case DT_ACT_USYM: + kind = DTRACEACT_USYM; + goto add_rec; + case DT_ACT_UMOD: + kind = DTRACEACT_UMOD; + goto add_rec; + case DT_ACT_UADDR: + kind = DTRACEACT_UADDR; + goto add_rec; + case DT_ACT_SYM: + kind = DTRACEACT_SYM; + size = 8; + goto add_rec; + case DT_ACT_MOD: + kind = DTRACEACT_MOD; + size = 8; + goto add_rec; + } } - } else if (dt_node_is_string(knp)) { + } + + if (dt_node_is_string(knp)) { size = dtp->dt_options[DTRACEOPT_STRSIZE] + 1; alignment = 1; } else { @@ -8739,6 +8784,7 @@ dt_cg_agg(dt_pcb_t *pcb, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) alignment = size; } +add_rec: dt_aggid_rec_add(dtp, aid->di_id, kind, size, alignment, arg); } } @@ -8822,10 +8868,34 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) if (enp->dn_kind == DT_NODE_AGG) dt_cg_agg(pcb, enp, &pcb->pcb_ir, pcb->pcb_regs); - else + else { + /* + * Special case: [u]stack() in statement + * context is treated as data generating + * action. + */ + if (enp->dn_kind == DT_NODE_FUNC) { + uint_t id; + + id = enp->dn_ident->di_id; + if (id == DIF_SUBR_STACK) + id = DTRACEACT_STACK; + else if (id == DIF_SUBR_USTACK) + id = DTRACEACT_USTACK; + else + id = 0; + + if (id) { + dt_cg_act_stack(pcb, enp, id); + pcb->pcb_stmt->dtsd_clauseflags |= DT_CLSFLAG_DATAREC; + goto done; + } + } dt_cg_node(enp, &pcb->pcb_ir, pcb->pcb_regs); + } +done: if (enp->dn_reg != -1) { dt_regset_free(pcb->pcb_regs, enp->dn_reg); diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h index 9ff6cca5..b50a1395 100644 --- a/libdtrace/dt_dctx.h +++ b/libdtrace/dt_dctx.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -128,7 +128,7 @@ typedef struct dt_dctx { * completed. */ #define DMEM_STACK_SZ(dtp) \ - (sizeof(uint64_t) * (dtp)->dt_options[DTRACEOPT_MAXFRAMES]) + (sizeof(uint64_t) * (dtp)->dt_options[DTRACEOPT_MAXFRAMES] + 1) #define DMEM_TSTR_SZ(dtp) \ (DT_TSTRING_SLOTS * DT_TSTRING_SIZE(dtp)) #define DMEM_STRTOK_SZ(dtp) \ diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index 509f263d..ed0b14a1 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -175,7 +175,7 @@ static const dt_ident_t _dtrace_globals[] = { { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0, - &dt_idops_func, "stack([uint32_t], [uint32_t])" }, + &dt_idops_func, "dt_stack([uint32_t], [uint32_t])" }, { "link_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_LINK_NTOP, DT_ATTR_STABCMN, DT_VERS_1_5, &dt_idops_func, "string(int, void *)" }, { "llquantize", DT_IDENT_AGGFUNC, 0, DT_AGG_LLQUANTIZE, @@ -273,8 +273,8 @@ static const dt_ident_t _dtrace_globals[] = { { "speculation", DT_IDENT_FUNC, 0, DIF_SUBR_SPECULATION, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, -{ "stack", DT_IDENT_ACTFUNC, 0, DT_ACT_STACK, DT_ATTR_STABCMN, DT_VERS_1_0, - &dt_idops_func, "stack([uint32_t])" }, +{ "stack", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_STACK, DT_ATTR_STABCMN, + DT_VERS_1_0, &dt_idops_func, "dt_stack([uint32_t])" }, { "stackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_STACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint32_t" }, @@ -328,8 +328,8 @@ static const dt_ident_t _dtrace_globals[] = { DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_regs, NULL }, -{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0, - &dt_idops_func, "stack([uint32_t], [uint32_t])" }, +{ "ustack", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_USTACK, DT_ATTR_STABCMN, + DT_VERS_1_0, &dt_idops_func, "dt_stack([uint32_t], [uint32_t])" }, { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_type, "uint32_t" }, @@ -1054,8 +1054,17 @@ dt_vopen(int version, int flags, int *errp, dtp->dt_type_dyn = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "<DYN>", ctf_lookup_by_name(dmp->dm_ctfp, "void")); + /* + * The stack type is added as a typedef of uint64_t[MAXFRAMES]. The + * final value of MAXFRAMES may be adjusted with the "stackframes" + * option. + */ + ctr.ctr_contents = ctf_lookup_by_name(dmp->dm_ctfp, "uint64_t"); + ctr.ctr_index = ctf_lookup_by_name(dmp->dm_ctfp, "long"); + ctr.ctr_nelems = _dtrace_stackframes; + dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, - "stack", ctf_lookup_by_name(dmp->dm_ctfp, "void")); + "dt_stack", ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &ctr)); dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void")); diff --git a/libdtrace/dt_options.c b/libdtrace/dt_options.c index 25e79979..7508f044 100644 --- a/libdtrace/dt_options.c +++ b/libdtrace/dt_options.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -912,6 +912,46 @@ dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) return 0; } +/* + * When setting the maxframes option, set the option in the dt_options array + * using dt_opt_runtime() as usual, and then update the definition of the CTF + * type for "_stack" to be an array of the corresponding size. + * If any errors occur, reset dt_options[option] to its previous value. + */ +static int +dt_opt_maxframes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ + dtrace_optval_t val = dtp->dt_options[option]; + ctf_file_t *fp = DT_STACK_CTFP(dtp); + ctf_id_t type = ctf_type_resolve(fp, DT_STACK_TYPE(dtp)); + ctf_arinfo_t r; + + if (dt_opt_runtime(dtp, arg, option) != 0) + return -1; /* dt_errno is set for us */ + + if (dtp->dt_options[option] > UINT_MAX) { + dtp->dt_options[option] = val; + return dt_set_errno(dtp, EOVERFLOW); + } + + if (ctf_array_info(fp, type, &r) == CTF_ERR) { + dtp->dt_options[option] = val; + dtp->dt_ctferr = ctf_errno(fp); + return dt_set_errno(dtp, EDT_CTF); + } + + r.ctr_nelems = (uint_t)dtp->dt_options[option]; + + if (ctf_set_array(fp, type, &r) == CTF_ERR || + ctf_update(fp) == CTF_ERR) { + dtp->dt_options[option] = val; + dtp->dt_ctferr = ctf_errno(fp); + return dt_set_errno(dtp, EDT_CTF); + } + + return 0; +} + /* * When setting the strsize option, set the option in the dt_options array * using dt_opt_size() as usual, and then update the definition of the CTF @@ -1157,7 +1197,7 @@ static const dt_option_t _dtrace_rtoptions[] = { { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES }, { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE }, { "lockmem", dt_opt_lockmem, DTRACEOPT_LOCKMEM }, - { "maxframes", dt_opt_runtime, DTRACEOPT_MAXFRAMES }, + { "maxframes", dt_opt_maxframes, DTRACEOPT_MAXFRAMES }, { "nusdtprobes", dt_opt_runtime, DTRACEOPT_NUSDTPROBES }, { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC }, { "pcapsize", dt_opt_pcapsize, DTRACEOPT_PCAPSIZE }, diff --git a/libdtrace/dt_printf.c b/libdtrace/dt_printf.c index 0d7c0bb4..a3e15397 100644 --- a/libdtrace/dt_printf.c +++ b/libdtrace/dt_printf.c @@ -24,7 +24,8 @@ static int pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) { - return dt_node_is_pointer(dnp) || dt_node_is_integer(dnp); + return (dt_node_is_pointer(dnp) && !dt_node_is_stack(dnp)) || + dt_node_is_integer(dnp); } /*ARGSUSED*/ diff --git a/test/unittest/funcs/tst.subr.d b/test/unittest/funcs/tst.subr.d index 9f7203c0..d97a0780 100644 --- a/test/unittest/funcs/tst.subr.d +++ b/test/unittest/funcs/tst.subr.d @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -36,6 +36,15 @@ /*DSTYLED*/ \ } +#define STKFUNC(x) \ + BEGIN \ + /*DSTYLED*/ \ + { \ + subr++; \ + @stk[x] = sum(1); \ + /*DSTYLED*/ \ + } + #define NUM_UNIMPLEMENTED 7 INTFUNC(rand()) @@ -89,6 +98,8 @@ STRFUNC(inet_ntoa6((in6_addr_t *)alloca(sizeof(in6_addr_t)))) /* Not implemented yet. STRFUNC(d_path(&(curthread->fs->root))) STRFUNC(link_ntop(ARPHRD_ETHER, (void *)alloca(sizeof(ipaddr_t)))) */ +STKFUNC(stack(5)) +STKFUNC(ustack(5)) BEGIN /subr == DIF_SUBR_MAX + 1 - NUM_UNIMPLEMENTED/ diff --git a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r index 50e884a0..95ac80da 100644 --- a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r +++ b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r @@ -2,4 +2,4 @@ dtrace: failed to compile script test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.d: [D_PRINTF_ARG_TYPE] line 12: printa( ) argument #2 is incompatible with conversion #1 prototype: conversion: %p prototype: pointer or integer - argument: stack + argument: dt_stack diff --git a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r index fc9e1512..5df10376 100644 --- a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r +++ b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r @@ -2,4 +2,4 @@ dtrace: failed to compile script test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.d: [D_PRINTF_ARG_TYPE] line 12: printa( ) argument #2 is incompatible with conversion #1 prototype: conversion: %p prototype: pointer or integer - argument: stack + argument: dt_stack -- 2.43.5