[DTrace-devel] [PATCH v2 04/04] rawtp: retrieve probe arguments from CTF data

Kris Van Hees kris.van.hees at oracle.com
Thu Nov 30 20:55:45 UTC 2023


On Thu, Nov 30, 2023 at 08:26:33PM +0000, Nick Alcock wrote:
> On 30 Nov 2023, Kris Van Hees via DTrace-devel verbalised:
> 
> > We were determining the number of arguments using a trial-and-error
> > approach with minimal BPF programs.  If there is CTF type data for
> > the raw tracepoints (in the form of a function prototype), we use
> > that because it also gives us the types of the arguments.
> 
> Nice!
> 
> > Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> 
> Reviewed-by: Nick Alcock <nick.alcock at oracle.com>
> 
> with one memory leak fixed (see below).
> 
> > -static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
> > -		      int *argcp, dt_argdesc_t **argvp)
> > +/*
> > + * If there is no btf_trace_* prototype available in CTF, we can still probe
> > + * the number of available argument for a raw tracepoint by means of a trial
> > + * and error loop to see what the highest argument index is that the BPF
> > + * verifier allows us to load from.
> 
> Ew! :) but it's what we did before and it's a useful fallback in the
> absence of enough type info (OL7, right? dwarf2ctf doesn't emit function
> prototypes at all...)
> 
> > +static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
> > +		      int *argcp, dt_argdesc_t **argvp)
> > +{
> > +#ifdef HAVE_LIBCTF
> 
> ... yeah, OL7 :) it amazes me that Solaris libctf had CTF_K_FUNCTION but
> no way to get any actual *info* on CTF_K_FUNCTIONs...
> 
> > +	int			rc, i;
> > +	char			*str;
> > +	ctf_dict_t		*ctfp;
> > +	ctf_id_t		type;
> > +	int			argc = 0;
> > +	dt_argdesc_t		*argv = NULL;
> > +	ctf_funcinfo_t		fi;
> > +	dtrace_typeinfo_t	sym;
> > +	ctf_id_t		*argt;
> > +
> > +	if (asprintf(&str, "btf_trace_%s", prp->desc->prb) == -1)
> > +		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
> > +	rc = dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, str, &sym);
> > +	free(str);
> > +	if (rc ||
> > +	    ctf_type_kind(sym.dtt_ctfp, sym.dtt_type) != CTF_K_TYPEDEF)
> > +		goto use_alt;
> > +	ctfp = sym.dtt_ctfp;
> > +	type = ctf_type_reference(ctfp, sym.dtt_type);
> > +	if (ctf_type_kind(ctfp, type) != CTF_K_POINTER)
> > +		goto use_alt;
> > +	type = ctf_type_reference(ctfp, type);
> > +	if (ctf_type_kind(ctfp, type) != CTF_K_FUNCTION)
> > +		goto use_alt;
> 
> ... I guess that handles -1 just as well, and no matter what the error
> (or if it's just not a pointer) you want to switch to the other
> resolution method :)
> 
> > +	if (ctf_func_type_info(ctfp, type, &fi) == -1)
> > +		goto use_alt;
> > +
> > +	/*
> > +	 * Raw tracepoints have an extra first argument for the context, so we
> > +	 * need to skip that.  (We also handle the case where fi.ctc_argc is 0
> > +	 * even though that is not supposed to happen.)
> > +	 */
> 
> It could perfectly well happen if there is some *other* function pointer
> called btf_trace_foobar that isn't actually a tracepoint (unlikely,
> sure, but no more unlikely than non-function-pointer-typedef
> btf_trace_*s, I'd say.)
> 
> I agree that there's no point handling the case where it's a function
> pointer and the first arg is something else -- you could in theory
> verify that the first arg is a context, but if this gets common enough
> that we actually hit that case it'll be pretty obvious and we can add
> suitable code then.
> 
> > +	argc = fi.ctc_argc;
> > +	argt = dt_calloc(dtp, argc, sizeof(ctf_id_t));
> > +	ctf_func_type_args(ctfp, type, argc, argt);
> > +
> > +	argc--;
> > +	argv = dt_zalloc(dtp, argc * sizeof(dt_argdesc_t));
> 
> I guess if there's an allocation failure we just crash? dt_[cz]alloc
> return NULL on failure... (I know we don't handle this very well
> anywhere, so I'm happy to ignore this.)

I'll add a test to handle that.  We should.

> > +	for (i = 0; i < argc; i++) {
> > +		char	n[DT_TYPE_NAMELEN];
> 
> #define        DT_TYPE_NAMELEN        128
> 
> ugh. I'm adding extirpating *that* to my todo list. :)
> 
> (for now it's all you can do though.)
> 
> > +		ctf_type_name(ctfp, argt[i + 1], n, sizeof(n));
> > +		argv[i].mapping = i;
> > +		argv[i].native = strdup(n);
> 
> Hm. So this is assigned to the dt_probe_t's argv element, which is freed
> in dt_probe_destroy() -- but unless it's done in an earlier patch in
> this series, nothing frees dt_probe_t.argv[i].native, only the argv
> array itself...
> 
> ... with that caveat, this looks good.

That is a pre-existing issue with argument type data for probes.  Fixing that
is not in the scope of this patch.  I'll work on a more generic solution for
that because it is (1) a long-standing issue in DTrace (pre-dating the Linux
version), and (2) an sisue at the level of probes in general - not a particular
provider.



More information about the DTrace-devel mailing list