[DTrace-devel] [PATCH 3/7] Add rodata support

Eugene Loh eugene.loh at oracle.com
Thu Jul 27 20:02:22 UTC 2023


This is a kind of long patch, and I do not know what problem it is 
trying to solve.

If there is supposed to be read-only data, wouldn't that include strtab 
and the zeroes?  Why isn't this mechanism being used for them?  Or, why 
not skip this stuff entirely and just add the inet_ntoa6 table (when it 
appears down the road) in the same way that the zeroes were added?  As 
it is, we simply seem to be adding a lot of complexity (and duplicating 
a lot of code from strtab) for no clear purpose.

A big comment block in dt_rodata.h or .c explaining this stuff would be 
good.

Meanwhile other comments below.

On 7/27/23 11:29, Kris Van Hees via DTrace-devel wrote:
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
>   libdtrace/Build       |   1 +
>   libdtrace/dt_bpf.c    |   9 +-
>   libdtrace/dt_bpf.h    |  38 +++---
>   libdtrace/dt_cc.c     |   6 +
>   libdtrace/dt_cg.c     |  11 ++
>   libdtrace/dt_dctx.h   |   2 +
>   libdtrace/dt_dlibs.c  |   2 +
>   libdtrace/dt_impl.h   |  10 +-
>   libdtrace/dt_open.c   |   1 +
>   libdtrace/dt_rodata.c | 295 ++++++++++++++++++++++++++++++++++++++++++
>   libdtrace/dt_rodata.h |  35 +++++
>   libdtrace/dt_subr.c   |  22 ++++
>   12 files changed, 411 insertions(+), 21 deletions(-)
>   create mode 100644 libdtrace/dt_rodata.c
>   create mode 100644 libdtrace/dt_rodata.h
>
> diff --git a/libdtrace/Build b/libdtrace/Build
> index a392c5f3..d1b00933 100644
> --- a/libdtrace/Build
> +++ b/libdtrace/Build
> @@ -61,6 +61,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \
>   			  dt_provider_sdt.c \
>   			  dt_provider_tp.c \
>   			  dt_regset.c \
> +			  dt_rodata.c \
>   			  dt_string.c \
>   			  dt_strtab.c \
>   			  dt_subr.c \
> diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
> index 54086077..b4c880bc 100644
> --- a/libdtrace/dt_bpf.c
> +++ b/libdtrace/dt_bpf.c
> @@ -711,7 +711,9 @@ gmap_create_strtab(dtrace_hdl_t *dtp)

The big block comment describing gmap_create_strtab() should acknowledge 
the addition of rodata.

>   	int		fd, rc, err;
>   
>   	dtp->dt_strlen = dt_strtab_size(dtp->dt_ccstab);
> -	dtp->dt_zerooffset = P2ROUNDUP(dtp->dt_strlen, 8);
> +	dtp->dt_rooffset = P2ROUNDUP(dtp->dt_strlen, 8);
> +	dtp->dt_rosize = dt_rodata_size(dtp->dt_rodata);
> +	dtp->dt_zerooffset = P2ROUNDUP(dtp->dt_rooffset + dtp->dt_rosize, 8);
>   
>   	/*
>   	 * Ensure the zero-filled memory at the end of the strtab is large
> @@ -730,6 +732,7 @@ gmap_create_strtab(dtrace_hdl_t *dtp)
>   	if (strtab == NULL)
>   		return dt_set_errno(dtp, EDT_NOMEM);
>   
> +	/* Copy the string table data. */
>   	dt_strtab_write(dtp->dt_ccstab, (dt_strtab_write_f *)dt_strtab_copystr,
>   			strtab);

The new comment is helpful.  So a few statements earlier, there should 
also be a comment about the allocation.

> @@ -745,6 +748,10 @@ gmap_create_strtab(dtrace_hdl_t *dtp)
>   		buf += len + 1;
>   	}
>   
> +	/* Copy the read-only data. */
> +	dt_rodata_write(dtp->dt_rodata, (dt_rodata_copy_f *)dt_rodata_copy,
> +			strtab + dtp->dt_rooffset);
> +
>   	fd = create_gmap(dtp, "strtab", BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
>   			 sz, 1);
>   	if (fd == -1)

I do not see where this is going.  Why are we passing dt_rodata_copy to 
a function that is in a file that knows more about dt_rodata_copy than 
we do?  Is some future alternative use anticipated?  If so, how about 
allowing someone to pass a NULL function meaning "you know what to do."  
I suppose the real issue is we're trying to mimic strtab.

