Skip to content

Commit

Permalink
sdt: consolidate the SDT infrastructure in its own provider framework
Browse files Browse the repository at this point in the history
The various SDT providers are implemented using the same underlying
mechanisms.  A common SDT infrastructure avoids code duplication.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Reviewed-by: Eugene Loh <eugene.loh@oracle.com>
  • Loading branch information
kvanhees committed May 25, 2023
1 parent b739f88 commit cbee253
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 0 deletions.
1 change: 1 addition & 0 deletions libdtrace/Build
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \
dt_prov_syscall.c \
dt_prov_uprobe.c \
dt_provider.c \
dt_provider_sdt.c \
dt_provider_tp.c \
dt_regset.c \
dt_string.c \
Expand Down
165 changes: 165 additions & 0 deletions libdtrace/dt_provider_sdt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 2021, 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.
*
* Provider support code for tracepoint-based probes.
*/
#include <errno.h>
#include <ctype.h>

#include "dt_provider_sdt.h"
#include "dt_probe.h"
#include "dt_impl.h"

typedef struct sdt_data {
const probe_dep_t *probes;
const probe_arg_t *probe_args;
} sdt_data_t;

/*
* Create an SDT provider and populate it from the provided list of probes
* (with dependency information) and probe argument data.
*/
int
dt_sdt_populate(dtrace_hdl_t *dtp, const char *prvname, const char *modname,
const dt_provimpl_t *ops, const dtrace_pattr_t *pattr,
const probe_arg_t *probe_args, const probe_dep_t *probes)
{
dt_provider_t *prv;
const probe_arg_t *arg;
sdt_data_t *sdp;
int n = 0;

sdp = dt_alloc(dtp, sizeof(sdt_data_t));
if (sdp == NULL)
return 0;

sdp->probes = probes;
sdp->probe_args = probe_args;
prv = dt_provider_create(dtp, prvname, ops, pattr, sdp);
if (prv == NULL)
return 0;

/*
* Create SDT probes based on the probe_args list. Since each probe
* will have at least one entry (with argno == 0), we can use those
* entries to identify the probe names.
*/
for (arg = &probe_args[0]; arg->name != NULL; arg++) {
if (arg->argno == 0 &&
dt_probe_insert(dtp, prv, prvname, modname, "", arg->name,
NULL))
n++;
}

return n;
}

/*
* Add an SDT probe as a dependent probe for an underlying probe that has been
* provided by another provider.
*/
static int
add_dependency(dtrace_hdl_t *dtp, dt_probe_t *uprp, void *arg)
{
dt_probe_t *prp = arg;

dt_probe_add_dependent(dtp, uprp, prp);
dt_probe_enable(dtp, uprp);

return 0;
}

/*
* Enable an SDT probe.
*/
void
dt_sdt_enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
{
const probe_dep_t *dep;

for (dep = ((sdt_data_t *)prp->prov->prv_data)->probes;
dep->name != NULL; dep++) {
dtrace_probedesc_t pd;

if (strcmp(prp->desc->prb, dep->name) != 0)
continue;

if (dtrace_str2desc(dtp, dep->spec, dep->str, &pd) == -1)
return;

dt_probe_iter(dtp, &pd, add_dependency, NULL, prp);

free((void *)pd.prv);
free((void *)pd.mod);
free((void *)pd.fun);
free((void *)pd.prb);
}

/*
* Finally, ensure we're in the list of enablings as well.
* (This ensures that, among other things, the probes map
* gains entries for us.)
*/
if (!dt_in_list(&dtp->dt_enablings, prp))
dt_list_append(&dtp->dt_enablings, prp);
}

/*
* Populate the probe arguments for the given probe.
*/
int
dt_sdt_probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp, int *argcp,
dt_argdesc_t **argvp)
{
int i;
int pidx = -1;
int argc = 0;
dt_argdesc_t *argv = NULL;
const probe_arg_t *probe_args =
((sdt_data_t *)prp->prov->prv_data)->probe_args;
const probe_arg_t *arg;

for (arg = &probe_args[i = 0]; arg->name != NULL; arg++, i++) {
if (strcmp(arg->name, prp->desc->prb) == 0) {
if (pidx == -1) {
pidx = i;

if (arg->argdesc.native == NULL)
break;
}

argc++;
}
}

if (argc == 0)
goto done;

argv = dt_zalloc(dtp, argc * sizeof(dt_argdesc_t));
if (!argv)
return -ENOMEM;

for (i = pidx; i < pidx + argc; i++) {
const probe_arg_t *arg = &probe_args[i];

argv[arg->argno] = arg->argdesc;
}

done:
*argcp = argc;
*argvp = argv;

return 0;
}

/*
* Clean up SDT-specific data.
*/
void
dt_sdt_destroy(dtrace_hdl_t *dtp, void *datap)
{
dt_free(dtp, datap);
}
61 changes: 61 additions & 0 deletions libdtrace/dt_provider_sdt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 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.
*/

#ifndef _DT_PROVIDER_SDT_H
#define _DT_PROVIDER_SDT_H

#include <sys/dtrace_types.h>
#include <dt_provider.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
* Probe dependencies
*
* SDT probes are implemented using probes made available by other providers.
* THe probe dependency table associates each SDT probe with one or more probe
* specifications (possibly containing wildcards). Each matching probe will
* have SDT lockstat probe added as a dependent probe.
*/
typedef struct probe_dep {
const char *name; /* probe name */
dtrace_probespec_t spec; /* spec type */
const char *str; /* spec string */
} probe_dep_t;

/*
* Probe signature specifications
*
* This table *must* group the arguments of probes. I.e. the arguments of a
* given probe must be listed in consecutive records.
*
* A single probe entry that mentions only name of the probe indicates a probe
* that provides no arguments.
*/
typedef struct probe_arg {
const char *name; /* name of probe */
int argno; /* argument number */
dt_argdesc_t argdesc; /* argument description */
} probe_arg_t;

extern int dt_sdt_populate(dtrace_hdl_t *dtp, const char *prvname,
const char *modname, const dt_provimpl_t *ops,
const dtrace_pattr_t *pattr,
const probe_arg_t *probe_args,
const probe_dep_t *probes);
extern void dt_sdt_enable(dtrace_hdl_t *dtp, struct dt_probe *prp);
extern int dt_sdt_probe_info(dtrace_hdl_t *dtp, const struct dt_probe *prp,
int *argcp, dt_argdesc_t **argvp);
extern void dt_sdt_destroy(dtrace_hdl_t *dtp, void *datap);

#ifdef __cplusplus
}
#endif

#endif /* _DT_PROVIDER_SDT_H */

0 comments on commit cbee253

Please sign in to comment.