Pull kprobes updates from Masami Hiramatsu: - Skip negative return code check for snprintf in eprobe - Add recursive call test cases for kprobe unit test - Add 'char' type to probe events to show it as the character instead of value - Update kselftest kprobe-event testcase to ignore '__pfx_' symbols - Fix kselftest to check filter on eprobe event correctly - Add filter on eprobe to the README file in tracefs - Fix optprobes to check whether there is 'under unoptimizing' optprobe when optimizing another kprobe correctly - Fix optprobe to check whether there is 'under unoptimizing' optprobe when fetching the original instruction correctly - Fix optprobe to free 'forcibly unoptimized' optprobe correctly * tag 'probes-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: tracing/eprobe: no need to check for negative ret value for snprintf test_kprobes: Add recursed kprobe test case tracing/probe: add a char type to show the character value of traced arguments selftests/ftrace: Fix probepoint testcase to ignore __pfx_* symbols selftests/ftrace: Fix eprobe syntax test case to check filter support tracing/eprobe: Fix to add filter on eprobe description in README file x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe range x86/kprobes: Fix __recover_optprobed_insn check optimizing logic kprobes: Fix to handle forcibly unoptimized kprobes on freeing_list
Unified · Split
| @@ -58,7 +58,7 @@ Synopsis of kprobe_events · 57 unmodified lines | ||
| 58 | 58 | NAME=FETCHARG : Set NAME as the argument name of FETCHARG. |
| 59 | 59 | FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types |
| 60 | 60 | (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types |
| 61 | − (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr" | |
| 61 | + (x8/x16/x32/x64), "char", "string", "ustring", "symbol", "symstr" | |
| 62 | 62 | and bitfield are supported. |
| 63 | 63 | |
| 64 | 64 | (\*1) only for the probe on function entry (offs == 0). |
| @@ -82,6 +82,8 @@ Note that the array can be applied to memory type fetchargs, you can not · 17 unmodified lines | ||
| 82 | 82 | apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is |
| 83 | 83 | wrong, but '+8($stack):x8[8]' is OK.) |
| 84 | 84 | |
| 85 | +Char type can be used to show the character value of traced arguments. | |
| 86 | + | |
| 85 | 87 | String type is a special type, which fetches a "null-terminated" string from |
| 86 | 88 | kernel space. This means it will fail and store NULL if the string container |
| 87 | 89 | has been paged out. "ustring" type is an alternative of string for user-space. |
| @@ -46,8 +46,8 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) · 45 unmodified lines | ||
| 46 | 46 | /* This function only handles jump-optimized kprobe */ |
| 47 | 47 | if (kp && kprobe_optimized(kp)) { |
| 48 | 48 | op = container_of(kp, struct optimized_kprobe, kp); |
| 49 | − /* If op->list is not empty, op is under optimizing */ | |
| 50 | − if (list_empty(&op->list)) | |
| 49 | + /* If op is optimized or under unoptimizing */ | |
| 50 | + if (list_empty(&op->list) || optprobe_queued_unopt(op)) | |
| 51 | 51 | goto found; |
| 52 | 52 | } |
| 53 | 53 | } |
| @@ -353,7 +353,7 @@ int arch_check_optimized_kprobe(struct optimized_kprobe *op) · 299 unmodified lines | ||
| 353 | 353 | |
| 354 | 354 | for (i = 1; i < op->optinsn.size; i++) { |
| 355 | 355 | p = get_kprobe(op->kp.addr + i); |
| 356 | − if (p && !kprobe_disabled(p)) | |
| 356 | + if (p && !kprobe_disarmed(p)) | |
| 357 | 357 | return -EEXIST; |
| 358 | 358 | } |
| 359 | 359 | |
| @@ -378,6 +378,8 @@ extern void opt_pre_handler(struct kprobe *p, struct pt_regs *regs); · 377 unmodified lines | ||
| 378 | 378 | DEFINE_INSN_CACHE_OPS(optinsn); |
| 379 | 379 | |
| 380 | 380 | extern void wait_for_kprobe_optimizer(void); |
| 381 | +bool optprobe_queued_unopt(struct optimized_kprobe *op); | |
| 382 | +bool kprobe_disarmed(struct kprobe *p); | |
| 381 | 383 | #else /* !CONFIG_OPTPROBES */ |
| 382 | 384 | static inline void wait_for_kprobe_optimizer(void) { } |
| 383 | 385 | #endif /* CONFIG_OPTPROBES */ |
| @@ -458,7 +458,7 @@ static inline int kprobe_optready(struct kprobe *p) · 457 unmodified lines | ||
| 458 | 458 | } |
| 459 | 459 | |
| 460 | 460 | /* Return true if the kprobe is disarmed. Note: p must be on hash list */ |
| 461 | −static inline bool kprobe_disarmed(struct kprobe *p) | |
| 461 | +bool kprobe_disarmed(struct kprobe *p) | |
| 462 | 462 | { |
| 463 | 463 | struct optimized_kprobe *op; |
| 464 | 464 | |
| @@ -555,17 +555,15 @@ static void do_unoptimize_kprobes(void) · 90 unmodified lines | ||
| 555 | 555 | /* See comment in do_optimize_kprobes() */ |
| 556 | 556 | lockdep_assert_cpus_held(); |
| 557 | 557 | |
| 558 | − /* Unoptimization must be done anytime */ | |
| 559 | − if (list_empty(&unoptimizing_list)) | |
| 560 | − return; | |
| 558 | + if (!list_empty(&unoptimizing_list)) | |
| 559 | + arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list); | |
| 561 | 560 | |
| 562 | − arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list); | |
| 563 | − /* Loop on 'freeing_list' for disarming */ | |
| 561 | + /* Loop on 'freeing_list' for disarming and removing from kprobe hash list */ | |
| 564 | 562 | list_for_each_entry_safe(op, tmp, &freeing_list, list) { |
| 565 | 563 | /* Switching from detour code to origin */ |
| 566 | 564 | op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; |
| 567 | − /* Disarm probes if marked disabled */ | |
| 568 | − if (kprobe_disabled(&op->kp)) | |
| 565 | + /* Disarm probes if marked disabled and not gone */ | |
| 566 | + if (kprobe_disabled(&op->kp) && !kprobe_gone(&op->kp)) | |
| 569 | 567 | arch_disarm_kprobe(&op->kp); |
| 570 | 568 | if (kprobe_unused(&op->kp)) { |
| 571 | 569 | /* |
| @@ -662,7 +660,7 @@ void wait_for_kprobe_optimizer(void) · 90 unmodified lines | ||
| 662 | 660 | mutex_unlock(&kprobe_mutex); |
| 663 | 661 | } |
| 664 | 662 | |
| 665 | −static bool optprobe_queued_unopt(struct optimized_kprobe *op) | |
| 663 | +bool optprobe_queued_unopt(struct optimized_kprobe *op) | |
| 666 | 664 | { |
| 667 | 665 | struct optimized_kprobe *_op; |
| 668 | 666 | |
| @@ -797,14 +795,13 @@ static void kill_optimized_kprobe(struct kprobe *p) · 128 unmodified lines | ||
| 797 | 795 | op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; |
| 798 | 796 | |
| 799 | 797 | if (kprobe_unused(p)) { |
| 800 | − /* Enqueue if it is unused */ | |
| 801 | − list_add(&op->list, &freeing_list); | |
| 802 | 798 | /* |
| 803 | − * Remove unused probes from the hash list. After waiting | |
| 804 | − * for synchronization, this probe is reclaimed. | |
| 805 | − * (reclaiming is done by do_free_cleaned_kprobes().) | |
| 799 | + * Unused kprobe is on unoptimizing or freeing list. We move it | |
| 800 | + * to freeing_list and let the kprobe_optimizer() remove it from | |
| 801 | + * the kprobe hash list and free it. | |
| 806 | 802 | */ |
| 807 | − hlist_del_rcu(&op->kp.hlist); | |
| 803 | + if (optprobe_queued_unopt(op)) | |
| 804 | + list_move(&op->list, &freeing_list); | |
| 808 | 805 | } |
| 809 | 806 | |
| 810 | 807 | /* Don't touch the code, because it is already freed. */ |
| @@ -5646,7 +5646,7 @@ static const char readme_msg[] = · 5645 unmodified lines | ||
| 5646 | 5646 | #ifdef CONFIG_HIST_TRIGGERS |
| 5647 | 5647 | "\t s:[synthetic/]<event> <field> [<field>]\n" |
| 5648 | 5648 | #endif |
| 5649 | − "\t e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]\n" | |
| 5649 | + "\t e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>] [if <filter>]\n" | |
| 5650 | 5650 | "\t -:[<group>/][<event>]\n" |
| 5651 | 5651 | #ifdef CONFIG_KPROBE_EVENTS |
| 5652 | 5652 | "\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n" |
| @@ -5663,7 +5663,7 @@ static const char readme_msg[] = · 10 unmodified lines | ||
| 5663 | 5663 | "\t $stack<index>, $stack, $retval, $comm,\n" |
| 5664 | 5664 | #endif |
| 5665 | 5665 | "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" |
| 5666 | − "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n" | |
| 5666 | + "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n" | |
| 5667 | 5667 | "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n" |
| 5668 | 5668 | "\t symstr, <type>\\[<array-size>\\]\n" |
| 5669 | 5669 | #ifdef CONFIG_HIST_TRIGGERS |
| @@ -923,17 +923,13 @@ static int trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, const ch · 922 unmodified lines | ||
| 923 | 923 | |
| 924 | 924 | p = ep->filter_str; |
| 925 | 925 | for (i = 0; i < argc; i++) { |
| 926 | − ret = snprintf(p, len, "%s ", argv[i]); | |
| 927 | − if (ret < 0) | |
| 928 | − goto error; | |
| 929 | − if (ret > len) { | |
| 930 | − ret = -E2BIG; | |
| 931 | − goto error; | |
| 932 | − } | |
| 926 | + if (i) | |
| 927 | + ret = snprintf(p, len, " %s", argv[i]); | |
| 928 | + else | |
| 929 | + ret = snprintf(p, len, "%s", argv[i]); | |
| 933 | 930 | p += ret; |
| 934 | 931 | len -= ret; |
| 935 | 932 | } |
| 936 | − p[-1] = '\0'; | |
| 937 | 933 | |
| 938 | 934 | /* |
| 939 | 935 | * Ensure the filter string can be parsed correctly. Note, this |
| @@ -50,6 +50,7 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x") · 49 unmodified lines | ||
| 50 | 50 | DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x") |
| 51 | 51 | DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") |
| 52 | 52 | DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") |
| 53 | +DEFINE_BASIC_PRINT_TYPE_FUNC(char, u8, "'%c'") | |
| 53 | 54 | |
| 54 | 55 | int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent) |
| 55 | 56 | { |
| @@ -95,6 +96,7 @@ static const struct fetch_type probe_fetch_types[] = { · 39 unmodified lines | ||
| 95 | 96 | ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0), |
| 96 | 97 | ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0), |
| 97 | 98 | ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0), |
| 99 | + ASSIGN_FETCH_TYPE_ALIAS(char, u8, u8, 0), | |
| 98 | 100 | ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0), |
| 99 | 101 | |
| 100 | 102 | ASSIGN_FETCH_TYPE_END |
| @@ -166,6 +166,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x16); · 165 unmodified lines | ||
| 166 | 166 | DECLARE_BASIC_PRINT_TYPE_FUNC(x32); |
| 167 | 167 | DECLARE_BASIC_PRINT_TYPE_FUNC(x64); |
| 168 | 168 | |
| 169 | +DECLARE_BASIC_PRINT_TYPE_FUNC(char); | |
| 169 | 170 | DECLARE_BASIC_PRINT_TYPE_FUNC(string); |
| 170 | 171 | DECLARE_BASIC_PRINT_TYPE_FUNC(symbol); |
| 171 | 172 | |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | static u32 rand1, preh_val, posth_val; |
| 16 | 16 | static u32 (*target)(u32 value); |
| 17 | +static u32 (*recursed_target)(u32 value); | |
| 17 | 18 | static u32 (*target2)(u32 value); |
| 18 | 19 | static struct kunit *current_test; |
| 19 | 20 | |
| @@ -27,18 +28,27 @@ static noinline u32 kprobe_target(u32 value) · 7 unmodified lines | ||
| 27 | 28 | return (value / div_factor); |
| 28 | 29 | } |
| 29 | 30 | |
| 31 | +static noinline u32 kprobe_recursed_target(u32 value) | |
| 32 | +{ | |
| 33 | + return (value / div_factor); | |
| 34 | +} | |
| 35 | + | |
| 30 | 36 | static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
| 31 | 37 | { |
| 32 | 38 | KUNIT_EXPECT_FALSE(current_test, preemptible()); |
| 33 | − preh_val = (rand1 / div_factor); | |
| 39 | + | |
| 40 | + preh_val = recursed_target(rand1); | |
| 34 | 41 | return 0; |
| 35 | 42 | } |
| 36 | 43 | |
| 37 | 44 | static void kp_post_handler(struct kprobe *p, struct pt_regs *regs, |
| 38 | 45 | unsigned long flags) |
| 39 | 46 | { |
| 47 | + u32 expval = recursed_target(rand1); | |
| 48 | + | |
| 40 | 49 | KUNIT_EXPECT_FALSE(current_test, preemptible()); |
| 41 | − KUNIT_EXPECT_EQ(current_test, preh_val, (rand1 / div_factor)); | |
| 50 | + KUNIT_EXPECT_EQ(current_test, preh_val, expval); | |
| 51 | + | |
| 42 | 52 | posth_val = preh_val + div_factor; |
| 43 | 53 | } |
| 44 | 54 | |
| @@ -136,6 +146,29 @@ static void test_kprobes(struct kunit *test) · 91 unmodified lines | ||
| 136 | 146 | unregister_kprobes(kps, 2); |
| 137 | 147 | } |
| 138 | 148 | |
| 149 | +static struct kprobe kp_missed = { | |
| 150 | + .symbol_name = "kprobe_recursed_target", | |
| 151 | + .pre_handler = kp_pre_handler, | |
| 152 | + .post_handler = kp_post_handler, | |
| 153 | +}; | |
| 154 | + | |
| 155 | +static void test_kprobe_missed(struct kunit *test) | |
| 156 | +{ | |
| 157 | + current_test = test; | |
| 158 | + preh_val = 0; | |
| 159 | + posth_val = 0; | |
| 160 | + | |
| 161 | + KUNIT_EXPECT_EQ(test, 0, register_kprobe(&kp_missed)); | |
| 162 | + | |
| 163 | + recursed_target(rand1); | |
| 164 | + | |
| 165 | + KUNIT_EXPECT_EQ(test, 2, kp_missed.nmissed); | |
| 166 | + KUNIT_EXPECT_NE(test, 0, preh_val); | |
| 167 | + KUNIT_EXPECT_NE(test, 0, posth_val); | |
| 168 | + | |
| 169 | + unregister_kprobe(&kp_missed); | |
| 170 | +} | |
| 171 | + | |
| 139 | 172 | #ifdef CONFIG_KRETPROBES |
| 140 | 173 | static u32 krph_val; |
| 141 | 174 | |
| @@ -336,6 +369,7 @@ static int kprobes_test_init(struct kunit *test) · 194 unmodified lines | ||
| 336 | 369 | { |
| 337 | 370 | target = kprobe_target; |
| 338 | 371 | target2 = kprobe_target2; |
| 372 | + recursed_target = kprobe_recursed_target; | |
| 339 | 373 | stacktrace_target = kprobe_stacktrace_target; |
| 340 | 374 | internal_target = kprobe_stacktrace_internal_target; |
| 341 | 375 | stacktrace_driver = kprobe_stacktrace_driver; |
| @@ -346,6 +380,7 @@ static int kprobes_test_init(struct kunit *test) · 4 unmodified lines | ||
| 346 | 380 | static struct kunit_case kprobes_testcases[] = { |
| 347 | 381 | KUNIT_CASE(test_kprobe), |
| 348 | 382 | KUNIT_CASE(test_kprobes), |
| 383 | + KUNIT_CASE(test_kprobe_missed), | |
| 349 | 384 | #ifdef CONFIG_KRETPROBES |
| 350 | 385 | KUNIT_CASE(test_kretprobe), |
| 351 | 386 | KUNIT_CASE(test_kretprobes), |
| @@ -22,6 +22,8 @@ check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME · 21 unmodified lines | ||
| 22 | 22 | check_error 'e:foo/bar syscalls/sys_enter_openat arg=^dfd' # BAD_FETCH_ARG |
| 23 | 23 | check_error 'e:foo/bar syscalls/sys_enter_openat ^arg=$foo' # BAD_ATTACH_ARG |
| 24 | 24 | |
| 25 | −check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER | |
| 25 | +if grep -q '<attached-group>\.<attached-event>.*\[if <filter>\]' README; then | |
| 26 | + check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER | |
| 27 | +fi | |
| 26 | 28 | |
| 27 | 29 | exit 0 |
| @@ -0,0 +1,47 @@ | ||
| 1 | +#!/bin/sh | |
| 2 | +# SPDX-License-Identifier: GPL-2.0 | |
| 3 | +# description: Kprobe event char type argument | |
| 4 | +# requires: kprobe_events | |
| 5 | + | |
| 6 | +case `uname -m` in | |
| 7 | +x86_64) | |
| 8 | + ARG1=%di | |
| 9 | +;; | |
| 10 | +i[3456]86) | |
| 11 | + ARG1=%ax | |
| 12 | +;; | |
| 13 | +aarch64) | |
| 14 | + ARG1=%x0 | |
| 15 | +;; | |
| 16 | +arm*) | |
| 17 | + ARG1=%r0 | |
| 18 | +;; | |
| 19 | +ppc64*) | |
| 20 | + ARG1=%r3 | |
| 21 | +;; | |
| 22 | +ppc*) | |
| 23 | + ARG1=%r3 | |
| 24 | +;; | |
| 25 | +s390*) | |
| 26 | + ARG1=%r2 | |
| 27 | +;; | |
| 28 | +mips*) | |
| 29 | + ARG1=%r4 | |
| 30 | +;; | |
| 31 | +*) | |
| 32 | + echo "Please implement other architecture here" | |
| 33 | + exit_untested | |
| 34 | +esac | |
| 35 | + | |
| 36 | +: "Test get argument (1)" | |
| 37 | +echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char" > kprobe_events | |
| 38 | +echo 1 > events/kprobes/testprobe/enable | |
| 39 | +echo "p:test $FUNCTION_FORK" >> kprobe_events | |
| 40 | +grep -qe "testprobe.* arg1='t'" trace | |
| 41 | + | |
| 42 | +echo 0 > events/kprobes/testprobe/enable | |
| 43 | +: "Test get argument (2)" | |
| 44 | +echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char arg2=+0(${ARG1}):char[4]" > kprobe_events | |
| 45 | +echo 1 > events/kprobes/testprobe/enable | |
| 46 | +echo "p:test $FUNCTION_FORK" >> kprobe_events | |
| 47 | +grep -qe "testprobe.* arg1='t' arg2={'t','e','s','t'}" trace | |
| @@ -21,7 +21,7 @@ set_offs() { # prev target next · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | # We have to decode symbol addresses to get correct offsets. |
| 23 | 23 | # If the offset is not an instruction boundary, it cause -EILSEQ. |
| 24 | −set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` | |
| 24 | +set_offs `grep -v __pfx_ /proc/kallsyms | grep -A1 -B1 ${TARGET_FUNC} | cut -f 1 -d " " | xargs` | |
| 25 | 25 | |
| 26 | 26 | UINT_TEST=no |
| 27 | 27 | # printf "%x" -1 returns (unsigned long)-1. |