Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'probes-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull probes updates from Masami Hiramatsu:

- kprobes: use struct_size() for variable size kretprobe_instance data
structure.

- eprobe: Simplify trace_eprobe list iteration.

- probe events: Data structure field access support on BTF argument.

- Update BTF argument support on the functions in the kernel
loadable modules (only loaded modules are supported).

- Move generic BTF access function (search function prototype and
get function parameters) to a separated file.

- Add a function to search a member of data structure in BTF.

- Support accessing BTF data structure member from probe args by
C-like arrow('->') and dot('.') operators. e.g.
't sched_switch next=next->pid vruntime=next->se.vruntime'

- Support accessing BTF data structure member from $retval. e.g.
'f getname_flags%return +0($retval->name):string'

- Add string type checking if BTF type info is available. This will
reject if user specify ":string" type for non "char pointer"
type.

- Automatically assume the fprobe event as a function return event
if $retval is used.

- selftests/ftrace: Add BTF data field access test cases.

- Documentation: Update fprobe event example with BTF data field.

* tag 'probes-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
Documentation: tracing: Update fprobe event example with BTF field
selftests/ftrace: Add BTF fields access testcases
tracing/fprobe-event: Assume fprobe is a return event by $retval
tracing/probes: Add string type check with BTF
tracing/probes: Support BTF field access from $retval
tracing/probes: Support BTF based data structure field access
tracing/probes: Add a function to search a member of a struct/union
tracing/probes: Move finding func-proto API and getting func-param API to trace_btf
tracing/probes: Support BTF argument on module functions
tracing/eprobe: Iterate trace_eprobe directly
kernel: kprobes: Use struct_size()

