[DTrace-devel] [PATCH 05/16] Move tracepoint-based probe handling into its own source file
Kris Van Hees
kris.van.hees at oracle.com
Thu Mar 18 21:54:24 PDT 2021
Various providers make use of tracepoint-based probes. They share a
common need for manipulating the tracepoint-specific probe data. We
will also be implementing providers making use of tracepoint-based
probes that need some additinal provider-specific data associated
with the probe.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libdtrace/Build | 65 +++++--
libdtrace/dt_prov_dtrace.c | 20 +--
libdtrace/dt_prov_fbt.c | 16 +-
libdtrace/dt_prov_profile.c | 42 ++---
libdtrace/dt_prov_sdt.c | 286 ++-----------------------------
libdtrace/dt_prov_syscall.c | 21 ++-
libdtrace/dt_provider.h | 34 ++--
libdtrace/dt_provider_tp.c | 333 ++++++++++++++++++++++++++++++++++++
8 files changed, 467 insertions(+), 350 deletions(-)
create mode 100644 libdtrace/dt_provider_tp.c
diff --git a/libdtrace/Build b/libdtrace/Build
index 1c8b74f5..9c683e8f 100644
--- a/libdtrace/Build
+++ b/libdtrace/Build
@@ -10,19 +10,58 @@ libdtrace-build_CPPFLAGS = -Ilibdtrace -Ilibproc -Iuts/intel -Ilibdtrace/$(ARCHI
-DUNPRIV_HOME=\"$(UNPRIV_HOME)\"
libdtrace-build_TARGET = libdtrace
libdtrace-build_DIR := $(current-dir)
-libdtrace-build_SOURCES = dt_lex.c dt_aggregate.c dt_as.c dt_bpf.c \
- dt_buf.c dt_cc.c dt_cg.c dt_conf.c dt_consume.c \
- dt_debug.c dt_decl.c dt_dis.c dt_dlibs.c dt_dof.c \
- dt_error.c dt_errtags.c dt_grammar.c dt_handle.c \
- dt_htab.c dt_ident.c dt_link.c dt_kernel_module.c \
- dt_list.c dt_map.c dt_module.c dt_names.c dt_open.c \
- dt_options.c dt_parser.c dt_pcap.c dt_pcb.c \
- dt_pid.c dt_pragma.c dt_printf.c dt_probe.c \
- dt_proc.c dt_program.c dt_provider.c dt_regset.c \
- dt_string.c dt_strtab.c dt_subr.c dt_symtab.c \
- dt_work.c dt_xlator.c dt_peb.c dt_prov_dtrace.c \
- dt_prov_fbt.c dt_prov_profile.c dt_prov_sdt.c \
- dt_prov_syscall.c
+libdtrace-build_SOURCES = dt_aggregate.c \
+ dt_as.c \
+ dt_bpf.c \
+ dt_buf.c \
+ dt_cc.c \
+ dt_cg.c \
+ dt_conf.c \
+ dt_consume.c \
+ dt_debug.c \
+ dt_decl.c \
+ dt_dis.c \
+ dt_dlibs.c \
+ dt_dof.c \
+ dt_error.c \
+ dt_errtags.c \
+ dt_grammar.c \
+ dt_handle.c \
+ dt_htab.c \
+ dt_ident.c \
+ dt_lex.c \
+ dt_link.c \
+ dt_kernel_module.c \
+ dt_list.c \
+ dt_map.c \
+ dt_module.c \
+ dt_names.c \
+ dt_open.c \
+ dt_options.c \
+ dt_parser.c \
+ dt_pcap.c \
+ dt_pcb.c \
+ dt_peb.c \
+ dt_pid.c \
+ dt_pragma.c \
+ dt_printf.c \
+ dt_probe.c \
+ dt_proc.c \
+ dt_program.c \
+ dt_prov_dtrace.c \
+ dt_prov_fbt.c \
+ dt_prov_profile.c \
+ dt_prov_sdt.c \
+ dt_prov_syscall.c \
+ dt_provider.c \
+ dt_provider_tp.c \
+ dt_regset.c \
+ dt_string.c \
+ dt_strtab.c \
+ dt_subr.c \
+ dt_symtab.c \
+ dt_work.c \
+ dt_xlator.c
libdtrace-build_SRCDEPS := dt_grammar.h $(objdir)/dt_git_version.h
diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
index 7344a9df..55090e53 100644
--- a/libdtrace/dt_prov_dtrace.c
+++ b/libdtrace/dt_prov_dtrace.c
@@ -43,19 +43,19 @@ static int populate(dtrace_hdl_t *dtp)
if (prv == NULL)
return 0;
- prp = tp_probe_insert(dtp, prv, prvname, modname, funname, "BEGIN");
+ prp = dt_tp_probe_insert(dtp, prv, prvname, modname, funname, "BEGIN");
if (prp) {
n++;
dt_list_append(&dtp->dt_enablings, prp);
}
- prp = tp_probe_insert(dtp, prv, prvname, modname, funname, "END");
+ prp = dt_tp_probe_insert(dtp, prv, prvname, modname, funname, "END");
if (prp) {
n++;
dt_list_append(&dtp->dt_enablings, prp);
}
- prp = tp_probe_insert(dtp, prv, prvname, modname, funname, "ERROR");
+ prp = dt_tp_probe_insert(dtp, prv, prvname, modname, funname, "ERROR");
if (prp) {
n++;
dt_list_append(&dtp->dt_enablings, prp);
@@ -282,9 +282,9 @@ out:
static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
{
- tp_probe_t *datap = prp->prv_data;
+ tp_probe_t *tpp = prp->prv_data;
- if (datap->event_id == -1) {
+ if (!dt_tp_is_attached(tpp)) {
char *spec;
char *fn;
FILE *f;
@@ -321,12 +321,12 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
if (f == NULL)
return -ENOENT;
- rc = tp_event_info(dtp, f, 0, datap, NULL, NULL);
+ rc = dt_tp_event_info(dtp, f, 0, tpp, NULL, NULL);
fclose(f);
}
- /* attach BPF program to the probe */
- return tp_attach(dtp, prp, bpf_fd);
+ /* attach BPF program to the tracepoint */
+ return dt_tp_attach(dtp, tpp, bpf_fd);
}
static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
@@ -353,7 +353,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
{
int fd;
- tp_detach(dtp, prp);
+ dt_tp_detach(dtp, prp->prv_data);
fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
if (fd == -1)
@@ -371,5 +371,5 @@ dt_provimpl_t dt_dtrace = {
.attach = &attach,
.probe_info = &probe_info,
.detach = &detach,
- .probe_destroy = &tp_probe_destroy,
+ .probe_destroy = &dt_tp_probe_destroy,
};
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index 1f519039..6db41767 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -136,9 +136,9 @@ static int populate(dtrace_hdl_t *dtp)
if (dt_probe_lookup(dtp, &pd) != NULL)
continue;
- if (tp_probe_insert(dtp, prv, prvname, mod, buf, "entry"))
+ if (dt_tp_probe_insert(dtp, prv, prvname, mod, buf, "entry"))
n++;
- if (tp_probe_insert(dtp, prv, prvname, mod, buf, "return"))
+ if (dt_tp_probe_insert(dtp, prv, prvname, mod, buf, "return"))
n++;
}
@@ -230,9 +230,9 @@ static void trampoline(dt_pcb_t *pcb)
static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
{
- tp_probe_t *datap = prp->prv_data;
+ tp_probe_t *tpp = prp->prv_data;
- if (datap->event_id == -1) {
+ if (!dt_tp_is_attached(tpp)) {
char *fn;
FILE *f;
size_t len;
@@ -270,7 +270,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
return -ENOENT;
/* read event id from format file */
- rc = tp_event_info(dtp, f, 0, datap, NULL, NULL);
+ rc = dt_tp_event_info(dtp, f, 0, tpp, NULL, NULL);
fclose(f);
if (rc < 0)
@@ -278,7 +278,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
}
/* attach BPF program to the probe */
- return tp_attach(dtp, prp, bpf_fd);
+ return dt_tp_attach(dtp, tpp, bpf_fd);
}
static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
@@ -305,7 +305,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
{
int fd;
- tp_detach(dtp, prp);
+ dt_tp_detach(dtp, prp->prv_data);
fd = open(KPROBE_EVENTS, O_WRONLY | O_APPEND);
if (fd == -1)
@@ -324,5 +324,5 @@ dt_provimpl_t dt_fbt = {
.attach = &attach,
.probe_info = &probe_info,
.detach = &detach,
- .probe_destroy = &tp_probe_destroy,
+ .probe_destroy = &dt_tp_probe_destroy,
};
diff --git a/libdtrace/dt_prov_profile.c b/libdtrace/dt_prov_profile.c
index e4410155..f7512387 100644
--- a/libdtrace/dt_prov_profile.c
+++ b/libdtrace/dt_prov_profile.c
@@ -44,27 +44,27 @@ static dt_probe_t *profile_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prv,
const char *prb, int kind,
uint64_t period)
{
- profile_probe_t *datap;
+ profile_probe_t *pp;
int i;
int cnt = FDS_CNT(kind);
- datap = dt_zalloc(dtp, sizeof(profile_probe_t));
- if (datap == NULL)
+ pp = dt_zalloc(dtp, sizeof(profile_probe_t));
+ if (pp == NULL)
return NULL;
- datap->kind = kind;
- datap->period = period;
- datap->fds = dt_calloc(dtp, cnt, sizeof(int));
- if (datap->fds == NULL)
+ pp->kind = kind;
+ pp->period = period;
+ pp->fds = dt_calloc(dtp, cnt, sizeof(int));
+ if (pp->fds == NULL)
goto err;
for (i = 0; i < cnt; i++)
- datap->fds[i] = -1;
+ pp->fds[i] = -1;
- return dt_probe_insert(dtp, prv, prvname, modname, funname, prb, datap);
+ return dt_probe_insert(dtp, prv, prvname, modname, funname, prb, pp);
err:
- dt_free(dtp, datap);
+ dt_free(dtp, pp);
return NULL;
}
@@ -274,10 +274,10 @@ static void trampoline(dt_pcb_t *pcb)
static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
{
- profile_probe_t *datap = prp->prv_data;
+ profile_probe_t *pp = prp->prv_data;
struct perf_event_attr attr;
int i, nattach = 0;;
- int cnt = FDS_CNT(datap->kind);
+ int cnt = FDS_CNT(pp->kind);
memset(&attr, 0, sizeof(attr));
attr.type = PERF_TYPE_SOFTWARE;
@@ -286,7 +286,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
attr.size = sizeof(struct perf_event_attr);
attr.wakeup_events = 1;
attr.freq = 0;
- attr.sample_period = datap->period;
+ attr.sample_period = pp->period;
for (i = 0; i < cnt; i++) {
int j = i, fd;
@@ -303,7 +303,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
close(fd);
continue;
}
- datap->fds[i] = fd;
+ pp->fds[i] = fd;
nattach++;
}
@@ -322,22 +322,22 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
{
- profile_probe_t *datap = prp->prv_data;
+ profile_probe_t *pp = prp->prv_data;
int i;
- int cnt = FDS_CNT(datap->kind);
+ int cnt = FDS_CNT(pp->kind);
for (i = 0; i < cnt; i++) {
- if (datap->fds[i] != -1)
- close(datap->fds[i]);
+ if (pp->fds[i] != -1)
+ close(pp->fds[i]);
}
}
static void probe_destroy(dtrace_hdl_t *dtp, void *arg)
{
- profile_probe_t *datap = arg;
+ profile_probe_t *pp = arg;
- dt_free(dtp, datap->fds);
- dt_free(dtp, datap);
+ dt_free(dtp, pp->fds);
+ dt_free(dtp, pp);
}
dt_provimpl_t dt_profile = {
diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
index 2512f9ec..bd8a201b 100644
--- a/libdtrace/dt_prov_sdt.c
+++ b/libdtrace/dt_prov_sdt.c
@@ -60,271 +60,6 @@ static const dtrace_pattr_t pattr = {
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
};
-/*
- * Attach the given (loaded) BPF program to the given probe. This function
- * performs the necessary steps for attaching the BPF program to a tracepoint
- * based probe by opening a perf event for the probe, and associating the BPF
- * program with the perf event.
- */
-int tp_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
-{
- tp_probe_t *datap = prp->prv_data;
-
- if (datap->event_id == -1)
- return 0;
-
- if (datap->event_fd == -1) {
- int fd;
- struct perf_event_attr attr = { 0, };
-
- attr.type = PERF_TYPE_TRACEPOINT;
- attr.sample_type = PERF_SAMPLE_RAW;
- attr.sample_period = 1;
- attr.wakeup_events = 1;
- attr.config = datap->event_id;
-
- fd = perf_event_open(&attr, -1, 0, -1, 0);
- if (fd < 0)
- return dt_set_errno(dtp, errno);
-
- datap->event_fd = fd;
- }
-
- if (ioctl(datap->event_fd, PERF_EVENT_IOC_SET_BPF, bpf_fd) < 0)
- return dt_set_errno(dtp, errno);
-
- return 0;
-}
-
-/*
- * Create tracepoint-specific probe data.
- */
-tp_probe_t *
-tp_probe_create(dtrace_hdl_t *dtp)
-{
- tp_probe_t *datap;
-
- datap = dt_zalloc(dtp, sizeof(tp_probe_t));
- if (datap == NULL)
- return NULL;
-
- datap->event_fd = -1;
- datap->event_id = -1;
-
- return datap;
-}
-
-/*
- * Create a tracepoint-based probe. This function is called from any provider
- * that handled tracepoint-based probes. It sets up the provider-specific
- * data of the probe, and calls dt_probe_insert() to add the probe to the
- * framework.
- */
-dt_probe_t *tp_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov,
- const char *prv, const char *mod,
- const char *fun, const char *prb)
-{
- tp_probe_t *datap;
-
- datap = tp_probe_create(dtp);
- if (datap == NULL)
- return NULL;
-
- return dt_probe_insert(dtp, prov, prv, mod, fun, prb, datap);
-}
-
-/*
- * Parse the EVENTSFS/<group>/<event>/format file to determine the event id and
- * the argument types.
- *
- * The event id easy enough to parse out, because it appears on a line in the
- * following format:
- * ID: <num>
- *
- * The argument types are a bit more complicated. The basic format for each
- * argument is:
- * field:<var-decl>; offset:<num> size:<num> signed:(0|1);
- * The <var-decl> may be prefixed by __data_loc, which is a tag that we can
- * ignore. The <var-decl> does contain an identifier name that dtrace cannot
- * cope with because it expects just the type specification. Getting rid of
- * the identifier isn't as easy because it may be suffixed by one or more
- * array dimension specifiers (and those are part of the type).
- *
- * All events include a number of fields that we are not interested and that
- * need to be skipped (SKIP_FIELDS_COUNT). Callers of this function can
- * specify an additional numbe of fields to skip (using the 'skip' parameter)
- * before we get to the actual arguments.
- */
-int tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, tp_probe_t *datap,
- int *argcp, dt_argdesc_t **argvp)
-{
- char buf[1024];
- int argc;
- size_t argsz = 0;
- dt_argdesc_t *argv = NULL;
- char *strp;
-
- datap->event_id = -1;
-
- /*
- * Let skip be the total number of fields to skip.
- */
- skip += SKIP_FIELDS_COUNT;
-
- /*
- * Pass 1:
- * Determine the event id and the number of arguments (along with the
- * total size of all type strings together).
- */
- argc = -skip;
- while (fgets(buf, sizeof(buf), f)) {
- char *p = buf;
-
- if (sscanf(buf, "ID: %d\n", &datap->event_id) == 1)
- continue;
-
- if (sscanf(buf, " field:%[^;]", p) <= 0)
- continue;
- sscanf(p, "__data_loc %[^;]", p);
-
- /* We found a field: description - see if we should skip it. */
- if (argc++ < 0)
- continue;
-
- /*
- * We over-estimate the space needed (pass 2 will strip off the
- * identifier name).
- */
- argsz += strlen(p) + 1;
- }
-
- /*
- * If we saw less fields than expected, we flag an error.
- * If we are not interested in arguments, we are done.
- * If there are no arguments, we are done.
- */
- if (argc < 0)
- return -EINVAL;
- if (argcp == NULL)
- return 0;
- if (argc == 0)
- goto done;
-
- argv = dt_zalloc(dtp, argc * sizeof(dt_argdesc_t) + argsz);
- if (!argv)
- return -ENOMEM;
- strp = (char *)(argv + argc);
-
- /*
- * Pass 2:
- * Fill in the actual argument datatype strings.
- */
- rewind(f);
- argc = -skip;
- while (fgets(buf, sizeof(buf), f)) {
- char *p = buf;
- size_t l;
-
- if (sscanf(buf, " field:%[^;]", p) <= 0)
- continue;
- sscanf(p, "__data_loc %[^;]", p);
-
- /* We found a field: description - see if we should skip it. */
- if (argc < 0)
- goto skip;
-
- /*
- * If the last character is not ']', the last token must be the
- * identifier name. Get rid of it.
- */
- l = strlen(p);
- if (p[l - 1] != ']') {
- char *q;
-
- if ((q = strrchr(p, ' ')))
- *q = '\0';
-
- l = q - p;
- memcpy(strp, p, l);
- } else {
- char *s, *q;
- int n;
-
- /*
- * The identifier is followed by at least one array
- * size specification. Find the beginning of the
- * sequence of (one or more) array size specifications.
- * We also skip any spaces in front of [ characters.
- */
- s = p + l - 1;
- for (;;) {
- while (*(--s) != '[') ;
- while (*(--s) == ' ') ;
- if (*s != ']')
- break;
- }
-
- /*
- * Insert a \0 byte right before the array size
- * specifications. The \0 byte overwrites the last
- * character of the identifier which is fine because we
- * know that the identifier is at least one character
- * long.
- */
- *(s++) = '\0';
- if ((q = strrchr(p, ' ')))
- *q = '\0';
-
- l = q - p;
- memcpy(strp, p, l);
- n = strlen(s);
- memcpy(strp + l, s, n);
- l += n;
- }
-
- argv[argc].mapping = argc;
- argv[argc].native = strp;
- argv[argc].xlate = NULL;
-
- strp += l + 1;
-
-skip:
- argc++;
- }
-
-done:
- *argcp = argc;
- *argvp = argv;
-
- return 0;
-}
-
-/*
- * Clean up the provider-specific data for a probe. This may be called with
- * provider-specific data that has not been attached to a probe (e.g. if the
- * creation of the actual probe failed).
- */
-void tp_probe_destroy(dtrace_hdl_t *dtp, void *datap)
-{
- dt_free(dtp, datap);
-}
-
-/*
- * Perform any provider specific cleanup for a probe that is being removed from
- * the framework.
- */
-void tp_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
-{
- tp_probe_t *datap = prp->prv_data;
-
- if (datap->event_fd != -1) {
- close(datap->event_fd);
- datap->event_fd = -1;
- }
-
- datap->event_id = -1;
-}
-
/*
* The PROBE_LIST file lists all tracepoints in a <group>:<name> format.
* We need to ignore these groups:
@@ -375,10 +110,10 @@ static int populate(dtrace_hdl_t *dtp)
strcmp(buf, UPROBES) == 0)
continue;
- if (tp_probe_insert(dtp, prv, prvname, buf, "", p))
+ if (dt_tp_probe_insert(dtp, prv, prvname, buf, "", p))
n++;
} else {
- if (tp_probe_insert(dtp, prv, prvname, modname, "",
+ if (dt_tp_probe_insert(dtp, prv, prvname, modname, "",
buf))
n++;
}
@@ -450,10 +185,13 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
FILE *f;
char fn[256];
int rc;
- tp_probe_t *datap = prp->prv_data;
+ tp_probe_t *tpp = prp->prv_data;
- /* if we have an event ID, no need to retrieve it again */
- if (datap->event_id != -1)
+ /*
+ * If we are already attached, there is no need to retrieve the probe
+ * info again.
+ */
+ if (dt_tp_is_attached(tpp))
return -1;
strcpy(fn, EVENTSFS);
@@ -466,7 +204,7 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
if (!f)
return -ENOENT;
- rc = tp_event_info(dtp, f, 0, datap, argcp, argvp);
+ rc = dt_tp_event_info(dtp, f, 0, tpp, argcp, argvp);
fclose(f);
return rc;
@@ -477,8 +215,8 @@ dt_provimpl_t dt_sdt = {
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
.populate = &populate,
.trampoline = &trampoline,
- .attach = &tp_attach,
+ .attach = &dt_tp_probe_attach,
.probe_info = &probe_info,
- .detach = &tp_detach,
- .probe_destroy = &tp_probe_destroy,
+ .detach = &dt_tp_probe_detach,
+ .probe_destroy = &dt_tp_probe_destroy,
};
diff --git a/libdtrace/dt_prov_syscall.c b/libdtrace/dt_prov_syscall.c
index aa426990..5b142733 100644
--- a/libdtrace/dt_prov_syscall.c
+++ b/libdtrace/dt_prov_syscall.c
@@ -116,12 +116,12 @@ static int populate(dtrace_hdl_t *dtp)
*/
if (!memcmp(p, ENTRY_PREFIX, sizeof(ENTRY_PREFIX) - 1)) {
p += sizeof(ENTRY_PREFIX) - 1;
- if (tp_probe_insert(dtp, prv, prvname, modname, p,
+ if (dt_tp_probe_insert(dtp, prv, prvname, modname, p,
"entry"))
n++;
} else if (!memcmp(p, EXIT_PREFIX, sizeof(EXIT_PREFIX) - 1)) {
p += sizeof(EXIT_PREFIX) - 1;
- if (tp_probe_insert(dtp, prv, prvname, modname, p,
+ if (dt_tp_probe_insert(dtp, prv, prvname, modname, p,
"return"))
n++;
}
@@ -201,10 +201,13 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
FILE *f;
char fn[256];
int rc;
- tp_probe_t *datap = prp->prv_data;
+ tp_probe_t *tpp = prp->prv_data;
- /* if we have an event ID, no need to retrieve it again */
- if (datap->event_id != -1)
+ /*
+ * If we are already attached, there is no need to retrieve the probe
+ * info again.
+ */
+ if (dt_tp_is_attached(tpp))
return -1;
/*
@@ -223,7 +226,7 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
if (!f)
return -ENOENT;
- rc = tp_event_info(dtp, f, SKIP_EXTRA_FIELDS, datap, argcp, argvp);
+ rc = dt_tp_event_info(dtp, f, SKIP_EXTRA_FIELDS, tpp, argcp, argvp);
fclose(f);
return rc;
@@ -234,8 +237,8 @@ dt_provimpl_t dt_syscall = {
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
.populate = &populate,
.trampoline = &trampoline,
- .attach = &tp_attach,
+ .attach = &dt_tp_probe_attach,
.probe_info = &probe_info,
- .detach = &tp_detach,
- .probe_destroy = &tp_probe_destroy,
+ .detach = &dt_tp_probe_detach,
+ .probe_destroy = &dt_tp_probe_destroy,
};
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index 8823ca52..02eca0ae 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -93,21 +93,25 @@ typedef struct dt_provider {
uint_t pv_flags; /* flags (see below) */
} dt_provider_t;
-typedef struct tp_probe {
- int event_id; /* tracepoint event id */
- int event_fd; /* tracepoint perf event fd */
-} tp_probe_t;
-
-extern int tp_attach(dtrace_hdl_t *dtp, const struct dt_probe *prp, int bpf_fd);
-extern tp_probe_t *tp_probe_create(dtrace_hdl_t *dtp);
-extern struct dt_probe *tp_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov,
- const char *prv, const char *mod,
- const char *fun, const char *prb);
-extern int tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip,
- tp_probe_t *datap, int *argcp, dt_argdesc_t **argvp);
-extern void tp_probe_destroy(dtrace_hdl_t *dtp, void *datap);
-extern void tp_detach(dtrace_hdl_t *dtp, const struct dt_probe *prb);
-
+typedef struct tp_probe tp_probe_t;
+
+extern tp_probe_t *dt_tp_alloc(dtrace_hdl_t *dtp);
+extern int dt_tp_attach(dtrace_hdl_t *dtp, tp_probe_t *tpp, int bpf_fd);
+extern int dt_tp_is_attached(const tp_probe_t *tpp);
+extern int dt_tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip,
+ tp_probe_t *tpp, int *argcp,
+ dt_argdesc_t **argvp);
+extern void dt_tp_detach(dtrace_hdl_t *dtp, tp_probe_t *tpp);
+extern void dt_tp_destroy(dtrace_hdl_t *dtp, tp_probe_t *tpp);
+
+extern struct dt_probe *dt_tp_probe_insert(dtrace_hdl_t *dtp,
+ dt_provider_t *prov,
+ const char *prv, const char *mod,
+ const char *fun, const char *prb);
+extern int dt_tp_probe_attach(dtrace_hdl_t *dtp, const struct dt_probe *prp,
+ int bpf_fd);
+extern void dt_tp_probe_detach(dtrace_hdl_t *dtp, const struct dt_probe *prp);
+extern void dt_tp_probe_destroy(dtrace_hdl_t *dtp, void *datap);
#define DT_PROVIDER_INTF 0x1 /* provider interface declaration */
#define DT_PROVIDER_IMPL 0x2 /* provider implementation is loaded */
diff --git a/libdtrace/dt_provider_tp.c b/libdtrace/dt_provider_tp.c
new file mode 100644
index 00000000..88740bbb
--- /dev/null
+++ b/libdtrace/dt_provider_tp.c
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ *
+ * Provider support code for tracepoint-based probes.
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/perf_event.h>
+
+#include "dt_bpf.h"
+#include "dt_provider.h"
+#include "dt_probe.h"
+#include "dt_impl.h"
+
+/*
+ * All tracing events (tracepoints) include a number of fields that we need to
+ * skip in the tracepoint format description. These fields are: common_type,
+ * common_flags, common_preempt_coint, and common_pid.
+ */
+#define SKIP_FIELDS_COUNT 4
+
+/*
+ * Tracepoint-specific probe data. This is allocated for every tracepoint
+ * based probe.
+ */
+struct tp_probe {
+ int event_id; /* tracepoint event id */
+ int event_fd; /* tracepoint perf event fd */
+};
+
+/*
+ * Allocate tracepoint-specific probe data.
+ */
+tp_probe_t *
+dt_tp_alloc(dtrace_hdl_t *dtp)
+{
+ tp_probe_t *tpp;
+
+ tpp = dt_zalloc(dtp, sizeof(tp_probe_t));
+ if (tpp == NULL)
+ return NULL;
+
+ tpp->event_fd = -1;
+ tpp->event_id = -1;
+
+ return tpp;
+}
+
+/*
+ * Attach the given (loaded) BPF program to the given tracepoint probe. This
+ * function performs the necessary steps for attaching the BPF program to a
+ * tracepoint based probe by opening a perf event for the tracepoint, and
+ * associating the BPF program with the perf event.
+ */
+int
+dt_tp_attach(dtrace_hdl_t *dtp, tp_probe_t *tpp, int bpf_fd)
+{
+ if (tpp->event_id == -1)
+ return 0;
+
+ if (tpp->event_fd == -1) {
+ int fd;
+ struct perf_event_attr attr = { 0, };
+
+ attr.type = PERF_TYPE_TRACEPOINT;
+ attr.sample_type = PERF_SAMPLE_RAW;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+ attr.config = tpp->event_id;
+
+ fd = perf_event_open(&attr, -1, 0, -1, 0);
+ if (fd < 0)
+ return dt_set_errno(dtp, errno);
+
+ tpp->event_fd = fd;
+ }
+
+ if (ioctl(tpp->event_fd, PERF_EVENT_IOC_SET_BPF, bpf_fd) < 0)
+ return dt_set_errno(dtp, errno);
+
+ return 0;
+}
+
+/*
+ * Return whether the tracepoint has already been attached.
+ */
+int
+dt_tp_is_attached(const tp_probe_t *tpp)
+{
+ return tpp->event_id != -1;
+}
+
+/*
+ * Parse a EVENTSFS/<group>/<event>/format file to determine the event id and
+ * the argument types.
+ *
+ * The event id is easy enough to parse out, because it appears on a line in
+ * the following format:
+ * ID: <num>
+ *
+ * The argument types are a bit more complicated. The basic format for each
+ * argument is:
+ * field:<var-decl>; offset:<num> size:<num> signed:(0|1);
+ * The <var-decl> may be prefixed by __data_loc, which is a tag that we can
+ * ignore. The <var-decl> does contain an identifier name that dtrace cannot
+ * cope with because it expects just the type specification. Getting rid of
+ * the identifier isn't as easy because it may be suffixed by one or more
+ * array dimension specifiers (and those are part of the type).
+ *
+ * All events include a number of fields that we are not interested and that
+ * need to be skipped (SKIP_FIELDS_COUNT). Callers of this function can
+ * specify an additional numbe of fields to skip (using the 'skip' parameter)
+ * before we get to the actual arguments.
+ */
+int
+dt_tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, tp_probe_t *tpp,
+ int *argcp, dt_argdesc_t **argvp)
+{
+ char buf[1024];
+ int argc;
+ size_t argsz = 0;
+ dt_argdesc_t *argv = NULL;
+ char *strp;
+
+ tpp->event_id = -1;
+
+ /*
+ * Let skip be the total number of fields to skip.
+ */
+ skip += SKIP_FIELDS_COUNT;
+
+ /*
+ * Pass 1:
+ * Determine the event id and the number of arguments (along with the
+ * total size of all type strings together).
+ */
+ argc = -skip;
+ while (fgets(buf, sizeof(buf), f)) {
+ char *p = buf;
+
+ if (sscanf(buf, "ID: %d\n", &tpp->event_id) == 1)
+ continue;
+
+ if (sscanf(buf, " field:%[^;]", p) <= 0)
+ continue;
+ sscanf(p, "__data_loc %[^;]", p);
+
+ /* We found a field: description - see if we should skip it. */
+ if (argc++ < 0)
+ continue;
+
+ /*
+ * We over-estimate the space needed (pass 2 will strip off the
+ * identifier name).
+ */
+ argsz += strlen(p) + 1;
+ }
+
+ /*
+ * If we saw less fields than expected, we flag an error.
+ * If we are not interested in arguments, we are done.
+ * If there are no arguments, we are done.
+ */
+ if (argc < 0)
+ return -EINVAL;
+ if (argcp == NULL)
+ return 0;
+ if (argc == 0)
+ goto done;
+
+ argv = dt_zalloc(dtp, argc * sizeof(dt_argdesc_t) + argsz);
+ if (!argv)
+ return -ENOMEM;
+ strp = (char *)(argv + argc);
+
+ /*
+ * Pass 2:
+ * Fill in the actual argument datatype strings.
+ */
+ rewind(f);
+ argc = -skip;
+ while (fgets(buf, sizeof(buf), f)) {
+ char *p = buf;
+ size_t l;
+
+ if (sscanf(buf, " field:%[^;]", p) <= 0)
+ continue;
+ sscanf(p, "__data_loc %[^;]", p);
+
+ /* We found a field: description - see if we should skip it. */
+ if (argc < 0)
+ goto skip;
+
+ /*
+ * If the last character is not ']', the last token must be the
+ * identifier name. Get rid of it.
+ */
+ l = strlen(p);
+ if (p[l - 1] != ']') {
+ char *q;
+
+ if ((q = strrchr(p, ' ')))
+ *q = '\0';
+
+ l = q - p;
+ memcpy(strp, p, l);
+ } else {
+ char *s, *q;
+ int n;
+
+ /*
+ * The identifier is followed by at least one array
+ * size specification. Find the beginning of the
+ * sequence of (one or more) array size specifications.
+ * We also skip any spaces in front of [ characters.
+ */
+ s = p + l - 1;
+ for (;;) {
+ while (*(--s) != '[') ;
+ while (*(--s) == ' ') ;
+ if (*s != ']')
+ break;
+ }
+
+ /*
+ * Insert a \0 byte right before the array size
+ * specifications. The \0 byte overwrites the last
+ * character of the identifier which is fine because we
+ * know that the identifier is at least one character
+ * long.
+ */
+ *(s++) = '\0';
+ if ((q = strrchr(p, ' ')))
+ *q = '\0';
+
+ l = q - p;
+ memcpy(strp, p, l);
+ n = strlen(s);
+ memcpy(strp + l, s, n);
+ l += n;
+ }
+
+ argv[argc].mapping = argc;
+ argv[argc].native = strp;
+ argv[argc].xlate = NULL;
+
+ strp += l + 1;
+
+skip:
+ argc++;
+ }
+
+done:
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+/*
+ * Detach from a tracepoint for a tracepoint-based probe. The caller should
+ * still call dt_tp_destroy() to free the tracepointer-specific probe data.
+ */
+void
+dt_tp_detach(dtrace_hdl_t *dtp, tp_probe_t *tpp)
+{
+ if (tpp->event_fd != -1) {
+ close(tpp->event_fd);
+ tpp->event_fd = -1;
+ }
+
+ tpp->event_id = -1;
+}
+
+/*
+ * Clean up the provider-specific data for a probe. This may be called with
+ * provider-specific data that has not been attached to a probe (e.g. if the
+ * creation of the actual probe failed).
+ */
+void
+dt_tp_destroy(dtrace_hdl_t *dtp, tp_probe_t *tpp)
+{
+ dt_free(dtp, tpp);
+}
+
+/*
+ * Create a tracepoint-based probe. This function is called from any provider
+ * that handles tracepoint-based probes. It allocates provider-specific data
+ * for the probe, and adds the probe to the framework.
+ */
+dt_probe_t *
+dt_tp_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov, const char *prv,
+ const char *mod, const char *fun, const char *prb)
+{
+ tp_probe_t *tpp;
+
+ tpp = dt_tp_alloc(dtp);
+ if (tpp == NULL)
+ return NULL;
+
+ return dt_probe_insert(dtp, prov, prv, mod, fun, prb, tpp);
+}
+
+/*
+ * Convenience function for basic tracepoint-based probe attach.
+ */
+int
+dt_tp_probe_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
+{
+ return dt_tp_attach(dtp, prp->prv_data, bpf_fd);
+}
+
+/*
+ * Convenience function for basic tracepoint-based probe detach.
+ */
+void
+dt_tp_probe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
+{
+ dt_tp_detach(dtp, prp->prv_data);
+}
+
+/*
+ * Convenience function for probe cleanup for tracepoint-based probes.
+ */
+void
+dt_tp_probe_destroy(dtrace_hdl_t *dtp, void *datap)
+{
+ dt_tp_destroy(dtp, datap);
+}
--
2.28.0
More information about the DTrace-devel
mailing list