[DTrace-devel] [PATCH 1/2 v3] Add support for the basename() action

Eugene Loh eugene.loh at oracle.com
Wed Dec 1 19:25:40 UTC 2021


On 12/1/21 2:13 PM, Kris Van Hees wrote:

> Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
>
> ... with the little changes below.  I can apply them if you like as I do the
> integration on 'dev' since it is so minor.
Sounds great, thanks.
> On Fri, Nov 19, 2021 at 02:56:20PM -0500, eugene.loh--- via DTrace-devel wrote:
>> From: Eugene Loh <eugene.loh at oracle.com>
>>
>> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
>> ---
>>   bpf/Build                           |   1 +
>>   bpf/basename.S                      | 125 ++++++++++++++++++++++++++++
>>   libdtrace/dt_cg.c                   |  56 ++++++++++++-
>>   libdtrace/dt_dlibs.c                |   1 +
>>   test/unittest/dif/basename.d        |   1 -
>>   test/unittest/funcs/tst.basename0.d |  38 +++++++++
>>   test/unittest/funcs/tst.basename0.r |  21 +++++
>>   7 files changed, 241 insertions(+), 2 deletions(-)
>>   create mode 100644 bpf/basename.S
>>   create mode 100644 test/unittest/funcs/tst.basename0.d
>>   create mode 100644 test/unittest/funcs/tst.basename0.r
>>
>> diff --git a/bpf/Build b/bpf/Build
>> index d8279411..e66e8dc9 100644
>> --- a/bpf/Build
>> +++ b/bpf/Build
>> @@ -23,6 +23,7 @@ bpf_dlib_DIR := $(current-dir)
>>   bpf_dlib_SRCDEPS = $(objdir)/include/.dir.stamp
>>   bpf_dlib_SOURCES = \
>>   	agg_lqbin.c agg_qbin.c \
>> +	basename.S \
>>   	get_bvar.c \
>>   	get_tvar.c set_tvar.c \
>>   	index.S \
>> diff --git a/bpf/basename.S b/bpf/basename.S
>> new file mode 100644
>> index 00000000..3ddb3bbf
>> --- /dev/null
>> +++ b/bpf/basename.S
>> @@ -0,0 +1,125 @@
>> +// 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_str	45
>> +
>> +/*
>> + * void dt_basename(char *src, char *dst);
>> + */
>> +	.text
>> +	.align	4
>> +	.global	dt_basename
>> +	.type	dt_basename, @function
>> +dt_basename :
>> +#define SRC %r6
>> +#define DST %r7
>> +#define BGN %r8
>> +#define LEN %r9
>> +
>> +	/* store copies of input arguments */
>> +	mov	SRC, %r1
>> +	mov	DST, %r2
>> +
>> +	/* ignore the string-length prefix */
>> +	add	SRC, DT_STRLEN_BYTES
>> +
>> +	/* r0 = bpf_probe_read_str(dst, STRSZ + 1, src) */
>> +	mov	%r1, DST
>> +	lddw	%r2, STRSZ
>> +	add	%r2, 1
>> +	mov	%r3, SRC
>> +	call	BPF_FUNC_probe_read_str
>> +
>> +	/* if (r0 s<= 1) goto Ldot */
>> +	jsle	%r0, 1, .Ldot
>> +
>> +	/* len = r0 - 1 */
>> +	mov	LEN, %r0
>> +	sub	LEN, 1
>> +
>> +	/*
>> +	 * Loop over len, backing it up to find a non-'/' char.
>> +	 */
>> +.Lend:
>> +	/* len-- */
>> +	sub	LEN, 1
>> +	/* if (len s< 0) goto Lslash */
>> +	jslt	LEN, 0, .Lslash
>> +	/* if (src[len] == '/') goto Lend */
>> +	mov	%r1, SRC
>> +	add	%r1, LEN
>> +	ldxb	%r1, [%r1+0]
>> +	and	%r1, 0xff
>> +	jeq	%r1, '/', .Lend
>> +
>> +	/*
>> +	 * Loop over bgn, backing it up to find a '/' char.
>> +	 */
>> +	/* bgn = len */
>> +	mov	BGN, LEN
>> +.Lbgn:
>> +	/* bgn-- */
>> +	sub	BGN, 1
>> +	/* if (bgn s< 0) goto Lcopy */
>> +	jslt	BGN, 0, .Lcopy
>> +	/* if (src[bgn] != '/') goto Lbgn */
>> +	mov	%r1, SRC
>> +	add	%r1, BGN
>> +	ldxb	%r1, [%r1+0]
>> +	and	%r1, 0xff
>> +	jne	%r1, '/', .Lbgn
>> +
>> +.Lcopy:
>> +	/*
>> +	 * The output string is a copy of the designated substring.
>> +	 */
>> +	/* len -= bgn (and help the BPF verifier) */
>> +	sub	LEN, BGN
>> +	jsge	LEN, 0, 1
>> +	mov	LEN, 0
>> +	/* bgn++ */
>> +	add	BGN, 1
>> +	/* bpf_probe_read_str(dst + DT_STRLEN_BYTES, len + 1, &src[bgn]) */
>> +	mov	%r1, DST
>> +	add	%r1, DT_STRLEN_BYTES
>> +	mov	%r2, LEN
>> +	add	%r2, 1
>> +	mov	%r3, SRC
>> +	add	%r3, BGN
>> +	call	BPF_FUNC_probe_read_str
>> +
>> +.Lcoda:
>> +	/* dt_strlen_store(len, dst) */
>> +	mov	%r1, LEN
>> +	mov	%r2, DST
>> +	call	dt_strlen_store
>> +
>> +	/* return */
>> +	exit
>> +
>> +.Ldot:
>> +	/*
>> +	 * The output string is simply ".\0".
>> +	 */
>> +	mov	LEN, 1
>> +	stb	[DST+DT_STRLEN_BYTES], '.'
>> +	stb	[DST+(DT_STRLEN_BYTES+1)], '\0'
>> +	ja	.Lcoda
>> +
>> +.Lslash:
>> +	/*
>> +	 * The output string is simply "/\0".
>> +	 */
>> +	mov	LEN, 1
>> +	stb	[DST+DT_STRLEN_BYTES], '/'
>> +	stb	[DST+(DT_STRLEN_BYTES+1)], '\0'
>> +	ja	.Lcoda
>> +#undef SRC
>> +#undef DST
>> +#undef BGN
>> +#undef LEN
>> +	.size	dt_basename, .-dt_basename
>> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
>> index 537e6706..ff28b748 100644
>> --- a/libdtrace/dt_cg.c
>> +++ b/libdtrace/dt_cg.c
>> @@ -3294,6 +3294,60 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>>   	emit(dlp, BPF_ALU64_REG((dnp->dn_flags & DT_NF_SIGNED) ? BPF_ARSH : BPF_RSH, dnp->dn_reg, n));
>>   }
>>   
>> +/*
>> + * This function is a helper function for subroutines that take a path
>> + * argument and return the tstring resulting from applying a given BPF
>> + * function (passed by name) on it.
>> + */
>> +static void
>> +dt_cg_subr_path_helper(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp,
>> +		       const char *fname)
>> +{
>> +	dt_ident_t	*idp;
>> +	dt_node_t	*str = dnp->dn_args;
>> +
>> +	TRACE_REGSET("    subr-str_of_str:Begin");
> s/str_of_str/path_helper/
>
>> +	dt_cg_node(str, dlp, drp);
>> +	dt_cg_check_notnull(dlp, drp, str->dn_reg);
>> +
>> +	/*
>> +	 * The result needs be be a temporary string, so we request one.
>> +	 */
>> +	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));
>> +
>> +	/* function call */
>> +	if (dt_regset_xalloc_args(drp) == -1)
>> +		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
>> +
>> +	emit(dlp, BPF_MOV_REG(BPF_REG_1, str->dn_reg));
>> +	dt_regset_free(drp, str->dn_reg);
>> +	if (str->dn_tstring)
>> +		dt_cg_tstring_free(yypcb, str);
> No need to have the conditional - we do that in dt_cg_tstring_free().
>
>> +
>> +	emit(dlp,  BPF_MOV_REG(BPF_REG_2, dnp->dn_reg));
>> +
>> +	dt_regset_xalloc(drp, BPF_REG_0);
>> +	idp = dt_dlib_get_func(yypcb->pcb_hdl, fname);
>> +	assert(idp != NULL);
>> +	emite(dlp,  BPF_CALL_FUNC(idp->di_id), idp);
>> +	dt_regset_free_args(drp);
>> +	dt_regset_free(drp, BPF_REG_0);
>> +
>> +	TRACE_REGSET("    subr-str_of_str:End  ");
> s/str_of_str/path_helper/
>
>> +}
>> +
>> +static void
>> +dt_cg_subr_basename(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>> +{
>> +	dt_cg_subr_path_helper(dnp, dlp, drp, "dt_basename");
>> +}
>> +
>>   /*
>>    * Get and return a new speculation ID.  These are unallocated entries in the
>>    * specs map, obtained by calling dt_speculation().  Return zero if none is
>> @@ -3986,7 +4040,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
>>   	[DIF_SUBR_DDI_PATHNAME]		= NULL,
>>   	[DIF_SUBR_STRJOIN]		= dt_cg_subr_strjoin,
>>   	[DIF_SUBR_LLTOSTR]		= &dt_cg_subr_lltostr,
>> -	[DIF_SUBR_BASENAME]		= NULL,
>> +	[DIF_SUBR_BASENAME]		= &dt_cg_subr_basename,
>>   	[DIF_SUBR_DIRNAME]		= NULL,
>>   	[DIF_SUBR_CLEANPATH]		= NULL,
>>   	[DIF_SUBR_STRCHR]		= &dt_cg_subr_strchr,
>> diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
>> index 50acc0dc..771eba64 100644
>> --- a/libdtrace/dt_dlibs.c
>> +++ b/libdtrace/dt_dlibs.c
>> @@ -54,6 +54,7 @@ static const dt_ident_t		dt_bpf_symbols[] = {
>>   	/* BPF library (external) functions */
>>   	DT_BPF_SYMBOL(dt_agg_lqbin, DT_IDENT_SYMBOL),
>>   	DT_BPF_SYMBOL(dt_agg_qbin, DT_IDENT_SYMBOL),
>> +	DT_BPF_SYMBOL(dt_basename, DT_IDENT_SYMBOL),
>>   	DT_BPF_SYMBOL(dt_error, DT_IDENT_SYMBOL),
>>   	DT_BPF_SYMBOL(dt_get_bvar, DT_IDENT_SYMBOL),
>>   	DT_BPF_SYMBOL(dt_get_string, DT_IDENT_SYMBOL),
>> diff --git a/test/unittest/dif/basename.d b/test/unittest/dif/basename.d
>> index a4c50d7e..5e60b96d 100644
>> --- a/test/unittest/dif/basename.d
>> +++ b/test/unittest/dif/basename.d
>> @@ -1,4 +1,3 @@
>> -/* @@xfail: dtv2 */
>>   BEGIN
>>   {
>>   	exit(basename("/foo/bar") == "bar" ? 0 : 1);
>> diff --git a/test/unittest/funcs/tst.basename0.d b/test/unittest/funcs/tst.basename0.d
>> new file mode 100644
>> index 00000000..0f758996
>> --- /dev/null
>> +++ b/test/unittest/funcs/tst.basename0.d
>> @@ -0,0 +1,38 @@
>> +/*
>> + * 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
>> +
>> +BEGIN
>> +{
>> +	printf("|%s|\n", basename("/foo/bar/baz"));
>> +	printf("|%s|\n", basename("/foo/bar///baz/"));
>> +	printf("|%s|\n", basename("/foo/bar/baz/"));
>> +	printf("|%s|\n", basename("/foo/bar/baz//"));
>> +	printf("|%s|\n", basename("/foo/bar/baz/."));
>> +	printf("|%s|\n", basename("/foo/bar/baz/./"));
>> +	printf("|%s|\n", basename("/foo/bar/baz/.//"));
>> +	printf("|%s|\n", basename("foo/bar/baz/"));
>> +	printf("|%s|\n", basename("/"));
>> +	printf("|%s|\n", basename("./"));
>> +	printf("|%s|\n", basename("//"));
>> +	printf("|%s|\n", basename("/."));
>> +	printf("|%s|\n", basename("/./"));
>> +	printf("|%s|\n", basename("/./."));
>> +	printf("|%s|\n", basename("/.//"));
>> +	printf("|%s|\n", basename("."));
>> +	printf("|%s|\n", basename("f"));
>> +	printf("|%s|\n", basename("f/"));
>> +	printf("|%s|\n", basename("/////"));
>> +	printf("|%s|\n", basename(""));
>> +	exit(0);
>> +}
>> +
>> +ERROR
>> +{
>> +	exit(1);
>> +}
>> diff --git a/test/unittest/funcs/tst.basename0.r b/test/unittest/funcs/tst.basename0.r
>> new file mode 100644
>> index 00000000..37a96547
>> --- /dev/null
>> +++ b/test/unittest/funcs/tst.basename0.r
>> @@ -0,0 +1,21 @@
>> +|baz|
>> +|baz|
>> +|baz|
>> +|baz|
>> +|.|
>> +|.|
>> +|.|
>> +|baz|
>> +|/|
>> +|.|
>> +|/|
>> +|.|
>> +|.|
>> +|.|
>> +|.|
>> +|.|
>> +|f|
>> +|f|
>> +|/|
>> +|.|
>> +
>> -- 
>> 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