Skip to content

Commit b1d1e90

Browse files
committed
tracing/probes: Support BTF argument on module functions
Since the btf returned from bpf_get_btf_vmlinux() only covers functions in the vmlinux, BTF argument is not available on the functions in the modules. Use bpf_find_btf_id() instead of bpf_get_btf_vmlinux()+btf_find_name_kind() so that BTF argument can find the correct struct btf and btf_type in it. With this fix, fprobe events can use `$arg*` on module functions as below # grep nf_log_ip_packet /proc/kallsyms ffffffffa0005c00 t nf_log_ip_packet [nf_log_syslog] ffffffffa0005bf0 t __pfx_nf_log_ip_packet [nf_log_syslog] # echo 'f nf_log_ip_packet $arg*' > dynamic_events # cat dynamic_events f:fprobes/nf_log_ip_packet__entry nf_log_ip_packet net=net pf=pf hooknum=hooknum skb=skb in=in out=out loginfo=loginfo prefix=prefix To support the module's btf which is removable, the struct btf needs to be ref-counted. So this also records the btf in the traceprobe_parse_context and returns the refcount when the parse has done. Link: https://lore.kernel.org/all/169272154223.160970.3507930084247934031.stgit@devnote2/ Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent f8bbf8b commit b1d1e90

File tree

8 files changed

+75
-49
lines changed

8 files changed

+75
-49
lines changed

include/linux/btf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
211211
int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec);
212212
bool btf_type_is_void(const struct btf_type *t);
213213
s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind);
214+
s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p);
214215
const struct btf_type *btf_type_skip_modifiers(const struct btf *btf,
215216
u32 id, u32 *res_id);
216217
const struct btf_type *btf_type_resolve_ptr(const struct btf *btf,

kernel/bpf/btf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
552552
return -ENOENT;
553553
}
554554

555-
static s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
555+
s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
556556
{
557557
struct btf *btf;
558558
s32 ret;

kernel/trace/trace_eprobe.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -807,13 +807,11 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
807807
int ret;
808808

809809
ret = traceprobe_parse_probe_arg(&ep->tp, i, argv[i], &ctx);
810-
if (ret)
811-
return ret;
812-
813810
/* Handle symbols "@" */
814811
if (!ret)
815812
ret = traceprobe_update_arg(&ep->tp.args[i]);
816813

814+
traceprobe_finish_parse(&ctx);
817815
return ret;
818816
}
819817

kernel/trace/trace_fprobe.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
10961096
}
10971097

10981098
out:
1099+
traceprobe_finish_parse(&ctx);
10991100
trace_probe_log_clear();
11001101
kfree(new_argv);
11011102
kfree(symbol);

kernel/trace/trace_kprobe.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
907907
}
908908

909909
out:
910+
traceprobe_finish_parse(&ctx);
910911
trace_probe_log_clear();
911912
kfree(new_argv);
912913
kfree(symbol);

kernel/trace/trace_probe.c

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,6 @@ static int parse_trace_event_arg(char *arg, struct fetch_insn *code,
304304

305305
#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS
306306

307-
static struct btf *traceprobe_get_btf(void)
308-
{
309-
struct btf *btf = bpf_get_btf_vmlinux();
310-
311-
if (IS_ERR_OR_NULL(btf))
312-
return NULL;
313-
314-
return btf;
315-
}
316-
317307
static u32 btf_type_int(const struct btf_type *t)
318308
{
319309
return *(u32 *)(t + 1);
@@ -371,42 +361,49 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
371361
return NULL;
372362
}
373363

374-
static const struct btf_type *find_btf_func_proto(const char *funcname)
364+
static const struct btf_type *find_btf_func_proto(const char *funcname,
365+
struct btf **btf_p)
375366
{
376-
struct btf *btf = traceprobe_get_btf();
377367
const struct btf_type *t;
368+
struct btf *btf = NULL;
378369
s32 id;
379370

380-
if (!btf || !funcname)
371+
if (!funcname)
381372
return ERR_PTR(-EINVAL);
382373

383-
id = btf_find_by_name_kind(btf, funcname, BTF_KIND_FUNC);
374+
id = bpf_find_btf_id(funcname, BTF_KIND_FUNC, &btf);
384375
if (id <= 0)
385376
return ERR_PTR(-ENOENT);
386377

387378
/* Get BTF_KIND_FUNC type */
388379
t = btf_type_by_id(btf, id);
389380
if (!t || !btf_type_is_func(t))
390-
return ERR_PTR(-ENOENT);
381+
goto err;
391382

392383
/* The type of BTF_KIND_FUNC is BTF_KIND_FUNC_PROTO */
393384
t = btf_type_by_id(btf, t->type);
394385
if (!t || !btf_type_is_func_proto(t))
395-
return ERR_PTR(-ENOENT);
386+
goto err;
396387

388+
*btf_p = btf;
397389
return t;
390+
391+
err:
392+
btf_put(btf);
393+
return ERR_PTR(-ENOENT);
398394
}
399395

400396
static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
401-
bool tracepoint)
397+
struct btf **btf_p, bool tracepoint)
402398
{
403399
const struct btf_param *param;
404400
const struct btf_type *t;
401+
struct btf *btf;
405402

406403
if (!funcname || !nr)
407404
return ERR_PTR(-EINVAL);
408405

409-
t = find_btf_func_proto(funcname);
406+
t = find_btf_func_proto(funcname, &btf);
410407
if (IS_ERR(t))
411408
return (const struct btf_param *)t;
412409

@@ -419,29 +416,37 @@ static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr
419416
param++;
420417
}
421418