Anyhow, how about adding another comment before the create_gmap() call?

> diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
> index f414e78e..e64ca3c1 100644
> --- a/libdtrace/dt_bpf.h
> +++ b/libdtrace/dt_bpf.h
> @@ -19,25 +19,27 @@ struct dtrace_hdl;
>   extern "C" {
>   #endif
>   
> -#define DT_CONST_EPID	1
> -#define DT_CONST_PRID	2
> -#define DT_CONST_CLID	3
> -#define DT_CONST_ARGC	4
> -#define DT_CONST_STBSZ	5
> -#define DT_CONST_STRSZ	6
> -#define DT_CONST_STKSIZ	7
> -#define DT_CONST_BOOTTM	8
> -#define DT_CONST_NSPEC	9
> -#define DT_CONST_NCPUS	10
> -#define DT_CONST_PC	11
> -#define DT_CONST_TUPSZ	12
> -#define DT_CONST_TASK_PID	13
> -#define DT_CONST_TASK_TGID	14
> +#define DT_CONST_EPID			1
> +#define DT_CONST_PRID			2
> +#define DT_CONST_CLID			3
> +#define DT_CONST_ARGC			4
> +#define DT_CONST_STBSZ			5
> +#define DT_CONST_STRSZ			6
> +#define DT_CONST_STKSIZ			7
> +#define DT_CONST_BOOTTM			8
> +#define DT_CONST_NSPEC			9
> +#define DT_CONST_NCPUS			10
> +#define DT_CONST_PC			11
> +#define DT_CONST_TUPSZ			12
> +#define DT_CONST_TASK_PID		13
> +#define DT_CONST_TASK_TGID		14
>   #define DT_CONST_TASK_REAL_PARENT	15
> -#define DT_CONST_TASK_COMM	16
> -#define DT_CONST_MUTEX_OWNER	17
> -#define DT_CONST_RWLOCK_CNTS	18
> -#define DT_CONST_ZERO_OFF	19
> +#define DT_CONST_TASK_COMM		16
> +#define DT_CONST_MUTEX_OWNER		17
> +#define DT_CONST_RWLOCK_CNTS		18
> +#define DT_CONST_RODATA_OFF		19
> +#define DT_CONST_RODATA_SIZE		20
> +#define DT_CONST_ZERO_OFF		21
>   
>   #define DT_BPF_LOG_SIZE_DEFAULT	(UINT32_MAX >> 8)
>   #define DT_BPF_LOG_SIZE_SMALL	4096
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index 88d7f1fe..2293892c 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -2468,6 +2468,12 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
>   				nrp->dofr_data = total_offset;
>   				continue;
>   			}
> +			case DT_CONST_RODATA_OFF:
> +				nrp->dofr_data = dtp->dt_rooffset;
> +				continue;
> +			case DT_CONST_RODATA_SIZE:
> +				nrp->dofr_data = dtp->dt_rosize;
> +				continue;
>   			case DT_CONST_ZERO_OFF:
>   				nrp->dofr_data = dtp->dt_zerooffset;
>   				continue;
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index bb6cff4a..6a1413f0 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -56,6 +56,7 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
>   	dt_ident_t	*mem = dt_dlib_get_map(dtp, "mem");
>   	dt_ident_t	*state = dt_dlib_get_map(dtp, "state");
>   	dt_ident_t	*prid = dt_dlib_get_var(pcb->pcb_hdl, "PRID");

While we're here, how about s/pcb->pcb_hdl/dtp/?

