[DTrace-devel] [PATCH 3/7] Add rodata support
Kris Van Hees
kris.van.hees at oracle.com
Thu Jul 27 15:29:57 UTC 2023
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)
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);
@@ -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)
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");
+ 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);
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.
+ * 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;
+
+ 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. */
+ *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);
+
+ 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)
+{
+ dt_rohash_t *hp;
+
+ for (hp = dp->hash[h]; hp != NULL; hp = hp->next) {
+ 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)
+{
+ 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;
+ 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;
+ 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.
+ * 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);
+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 *);
+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;
+}
--
2.39.3
More information about the DTrace-devel
mailing list