[DTrace-devel] [PATCH 8/8] Add support for lltostr() subroutine
Kris Van Hees
kris.van.hees at oracle.com
Thu Oct 14 21:07:58 PDT 2021
On Wed, Sep 29, 2021 at 11:13:41AM -0400, eugene.loh at oracle.com wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
>
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
... and added to my staging dev branch. I did add the .type and .size
markers to the strchr.S file.
> ---
> bpf/Build | 1 +
> bpf/lltostr.S | 167 ++++++++++++++++++++++++
> libdtrace/dt_cg.c | 37 +++++-
> libdtrace/dt_dlibs.c | 1 +
> test/unittest/dif/lltostr.d | 1 -
> test/unittest/funcs/tst.lltostr-short.d | 39 ++++++
> test/unittest/funcs/tst.lltostr-short.r | 26 ++++
> test/unittest/funcs/tst.lltostr.d | 7 +-
> test/unittest/funcs/tst.lltostr.r | 4 +
> 9 files changed, 279 insertions(+), 4 deletions(-)
> create mode 100644 bpf/lltostr.S
> create mode 100644 test/unittest/funcs/tst.lltostr-short.d
> create mode 100644 test/unittest/funcs/tst.lltostr-short.r
>
> diff --git a/bpf/Build b/bpf/Build
> index 0b39764f..606c9b8f 100644
> --- a/bpf/Build
> +++ b/bpf/Build
> @@ -26,6 +26,7 @@ bpf_dlib_SOURCES = \
> get_bvar.c \
> get_tvar.c set_tvar.c \
> index.S \
> + lltostr.S \
> probe_error.c \
> rindex.S \
> strchr.S \
> diff --git a/bpf/lltostr.S b/bpf/lltostr.S
> new file mode 100644
> index 00000000..6b600264
> --- /dev/null
> +++ b/bpf/lltostr.S
> @@ -0,0 +1,167 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
> + */
> +
> +#define DT_STRLEN_BYTES 2
> +#define BPF_FUNC_probe_read 4
> +#define MAXCHARS 19
> +
> + .text
> +/*
> + * int dt_lltostr(char *STR, uint64_t VAL)
> + * {
> + * // start writing at the end (IDX==1 is the last char)
> + * IDX = 1
> + *
> + * // compute sign bit
> + * SGN = VAL >> 63
> + *
> + * // replace VAL with its absolute value
> + * VAL *= (1 - 2 * SGN)
> + *
> + * // prewrite a '0' in case VAL==0
> + * [%fp + -1] = '0'
> + *
> + * Lloop:
> + * if (VAL == 0) goto Ldone
> + *
> + * r5 = VAL / 10
> + * r3 = itoa(VAL % 10)
> + *
> + * [%fp + -IDX] = r3
> + *
> + * VAL = r5
> + * IDX++
> + *
> + * jump Lloop
> + *
> + * Ldone:
> + *
> + * // back IDX up one char (unless no chars were written in loop)
> + * if (IDX > 1) IDX--
> + *
> + * // if (SGN), account for sign char
> + * IDX += SGN
> + *
> + * LEN = min(IDX, STRSZ)
> + *
> + * dt_strlen_store(LEN, STR)
> + * STR += DT_STRLEN_BYTES
> + *
> + * // copy to output string
> + * bpf_probe_read(STR, LEN, %fp + -IDX)
> + *
> + * // if (SGN), we included a garbage sign char; fix it
> + * if (SGN) STR[0] = '-'
> + *
> + * // add terminating NULL byte
> + * if (LEN < STRSZ) STR[LEN] = '\0'
> + * }
> + */
> + .align 4
> + .global dt_lltostr
> +dt_lltostr:
> +
> +/*
> + * assign certain variables to registers:
> + * - STR is the output string
> + * - VAL is the value we are trying to convert
> + * - IDX is the index of the output char we are writing
> + * (1-based, starting from the end)
> + * - SGN is the sign bit of the input value (1: neg; 0: otherwise)
> + * registers r0-r5 are used as temporary variables
> + * (including of course for function calls)
> + */
> +#define STR %r6
> +#define VAL %r7
> +#define IDX %r8
> +#define SGN %r9
> +
> + mov STR, %r1
> + mov VAL, %r2
> +
> + mov IDX, 1 /* IDX = 1 */
> +
> + mov SGN, VAL
> + rsh SGN, 63 /* SGN = VAL >> 63 */
> +
> + mov %r5, 1
> + sub %r5, SGN
> + sub %r5, SGN
> + mul VAL, %r5 /* VAL *= (1 - 2 * SGN) */
> +
> + mov %r5, '0'
> + stxb [%fp+-1], %r5 /* prewrite a '0' in case VAL==0 */
> +
> +.Lloop:
> + jeq VAL, 0, .Ldone /* if (VAL == 0) goto Ldone */
> + jgt IDX, MAXCHARS, .Ldone /* help the BPF verifier */
> +
> + mov %r5, VAL
> + div %r5, 10 /* r5 = VAL / 10 */
> +
> + mov %r4, 10
> + mul %r4, %r5
> + mov %r3, VAL
> + sub %r3, %r4
> + add %r3, '0' /* r3 = itoa(VAL % 10) */
> +
> + mov %r2, %fp
> + mov %r1, IDX
> + mul %r1, -1
> + add %r2, %r1
> + stxb [%r2+0], %r3 /* [%fp + -IDX] = r3 */
> +
> + mov VAL, %r5 /* VAL = r5 */
> + add IDX, 1 /* IDX++ */
> +
> + ja .Lloop
> +
> +.Ldone:
> +
> +/* at this point VAL==0, so use its register for string length */
> +#undef VAL
> +#define LEN %r7
> +
> + jle IDX, 1, 1 /* if (IDX > 1) IDX-- */
> + sub IDX, 1
> +
> + jge IDX, 1, 1 /* help the BPF verifier out */
> + mov IDX, 1
> + jle IDX, MAXCHARS, 1
> + mov IDX, MAXCHARS
> + and SGN, 1
> +
> + add IDX, SGN /* IDX += SGN */
> +
> + lddw %r1, STRSZ
> + mov LEN, IDX
> + jle LEN, %r1, 1
> + mov LEN, %r1 /* LEN = min(IDX, STRSZ) */
> +
> + mov %r1, LEN
> + mov %r2, STR
> + call dt_strlen_store /* dt_strlen_store(LEN, STR) */
> +
> + add STR, DT_STRLEN_BYTES /* STR += DT_STRLEN_BYTES */
> +
> + mov %r1, STR
> + mov %r2, LEN
> + mov %r3, %fp
> + mov %r4, 0
> + sub %r4, IDX
> + add %r3, %r4
> + call BPF_FUNC_probe_read /* bpf_probe_read(STR, LEN, %fp + -IDX) */
> +
> + mov %r5, '-'
> + jeq SGN, 0, 1
> + stxb [STR+0], %r5 /* if (SGN) STR[0] = '-' */
> +
> + lddw %r5, STRSZ
> + jlt LEN, %r5, 1
> + exit
> + add STR, LEN
> + mov %r5, 0
> + stxb [STR+0], %r5 /* if (LEN < STRSZ) STR[LEN] = '\0' */
> + exit
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 6aac64ae..80b8566e 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -3231,6 +3231,41 @@ dt_cg_subr_index(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> TRACE_REGSET(" subr-index:End ");
> }
>
> +static void
> +dt_cg_subr_lltostr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> +{
> + dt_ident_t *idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_lltostr");
> + dt_node_t *val = dnp->dn_args;
> +
> + assert(idp != NULL);
> +
> + TRACE_REGSET(" subr-lltostr:Begin");
> + dt_cg_node(val, dlp, drp);
> +
> + if (dt_regset_xalloc_args(drp) == -1)
> + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> +
> + dnp->dn_reg = dt_regset_alloc(drp);
> + if (dnp->dn_reg == -1)
> + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> + dt_cg_tstring_alloc(yypcb, dnp);
> +
> + emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, BPF_REG_FP, DT_STK_DCTX));
> + emit(dlp, BPF_LOAD(BPF_DW, dnp->dn_reg, dnp->dn_reg, DCTX_MEM));
> + emit(dlp, BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, dnp->dn_tstring->dn_value));
> + emit(dlp, BPF_MOV_REG(BPF_REG_1, dnp->dn_reg));
> +
> + emit(dlp, BPF_MOV_REG(BPF_REG_2, val->dn_reg));
> + dt_regset_free(drp, val->dn_reg);
> +
> + dt_regset_xalloc(drp, BPF_REG_0);
> + emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
> + dt_regset_free_args(drp);
> + dt_regset_free(drp, BPF_REG_0);
> +
> + TRACE_REGSET(" subr-lltostr:End ");
> +}
> +
> static void
> dt_cg_subr_rindex(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> {
> @@ -3689,7 +3724,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
> [DIF_SUBR_GETMINOR] = NULL,
> [DIF_SUBR_DDI_PATHNAME] = NULL,
> [DIF_SUBR_STRJOIN] = dt_cg_subr_strjoin,
> - [DIF_SUBR_LLTOSTR] = NULL,
> + [DIF_SUBR_LLTOSTR] = &dt_cg_subr_lltostr,
> [DIF_SUBR_BASENAME] = NULL,
> [DIF_SUBR_DIRNAME] = NULL,
> [DIF_SUBR_CLEANPATH] = NULL,
> diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
> index 0e3ebb85..7d10898f 100644
> --- a/libdtrace/dt_dlibs.c
> +++ b/libdtrace/dt_dlibs.c
> @@ -60,6 +60,7 @@ static const dt_ident_t dt_bpf_symbols[] = {
> DT_BPF_SYMBOL(dt_get_tvar, DT_IDENT_SYMBOL),
> DT_BPF_SYMBOL(dt_set_tvar, DT_IDENT_SYMBOL),
> DT_BPF_SYMBOL(dt_index, DT_IDENT_SYMBOL),
> + DT_BPF_SYMBOL(dt_lltostr, DT_IDENT_SYMBOL),
> DT_BPF_SYMBOL(dt_rindex, DT_IDENT_SYMBOL),
> DT_BPF_SYMBOL(dt_strchr, DT_IDENT_SYMBOL),
> DT_BPF_SYMBOL(dt_strcmp, DT_IDENT_SYMBOL),
> diff --git a/test/unittest/dif/lltostr.d b/test/unittest/dif/lltostr.d
> index fe7b3b9e..6aa19d94 100644
> --- a/test/unittest/dif/lltostr.d
> +++ b/test/unittest/dif/lltostr.d
> @@ -1,4 +1,3 @@
> -/* @@xfail: dtv2 */
> BEGIN
> {
> exit(lltostr(12345678) == "12345678" ? 0 : 1);
> diff --git a/test/unittest/funcs/tst.lltostr-short.d b/test/unittest/funcs/tst.lltostr-short.d
> new file mode 100644
> index 00000000..96904566
> --- /dev/null
> +++ b/test/unittest/funcs/tst.lltostr-short.d
> @@ -0,0 +1,39 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2021, 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.
> + */
> +
> +#pragma D option quiet
> +#pragma D option strsize=7
> +
> +BEGIN
> +{
> + printf("%s\n", lltostr(0));
> + printf("%s\n", lltostr(1));
> + printf("%s\n", lltostr(12));
> + printf("%s\n", lltostr(123));
> + printf("%s\n", lltostr(1234));
> + printf("%s\n", lltostr(12345));
> + printf("%s\n", lltostr(123456));
> + printf("%s\n", lltostr(1234567));
> + printf("%s\n", lltostr(12345678));
> + printf("%s\n", lltostr(123456789));
> + printf("%s\n", lltostr(1234567890));
> + printf("%s\n", lltostr(-1));
> + printf("%s\n", lltostr(-12));
> + printf("%s\n", lltostr(-123));
> + printf("%s\n", lltostr(-1234));
> + printf("%s\n", lltostr(-12345));
> + printf("%s\n", lltostr(-123456));
> + printf("%s\n", lltostr(-1234567));
> + printf("%s\n", lltostr(-12345678));
> + printf("%s\n", lltostr(-123456789));
> + printf("%s\n", lltostr(-1234567890));
> + printf("%s\n", lltostr(9999999));
> + printf("%s\n", lltostr(10000000));
> + printf("%s\n", lltostr(-999999));
> + printf("%s\n", lltostr(-1000000));
> + exit(0);
> +}
> diff --git a/test/unittest/funcs/tst.lltostr-short.r b/test/unittest/funcs/tst.lltostr-short.r
> new file mode 100644
> index 00000000..a70a84f5
> --- /dev/null
> +++ b/test/unittest/funcs/tst.lltostr-short.r
> @@ -0,0 +1,26 @@
> +0
> +1
> +12
> +123
> +1234
> +12345
> +123456
> +1234567
> +1234567
> +1234567
> +1234567
> +-1
> +-12
> +-123
> +-1234
> +-12345
> +-123456
> +-123456
> +-123456
> +-123456
> +-123456
> +9999999
> +1000000
> +-999999
> +-100000
> +
> diff --git a/test/unittest/funcs/tst.lltostr.d b/test/unittest/funcs/tst.lltostr.d
> index 2415906b..0563778b 100644
> --- a/test/unittest/funcs/tst.lltostr.d
> +++ b/test/unittest/funcs/tst.lltostr.d
> @@ -1,10 +1,9 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2006, 2021, 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.
> */
> -/* @@xfail: dtv2 */
>
> #pragma D option quiet
>
> @@ -17,5 +16,9 @@ BEGIN
> printf("%s\n", lltostr(-123456789));
> printf("%s\n", lltostr(1LL << 62));
> printf("%s\n", lltostr(-(1LL << 62)));
> + printf("%s\n", lltostr(0x7ffffffffffffffe));
> + printf("%s\n", lltostr(0x7fffffffffffffff));
> + printf("%s\n", lltostr(0x8000000000000000));
> + printf("%s\n", lltostr(0x8000000000000001));
> exit(0);
> }
> diff --git a/test/unittest/funcs/tst.lltostr.r b/test/unittest/funcs/tst.lltostr.r
> index e007c648..05480536 100644
> --- a/test/unittest/funcs/tst.lltostr.r
> +++ b/test/unittest/funcs/tst.lltostr.r
> @@ -5,4 +5,8 @@
> -123456789
> 4611686018427387904
> -4611686018427387904
> +9223372036854775806
> +9223372036854775807
> +-9223372036854775808
> +-9223372036854775807
>
> --
> 2.18.4
>
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
More information about the DTrace-devel
mailing list