422-
if (*nr > 0)
419+
if (*nr > 0) {
420+
*btf_p = btf;
423421
return param;
424-
else
425-
return NULL;
422+
}
423+
424+
btf_put(btf);
425+
return NULL;
426+
}
427+
428+
static void clear_btf_context(struct traceprobe_parse_context *ctx)
429+
{
430+
if (ctx->btf) {
431+
btf_put(ctx->btf);
432+
ctx->btf = NULL;
433+
ctx->params = NULL;
434+
ctx->nr_params = 0;
435+
}
426436
}
427437

428438
static int parse_btf_arg(const char *varname, struct fetch_insn *code,
429439
struct traceprobe_parse_context *ctx)
430440
{
431-
struct btf *btf = traceprobe_get_btf();
432441
const struct btf_param *params;
433442
int i;
434443

435-
if (!btf) {
436-
trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
437-
return -EOPNOTSUPP;
438-
}
439-
440444
if (WARN_ON_ONCE(!ctx->funcname))
441445
return -EINVAL;
442446

443447
if (!ctx->params) {
444-
params = find_btf_func_param(ctx->funcname, &ctx->nr_params,
448+
params = find_btf_func_param(ctx->funcname,
449+
&ctx->nr_params, &ctx->btf,
445450
ctx->flags & TPARG_FL_TPOINT);
446451
if (IS_ERR_OR_NULL(params)) {
447452
trace_probe_log_err(ctx->offset, NO_BTF_ENTRY);
@@ -452,7 +457,7 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
452457
params = ctx->params;
453458

454459
for (i = 0; i < ctx->nr_params; i++) {
455-
const char *name = btf_name_by_offset(btf, params[i].name_off);
460+
const char *name = btf_name_by_offset(ctx->btf, params[i].name_off);
456461

457462
if (name && !strcmp(name, varname)) {
458463
code->op = FETCH_OP_ARG;
@@ -470,7 +475,7 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
470475
static const struct fetch_type *parse_btf_arg_type(int arg_idx,
471476
struct traceprobe_parse_context *ctx)
472477
{
473-
struct btf *btf = traceprobe_get_btf();
478+
struct btf *btf = ctx->btf;
474479
const char *typestr = NULL;
475480

476481
if (btf && ctx->params) {
@@ -485,14 +490,17 @@ static const struct fetch_type *parse_btf_arg_type(int arg_idx,
485490
static const struct fetch_type *parse_btf_retval_type(
486491
struct traceprobe_parse_context *ctx)
487492
{
488-
struct btf *btf = traceprobe_get_btf();
489493
const char *typestr = NULL;
490494
const struct btf_type *t;
495+
struct btf *btf;
491496

492-
if (btf && ctx->funcname) {
493-
t = find_btf_func_proto(ctx->funcname);
494-
if (!IS_ERR(t))
497+
if (ctx->funcname) {
498+
/* Do not use ctx->btf, because it must be used with ctx->param */
499+
t = find_btf_func_proto(ctx->funcname, &btf);
500+
if (!IS_ERR(t)) {
495501
typestr = type_from_btf_id(btf, t->type);
502+
btf_put(btf);
503+
}
496504
}
497505

498506
return find_fetch_type(typestr, ctx->flags);
@@ -501,21 +509,25 @@ static const struct fetch_type *parse_btf_retval_type(
501509
static bool is_btf_retval_void(const char *funcname)
502510
{
503511
const struct btf_type *t;
512+
struct btf *btf;
513+
bool ret;
504514

505-
t = find_btf_func_proto(funcname);
515+
t = find_btf_func_proto(funcname, &btf);
506516
if (IS_ERR(t))
507517
return false;
508518

509-
return t->type == 0;
519+
ret = (t->type == 0);
520+
btf_put(btf);
521+
return ret;
510522
}
511523
#else
512-
static struct btf *traceprobe_get_btf(void)
524+
static void clear_btf_context(struct traceprobe_parse_context *ctx)
513525
{
514-
return NULL;
526+
ctx->btf = NULL;
515527
}
516528

517529
static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
518-
bool tracepoint)
530+
struct btf **btf_p, bool tracepoint)
519531
{
520532
return ERR_PTR(-EOPNOTSUPP);
521533
}
@@ -1231,15 +1243,14 @@ static int sprint_nth_btf_arg(int idx, const char *type,
12311243
char *buf, int bufsize,
12321244
struct traceprobe_parse_context *ctx)
12331245
{
1234-
struct btf *btf = traceprobe_get_btf();
12351246
const char *name;
12361247
int ret;
12371248

12381249
if (idx >= ctx->nr_params) {
12391250
trace_probe_log_err(0, NO_BTFARG);
12401251
return -ENOENT;
12411252
}
1242-
name = btf_name_by_offset(btf, ctx->params[idx].name_off);
1253+
name = btf_name_by_offset(ctx->btf, ctx->params[idx].name_off);
12431254
if (!name) {
12441255
trace_probe_log_err(0, NO_BTF_ENTRY);
12451256
return -ENOENT;
@@ -1271,7 +1282,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
12711282
return NULL;
12721283
}
12731284

1274-
params = find_btf_func_param(ctx->funcname, &nr_params,
1285+
params = find_btf_func_param(ctx->funcname, &nr_params, &ctx->btf,
12751286
ctx->flags & TPARG_FL_TPOINT);
12761287
if (IS_ERR_OR_NULL(params)) {
12771288
if (args_idx != -1) {
@@ -1337,6 +1348,11 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
13371348
return ERR_PTR(ret);
13381349
}
13391350

1351+
void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)
1352+
{
1353+
clear_btf_context(ctx);
1354+
}
1355+
13401356
int traceprobe_update_arg(struct probe_arg *arg)
13411357
{
13421358
struct fetch_insn *code = arg->code;

kernel/trace/trace_probe.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,9 +383,11 @@ static inline bool tparg_is_function_entry(unsigned int flags)
383383

384384
struct traceprobe_parse_context {
385385
struct trace_event_call *event;
386-
const struct btf_param *params;
387-
s32 nr_params;
388-
const char *funcname;
386+
/* BTF related parameters */
387+
const char *funcname; /* Function name in BTF */
388+
const struct btf_param *params; /* Parameter of the function */
389+
s32 nr_params; /* The number of the parameters */
390+
struct btf *btf; /* The BTF to be used */
389391
unsigned int flags;
390392
int offset;
391393
};
@@ -400,6 +402,12 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
400402
extern int traceprobe_update_arg(struct probe_arg *arg);
401403
extern void traceprobe_free_probe_arg(struct probe_arg *arg);
402404

405+
/*
406+
* If either traceprobe_parse_probe_arg() or traceprobe_expand_meta_args() is called,
407+
* this MUST be called for clean up the context and return a resource.
408+
*/
409+
void traceprobe_finish_parse(struct traceprobe_parse_context *ctx);
410+
403411
extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
404412
int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
405413
char *buf, int offset);

kernel/trace/trace_uprobe.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
693693

694694
trace_probe_log_set_index(i + 2);
695695
ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx);
696+
traceprobe_finish_parse(&ctx);
696697
if (ret)
697698
goto error;
698699
}

0 commit comments

Comments
 (0)