1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
/*
* Oracle Linux DTrace.
* Copyright (c) 2021, 2024, 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 dt_set_errno(dtp, EDT_NOMEM);
sdp->probes = probes;
sdp->probe_args = probe_args;
prv = dt_provider_create(dtp, prvname, ops, pattr, sdp);
if (prv == NULL)
return -1; /* errno already set */
/*
* 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 the dependency specifies a minimum and/or maximum kernel
* version, skip this dependency if the runtime kernel version
* does not fall in the specified range.
*/
if (dep->kver_min && dtp->dt_kernver < dep->kver_min)
continue;
if (dep->kver_max && dtp->dt_kernver > dep->kver_max)
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];
const dt_argdesc_t *argd = &arg->argdesc;
dt_argdesc_t *parg = &argv[arg->argno];
*parg = *argd;
if (argd->native)
parg->native = strdup(argd->native);
if (argd->xlate)
parg->xlate = strdup(argd->xlate);
}
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);
}
|