[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