+671 -198
+46 -18
Documentation/trace/fprobetrace.rst
··· 79 79 f:fprobes/myprobe vfs_read count=count pos=pos 80 80 81 81 It also chooses the fetch type from BTF information. For example, in the above 82 - example, the ``count`` is unsigned long, and the ``pos`` is a pointer. Thus, both 83 - are converted to 64bit unsigned long, but only ``pos`` has "%Lx" print-format as 84 - below :: 82 + example, the ``count`` is unsigned long, and the ``pos`` is a pointer. Thus, 83 + both are converted to 64bit unsigned long, but only ``pos`` has "%Lx" 84 + print-format as below :: 85 85 86 86 # cat events/fprobes/myprobe/format 87 87 name: myprobe ··· 105 105 # cat dynamic_events 106 106 f:fprobes/myprobe vfs_read file=file buf=buf count=count pos=pos 107 107 108 - BTF also affects the ``$retval``. If user doesn't set any type, the retval type is 109 - automatically picked from the BTF. If the function returns ``void``, ``$retval`` 110 - is rejected. 108 + BTF also affects the ``$retval``. If user doesn't set any type, the retval 109 + type is automatically picked from the BTF. If the function returns ``void``, 110 + ``$retval`` is rejected. 111 + 112 + You can access the data fields of a data structure using allow operator ``->`` 113 + (for pointer type) and dot operator ``.`` (for data structure type.):: 114 + 115 + # echo 't sched_switch preempt prev_pid=prev->pid next_pid=next->pid' >> dynamic_events 116 + 117 + The field access operators, ``->`` and ``.`` can be combined for accessing deeper 118 + members and other structure members pointed by the member. e.g. ``foo->bar.baz->qux`` 119 + If there is non-name union member, you can directly access it as the C code does. 120 + For example:: 121 + 122 + struct { 123 + union { 124 + int a; 125 + int b; 126 + }; 127 + } *foo; 128 + 129 + To access ``a`` and ``b``, use ``foo->a`` and ``foo->b`` in this case. 130 + 131 + This data field access is available for the return value via ``$retval``, 132 + e.g. ``$retval->name``. 133 + 134 + For these BTF arguments and fields, ``:string`` and ``:ustring`` change the 135 + behavior. If these are used for BTF argument or field, it checks whether 136 + the BTF type of the argument or the data field is ``char *`` or ``char []``, 137 + or not. If not, it rejects applying the string types. Also, with the BTF 138 + support, you don't need a memory dereference operator (``+0(PTR)``) for 139 + accessing the string pointed by a ``PTR``. It automatically adds the memory 140 + dereference operator according to the BTF type. e.g. :: 141 + 142 + # echo 't sched_switch prev->comm:string' >> dynamic_events 143 + # echo 'f getname_flags%return $retval->name:string' >> dynamic_events 144 + 145 + The ``prev->comm`` is an embedded char array in the data structure, and 146 + ``$retval->name`` is a char pointer in the data structure. But in both 147 + cases, you can use ``:string`` type to get the string. 148 + 111 149 112 150 Usage examples 113 151 -------------- ··· 199 161 structure pointed by the ``prev`` and ``next`` arguments. 200 162 201 163 For example, usually ``task_struct::start_time`` is not traced, but with this 202 - traceprobe event, you can trace it as below. 164 + traceprobe event, you can trace that field as below. 203 165 :: 204 166 205 - # echo 't sched_switch comm=+1896(next):string start_time=+1728(next):u64' > dynamic_events 167 + # echo 't sched_switch comm=next->comm:string next->start_time' > dynamic_events 206 168 # head -n 20 trace | tail 207 169 # TASK-PID CPU# ||||| TIMESTAMP FUNCTION 208 170 # | | | ||||| | | ··· 214 176 <idle>-0 [000] d..3. 5606.690317: sched_switch: (__probestub_sched_switch+0x4/0x10) comm="kworker/0:1" usage=1 start_time=137000000 215 177 kworker/0:1-14 [000] d..3. 5606.690339: sched_switch: (__probestub_sched_switch+0x4/0x10) comm="swapper/0" usage=2 start_time=0 216 178 <idle>-0 [000] d..3. 5606.692368: sched_switch: (__probestub_sched_switch+0x4/0x10) comm="kworker/0:1" usage=1 start_time=137000000 217 - 218 - Currently, to find the offset of a specific field in the data structure, 219 - you need to build kernel with debuginfo and run `perf probe` command with 220 - `-D` option. e.g. 221 - :: 222 - 223 - # perf probe -D "__probestub_sched_switch next->comm:string next->start_time" 224 - p:probe/__probestub_sched_switch __probestub_sched_switch+0 comm=+1896(%cx):string start_time=+1728(%cx):u64 225 - 226 - And replace the ``%cx`` with the ``next``.
+1
include/linux/btf.h
··· 209 209 int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec); 210 210 bool btf_type_is_void(const struct btf_type *t); 211 211 s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind); 212 + s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p); 212 213 const struct btf_type *btf_type_skip_modifiers(const struct btf *btf, 213 214 u32 id, u32 *res_id); 214 215 const struct btf_type *btf_type_resolve_ptr(const struct btf *btf,
+1 -1
kernel/bpf/btf.c
··· 553 553 return -ENOENT; 554 554 } 555 555 556 - static s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p) 556 + s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p) 557 557 { 558 558 struct btf *btf; 559 559 s32 ret;
+2 -4
kernel/kprobes.c
··· 2232 2232 return -ENOMEM; 2233 2233 2234 2234 for (i = 0; i < rp->maxactive; i++) { 2235 - inst = kzalloc(sizeof(struct kretprobe_instance) + 2236 - rp->data_size, GFP_KERNEL); 2235 + inst = kzalloc(struct_size(inst, data, rp->data_size), GFP_KERNEL); 2237 2236 if (inst == NULL) { 2238 2237 rethook_free(rp->rh); 2239 2238 rp->rh = NULL; ··· 2255 2256 2256 2257 rp->rph->rp = rp; 2257 2258 for (i = 0; i < rp->maxactive; i++) { 2258 - inst = kzalloc(sizeof(struct kretprobe_instance) + 2259 - rp->data_size, GFP_KERNEL); 2259 + inst = kzalloc(struct_size(inst, data, rp->data_size), GFP_KERNEL); 2260 2260 if (inst == NULL) { 2261 2261 refcount_set(&rp->rph->ref, i); 2262 2262 free_rp_inst(rp);
+1
kernel/trace/Makefile
··· 99 99 endif 100 100 obj-$(CONFIG_DYNAMIC_EVENTS) += trace_dynevent.o 101 101 obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o 102 + obj-$(CONFIG_PROBE_EVENTS_BTF_ARGS) += trace_btf.o 102 103 obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o 103 104 obj-$(CONFIG_BOOTTIME_TRACING) += trace_boot.o 104 105 obj-$(CONFIG_FTRACE_RECORD_RECURSION) += trace_recursion_record.o
+2 -1
kernel/trace/trace.c
··· 5711 5711 "\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n" 5712 5712 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API 5713 5713 #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS 5714 - "\t $stack<index>, $stack, $retval, $comm, $arg<N>, <argname>\n" 5714 + "\t $stack<index>, $stack, $retval, $comm, $arg<N>,\n" 5715 + "\t <argname>[->field[->field|.field...]],\n" 5715 5716 #else 5716 5717 "\t $stack<index>, $stack, $retval, $comm, $arg<N>,\n" 5717 5718 #endif
+122
kernel/trace/trace_btf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/btf.h> 3 + #include <linux/kernel.h> 4 + #include <linux/slab.h> 5 + 6 + #include "trace_btf.h" 7 + 8 + /* 9 + * Find a function proto type by name, and return the btf_type with its btf 10 + * in *@btf_p. Return NULL if not found. 11 + * Note that caller has to call btf_put(*@btf_p) after using the btf_type. 12 + */ 13 + const struct btf_type *btf_find_func_proto(const char *func_name, struct btf **btf_p) 14 + { 15 + const struct btf_type *t; 16 + s32 id; 17 + 18 + id = bpf_find_btf_id(func_name, BTF_KIND_FUNC, btf_p); 19 + if (id < 0) 20 + return NULL; 21 + 22 + /* Get BTF_KIND_FUNC type */ 23 + t = btf_type_by_id(*btf_p, id); 24 + if (!t || !btf_type_is_func(t)) 25 + goto err; 26 + 27 + /* The type of BTF_KIND_FUNC is BTF_KIND_FUNC_PROTO */ 28 + t = btf_type_by_id(*btf_p, t->type); 29 + if (!t || !btf_type_is_func_proto(t)) 30 + goto err; 31 + 32 + return t; 33 + err: 34 + btf_put(*btf_p); 35 + return NULL; 36 + } 37 + 38 + /* 39 + * Get function parameter with the number of parameters. 40 + * This can return NULL if the function has no parameters. 41 + * It can return -EINVAL if the @func_proto is not a function proto type. 42 + */ 43 + const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, s32 *nr) 44 + { 45 + if (!btf_type_is_func_proto(func_proto)) 46 + return ERR_PTR(-EINVAL); 47 + 48 + *nr = btf_type_vlen(func_proto); 49 + if (*nr > 0) 50 + return (const struct btf_param *)(func_proto + 1); 51 + else 52 + return NULL; 53 + } 54 + 55 + #define BTF_ANON_STACK_MAX 16 56 + 57 + struct btf_anon_stack { 58 + u32 tid; 59 + u32 offset; 60 + }; 61 + 62 + /* 63 + * Find a member of data structure/union by name and return it. 64 + * Return NULL if not found, or -EINVAL if parameter is invalid. 65 + * If the member is an member of anonymous union/structure, the offset 66 + * of that anonymous union/structure is stored into @anon_offset. Caller 67 + * can calculate the correct offset from the root data structure by 68 + * adding anon_offset to the member's offset. 69 + */ 70 + const struct btf_member *btf_find_struct_member(struct btf *btf, 71 + const struct btf_type *type, 72 + const char *member_name, 73 + u32 *anon_offset) 74 + { 75 + struct btf_anon_stack *anon_stack; 76 + const struct btf_member *member; 77 + u32 tid, cur_offset = 0; 78 + const char *name; 79 + int i, top = 0; 80 + 81 + anon_stack = kcalloc(BTF_ANON_STACK_MAX, sizeof(*anon_stack), GFP_KERNEL); 82 + if (!anon_stack) 83 + return ERR_PTR(-ENOMEM); 84 + 85 + retry: 86 + if (!btf_type_is_struct(type)) { 87 + member = ERR_PTR(-EINVAL); 88 + goto out; 89 + } 90 + 91 + for_each_member(i, type, member) { 92 + if (!member->name_off) { 93 + /* Anonymous union/struct: push it for later use */ 94 + type = btf_type_skip_modifiers(btf, member->type, &tid); 95 + if (type && top < BTF_ANON_STACK_MAX) { 96 + anon_stack[top].tid = tid; 97 + anon_stack[top++].offset = 98 + cur_offset + member->offset; 99 + } 100 + } else { 101 + name = btf_name_by_offset(btf, member->name_off); 102 + if (name && !strcmp(member_name, name)) { 103 + if (anon_offset) 104 + *anon_offset = cur_offset; 105 + goto out; 106 + } 107 + } 108 + } 109 + if (top > 0) { 110 + /* Pop from the anonymous stack and retry */ 111 + tid = anon_stack[--top].tid; 112 + cur_offset = anon_stack[top].offset; 113 + type = btf_type_by_id(btf, tid); 114 + goto retry; 115 + } 116 + member = NULL; 117 + 118 + out: 119 + kfree(anon_stack); 120 + return member; 121 + } 122 +
+11
kernel/trace/trace_btf.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #include <linux/btf.h> 3 + 4 + const struct btf_type *btf_find_func_proto(const char *func_name, 5 + struct btf **btf_p); 6 + const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, 7 + s32 *nr); 8 + const struct btf_member *btf_find_struct_member(struct btf *btf, 9 + const struct btf_type *type, 10 + const char *member_name, 11 + u32 *anon_offset);
+10 -12
kernel/trace/trace_eprobe.c
··· 41 41 struct trace_eprobe *ep; 42 42 }; 43 43 44 + 45 + #define for_each_trace_eprobe_tp(ep, _tp) \ 46 + list_for_each_entry(ep, trace_probe_probe_list(_tp), tp.list) 47 + 44 48 static int __trace_eprobe_create(int argc, const char *argv[]); 45 49 46 50 static void trace_event_probe_cleanup(struct trace_eprobe *ep) ··· 644 640 static int enable_trace_eprobe(struct trace_event_call *call, 645 641 struct trace_event_file *file) 646 642 { 647 - struct trace_probe *pos, *tp; 643 + struct trace_probe *tp; 648 644 struct trace_eprobe *ep; 649 645 bool enabled; 650 646 int ret = 0; ··· 666 662 if (enabled) 667 663 return 0; 668 664 669 - list_for_each_entry(pos, trace_probe_probe_list(tp), list) { 670 - ep = container_of(pos, struct trace_eprobe, tp); 665 + for_each_trace_eprobe_tp(ep, tp) { 671 666 ret = enable_eprobe(ep, file); 672 667 if (ret) 673 668 break; ··· 683 680 */ 684 681 WARN_ON_ONCE(ret != -ENOMEM); 685 682 686 - list_for_each_entry(pos, trace_probe_probe_list(tp), list) { 687 - ep = container_of(pos, struct trace_eprobe, tp); 683 + for_each_trace_eprobe_tp(ep, tp) { 688 684 disable_eprobe(ep, file->tr); 689 685 if (!--cnt) 690 686 break; ··· 701 699 static int disable_trace_eprobe(struct trace_event_call *call, 702 700 struct trace_event_file *file) 703 701 { 704 - struct trace_probe *pos, *tp; 702 + struct trace_probe *tp; 705 703 struct trace_eprobe *ep; 706 704 707 705 tp = trace_probe_primary_from_call(call); ··· 718 716 trace_probe_clear_flag(tp, TP_FLAG_PROFILE); 719 717 720 718 if (!trace_probe_is_enabled(tp)) { 721 - list_for_each_entry(pos, trace_probe_probe_list(tp), list) { 722 - ep = container_of(pos, struct trace_eprobe, tp); 719 + for_each_trace_eprobe_tp(ep, tp) 723 720 disable_eprobe(ep, file->tr); 724 - } 725 721 } 726 722 727 723 out: ··· 807 807 int ret; 808 808 809 809 ret = traceprobe_parse_probe_arg(&ep->tp, i, argv[i], &ctx); 810 - if (ret) 811 - return ret; 812 - 813 810 /* Handle symbols "@" */ 814 811 if (!ret) 815 812 ret = traceprobe_update_arg(&ep->tp.args[i]); 816 813 814 + traceprobe_finish_parse(&ctx); 817 815 return ret; 818 816 } 819 817
+45 -14
kernel/trace/trace_fprobe.c
··· 898 898 return data.tpoint; 899 899 } 900 900 901 + static int parse_symbol_and_return(int argc, const char *argv[], 902 + char **symbol, bool *is_return, 903 + bool is_tracepoint) 904 + { 905 + char *tmp = strchr(argv[1], '%'); 906 + int i; 907 + 908 + if (tmp) { 909 + int len = tmp - argv[1]; 910 + 911 + if (!is_tracepoint && !strcmp(tmp, "%return")) { 912 + *is_return = true; 913 + } else { 914 + trace_probe_log_err(len, BAD_ADDR_SUFFIX); 915 + return -EINVAL; 916 + } 917 + *symbol = kmemdup_nul(argv[1], len, GFP_KERNEL); 918 + } else 919 + *symbol = kstrdup(argv[1], GFP_KERNEL); 920 + if (!*symbol) 921 + return -ENOMEM; 922 + 923 + if (*is_return) 924 + return 0; 925 + 926 + /* If there is $retval, this should be a return fprobe. */ 927 + for (i = 2; i < argc; i++) { 928 + tmp = strstr(argv[i], "$retval"); 929 + if (tmp && !isalnum(tmp[7]) && tmp[7] != '_') { 930 + *is_return = true; 931 + /* 932 + * NOTE: Don't check is_tracepoint here, because it will 933 + * be checked when the argument is parsed. 934 + */ 935 + break; 936 + } 937 + } 938 + return 0; 939 + } 940 + 901 941 static int __trace_fprobe_create(int argc, const char *argv[]) 902 942 { 903 943 /* ··· 967 927 struct trace_fprobe *tf = NULL; 968 928 int i, len, new_argc = 0, ret = 0; 969 929 bool is_return = false; 970 - char *symbol = NULL, *tmp = NULL; 930 + char *symbol = NULL; 971 931 const char *event = NULL, *group = FPROBE_EVENT_SYSTEM; 972 932 const char **new_argv = NULL; 973 933 int maxactive = 0; ··· 1023 983 trace_probe_log_set_index(1); 1024 984 1025 985 /* a symbol(or tracepoint) must be specified */ 1026 - symbol = kstrdup(argv[1], GFP_KERNEL); 1027 - if (!symbol) 1028 - return -ENOMEM; 986 + ret = parse_symbol_and_return(argc, argv, &symbol, &is_return, is_tracepoint); 987 + if (ret < 0) 988 + goto parse_error; 1029 989 1030 - tmp = strchr(symbol, '%'); 1031 - if (tmp) { 1032 - if (!is_tracepoint && !strcmp(tmp, "%return")) { 1033 - *tmp = '\0'; 1034 - is_return = true; 1035 - } else { 1036 - trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX); 1037 - goto parse_error; 1038 - } 1039 - } 1040 990 if (!is_return && maxactive) { 1041 991 trace_probe_log_set_index(0); 1042 992 trace_probe_log_err(1, BAD_MAXACT_TYPE); ··· 1126 1096 } 1127 1097 1128 1098 out: 1099 + traceprobe_finish_parse(&ctx); 1129 1100 trace_probe_log_clear(); 1130 1101 kfree(new_argv); 1131 1102 kfree(symbol);
+1
kernel/trace/trace_kprobe.c
··· 907 907 } 908 908 909 909 out: 910 + traceprobe_finish_parse(&ctx); 910 911 trace_probe_log_clear(); 911 912 kfree(new_argv); 912 913 kfree(symbol);
+376 -143
kernel/trace/trace_probe.c
··· 12 12 #define pr_fmt(fmt) "trace_probe: " fmt 13 13 14 14 #include <linux/bpf.h> 15 + #include "trace_btf.h" 15 16 16 17 #include "trace_probe.h" 17 18 ··· 305 304 306 305 #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS 307 306 308 - static struct btf *traceprobe_get_btf(void) 309 - { 310 - struct btf *btf = bpf_get_btf_vmlinux(); 311 - 312 - if (IS_ERR_OR_NULL(btf)) 313 - return NULL; 314 - 315 - return btf; 316 - } 317 - 318 307 static u32 btf_type_int(const struct btf_type *t) 319 308 { 320 309 return *(u32 *)(t + 1); 321 310 } 322 311 323 - static const char *type_from_btf_id(struct btf *btf, s32 id) 312 + static bool btf_type_is_char_ptr(struct btf *btf, const struct btf_type *type) 324 313 { 325 - const struct btf_type *t; 314 + const struct btf_type *real_type; 326 315 u32 intdata; 327 316 s32 tid; 328 317 329 - /* TODO: const char * could be converted as a string */ 330 - t = btf_type_skip_modifiers(btf, id, &tid); 318 + real_type = btf_type_skip_modifiers(btf, type->type, &tid); 319 + if (!real_type) 320 + return false; 331 321 332 - switch (BTF_INFO_KIND(t->info)) { 322 + if (BTF_INFO_KIND(real_type->info) != BTF_KIND_INT) 323 + return false; 324 + 325 + intdata = btf_type_int(real_type); 326 + return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) 327 + && BTF_INT_BITS(intdata) == 8; 328 + } 329 + 330 + static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type) 331 + { 332 + const struct btf_type *real_type; 333 + const struct btf_array *array; 334 + u32 intdata; 335 + s32 tid; 336 + 337 + if (BTF_INFO_KIND(type->info) != BTF_KIND_ARRAY) 338 + return false; 339 + 340 + array = (const struct btf_array *)(type + 1); 341 + 342 + real_type = btf_type_skip_modifiers(btf, array->type, &tid); 343 + 344 + intdata = btf_type_int(real_type); 345 + return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) 346 + && BTF_INT_BITS(intdata) == 8; 347 + } 348 + 349 + static int check_prepare_btf_string_fetch(char *typename, 350 + struct fetch_insn **pcode, 351 + struct traceprobe_parse_context *ctx) 352 + { 353 + struct btf *btf = ctx->btf; 354 + 355 + if (!btf || !ctx->last_type) 356 + return 0; 357 + 358 + /* char [] does not need any change. */ 359 + if (btf_type_is_char_array(btf, ctx->last_type)) 360 + return 0; 361 + 362 + /* char * requires dereference the pointer. */ 363 + if (btf_type_is_char_ptr(btf, ctx->last_type)) { 364 + struct fetch_insn *code = *pcode + 1; 365 + 366 + if (code->op == FETCH_OP_END) { 367 + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); 368 + return -E2BIG; 369 + } 370 + if (typename[0] == 'u') 371 + code->op = FETCH_OP_UDEREF; 372 + else 373 + code->op = FETCH_OP_DEREF; 374 + code->offset = 0; 375 + *pcode = code; 376 + return 0; 377 + } 378 + /* Other types are not available for string */ 379 + trace_probe_log_err(ctx->offset, BAD_TYPE4STR); 380 + return -EINVAL; 381 + } 382 + 383 + static const char *fetch_type_from_btf_type(struct btf *btf, 384 + const struct btf_type *type, 385 + struct traceprobe_parse_context *ctx) 386 + { 387 + u32 intdata; 388 + 389 + /* TODO: const char * could be converted as a string */ 390 + switch (BTF_INFO_KIND(type->info)) { 333 391 case BTF_KIND_ENUM: 334 392 /* enum is "int", so convert to "s32" */ 335 393 return "s32"; ··· 401 341 else 402 342 return "x32"; 403 343 case BTF_KIND_INT: 404 - intdata = btf_type_int(t); 344 + intdata = btf_type_int(type); 405 345 if (BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) { 406 346 switch (BTF_INT_BITS(intdata)) { 407 347 case 8: ··· 424 364 case 64: 425 365 return "u64"; 426 366 } 367 + /* bitfield, size is encoded in the type */ 368 + ctx->last_bitsize = BTF_INT_BITS(intdata); 369 + ctx->last_bitoffs += BTF_INT_OFFSET(intdata); 370 + return "u64"; 427 371 } 428 372 } 429 373 /* TODO: support other types */ ··· 435 371 return NULL; 436 372 } 437 373 438 - static const struct btf_type *find_btf_func_proto(const char *funcname) 439 - { 440 - struct btf *btf = traceprobe_get_btf(); 441 - const struct btf_type *t; 442 - s32 id; 443 - 444 - if (!btf || !funcname) 445 - return ERR_PTR(-EINVAL); 446 - 447 - id = btf_find_by_name_kind(btf, funcname, BTF_KIND_FUNC); 448 - if (id <= 0) 449 - return ERR_PTR(-ENOENT); 450 - 451 - /* Get BTF_KIND_FUNC type */ 452 - t = btf_type_by_id(btf, id); 453 - if (!t || !btf_type_is_func(t)) 454 - return ERR_PTR(-ENOENT); 455 - 456 - /* The type of BTF_KIND_FUNC is BTF_KIND_FUNC_PROTO */ 457 - t = btf_type_by_id(btf, t->type); 458 - if (!t || !btf_type_is_func_proto(t)) 459 - return ERR_PTR(-ENOENT); 460 - 461 - return t; 462 - } 463 - 464 - static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr, 465 - bool tracepoint) 374 + static int query_btf_context(struct traceprobe_parse_context *ctx) 466 375 { 467 376 const struct btf_param *param; 468 - const struct btf_type *t; 377 + const struct btf_type *type; 378 + struct btf *btf; 379 + s32 nr; 469 380 470 - if (!funcname || !nr) 471 - return ERR_PTR(-EINVAL); 381 + if (ctx->btf) 382 + return 0; 472 383 473 - t = find_btf_func_proto(funcname); 474 - if (IS_ERR(t)) 475 - return (const struct btf_param *)t; 384 + if (!ctx->funcname) 385 + return -EINVAL; 476 386 477 - *nr = btf_type_vlen(t); 478 - param = (const struct btf_param *)(t + 1); 387 + type = btf_find_func_proto(ctx->funcname, &btf); 388 + if (!type) 389 + return -ENOENT; 479 390 480 - /* Hide the first 'data' argument of tracepoint */ 481 - if (tracepoint) { 482 - (*nr)--; 483 - param++; 391 + ctx->btf = btf; 392 + ctx->proto = type; 393 + 394 + /* ctx->params is optional, since func(void) will not have params. */ 395 + nr = 0; 396 + param = btf_get_func_param(type, &nr); 397 + if (!IS_ERR_OR_NULL(param)) { 398 + /* Hide the first 'data' argument of tracepoint */ 399 + if (ctx->flags & TPARG_FL_TPOINT) { 400 + nr--; 401 + param++; 402 + } 484 403 } 485 404 486 - if (*nr > 0) 487 - return param; 488 - else 489 - return NULL; 405 + if (nr > 0) { 406 + ctx->nr_params = nr; 407 + ctx->params = param; 408 + } else { 409 + ctx->nr_params = 0; 410 + ctx->params = NULL; 411 + } 412 + 413 + return 0; 490 414 } 491 415 492 - static int parse_btf_arg(const char *varname, struct fetch_insn *code, 416 + static void clear_btf_context(struct traceprobe_parse_context *ctx) 417 + { 418 + if (ctx->btf) { 419 + btf_put(ctx->btf); 420 + ctx->btf = NULL; 421 + ctx->proto = NULL; 422 + ctx->params = NULL; 423 + ctx->nr_params = 0; 424 + } 425 + } 426 + 427 + /* Return 1 if the field separater is arrow operator ('->') */ 428 + static int split_next_field(char *varname, char **next_field, 429 + struct traceprobe_parse_context *ctx) 430 + { 431 + char *field; 432 + int ret = 0; 433 + 434 + field = strpbrk(varname, ".-"); 435 + if (field) { 436 + if (field[0] == '-' && field[1] == '>') { 437 + field[0] = '\0'; 438 + field += 2; 439 + ret = 1; 440 + } else if (field[0] == '.') { 441 + field[0] = '\0'; 442 + field += 1; 443 + } else { 444 + trace_probe_log_err(ctx->offset + field - varname, BAD_HYPHEN); 445 + return -EINVAL; 446 + } 447 + *next_field = field; 448 + } 449 + 450 + return ret; 451 + } 452 + 453 + /* 454 + * Parse the field of data structure. The @type must be a pointer type 455 + * pointing the target data structure type. 456 + */ 457 + static int parse_btf_field(char *fieldname, const struct btf_type *type, 458 + struct fetch_insn **pcode, struct fetch_insn *end, 459 + struct traceprobe_parse_context *ctx) 460 + { 461 + struct fetch_insn *code = *pcode; 462 + const struct btf_member *field; 463 + u32 bitoffs, anon_offs; 464 + char *next; 465 + int is_ptr; 466 + s32 tid; 467 + 468 + do { 469 + /* Outer loop for solving arrow operator ('->') */ 470 + if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) { 471 + trace_probe_log_err(ctx->offset, NO_PTR_STRCT); 472 + return -EINVAL; 473 + } 474 + /* Convert a struct pointer type to a struct type */ 475 + type = btf_type_skip_modifiers(ctx->btf, type->type, &tid); 476 + if (!type) { 477 + trace_probe_log_err(ctx->offset, BAD_BTF_TID); 478 + return -EINVAL; 479 + } 480 + 481 + bitoffs = 0; 482 + do { 483 + /* Inner loop for solving dot operator ('.') */ 484 + next = NULL; 485 + is_ptr = split_next_field(fieldname, &next, ctx); 486 + if (is_ptr < 0) 487 + return is_ptr; 488 + 489 + anon_offs = 0; 490 + field = btf_find_struct_member(ctx->btf, type, fieldname, 491 + &anon_offs); 492 + if (!field) { 493 + trace_probe_log_err(ctx->offset, NO_BTF_FIELD); 494 + return -ENOENT; 495 + } 496 + /* Add anonymous structure/union offset */ 497 + bitoffs += anon_offs; 498 + 499 + /* Accumulate the bit-offsets of the dot-connected fields */ 500 + if (btf_type_kflag(type)) { 501 + bitoffs += BTF_MEMBER_BIT_OFFSET(field->offset); 502 + ctx->last_bitsize = BTF_MEMBER_BITFIELD_SIZE(field->offset); 503 + } else { 504 + bitoffs += field->offset; 505 + ctx->last_bitsize = 0; 506 + } 507 + 508 + type = btf_type_skip_modifiers(ctx->btf, field->type, &tid); 509 + if (!type) { 510 + trace_probe_log_err(ctx->offset, BAD_BTF_TID); 511 + return -EINVAL; 512 + } 513 + 514 + ctx->offset += next - fieldname; 515 + fieldname = next; 516 + } while (!is_ptr && fieldname); 517 + 518 + if (++code == end) { 519 + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); 520 + return -EINVAL; 521 + } 522 + code->op = FETCH_OP_DEREF; /* TODO: user deref support */ 523 + code->offset = bitoffs / 8; 524 + *pcode = code; 525 + 526 + ctx->last_bitoffs = bitoffs % 8; 527 + ctx->last_type = type; 528 + } while (fieldname); 529 + 530 + return 0; 531 + } 532 + 533 + static int parse_btf_arg(char *varname, 534 + struct fetch_insn **pcode, struct fetch_insn *end, 493 535 struct traceprobe_parse_context *ctx) 494 536 { 495 - struct btf *btf = traceprobe_get_btf(); 537 + struct fetch_insn *code = *pcode; 496 538 const struct btf_param *params; 497 - int i; 498 - 499 - if (!btf) { 500 - trace_probe_log_err(ctx->offset, NOSUP_BTFARG); 501 - return -EOPNOTSUPP; 502 - } 539 + const struct btf_type *type; 540 + char *field = NULL; 541 + int i, is_ptr, ret; 542 + u32 tid; 503 543 504 544 if (WARN_ON_ONCE(!ctx->funcname)) 505 545 return -EINVAL; 506 546 507 - if (!ctx->params) { 508 - params = find_btf_func_param(ctx->funcname, &ctx->nr_params, 509 - ctx->flags & TPARG_FL_TPOINT); 510 - if (IS_ERR_OR_NULL(params)) { 547 + is_ptr = split_next_field(varname, &field, ctx); 548 + if (is_ptr < 0) 549 + return is_ptr; 550 + if (!is_ptr && field) { 551 + /* dot-connected field on an argument is not supported. */ 552 + trace_probe_log_err(ctx->offset + field - varname, 553 + NOSUP_DAT_ARG); 554 + return -EOPNOTSUPP; 555 + } 556 + 557 + if (ctx->flags & TPARG_FL_RETURN) { 558 + if (strcmp(varname, "$retval") != 0) { 559 + trace_probe_log_err(ctx->offset, NO_BTFARG); 560 + return -ENOENT; 561 + } 562 + code->op = FETCH_OP_RETVAL; 563 + /* Check whether the function return type is not void */ 564 + if (query_btf_context(ctx) == 0) { 565 + if (ctx->proto->type == 0) { 566 + trace_probe_log_err(ctx->offset, NO_RETVAL); 567 + return -ENOENT; 568 + } 569 + tid = ctx->proto->type; 570 + goto found; 571 + } 572 + if (field) { 573 + trace_probe_log_err(ctx->offset + field - varname, 574 + NO_BTF_ENTRY); 575 + return -ENOENT; 576 + } 577 + return 0; 578 + } 579 + 580 + if (!ctx->btf) { 581 + ret = query_btf_context(ctx); 582 + if (ret < 0 || ctx->nr_params == 0) { 511 583 trace_probe_log_err(ctx->offset, NO_BTF_ENTRY); 512 584 return PTR_ERR(params); 513 585 } 514 - ctx->params = params; 515 - } else 516 - params = ctx->params; 586 + } 587 + params = ctx->params; 517 588 518 589 for (i = 0; i < ctx->nr_params; i++) { 519 - const char *name = btf_name_by_offset(btf, params[i].name_off); 590 + const char *name = btf_name_by_offset(ctx->btf, params[i].name_off); 520 591 521 592 if (name && !strcmp(name, varname)) { 522 593 code->op = FETCH_OP_ARG; ··· 659 460 code->param = i + 1; 660 461 else 661 462 code->param = i; 662 - return 0; 463 + tid = params[i].type; 464 + goto found; 663 465 } 664 466 } 665 467 trace_probe_log_err(ctx->offset, NO_BTFARG); 666 468 return -ENOENT; 469 + 470 + found: 471 + type = btf_type_skip_modifiers(ctx->btf, tid, &tid); 472 + if (!type) { 473 + trace_probe_log_err(ctx->offset, BAD_BTF_TID); 474 + return -EINVAL; 475 + } 476 + /* Initialize the last type information */ 477 + ctx->last_type = type; 478 + ctx->last_bitoffs = 0; 479 + ctx->last_bitsize = 0; 480 + if (field) { 481 + ctx->offset += field - varname; 482 + return parse_btf_field(field, type, pcode, end, ctx); 483 + } 484 + return 0; 667 485 } 668 486 669 - static const struct fetch_type *parse_btf_arg_type(int arg_idx, 487 + static const struct fetch_type *find_fetch_type_from_btf_type( 670 488 struct traceprobe_parse_context *ctx) 671 489 { 672 - struct btf *btf = traceprobe_get_btf(); 490 + struct btf *btf = ctx->btf; 673 491 const char *typestr = NULL; 674 492 675 - if (btf && ctx->params) { 676 - if (ctx->flags & TPARG_FL_TPOINT) 677 - arg_idx--; 678 - typestr = type_from_btf_id(btf, ctx->params[arg_idx].type); 679 - } 493 + if (btf && ctx->last_type) 494 + typestr = fetch_type_from_btf_type(btf, ctx->last_type, ctx); 680 495 681 496 return find_fetch_type(typestr, ctx->flags); 682 497 } 683 498 684 - static const struct fetch_type *parse_btf_retval_type( 685 - struct traceprobe_parse_context *ctx) 499 + static int parse_btf_bitfield(struct fetch_insn **pcode, 500 + struct traceprobe_parse_context *ctx) 686 501 { 687 - struct btf *btf = traceprobe_get_btf(); 688 - const char *typestr = NULL; 689 - const struct btf_type *t; 502 + struct fetch_insn *code = *pcode; 690 503 691 - if (btf && ctx->funcname) { 692 - t = find_btf_func_proto(ctx->funcname); 693 - if (!IS_ERR(t)) 694 - typestr = type_from_btf_id(btf, t->type); 504 + if ((ctx->last_bitsize % 8 == 0) && ctx->last_bitoffs == 0) 505 + return 0; 506 + 507 + code++; 508 + if (code->op != FETCH_OP_NOP) { 509 + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); 510 + return -EINVAL; 695 511 } 512 + *pcode = code; 696 513 697 - return find_fetch_type(typestr, ctx->flags); 514 + code->op = FETCH_OP_MOD_BF; 515 + code->lshift = 64 - (ctx->last_bitsize + ctx->last_bitoffs); 516 + code->rshift = 64 - ctx->last_bitsize; 517 + code->basesize = 64 / 8; 518 + return 0; 698 519 } 699 520 700 - static bool is_btf_retval_void(const char *funcname) 701 - { 702 - const struct btf_type *t; 703 - 704 - t = find_btf_func_proto(funcname); 705 - if (IS_ERR(t)) 706 - return false; 707 - 708 - return t->type == 0; 709 - } 710 521 #else 711 - static struct btf *traceprobe_get_btf(void) 522 + static void clear_btf_context(struct traceprobe_parse_context *ctx) 712 523 { 713 - return NULL; 524 + ctx->btf = NULL; 714 525 } 715 526 716 - static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr, 717 - bool tracepoint) 527 + static int query_btf_context(struct traceprobe_parse_context *ctx) 718 528 { 719 - return ERR_PTR(-EOPNOTSUPP); 529 + return -EOPNOTSUPP; 720 530 } 721 531 722 - static int parse_btf_arg(const char *varname, struct fetch_insn *code, 532 + static int parse_btf_arg(char *varname, 533 + struct fetch_insn **pcode, struct fetch_insn *end, 723 534 struct traceprobe_parse_context *ctx) 724 535 { 725 536 trace_probe_log_err(ctx->offset, NOSUP_BTFARG); 726 537 return -EOPNOTSUPP; 727 538 } 728 539 729 - #define parse_btf_arg_type(idx, ctx) \ 540 + static int parse_btf_bitfield(struct fetch_insn **pcode, 541 + struct traceprobe_parse_context *ctx) 542 + { 543 + trace_probe_log_err(ctx->offset, NOSUP_BTFARG); 544 + return -EOPNOTSUPP; 545 + } 546 + 547 + #define find_fetch_type_from_btf_type(ctx) \ 730 548 find_fetch_type(NULL, ctx->flags) 731 549 732 - #define parse_btf_retval_type(ctx) \ 733 - find_fetch_type(NULL, ctx->flags) 734 - 735 - #define is_btf_retval_void(funcname) (false) 550 + static int check_prepare_btf_string_fetch(char *typename, 551 + struct fetch_insn **pcode, 552 + struct traceprobe_parse_context *ctx) 553 + { 554 + return 0; 555 + } 736 556 737 557 #endif 738 558 739 559 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) 740 560 741 - static int parse_probe_vars(char *arg, const struct fetch_type *t, 742 - struct fetch_insn *code, 561 + /* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */ 562 + static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, 563 + struct fetch_insn **pcode, 564 + struct fetch_insn *end, 743 565 struct traceprobe_parse_context *ctx) 744 566 { 745 - unsigned long param; 567 + struct fetch_insn *code = *pcode; 746 568 int err = TP_ERR_BAD_VAR; 569 + char *arg = orig_arg + 1; 570 + unsigned long param; 747 571 int ret = 0; 748 572 int len; 749 573 ··· 785 563 goto inval; 786 564 } 787 565 788 - if (strcmp(arg, "retval") == 0) { 789 - if (ctx->flags & TPARG_FL_RETURN) { 790 - if ((ctx->flags & TPARG_FL_KERNEL) && 791 - is_btf_retval_void(ctx->funcname)) { 792 - err = TP_ERR_NO_RETVAL; 793 - goto inval; 794 - } 566 + if (str_has_prefix(arg, "retval")) { 567 + if (!(ctx->flags & TPARG_FL_RETURN)) { 568 + err = TP_ERR_RETVAL_ON_PROBE; 569 + goto inval; 570 + } 571 + if (!(ctx->flags & TPARG_FL_KERNEL) || 572 + !IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) { 795 573 code->op = FETCH_OP_RETVAL; 796 574 return 0; 797 575 } 798 - err = TP_ERR_RETVAL_ON_PROBE; 799 - goto inval; 576 + return parse_btf_arg(orig_arg, pcode, end, ctx); 800 577 } 801 578 802 579 len = str_has_prefix(arg, "stack"); ··· 897 676 898 677 switch (arg[0]) { 899 678 case '$': 900 - ret = parse_probe_vars(arg + 1, type, code, ctx); 679 + ret = parse_probe_vars(arg, type, pcode, end, ctx); 901 680 break; 902 681 903 682 case '%': /* named register */ ··· 1016 795 1017 796 code->op = deref; 1018 797 code->offset = offset; 798 + /* Reset the last type if used */ 799 + ctx->last_type = NULL; 1019 800 } 1020 801 break; 1021 802 case '\\': /* Immediate value */ ··· 1041 818 trace_probe_log_err(ctx->offset, NOSUP_BTFARG); 1042 819 return -EINVAL; 1043 820 } 1044 - ret = parse_btf_arg(arg, code, ctx); 821 + ret = parse_btf_arg(arg, pcode, end, ctx); 1045 822 break; 1046 823 } 1047 824 } ··· 1187 964 goto out; 1188 965 code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; 1189 966 967 + ctx->last_type = NULL; 1190 968 ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], 1191 969 ctx); 1192 970 if (ret) 1193 971 goto fail; 1194 972 1195 973 /* Update storing type if BTF is available */ 1196 - if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && !t) { 1197 - if (code->op == FETCH_OP_ARG) 1198 - parg->type = parse_btf_arg_type(code->param, ctx); 1199 - else if (code->op == FETCH_OP_RETVAL) 1200 - parg->type = parse_btf_retval_type(ctx); 974 + if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && 975 + ctx->last_type) { 976 + if (!t) { 977 + parg->type = find_fetch_type_from_btf_type(ctx); 978 + } else if (strstr(t, "string")) { 979 + ret = check_prepare_btf_string_fetch(t, &code, ctx); 980 + if (ret) 981 + goto fail; 982 + } 1201 983 } 1202 984 1203 985 ret = -EINVAL; ··· 1276 1048 trace_probe_log_err(ctx->offset + t - arg, BAD_BITFIELD); 1277 1049 goto fail; 1278 1050 } 1051 + } else if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && 1052 + ctx->last_type) { 1053 + ret = parse_btf_bitfield(&code, ctx); 1054 + if (ret) 1055 + goto fail; 1279 1056 } 1280 1057 ret = -EINVAL; 1281 1058 /* Loop(Array) operation */ ··· 1464 1231 char *buf, int bufsize, 1465 1232 struct traceprobe_parse_context *ctx) 1466 1233 { 1467 - struct btf *btf = traceprobe_get_btf(); 1468 1234 const char *name; 1469 1235 int ret; 1470 1236 ··· 1471 1239 trace_probe_log_err(0, NO_BTFARG); 1472 1240 return -ENOENT; 1473 1241 } 1474 - name = btf_name_by_offset(btf, ctx->params[idx].name_off); 1242 + name = btf_name_by_offset(ctx->btf, ctx->params[idx].name_off); 1475 1243 if (!name) { 1476 1244 trace_probe_log_err(0, NO_BTF_ENTRY); 1477 1245 return -ENOENT; ··· 1492 1260 const struct btf_param *params = NULL; 1493 1261 int i, j, n, used, ret, args_idx = -1; 1494 1262 const char **new_argv = NULL; 1495 - int nr_params; 1496 1263 1497 1264 ret = argv_has_var_arg(argc, argv, &args_idx, ctx); 1498 1265 if (ret < 0) ··· 1502 1271 return NULL; 1503 1272 } 1504 1273 1505 - params = find_btf_func_param(ctx->funcname, &nr_params, 1506 - ctx->flags & TPARG_FL_TPOINT); 1507 - if (IS_ERR_OR_NULL(params)) { 1274 + ret = query_btf_context(ctx); 1275 + if (ret < 0 || ctx->nr_params == 0) { 1508 1276 if (args_idx != -1) { 1509 1277 /* $arg* requires BTF info */ 1510 1278 trace_probe_log_err(0, NOSUP_BTFARG); ··· 1512 1282 *new_argc = argc; 1513 1283 return NULL; 1514 1284 } 1515 - ctx->params = params; 1516 - ctx->nr_params = nr_params; 1517 1285 1518 1286 if (args_idx >= 0) 1519 1287 *new_argc = argc + ctx->nr_params - 1; ··· 1526 1298 for (i = 0, j = 0; i < argc; i++) { 1527 1299 trace_probe_log_set_index(i + 2); 1528 1300 if (i == args_idx) { 1529 - for (n = 0; n < nr_params; n++) { 1301 + for (n = 0; n < ctx->nr_params; n++) { 1530 1302 ret = sprint_nth_btf_arg(n, "", buf + used, 1531 1303 bufsize - used, ctx); 1532 1304 if (ret < 0) ··· 1563 1335 error: 1564 1336 kfree(new_argv); 1565 1337 return ERR_PTR(ret); 1338 + } 1339 + 1340 + void traceprobe_finish_parse(struct traceprobe_parse_context *ctx) 1341 + { 1342 + clear_btf_context(ctx); 1566 1343 } 1567 1344 1568 1345 int traceprobe_update_arg(struct probe_arg *arg)
+23 -4
kernel/trace/trace_probe.h
··· 383 383 384 384 struct traceprobe_parse_context { 385 385 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_type *proto; /* Prototype of the function */ 389 + const struct btf_param *params; /* Parameter of the function */ 390 + s32 nr_params; /* The number of the parameters */ 391 + struct btf *btf; /* The BTF to be used */ 392 + const struct btf_type *last_type; /* Saved type */ 393 + u32 last_bitoffs; /* Saved bitoffs */ 394 + u32 last_bitsize; /* Saved bitsize */ 389 395 unsigned int flags; 390 396 int offset; 391 397 }; ··· 405 399 406 400 extern int traceprobe_update_arg(struct probe_arg *arg); 407 401 extern void traceprobe_free_probe_arg(struct probe_arg *arg); 402 + 403 + /* 404 + * If either traceprobe_parse_probe_arg() or traceprobe_expand_meta_args() is called, 405 + * this MUST be called for clean up the context and return a resource. 406 + */ 407 + void traceprobe_finish_parse(struct traceprobe_parse_context *ctx); 408 408 409 409 extern int traceprobe_split_symbol_offset(char *symbol, long *offset); 410 410 int traceprobe_parse_event_name(const char **pevent, const char **pgroup, ··· 507 495 C(BAD_VAR_ARGS, "$arg* must be an independent parameter without name etc."),\ 508 496 C(NOFENTRY_ARGS, "$arg* can be used only on function entry"), \ 509 497 C(DOUBLE_ARGS, "$arg* can be used only once in the parameters"), \ 510 - C(ARGS_2LONG, "$arg* failed because the argument list is too long"), 498 + C(ARGS_2LONG, "$arg* failed because the argument list is too long"), \ 499 + C(ARGIDX_2BIG, "$argN index is too big"), \ 500 + C(NO_PTR_STRCT, "This is not a pointer to union/structure."), \ 501 + C(NOSUP_DAT_ARG, "Non pointer structure/union argument is not supported."),\ 502 + C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \ 503 + C(NO_BTF_FIELD, "This field is not found."), \ 504 + C(BAD_BTF_TID, "Failed to get BTF type info."),\ 505 + C(BAD_TYPE4STR, "This type does not fit for string."), 511 506 512 507 #undef C 513 508 #define C(a, b) TP_ERR_##a
+1
kernel/trace/trace_uprobe.c
··· 688 688 689 689 trace_probe_log_set_index(i + 2); 690 690 ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx); 691 + traceprobe_finish_parse(&ctx); 691 692 if (ret) 692 693 goto error; 693 694 }
+20
tools/testing/selftests/ftrace/test.d/dynevent/add_remove_btfarg.tc
··· 5 5 6 6 KPROBES= 7 7 FPROBES= 8 + FIELDS= 8 9 9 10 if grep -qF "p[:[<group>/][<event>]] <place> [<args>]" README ; then 10 11 KPROBES=yes 11 12 fi 12 13 if grep -qF "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README ; then 13 14 FPROBES=yes 15 + fi 16 + if grep -qF "<argname>[->field[->field|.field...]]" README ; then 17 + FIELDS=yes 14 18 fi 15 19 16 20 if [ -z "$KPROBES" -a -z "$FPROBES" ] ; then ··· 25 21 echo > dynamic_events 26 22 27 23 TP=kfree 24 + TP2=kmem_cache_alloc 25 + TP3=getname_flags 26 + TP4=sched_wakeup 28 27 29 28 if [ "$FPROBES" ] ; then 30 29 echo "f:fpevent $TP object" >> dynamic_events ··· 40 33 41 34 echo "f:fpevent $TP "'$arg1' >> dynamic_events 42 35 grep -q "fpevent.*object=object" dynamic_events 36 + 43 37 echo > dynamic_events 44 38 45 39 echo "f:fpevent $TP "'$arg*' >> dynamic_events ··· 52 44 fi 53 45 54 46 echo > dynamic_events 47 + 48 + if [ "$FIELDS" ] ; then 49 + echo "t:tpevent ${TP2} obj_size=s->object_size" >> dynamic_events 50 + echo "f:fpevent ${TP3}%return path=\$retval->name:string" >> dynamic_events 51 + echo "t:tpevent2 ${TP4} p->se.group_node.next->prev" >> dynamic_events 52 + 53 + grep -q "tpevent .*obj_size=s->object_size" dynamic_events 54 + grep -q "fpevent.*path=\$retval->name:string" dynamic_events 55 + grep -q 'tpevent2 .*p->se.group_node.next->prev' dynamic_events 56 + 57 + echo > dynamic_events 58 + fi 55 59 56 60 if [ "$KPROBES" ] ; then 57 61 echo "p:kpevent $TP object" >> dynamic_events
+9 -1
tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc
··· 30 30 check_error 'f:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read' # EVENT_TOO_LONG 31 31 check_error 'f:foo/^bar.1 vfs_read' # BAD_EVENT_NAME 32 32 33 - check_error 'f vfs_read ^$retval' # RETVAL_ON_PROBE 34 33 check_error 'f vfs_read ^$stack10000' # BAD_STACK_NUM 35 34 36 35 check_error 'f vfs_read ^$arg10000' # BAD_ARG_NUM 37 36 37 + check_error 'f vfs_read $retval ^$arg1' # BAD_VAR 38 38 check_error 'f vfs_read ^$none_var' # BAD_VAR 39 39 check_error 'f vfs_read ^'$REG # BAD_VAR 40 40 ··· 103 103 check_error 'f vfs_read ^hoge' # NO_BTFARG 104 104 check_error 'f kfree ^$arg10' # NO_BTFARG (exceed the number of parameters) 105 105 check_error 'f kfree%return ^$retval' # NO_RETVAL 106 + 107 + if grep -qF "<argname>[->field[->field|.field...]]" README ; then 108 + check_error 'f vfs_read%return $retval->^foo' # NO_PTR_STRCT 109 + check_error 'f vfs_read file->^foo' # NO_BTF_FIELD 110 + check_error 'f vfs_read file^-.foo' # BAD_HYPHEN 111 + check_error 'f vfs_read ^file:string' # BAD_TYPE4STR 112 + fi 113 + 106 114 else 107 115 check_error 'f vfs_read ^$arg*' # NOSUP_BTFARG 108 116 check_error 't kfree ^$arg*' # NOSUP_BTFARG