[DTrace-devel] [PATCH] bpf: separate bvar implementation into separate functions
Eugene Loh
eugene.loh at oracle.com
Fri Jan 24 07:35:49 UTC 2025
I think I'm on board with this patch, but two questions.
1. There is DIF_VAR_EXECARGS stuff in two places. Is that stuff in the
wrong patch?
2. I'm confused why
test/demo/builtin/ipl.d
test/demo/builtin/vtimestamp.d
were passing: there was no ipl or vtimestamp support before and there
is none now. Presumably, the tests used to time out... so why was that
considered a PASS? I guess I see why
test/unittest/buffering/tst.cputime.sh used to pass, but maybe that
suggests that the test needs to be tightened up and be made quite a bit
more discriminating.
On 1/23/25 22:48, Kris Van Hees wrote:
> The handling of builtin variables was done with a single big function
> that therefore got linked into every single BPF program (twice if the
> builtin variable might raise a fault). Providing separate functions
> for most builtin variables reduces BPF program size significantly.
>
> This also reduces pressure on the BPF verifies.
>
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
> bpf/get_bvar.c | 412 +++++++++++++-----------
> include/dtrace/dif_defines.h | 1 +
> libdtrace/dt_cg.c | 39 ++-
> libdtrace/dt_dis.c | 57 +++-
> libdtrace/dt_open.c | 2 +
> test/demo/builtin/ipl.d | 2 +
> test/demo/builtin/vtimestamp.d | 2 +
> test/demo/io/iocpu.d | 2 +
> test/unittest/buffering/tst.cputime.sh | 1 +
> test/unittest/disasm/tst.ann-bvar.r | 69 ++--
> test/unittest/disasm/tst.ann-bvar.sh | 9 +-
> test/unittest/disasm/tst.vartab-bvar.r | 2 -
> test/unittest/disasm/tst.vartab-bvar.sh | 7 +-
> 13 files changed, 360 insertions(+), 245 deletions(-)
>
> diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
> index 1c0fa884..c760126d 100644
> --- a/bpf/get_bvar.c
> +++ b/bpf/get_bvar.c
> @@ -19,18 +19,21 @@
> # define noinline __attribute__((noinline))
> #endif
>
> -extern struct bpf_map_def cpuinfo;
> -extern struct bpf_map_def probes;
> -extern struct bpf_map_def state;
> -extern struct bpf_map_def usdt_names;
> -
> -extern uint64_t PC;
> -extern uint64_t STBSZ;
> -extern uint64_t STKSIZ;
> -extern uint64_t BOOTTM;
> +extern struct bpf_map_def cpuinfo;
> +extern struct bpf_map_def probes;
> +extern struct bpf_map_def state;
> +extern struct bpf_map_def usdt_names;
> +
> +extern uint64_t BOOTTM;
> +extern uint64_t NPROBES;
> +extern uint64_t PC;
> +extern uint64_t STBSZ;
> +extern uint64_t STKSIZ;
> extern uint64_t STACK_OFF;
> -extern uint64_t STACK_SKIP;
> -extern uint64_t NPROBES;
> +extern uint64_t STACK_SKIP;
> +extern uint64_t TASK_COMM;
> +extern uint64_t TASK_REAL_PARENT;
> +extern uint64_t TASK_TGID;
>
> #define error(dctx, fault, illval) \
> ({ \
> @@ -38,198 +41,231 @@ extern uint64_t NPROBES;
> -1; \
> })
>
> -noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
> +noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx)
> {
> dt_mstate_t *mst = dctx->mst;
>
> - switch (id) {
> - case DIF_VAR_CURTHREAD:
> - return bpf_get_current_task();
> - case DIF_VAR_TIMESTAMP:
> - if (mst->tstamp == 0)
> - mst->tstamp = bpf_ktime_get_ns();
> + if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0]))
> + return error(dctx, DTRACEFLT_ILLOP, 0);
>
> - return mst->tstamp;
> - case DIF_VAR_EPID: {
> - return (((uint64_t)mst->prid) << 32) | mst->stid;
> - }
> - case DIF_VAR_ID:
> - return mst->prid;
> - case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2:
> - case DIF_VAR_ARG3: case DIF_VAR_ARG4: case DIF_VAR_ARG5:
> - case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8:
> - case DIF_VAR_ARG9:
> - return mst->argv[id - DIF_VAR_ARG0];
> - case DIF_VAR_ARGS:
> - if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0]))
> - return error(dctx, DTRACEFLT_ILLOP, 0);
> -
> - return mst->argv[idx];
> - case DIF_VAR_STACKDEPTH:
> - case DIF_VAR_USTACKDEPTH: {
> - uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ);
> - uint64_t flags;
> - char *buf = dctx->mem + (uint64_t)(&STACK_OFF);
> - uint64_t stacksize;
> -
> - if (id == DIF_VAR_USTACKDEPTH)
> - flags = BPF_F_USER_STACK;
> - else
> - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK;
> -
> - stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags);
> - if (stacksize < 0)
> - return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */);
> + return mst->argv[idx];
> +}
> +
> +noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx)
> +{
> + uint64_t buf[2] = { 0, };
>
> + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf),
> + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0)
> + return 0;
> +
> + return buf[1];
> +}
> +
> +noinline uint64_t dt_bvar_curcpu(const dt_dctx_t *dctx)
> +{
> + uint32_t key = 0;
> + void *val = bpf_map_lookup_elem(&cpuinfo, &key);
> +
> + if (val == NULL) {
> /*
> - * While linux/bpf.h does not describe the meaning of
> - * bpf_get_stack()'s return value outside of its sign,
> - * it is presumably the length of the copied stack.
> - *
> - * If stacksize==bufsiz, presumably the stack is larger than
> - * what we can retrieve. But it's also possible that the
> - * buffer was exactly large enough. So, leave it to the user
> - * to interpret the result.
> + * Typically, we would use 'return error(...);' but
> + * that confuses the verifier because it returns -1.
> + * So, instead, we explicitly return 0.
> */
> - return stacksize / sizeof(uint64_t);
> - }
> - case DIF_VAR_CALLER:
> - case DIF_VAR_UCALLER: {
> - uint64_t flags;
> - uint64_t buf[2] = { 0, };
> -
> - if (id == DIF_VAR_UCALLER)
> - flags = BPF_F_USER_STACK;
> - else
> - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK;
> -
> - if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0)
> - return 0;
> - return buf[1];
> + error(dctx, DTRACEFLT_ILLOP, 0);
> + return 0;
> }
> - case DIF_VAR_PROBEPROV:
> - case DIF_VAR_PROBEMOD:
> - case DIF_VAR_PROBEFUNC:
> - case DIF_VAR_PROBENAME: {
> - uint32_t key = mst->prid;
> -
> - if (key < ((uint64_t)&NPROBES)) {
> - dt_bpf_probe_t *pinfo;
> - uint64_t off;
> -
> - pinfo = bpf_map_lookup_elem(&probes, &key);
> - if (pinfo == NULL)
> - return (uint64_t)dctx->strtab;
> -
> - switch (id) {
> - case DIF_VAR_PROBEPROV:
> - off = pinfo->prv;
> - break;
> - case DIF_VAR_PROBEMOD:
> - off = pinfo->mod;
> - break;
> - case DIF_VAR_PROBEFUNC:
> - off = pinfo->fun;
> - break;
> - case DIF_VAR_PROBENAME:
> - off = pinfo->prb;
> - }
> - if (off > (uint64_t)&STBSZ)
> - return (uint64_t)dctx->strtab;
> -
> - return (uint64_t)(dctx->strtab + off);
> - } else {
> - char *s;
> -
> - s = bpf_map_lookup_elem(&usdt_names, &key);
> - if (s == NULL)
> - return (uint64_t)dctx->strtab;
> -
> - switch (id) {
> - case DIF_VAR_PROBENAME:
> - s += DTRACE_FUNCNAMELEN;
> - case DIF_VAR_PROBEFUNC:
> - s += DTRACE_MODNAMELEN;
> - case DIF_VAR_PROBEMOD:
> - s += DTRACE_PROVNAMELEN;
> - case DIF_VAR_PROBEPROV:
> - }
> -
> - return (uint64_t)s;
> - }
> - }
> - case DIF_VAR_PID: {
> - uint64_t val = bpf_get_current_pid_tgid();
>
> - return val >> 32;
> - }
> - case DIF_VAR_TID: {
> - uint64_t val = bpf_get_current_pid_tgid();
> + return (uint64_t)val;
> +}
>
> - return val & 0x00000000ffffffffUL;
> - }
> - case DIF_VAR_EXECNAME: {
> - uint64_t ptr;
> - extern uint64_t TASK_COMM;
> +noinline uint64_t dt_bvar_curthread(const dt_dctx_t *dctx)
> +{
> + return bpf_get_current_task();
> +}
>
> - /* &(current->comm) */
> - ptr = bpf_get_current_task();
> - if (ptr == 0)
> - return error(dctx, DTRACEFLT_BADADDR, ptr);
> +noinline uint64_t dt_bvar_epid(const dt_dctx_t *dctx)
> +{
> + dt_mstate_t *mst = dctx->mst;
>
> - return (uint64_t)ptr + (uint64_t)&TASK_COMM;
> - }
> - case DIF_VAR_WALLTIMESTAMP:
> - return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM);
> - case DIF_VAR_PPID: {
> - uint64_t ptr;
> - int32_t val = -1;
> - extern uint64_t TASK_REAL_PARENT;
> - extern uint64_t TASK_TGID;
> -
> - /* Chase pointers val = current->real_parent->tgid. */
> - ptr = bpf_get_current_task();
> - if (ptr == 0)
> - return error(dctx, DTRACEFLT_BADADDR, ptr);
> - if (bpf_probe_read((void *)&ptr, 8,
> - (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT)))
> - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT);
> - if (bpf_probe_read((void *)&val, 4,
> - (const void *)(ptr + (uint64_t)&TASK_TGID)))
> - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID);
> -
> - return (uint64_t)val;
> - }
> - case DIF_VAR_UID: {
> - uint64_t val = bpf_get_current_uid_gid();
> + return (((uint64_t)mst->prid) << 32) | mst->stid;
> +}
>
> - return val & 0x00000000ffffffffUL;
> - }
> - case DIF_VAR_GID: {
> - uint64_t val = bpf_get_current_uid_gid();
> +noinline uint64_t dt_bvar_errno(const dt_dctx_t *dctx)
> +{
> + dt_mstate_t *mst = dctx->mst;
>
> - return val >> 32;
> - }
> - case DIF_VAR_ERRNO:
> - return mst->syscall_errno;
> - case DIF_VAR_CURCPU: {
> - uint32_t key = 0;
> - void *val = bpf_map_lookup_elem(&cpuinfo, &key);
> -
> - if (val == NULL) {
> - /*
> - * Typically, we would use 'return error(...);' but
> - * that confuses the verifier because it returns -1.
> - * So, instead, we explicitly return 0.
> - */
> - error(dctx, DTRACEFLT_ILLOP, 0);
> - return 0;
> + return mst->syscall_errno;
> +}
> +
> +noinline uint64_t dt_bvar_execname(const dt_dctx_t *dctx)
> +{
> + uint64_t ptr;
> +
> + /* &(current->comm) */
> + ptr = bpf_get_current_task();
> + if (ptr == 0)
> + return error(dctx, DTRACEFLT_BADADDR, ptr);
> +
> + return (uint64_t)ptr + (uint64_t)&TASK_COMM;
> +}
> +
> +noinline uint64_t dt_bvar_gid(const dt_dctx_t *dctx)
> +{
> + return bpf_get_current_uid_gid() >> 32;
> +}
> +
> +noinline uint64_t dt_bvar_id(const dt_dctx_t *dctx)
> +{
> + dt_mstate_t *mst = dctx->mst;
> +
> + return mst->prid;
> +}
> +
> +noinline uint64_t dt_bvar_pid(const dt_dctx_t *dctx)
> +{
> + return bpf_get_current_pid_tgid() >> 32;
> +}
> +
> +noinline uint64_t dt_bvar_ppid(const dt_dctx_t *dctx)
> +{
> + uint64_t ptr;
> + int32_t val = -1;
> +
> + /* Chase pointers val = current->real_parent->tgid. */
> + ptr = bpf_get_current_task();
> + if (ptr == 0)
> + return error(dctx, DTRACEFLT_BADADDR, ptr);
> + if (bpf_probe_read((void *)&ptr, 8,
> + (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT)))
> + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT);
> + if (bpf_probe_read((void *)&val, 4,
> + (const void *)(ptr + (uint64_t)&TASK_TGID)))
> + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID);
> +
> + return (uint64_t)val;
> +}
> +
> +noinline uint64_t dt_bvar_probedesc(const dt_dctx_t *dctx, uint32_t idx)
> +{
> + dt_mstate_t *mst = dctx->mst;
> + uint32_t key = mst->prid;
> +
> + if (key < ((uint64_t)&NPROBES)) {
> + dt_bpf_probe_t *pinfo;
> + uint64_t off = 0;
> +
> + pinfo = bpf_map_lookup_elem(&probes, &key);
> + if (pinfo == NULL)
> + return (uint64_t)dctx->strtab;
> +
> + switch (idx) {
> + case DIF_VAR_PROBEPROV:
> + off = pinfo->prv;
> + break;
> + case DIF_VAR_PROBEMOD:
> + off = pinfo->mod;
> + break;
> + case DIF_VAR_PROBEFUNC:
> + off = pinfo->fun;
> + break;
> + case DIF_VAR_PROBENAME:
> + off = pinfo->prb;
> }
> + if (off > (uint64_t)&STBSZ)
> + return (uint64_t)dctx->strtab;
>
> - return (uint64_t)val;
> - }
> - default:
> - /* Not implemented yet. */
> - return error(dctx, DTRACEFLT_ILLOP, 0);
> + return (uint64_t)(dctx->strtab + off);
> + } else {
> + char *s;
> +
> + s = bpf_map_lookup_elem(&usdt_names, &key);
> + if (s == NULL)
> + return (uint64_t)dctx->strtab;
> +
> + switch (idx) {
> + case DIF_VAR_PROBEPROV:
> + s += DTRACE_FUNCNAMELEN;
> + case DIF_VAR_PROBEMOD:
> + s += DTRACE_MODNAMELEN;
> + case DIF_VAR_PROBEFUNC:
> + s += DTRACE_PROVNAMELEN;
> + case DIF_VAR_PROBENAME:
> + }
> +
> + return (uint64_t)s;
> }
> }
> +
> +noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx)
> +{
> + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ);
> + char *buf = dctx->mem + (uint64_t)(&STACK_OFF);
> + uint64_t retv;
> +
> + retv = bpf_get_stack(dctx->ctx, buf, bufsiz,
> + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK);
> + if (retv < 0)
> + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */);
> +
> + /*
> + * While linux/bpf.h does not describe the meaning of bpf_get_stack()'s
> + * return value outside of its sign, it is presumably the length of the
> + * copied stack.
> + *
> + * If retv==bufsiz, presumably the stack is larger than what we
> + * can retrieve. But it's also possible that the buffer was exactly
> + * large enough. So, leave it to the user to interpret the result.
> + */
> + return retv / sizeof(uint64_t);
> +}
> +
> +noinline uint64_t dt_bvar_tid(const dt_dctx_t *dctx)
> +{
> + return bpf_get_current_pid_tgid() & 0x00000000ffffffffUL;
> +}
> +
> +noinline uint64_t dt_bvar_timestamp(const dt_dctx_t *dctx)
> +{
> + dt_mstate_t *mst = dctx->mst;
> +
> + if (mst->tstamp == 0)
> + mst->tstamp = bpf_ktime_get_ns();
> +
> + return mst->tstamp;
> +}
> +
> +noinline uint64_t dt_bvar_ucaller(const dt_dctx_t *dctx)
> +{
> + uint64_t buf[2] = { 0, };
> +
> + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), BPF_F_USER_STACK) < 0)
> + return 0;
> +
> + return buf[1];
> +}
> +
> +noinline uint64_t dt_bvar_uid(const dt_dctx_t *dctx)
> +{
> + return bpf_get_current_uid_gid() & 0x00000000ffffffffUL;
> +}
> +
> +noinline uint64_t dt_bvar_ustackdepth(const dt_dctx_t *dctx)
> +{
> + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ);
> + char *buf = dctx->mem + (uint64_t)(&STACK_OFF);
> + uint64_t retv;
> +
> + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, BPF_F_USER_STACK);
> + if (retv < 0)
> + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */);
> +
> + /* See dt_bvar_stackdepth() above. */
> + return retv / sizeof(uint64_t);
> +}
> +
> +noinline uint64_t dt_bvar_walltimestamp(const dt_dctx_t *dctx)
> +{
> + return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM);
> +}
> diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h
> index c8c1d961..9f6e3b55 100644
> --- a/include/dtrace/dif_defines.h
> +++ b/include/dtrace/dif_defines.h
> @@ -162,6 +162,7 @@
> #define DIF_VAR_GID 0x011f
> #define DIF_VAR_ERRNO 0x0120
> #define DIF_VAR_CURCPU 0x0121
> +#define DIF_VAR_EXECARGS 0x0122
>
> #define DIF_SUBR_RAND 0
> #define DIF_SUBR_MUTEX_OWNED 1
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index e7e3a132..6e74b4b0 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -3197,6 +3197,7 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> {
> dt_ident_t *idp = dt_ident_resolve(dnp->dn_ident);
> dt_ident_t *fnp;
> + uint32_t idx = UINT32_MAX;
>
> idp->di_flags |= DT_IDFLG_DIFR;
>
> @@ -3298,15 +3299,38 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> return;
> }
>
> - /* built-in variables */
> + /* built-in variables (note: args[] is handled in dt_cg_array_op) */
> + /* Special case for arg0 through arg9; encode as args[n] */
> + if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) {
> + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args");
> + idx = idp->di_id - DIF_VAR_ARG0;
> + } else if (idp->di_id == DIF_VAR_PROBEPROV ||
> + idp->di_id == DIF_VAR_PROBEMOD ||
> + idp->di_id == DIF_VAR_PROBEFUNC ||
> + idp->di_id == DIF_VAR_PROBENAME) {
> + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc");
> + idx = idp->di_id;
> + } else {
> + char *fn;
> +
> + if (asprintf(&fn, "dt_bvar_%s", idp->di_name) == -1)
> + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
> +
> + fnp = dt_dlib_get_func(yypcb->pcb_hdl, fn);
> + free(fn);
> + }
> +
> + /* No implementing function found - report ILLOP. */
> + if (fnp == NULL)
> + xyerror(D_IDENT_UNDEF,
> + "built-in variable '%s' not implemented", idp->di_name);
> +
> if (dt_regset_xalloc_args(drp) == -1)
> longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
>
> dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1);
> - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id));
> - emit(dlp, BPF_MOV_IMM(BPF_REG_3, 0));
> - fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar");
> - assert(fnp != NULL);
> + if (idx != UINT32_MAX)
> + emit(dlp, BPF_MOV_IMM(BPF_REG_2, idx));
> dt_regset_xalloc(drp, BPF_REG_0);
> emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp);
> dt_regset_free_args(drp);
> @@ -5065,7 +5089,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> dt_probe_t *prp = yypcb->pcb_probe;
> uintmax_t saved = dnp->dn_args->dn_value;
> dt_ident_t *idp = dnp->dn_ident;
> - dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar");
> + dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args");
> size_t size;
> int n;
> int ustr = 0;
> @@ -5135,8 +5159,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> if (dt_regset_xalloc_args(drp) == -1)
> longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1);
> - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id));
> - emit(dlp, BPF_MOV_REG(BPF_REG_3, dnp->dn_reg));
> + emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_reg));
> dt_regset_xalloc(drp, BPF_REG_0);
> emite(dlp, BPF_CALL_FUNC(fidp->di_id), fidp);
> dt_regset_free_args(drp);
> diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c
> index 9f319d70..d983c099 100644
> --- a/libdtrace/dt_dis.c
> +++ b/libdtrace/dt_dis.c
> @@ -364,16 +364,57 @@ static char *
> dt_dis_bpf_args(const dtrace_difo_t *dp, const char *fn,
> const struct bpf_insn *in, char *buf, size_t len, uint_t addr)
> {
> - if (strcmp(fn, "dt_get_bvar") == 0) {
> + if (strcmp(fn, "dt_bvar_args") == 0) {
> /*
> - * We know that the previous two instructions exist and move
> - * the variable id to a register in the first instruction of
> - * that sequence (because we wrote the code generator to emit
> - * the instructions in this exact order.)
> + * We need to support two cases:
> + * - access to argN:
> + * lddw %r1, dctx
> + * mov %r2, N
> + * call dt_bvar_args
> + * - access to args[N]:
> + * mov %rX, N
> + * lddw %r1, dctx
> + * mov %r2, %rX
> + * call dt_bvar_args
> */
> - in -= 2;
> - snprintf(buf, len, "%s",
> - dt_dis_varname_id(dp, in->imm, DIFV_SCOPE_GLOBAL, addr));
> + in--;
> + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2) {
> + if (BPF_SRC(in->code) == BPF_K) {
> + snprintf(buf, len, "arg%d", in->imm);
> + return buf;
> + }
> +
> + in -= 2;
> + if (BPF_OP(in->code) == BPF_MOV &&
> + BPF_SRC(in->code) == BPF_K &&
> + in->dst_reg == in[2].src_reg) {
> + snprintf(buf, len, "args[%d]", in->imm);
> + return buf;
> + }
> + }
> +
> + snprintf(buf, len, "args[?]");
> + return buf;
> + } else if (strcmp(fn, "dt_bvar_probedesc") == 0) {
> + /*
> + * Access to probe(prov|mod|func|name);
> + * lddw %r1, dctx
> + * mov %r2, N
> + * call dt_bvar_probedesc
> + */
> + in--;
> + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2 &&
> + BPF_SRC(in->code) == BPF_K) {
> + snprintf(buf, len, "%s",
> + dt_dis_varname_id(dp, in->imm,
> + DIFV_SCOPE_GLOBAL, addr));
> + return buf;
> + }
> +
> + return NULL;
> + } else if (strncmp(fn, "dt_bvar_", 8) == 0) {
> + /* The variable name is in the function name.*/
> + snprintf(buf, len, "%s", fn + 8);
> return buf;
> } else if (strcmp(fn, "dt_get_agg") == 0) {
> /*
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index a0205887..51c056b2 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = {
> &dt_idops_type, "uint64_t" },
> { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0,
> &dt_idops_type, "int" },
> +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS,
> + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" },
> { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME,
> DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
> { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0,
> diff --git a/test/demo/builtin/ipl.d b/test/demo/builtin/ipl.d
> index ca7f3bb7..f613bb70 100644
> --- a/test/demo/builtin/ipl.d
> +++ b/test/demo/builtin/ipl.d
> @@ -1,3 +1,5 @@
> +/* @@xfail: dtv2: need ipl support */
> +
> BEGIN {
> trace(ipl);
> exit(0);
> diff --git a/test/demo/builtin/vtimestamp.d b/test/demo/builtin/vtimestamp.d
> index 9f01bbf0..fcb708d0 100644
> --- a/test/demo/builtin/vtimestamp.d
> +++ b/test/demo/builtin/vtimestamp.d
> @@ -1,3 +1,5 @@
> +/* @@xfail: dtv2: need vtimestamp support */
> +
> BEGIN {
> trace(vtimestamp);
> exit(0);
> diff --git a/test/demo/io/iocpu.d b/test/demo/io/iocpu.d
> index c7b847e7..1230d6f6 100644
> --- a/test/demo/io/iocpu.d
> +++ b/test/demo/io/iocpu.d
> @@ -5,6 +5,8 @@
> * http://oss.oracle.com/licenses/upl.
> */
>
> +/* @@xfail: dtv2: need vtimestamp support */
> +
> #pragma D option quiet
>
> sched:::on-cpu
> diff --git a/test/unittest/buffering/tst.cputime.sh b/test/unittest/buffering/tst.cputime.sh
> index 6a420e8d..c0e248a6 100755
> --- a/test/unittest/buffering/tst.cputime.sh
> +++ b/test/unittest/buffering/tst.cputime.sh
> @@ -5,6 +5,7 @@
> # Licensed under the Universal Permissive License v 1.0 as shown at
> # http://oss.oracle.com/licenses/upl.
> #
> +# @@xfail: dtv2: need vtimestamp support
> # @@timeout: 12
>
> script()
> diff --git a/test/unittest/disasm/tst.ann-bvar.r b/test/unittest/disasm/tst.ann-bvar.r
> index b514dd99..a55fb6de 100644
> --- a/test/unittest/disasm/tst.ann-bvar.r
> +++ b/test/unittest/disasm/tst.ann-bvar.r
> @@ -1,34 +1,35 @@
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg0
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg1
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg2
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg3
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg4
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg5
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg6
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg7
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg8
> -85 0 1 0000 ffffffff call dt_get_bvar ! arg9
> -85 0 1 0000 ffffffff call dt_get_bvar ! args
> -85 0 1 0000 ffffffff call dt_get_bvar ! caller
> -85 0 1 0000 ffffffff call dt_get_bvar ! curcpu
> -85 0 1 0000 ffffffff call dt_get_bvar ! curthread
> -85 0 1 0000 ffffffff call dt_get_bvar ! epid
> -85 0 1 0000 ffffffff call dt_get_bvar ! errno
> -85 0 1 0000 ffffffff call dt_get_bvar ! execname
> -85 0 1 0000 ffffffff call dt_get_bvar ! gid
> -85 0 1 0000 ffffffff call dt_get_bvar ! id
> -85 0 1 0000 ffffffff call dt_get_bvar ! ipl
> -85 0 1 0000 ffffffff call dt_get_bvar ! pid
> -85 0 1 0000 ffffffff call dt_get_bvar ! ppid
> -85 0 1 0000 ffffffff call dt_get_bvar ! probefunc
> -85 0 1 0000 ffffffff call dt_get_bvar ! probemod
> -85 0 1 0000 ffffffff call dt_get_bvar ! probename
> -85 0 1 0000 ffffffff call dt_get_bvar ! probeprov
> -85 0 1 0000 ffffffff call dt_get_bvar ! stackdepth
> -85 0 1 0000 ffffffff call dt_get_bvar ! tid
> -85 0 1 0000 ffffffff call dt_get_bvar ! timestamp
> -85 0 1 0000 ffffffff call dt_get_bvar ! ucaller
> -85 0 1 0000 ffffffff call dt_get_bvar ! uid
> -85 0 1 0000 ffffffff call dt_get_bvar ! ustackdepth
> -85 0 1 0000 ffffffff call dt_get_bvar ! vtimestamp
> -85 0 1 0000 ffffffff call dt_get_bvar ! walltimestamp
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg0
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg1
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg2
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg3
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg4
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg5
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg6
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg7
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg8
> +85 0 1 0000 ffffffff call dt_bvar_args ! arg9
> +85 0 1 0000 ffffffff call dt_bvar_args ! args[0]
> +85 0 1 0000 ffffffff call dt_bvar_args ! args[1]
> +85 0 1 0000 ffffffff call dt_bvar_args ! args[2]
> +85 0 1 0000 ffffffff call dt_bvar_args ! args[3]
> +85 0 1 0000 ffffffff call dt_bvar_caller ! caller
> +85 0 1 0000 ffffffff call dt_bvar_curcpu ! curcpu
> +85 0 1 0000 ffffffff call dt_bvar_curthread ! curthread
> +85 0 1 0000 ffffffff call dt_bvar_epid ! epid
> +85 0 1 0000 ffffffff call dt_bvar_errno ! errno
> +85 0 1 0000 ffffffff call dt_bvar_execname ! execname
> +85 0 1 0000 ffffffff call dt_bvar_gid ! gid
> +85 0 1 0000 ffffffff call dt_bvar_id ! id
> +85 0 1 0000 ffffffff call dt_bvar_pid ! pid
> +85 0 1 0000 ffffffff call dt_bvar_ppid ! ppid
> +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probefunc
> +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probemod
> +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probename
> +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probeprov
> +85 0 1 0000 ffffffff call dt_bvar_stackdepth ! stackdepth
> +85 0 1 0000 ffffffff call dt_bvar_tid ! tid
> +85 0 1 0000 ffffffff call dt_bvar_timestamp ! timestamp
> +85 0 1 0000 ffffffff call dt_bvar_ucaller ! ucaller
> +85 0 1 0000 ffffffff call dt_bvar_uid ! uid
> +85 0 1 0000 ffffffff call dt_bvar_ustackdepth ! ustackdepth
> +85 0 1 0000 ffffffff call dt_bvar_walltimestamp ! walltimestamp
> diff --git a/test/unittest/disasm/tst.ann-bvar.sh b/test/unittest/disasm/tst.ann-bvar.sh
> index 6dc43424..61e838d1 100755
> --- a/test/unittest/disasm/tst.ann-bvar.sh
> +++ b/test/unittest/disasm/tst.ann-bvar.sh
> @@ -22,6 +22,9 @@ sdt:task::task_rename
> trace(arg8);
> trace(arg9);
> trace(args[0]);
> + trace(args[1]);
> + trace(args[2]);
> + trace(args[3]);
> trace(caller);
> trace(curcpu);
> trace(curthread);
> @@ -30,7 +33,7 @@ sdt:task::task_rename
> trace(execname);
> trace(gid);
> trace(id);
> - trace(ipl);
> +/* trace(ipl); */
> trace(pid);
> trace(ppid);
> trace(probefunc);
> @@ -43,10 +46,10 @@ sdt:task::task_rename
> trace(ucaller);
> trace(uid);
> trace(ustackdepth);
> - trace(vtimestamp);
> +/* trace(vtimestamp); */
> trace(walltimestamp);
> exit(0);
> }
> -' 2>&1 | gawk '/ call dt_get_bvar/ { sub(/^[^:]+: /, ""); print; }'
> +' 2>&1 | gawk '/ call dt_bvar_/ { sub(/^[^:]+: /, ""); print; }'
>
> exit $?
> diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r
> index 53e5f618..04fa3a8d 100644
> --- a/test/unittest/disasm/tst.vartab-bvar.r
> +++ b/test/unittest/disasm/tst.vartab-bvar.r
> @@ -2,8 +2,6 @@ NAME OFFSET KND SCP FLAG TYPE
> args arr glb r any (unknown) by ref (size 0)
> curthread scl glb r D type (pointer) (size 8)
> timestamp scl glb r D type (integer) (size 8)
> -vtimestamp scl glb r D type (integer) (size 8)
> -ipl scl glb r D type (integer) (size 4)
> epid scl glb r D type (integer) (size 8)
> id scl glb r D type (integer) (size 4)
> arg0 scl glb r D type (integer) (size 8)
> diff --git a/test/unittest/disasm/tst.vartab-bvar.sh b/test/unittest/disasm/tst.vartab-bvar.sh
> index 098c1f45..ce489a24 100755
> --- a/test/unittest/disasm/tst.vartab-bvar.sh
> +++ b/test/unittest/disasm/tst.vartab-bvar.sh
> @@ -30,6 +30,9 @@ sdt:task::task_rename
> trace(arg8);
> trace(arg9);
> trace(args[0]);
> + trace(args[1]);
> + trace(args[2]);
> + trace(args[3]);
> trace(caller);
> trace(curcpu);
> trace(curthread);
> @@ -38,7 +41,7 @@ sdt:task::task_rename
> trace(execname);
> trace(gid);
> trace(id);
> - trace(ipl);
> +/* trace(ipl); */
> trace(pid);
> trace(ppid);
> trace(probefunc);
> @@ -52,7 +55,7 @@ sdt:task::task_rename
> trace(uid);
> /* trace(uregs[0]); */ /* test this separately until uregs[0] works on all kernels */
> trace(ustackdepth);
> - trace(vtimestamp);
> +/* trace(vtimestamp); */
> trace(walltimestamp);
> exit(0);
> }
More information about the DTrace-devel
mailing list