tracing: probeevent: Improve fetcharg features
Subsystems (6)
Masami Hiramatsu
maintainerv6 cover tracing: probeevent: Improve fetcharg features
Hi,
This is the 6th version of the fetch-arg improvement series. This includes variable changes on fetcharg framework like,
- Add fetcharg testcases (syntax, argN, symbol, string and array) and probepoint testcase.
- Rewrite fetcharg framework with fetch_insn, switch-case based instead of function pointer.
- Add "symbol" type support, which shows symbol+offset instead of address value.
- Add "$argN" fetcharg, which fetches function parameters. (currently only for x86-64)
- Add array type support (including string arrary :) ) , which enables to get fixed length array from probe-events.
- Add array type support for perf-probe, so that user can dump partial array entries.
V5 is here:
https://lkml.org/lkml/2018/3/12/558
Changes from the v5 is here:
- [16/21] Fix README to add backslash escapes to "[]"
- [20/21] Add a bugfix patch for perf-probe.
- [21/21] Add array type support for perf-probe.
Note that [20/21] is same as https://lkml.org/lkml/2018/3/16/108
I have to add this because the last patch depends on it. Anyway, [20/21] and [21/21] is only for showing how perf-probe will enhanced by this series. So those are extra work. I will resend thodr again after [01/21]-[19/21] are merged.
Here are examples:
o 'symbol' type
# echo 'p vfs_read $stack0:symbol' > kprobe_events
# echo 1 > events/kprobes/p_vfs_read_0/enable
# tail -n 3 trace
sh-729 [007] ...2 105.753637: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=SyS_read+0x42/0x90
tail-736 [000] ...2 105.754904: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=kernel_read+0x2c/0x40
tail-736 [000] ...2 105.754929: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=kernel_read+0x2c/0x40o $argN
# echo 'p vfs_read $arg0 $arg1 $arg2' > kprobe_events
# echo 1 > events/kprobes/p_vfs_read_0/enable
# tail -n 3 trace
sh-726 [007] ...2 134.288973: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d98ec00 arg2=0x7ffeb4330f79 arg3=0x1
tail-731 [000] ...2 134.289987: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d9dd200 arg2=0xffff88001d8a0a00 arg3=0x80
tail-731 [000] ...2 134.290016: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d9dd200 arg2=0xffff88001faf4a00 arg3=0x150o Array type
# echo 'p vfs_read +0($stack):x64 +0($stack):x8[8]' > kprobe_events
# echo 1 > events/kprobes/p_vfs_read_0/enable
# tail -n 3 trace
sh-729 [007] ...2 91.701664: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b1252 arg2={0x52,0x12,0x1b,0x81,0xff,0xff,0xff,0xff}
tail-734 [000] ...2 91.702366: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b0dec arg2={0xec,0xd,0x1b,0x81,0xff,0xff,0xff,0xff}
tail-734 [000] ...2 91.702386: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b0dec arg2={0xec,0xd,0x1b,0x81,0xff,0xff,0xff,0xff}
#
# cat events/kprobes/p_vfs_read_0/format
name: p_vfs_read_0
ID: 1069
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;field:unsigned long __probe_ip; offset:8; size:8; signed:0; field:u64 arg1; offset:16; size:0; signed:0; field:u8 arg2[8]; offset:24; size:8; signed:0;
print fmt: "(%lx) arg1=0x%Lx arg2={0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x}", REC->__probe_ip, REC->arg1, REC->arg2[0], REC->arg2[1], REC->arg2[2], REC->arg2[3], REC->arg2[4], REC->arg2[5], REC->arg2[6], REC->arg2[7]
o String Array type
# echo "p create_trace_kprobe arg1=+0(%si):string[3]" > kprobe_events
# echo test1 test2 test3 >> kprobe_events
sh: write error: Invalid argument
# echo 'p vfs_read $stack' >> kprobe_events
# tail -n 2 trace
sh-744 [007] ...1 183.382407: p_create_trace_kprobe_0: (create_trace_kprobe+0x0/0x890) arg1={"test1","test2","test3"}
sh-744 [007] ...1 230.487809: p_create_trace_kprobe_0: (create_trace_kprobe+0x0/0x890) arg1={"p","vfs_read","$stack"}Thank you,
---
Masami Hiramatsu (21):
[BUGFIX] tracing: probeevent: Fix to support minus offset from symbol
selftests: ftrace: Add probe event argument syntax testcase
selftests: ftrace: Add a testcase for string type with kprobe_event
selftests: ftrace: Add a testcase for probepoint
tracing: probeevent: Cleanup print argument functions
tracing: probeevent: Cleanup argument field definition
tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
tracing: probeevent: Introduce new argument fetching code
tracing: probeevent: Unify fetch type tables
tracing: probeevent: Return consumed bytes of dynamic area
tracing: probeevent: Append traceprobe_ for exported function
tracing: probeevent: Unify fetch_insn processing common part
tracing: probeevent: Add symbol type
x86: ptrace: Add function argument access API
tracing: probeevent: Add $argN for accessing function args
tracing: probeevent: Add array type support
selftests: ftrace: Add a testcase for symbol type
selftests: ftrace: Add a testcase for $argN with kprobe_event
selftests: ftrace: Add a testcase for array type with kprobe_event [RESEND] perf-probe: Fix to convert array type collectly
perf-probe: Add array argument support
Documentation/trace/kprobetrace.txt | 26 + arch/Kconfig | 7 arch/x86/Kconfig | 1 arch/x86/include/asm/ptrace.h | 38 + kernel/trace/trace.c | 9 kernel/trace/trace_kprobe.c | 366 ++++-------- kernel/trace/trace_probe.c | 628 +++++++++----------- kernel/trace/trace_probe.h | 284 +++------ kernel/trace/trace_probe_tmpl.h | 214 +++++++ kernel/trace/trace_uprobe.c | 168 ++--- tools/perf/Documentation/perf-probe.txt | 2 tools/perf/util/probe-event.c | 20 + tools/perf/util/probe-event.h | 2 tools/perf/util/probe-file.c | 5 tools/perf/util/probe-file.h | 1 tools/perf/util/probe-finder.c | 108 ++- .../ftrace/test.d/kprobe/kprobe_args_argN.tc | 25 + .../ftrace/test.d/kprobe/kprobe_args_array.tc | 92 +++ .../ftrace/test.d/kprobe/kprobe_args_string.tc | 46 + .../ftrace/test.d/kprobe/kprobe_args_symbol.tc | 77 ++ .../ftrace/test.d/kprobe/kprobe_args_syntax.tc | 97 +++ .../selftests/ftrace/test.d/kprobe/probepoint.tc | 43 + 22 files changed, 1319 insertions(+), 940 deletions(-) create mode 100644 kernel/trace/trace_probe_tmpl.h create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc
--
Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 1/21 tracing: probeevent: Fix to support minus offset from symbol
In Documentation/trace/kprobetrace.txt, it says
@SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol)
However, the parser doesn't parse minus offset correctly, since commit 2fba0c8867af ("tracing/kprobes: Fix probe offset to be unsigned") drops minus ("-") offset support for kprobe probe address usage.
This fixes the traceprobe_split_symbol_offset() to parse minus offset again with checking the offset range, and add a minus offset check in kprobe probe address usage.
---
Changes in v3:
- Use kstrtol instead of kstrtoul. (Thanks Namhyung!)
Changes in v4:
- Fix to decode sign. (Thanks Namhyung!)
- Fix to check UINT_MAX for kprobe offset.
--- kernel/trace/trace_kprobe.c | 4 ++-- kernel/trace/trace_probe.c | 8 +++----- kernel/trace/trace_probe.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-)
kernel/trace/trace_kprobe.c +2 -2
@@ -667,7 +667,7 @@ static int create_trace_kprobe(int argc, char **argv)char *symbol =NULL , *event =NULL , *group =NULL ;int maxactive =0 ;char *arg; -unsigned long offset =0 ; +long offset =0 ;void *addr =NULL ;char buf[MAX_EVENT_NAME_LEN ];
@@ -755,7 +755,7 @@ static int create_trace_kprobe(int argc, char **argv) symbol = argv[1 ];/* TODO: support .init module functions */ ret =traceprobe_split_symbol_offset (symbol, &offset); -if (ret) { +if (ret || offset <0 || offset >UINT_MAX ) {pr_info ("Failed to parse either an address or a symbol.\n" );return ret; }
kernel/trace/trace_probe.c +3 -5
@@ -320,7 +320,7 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type, }/* Split symbol and offset. */ -int traceprobe_split_symbol_offset (char *symbol,unsigned long *offset) +int traceprobe_split_symbol_offset (char *symbol,long *offset) {char *tmp;int ret;
@@ -328,13 +328,11 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)if (!offset)return -EINVAL ; - tmp =strchr (symbol,'+' ); + tmp =strpbrk (symbol,"+-" );if (tmp) { -/* skip sign because kstrtoul doesn't accept '+' */ - ret =kstrtoul (tmp +1 ,0 , offset); + ret =kstrtol (tmp,0 , offset);if (ret)return ret; - *tmp ='\0' ; }else *offset =0 ;
kernel/trace/trace_probe.h +1 -1
@@ -365,7 +365,7 @@ extern int traceprobe_conflict_field_name(const char *name,extern void traceprobe_update_arg (struct probe_arg *arg);extern void traceprobe_free_probe_arg (struct probe_arg *arg); -extern int traceprobe_split_symbol_offset (char *symbol,unsigned long *offset); +extern int traceprobe_split_symbol_offset (char *symbol,long *offset);/* Sum up total data length for dynamic arraies (strings) */ static nokprobe_inline int
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 2/21 selftests: ftrace: Add probe event argument syntax testcase
In reply to Masami HiramatsuAdd a testcase for probe event argument syntax which ensures the kprobe_events interface correctly parses given event arguments.
--- .../ftrace/test.d/kprobe/kprobe_args_syntax.tc | 97 ++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc new file +97 -0
@@ -0,0 +1,97 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event argument syntax + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue + +echo 0 > events/enable +echo > kprobe_events + +PROBEFUNC="vfs_read" +GOODREG= +BADREG= +GOODSYM="_sdata" +if ! grep -qw ${GOODSYM} /proc/kallsyms ; then + GOODSYM=$PROBEFUNC +fi +BADSYM="deaqswdefr" +SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "` +GOODTYPE="x16" +BADTYPE="y16" + +case `uname -m` in +x86_64|i[3456]86) + GOODREG=%ax + BADREG=%ex +;; +aarch64) + GOODREG=%x0 + BADREG=%ax +;; +arm*) + GOODREG=%r0 + BADREG=%ax +;; +esac + +test_goodarg() # Good-args +{ + while [ "$1" ]; do + echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +test_badarg() # Bad-args +{ + while [ "$1" ]; do + ! echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +echo > kprobe_events + +: "Register access" +test_goodarg ${GOODREG} +test_badarg ${BADREG} + +: "Symbol access" +test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10" +test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \ + "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10" + +: "Stack access" +test_goodarg "\$stack" "\$stack0" "\$stack1" +test_badarg "\$stackp" "\$stack0+10" "\$stack1-10" + +: "Retval access" +echo "r ${PROBEFUNC} \$retval" > kprobe_events +! echo "p ${PROBEFUNC} \$retval" > kprobe_events + +: "Comm access" +test_goodarg "\$comm" + +: "Indirect memory access" +test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \ + "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))" +test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \ + "+10(\$comm)" "+0(${GOODREG})+10" + +: "Name assignment" +test_goodarg "varname=${GOODREG}" +test_badarg "varname=varname2=${GOODREG}" + +: "Type syntax" +test_goodarg "${GOODREG}:${GOODTYPE}" +test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \ + "${GOODTYPE}:${GOODREG}" + +: "Combination check" + +test_goodarg "\$comm:string" "+0(\$stack):string" +test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string" + +echo > kprobe_events
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 3/21 selftests: ftrace: Add a testcase for string type with kprobe_event
In reply to Masami HiramatsuAdd a testcase for string type with kprobe event.
This tests good/bad syntax combinations and also
the traced data is correct in several way.
--- .../ftrace/test.d/kprobe/kprobe_args_string.tc | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc new file +46 -0
@@ -0,0 +1,46 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event string type argument + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +echo 0 > events/enable +echo > kprobe_events + +case `uname -m` in +x86_64) + ARG2=%si + OFFS=8 +;; +i[3456]86) + ARG2=%cx + OFFS=4 +;; +aarch64) + ARG2=%x1 + OFFS=8 +;; +arm*) + ARG2=%r1 + OFFS=4 +;; +*) + echo "Please implement other architecture here" + exit_untested +esac + +: "Test get argument (1)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" + +echo 0 > events/kprobes/testprobe/enable +: "Test get argument (2)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test1 test2 >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" + +echo 0 > events/enable +echo > kprobe_events
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 4/21 selftests: ftrace: Add a testcase for probepoint
In reply to Masami HiramatsuAdd a testcase for probe point definition. This tests symbol, address and symbol+offset syntax. The offset must be positive and smaller than UINT_MAX.
--- .../selftests/ftrace/test.d/kprobe/probepoint.tc | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc
tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc new file +43 -0
@@ -0,0 +1,43 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe events - probe points + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +TARGET_FUNC=create_trace_kprobe + +dec_addr() { # hexaddr + printf "%d" "0x"`echo $1 | tail -c 8` +} + +set_offs() { # prev target next + A1=`dec_addr $1` + A2=`dec_addr $2` + A3=`dec_addr $3` + TARGET="0x$2" # an address + PREV=`expr $A1 - $A2` # offset to previous symbol + NEXT=+`expr $A3 - $A2` # offset to next symbol + OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol +} + +# We have to decode symbol addresses to get correct offsets. +# If the offset is not an instruction boundary, it cause -EILSEQ. +set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` + +UINT_TEST=no +# printf "%x" -1 returns (unsigned long)-1. +if [ `printf "%x" -1 | wc -c` != 9 ]; then + UINT_TEST=yes +fi + +echo 0 > events/enable +echo > kprobe_events +echo "p:testprobe ${TARGET_FUNC}" > kprobe_events +echo "p:testprobe ${TARGET}" > kprobe_events +echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events +! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events +if [ "${UINT_TEST}" = yes ]; then +! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events +fi +echo > kprobe_events +clear_trace
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Steven Rostedt
maintainerRe: [PATCH v6 04/21] selftests: ftrace: Add a testcase for probepoint
Quoted 6 lines · On Sat, 17 Mar 2018 21:40:31 +0900 Masami Hiramatsu <[email protected]> wrote:
Add a testcase for probe point definition. This tests symbol, address and symbol+offset syntax. The offset must be positive and smaller than
UINT_MAX.Signed-off-by Masami Hiramatsu <mhiramat at kernel.org>
I've pulled the first 4 patches into my urgent tree and I'm currently testing it. When it finishes the tests (and I'm sure they will pass ;-) I'll push it to Linus.
-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 5/21 tracing: probeevent: Cleanup print argument functions
In reply to Masami HiramatsuCurrent print argument functions prints the argument name too. It is not good for printing out multiple values for one argument. This change it to just print out the value.
--- kernel/trace/trace_kprobe.c | 20 ++++++-------------- kernel/trace/trace_probe.c | 12 +++++------- kernel/trace/trace_probe.h | 19 ++++++++++++++++--- kernel/trace/trace_uprobe.c | 9 ++------- 4 files changed, 29 insertions(+), 31 deletions(-)
kernel/trace/trace_kprobe.c +6 -14
@@ -1090,8 +1090,6 @@ print_kprobe_event(struct trace_iterator *iter, int flags,struct kprobe_trace_entry_head *field;struct trace_seq *s = &iter->seq;struct trace_probe *tp; -u8 *data; -int i; field = (struct kprobe_trace_entry_head *)iter->ent; tp = container_of(event, struct trace_probe, call.event);
@@ -1103,11 +1101,9 @@ print_kprobe_event(struct trace_iterator *iter, int flags,trace_seq_putc (s,')' ); - data = (u8 *)&field[1 ]; -for (i =0 ; i < tp->nr_args; i++) -if (!tp->args[i].type->if (print_probe_args (s, tp->args, tp->nr_args, + (u8 *)&field[1 ], field) <0 ) + goto out;trace_seq_putc (s,'\n' ); out:
@@ -1121,8 +1117,6 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,struct kretprobe_trace_entry_head *field;struct trace_seq *s = &iter->seq;struct trace_probe *tp; -u8 *data; -int i; field = (struct kretprobe_trace_entry_head *)iter->ent; tp = container_of(event, struct trace_probe, call.event);
@@ -1139,11 +1133,9 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,trace_seq_putc (s,')' ); - data = (u8 *)&field[1 ]; -for (i =0 ; i < tp->nr_args; i++) -if (!tp->args[i].type->if (print_probe_args (s, tp->args, tp->nr_args, + (u8 *)&field[1 ], field) <0 ) + goto out;trace_seq_putc (s,'\n' );
kernel/trace/trace_probe.c +5 -7
@@ -38,10 +38,9 @@ const char *reserved_field_names[] = {/* Printing in basic type function template */ #define DEFINE_BASIC_PRINT_TYPE_FUNC (tname, type, fmt) \ -int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name, \ - void *data, void *ent) \ +int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\ { \ - trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ + trace_seq_printf(s, fmt, *(type *)data); \ return !trace_seq_has_overflowed(s); \ } \ const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; \
@@ -61,15 +60,14 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")DEFINE_BASIC_PRINT_TYPE_FUNC (x64, u64,"0x%Lx" ) /* Print type function for string type */ -int PRINT_TYPE_FUNC_NAME (string )(struct trace_seq *s,const char *name, -void *data,void *ent) +int PRINT_TYPE_FUNC_NAME (string )(struct trace_seq *s,void *data,void *ent) {int len = *(u32 *)data >>16 ;if (!len) -trace_seq_printf (s," %s=(fault)" , name); +trace_seq_puts (s,"(fault)" );else -trace_seq_printf (s," %s=\"%s\"" , name, +trace_seq_printf (s,"\"%s\"" , (const char *)get_loc_data (data, ent));return !trace_seq_has_overflowed (s); }
kernel/trace/trace_probe.h +16 -3
@@ -94,7 +94,7 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)/* Data fetch function type */ typedef void (*fetch_func_t )(struct pt_regs *,void *,void *);/* Printing function type */ -typedef int (*print_type_func_t )(struct trace_seq *,const char *,void *,void *); +typedef int (*print_type_func_t )(struct trace_seq *,void *,void *);/* Fetch types */ enum {
@@ -136,8 +136,7 @@ typedef u32 string_size;/* Printing in basic type function template */ #define DECLARE_BASIC_PRINT_TYPE_FUNC (type) \ -int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \ - void *data, void *ent); \ +int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, void *data, void *ent);\ extern const char PRINT_TYPE_FMT_NAME(type)[]DECLARE_BASIC_PRINT_TYPE_FUNC (u8);
@@ -415,6 +414,20 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, } } +static inline int +print_probe_args (struct trace_seq *s,struct probe_arg *args,int nr_args, +u8 *data,void *field) +{ +int i; + +for (i =0 ; i < nr_args; i++) { +trace_seq_printf (s," %s=" , args[i].name); +if (!args[i].type->return -ENOMEM ; + } +return 0 ; +} +extern int set_print_fmt (struct trace_probe *tp,bool is_return);#ifdef CONFIG_PERF_EVENTS
kernel/trace/trace_uprobe.c +2 -7
@@ -864,7 +864,6 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *estruct trace_seq *s = &iter->seq;struct trace_uprobe *tu;u8 *data; -int i; entry = (struct uprobe_trace_entry_head *)iter->ent; tu = container_of(event, struct trace_uprobe, tp.call.event);
@@ -881,12 +880,8 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e data =DATAOF_TRACE_ENTRY (entry, false); } -for (i =0 ; i < tu->tp.nr_args; i++) { -struct probe_arg *parg = &tu->tp.args[i]; - -if (!parg->type->if (print_probe_args (s, tu->tp.args, tu->tp.nr_args, data, entry) <0 ) + goto out;trace_seq_putc (s,'\n' );
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Steven Rostedt
maintainerRe: [PATCH v6 05/21] tracing: probeevent: Cleanup print argument functions
Quoted 4 lines · On Sat, 17 Mar 2018 21:41:12 +0900 Masami Hiramatsu <mhiramat at kernel.org>…
Current print argument functions prints the argument name too. It is not good for printing out multiple values for one argument. This change it to just print out the value.
Hi Masami,
This is a confusing change log, as I have no idea what this patch does. Can you add a "before" and "after" of what you mean. Some examples of what it currently does to show why it looks bad, and then an example of what it looks like after the patch.
Thanks!
-- Steve
Quoted 3 lines
Signed-off-by Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerRe: [PATCH v6 05/21] tracing: probeevent: Cleanup print argument functions
Quoted 8 lines · On Fri, 23 Mar 2018 12:36:47 -0400 Steven Rostedt <rostedt at goodmis.org>…
Quoted 4 lines · On Sat, 17 Mar 2018 21:41:12 +0900 Masami Hiramatsu <mhiramat at kernel.org>…
Current print argument functions prints the argument name too. It is not good for printing out multiple values for one argument. This change it to just print out the value.
Quoted 6 lines
Hi Masami,
This is a confusing change log, as I have no idea what this patch does. Can you add a "before" and "after" of what you mean. Some examples of what it currently does to show why it looks bad, and then an example of what it looks like after the patch.
OK, this is actually just a cleanup patch. No functional difference between "before" and "after". For more flexible argument, like array type, we need to decouple with argument name and its value printing. Is below more clear to you?
Cleanup argument-printing functions to decouple it into name-printing and value-printing, so that it can support more flexible argument expression, like array type.
Thanks,
Quoted 9 lines
Thanks!
-- Steve
Quoted 3 lines
Signed-off-by Masami Hiramatsu <mhiramat at kernel.org>
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Steven Rostedt
maintainerRe: [PATCH v6 05/21] tracing: probeevent: Cleanup print argument functions
Quoted 10 lines · On Mon, 26 Mar 2018 13:17:33 +0900 Masami Hiramatsu <mhiramat at kernel.org>…
Quoted 7 lines
Quoted 4 lines · Masami Hiramatsu
Current print argument functions prints the argument name too. It is not good for printing out multiple values for one argument. This change it to just print out the value.
Quoted 3 lines
Cleanup argument-printing functions to decouple it into name-printing and value-printing, so that it can support more flexible argument expression, like array type.
Ah, so this is a change to make it possible in the next patches to do something more? I'll update the change log to your above.
That makes more sense. Thanks.
-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerRe: [PATCH v6 05/21] tracing: probeevent: Cleanup print argument functions
Quoted 13 lines · On Mon, 26 Mar 2018 13:28:32 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 10 lines · On Mon, 26 Mar 2018 13:17:33 +0900 Masami Hiramatsu <[email protected]> wrote:
Quoted 7 lines
Quoted 4 lines · Masami Hiramatsu
Current print argument functions prints the argument name too. It is not good for printing out multiple values for one argument. This change it to just print out the value.
Quoted 6 lines
Quoted 3 lines
Cleanup argument-printing functions to decouple it into name-printing and value-printing, so that it can support more flexible argument expression, like array type.
Ah, so this is a change to make it possible in the next patches to do something more? I'll update the change log to your above.
Yes, I'll update the patch description :)
Thanks!
Quoted 5 lines
That makes more sense. Thanks.
-- Steve
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 6/21 tracing: probeevent: Cleanup argument field definition
In reply to Masami HiramatsuCleanup event argument definition code in one place for maintenancability.
--- kernel/trace/trace_kprobe.c | 32 ++++---------------------------- kernel/trace/trace_probe.c | 21 +++++++++++++++++++++ kernel/trace/trace_probe.h | 2 ++ kernel/trace/trace_uprobe.c | 15 ++------------- 4 files changed, 29 insertions(+), 41 deletions(-)
kernel/trace/trace_kprobe.c +4 -28
@@ -1146,49 +1146,25 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,static int kprobe_event_define_fields (struct trace_event_call *event_call) { -int ret, i; +int ret;struct kprobe_trace_entry_head field;struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data; DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); -/* Set argument names as fields */ -for (i =0 ; i < tk->tp.nr_args; i++) { -struct probe_arg *parg = &tk->tp.args[i]; - ret =trace_define_field (event_call, parg->type->fmttype, - parg->name, -sizeof (field) + parg->offset, - parg->type->size, - parg->type->is_signed, -FILTER_OTHER ); -if (ret) -return ret; - } -return 0 ; +return traceprobe_define_arg_fields (event_call,sizeof (field), &tk->tp); }static int kretprobe_event_define_fields (struct trace_event_call *event_call) { -int ret, i; +int ret;struct kretprobe_trace_entry_head field;struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data; DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0); -/* Set argument names as fields */ -for (i =0 ; i < tk->tp.nr_args; i++) { -struct probe_arg *parg = &tk->tp.args[i]; - ret =trace_define_field (event_call, parg->type->fmttype, - parg->name, -sizeof (field) + parg->offset, - parg->type->size, - parg->type->is_signed, -FILTER_OTHER ); -if (ret) -return ret; - } -return 0 ; +return traceprobe_define_arg_fields (event_call,sizeof (field), &tk->tp); }#ifdef CONFIG_PERF_EVENTS
kernel/trace/trace_probe.c +21 -0
@@ -680,3 +680,24 @@ int set_print_fmt(struct trace_probe *tp, bool is_return)return 0 ; } + +int traceprobe_define_arg_fields (struct trace_event_call *event_call, +size_t offset,struct trace_probe *tp) +{ +int ret, i; + +/* Set argument names as fields */ +for (i =0 ; i < tp->nr_args; i++) { +struct probe_arg *parg = &tp->args[i]; + + ret =trace_define_field (event_call, parg->type->fmttype, + parg->name, + offset + parg->offset, + parg->type->size, + parg->type->is_signed, +FILTER_OTHER ); +if (ret) +return ret; + } +return 0 ; +}
kernel/trace/trace_probe.h +2 -0
@@ -440,3 +440,5 @@ extern struct trace_event_call * create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);extern void destroy_local_trace_uprobe (struct trace_event_call *event_call);#endif +extern int traceprobe_define_arg_fields (struct trace_event_call *event_call, +size_t offset,struct trace_probe *tp);
kernel/trace/trace_uprobe.c +2 -13
@@ -982,7 +982,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)static int uprobe_event_define_fields (struct trace_event_call *event_call) { -int ret, i, size; +int ret, size;struct uprobe_trace_entry_head field;struct trace_uprobe *tu = event_call->data;
@@ -994,19 +994,8 @@ static int uprobe_event_define_fields(struct trace_event_call *event_call) DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0); size =SIZEOF_TRACE_ENTRY (false); } -/* Set argument names as fields */ -for (i =0 ; i < tu->tp.nr_args; i++) { -struct probe_arg *parg = &tu->tp.args[i]; - - ret =trace_define_field (event_call, parg->type->fmttype, - parg->name, size + parg->offset, - parg->type->size, parg->type->is_signed, -FILTER_OTHER ); -if (ret) -return ret; - } -return 0 ; +return traceprobe_define_arg_fields (event_call, size, &tu->tp); }#ifdef CONFIG_PERF_EVENTS
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 7/21 tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
In reply to Masami HiramatsuRemove unneeded NOKPROBE_SYMBOL from print functions since the print functions are only used when printing out the trace data, and not from kprobe handler.
--- kernel/trace/trace_probe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
kernel/trace/trace_probe.c +1 -3
@@ -43,8 +43,7 @@ int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\trace_seq_printf (s, fmt, *(type *)data); \return !trace_seq_has_overflowed (s); \ } \ -const char PRINT_TYPE_FMT_NAME (tname )[] = fmt; \ -NOKPROBE_SYMBOL (PRINT_TYPE_FUNC_NAME (tname)); +const char PRINT_TYPE_FMT_NAME (tname )[] = fmt; DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u")DEFINE_BASIC_PRINT_TYPE_FUNC (u16, u16,"%u" )
@@ -71,7 +70,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) (const char *)get_loc_data(data, ent));return !trace_seq_has_overflowed (s); } -NOKPROBE_SYMBOL (PRINT_TYPE_FUNC_NAME (string));const char PRINT_TYPE_FMT_NAME (string )[] ="\\\"%s\\\"" ;
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 8/21 tracing: probeevent: Introduce new argument fetching code
In reply to Masami HiramatsuReplace {k,u}probe event argument fetching framework with switch-case based. Currently that is implemented with structures, macros and chain of function-pointers, which is more complicated than necessary and may get a performance penalty by retpoline.
This simplify that with an array of "fetch_insn" (opcode and oprands), and make process_fetch_insn() just interprets it. No function pointers are used.
---
Changes in v3:
- Split out probe type table unification.
--- kernel/trace/trace_kprobe.c | 291 +++++++++++++--------------- kernel/trace/trace_probe.c | 401 +++++++++++---------------------------- kernel/trace/trace_probe.h | 230 ++++------------------ kernel/trace/trace_probe_tmpl.h | 120 ++++++++++++ kernel/trace/trace_uprobe.c | 127 ++++++++---- 5 files changed, 491 insertions(+), 678 deletions(-) create mode 100644 kernel/trace/trace_probe_tmpl.h
kernel/trace/trace_kprobe.c +131 -160
@@ -24,6 +24,7 @@#include <linux/error-injection.h> #include "trace_probe.h" +#include "trace_probe_tmpl.h" #define KPROBE_EVENT_SYSTEM "kprobes"#define KRETPROBE_MAXACTIVE_MAX 4096
@@ -121,160 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);static int kretprobe_dispatcher (struct kretprobe_instance *ri,struct pt_regs *regs); -/* Memory fetching by symbol */ -struct symbol_cache { -char *symbol; -long offset; -unsigned long addr; -}; - -unsigned long update_symbol_cache (struct symbol_cache *sc) -{ - sc->addr = (unsigned long )kallsyms_lookup_name (sc->symbol); - -if (sc->addr) - sc->addr += sc->offset; - -return sc->addr; -} - -void free_symbol_cache (struct symbol_cache *sc) -{ -kfree (sc->symbol); -kfree (sc); -} - -struct symbol_cache *alloc_symbol_cache (const char *sym,long offset) -{ -struct symbol_cache *sc; - -if (!sym ||strlen (sym) ==0 ) -return NULL ; - - sc =kzalloc (sizeof (struct symbol_cache ),GFP_KERNEL ); -if (!sc) -return NULL ; - - sc->symbol =kstrdup (sym,GFP_KERNEL ); -if (!sc->symbol) { -kfree (sc); -return NULL ; - } - sc->offset = offset; -update_symbol_cache (sc); - -return sc; -} - -/* -* Kprobes-specific fetch functions -*/ -#define DEFINE_FETCH_stack (type) \ -static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ - void *offset, void *dest) \ -{ \ - *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ - (unsigned int)((unsigned long)offset)); \ -} \ -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type)); - -DEFINE_BASIC_FETCH_FUNCS (stack) -/* No string on the stack entry */ -#define fetch_stack_string NULL -#define fetch_stack_string_size NULL - -#define DEFINE_FETCH_memory (type) \ -static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ - void *addr, void *dest) \ -{ \ - type retval; \ - if (probe_kernel_address(addr, retval)) \ - *(type *)dest = 0; \ - else \ - *(type *)dest = retval; \ -} \ -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type)); - -DEFINE_BASIC_FETCH_FUNCS (memory) -/* -* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max -* length and relative data location. -*/ -static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, -void *addr,void *dest) -{ -int maxlen =get_rloc_len (*(u32 *)dest); -u8 *dst =get_rloc_data (dest); -long ret; - -if (!maxlen) -return ; - -/* -* Try to get string again, since the string can be changed while -* probing. -*/ - ret =strncpy_from_unsafe (dst, addr, maxlen); - -if (ret <0 ) {/* Failed to fetch string */ - dst[0 ] ='\0' ; - *(u32 *)dest =make_data_rloc (0 ,get_rloc_offs (*(u32 *)dest)); - }else { - *(u32 *)dest =make_data_rloc (ret,get_rloc_offs (*(u32 *)dest)); - } -} -NOKPROBE_SYMBOL (FETCH_FUNC_NAME (memory, string)); - -/* Return the length of string -- including null terminal byte */ -static void FETCH_FUNC_NAME (memory ,string_size )(struct pt_regs *regs, -void *addr,void *dest) -{ -mm_segment_t old_fs; -int ret, len =0 ; -u8 c; - - old_fs =get_fs (); -set_fs (KERNEL_DS ); -pagefault_disable (); - -do { - ret =__copy_from_user_inatomic (&c, (u8 *)addr + len,1 ); - len++; - }while (c && ret ==0 && len <MAX_STRING_SIZE ); - -pagefault_enable (); -set_fs (old_fs); - -if (ret <0 )/* Failed to check the length */ - *(u32 *)dest =0 ; -else - *(u32 *)dest = len; -} -NOKPROBE_SYMBOL (FETCH_FUNC_NAME (memory, string_size)); - -#define DEFINE_FETCH_symbol (type) \ -void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\ -{ \ - struct symbol_cache *sc = data; \ - if (sc->addr) \ - fetch_memory_##type(regs, (void *)sc->addr, dest); \ - else \ - *(type *)dest = 0; \ -} \ -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type)); - -DEFINE_BASIC_FETCH_FUNCS(symbol) -DEFINE_FETCH_symbol(string) -DEFINE_FETCH_symbol(string_size) - -/* kprobes don't support file_offset fetch methods */ -#define fetch_file_offset_u8 NULL -#define fetch_file_offset_u16 NULL -#define fetch_file_offset_u32 NULL -#define fetch_file_offset_u64 NULL -#define fetch_file_offset_string NULL -#define fetch_file_offset_string_size NULL -/* Fetch type information table */ static const struct fetch_type kprobes_fetch_type_table[] = {/* Special types */
@@ -490,14 +337,11 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)/* Internal register function - just handle k*probes and flags */ static int __register_trace_kprobe (struct trace_kprobe *tk) { -int i, ret; +int ret;if (trace_probe_is_registered (&tk->tp))return -EINVAL ; -for (i =0 ; i < tk->tp.nr_args; i++) -traceprobe_update_arg (&tk->tp.args[i]); -/* Set/clear disabled flag according to tp->flag */ if (trace_probe_is_enabled (&tk->tp)) tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED ;
@@ -830,8 +674,8 @@ static int create_trace_kprobe(int argc, char **argv)/* Parse fetch argument */ ret =traceprobe_parse_probe_arg (arg, &tk->tp.size, parg, - is_return, true, - kprobes_fetch_type_table); + is_return, true, + kprobes_fetch_type_table);if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
@@ -985,6 +829,133 @@ static const struct file_operations kprobe_profile_ops = { .release = seq_release, }; +/* Kprobe specific fetch functions */ + +/* Return the length of string -- including null terminal byte */ +static nokprobe_inline void +fetch_store_strlen (unsigned long addr,void *dest) +{ +mm_segment_t old_fs; +int ret, len =0 ; +u8 c; + + old_fs =get_fs (); +set_fs (KERNEL_DS ); +pagefault_disable (); + +do { + ret =__copy_from_user_inatomic (&c, (u8 *)addr + len,1 ); + len++; + }while (c && ret ==0 && len <MAX_STRING_SIZE ); + +pagefault_enable (); +set_fs (old_fs); + +if (ret <0 )/* Failed to check the length */ + *(u32 *)dest =0 ; +else + *(u32 *)dest = len; +} + +/* +* Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max +* length and relative data location. +*/ +static nokprobe_inline void +fetch_store_string (unsigned long addr,void *dest) +{ +int maxlen =get_rloc_len (*(u32 *)dest); +u8 *dst =get_rloc_data (dest); +long ret; + +if (!maxlen) +return ; + +/* +* Try to get string again, since the string can be changed while +* probing. +*/ + ret =strncpy_from_unsafe (dst, (void *)addr, maxlen); + +if (ret <0 ) {/* Failed to fetch string */ + dst[0 ] ='\0' ; + *(u32 *)dest =make_data_rloc (0 ,get_rloc_offs (*(u32 *)dest)); + }else { + *(u32 *)dest =make_data_rloc (ret,get_rloc_offs (*(u32 *)dest)); + } +} + +/* Note that we don't verify it, since the code does not come from user space */ +static int +process_fetch_insn (struct fetch_insn *code,struct pt_regs *regs,void *dest, +bool pre) +{ +unsigned long val; +int ret; + +/* 1st stage: get value from context */ +switch (code->op) { +case FETCH_OP_REG : + val =regs_get_register (regs, code->param); +break ; +case FETCH_OP_STACK : + val =regs_get_kernel_stack_nth (regs, code->param); +break ; +case FETCH_OP_STACKP : + val =kernel_stack_pointer (regs); +break ; +case FETCH_OP_RETVAL : + val =regs_return_value (regs); +break ; +case FETCH_OP_IMM : + val = code->immediate; +break ; +case FETCH_OP_COMM : + val = (unsigned long )current->comm; +break ; +default : +return -EILSEQ ; + } + code++; + +/* 2nd stage: dereference memory if needed */ +while (code->op ==FETCH_OP_DEREF ) { + ret =probe_kernel_read (&val, (void *)val + code->offset, +sizeof (val)); +if (ret) +return ret; + code++; + } + +/* 3rd stage: store value to buffer */ +switch (code->op) { +case FETCH_OP_ST_RAW : +fetch_store_raw (val, code, dest); +break ; +case FETCH_OP_ST_MEM : +probe_kernel_read (dest, (void *)val + code->offset, code->size); +break ; +case FETCH_OP_ST_STRING : +if (pre) +fetch_store_strlen (val + code->offset, dest); +else +fetch_store_string (val + code->offset, dest); +break ; +default : +return -EILSEQ ; + } + code++; + +/* 4th stage: modify stored value if needed */ +if (code->op ==FETCH_OP_MOD_BF ) { +fetch_apply_bitfield (code, dest); + code++; + } + +return code->op ==FETCH_OP_END ?0 : -EILSEQ ; +} +NOKPROBE_SYMBOL (process_fetch_insn) +/* Kprobe handler */ static nokprobe_inline void __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
kernel/trace/trace_probe.c +112 -289
541 lines not on this page · raw message
kernel/trace/trace_probe.h +43 -187
294 lines not on this page · raw message
kernel/trace/trace_probe_tmpl.h new file +120 -0
120 lines not on this page · raw message
kernel/trace/trace_uprobe.c +85 -42
170 lines not on this page · raw message
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 9/21 tracing: probeevent: Unify fetch type tables
In reply to Masami HiramatsuUnify {k,u}probe_fetch_type_table to probe_fetch_type_table because the main difference of those type tables (fetcharg methods) are gone. Now we can consolidate it.
--- kernel/trace/trace_kprobe.c | 27 +--------------------- kernel/trace/trace_probe.c | 54 +++++++++++++++++++++++++++++-------------- kernel/trace/trace_probe.h | 6 +---- kernel/trace/trace_uprobe.c | 27 +--------------------- 4 files changed, 39 insertions(+), 75 deletions(-)
kernel/trace/trace_kprobe.c +1 -26
@@ -122,30 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);static int kretprobe_dispatcher (struct kretprobe_instance *ri,struct pt_regs *regs); -/* Fetch type information table */ -static const struct fetch_type kprobes_fetch_type_table[] = { -/* Special types */ - [FETCH_TYPE_STRING ] =__ASSIGN_FETCH_TYPE ("string" , string, string, -sizeof (u32),1 ,"__data_loc char[]" ), - [FETCH_TYPE_STRSIZE ] =__ASSIGN_FETCH_TYPE ("string_size" , u32, - string_size,sizeof (u32),0 ,"u32" ), -/* Basic types */ -ASSIGN_FETCH_TYPE (u8, u8,0 ), -ASSIGN_FETCH_TYPE (u16, u16,0 ), -ASSIGN_FETCH_TYPE (u32, u32,0 ), -ASSIGN_FETCH_TYPE (u64, u64,0 ), -ASSIGN_FETCH_TYPE (s8, u8,1 ), -ASSIGN_FETCH_TYPE (s16, u16,1 ), -ASSIGN_FETCH_TYPE (s32, u32,1 ), -ASSIGN_FETCH_TYPE (s64, u64,1 ), -ASSIGN_FETCH_TYPE_ALIAS (x8, u8, u8,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x16, u16, u16,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x32, u32, u32,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x64, u64, u64,0 ), - -ASSIGN_FETCH_TYPE_END -}; -/* * Allocate new trace_probe and initialize it (including kprobes). */
@@ -674,8 +650,7 @@ static int create_trace_kprobe(int argc, char **argv)/* Parse fetch argument */ ret =traceprobe_parse_probe_arg (arg, &tk->tp.size, parg, - is_return, true, - kprobes_fetch_type_table); + is_return, true);if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
kernel/trace/trace_probe.c +36 -18
107 lines not on this page · raw message
kernel/trace/trace_probe.h +1 -5
@@ -196,9 +196,6 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);#define ASSIGN_FETCH_TYPE_END {} -#define FETCH_TYPE_STRING 0 -#define FETCH_TYPE_STRSIZE 1 -#ifdef CONFIG_KPROBE_EVENTS bool trace_kprobe_on_func_entry (struct trace_event_call *call);bool trace_kprobe_error_injectable (struct trace_event_call *call);
@@ -273,8 +270,7 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file) }extern int traceprobe_parse_probe_arg (char *arg,ssize_t *size, -struct probe_arg *parg,bool is_return,bool is_kprobe, -const struct fetch_type *ftbl); +struct probe_arg *parg,bool is_return,bool is_kprobe);extern int traceprobe_conflict_field_name (const char *name,struct probe_arg *args,int narg);
kernel/trace/trace_uprobe.c +1 -26
@@ -169,30 +169,6 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)return base_addr + file_offset; } -/* Fetch type information table */ -static const struct fetch_type uprobes_fetch_type_table[] = { -/* Special types */ - [FETCH_TYPE_STRING ] =__ASSIGN_FETCH_TYPE ("string" , string, string, -sizeof (u32),1 ,"__data_loc char[]" ), - [FETCH_TYPE_STRSIZE ] =__ASSIGN_FETCH_TYPE ("string_size" , u32, - string_size,sizeof (u32),0 ,"u32" ), -/* Basic types */ -ASSIGN_FETCH_TYPE (u8, u8,0 ), -ASSIGN_FETCH_TYPE (u16, u16,0 ), -ASSIGN_FETCH_TYPE (u32, u32,0 ), -ASSIGN_FETCH_TYPE (u64, u64,0 ), -ASSIGN_FETCH_TYPE (s8, u8,1 ), -ASSIGN_FETCH_TYPE (s16, u16,1 ), -ASSIGN_FETCH_TYPE (s32, u32,1 ), -ASSIGN_FETCH_TYPE (s64, u64,1 ), -ASSIGN_FETCH_TYPE_ALIAS (x8, u8, u8,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x16, u16, u16,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x32, u32, u32,0 ), -ASSIGN_FETCH_TYPE_ALIAS (x64, u64, u64,0 ), - -ASSIGN_FETCH_TYPE_END -}; -/* Note that we don't verify it, since the code does not come from user space */ static int process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
@@ -581,8 +557,7 @@ static int create_trace_uprobe(int argc, char **argv)/* Parse fetch argument */ ret =traceprobe_parse_probe_arg (arg, &tu->tp.size, parg, - is_return, false, - uprobes_fetch_type_table); + is_return, false);if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 10/21 tracing: probeevent: Return consumed bytes of dynamic area
In reply to Masami HiramatsuCleanup string fetching routine so that returns the consumed bytes of dynamic area and store the string information as data_loc format instead of data_rloc.
This simplifies the fetcharg loop.
--- kernel/trace/trace_kprobe.c | 51 +++++++++++++++++++------------------- kernel/trace/trace_probe.h | 26 ++++--------------- kernel/trace/trace_probe_tmpl.h | 52 +++++++++++++++++--------------------- kernel/trace/trace_uprobe.c | 53 ++++++++++++++++++++------------------- 4 files changed, 82 insertions(+), 100 deletions(-)
kernel/trace/trace_kprobe.c +26 -25
@@ -807,8 +807,8 @@ static const struct file_operations kprobe_profile_ops = {/* Kprobe specific fetch functions */ /* Return the length of string -- including null terminal byte */ -static nokprobe_inline void -fetch_store_strlen (unsigned long addr,void *dest) +static nokprobe_inline int +fetch_store_strlen (unsigned long addr) {mm_segment_t old_fs;int ret, len =0 ;
@@ -826,25 +826,22 @@ fetch_store_strlen(unsigned long addr, void *dest)pagefault_enable ();set_fs (old_fs); -if (ret <0 )/* Failed to check the length */ - *(u32 *)dest =0 ; -else - *(u32 *)dest = len; +return (ret <0 ) ? ret : len; }/* * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max * length and relative data location. */ -static nokprobe_inline void -fetch_store_string (unsigned long addr,void *dest) +static nokprobe_inline int +fetch_store_string (unsigned long addr,void *dest,void *base) { -int maxlen =get_rloc_len (*(u32 *)dest); -u8 *dst =get_rloc_data (dest); +int maxlen =get_loc_len (*(u32 *)dest); +u8 *dst =get_loc_data (dest, base);long ret;if (!maxlen) -return ; +return -ENOMEM ;/* * Try to get string again, since the string can be changed while
@@ -854,19 +851,19 @@ fetch_store_string(unsigned long addr, void *dest)if (ret <0 ) {/* Failed to fetch string */ dst[0 ] ='\0' ; - *(u32 *)dest =make_data_rloc (0 ,get_rloc_offs (*(u32 *)dest)); - }else { - *(u32 *)dest =make_data_rloc (ret,get_rloc_offs (*(u32 *)dest)); + ret =0 ; } + *(u32 *)dest =make_data_loc (ret, (void *)dst - base); +return ret; }/* Note that we don't verify it, since the code does not come from user space */ static int process_fetch_insn (struct fetch_insn *code,struct pt_regs *regs,void *dest, -bool pre) +void *base) {unsigned long val; -int ret; +int ret =0 ;/* 1st stage: get value from context */ switch (code->op) {
@@ -903,6 +900,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, }/* 3rd stage: store value to buffer */ +if (unlikely (!dest)) { +if (code->op ==FETCH_OP_ST_STRING ) +return fetch_store_strlen (val + code->offset); +else +return -EILSEQ ; + } +switch (code->op) {case FETCH_OP_ST_RAW :fetch_store_raw (val, code, dest);
@@ -911,10 +915,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,probe_kernel_read (dest, (void *)val + code->offset, code->size);break ;case FETCH_OP_ST_STRING : -if (pre) -fetch_store_strlen (val + code->offset, dest); -else -fetch_store_string (val + code->offset, dest); + ret =fetch_store_string (val + code->offset, dest, base);break ;default :return -EILSEQ ;
@@ -927,7 +928,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, code++; } -return code->op ==FETCH_OP_END ?0 : -EILSEQ ; +return code->op ==FETCH_OP_END ? ret : -EILSEQ ; }NOKPROBE_SYMBOL (process_fetch_insn)
@@ -962,7 +963,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, entry =ring_buffer_event_data (event); entry->ip = (unsigned long )tk->rp.kp.addr; -store_trace_args (sizeof (*entry), &tk->tp, regs, (u8 *)&entry[1 ], dsize); +store_trace_args (&entry[1 ], &tk->tp, regs,sizeof (*entry), dsize);event_trigger_unlock_commit_regs (trace_file, buffer, event, entry, irq_flags, pc, regs);
@@ -1011,7 +1012,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, entry =ring_buffer_event_data (event); entry->func = (unsigned long )tk->rp.kp.addr; entry->ret_ip = (unsigned long )ri->ret_addr; -store_trace_args (sizeof (*entry), &tk->tp, regs, (u8 *)&entry[1 ], dsize); +store_trace_args (&entry[1 ], &tk->tp, regs,sizeof (*entry), dsize);event_trigger_unlock_commit_regs (trace_file, buffer, event, entry, irq_flags, pc, regs);
@@ -1162,7 +1163,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) entry->ip = (unsigned long )tk->rp.kp.addr;memset (&entry[1 ],0 , dsize); -store_trace_args (sizeof (*entry), &tk->tp, regs, (u8 *)&entry[1 ], dsize); +store_trace_args (&entry[1 ], &tk->tp, regs,sizeof (*entry), dsize);perf_trace_buf_submit (entry, size, rctx, call->event.type,1 , regs, head,NULL );return 0 ;
@@ -1198,7 +1199,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, entry->func = (unsigned long )tk->rp.kp.addr; entry->ret_ip = (unsigned long )ri->ret_addr; -store_trace_args (sizeof (*entry), &tk->tp, regs, (u8 *)&entry[1 ], dsize); +store_trace_args (&entry[1 ], &tk->tp, regs,sizeof (*entry), dsize);perf_trace_buf_submit (entry, size, rctx, call->event.type,1 , regs, head,NULL ); }
kernel/trace/trace_probe.h +6 -20
@@ -66,29 +66,15 @@#define TP_FLAG_PROFILE 2#define TP_FLAG_REGISTERED 4 +/* data_loc: data location, compatible with u32 */ +#define make_data_loc (len, offs) \ + (((u32)(len) << 16) | ((u32)(offs) & 0xffff)) +#define get_loc_len (dl) ((u32)(dl) >> 16) +#define get_loc_offs (dl) ((u32)(dl) & 0xffff) -/* data_rloc: data relative location, compatible with u32 */ -#define make_data_rloc (len, roffs) \ - (((u32)(len) << 16) | ((u32)(roffs) & 0xffff)) -#define get_rloc_len (dl) ((u32)(dl) >> 16) -#define get_rloc_offs (dl) ((u32)(dl) & 0xffff) - -/* -* Convert data_rloc to data_loc: -* data_rloc stores the offset from data_rloc itself, but data_loc -* stores the offset from event entry. -*/ -#define convert_rloc_to_loc (dl, offs) ((u32)(dl) + (offs)) - -static nokprobe_inline void *get_rloc_data(u32 *dl) -{ -return (u8 *)dl +get_rloc_offs (*dl); -} - -/* For data_loc conversion */ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent) { -return (u8 *)ent +get_rloc_offs (*dl); +return (u8 *)ent +get_loc_offs (*dl); }/* Printing function type */
kernel/trace/trace_probe_tmpl.h +23 -29
81 lines not on this page · raw message
kernel/trace/trace_uprobe.c +27 -26
117 lines not on this page · raw message
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Steven Rostedt
maintainerRe: [PATCH v6 10/21] tracing: probeevent: Return consumed bytes of dynamic area
Quoted 18 lines · On Sat, 17 Mar 2018 21:44:52 +0900 Masami Hiramatsu <[email protected]> wrote:
kernel/trace/trace_kprobe.c +5
-5-static nokprobe_inline void -fetch_store_string (unsigned long addr,void *dest) +static nokprobe_inline int +fetch_store_string (unsigned long addr,void *dest,void *base) { -int maxlen =get_rloc_len (*(u32 *)dest); -u8 *dst =get_rloc_data (dest); +int maxlen =get_loc_len (*(u32 *)dest); +u8 *dst =get_loc_data (dest, base);long ret;if (!maxlen) -return ; +return -ENOMEM ;/* * Try to get string again, since the string can be changed while
kernel/trace/trace_kprobe.c fetch_store_string(unsigned long addr, void *dest) · line 854
Quoted 7 lines
kernel/trace/trace_kprobe.c +1
-3@@ -854,19 +851,19 @@ fetch_store_string(unsigned long addr, void *dest)if (ret <0 ) {/* Failed to fetch string */ dst[0 ] ='\0' ; - *(u32 *)dest =make_data_rloc (0 ,get_rloc_offs (*(u32 *)dest)); - }else { - *(u32 *)dest =make_data_rloc (ret,get_rloc_offs (*(u32 *)dest)); + ret =0 ;
Why do you return 0 here and not the error value? You return -ENOMEM above if maxlen is zero.
-- Steve
kernel/trace/trace_kprobe.c fetch_store_string(unsigned long addr, void *dest) · line 858
Quoted 4 lines
kernel/trace/trace_kprobe.c +2
-0} + *(u32 *)dest =make_data_loc (ret, (void *)dst - base); +return ret; }
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerRe: [PATCH v6 10/21] tracing: probeevent: Return consumed bytes of dynamic area
Quoted 22 lines · On Mon, 2 Apr 2018 16:02:07 -0400 Steven Rostedt <rostedt at goodmis.org> wrote:
Quoted 19 lines · On Sat, 17 Mar 2018 21:44:52 +0900 Masami Hiramatsu <mhiramat at kernel.org>…
kernel/trace/trace_kprobe.c +5
-5-static nokprobe_inline void -fetch_store_string (unsigned long addr,void *dest) +static nokprobe_inline int +fetch_store_string (unsigned long addr,void *dest,void *base) { -int maxlen =get_rloc_len (*(u32 *)dest); -u8 *dst =get_rloc_data (dest); +int maxlen =get_loc_len (*(u32 *)dest); +u8 *dst =get_loc_data (dest, base);long ret;if (!maxlen) -return ; +return -ENOMEM ;/* * Try to get string again, since the string can be changed while @@ -854,19 +851,19 @@ fetch_store_string(unsigned long addr, void *dest)
Quoted 9 lines
kernel/trace/trace_kprobe.c fetch_store_string(unsigned long addr, void *dest) · line 854
Quoted 6 lines
kernel/trace/trace_kprobe.c +1
-3if (ret <0 ) {/* Failed to fetch string */ dst[0 ] ='\0' ; - *(u32 *)dest =make_data_rloc (0 ,get_rloc_offs (*(u32 *)dest)); - }else { - *(u32 *)dest =make_data_rloc (ret,get_rloc_offs (*(u32 *)dest)); + ret =0 ;Why do you return 0 here and not the error value? You return
-ENOMEMabove if maxlen is zero.
Good catch! it should clear dst[0] and return 0 even if no buffer remains... OK, I'll fix it.
Thank you!
Quoted 7 lines
-- Steve
Quoted 4 lines
kernel/trace/trace_kprobe.c +2
-0} + *(u32 *)dest =make_data_loc (ret, (void *)dst - base); +return ret; }
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 11/21 tracing: probeevent: Append traceprobe_ for exported function
In reply to Masami HiramatsuAppend traceprobe_ for exported function set_print_fmt() as same as other functions.
--- kernel/trace/trace_kprobe.c | 4 ++-- kernel/trace/trace_probe.c | 2 +- kernel/trace/trace_probe.h | 2 +- kernel/trace/trace_uprobe.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-)
kernel/trace/trace_kprobe.c +2 -2
@@ -1305,7 +1305,7 @@ static int register_kprobe_event(struct trace_kprobe *tk)init_trace_event_call (tk, call); -if (set_print_fmt (&tk->tp,trace_kprobe_is_return (tk)) <0 ) +if (traceprobe_set_print_fmt (&tk->tp,trace_kprobe_is_return (tk)) <0 )return -ENOMEM ; ret =register_trace_event (&call->event);if (!ret) {
@@ -1362,7 +1362,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,init_trace_event_call (tk, &tk->tp.call); -if (set_print_fmt (&tk->tp,trace_kprobe_is_return (tk)) <0 ) { +if (traceprobe_set_print_fmt (&tk->tp,trace_kprobe_is_return (tk)) <0 ) { ret = -ENOMEM ; goto error; }
kernel/trace/trace_probe.c +1 -1
@@ -502,7 +502,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,return pos; } -int set_print_fmt (struct trace_probe *tp,bool is_return) +int traceprobe_set_print_fmt (struct trace_probe *tp,bool is_return) {int len;char *print_fmt;
kernel/trace/trace_probe.h +1 -1
@@ -266,7 +266,7 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg);extern int traceprobe_split_symbol_offset (char *symbol,long *offset); -extern int set_print_fmt (struct trace_probe *tp,bool is_return); +extern int traceprobe_set_print_fmt (struct trace_probe *tp,bool is_return);#ifdef CONFIG_PERF_EVENTS extern struct trace_event_call *
kernel/trace/trace_uprobe.c +2 -2
@@ -1314,7 +1314,7 @@ static int register_uprobe_event(struct trace_uprobe *tu)init_trace_event_call (tu, call); -if (set_print_fmt (&tu->tp,is_ret_probe (tu)) <0 ) +if (traceprobe_set_print_fmt (&tu->tp,is_ret_probe (tu)) <0 )return -ENOMEM ; ret =register_trace_event (&call->event);
@@ -1388,7 +1388,7 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return) tu->filename =kstrdup (name,GFP_KERNEL );init_trace_event_call (tu, &tu->tp.call); -if (set_print_fmt (&tu->tp,is_ret_probe (tu)) <0 ) { +if (traceprobe_set_print_fmt (&tu->tp,is_ret_probe (tu)) <0 ) { ret = -ENOMEM ; goto error; }
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 12/21 tracing: probeevent: Unify fetch_insn processing common part
In reply to Masami HiramatsuUnify the fetch_insn bottom process (from stage 2: dereference indirect data) from kprobe and uprobe events, since those are mostly same.
--- kernel/trace/trace_kprobe.c | 47 +++++---------------------------- kernel/trace/trace_probe_tmpl.h | 55 ++++++++++++++++++++++++++++++++++++++- kernel/trace/trace_uprobe.c | 43 +----------------------------- 3 files changed, 63 insertions(+), 82 deletions(-)
kernel/trace/trace_kprobe.c +7 -40
@@ -857,13 +857,18 @@ fetch_store_string(unsigned long addr, void *dest, void *base)return ret; } +static nokprobe_inline int +probe_mem_read (void *dest,void *src,size_t size) +{ +return probe_kernel_read (dest, src, size); +} +/* Note that we don't verify it, since the code does not come from user space */ static int process_fetch_insn (struct fetch_insn *code,struct pt_regs *regs,void *dest,void *base) {unsigned long val; -int ret =0 ;/* 1st stage: get value from context */ switch (code->op) {
@@ -890,45 +895,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, } code++; -/* 2nd stage: dereference memory if needed */ -while (code->op ==FETCH_OP_DEREF ) { - ret =probe_kernel_read (&val, (void *)val + code->offset, -sizeof (val)); -if (ret) -return ret; - code++; - } - -/* 3rd stage: store value to buffer */ -if (unlikely (!dest)) { -if (code->op ==FETCH_OP_ST_STRING ) -return fetch_store_strlen (val + code->offset); -else -return -EILSEQ ; - } - -switch (code->op) { -case FETCH_OP_ST_RAW : -fetch_store_raw (val, code, dest); -break ; -case FETCH_OP_ST_MEM : -probe_kernel_read (dest, (void *)val + code->offset, code->size); -break ; -case FETCH_OP_ST_STRING : - ret =fetch_store_string (val + code->offset, dest, base); -break ; -default : -return -EILSEQ ; - } - code++; - -/* 4th stage: modify stored value if needed */ -if (code->op ==FETCH_OP_MOD_BF ) { -fetch_apply_bitfield (code, dest); - code++; - } - -return code->op ==FETCH_OP_END ? ret : -EILSEQ ; +return process_fetch_insn_bottom (code, val, dest, base); }NOKPROBE_SYMBOL (process_fetch_insn)
kernel/trace/trace_probe_tmpl.h +54 -1
67 lines not on this page · raw message
kernel/trace/trace_uprobe.c +2 -41
61 lines not on this page · raw message
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 13/21 tracing: probeevent: Add symbol type
In reply to Masami HiramatsuAdd "symbol" type to probeevent, which is an alias of u32 or u64 (depends on BITS_PER_LONG). This shows the result value in symbol+offset style. This type is only available with kprobe events.
---
Changes in v2:
- Add symbol type to README file.
--- Documentation/trace/kprobetrace.txt | 3 +++ kernel/trace/trace.c | 2 +- kernel/trace/trace_probe.c | 8 ++++++++ kernel/trace/trace_probe.h | 12 +++++++++--- 4 files changed, 21 insertions(+), 4 deletions(-)
Documentation/trace/kprobetrace.txt +3 -0
@@ -62,6 +62,7 @@ respectively. 'x' prefix implies it is unsigned. Traced arguments are shown in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32' or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and x86-64 uses x64). + String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out.
@@ -70,6 +71,8 @@ offset, and container-size (usually 32). The syntax is; b<bit-width>@<bit-offset>/<container-size> +Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG) +which shows given pointer in "symbol+offset" style. For $comm, the default type is "string"; any other type is invalid.
kernel/trace/trace.c +1 -1
@@ -4609,7 +4609,7 @@ static const char readme_msg[] ="\t args: <name>=fetcharg[:type]\n" "\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n" "\t $stack<index>, $stack, $retval, $comm\n" -"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string,\n" +"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n" "\t b<bit-width>@<bit-offset>/<container-size>\n"#endif " events/\t\t- Directory containing all trace event subsystems:\n"
kernel/trace/trace_probe.c +8 -0
@@ -58,6 +58,13 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") +int PRINT_TYPE_FUNC_NAME (symbol )(struct trace_seq *s,void *data,void *ent) +{ +trace_seq_printf (s,"%pS" , (void *)*(unsigned long *)data); +return !trace_seq_has_overflowed (s); +} +const char PRINT_TYPE_FMT_NAME (symbol )[] ="%pS" ; +/* Print type function for string type */ int PRINT_TYPE_FUNC_NAME (string )(struct trace_seq *s,void *data,void *ent) {
@@ -91,6 +98,7 @@ static const struct fetch_type probe_fetch_types[] = {ASSIGN_FETCH_TYPE_ALIAS (x16, u16, u16,0 ),ASSIGN_FETCH_TYPE_ALIAS (x32, u32, u32,0 ),ASSIGN_FETCH_TYPE_ALIAS (x64, u64, u64,0 ), +ASSIGN_FETCH_TYPE_ALIAS (symbol,ADDR_FETCH_TYPE ,ADDR_FETCH_TYPE ,0 ), ASSIGN_FETCH_TYPE_END };
kernel/trace/trace_probe.h +9 -3
@@ -157,6 +157,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x32);DECLARE_BASIC_PRINT_TYPE_FUNC (x64);DECLARE_BASIC_PRINT_TYPE_FUNC (string); +DECLARE_BASIC_PRINT_TYPE_FUNC (symbol);/* Default (unsigned long) fetch type */ #define __DEFAULT_FETCH_TYPE (t) x##t
@@ -164,6 +165,10 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) +#define __ADDR_FETCH_TYPE (t) u##t +#define _ADDR_FETCH_TYPE (t) __ADDR_FETCH_TYPE(t) +#define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG) +#define __ASSIGN_FETCH_TYPE (_name, ptype, ftype, _size, sign, _fmttype) \ {.name = _name, \ .size = _size, \
@@ -172,13 +177,14 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string); .fmt = PRINT_TYPE_FMT_NAME(ptype), \ .fmttype = _fmttype, \ } - +#define _ASSIGN_FETCH_TYPE (_name, ptype, ftype, _size, sign, _fmttype) \ + __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)#define ASSIGN_FETCH_TYPE (ptype, ftype, sign) \ - __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype) + _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)/* If ptype is an alias of atype, use this macro (show atype in format) */ #define ASSIGN_FETCH_TYPE_ALIAS (ptype, atype, ftype, sign) \ - __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #atype) + _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)#define ASSIGN_FETCH_TYPE_END {}
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 14/21 x86: ptrace: Add function argument access API
In reply to Masami HiramatsuAdd regs_get_argument() which returns N th argument of the function call.
Note that this chooses most probably assignment, in some case it can be incorrect (e.g. passing data structure or floating point etc.)
This is expected to be called from kprobes or ftrace with regs where the top of stack is the return address.
--- arch/Kconfig | 7 +++++++ arch/x86/Kconfig | 1 + arch/x86/include/asm/ptrace.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+)
arch/Kconfig +7 -0
@@ -272,6 +272,13 @@ config HAVE_REGS_AND_STACK_ACCESS_API declared in asm/ptrace.h For example the kprobes-based event tracer needs this API. +config HAVE_FUNCTION_ARG_ACCESS_API + bool + help + This symbol should be selected by an architecure if it supports + the API needed to access function arguments from pt_regs, + declared in asm/ptrace.h + config HAVE_CLK bool help
arch/x86/Kconfig +1 -0
@@ -176,6 +176,7 @@ config X86 select HAVE_PERF_USER_STACK_DUMP select HAVE_RCU_TABLE_FREE select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_RELIABLE_STACKTRACE if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION select HAVE_STACK_VALIDATION if X86_64 select HAVE_SYSCALL_TRACEPOINTS
arch/x86/include/asm/ptrace.h +38 -0
@@ -256,6 +256,44 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,return 0 ; } +/** +* regs_get_kernel_argument() - get Nth function argument in kernel +* @regs: pt_regs of that context +* @n: function argument number (start from 0) +* +* regs_get_argument() returns @n th argument of the function call. +* Note that this chooses most probably assignment, in some case +* it can be incorrect. +* This is expected to be called from kprobes or ftrace with regs +* where the top of stack is the return address. +*/ +static inline unsigned long regs_get_kernel_argument (struct pt_regs *regs, +unsigned int n) +{ +static const unsigned int argument_offs[] = { +#ifdef __i386__ + offsetof(struct pt_regs , ax), + offsetof(struct pt_regs , cx), + offsetof(struct pt_regs , dx), +#define NR_REG_ARGUMENTS 3 +#else + offsetof(struct pt_regs , di), + offsetof(struct pt_regs , si), + offsetof(struct pt_regs , dx), + offsetof(struct pt_regs , cx), + offsetof(struct pt_regs , r8), + offsetof(struct pt_regs , r9), +#define NR_REG_ARGUMENTS 6 +#endif + }; + +if (n >=NR_REG_ARGUMENTS ) { + n -=NR_REG_ARGUMENTS -1 ; +return regs_get_kernel_stack_nth (regs, n); + }else +return regs_get_register (regs, argument_offs[n]); +} +#define arch_has_single_step () (1)#ifdef CONFIG_X86_DEBUGCTLMSR #define arch_has_block_step () (1)
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 15/21 tracing: probeevent: Add $argN for accessing function args
In reply to Masami HiramatsuAdd $argN special fetch variable for accessing function arguments. This allows user to trace the Nth argument easily at the function entry.
Note that this returns most probably assignment of registers and stacks. In some case, it may not work well. If you need to access correct registers or stacks you should use perf-probe.
---
Changes in v2:
- Add $argN in README file
- Make N start from 1 as same as auto-generate event argument names.
Changes in v3:
- Show $arg<N> in README only when this feature is supported.
--- Documentation/trace/kprobetrace.txt | 10 ++++++---- kernel/trace/trace.c | 4 ++++ kernel/trace/trace_kprobe.c | 18 +++++++++++++----- kernel/trace/trace_probe.c | 36 ++++++++++++++++++++++------------- kernel/trace/trace_probe.h | 9 ++++++++- kernel/trace/trace_uprobe.c | 2 +- 6 files changed, 55 insertions(+), 24 deletions(-)
Documentation/trace/kprobetrace.txt +6 -4
@@ -43,16 +43,18 @@ Synopsis of kprobe_events @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) $stackN : Fetch Nth entry of stack (N >= 0) $stack : Fetch stack address. - $retval : Fetch return value.(*) + $argN : Fetch the Nth function argument. (N >= 1) (*1) + $retval : Fetch return value.(*2) $comm : Fetch current task comm. - +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) + +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(*3) NAME=FETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types (x8/x16/x32/x64), "string" and bitfield are supported. - (*) only for return probe. - (**) this is useful for fetching a field of data structures. + (*1) only for the probe on function entry (offs == 0). + (*2) only for return probe. + (*3) this is useful for fetching a field of data structures. Types -----
kernel/trace/trace.c +4 -0
@@ -4608,7 +4608,11 @@ static const char readme_msg[] =#endif "\t args: <name>=fetcharg[:type]\n" "\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n" +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API + "\t $stack<index>, $stack, $retval, $comm, $arg<N>\n" +#else "\t $stack<index>, $stack, $retval, $comm\n" +#endif"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n" "\t b<bit-width>@<bit-offset>/<container-size>\n"#endif
kernel/trace/trace_kprobe.c +13 -5
@@ -490,13 +490,15 @@ static int create_trace_kprobe(int argc, char **argv)long offset =0 ;void *addr =NULL ;char buf[MAX_EVENT_NAME_LEN ]; +unsigned int flags =TPARG_FL_KERNEL ;/* argc must be >= 1 */ if (argv[0 ][0 ] =='p' ) is_return = false; -else if (argv[0 ][0 ] =='r' ) +else if (argv[0 ][0 ] =='r' ) { is_return = true; -else if (argv[0 ][0 ] =='-' ) + flags |=TPARG_FL_RETURN ; + }else if (argv[0 ][0 ] =='-' ) is_delete = true;else { pr_info("Probe definition must be started with 'p', 'r' or"
@@ -579,8 +581,9 @@ static int create_trace_kprobe(int argc, char **argv)pr_info ("Failed to parse either an address or a symbol.\n" );return ret; } -if (offset && is_return && - !kprobe_on_func_entry (NULL , symbol, offset)) { +if (kprobe_on_func_entry (NULL , symbol, offset)) + flags |=TPARG_FL_FENTRY ; +if (offset && is_return && !(flags &TPARG_FL_FENTRY )) {pr_info ("Given offset is not valid for return probe.\n" );return -EINVAL ; }
@@ -650,7 +653,7 @@ static int create_trace_kprobe(int argc, char **argv)/* Parse fetch argument */ ret =traceprobe_parse_probe_arg (arg, &tk->tp.size, parg, - is_return, true); + flags);if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
@@ -890,6 +893,11 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,case FETCH_OP_COMM : val = (unsigned long )current->comm;break ; +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API +case FETCH_OP_ARG : + val =regs_get_kernel_argument (regs, code->param); +break ; +#endif default :return -EILSEQ ; }
kernel/trace/trace_probe.c +23 -13
@@ -169,14 +169,13 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))static int parse_probe_vars (char *arg,const struct fetch_type *t, -struct fetch_insn *code,bool is_return, -bool is_kprobe) +struct fetch_insn *code,unsigned int flags) {int ret =0 ;unsigned long param;if (strcmp (arg,"retval" ) ==0 ) { -if (is_return) +if (flags &TPARG_FL_RETURN ) code->op =FETCH_OP_RETVAL ;else ret = -EINVAL ;
@@ -185,7 +184,8 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, code->op =FETCH_OP_STACKP ; }else if (isdigit (arg[5 ])) { ret =kstrtoul (arg +5 ,10 , ¶m); -if (ret || (is_kprobe && param >PARAM_MAX_STACK )) +if (ret || ((flags &TPARG_FL_KERNEL ) && + param >PARAM_MAX_STACK )) ret = -EINVAL ;else { code->op =FETCH_OP_STACK ;
@@ -195,6 +195,18 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, ret = -EINVAL ; }else if (strcmp (arg,"comm" ) ==0 ) { code->op =FETCH_OP_COMM ; +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API + }else if (((flags &TPARG_FL_MASK ) == + (TPARG_FL_KERNEL |TPARG_FL_FENTRY )) && +strncmp (arg,"arg" ,3 ) ==0 ) { +if (!isdigit (arg[3 ])) +return -EINVAL ; + ret =kstrtoul (arg +3 ,10 , ¶m); +if (ret || !param || param >PARAM_MAX_STACK ) +return -EINVAL ; + code->op =FETCH_OP_ARG ; + code->param = (unsigned int )param -1 ; +#endif }else ret = -EINVAL ;
@@ -205,7 +217,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,static int parse_probe_arg (char *arg,const struct fetch_type *type,struct fetch_insn **pcode,struct fetch_insn *end, -bool is_return,bool is_kprobe) +unsigned int flags) {struct fetch_insn *code = *pcode;unsigned long param;
@@ -215,8 +227,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,switch (arg[0 ]) {case '$' : - ret =parse_probe_vars (arg +1 , type, code, - is_return, is_kprobe); + ret =parse_probe_vars (arg +1 , type, code, flags);break ;case '%' :/* named register */
@@ -238,7 +249,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, code->immediate = param; }else if (arg[1 ] =='+' ) {/* kprobes don't support file offsets */ -if (is_kprobe) +if (flags &TPARG_FL_KERNEL )return -EINVAL ; ret =kstrtol (arg +2 ,0 , &offset);
@@ -249,7 +260,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, code->immediate = (unsigned long )offset;// imm64? }else {/* uprobes don't support symbols */ -if (!is_kprobe) +if (!(flags &TPARG_FL_KERNEL ))return -EINVAL ; ret =traceprobe_split_symbol_offset (arg +1 , &offset);
@@ -290,8 +301,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,const struct fetch_type *t2 =find_fetch_type (NULL ); *tmp ='\0' ; - ret =parse_probe_arg (arg, t2, &code, end, is_return, - is_kprobe); + ret =parse_probe_arg (arg, t2, &code, end, flags);if (ret)break ;if (code->op ==FETCH_OP_COMM )
@@ -351,7 +361,7 @@ static int __parse_bitfield_probe_arg(const char *bf,/* String length checking wrapper */ int traceprobe_parse_probe_arg (char *arg,ssize_t *size, -struct probe_arg *parg,bool is_return,bool is_kprobe) +struct probe_arg *parg,unsigned int flags) {struct fetch_insn *code, *tmp =NULL ;const char *t;
@@ -391,7 +401,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, code[FETCH_INSN_MAX -1 ].op =FETCH_OP_END ; ret =parse_probe_arg (arg, parg->type, &code, &code[FETCH_INSN_MAX -1 ], - is_return, is_kprobe); + flags);if (ret) goto fail;
kernel/trace/trace_probe.h +8 -1
@@ -35,6 +35,7 @@#include <linux/stringify.h> #include <linux/limits.h> #include <linux/uaccess.h> +#include <linux/bitops.h> #include <asm/bitsperlong.h> #include "trace.h"
@@ -89,6 +90,7 @@ enum fetch_op {FETCH_OP_RETVAL ,/* Return value */ FETCH_OP_IMM ,/* Immediate : .immediate */ FETCH_OP_COMM ,/* Current comm */ +FETCH_OP_ARG ,/* Function argument : .param */ FETCH_OP_FOFFS ,/* File offset: .immediate */ // Stage 2 (dereference) op FETCH_OP_DEREF, /* Dereference: .offset */
@@ -261,8 +263,13 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)return NULL ; } +#define TPARG_FL_RETURN BIT(0) +#define TPARG_FL_KERNEL BIT(1) +#define TPARG_FL_FENTRY BIT(2) +#define TPARG_FL_MASK GENMASK(2, 0) +extern int traceprobe_parse_probe_arg (char *arg,ssize_t *size, -struct probe_arg *parg,bool is_return,bool is_kprobe); +struct probe_arg *parg,unsigned int flags);extern int traceprobe_conflict_field_name (const char *name,struct probe_arg *args,int narg);
kernel/trace/trace_uprobe.c +1 -1
@@ -519,7 +519,7 @@ static int create_trace_uprobe(int argc, char **argv)/* Parse fetch argument */ ret =traceprobe_parse_probe_arg (arg, &tu->tp.size, parg, - is_return, false); + is_return ?TPARG_FL_RETURN :0 );if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 16/21 tracing: probeevent: Add array type support
In reply to Masami HiramatsuAdd array type support for probe events.
This allows user to get arraied types from memory address. The array type syntax is
TYPE[N]
Where TYPE is one of types (u8/16/32/64,s8/16/32/64, x8/16/32/64, symbol, string) and N is a fixed value less than 64.
The string array type is a bit different from other types. For other base types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same as +0(%di):x32.) But string[1] is not equal to string. The string type itself represents "char array", but string array type represents "char * array". So, for example, +0(%di):string[1] is equal to +0(+0(%di)):string.
---
Changes in v6:
- Fix to add escaping backslash to a brace for syntax in README file.
Changes in v4:
- Fix to use calculated size correctly for field definition. (Thank you Namhyung!)
Changes in v2:
- Add array description in README file
- Fix to init s3 code out of loop.
- Fix to proceed code when the last code is OP_ARRAY.
- Add string array type and bitfield array type.
--- Documentation/trace/kprobetrace.txt | 13 ++++ kernel/trace/trace.c | 3 + kernel/trace/trace_probe.c | 130 +++++++++++++++++++++++++++-------- kernel/trace/trace_probe.h | 14 ++++ kernel/trace/trace_probe_tmpl.h | 63 +++++++++++++++-- 5 files changed, 183 insertions(+), 40 deletions(-)
Documentation/trace/kprobetrace.txt +13 -0
@@ -65,9 +65,22 @@ in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32' or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and x86-64 uses x64). +These value types can be an array. To record array data, you can add '[N]' +(where N is a fixed number, less than 64) to the base type. +E.g. 'x16[4]' means an array of x16 (2bytes hex) with 4 elements. +Note that the array can be applied to memory type fetchargs, you can not +apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is +wrong, but '+8($stack):x8[8]' is OK.) + String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. +The string array type is a bit different from other types. For other base +types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same +as +0(%di):x32.) But string[1] is not equal to string. The string type itself +represents "char array", but string array type represents "char * array". +So, for example, +0(%di):string[1] is equal to +0(+0(%di)):string. + Bitfield is another special type, which takes 3 parameters, bit-width, bit- offset, and container-size (usually 32). The syntax is;
kernel/trace/trace.c +2 -1
@@ -4614,7 +4614,8 @@ static const char readme_msg[] ="\t $stack<index>, $stack, $retval, $comm\n" #endif"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n" - "\t b<bit-width>@<bit-offset>/<container-size>\n" +"\t b<bit-width>@<bit-offset>/<container-size>,\n" + "\t <type>\\[<array-size>\\]\n"#endif " events/\t\t- Directory containing all trace event subsystems:\n" " enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
kernel/trace/trace_probe.c +99 -31
212 lines not on this page · raw message
kernel/trace/trace_probe.h +14 -0
@@ -43,6 +43,7 @@#define MAX_TRACE_ARGS 128#define MAX_ARGSTR_LEN 63 +#define MAX_ARRAY_LEN 64#define MAX_STRING_SIZE PATH_MAX/* Reserved field names */
@@ -78,6 +79,14 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)return (u8 *)ent +get_loc_offs (*dl); } +static nokprobe_inline u32 update_data_loc(u32 loc, int consumed) +{ +u32 maxlen =get_loc_len (loc); +u32 offset =get_loc_offs (loc); + +return make_data_loc (maxlen - consumed, offset + consumed); +} +/* Printing function type */ typedef int (*print_type_func_t )(struct trace_seq *,void *,void *);
@@ -100,6 +109,8 @@ enum fetch_op {FETCH_OP_ST_STRING ,/* String: .offset, .size */ // Stage 4 (modify) op FETCH_OP_MOD_BF ,/* Bitfield: .basesize, .lshift, .rshift */ +// Stage 5 (loop) op +FETCH_OP_LP_ARRAY ,/* Array: .param = loop count */ FETCH_OP_END, };
@@ -189,6 +200,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol); _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)#define ASSIGN_FETCH_TYPE_END {} +#define MAX_ARRAY_LEN 64#ifdef CONFIG_KPROBE_EVENTS bool trace_kprobe_on_func_entry (struct trace_event_call *call);
@@ -209,8 +221,10 @@ struct probe_arg {struct fetch_insn *code;bool dynamic;/* Dynamic array (string) is used */ unsigned int offset;/* Offset from argument entry */ +unsigned int count;/* Array count */ const char *name;/* Name of this argument */ const char *comm;/* Command of this argument */ +char *fmt;/* Format string if needed */ const struct fetch_type *type;/* Type of this argument */ };
kernel/trace/trace_probe_tmpl.h +55 -8
100 lines not on this page · raw message
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 17/21 selftests: ftrace: Add a testcase for symbol type
In reply to Masami HiramatsuAdd a testcase for symbol type with kprobe event. This tests good/bad syntax combinations and also the traced data.
If the kernel doesn't support symbol type, it skips the test as UNSUPPORTED.
---
Changes in v3:
- Use IP/PC register to test the symbol type
--- .../ftrace/test.d/kprobe/kprobe_args_symbol.tc | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc new file +77 -0
@@ -0,0 +1,77 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event argument symbol type + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep -qe "type:.* symbol" README || exit_unsupported # version issue + +echo 0 > events/enable +echo > kprobe_events + +PROBEFUNC="vfs_read" +GOODREG= +BADREG= +REG= +GOODSYM="_sdata" +if ! grep -qw ${GOODSYM} /proc/kallsyms ; then + GOODSYM=$PROBEFUNC +fi + +case `uname -m` in +x86_64|i[3456]86) + GOODREG=%ax + BADREG=%ex + REG=%ip +;; +aarch64) + GOODREG=%x0 + BADREG=%ax + REG=%pc +;; +arm*) + GOODREG=%r0 + BADREG=%ax + REG=%pc +;; +*) + echo "Please implement other architecture here" + exit_untested +esac + +test_goodarg() # Good-args +{ + while [ "$1" ]; do + echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +test_badarg() # Bad-args +{ + while [ "$1" ]; do + ! echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +echo > kprobe_events + +: "Symbol type" +test_goodarg "${GOODREG}:symbol" "@${GOODSYM}:symbol" "@${GOODSYM}+10:symbol" \ + "\$stack0:symbol" "+0(\$stack):symbol" +test_badarg "\$comm:symbol" + +: "Retval with symbol type" +echo "r ${PROBEFUNC} \$retval:symbol" > kprobe_events + +echo > kprobe_events + +: "Test get symbol" +echo "p:testprobe create_trace_kprobe ${REG}:symbol" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -q "arg1=create_trace_kprobe" + +echo 0 > events/enable +echo > kprobe_events
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 18/21 selftests: ftrace: Add a testcase for $argN with kprobe_event
In reply to Masami HiramatsuAdd a testcase for $argN with kprobe event. This tests whether the traced data is correct or not. If the kernel doesn't support $argN (depends on arch), it skips the test as UNSUPPORTED.
---
Changes in v5:
- Fix description.
--- .../ftrace/test.d/kprobe/kprobe_args_argN.tc | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc new file +25 -0
@@ -0,0 +1,25 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event argN argument + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep -q "arg<N>" README || exit_unsupported # version issue + +echo 0 > events/enable +echo > kprobe_events + +: "Test bad pattern : arg0 is not allowed" +! echo 'p:testprobe create_trace_kprobe $arg0' > kprobe_events + +: "Test get argument" +echo 'p:testprobe create_trace_kprobe $arg1' > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=0x1" + +! echo test test test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=0x3" + +echo 0 > events/enable +echo > kprobe_events
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH v6 19/21 selftests: ftrace: Add a testcase for array type with kprobe_event
In reply to Masami HiramatsuAdd a testcase for array type with kprobe event. This tests good/bad syntax combinations and also the traced data is correct in several way. If the kernel doesn't support array type, it skips the test as UNSUPPORTED.
---
Changes in v4:
- Add format field tests.
--- .../ftrace/test.d/kprobe/kprobe_args_array.tc | 92 ++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc new file +92 -0
@@ -0,0 +1,92 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event array argument + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep -q "<type>\[<array-size>\]" README || exit_unsupported # version issue + +GOODSYM="_sdata" +if ! grep -qw ${GOODSYM} /proc/kallsyms ; then + GOODSYM="create_trace_kprobe" +fi +case `uname -m` in +x86_64) + ARG2=%si + OFFS=8 + BITS=64 +;; +i[3456]86) + ARG2=%cx + OFFS=4 + BITS=32 +;; +aarch64) + ARG2=%x1 + OFFS=8 + BITS=64 +;; +arm*) + ARG2=%r1 + OFFS=4 + BITS=32 +;; +*) + echo "Please implement other architecture here" + exit_untested +esac + +create_testprobe() { # args + echo "p:testprobe create_trace_kprobe $*" > kprobe_events +} + +check_field() { # grep-pattern + grep -e "$*" events/kprobes/testprobe/format +} + +echo 0 > events/enable +echo > kprobe_events + +: "Syntax test" +create_testprobe "+0(${ARG2}):x8[1] +0(${ARG2}):s16[1] +0(${ARG2}):u32[1]" +check_field "field:u8 arg1\[1\];.*size:1;" +check_field "field:s16 arg2\[1\];.*size:2;" +check_field "field:u32 arg3\[1\];.*size:4;" +create_testprobe "+0(${ARG2}):x64[1] +0(${ARG2}):symbol[1]" +check_field "field:u64 arg1\[1\];.*size:8;" +check_field "field:u${BITS} arg2\[1\];.*size:${OFFS};" +create_testprobe "+0(${ARG2}):b2 at 3/8[1] +0(${ARG2}):string[1]" +check_field "field:u8 arg1\[1\];.*size:1;" +check_field "field:__data_loc char\[\]\[1\] arg2;.*size:4;" +create_testprobe "+0(${ARG2}):x8[64] @${GOODSYM}:x8[4]" +check_field "field:u8 arg1\[64\];.*size:64;" +check_field "field:u8 arg2\[4\];.*size:4;" + +! create_testprobe "${ARG2}:x8[1]" # Can not use array type on register +! create_testprobe "\$comm:x8[1]" # Can not use array type on \$comm +! create_testprobe "\$comm:string[1]" # No, even if it is string array +! create_testprobe "+0(${ARG2}):x64[0]" # array size >= 1 +! create_testprobe "+0(${ARG2}):x64[65]" # array size <= 64 + +: "Test get argument (1)" +create_testprobe "arg1=+0(${ARG2}):string[1]" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1={\"test\"}" +echo 0 > events/kprobes/testprobe/enable + +: "Test get argument (2)" +create_testprobe "arg1=+0(${ARG2}):string[3]" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo foo bar buzz >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1={\"foo\",\"bar\",\"buzz\"}" +echo 0 > events/kprobes/testprobe/enable + +: "Test get argument (3)" +create_testprobe "arg1=+0(+0(${ARG2})):u8[4]" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo 1234 >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1={49,50,51,52}" # ascii code +echo 0 > events/kprobes/testprobe/enable + +echo > kprobe_events
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerPATCH RESEND v6 20/21 perf-probe: Fix to convert array type collectly
In reply to Masami HiramatsuFix to convert array element type collectly. Current perf-probe converts the type of array-elements incorrectly. It always converts the types as a pointer of array. This passes the "array" type DIE to the type converter so that it can get correct "element of array" type DIE from it.
E.g.
====
$ cat hello.c #include <stdio.h>
void foo(int a[])
{
printf("%d\n", a[1]);}
void main()
{
int a[3] = {4, 5, 6};
printf("%d\n", a[0]);
foo(a);}
$ gcc -g hello.c -o hello $ perf probe -x ./hello -D "foo a[1]" ====
Without this fix, above outputs
====
p:probe_hello/foo /tmp/hello:0x4d3 a=+4(-8(%bp)):u64
====
The "u64" means "int *", but a[1] is "int".
With this,
====
p:probe_hello/foo /tmp/hello:0x4d3 a=+4(-8(%bp)):s32
====
So, "int" correctly converted to "s32"
--- tools/perf/util/probe-finder.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
tools/perf/util/probe-finder.c +5 -8
@@ -423,20 +423,20 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,pr_warning ("Failed to get the type of %s.\n" , varname);return -ENOENT ; } -pr_debug2 ("Var real type: (%x)\n" , (unsigned )dwarf_dieoffset (&type)); +pr_debug2 ("Var real type: %s (%x)\n" ,dwarf_diename (&type), + (unsigned )dwarf_dieoffset (&type)); tag =dwarf_tag (&type);if (field->name[0 ] =='[' && (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { -if (field->next) -/* Save original type for next field */ -memcpy (die_mem, &type,sizeof (*die_mem)); +/* Save original type for next field or type */ +memcpy (die_mem, &type,sizeof (*die_mem));/* Get the type of this array */ if (die_get_real_type (&type, &type) ==NULL ) {pr_warning ("Failed to get the type of %s.\n" , varname);return -ENOENT ; } -pr_debug2 ("Array real type: (%x)\n" , +pr_debug2 ("Array real type: %s (%x)\n" ,dwarf_diename (&type), (unsigned )dwarf_dieoffset (&type));if (tag == DW_TAG_pointer_type) { ref =zalloc (sizeof (struct probe_trace_arg_ref ));
@@ -448,9 +448,6 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, *ref_ptr = ref; } ref->offset +=dwarf_bytesize (&type) * field->index; -if (!field->next) -/* Save vr_die for converting types */ -memcpy (die_mem, vr_die,sizeof (*die_mem)); goto next; }else if (tag == DW_TAG_pointer_type) {/* Check the pointer and dereference */
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
tip-bot for Masami Hiramatsu
merge bot[tip:perf/core] perf probe: Use right type to access array elements
perf probe: Use right type to access array elements
Commit-ID: d0461794a1dcaf552b507e23788777f718b736a1 Gitweb: https://git.kernel.org/tip/d0461794a1dcaf552b507e23788777f718b736a1 Author: Masami Hiramatsu <[email protected]> AuthorDate: Sat, 17 Mar 2018 21:52:25 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 19 Mar 2018 13:51:53 -0300
perf probe: Use right type to access array elements
Current 'perf probe' converts the type of array-elements incorrectly. It always converts the types as a pointer of array. This passes the "array" type DIE to the type converter so that it can get correct "element of array" type DIE from it.
E.g.
====
$ cat hello.c #include <stdio.h>
void foo(int a[])
{
printf("%d\n", a[1]);}
void main()
{
int a[3] = {4, 5, 6};
printf("%d\n", a[0]);
foo(a);}
$ gcc -g hello.c -o hello $ perf probe -x ./hello -D "foo a[1]" ====
Without this fix, above outputs
====
p:probe_hello/foo /tmp/hello:0x4d3 a=+4(-8(%bp)):u64
====
The "u64" means "int *", but a[1] is "int".
With this,
====
p:probe_hello/foo /tmp/hello:0x4d3 a=+4(-8(%bp)):s32
====
So, "int" correctly converted to "s32"
--- tools/perf/util/probe-finder.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
tools/perf/util/probe-finder.c +5 -8
@@ -423,20 +423,20 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,pr_warning ("Failed to get the type of %s.\n" , varname);return -ENOENT ; } -pr_debug2 ("Var real type: (%x)\n" , (unsigned )dwarf_dieoffset (&type)); +pr_debug2 ("Var real type: %s (%x)\n" ,dwarf_diename (&type), + (unsigned )dwarf_dieoffset (&type)); tag =dwarf_tag (&type);if (field->name[0 ] =='[' && (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { -if (field->next) -/* Save original type for next field */ -memcpy (die_mem, &type,sizeof (*die_mem)); +/* Save original type for next field or type */ +memcpy (die_mem, &type,sizeof (*die_mem));/* Get the type of this array */ if (die_get_real_type (&type, &type) ==NULL ) {pr_warning ("Failed to get the type of %s.\n" , varname);return -ENOENT ; } -pr_debug2 ("Array real type: (%x)\n" , +pr_debug2 ("Array real type: %s (%x)\n" ,dwarf_diename (&type), (unsigned )dwarf_dieoffset (&type));if (tag == DW_TAG_pointer_type) { ref =zalloc (sizeof (struct probe_trace_arg_ref ));
@@ -448,9 +448,6 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, *ref_ptr = ref; } ref->offset +=dwarf_bytesize (&type) * field->index; -if (!field->next) -/* Save vr_die for converting types */ -memcpy (die_mem, vr_die,sizeof (*die_mem)); goto next; }else if (tag == DW_TAG_pointer_type) {/* Check the pointer and dereference */
Masami Hiramatsu
maintainerPATCH v6 21/21 perf-probe: Add array argument support
In reply to Masami HiramatsuSince kprobes events support an array argument, perf-probe can also support dumping array now.
The syntax are
<array-var>[<range>]
or
<pointer-var>[<range>]
where the <range> is <start>..<end>. e.g. array[0..5]. This can also be available with string type. In this case, the string array should be "char *array[]" or "char **array_ptr".
Note that this feature is only available on the kernel which supports array type.
--- tools/perf/Documentation/perf-probe.txt | 2 - tools/perf/util/probe-event.c | 20 ++++++- tools/perf/util/probe-event.h | 2 + tools/perf/util/probe-file.c | 5 ++ tools/perf/util/probe-file.h | 1 tools/perf/util/probe-finder.c | 95 ++++++++++++++++++------------- 6 files changed, 84 insertions(+), 41 deletions(-)
tools/perf/Documentation/perf-probe.txt +1 -1
@@ -196,7 +196,7 @@ Each probe argument follows below syntax. [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] -'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) +'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]) or range (e.g. array[1..4], var->array[0..2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) '$vars' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters. 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail) On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
tools/perf/util/probe-event.c +19 -1
@@ -1570,6 +1570,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) {char *tmp, *goodname;struct perf_probe_arg_field **fieldp; +long end;pr_debug ("parsing arg: %s into " , str);
@@ -1617,7 +1618,18 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) str = tmp; (*fieldp)->index =strtol (str +1 , &tmp,0 ); (*fieldp)->ref = true; -if (*tmp !=']' || tmp == str +1 ) { +if (tmp[0 ] =='.' && tmp[1 ] =='.' ) {/* dump array */ + end =strtol (tmp +2 , &tmp,0 ); +if (end < (*fieldp)->index || *tmp !=']' ) { +semantic_error ("Invalid array range\n" ); +return -EINVAL ; + } + arg->length = end - (*fieldp)->index +1 ; +if (tmp[1 ] !='\0' ) { +semantic_error ("Array range must not follow anything." ); +return -EINVAL ; + } + }else if (*tmp !=']' || tmp == str +1 ) {semantic_error ("Array index must be a" " number.\n" );return -EINVAL ;
@@ -2022,6 +2034,12 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,if (!err && arg->type) err =strbuf_addf (buf,":%s" , arg->type); +if (!err && arg->length) { +if (!arg->type) +return -EINVAL ; + err =strbuf_addf (buf,"[%d]" , arg->length); + } +return err; }
tools/perf/util/probe-event.h +2 -0
@@ -42,6 +42,7 @@ struct probe_trace_arg {char *name;/* Argument name */ char *value;/* Base value */ char *type;/* Type name */ +unsigned int length;/* Length of array */ struct probe_trace_arg_ref *ref;/* Referencing offset */ };
@@ -79,6 +80,7 @@ struct perf_probe_arg {char *name;/* Argument name */ char *var;/* Variable name */ char *type;/* Type name */ +unsigned int length;/* Length of array */ struct perf_probe_arg_field *field;/* Structure fields */ };
tools/perf/util/probe-file.c +5 -0
@@ -999,6 +999,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)enum ftrace_readme {FTRACE_README_PROBE_TYPE_X =0 ,FTRACE_README_KRETPROBE_OFFSET , +FTRACE_README_ARRAY_TYPE ,FTRACE_README_END , };
@@ -1010,6 +1011,8 @@ static struct { [idx] = {.pattern = pat, .avail = false}DEFINE_TYPE (FTRACE_README_PROBE_TYPE_X ,"*type: * x8/16/32/64,*" ),DEFINE_TYPE (FTRACE_README_KRETPROBE_OFFSET ,"*place (kretprobe): *" ), +DEFINE_TYPE (FTRACE_README_ARRAY_TYPE , + "*<type>\\\\\\[<array-size>\\\\\\]*"), };static bool scan_ftrace_readme (enum ftrace_readme type)
@@ -1057,6 +1060,8 @@ bool probe_type_is_available(enum probe_type type)return false; else if (type == PROBE_TYPE_X) return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X); + else if (type == PROBE_TYPE_ARRAY) + return scan_ftrace_readme(FTRACE_README_ARRAY_TYPE);return true; }
tools/perf/util/probe-file.h +1 -0
@@ -27,6 +27,7 @@ enum probe_type {PROBE_TYPE_X ,PROBE_TYPE_STRING ,PROBE_TYPE_BITFIELD , +PROBE_TYPE_ARRAY , PROBE_TYPE_END, };
tools/perf/util/probe-finder.c +56 -39
131 lines not on this page · raw message
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 21/21] perf-probe: Add array argument support
Hi Masami,
Quoted 8 lines · Masami Hiramatsu
Since kprobes events support an array argument, perf-probe can also support dumping array now.
The syntax are<array-var>[<range>]
or
<pointer-var>[<range>]
Quoted 7 lines
where the <range> is <start>..<end>. e.g. array[0..5]. This can also be available with string type. In this case, the string array should be "char *array[]" or "char **array_ptr".
Note that this feature is only available on the kernel which supports array type.
User can still do,
# perf probe -x ~/hello main:3 'a=a:x32[3]'
which will successfully be installed in uprobe_events. But for a perf tool, x32[3] is not a valid type. And it seems perf tool don't validate the 'type' field:
static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) {
....
tmp = strchr(str, ':');
if (tmp) { /* Type setting */
*tmp = '\0';
arg->type = strdup(tmp + 1);
if (arg->type == NULL)
return -ENOMEM;
pr_debug("type:%s ", arg->type);
}
Is it okay to allow user to specify array size with type field?
Thanks,
Ravi
Masami Hiramatsu
maintainerRe: [PATCH v6 21/21] perf-probe: Add array argument support
Quoted 39 lines · On Mon, 19 Mar 2018 13:29:59 +0530 Ravi Bangoria…
Hi Masami,
Quoted 8 lines · Masami Hiramatsu
Since kprobes events support an array argument, perf-probe can also support dumping array now.
The syntax are<array-var>[<range>]
or
<pointer-var>[<range>]Quoted 7 lines
where the <range> is <start>..<end>. e.g. array[0..5]. This can also be available with string type. In this case, the string array should be "char *array[]" or "char **array_ptr".
Note that this feature is only available on the kernel which supports array type.
User can still do,
# perf probe -x ~/hello main:3 'a=a:x32[3]'which will successfully be installed in
uprobe_events. But for a perf tool, x32[3] is not a valid type. And it seems perf tool don't validate the 'type' field:static int
parse_perf_probe_arg(char *str, struct perf_probe_arg *arg){
....
tmp =strchr(str, ':');
if (tmp) { /* Type setting */
*tmp = '\0';
arg->type= strdup(tmp + 1);
if (arg->type== NULL)
return-ENOMEM;
pr_debug("type:%s ", arg->type);
}
Quoted 1 line
Is it okay to allow user to specify array size with type field?
Fro this patch, yes. The availability of type is checked only when it is automatically generated.
IMO, it should be done in another patch, something like "Validate user specified type casting" patch. Would you need it?
Thank you,
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Ravi Bangoria
Acked-byRe: [PATCH v6 21/21] perf-probe: Add array argument support
Hi Masami :)
Quoted 6 lines · Masami Hiramatsu
Quoted 2 lines · On Mon, 19 Mar 2018 13:29:59 +0530 Ravi Bangoria…
Is it okay to allow user to specify array size with type field?
Fro this patch, yes.
So IIUC, perf _tool_ will allow user to record array either with "name[range]" or by "name:type[length]". Please correct me if that's wrong.
And If perf tool will allow array length along with TYPE field, I guess we should document that in man perf-probe?
Otherwise,
Thanks,
Ravi
Quoted 7 lines
The availability of type is checked only when
it is automatically generated.
IMO, it should be done in another patch, something like "Validate user specified type casting" patch. Would you need it?Thank you,
Masami Hiramatsu
maintainerRe: [PATCH v6 21/21] perf-probe: Add array argument support
Quoted 7 lines · On Thu, 22 Mar 2018 16:19:46 +0530 Ravi Bangoria <ravi.bangoria at…
Hi Masami :)
Quoted 4 lines · Masami Hiramatsu
Quoted 1 line · On Mon, 19 Mar 2018 13:29:59 +0530 Ravi Bangoria <ravi.bangoria at…
Quoted 5 lines
Quoted 2 lines
Quoted 1 line
Is it okay to allow user to specify array size with type field?
Fro this patch, yes.
So IIUC, perf _tool_ will allow user to record array either with "name[range]" or by "name:type[length]". Please correct me if that's wrong.
Yes, it is correct.
Quoted 2 lines
And If perf tool will allow array length along with TYPE field, I guess we should document that in man perf-probe?
Ah, right. OK, I'll add it.
Thanks!
Quoted 16 lines
Otherwise,
Acked-by Ravi Bangoria <ravi.bangoria at linux.vnet.ibm.com>Thanks,
RaviQuoted 7 lines
The availability of type is checked only when
it is automatically generated.
IMO, it should be done in another patch, something like "Validate user specified type casting" patch. Would you need it?Thank you,
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Masami Hiramatsu
maintainerQuoted 18 lines · On Sat, 17 Mar 2018 21:37:21 +0900 Masami Hiramatsu <[email protected]> wrote:
Hi,
This is the 6th version of the fetch-arg improvement series. This includes variable changes on fetcharg framework like,
- Add fetcharg testcases (syntax, argN, symbol, string and array) and probepoint testcase.
- Rewrite fetcharg framework withfetch_insn, switch-case based instead of function pointer.
- Add "symbol" type support, which shows symbol+offset instead of address value.
- Add "$argN" fetcharg, which fetches function parameters. (currently only for x86-64)
- Add array type support (including string arrary :) ) , which enables to get fixed length array from probe-events.
- Add array type support for perf-probe, so that user can dump partial array entries.
Quoted 2 lines
V5 is here:
https://lkml.org/lkml/2018/3/12/558
No, this is another series, v5 is here.
https://lkml.org/lkml/2018/3/8/562
Thanks,
Quoted 131 lines
Changes from the v5 is here:
- [16/21] Fix README to add backslash escapes to "[]"
- [20/21] Add a bugfix patch for perf-probe.
- [21/21] Add array type support for perf-probe.Note that [20/21] is same as https://lkml.org/lkml/2018/3/16/108
I have to add this because the last patch depends on it. Anyway, [20/21] and [21/21] is only for showing how perf-probe will enhanced by this series. So those are extra work. I will resend thodr again after [01/21]-[19/21] are merged.Here are examples:
o 'symbol' type
# echo 'p vfs_read $stack0:symbol' > kprobe_events # echo 1 > events/kprobes/p_vfs_read_0/enable # tail -n 3 trace sh-729 [007] ...2 105.753637: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=SyS_read+0x42/0x90 tail-736 [000] ...2 105.754904: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=kernel_read+0x2c/0x40 tail-736 [000] ...2 105.754929: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=kernel_read+0x2c/0x40o $argN
# echo 'p vfs_read $arg0 $arg1 $arg2' > kprobe_events # echo 1 > events/kprobes/p_vfs_read_0/enable # tail -n 3 trace sh-726 [007] ...2 134.288973: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d98ec00 arg2=0x7ffeb4330f79 arg3=0x1 tail-731 [000] ...2 134.289987: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d9dd200 arg2=0xffff88001d8a0a00 arg3=0x80 tail-731 [000] ...2 134.290016: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffff88001d9dd200 arg2=0xffff88001faf4a00 arg3=0x150o Array type
# echo 'p vfs_read +0($stack):x64 +0($stack):x8[8]' > kprobe_events # echo 1 > events/kprobes/p_vfs_read_0/enable # tail -n 3 trace sh-729 [007] ...2 91.701664: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b1252 arg2={0x52,0x12,0x1b,0x81,0xff,0xff,0xff,0xff} tail-734 [000] ...2 91.702366: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b0dec arg2={0xec,0xd,0x1b,0x81,0xff,0xff,0xff,0xff} tail-734 [000] ...2 91.702386: p_vfs_read_0: (vfs_read+0x0/0x130) arg1=0xffffffff811b0dec arg2={0xec,0xd,0x1b,0x81,0xff,0xff,0xff,0xff} # # cat events/kprobes/p_vfs_read_0/format name: p_vfs_read_0 ID: 1069 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1;field:unsigned long __probe_ip; offset:8; size:8; signed:0; field:u64 arg1; offset:16; size:0; signed:0; field:u8 arg2[8]; offset:24; size:8; signed:0;print fmt: "(%lx) arg1=0x%Lx arg2={0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x}",
REC->__probe_ip,REC->arg1, REC->arg2[0], REC->arg2[1], REC->arg2[2], REC->arg2[3], REC->arg2[4], REC->arg2[5], REC->arg2[6], REC->arg2[7]o String Array type
# echo "p create_trace_kprobe arg1=+0(%si):string[3]" > kprobe_events # echo test1 test2 test3 >> kprobe_events sh: write error: Invalid argument # echo 'p vfs_read $stack' >> kprobe_events # tail -n 2 trace sh-744 [007] ...1 183.382407: p_create_trace_kprobe_0: (create_trace_kprobe+0x0/0x890) arg1={"test1","test2","test3"} sh-744 [007] ...1 230.487809: p_create_trace_kprobe_0: (create_trace_kprobe+0x0/0x890) arg1={"p","vfs_read","$stack"}Thank you,
---
Masami Hiramatsu (21):
[BUGFIX] tracing: probeevent: Fix to support minus offset from symbol
selftests: ftrace: Add probe event argument syntax testcase
selftests: ftrace: Add a testcase for string type withkprobe_event
selftests: ftrace: Add a testcase for probepoint
tracing: probeevent: Cleanup print argument functions
tracing: probeevent: Cleanup argument field definition
tracing: probeevent: RemoveNOKPROBE_SYMBOLfrom print functions
tracing: probeevent: Introduce new argument fetching code
tracing: probeevent: Unify fetch type tables
tracing: probeevent: Return consumed bytes of dynamic area
tracing: probeevent: Appendtraceprobe_for exported function
tracing: probeevent: Unifyfetch_insnprocessing common part
tracing: probeevent: Add symbol type
x86: ptrace: Add function argument access API
tracing: probeevent: Add $argN for accessing function args
tracing: probeevent: Add array type support
selftests: ftrace: Add a testcase for symbol type
selftests: ftrace: Add a testcase for $argN withkprobe_event
selftests: ftrace: Add a testcase for array type withkprobe_event[RESEND] perf-probe: Fix to convert array type collectly
perf-probe: Add array argument supportDocumentation/trace/kprobetrace.txt | 26 + arch/Kconfig | 7 arch/x86/Kconfig | 1 arch/x86/include/asm/ptrace.h | 38 + kernel/trace/trace.c | 9 kernel/trace/trace_kprobe.c | 366 ++++-------- kernel/trace/trace_probe.c | 628 +++++++++----------- kernel/trace/trace_probe.h | 284 +++------ kernel/trace/trace_probe_tmpl.h | 214 +++++++ kernel/trace/trace_uprobe.c | 168 ++--- tools/perf/Documentation/perf-probe.txt | 2 tools/perf/util/probe-event.c | 20 + tools/perf/util/probe-event.h | 2 tools/perf/util/probe-file.c | 5 tools/perf/util/probe-file.h | 1 tools/perf/util/probe-finder.c | 108 ++- .../ftrace/test.d/kprobe/kprobe_args_argN.tc | 25 + .../ftrace/test.d/kprobe/kprobe_args_array.tc | 92 +++ .../ftrace/test.d/kprobe/kprobe_args_string.tc | 46 + .../ftrace/test.d/kprobe/kprobe_args_symbol.tc | 77 ++ .../ftrace/test.d/kprobe/kprobe_args_syntax.tc | 97 +++ .../selftests/ftrace/test.d/kprobe/probepoint.tc | 43 + 22 files changed, 1319 insertions(+), 940 deletions(-) create mode 100644 kernel/trace/trace_probe_tmpl.h create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc--
Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
Signature · 5 lines
Masami Hiramatsu <mhiramat at kernel.org> -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html