> +	dt_ident_t	*ro_off = dt_dlib_get_var(dtp, "RODATA_OFF");
>   	uint_t		lbl_exit = pcb->pcb_exitlbl;
>   
>   	assert(aggs != NULL);
> @@ -206,6 +207,16 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
>   	} while(0)
>   
>   	DT_CG_STORE_MAP_PTR("strtab", DCTX_STRTAB);
> +
> +	/*
> +	 * We know that a pointer to the strtab data is in %r0 (because that is
> +	 * where the DT_CG_STORE_MAP_PTR() macro left it, and we know that dctx
> +	 * is in %r9.  So, we can just add RODATA_OFF to %r0, and store that in
> +	 * [%r9 + DCTX_RODATA].
> +	 */
> +	emite(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, -1), ro_off);
> +	emit(dlp,  BPF_STORE(BPF_DW, BPF_REG_9, DCTX_RODATA, BPF_REG_0));
> +
>   	if (dtp->dt_options[DTRACEOPT_SCRATCHSIZE] > 0)
>   		DT_CG_STORE_MAP_PTR("scratchmem", DCTX_SCRATCHMEM);
>   	if (dt_idhash_datasize(dtp->dt_globals) > 0)
> diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
> index 315bdc37..86bfe6f2 100644
> --- a/libdtrace/dt_dctx.h
> +++ b/libdtrace/dt_dctx.h
> @@ -58,6 +58,7 @@ typedef struct dt_dctx {
>   	char		*mem;		/* General scratch memory */
>   	char		*scratchmem;	/* Scratch space for alloca, etc */
>   	char		*strtab;	/* String constant table */
> +	char		*rodata;	/* Read-only data */
>   	char		*agg;		/* Aggregation data */
>   	char		*gvars;		/* Global variables */
>   	char		*lvars;		/* Local variables */
> @@ -70,6 +71,7 @@ typedef struct dt_dctx {
>   #define DCTX_MEM	offsetof(dt_dctx_t, mem)
>   #define DCTX_SCRATCHMEM	offsetof(dt_dctx_t, scratchmem)
>   #define DCTX_STRTAB	offsetof(dt_dctx_t, strtab)
> +#define DCTX_RODATA	offsetof(dt_dctx_t, rodata)
>   #define DCTX_AGG	offsetof(dt_dctx_t, agg)
>   #define DCTX_GVARS	offsetof(dt_dctx_t, gvars)
>   #define DCTX_LVARS	offsetof(dt_dctx_t, lvars)
> diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
> index 1005e027..02a24ad2 100644
> --- a/libdtrace/dt_dlibs.c
> +++ b/libdtrace/dt_dlibs.c
> @@ -91,6 +91,8 @@ static const dt_ident_t		dt_bpf_symbols[] = {
>   	DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM),
>   	DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER),
>   	DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS),
> +	DT_BPF_SYMBOL_ID(RODATA_OFF, DT_IDENT_SCALAR, DT_CONST_RODATA_OFF),
> +	DT_BPF_SYMBOL_ID(RODATA_SIZE, DT_IDENT_SCALAR, DT_CONST_RODATA_SIZE),
>   	DT_BPF_SYMBOL_ID(ZERO_OFF, DT_IDENT_SCALAR, DT_CONST_ZERO_OFF),
>   
>   	/* End-of-list marker */
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 42a7ccaa..adc8d8db 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -34,6 +34,7 @@ extern "C" {
>   #include <dt_bpf_maps.h>
>   #include <dt_parser.h>
>   #include <dt_regset.h>
> +#include <dt_rodata.h>
>   #include <dt_strtab.h>
>   #include <dt_symtab.h>
>   #include <dt_ident.h>
> @@ -306,14 +307,17 @@ struct dtrace_hdl {
>   	dt_idhash_t *dt_tls;	/* hash table of thread-local identifiers */
>   	dt_idhash_t *dt_bpfsyms;/* hash table of BPF identifiers */
>   	dt_strtab_t *dt_ccstab;	/* global string table (during compilation) */
> +	dt_rodata_t *dt_rodata;	/* global read-only data */
>   	uint_t dt_strlen;	/* global string table (runtime) size */
> +	uint_t dt_rooffset;	/* read-only data offset */
> +	uint_t dt_rosize;	/* read-only data size */
> +	uint_t dt_zerooffset;	/* zero region, offset */
> +	uint_t dt_zerosize;	/* zero region, size */
>   	uint_t dt_maxreclen;	/* largest record size across programs */
>   	uint_t dt_maxdvarsize;	/* largest dynamic variable across programs */
>   	uint_t dt_maxtuplesize;	/* largest tuple across programs */
>   	uint_t dt_maxlvaralloc;	/* largest lvar alloc across pcbs */
>   	uint_t dt_maxaggdsize;	/* largest aggregation data sizw */
> -	uint_t dt_zerosize;	/* zero region, size */
> -	uint_t dt_zerooffset;	/* zero region, offset */
>   	dt_tstring_t *dt_tstrings; /* temporary string slots */
>   	dt_list_t dt_modlist;	/* linked list of dt_module_t's */
>   	dt_htab_t *dt_mods;	/* hash table of dt_module_t's */
> @@ -725,6 +729,8 @@ extern int dt_version_defined(dt_version_t);
>   
>   extern int dt_str2kver(const char *, dt_version_t *);
>   
> +extern uint32_t dt_gen_hval(const char *, uint32_t, size_t);
> +
>   /*
>    * Miscellaneous internal libdtrace interfaces.  The definitions below are for
>    * libdtrace routines that do not yet merit their own separate header file.
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index b6a0b623..a90601b0 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -888,6 +888,7 @@ dt_vopen(int version, int flags, int *errp,
>   	    DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);
>   
>   	dtp->dt_ccstab = dt_strtab_create(BUFSIZ);
> +	dtp->dt_rodata = dt_rodata_create(BUFSIZ);

Memory leak?  No companion destroy call?  (No big deal.)

And do we need to check if NULL was returned?

>   	dtp->dt_strlen = 0;
>   
>   	if (dtp->dt_macros == NULL || dtp->dt_aggs == NULL ||
> diff --git a/libdtrace/dt_rodata.c b/libdtrace/dt_rodata.c
> new file mode 100644
> index 00000000..cba12d77
> --- /dev/null
> +++ b/libdtrace/dt_rodata.c
> @@ -0,0 +1,295 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.

Why 2006?  Because we're duplicating code from strtab?

> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +#include <sys/types.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <assert.h>
> +
> +#include <dt_rodata.h>
> +#include <dt_string.h>
> +#include <dt_impl.h>
> +
> +typedef struct dt_rohash	dt_rohash_t;
> +struct dt_rohash {
> +	const char	*data;		/* pointer to actual data */
> +	size_t		buf;		/* index of data buffer */
> +	size_t		off;		/* offset in bytes of this item */
> +	size_t		len;		/* length in bytes of this item */
> +	dt_rohash_t	*next;		/* next item in hash chain */
> +};
> +
> +struct dt_rodata {
> +	dt_rohash_t	**hash;		/* array of hash buckets */
> +	size_t		hashsz;		/* size of hash bucket array */
> +	char		**bufs;		/* array of buffer pointers */
> +	char		*ptr;		/* pointer to current buffer location */
> +	size_t		nbufs;		/* size of buffer pointer array */
> +	size_t		bufsz;		/* size of individual buffer */
> +	size_t		count;		/* total number of items in rodata */
> +	size_t		size;		/* total size of items in bytes */
> +};
> +
> +static int
> +dt_rodata_grow(dt_rodata_t *dp)
> +{
> +	char	*ptr, **bufs;
> +
> +	ptr = malloc(dp->bufsz);
> +	if (ptr == NULL)
> +		return -1;
> +
> +	bufs = realloc(dp->bufs, (dp->nbufs + 1) * sizeof(char *));
> +	if (bufs == NULL) {
> +		free(ptr);
> +		return -1;
> +	}
> +
> +	dp->nbufs++;
> +	dp->bufs = bufs;
> +	dp->ptr = ptr;
> +	dp->bufs[dp->nbufs - 1] = dp->ptr;

No big deal, but could "= ptr" here.

> +
> +	return 0;
> +}
> +
> +dt_rodata_t *
> +dt_rodata_create(size_t bufsz)
> +{
> +	dt_rodata_t	*dp = malloc(sizeof(dt_rodata_t));
> +	size_t		nbuckets = _dtrace_strbuckets;
> +
> +	assert(bufsz != 0);
> +
> +	if (dp == NULL)
> +		return NULL;
> +
> +	memset(dp, 0, sizeof(dt_rodata_t));
> +	dp->hash = malloc(nbuckets * sizeof(dt_rohash_t *));
> +	if (dp->hash == NULL)
> +		goto err;
> +
> +	memset(dp->hash, 0, nbuckets * sizeof(dt_rohash_t *));
> +	dp->hashsz = nbuckets;
> +	dp->bufs = NULL;
> +	dp->ptr = NULL;
> +	dp->nbufs = 0;
> +	dp->bufsz = bufsz;
> +
> +	if (dt_rodata_grow(dp) == -1)
> +		goto err;
> +
> +	/* Pre-populate the read-only data with a 0-byte at offset 0.  */

Don't hyphenate 0-byte?

> +	*dp->ptr++ = 0;
> +	dp->size = 1;
> +	dp->count = 1;
> +
> +	return dp;
> +
> +err:
> +	dt_rodata_destroy(dp);
> +	return NULL;
> +}
> +
> +void
> +dt_rodata_destroy(dt_rodata_t *dp)
> +{
> +	dt_rohash_t	*hp, *hq;
> +	size_t		i;
> +
> +	if (dp == NULL)
> +		return;
> +
> +	for (i = 0; i < dp->hashsz; i++) {
> +		for (hp = dp->hash[i]; hp != NULL; hp = hq) {
> +			hq = hp->next;
> +			free(hp);
> +		}
> +	}
> +
> +	for (i = 0; i < dp->nbufs; i++)
> +		free(dp->bufs[i]);
> +
> +	if (dp->hash != NULL)
> +		free(dp->hash);
> +	if (dp->bufs != NULL)
> +		free(dp->bufs);

If dp->hash or dp->bufs could be NULL, we should have checked earlier, 
before using them.

> +
> +	free(dp);
> +}
> +
> +static int
> +dt_rodata_compare(dt_rodata_t *dp, dt_rohash_t *hp, const char *ptr, size_t len)
> +{
> +	size_t		b = hp->buf;
> +	const char	*buf = hp->data;
> +	size_t		resid, n;
> +	int		rv;
> +
> +	while (len != 0) {
> +		if (buf == dp->bufs[b] + dp->bufsz)
> +			buf = dp->bufs[++b];
> +
> +		resid = dp->bufs[b] + dp->bufsz - buf;
> +		n = MIN(resid, len);
> +
> +		if ((rv = memcmp(buf, ptr, n)) != 0)
> +			return rv;
> +
> +		buf += n;
> +		ptr += n;
> +		len -= n;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +dt_rodata_copyin(dt_rodata_t *dp, const char *ptr, size_t len)
> +{
> +	char	*old_p = dp->ptr;
> +	size_t	old_n = dp->nbufs;
> +	size_t	b = dp->nbufs - 1;
> +	size_t	resid, n;
> +
> +	while (len != 0) {
> +		if (dp->ptr == dp->bufs[b] + dp->bufsz) {
> +			if (dt_rodata_grow(dp) == -1)
> +				goto err;
> +			b++;
> +		}
> +
> +		resid = dp->bufs[b] + dp->bufsz - dp->ptr;
> +		n = MIN(resid, len);
> +		memcpy(dp->ptr, ptr, n);
> +
> +		dp->ptr += n;
> +		ptr += n;
> +		len -= n;
> +	}
> +
> +	return 0;
> +
> +err:
> +	while (dp->nbufs != old_n)
> +		free(dp->bufs[--dp->nbufs]);
> +
> +	dp->ptr = old_p;
> +	return -1;
> +}
> +
> +static ssize_t
> +dt_rodata_xindex(dt_rodata_t *dp, const char *ptr, size_t len, uint32_t h)

How about putting the h%dp->hashsz in here to ensure it's done?
In fact, just move the h=dt_gen_hval() in here rather than passing h in.

> +{
> +	dt_rohash_t	*hp;
> +
> +	for (hp = dp->hash[h]; hp != NULL; hp = hp->next) {

No need for these brackets?

> +		if (dt_rodata_compare(dp, hp, ptr, len) == 0)
> +			return hp->off;
> +	}
> +
> +	return -1;
> +}
> +
> +ssize_t
> +dt_rodata_index(dt_rodata_t *dp, const char *ptr, size_t len)

No one uses this?
Or is dt_rodata_insert() supposed to call it?
In which case, xindex can be inlined here.

> +{
> +	ssize_t		rc;
> +	uint32_t	h;
> +
> +	if (ptr == NULL || ptr[0] == '\0')
> +		return 0;	/* NULL or a single 0-byte are at offset 0. */
> +
> +	h = dt_gen_hval(ptr, len, len) % dp->hashsz;

Why len, len?  Why not 0, len?

> +	rc = dt_rodata_xindex(dp, ptr, len, h);
> +
> +	return rc;
> +}
> +
> +ssize_t
> +dt_rodata_insert(dt_rodata_t *dp, const char *ptr, size_t len)
> +{
> +	dt_rohash_t	*hp;
> +	ssize_t		off;
> +	uint32_t	h;
> +
> +	if (ptr == NULL || ptr[0] == '\0')
> +		return 0;	/* NULL or a single 0-byte are at offset 0. */
> +
> +	h = dt_gen_hval(ptr, len, len) % dp->hashsz;

Ditto.

> +	off = dt_rodata_xindex(dp, ptr, len, h);
> +	if (off != -1)
> +		return off;
> +
> +	/*
> +	 * Create a new hash bucket, initialize it, and insert it at the front
> +	 * of the hash chain for the appropriate bucket.
> +	 */
> +	if ((hp = malloc(sizeof(dt_rohash_t))) == NULL)
> +		return -1L;
> +
> +	hp->data = dp->ptr;
> +	hp->buf = dp->nbufs - 1;
> +	hp->off = dp->size;
> +	hp->len = len;
> +	hp->next = dp->hash[h];
> +
> +	/*
> +	 * Now copy the data into our buffer list, and then update the global
> +	 * counts of items and bytes.  Return the item's byte offset.
> +	 */
> +	if (dt_rodata_copyin(dp, ptr, len) == -1) {
> +		free(hp);
> +		return -1L;
> +	}
> +
> +	dp->count++;
> +	dp->size += len;
> +	dp->hash[h] = hp;
> +
> +	return hp->off;
> +}
> +
> +size_t
> +dt_rodata_size(const dt_rodata_t *dp)
> +{
> +	return dp->size;
> +}
> +
> +/*
> + * Copy data from the compile-time read-only data into a DIFO-style read-only
> + * storage memory block.
> + */
> +ssize_t
> +dt_rodata_copy(const char *s, size_t n, size_t off, char *buf)
> +{
> +	memcpy(buf + off, s, n);
> +	return n;
> +}
> +
> +ssize_t
> +dt_rodata_write(const dt_rodata_t *dp, dt_rodata_copy_f *func, void *private)
> +{
> +	ssize_t	res, total = 0;
> +	size_t	i;
> +	size_t	n;
> +
> +	for (i = 0; i < dp->nbufs; i++, total += res) {
> +		if (i == dp->nbufs - 1)
> +			n = dp->ptr - dp->bufs[i];
> +		else
> +			n = dp->bufsz;
> +
> +		if ((res = func(dp->bufs[i], n, total, private)) <= 0)
> +			break;
> +	}
> +
> +	if (total == 0 && dp->size != 0)
> +		return -1;
> +
> +	return total;
> +}
> diff --git a/libdtrace/dt_rodata.h b/libdtrace/dt_rodata.h
> new file mode 100644
> index 00000000..d995d7ea
> --- /dev/null
> +++ b/libdtrace/dt_rodata.h
> @@ -0,0 +1,35 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.

Years?

> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +#ifndef	_DT_RODATA_H
> +#define	_DT_RODATA_H
> +
> +#include <sys/types.h>
> +#include <sys/dtrace_types.h>
> +
> +#ifdef	__cplusplus
> +extern "C" {
> +#endif
> +
> +typedef struct dt_rodata	dt_rodata_t;
> +
> +typedef ssize_t dt_rodata_copy_f(const char *, size_t, size_t, void *);
> +
> +extern dt_rodata_t *dt_rodata_create(size_t);
> +extern void dt_rodata_destroy(dt_rodata_t *);
> +extern ssize_t dt_rodata_index(dt_rodata_t *, const char *, size_t);

No one uses _index.

> +extern ssize_t dt_rodata_insert(dt_rodata_t *, const char *, size_t);
> +extern size_t dt_rodata_size(const dt_rodata_t *);
> +extern ssize_t dt_rodata_copy(const char *, size_t, size_t, char *);

Earlier questions about why this is externed.

> +extern ssize_t dt_rodata_write(const dt_rodata_t *, dt_rodata_copy_f *,
> +			       void *);
> +
> +#ifdef	__cplusplus
> +}
> +#endif
> +
> +#endif	/* _DT_RODATA_H */
> diff --git a/libdtrace/dt_subr.c b/libdtrace/dt_subr.c
> index 300c1a8d..6af2e0c8 100644
> --- a/libdtrace/dt_subr.c
> +++ b/libdtrace/dt_subr.c
> @@ -985,3 +985,25 @@ dt_str2kver(const char *kverstr, dt_version_t *vp)
>   
>   	return 0;
>   }
> +
> +/*
> + * Compute a 32-bit hash value for a memory block of given size.
> + */
> +uint32_t dt_gen_hval(const char *p, uint32_t hval, size_t len)
> +{
> +	uint32_t	g;
> +
> +	if (!p || len == 0)
> +		return hval;
> +
> +	while (len--) {
> +		hval = (hval << 4) + *p++;
> +		g = hval & 0xf0000000;
> +		if (g != 0) {
> +			hval ^= (g >> 24);
> +			hval ^= g;
> +		}
> +	}
> +
> +	return hval;
> +}

Same algorithm as
     dt_spec_buf_hval()
     str2hval()
     string_hash()
Can anything be consolidated here?



More information about the DTrace-devel mailing list