ARM: kprobes: OPTPROBES and other improvements.
Subsystems (6)
v15 cover ARM: kprobes: OPTPROBES and other improvements.
This is v15 patch series of kprobeopt related code. V14 uses stop_machine() incorrectly, this version fixes it.
Previous discussion can be found from:
https://lkml.org/lkml/2014/12/8/21
https://lkml.org/lkml/2014/12/4/942
https://lkml.org/lkml/2014/12/4/4
https://lkml.org/lkml/2014/12/1/64
https://lkml.org/lkml/2014/11/22/18
https://lkml.org/lkml/2014/11/21/55
https://lkml.org/lkml/2014/11/18/26
https://lkml.org/lkml/2014/11/19/31
https://lkml.org/lkml/2014/11/18/41
https://lkml.org/lkml/2014/10/25/48
https://lkml.org/lkml/2014/10/22/254
https://lkml.org/lkml/2014/8/27/255
https://lkml.org/lkml/2014/8/12/12
https://lkml.org/lkml/2014/8/8/992
https://lkml.org/lkml/2014/8/8/5
https://lkml.org/lkml/2014/8/5/63
Jon Medhurst (1):
ARM: kprobes: Add test cases for stack consuming instructions
Masami Hiramatsu (1):
kprobes: Pass the original kprobe for preparing optimized kprobe
Wang Nan (5):
ARM: probes: move all probe code to dedicate directory
ARM: kprobes: introduces checker
ARM: kprobes: collects stack consumption for store instructions
ARM: kprobes: disallow probing stack consuming instructions
ARM: kprobes: enable OPTPROBES for ARM 32
arch/arm/Kconfig | 1 +
arch/arm/Makefile | 1 +
arch/arm/{kernel => include/asm}/insn.h | 0
arch/arm/include/asm/kprobes.h | 30 +-
arch/arm/{kernel => include/asm}/patch.h | 0
arch/arm/include/asm/probes.h | 13 +
arch/arm/kernel/Makefile | 16 +-
arch/arm/kernel/entry-armv.S | 3 +-
arch/arm/kernel/ftrace.c | 3 +-
arch/arm/kernel/jump_label.c | 5 +-
arch/arm/kernel/patch.c | 3 +-
arch/arm/probes/Makefile | 7 +
.../{kernel/probes-arm.c => probes/decode-arm.c} | 12 +-
.../{kernel/probes-arm.h => probes/decode-arm.h} | 7 +-
.../probes-thumb.c => probes/decode-thumb.c} | 16 +-
.../probes-thumb.h => probes/decode-thumb.h} | 10 +-
arch/arm/{kernel/probes.c => probes/decode.c} | 74 ++++-
arch/arm/{kernel/probes.h => probes/decode.h} | 13 +-
arch/arm/probes/kprobes/Makefile | 12 +
.../kprobes-arm.c => probes/kprobes/actions-arm.c} | 9 +-
.../kprobes/actions-common.c} | 4 +-
.../kprobes/actions-thumb.c} | 10 +-
arch/arm/probes/kprobes/checkers-arm.c | 99 +++++++
arch/arm/probes/kprobes/checkers-common.c | 101 +++++++
arch/arm/probes/kprobes/checkers-thumb.c | 110 +++++++
arch/arm/probes/kprobes/checkers.h | 54 ++++
.../{kernel/kprobes.c => probes/kprobes/core.c} | 49 +++-
.../{kernel/kprobes.h => probes/kprobes/core.h} | 12 +-
arch/arm/probes/kprobes/opt-arm.c | 317 +++++++++++++++++++++
.../kprobes/test-arm.c} | 31 +-
.../kprobes-test.c => probes/kprobes/test-core.c} | 8 +-
.../kprobes-test.h => probes/kprobes/test-core.h} | 2 +-
.../kprobes/test-thumb.c} | 16 +-
arch/arm/probes/uprobes/Makefile | 2 +
.../uprobes-arm.c => probes/uprobes/actions-arm.c} | 6 +-
.../{kernel/uprobes.c => probes/uprobes/core.c} | 8 +-
.../{kernel/uprobes.h => probes/uprobes/core.h} | 0
arch/x86/kernel/kprobes/opt.c | 3 +-
include/linux/kprobes.h | 3 +-
kernel/kprobes.c | 4 +-
40 files changed, 976 insertions(+), 98 deletions(-)
rename arch/arm/{kernel => include/asm}/insn.h (100%)
rename arch/arm/{kernel => include/asm}/patch.h (100%)
create mode 100644 arch/arm/probes/Makefile
rename arch/arm/{kernel/probes-arm.c => probes/decode-arm.c} (99%)
rename arch/arm/{kernel/probes-arm.h => probes/decode-arm.h} (93%)
rename arch/arm/{kernel/probes-thumb.c => probes/decode-thumb.c} (98%)
rename arch/arm/{kernel/probes-thumb.h => probes/decode-thumb.h} (90%)
rename arch/arm/{kernel/probes.c => probes/decode.c} (85%)
rename arch/arm/{kernel/probes.h => probes/decode.h} (97%)
create mode 100644 arch/arm/probes/kprobes/Makefile
rename arch/arm/{kernel/kprobes-arm.c => probes/kprobes/actions-arm.c} (98%)
rename arch/arm/{kernel/kprobes-common.c => probes/kprobes/actions-common.c} (98%)
rename arch/arm/{kernel/kprobes-thumb.c => probes/kprobes/actions-thumb.c} (98%)
create mode 100644 arch/arm/probes/kprobes/checkers-arm.c
create mode 100644 arch/arm/probes/kprobes/checkers-common.c
create mode 100644 arch/arm/probes/kprobes/checkers-thumb.c
create mode 100644 arch/arm/probes/kprobes/checkers.h
rename arch/arm/{kernel/kprobes.c => probes/kprobes/core.c} (94%)
rename arch/arm/{kernel/kprobes.h => probes/kprobes/core.h} (79%)
create mode 100644 arch/arm/probes/kprobes/opt-arm.c
rename arch/arm/{kernel/kprobes-test-arm.c => probes/kprobes/test-arm.c} (97%)
rename arch/arm/{kernel/kprobes-test.c => probes/kprobes/test-core.c} (99%)
rename arch/arm/{kernel/kprobes-test.h => probes/kprobes/test-core.h} (99%)
rename arch/arm/{kernel/kprobes-test-thumb.c => probes/kprobes/test-thumb.c} (98%)
create mode 100644 arch/arm/probes/uprobes/Makefile
rename arch/arm/{kernel/uprobes-arm.c => probes/uprobes/actions-arm.c} (98%)
rename arch/arm/{kernel/uprobes.c => probes/uprobes/core.c} (97%)
rename arch/arm/{kernel/uprobes.h => probes/uprobes/core.h} (100%)Signature · 1 line
1.8.4
PATCH RESEND v15 1/7 ARM: probes: move all probe code to dedicate directory
In discussion on LKML (https://lkml.org/lkml/2014/11/28/158), Russell King suggests to move all probe related code to arch/arm/probes. This patch does the work. Due to dependency on 'arch/arm/kernel/patch.h', this patch also moves patch.h to 'arch/arm/include/asm/patch.h', and related '#include' directives are also midified to '#include <asm/patch.h>'.
Following is an overview of this patch:
./arch/arm/kernel/ ./arch/arm/probes/ |-- Makefile |-- Makefile |-- probes-arm.c ==> |-- decode-arm.c |-- probes-arm.h ==> |-- decode-arm.h |-- probes-thumb.c ==> |-- decode-thumb.c |-- probes-thumb.h ==> |-- decode-thumb.h |-- probes.c ==> |-- decode.c |-- probes.h ==> |-- decode.h | |-- kprobes | | |-- Makefile |-- kprobes-arm.c ==> | |-- actions-arm.c |-- kprobes-common.c ==> | |-- actions-common.c |-- kprobes-thumb.c ==> | |-- actions-thumb.c |-- kprobes.c ==> | |-- core.c |-- kprobes.h ==> | |-- core.h |-- kprobes-test-arm.c ==> | |-- test-arm.c |-- kprobes-test.c ==> | |-- test-core.c |-- kprobes-test.h ==> | |-- test-core.h |-- kprobes-test-thumb.c ==> | `-- test-thumb.c | `-- uprobes | |-- Makefile |-- uprobes-arm.c ==> |-- actions-arm.c |-- uprobes.c ==> |-- core.c |-- uprobes.h ==> `-- core.h | `-- patch.h ==> arch/arm/include/asm/patch.h
---
v1 -> v2:
- Rename source files to describe their functions.
- Add Makefiles in kprobes and uprobes directories.
---
arch/arm/Makefile | 1 +
arch/arm/{kernel => include/asm}/patch.h | 0
arch/arm/kernel/Makefile | 16 ++--------------
arch/arm/kernel/jump_label.c | 2 +-
arch/arm/kernel/patch.c | 3 +--
arch/arm/probes/Makefile | 7 +++++++
arch/arm/{kernel/probes-arm.c => probes/decode-arm.c} | 7 ++++---
arch/arm/{kernel/probes-arm.h => probes/decode-arm.h} | 4 +++-
.../arm/{kernel/probes-thumb.c => probes/decode-thumb.c} | 6 +++---
.../arm/{kernel/probes-thumb.h => probes/decode-thumb.h} | 4 +++-
arch/arm/{kernel/probes.c => probes/decode.c} | 4 ++--
arch/arm/{kernel/probes.h => probes/decode.h} | 2 +-
arch/arm/probes/kprobes/Makefile | 11 +++++++++++
.../kprobes-arm.c => probes/kprobes/actions-arm.c} | 6 +++---
.../kprobes-common.c => probes/kprobes/actions-common.c} | 4 ++--
.../kprobes-thumb.c => probes/kprobes/actions-thumb.c} | 6 +++---
arch/arm/{kernel/kprobes.c => probes/kprobes/core.c} | 8 ++++----
arch/arm/{kernel/kprobes.h => probes/kprobes/core.h} | 3 ++-
.../kprobes-test-arm.c => probes/kprobes/test-arm.c} | 2 +-
.../kprobes-test.c => probes/kprobes/test-core.c} | 8 ++++----
.../kprobes-test.h => probes/kprobes/test-core.h} | 2 +-
.../kprobes-test-thumb.c => probes/kprobes/test-thumb.c} | 4 ++--
arch/arm/probes/uprobes/Makefile | 2 ++
.../uprobes-arm.c => probes/uprobes/actions-arm.c} | 6 +++---
arch/arm/{kernel/uprobes.c => probes/uprobes/core.c} | 6 +++---
arch/arm/{kernel/uprobes.h => probes/uprobes/core.h} | 0
26 files changed, 69 insertions(+), 55 deletions(-)
rename arch/arm/{kernel => include/asm}/patch.h (100%)
create mode 100644 arch/arm/probes/Makefile
rename arch/arm/{kernel/probes-arm.c => probes/decode-arm.c} (99%)
rename arch/arm/{kernel/probes-arm.h => probes/decode-arm.h} (97%)
rename arch/arm/{kernel/probes-thumb.c => probes/decode-thumb.c} (99%)
rename arch/arm/{kernel/probes-thumb.h => probes/decode-thumb.h} (97%)
rename arch/arm/{kernel/probes.c => probes/decode.c} (99%)
rename arch/arm/{kernel/probes.h => probes/decode.h} (99%)
create mode 100644 arch/arm/probes/kprobes/Makefile
rename arch/arm/{kernel/kprobes-arm.c => probes/kprobes/actions-arm.c} (99%)
rename arch/arm/{kernel/kprobes-common.c => probes/kprobes/actions-common.c} (98%)
rename arch/arm/{kernel/kprobes-thumb.c => probes/kprobes/actions-thumb.c} (99%)
rename arch/arm/{kernel/kprobes.c => probes/kprobes/core.c} (99%)
rename arch/arm/{kernel/kprobes.h => probes/kprobes/core.h} (96%)
rename arch/arm/{kernel/kprobes-test-arm.c => probes/kprobes/test-arm.c} (99%)
rename arch/arm/{kernel/kprobes-test.c => probes/kprobes/test-core.c} (99%)
rename arch/arm/{kernel/kprobes-test.h => probes/kprobes/test-core.h} (99%)
rename arch/arm/{kernel/kprobes-test-thumb.c => probes/kprobes/test-thumb.c} (99%)
create mode 100644 arch/arm/probes/uprobes/Makefile
rename arch/arm/{kernel/uprobes-arm.c => probes/uprobes/actions-arm.c} (98%)
rename arch/arm/{kernel/uprobes.c => probes/uprobes/core.c} (98%)
rename arch/arm/{kernel/uprobes.h => probes/uprobes/core.h} (100%)arch/arm/Makefile +1 -0
@@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ +core-y += arch/arm/probes/ core-y += arch/arm/net/ core-y += arch/arm/crypto/ core-y += arch/arm/firmware/
arch/arm/include/asm/patch.h renamed from arch/arm/kernel/patch.h +0 -0
arch/arm/kernel/Makefile +2 -14
@@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o -obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o -ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o -else -obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o -endif -obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o -test-kprobes-objs := kprobes-test.o -ifdef CONFIG_THUMB2_KERNEL -test-kprobes-objs += kprobes-test-thumb.o -else -test-kprobes-objs += kprobes-test-arm.o -endif +# Main staffs in KPROBES are in arch/arm/probes/ . +obj-$(CONFIG_KPROBES) += patch.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.o
arch/arm/kernel/jump_label.c +1 -1
@@ -1,8 +1,8 @@#include <linux/kernel.h> #include <linux/jump_label.h> +#include <asm/patch.h> #include "insn.h" -#include "patch.h" #ifdef HAVE_JUMP_LABEL
arch/arm/kernel/patch.c +1 -2
@@ -5,8 +5,7 @@#include <asm/cacheflush.h> #include <asm/smp_plat.h> #include <asm/opcodes.h> - -#include "patch.h" +#include <asm/patch.h> struct patch {void *addr;
arch/arm/probes/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +obj-$(CONFIG_UPROBES) += decode.o decode-arm.o uprobes/ +obj-$(CONFIG_KPROBES) += decode.o kprobes/ +ifdef CONFIG_THUMB2_KERNEL +obj-$(CONFIG_KPROBES) += decode-thumb.o +else +obj-$(CONFIG_KPROBES) += decode-arm.o +endif
arch/arm/probes/decode-arm.c renamed from arch/arm/kernel/probes-arm.c +4 -3
@@ -1,5 +1,6 @@/* -* arch/arm/kernel/probes-arm.c +* +* arch/arm/probes/decode-arm.c * * Some code moved here from arch/arm/kernel/kprobes-arm.c *
@@ -20,8 +21,8 @@#include <linux/stddef.h> #include <linux/ptrace.h> -#include "probes.h" -#include "probes-arm.h" +#include "decode.h" +#include "decode-arm.h" #define sign_extend (x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
arch/arm/probes/decode-arm.h renamed from arch/arm/kernel/probes-arm.h +3 -1
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/probes-arm.h +* arch/arm/probes/decode-arm.h * * Copyright 2013 Linaro Ltd. * Written by: David A. Long
@@ -15,6 +15,8 @@#ifndef _ARM_KERNEL_PROBES_ARM_H#define _ARM_KERNEL_PROBES_ARM_H +#include "decode.h" +enum probes_arm_action {PROBES_EMULATE_NONE , PROBES_SIMULATE_NOP,
arch/arm/probes/decode-thumb.c renamed from arch/arm/kernel/probes-thumb.c +3 -3
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/probes-thumb.c +* arch/arm/probes/decode-thumb.c * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
@@ -12,8 +12,8 @@#include <linux/kernel.h> #include <linux/module.h> -#include "probes.h" -#include "probes-thumb.h" +#include "decode.h" +#include "decode-thumb.h" static const union decode_item t32_table_1110_100x_x0xx[] = {
arch/arm/probes/decode-thumb.h renamed from arch/arm/kernel/probes-thumb.h +3 -1
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/probes-thumb.h +* arch/arm/probes/decode-thumb.h * * Copyright 2013 Linaro Ltd. * Written by: David A. Long
@@ -15,6 +15,8 @@#ifndef _ARM_KERNEL_PROBES_THUMB_H#define _ARM_KERNEL_PROBES_THUMB_H +#include "decode.h" +/* * True if current instruction is in an IT block. */
arch/arm/probes/decode.c renamed from arch/arm/kernel/probes.c +2 -2
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/probes.c +* arch/arm/probes/decode.c * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
@@ -17,7 +17,7 @@#include <asm/ptrace.h> #include <linux/bug.h> -#include "probes.h" +#include "decode.h" #ifndef find_str_pc_offset
arch/arm/probes/decode.h renamed from arch/arm/kernel/probes.h +1 -1
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/probes.h +* arch/arm/probes/decode.h * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
arch/arm/probes/kprobes/Makefile new file +11 -0
@@ -0,0 +1,11 @@ +obj-$(CONFIG_KPROBES) += core.o actions-common.o +obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o +test-kprobes-objs := test-core.o + +ifdef CONFIG_THUMB2_KERNEL +obj-$(CONFIG_KPROBES) += actions-thumb.o +test-kprobes-objs += test-thumb.o +else +obj-$(CONFIG_KPROBES) += actions-arm.o +test-kprobes-objs += test-arm.o +endif
arch/arm/probes/kprobes/actions-arm.c renamed from arch/arm/kernel/kprobes-arm.c +3 -3
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/kprobes-decode.c +* arch/arm/probes/kprobes/actions-arm.c * * Copyright (C) 2006, 2007 Motorola Inc. *
@@ -62,8 +62,8 @@#include <linux/kprobes.h> #include <linux/ptrace.h> -#include "kprobes.h" -#include "probes-arm.h" +#include "../decode-arm.h" +#include "core.h" #if __LINUX_ARM_ARCH__ >=6 #define BLX (reg) "blx "reg" \n\t"
arch/arm/probes/kprobes/actions-common.c renamed from arch/arm/kernel/kprobes-common.c +2 -2
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/kprobes-common.c +* arch/arm/probes/kprobes/actions-common.c * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
@@ -15,7 +15,7 @@#include <linux/kprobes.h> #include <asm/opcodes.h> -#include "kprobes.h" +#include "core.h" static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
arch/arm/probes/kprobes/actions-thumb.c renamed from arch/arm/kernel/kprobes-thumb.c +3 -3
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/kprobes-thumb.c +* arch/arm/probes/kprobes/actions-thumb.c * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
@@ -13,8 +13,8 @@#include <linux/ptrace.h> #include <linux/kprobes.h> -#include "kprobes.h" -#include "probes-thumb.h" +#include "../decode-thumb.h" +#include "core.h" /* These emulation encodings are functionally equivalent... */ #define t32_emulate_rd8rn16rm0ra12_noflags \
arch/arm/probes/kprobes/core.c renamed from arch/arm/kernel/kprobes.c +4 -4
@@ -30,11 +30,11 @@#include <asm/cacheflush.h> #include <linux/percpu.h> #include <linux/bug.h> +#include <asm/patch.h> -#include "kprobes.h" -#include "probes-arm.h" -#include "probes-thumb.h" -#include "patch.h" +#include "../decode-arm.h" +#include "../decode-thumb.h" +#include "core.h" #define MIN_STACK_SIZE (addr) \ min((unsigned long)MAX_STACK_SIZE, \
arch/arm/probes/kprobes/core.h renamed from arch/arm/kernel/kprobes.h +2 -1
@@ -19,7 +19,8 @@#ifndef _ARM_KERNEL_KPROBES_H#define _ARM_KERNEL_KPROBES_H -#include "probes.h" +#include <asm/kprobes.h> +#include "../decode.h" /* * These undefined instructions must be unique and
arch/arm/probes/kprobes/test-arm.c renamed from arch/arm/kernel/kprobes-test-arm.c +1 -1
@@ -13,7 +13,7 @@#include <asm/system_info.h> #include <asm/opcodes.h> -#include "kprobes-test.h" +#include "test-core.h" #define TEST_ISA "32"
arch/arm/probes/kprobes/test-core.c renamed from arch/arm/kernel/kprobes-test.c +4 -4
@@ -209,10 +209,10 @@#include <linux/bug.h> #include <asm/opcodes.h> -#include "kprobes.h" -#include "probes-arm.h" -#include "probes-thumb.h" -#include "kprobes-test.h" +#include "core.h" +#include "test-core.h" +#include "../decode-arm.h" +#include "../decode-thumb.h" #define BENCHMARKING 1
arch/arm/probes/kprobes/test-core.h renamed from arch/arm/kernel/kprobes-test.h +1 -1
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/kprobes-test.h +* arch/arm/probes/kprobes/test-core.h * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
arch/arm/probes/kprobes/test-thumb.c renamed from arch/arm/kernel/kprobes-test-thumb.c +2 -2
@@ -1,5 +1,5 @@/* -* arch/arm/kernel/kprobes-test-thumb.c +* arch/arm/probes/kprobes/test-thumb.c * * Copyright (C) 2011 Jon Medhurst <[email protected]>. *
@@ -12,7 +12,7 @@#include <linux/module.h> #include <asm/opcodes.h> -#include "kprobes-test.h" +#include "test-core.h" #define TEST_ISA "16"
arch/arm/probes/uprobes/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +obj-$(CONFIG_UPROBES) += core.o actions-arm.o +
arch/arm/probes/uprobes/actions-arm.c renamed from arch/arm/kernel/uprobes-arm.c +3 -3
@@ -13,9 +13,9 @@#include <linux/uprobes.h> #include <linux/module.h> -#include "probes.h" -#include "probes-arm.h" -#include "uprobes.h" +#include "../decode.h" +#include "../decode-arm.h" +#include "core.h" static int uprobes_substitute_pc (unsigned long *pinsn,u32 oregs) {
arch/arm/probes/uprobes/core.c renamed from arch/arm/kernel/uprobes.c +3 -3
@@ -17,9 +17,9 @@#include <asm/opcodes.h> #include <asm/traps.h> -#include "probes.h" -#include "probes-arm.h" -#include "uprobes.h" +#include "../decode.h" +#include "../decode-arm.h" +#include "core.h" #define UPROBE_TRAP_NR UINT_MAX
arch/arm/probes/uprobes/core.h renamed from arch/arm/kernel/uprobes.h +0 -0
Signature · 1 line
1.8.4
PATCH RESEND v15 2/7 ARM: kprobes: introduces checker
In reply to Wang NanThis patch introdces 'checker' to decoding phase, and calls checkers when instruction decoding. This allows further decoding for specific instructions. This patch introduces a stub call of checkers in kprobe arch_prepare_kprobe() as an example and for further expansion.
---
v1 -> v2:
- kprobe checker stubs are introduced in this patch.
v2 -> v3:
- Code cleanups following Masami Hiramatsu and Tixy's advises.
- Commit message improvements.
v3 -> v4:
- Move to arch/arm/probes.
--- arch/arm/probes/decode-arm.c | 5 +-- arch/arm/probes/decode-arm.h | 3 +- arch/arm/probes/decode-thumb.c | 10 +++--- arch/arm/probes/decode-thumb.h | 6 ++-- arch/arm/probes/decode.c | 60 +++++++++++++++++++++++++++++---- arch/arm/probes/decode.h | 11 +++++- arch/arm/probes/kprobes/actions-arm.c | 2 ++ arch/arm/probes/kprobes/actions-thumb.c | 3 ++ arch/arm/probes/kprobes/core.c | 6 +++- arch/arm/probes/kprobes/core.h | 7 ++-- arch/arm/probes/uprobes/core.c | 2 +- 11 files changed, 95 insertions(+), 20 deletions(-)
arch/arm/probes/decode-arm.c +3 -2
@@ -726,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn,*/ enum probes_insn __kprobes arm_probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi, -bool emulate,const union decode_action *actions) +bool emulate,const union decode_action *actions, +const struct decode_checker *checkers[]) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28 ];return probes_decode_insn (insn, asi, probes_decode_arm_table, false, - emulate, actions); + emulate, actions, checkers); }
arch/arm/probes/decode-arm.h +2 -1
@@ -70,6 +70,7 @@ extern const union decode_item probes_decode_arm_table[];enum probes_insn arm_probes_decode_insn (probes_opcode_t ,struct arch_probes_insn *,bool emulate, -const union decode_action *actions); +const union decode_action *actions, +const struct decode_checker *checkers[]);#endif
arch/arm/probes/decode-thumb.c +6 -4
@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode,enum probes_insn __kprobes thumb16_probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi, -bool emulate,const union decode_action *actions) +bool emulate,const union decode_action *actions, +const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc;return probes_decode_insn (insn, asi, probes_decode_thumb16_table, true, - emulate, actions); + emulate, actions, checkers); }enum probes_insn __kprobes thumb32_probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi, -bool emulate,const union decode_action *actions) +bool emulate,const union decode_action *actions, +const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc;return probes_decode_insn (insn, asi, probes_decode_thumb32_table, true, - emulate, actions); + emulate, actions, checkers); }
arch/arm/probes/decode-thumb.h +4 -2
@@ -91,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[];enum probes_insn __kprobes thumb16_probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi, -bool emulate,const union decode_action *actions); +bool emulate,const union decode_action *actions, +const struct decode_checker *checkers[]);enum probes_insn __kprobes thumb32_probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi, -bool emulate,const union decode_action *actions); +bool emulate,const union decode_action *actions, +const struct decode_checker *checkers[]);#endif
arch/arm/probes/decode.c +54 -6
95 lines not on this page · raw message
arch/arm/probes/decode.h +10 -1
@@ -314,6 +314,14 @@ union decode_action {probes_custom_decode_t *decoder; }; +typedef enum probes_insn (probes_check_t )(probes_opcode_t , +struct arch_probes_insn *, +const struct decode_header *); + +struct decode_checker { +probes_check_t *checker; +}; +#define DECODE_END \ {.bits = DECODE_TYPE_END}
@@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none;int __kprobes probes_decode_insn (probes_opcode_t insn,struct arch_probes_insn *asi,const union decode_item *table,bool thumb,bool emulate, -const union decode_action *actions); +const union decode_action *actions, +const struct decode_checker **checkers);#endif
arch/arm/probes/kprobes/actions-arm.c +2 -0
@@ -341,3 +341,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_BRANCH] = {.handler = simulate_bbl}, [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} }; + +const struct decode_checker *kprobes_arm_checkers[] = {NULL };
arch/arm/probes/kprobes/actions-thumb.c +3 -0
@@ -664,3 +664,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { [PROBES_T32_MUL_ADD_LONG ] = { .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, }; + +const struct decode_checker *kprobes_t32_checkers[] = {NULL }; +const struct decode_checker *kprobes_t16_checkers[] = {NULL };
arch/arm/probes/kprobes/core.c +5 -1
@@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)kprobe_decode_insn_t *decode_insn;const union decode_action *actions;int is; +const struct decode_checker **checkers;if (in_exception_text (addr))return -EINVAL ;
@@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn =__opcode_thumb32_compose (insn, inst2); decode_insn = thumb32_probes_decode_insn; actions = kprobes_t32_actions; + checkers = kprobes_t32_checkers; }else { decode_insn = thumb16_probes_decode_insn; actions = kprobes_t16_actions; + checkers = kprobes_t16_checkers; }#else /* !CONFIG_THUMB2_KERNEL */ thumb = false;
@@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn =__mem_to_opcode_arm (*p->addr); decode_insn = arm_probes_decode_insn; actions = kprobes_arm_actions; + checkers = kprobes_arm_checkers;#endif p->opcode = insn; p->ainsn.insn = tmp_insn; -switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { +switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) {case INSN_REJECTED :/* not supported */ return -EINVAL ;
arch/arm/probes/kprobes/core.h +5 -2
@@ -37,16 +37,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,typedef enum probes_insn (kprobe_decode_insn_t )(probes_opcode_t ,struct arch_probes_insn *,bool , -const union decode_action *); +const union decode_action *, +const struct decode_checker *[*]);#ifdef CONFIG_THUMB2_KERNEL extern const union decode_action kprobes_t32_actions[];extern const union decode_action kprobes_t16_actions[]; - +extern const struct decode_checker *kprobes_t32_checkers[]; +extern const struct decode_checker *kprobes_t16_checkers[];#else /* !CONFIG_THUMB2_KERNEL */ extern const union decode_action kprobes_arm_actions[]; +extern const struct decode_checker *kprobes_arm_checkers[];#endif
arch/arm/probes/uprobes/core.c +1 -1
@@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, auprobe->ixol[1 ] =__opcode_to_mem_arm (UPROBE_SS_ARM_INSN ); ret =arm_probes_decode_insn (insn, &auprobe->asi, false, - uprobes_probes_actions); + uprobes_probes_actions,NULL );switch (ret) {case INSN_REJECTED :return -EINVAL ;
Signature · 1 line
1.8.4
PATCH RESEND v15 3/7 ARM: kprobes: collects stack consumption for store instructions
In reply to Wang NanThis patch uses the previously introduced checker functionality on store instructions to record their stack consumption information to arch_probes_insn.
---
v1 -> v2:
- Bugfix and code improvements following Tixy's suggestion. See:
http://www.spinics.net/lists/arm-kernel/msg372912.html
v2 -> v3:
- Totaly reconstructed following Tixy' instruction. See:
https://lkml.org/lkml/2014/10/27/662 .
Add his SOB.
v3 -> v4:
- Commit message improvements.
- Comments improvements and code cleanup.
- A bug is found and fixed in decode table in arm_check_stack().
v4 -> v5:
- Bugs in thumb2 decoding table is found by Tixy and fixed.
v5 -> v6:
- Move to arch/arm/probes/ .
--- arch/arm/include/asm/probes.h | 1 + arch/arm/probes/decode.c | 10 +++ arch/arm/probes/kprobes/Makefile | 6 +- arch/arm/probes/kprobes/actions-arm.c | 3 +- arch/arm/probes/kprobes/actions-thumb.c | 5 +- arch/arm/probes/kprobes/checkers-arm.c | 99 +++++++++++++++++++++++++++ arch/arm/probes/kprobes/checkers-common.c | 101 +++++++++++++++++++++++++++ arch/arm/probes/kprobes/checkers-thumb.c | 110 ++++++++++++++++++++++++++++++ arch/arm/probes/kprobes/checkers.h | 54 +++++++++++++++ 9 files changed, 383 insertions(+), 6 deletions(-) create mode 100644 arch/arm/probes/kprobes/checkers-arm.c create mode 100644 arch/arm/probes/kprobes/checkers-common.c create mode 100644 arch/arm/probes/kprobes/checkers-thumb.c create mode 100644 arch/arm/probes/kprobes/checkers.h
arch/arm/include/asm/probes.h +1 -0
@@ -38,6 +38,7 @@ struct arch_probes_insn {probes_check_cc *insn_check_cc;probes_insn_singlestep_t *insn_singlestep;probes_insn_fn_t *insn_fn; + int stack_space; };#endif
arch/arm/probes/decode.c +10 -0
@@ -425,6 +425,16 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,*/ probes_opcode_t origin_insn = insn; +/* +* stack_space is initialized to 0 here. Checker functions +* should update is value if they find this is a stack store +* instruction: positive value means bytes of stack usage, +* negitive value means unable to determine stack usage +* statically. For instruction doesn't store to stack, checker +* do nothing with it. +*/ + asi->stack_space =0 ; +if (emulate) insn =prepare_emulated_insn (insn, asi, thumb);
arch/arm/probes/kprobes/Makefile +3 -3
@@ -1,11 +1,11 @@ -obj-$(CONFIG_KPROBES) += core.o actions-common.o +obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o test-kprobes-objs := test-core.o ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += actions-thumb.o +obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o test-kprobes-objs += test-thumb.o else -obj-$(CONFIG_KPROBES) += actions-arm.o +obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o test-kprobes-objs += test-arm.o endif
arch/arm/probes/kprobes/actions-arm.c +2 -1
@@ -64,6 +64,7 @@#include "../decode-arm.h" #include "core.h" +#include "checkers.h" #if __LINUX_ARM_ARCH__ >=6 #define BLX (reg) "blx "reg" \n\t"
@@ -342,4 +343,4 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} }; -const struct decode_checker *kprobes_arm_checkers[] = {NULL }; +const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker,NULL };
arch/arm/probes/kprobes/actions-thumb.c +3 -2
@@ -15,6 +15,7 @@#include "../decode-thumb.h" #include "core.h" +#include "checkers.h" /* These emulation encodings are functionally equivalent... */ #define t32_emulate_rd8rn16rm0ra12_noflags \
@@ -665,5 +666,5 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, }; -const struct decode_checker *kprobes_t32_checkers[] = {NULL }; -const struct decode_checker *kprobes_t16_checkers[] = {NULL }; +const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker,NULL }; +const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker,NULL };
arch/arm/probes/kprobes/checkers-arm.c new file +99 -0
99 lines not on this page · raw message
arch/arm/probes/kprobes/checkers-common.c new file +101 -0
101 lines not on this page · raw message
arch/arm/probes/kprobes/checkers-thumb.c new file +110 -0
110 lines not on this page · raw message
arch/arm/probes/kprobes/checkers.h new file +54 -0
54 lines not on this page · raw message
Signature · 1 line
1.8.4
PATCH RESEND v15 4/7 ARM: kprobes: disallow probing stack consuming instructions
In reply to Wang NanThis patch prohibits probing instructions for which the stack requirements are unable to be determined statically. Some test cases are found not work again after the modification, this patch also removes them.
---
v1 -> v2:
- Use MAX_STACK_SIZE macro instead of hard coded stack size.
v2 -> v3:
- Commit message improvements.
v3 -> v4:
- Commit message improvements.
v4 -> v5:
- Move to arch/arm/probes.
--- arch/arm/include/asm/kprobes.h | 1 - arch/arm/include/asm/probes.h | 12 ++++++++++++ arch/arm/kernel/entry-armv.S | 3 ++- arch/arm/probes/kprobes/core.c | 9 +++++++++ arch/arm/probes/kprobes/test-arm.c | 16 ++++++++++------ 5 files changed, 33 insertions(+), 8 deletions(-)
arch/arm/include/asm/kprobes.h +0 -1
@@ -22,7 +22,6 @@#define __ARCH_WANT_KPROBES_INSN_SLOT#define MAX_INSN_SIZE 2 -#define MAX_STACK_SIZE 64/* 32 would probably be OK */ #define flush_insn_slot (p) do { } while (0)#define kretprobe_blacklist_size 0
arch/arm/include/asm/probes.h +12 -0
@@ -19,6 +19,8 @@#ifndef _ASM_PROBES_H#define _ASM_PROBES_H +#ifndef __ASSEMBLY__ +typedef u32 probes_opcode_t ;struct arch_probes_insn ;
@@ -41,4 +43,14 @@ struct arch_probes_insn {int stack_space; }; +#endif /* __ASSEMBLY__ */ + +/* +* We assume one instruction can consume at most 64 bytes stack, which is +* 'push {r0-r15}'. Instructions consume more or unknown stack space like +* 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe. +* Both kprobe and jprobe use this macro. +*/ +#define MAX_STACK_SIZE 64 +#endif
arch/arm/kernel/entry-armv.S +2 -1
@@ -31,6 +31,7 @@ #include "entry-header.S" #include <asm/entry-macro-multi.S> +#include <asm/probes.h> /* * Interrupt handling.
@@ -249,7 +250,7 @@ __und_svc: @ If a kprobe is about to simulate a "stmdb sp..." instruction, @ it obviously needs free stack space which then will belong to @ the saved context. - svc_entry 64 + svc_entry MAX_STACK_SIZE #else svc_entry #endif
arch/arm/probes/kprobes/core.c +9 -0
@@ -115,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)break ; } +/* +* Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes +* 'str r0, [sp, #-68]' should also be prohibited. +* See __und_svc. +*/ +if ((p->ainsn.stack_space <0 ) || + (p->ainsn.stack_space >MAX_STACK_SIZE )) +return -EINVAL ; +return 0 ; }
arch/arm/probes/kprobes/test-arm.c +10 -6
@@ -476,7 +476,8 @@ void kprobe_arm_test_cases(void) TEST_GROUP("Extra load/store instructions") TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") - TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]") + TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") + TEST_UNSUPPORTED( "streqh r14, [r13, r12]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strh r" ,2 ,VAL1 ,", [r" ,3 ,24 ,"], r" ,4 ,48 ,"" )
@@ -565,7 +566,8 @@ void kprobe_arm_test_cases(void)#if __LINUX_ARM_ARCH__ >=5 TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") - TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]") + TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") + TEST_UNSUPPORTED( "strccd r8, [r13, r12]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strd r" ,2 ,VAL1 ,", [r" ,5 ,24 ,"], r" ,4 ,48 ,"" )
@@ -638,13 +640,15 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ - TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \ + TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ - TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\ + TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]")\ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\TEST_P ("ldr" byte" r0, [r" ,0 ,24 ,", #-2]" ) \
@@ -668,12 +672,12 @@ void kprobe_arm_test_cases(void) LOAD_STORE("") TEST_P( "str pc, [r",0,0,", #15*4]") - TEST_R( "str pc, [sp, r",2,15*4,"]") + TEST_UNSUPPORTED( "str pc, [sp, r2]") TEST_BF( "ldr pc, [sp, #15*4]") TEST_BF_R("ldr pc, [sp, r",2,15*4,"]") TEST_P( "str sp, [r",0,0,", #13*4]") - TEST_R( "str sp, [sp, r",2,13*4,"]") + TEST_UNSUPPORTED( "str sp, [sp, r2]") TEST_BF( "ldr sp, [sp, #13*4]")TEST_BF_R ("ldr sp, [sp, r" ,2 ,13 *4 ,"]" )
Signature · 1 line
1.8.4
PATCH RESEND v15 5/7 ARM: kprobes: Add test cases for stack consuming instructions
In reply to Wang NanFrom: Jon Medhurst <[email protected]>
These have extra 'checker' functions associated with them so lets make sure those get covered by testing.
---
v1 -> v2:
- Move to arch/arm/probes/ .
--- arch/arm/probes/kprobes/test-arm.c | 17 +++++++++++++++-- arch/arm/probes/kprobes/test-thumb.c | 12 ++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-)
arch/arm/probes/kprobes/test-arm.c +15 -2
@@ -12,6 +12,7 @@#include <linux/module.h> #include <asm/system_info.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -478,6 +479,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") TEST_UNSUPPORTED( "streqh r14, [r13, r12]") + TEST_UNSUPPORTED( "streqh r14, [r12, r13]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strh r" ,2 ,VAL1 ,", [r" ,3 ,24 ,"], r" ,4 ,48 ,"" )
@@ -502,6 +504,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")
@@ -568,6 +573,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") TEST_UNSUPPORTED( "strccd r8, [r13, r12]") + TEST_UNSUPPORTED( "strccd r8, [r12, r13]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strd r" ,2 ,VAL1 ,", [r" ,5 ,24 ,"], r" ,4 ,48 ,"" )
@@ -591,6 +597,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")TEST_P ("ldrd r0, [r" ,0 ,24 ,", #-8]" )
@@ -639,16 +648,20 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ + TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\TEST_P ("ldr" byte" r0, [r" ,0 ,24 ,", #-2]" ) \
arch/arm/probes/kprobes/test-thumb.c +12 -0
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") + TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")
@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ + TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ + TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") SINGLE_STORE("b") SINGLE_STORE("h") SINGLE_STORE("") + TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") + TEST("str sp, [sp]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")
Signature · 1 line
1.8.4
PATCH v2 1/1 ARM: kprobes: Add test cases for stack consuming instructions
These have extra 'checker' functions associated with them so lets make sure those get covered by testing. As they may create uninitialised space on the stack we also update the test code to ensure such space is consistent between test runs. This is done by disabling interrupts in setup_test_context().
---
OK, so I lied in [1] when I said I won't be looking at the test failure for a few days, I had a sudden inspiration on how to fix things and the changes to test-core.c in this patch are the result. Rest of the patch is the same as the version posted in Wang Nan's v15 patch set [2]
With this change the kprobe test code passes on my TC2 with both ARM and Thumb kernels and both with and without optprobes forced using wait_for_kprobe_optimizer() hacks.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-December/309574.html
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-December/309399.html
arch/arm/probes/kprobes/test-arm.c | 17 +++++++++++++++-- arch/arm/probes/kprobes/test-core.c | 10 ++++++++++ arch/arm/probes/kprobes/test-thumb.c | 12 ++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-)
arch/arm/probes/kprobes/test-arm.c +15 -2
@@ -12,6 +12,7 @@#include <linux/module.h> #include <asm/system_info.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -478,6 +479,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") TEST_UNSUPPORTED( "streqh r14, [r13, r12]") + TEST_UNSUPPORTED( "streqh r14, [r12, r13]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strh r" ,2 ,VAL1 ,", [r" ,3 ,24 ,"], r" ,4 ,48 ,"" )
@@ -502,6 +504,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")
@@ -568,6 +573,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") TEST_UNSUPPORTED( "strccd r8, [r13, r12]") + TEST_UNSUPPORTED( "strccd r8, [r12, r13]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strd r" ,2 ,VAL1 ,", [r" ,5 ,24 ,"], r" ,4 ,48 ,"" )
@@ -591,6 +597,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")TEST_P ("ldrd r0, [r" ,0 ,24 ,", #-8]" )
@@ -639,16 +648,20 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ + TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\TEST_P ("ldr" byte" r0, [r" ,0 ,24 ,", #-2]" ) \
arch/arm/probes/kprobes/test-core.c +10 -0
@@ -1196,6 +1196,13 @@ static void setup_test_context(struct pt_regs *regs) regs->uregs[arg->reg] = (unsigned long )current_stack + arg->val; memory_needs_checking = true; +/* +* Test memory at an address below SP is in danger of +* being altered by an interrupt occurring and pushing +* data onto the stack. Disable interrupts to stop this. +*/ +if (arg->reg ==13 ) + regs->ARM_cpsr |=PSR_I_BIT ;break ; }case ARG_TYPE_MEM : {
@@ -1206,6 +1213,7 @@ static void setup_test_context(struct pt_regs *regs)default :break ; } + }struct test_probe {
@@ -1272,6 +1280,8 @@ test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack; +/* Enable interrupts in case setup_test_context diabled them */ + regs->ARM_cpsr &= ~PSR_I_BIT ; container_of(p, struct test_probe, kprobe)->hit = test_instance;return 0 ;
arch/arm/probes/kprobes/test-thumb.c +12 -0
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") + TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")
@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ + TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ + TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") SINGLE_STORE("b") SINGLE_STORE("h") SINGLE_STORE("") + TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") + TEST("str sp, [sp]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")
Signature · 1 line
2.1.3
PATCH v3 1/1 ARM: kprobes: Add test cases for stack consuming instructions
These have extra 'checker' functions associated with them so lets make sure those get covered by testing. As they may create uninitialised space on the stack we also update the test code to ensure such space is consistent between test runs. This is done by disabling interrupts in setup_test_context().
---
Sorry for the extra noise, sent this new version to correct whitespace and spelling errors in previous one.
arch/arm/probes/kprobes/test-arm.c | 17 +++++++++++++++-- arch/arm/probes/kprobes/test-core.c | 9 +++++++++ arch/arm/probes/kprobes/test-thumb.c | 12 ++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-)
arch/arm/probes/kprobes/test-arm.c +15 -2
@@ -12,6 +12,7 @@#include <linux/module.h> #include <asm/system_info.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -478,6 +479,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") TEST_UNSUPPORTED( "streqh r14, [r13, r12]") + TEST_UNSUPPORTED( "streqh r14, [r12, r13]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strh r" ,2 ,VAL1 ,", [r" ,3 ,24 ,"], r" ,4 ,48 ,"" )
@@ -502,6 +504,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")
@@ -568,6 +573,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") TEST_UNSUPPORTED( "strccd r8, [r13, r12]") + TEST_UNSUPPORTED( "strccd r8, [r12, r13]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strd r" ,2 ,VAL1 ,", [r" ,5 ,24 ,"], r" ,4 ,48 ,"" )
@@ -591,6 +597,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")TEST_P ("ldrd r0, [r" ,0 ,24 ,", #-8]" )
@@ -639,16 +648,20 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ + TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\TEST_P ("ldr" byte" r0, [r" ,0 ,24 ,", #-2]" ) \
arch/arm/probes/kprobes/test-core.c +9 -0
@@ -1196,6 +1196,13 @@ static void setup_test_context(struct pt_regs *regs) regs->uregs[arg->reg] = (unsigned long )current_stack + arg->val; memory_needs_checking = true; +/* +* Test memory at an address below SP is in danger of +* being altered by an interrupt occurring and pushing +* data onto the stack. Disable interrupts to stop this. +*/ +if (arg->reg ==13 ) + regs->ARM_cpsr |=PSR_I_BIT ;break ; }case ARG_TYPE_MEM : {
@@ -1272,6 +1279,8 @@ test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack; +/* Enable interrupts in case setup_test_context disabled them */ + regs->ARM_cpsr &= ~PSR_I_BIT ; container_of(p, struct test_probe, kprobe)->hit = test_instance;return 0 ;
arch/arm/probes/kprobes/test-thumb.c +12 -0
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h"
@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") + TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")
@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ + TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ + TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") SINGLE_STORE("b") SINGLE_STORE("h") SINGLE_STORE("") + TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") + TEST("str sp, [sp]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")
Signature · 1 line
2.1.3
Re: [PATCH v3] ARM: kprobes: Add test cases for stack consuming instructions
Hi Tixy,
I experienced another FAIL during test:
[11567.220477] Miscellaneous instructions [11567.265397] --------------------------------------------------------- [11567.342626] mrs r0, cpsr @ e10f0000 [11568.612656] FAIL: registers differ [11568.653414] FAIL: Test mrs r0, cpsr [11568.695210] FAIL: Scenario 5 [11568.729709] initial_regs: [11568.761083] r0 21522152 | r1 21522052 | r2 21522352 | r3 21522252 [11568.838301] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11568.915526] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11568.992748] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f590 [11569.069969] cpsr 58050013 [11569.101336] expected_regs: [11569.133750] r0 58050013 | r1 21522052 | r2 21522352 | r3 21522252 [11569.210975] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.288197] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.365417] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.442634] cpsr 58050013 [11569.474010] result_regs: [11569.504337] r0 58050113 | r1 21522052 | r2 21522352 | r3 21522252 <--- see R0 in this line [11569.581556] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.658776] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.736000] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.813222] cpsr 58050013 [11569.844593] mrspl r7, cpsr @ 510f7000 [11571.842652] mrs r14, cpsr @ e10fe000
The failure is raise when testing in "mrs r0, cpsr". The added bit is PSR_A_BIT, which should be ignored.
So looks like this is also a problem in your test framework. If you don't have enough time, you can give me some hints to deal with it.
Quoted 161 lines · Jon Medhurst (Tixy)
These have extra 'checker' functions associated with them so lets make sure those get covered by testing. As they may create uninitialised space on the stack we also update the test code to ensure such space is consistent between test runs. This is done by disabling interrupts in
setup_test_context().Signed-off-by Jon Medhurst <[email protected]>---
Sorry for the extra noise, sent this new version to correct whitespace and spelling errors in previous one.
arch/arm/probes/kprobes/test-arm.c | 17 +++++++++++++++-- arch/arm/probes/kprobes/test-core.c | 9 +++++++++ arch/arm/probes/kprobes/test-thumb.c | 12 ++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-)arch/arm/probes/kprobes/test-arm.c +15
-2@@ -12,6 +12,7 @@#include <linux/module.h> #include <asm/system_info.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h" @@ -478,6 +479,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") TEST_UNSUPPORTED( "streqh r14, [r13, r12]") + TEST_UNSUPPORTED( "streqh r14, [r12, r13]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strh r" ,2 ,VAL1 ,", [r" ,3 ,24 ,"], r" ,4 ,48 ,"" )@@ -502,6 +504,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")@@ -568,6 +573,7 @@ void kprobe_arm_test_cases(void) TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") TEST_UNSUPPORTED( "strccd r8, [r13, r12]") + TEST_UNSUPPORTED( "strccd r8, [r12, r13]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")TEST_RPR ("strd r" ,2 ,VAL1 ,", [r" ,5 ,24 ,"], r" ,4 ,48 ,"" )@@ -591,6 +597,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")TEST_P ("ldrd r0, [r" ,0 ,24 ,", #-8]" )@@ -639,16 +648,20 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ + TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ - TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\TEST_P ("ldr" byte" r0, [r" ,0 ,24 ,", #-2]" ) \arch/arm/probes/kprobes/test-core.c +9
-0@@ -1196,6 +1196,13 @@ static void setup_test_context(struct pt_regs *regs) regs->uregs[arg->reg] = (unsigned long )current_stack + arg->val; memory_needs_checking = true; +/* +* Test memory at an address below SP is in danger of +* being altered by an interrupt occurring and pushing +* data onto the stack. Disable interrupts to stop this. +*/ +if (arg->reg ==13 ) + regs->ARM_cpsr |=PSR_I_BIT ;break ; }case ARG_TYPE_MEM : {@@ -1272,6 +1279,8 @@ test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack; +/* Enable interrupts in case setup_test_context disabled them */ + regs->ARM_cpsr &= ~PSR_I_BIT ; container_of(p, struct test_probe, kprobe)->hit = test_instance;return 0 ;arch/arm/probes/kprobes/test-thumb.c +12
-0@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <asm/opcodes.h> +#include <asm/probes.h> #include "test-core.h" @@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") + TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ + TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ + TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") SINGLE_STORE("b") SINGLE_STORE("h") SINGLE_STORE("") + TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") + TEST("str sp, [sp]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")
Re: [PATCH v3] ARM: kprobes: Add test cases for stack consuming instructions
Quoted 31 lines · Wang Nan
Hi Tixy,
I experienced another FAIL during test:
[11567.220477] Miscellaneous instructions [11567.265397] --------------------------------------------------------- [11567.342626] mrs r0, cpsr @ e10f0000 [11568.612656] FAIL: registers differ [11568.653414] FAIL: Test mrs r0, cpsr [11568.695210] FAIL: Scenario 5 [11568.729709] initial_regs: [11568.761083] r0 21522152 | r1 21522052 | r2 21522352 | r3 21522252 [11568.838301] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11568.915526] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11568.992748] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f590 [11569.069969] cpsr 58050013 [11569.101336] expected_regs: [11569.133750] r0 58050013 | r1 21522052 | r2 21522352 | r3 21522252 [11569.210975] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.288197] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.365417] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.442634] cpsr 58050013 [11569.474010] result_regs: [11569.504337] r0 58050113 | r1 21522052 | r2 21522352 | r3 21522252 <--- see R0 in this line [11569.581556] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.658776] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.736000] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.813222] cpsr 58050013 [11569.844593] mrspl r7, cpsr @ 510f7000 [11571.842652] mrs r14, cpsr @ e10fe000
Quoted 5 lines
The failure is raise when testing in "mrs r0, cpsr". The added bit is
PSR_A_BIT, which should be ignored.So looks like this is also a problem in your test framework. If you don't have enough time, you can give me some hints to deal with it.
The problem is that the A bit can change randomly when interrupts or reschedules happen (I'm not sure it should, and it may be a bug). For the purposes of this test code, we can't disable interrupts and scheduling around all the iterations of a test case, because inserting and removing probes requires them to be enabled. So we need a method of ignoring bits in cpsr, how about the following patch...
----------------------------------------------------------------------------
From: Jon Medhurst <[email protected]>
Subject: [PATCH] ARM: kprobes: Fix unreliable MRS instruction tests
For the instruction 'mrs Rn, cpsr' the resulting value of Rn can vary due to external factors we can't control. So get the test code to mask out these indeterminate bits.
--- arch/arm/probes/kprobes/test-arm.c | 6 +++--- arch/arm/probes/kprobes/test-core.c | 19 ++++++++++--------- arch/arm/probes/kprobes/test-core.h | 33 ++++++++++++++++++++++++++++----- arch/arm/probes/kprobes/test-thumb.c | 4 ++-- 4 files changed, 43 insertions(+), 19 deletions(-)
arch/arm/probes/kprobes/test-arm.c +3 -3
@@ -204,9 +204,9 @@ void kprobe_arm_test_cases(void)#endif TEST_GROUP("Miscellaneous instructions") - TEST("mrs r0, cpsr") - TEST("mrspl r7, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") TEST_UNSUPPORTED("mrs r0, spsr")TEST_UNSUPPORTED ("mrs lr, spsr" )
arch/arm/probes/kprobes/test-core.c +10 -9
@@ -1056,15 +1056,6 @@ static int test_case_run_count;static bool test_case_is_thumb;static int test_instance; -/* -* We ignore the state of the imprecise abort disable flag (CPSR.A) because this -* can change randomly as the kernel doesn't take care to preserve or initialise -* this across context switches. Also, with Security Extentions, the flag may -* not be under control of the kernel; for this reason we ignore the state of -* the FIQ disable flag CPSR.F as well. -*/ -#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) -static unsigned long test_check_cc (int cc,unsigned long cpsr) {int ret =arm_check_condition (cc <<28 , cpsr);
@@ -1271,11 +1262,21 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)static int __kprobes test_after_pre_handler (struct kprobe *p,struct pt_regs *regs) { +struct test_arg *args; + if (container_of(p, struct test_probe, kprobe)->hit == test_instance)return 0 ;/* Already run for this test instance */ result_regs = *regs; + +/* Mask out results which are indeterminate */ result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS ; +for (args = current_args; args[0 ].type !=ARG_TYPE_END ; ++args) +if (args[0 ].type ==ARG_TYPE_REG_MASKED ) { +struct test_arg_regptr *arg = + (struct test_arg_regptr *)args; + result_regs.uregs[arg->reg] &= arg->val; + }/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack;
arch/arm/probes/kprobes/test-core.h +28 -5
@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position;* */ -#define ARG_TYPE_END 0 -#define ARG_TYPE_REG 1 -#define ARG_TYPE_PTR 2 -#define ARG_TYPE_MEM 3 +#define ARG_TYPE_END 0 +#define ARG_TYPE_REG 1 +#define ARG_TYPE_PTR 2 +#define ARG_TYPE_MEM 3 +#define ARG_TYPE_REG_MASKED 4#define ARG_FLAG_UNSUPPORTED 0x01#define ARG_FLAG_SUPPORTED 0x02
@@ -61,7 +62,7 @@ struct test_arg { };struct test_arg_regptr { -u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR */ +u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */ u8 reg;u8 _padding[2 ];u32 val;
@@ -138,6 +139,12 @@ struct test_arg_end {".short 0 \n\t" \ ".word "#val" \n\t" +#define TEST_ARG_REG_MASKED (reg, val) \ + ".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \ + ".byte "#reg" \n\t" \ + ".short 0 \n\t" \ + ".word "#val" \n\t" +#define TEST_ARG_END (flags) \ ".byte "__stringify(ARG_TYPE_END)" \n\t" \ ".byte "TEST_ISA flags" \n\t" \
@@ -395,6 +402,22 @@ struct test_arg_end {" " codex" \n\t" \ TESTCASE_END +#define TEST_RMASKED (code1, reg, mask, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG_MASKED(reg, mask) \ + TEST_ARG_END("") \ + TEST_INSTRUCTION(code1 #reg code2) \ + TESTCASE_END + +/* +* We ignore the state of the imprecise abort disable flag (CPSR.A) because this +* can change randomly as the kernel doesn't take care to preserve or initialise +* this across context switches. Also, with Security Extensions, the flag may +* not be under control of the kernel; for this reason we ignore the state of +* the FIQ disable flag CPSR.F as well. +*/ +#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) +/* * Macros for defining space directives spread over multiple lines.
arch/arm/probes/kprobes/test-thumb.c +2 -2
@@ -778,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, TEST_UNSUPPORTED("subs pc, lr, #4") - TEST("mrs r0, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr")TEST_UNSUPPORTED ("mrs r0, spsr" )
Signature · 1 line
2.1.3
Re: [PATCH v3] ARM: kprobes: Add test cases for stack consuming instructions
Quoted 192 lines · Jon Medhurst (Tixy)
Quoted 31 lines · Wang Nan
Hi Tixy,
I experienced another FAIL during test:
[11567.220477] Miscellaneous instructions [11567.265397] --------------------------------------------------------- [11567.342626] mrs r0, cpsr @ e10f0000 [11568.612656] FAIL: registers differ [11568.653414] FAIL: Test mrs r0, cpsr [11568.695210] FAIL: Scenario 5 [11568.729709] initial_regs: [11568.761083] r0 21522152 | r1 21522052 | r2 21522352 | r3 21522252 [11568.838301] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11568.915526] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11568.992748] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f590 [11569.069969] cpsr 58050013 [11569.101336] expected_regs: [11569.133750] r0 58050013 | r1 21522052 | r2 21522352 | r3 21522252 [11569.210975] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.288197] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.365417] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.442634] cpsr 58050013 [11569.474010] result_regs: [11569.504337] r0 58050113 | r1 21522052 | r2 21522352 | r3 21522252 <--- see R0 in this line [11569.581556] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.658776] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.736000] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.813222] cpsr 58050013 [11569.844593] mrspl r7, cpsr @ 510f7000 [11571.842652] mrs r14, cpsr @ e10fe000Quoted 5 lines
The failure is raise when testing in "mrs r0, cpsr". The added bit is
PSR_A_BIT, which should be ignored.So looks like this is also a problem in your test framework. If you don't have enough time, you can give me some hints to deal with it.
The problem is that the A bit can change randomly when interrupts or reschedules happen (I'm not sure it should, and it may be a bug). For the purposes of this test code, we can't disable interrupts and scheduling around all the iterations of a test case, because inserting and removing probes requires them to be enabled. So we need a method of ignoring bits in cpsr, how about the following patch...
----------------------------------------------------------------------------
From: Jon Medhurst <[email protected]>
Subject: [PATCH] ARM: kprobes: Fix unreliable MRS instruction testsFor the instruction 'mrs Rn, cpsr' the resulting value of Rn can vary due to external factors we can't control. So get the test code to mask out these indeterminate bits.
Signed-off-by Jon Medhurst <[email protected]>--- arch/arm/probes/kprobes/test-arm.c | 6 +++--- arch/arm/probes/kprobes/test-core.c | 19 ++++++++++--------- arch/arm/probes/kprobes/test-core.h | 33 ++++++++++++++++++++++++++++----- arch/arm/probes/kprobes/test-thumb.c | 4 ++-- 4 files changed, 43 insertions(+), 19 deletions(-)arch/arm/probes/kprobes/test-arm.c +3
-3@@ -204,9 +204,9 @@ void kprobe_arm_test_cases(void)#endif TEST_GROUP("Miscellaneous instructions") - TEST("mrs r0, cpsr") - TEST("mrspl r7, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") TEST_UNSUPPORTED("mrs r0, spsr")TEST_UNSUPPORTED ("mrs lr, spsr" )arch/arm/probes/kprobes/test-core.c +10
-9@@ -1056,15 +1056,6 @@ static int test_case_run_count;static bool test_case_is_thumb;static int test_instance; -/* -* We ignore the state of the imprecise abort disable flag (CPSR.A) because this -* can change randomly as the kernel doesn't take care to preserve or initialise -* this across context switches. Also, with Security Extentions, the flag may -* not be under control of the kernel; for this reason we ignore the state of -* the FIQ disable flag CPSR.F as well. -*/ -#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) -static unsigned long test_check_cc (int cc,unsigned long cpsr) {int ret =arm_check_condition (cc <<28 , cpsr);@@ -1271,11 +1262,21 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)static int __kprobes test_after_pre_handler (struct kprobe *p,struct pt_regs *regs) { +struct test_arg *args; + if (container_of(p, struct test_probe, kprobe)->hit == test_instance)return 0 ;/* Already run for this test instance */ result_regs = *regs; + +/* Mask out results which are indeterminate */ result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS ; +for (args = current_args; args[0 ].type !=ARG_TYPE_END ; ++args) +if (args[0 ].type ==ARG_TYPE_REG_MASKED ) { +struct test_arg_regptr *arg = + (struct test_arg_regptr *)args; + result_regs.uregs[arg->reg] &= arg->val; + }/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack;arch/arm/probes/kprobes/test-core.h +28
-5@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position;* */ -#define ARG_TYPE_END 0 -#define ARG_TYPE_REG 1 -#define ARG_TYPE_PTR 2 -#define ARG_TYPE_MEM 3 +#define ARG_TYPE_END 0 +#define ARG_TYPE_REG 1 +#define ARG_TYPE_PTR 2 +#define ARG_TYPE_MEM 3 +#define ARG_TYPE_REG_MASKED 4#define ARG_FLAG_UNSUPPORTED 0x01#define ARG_FLAG_SUPPORTED 0x02@@ -61,7 +62,7 @@ struct test_arg { };struct test_arg_regptr { -u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR */ +u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */ u8 reg;u8 _padding[2 ];u32 val;@@ -138,6 +139,12 @@ struct test_arg_end {".short 0 \n\t" \ ".word "#val" \n\t" +#define TEST_ARG_REG_MASKED (reg, val) \ + ".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \ + ".byte "#reg" \n\t" \ + ".short 0 \n\t" \ + ".word "#val" \n\t" +#define TEST_ARG_END (flags) \ ".byte "__stringify(ARG_TYPE_END)" \n\t" \ ".byte "TEST_ISA flags" \n\t" \@@ -395,6 +402,22 @@ struct test_arg_end {" " codex" \n\t" \ TESTCASE_END +#define TEST_RMASKED (code1, reg, mask, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG_MASKED(reg, mask) \ + TEST_ARG_END("") \ + TEST_INSTRUCTION(code1 #reg code2) \ + TESTCASE_END + +/* +* We ignore the state of the imprecise abort disable flag (CPSR.A) because this +* can change randomly as the kernel doesn't take care to preserve or initialise +* this across context switches. Also, with Security Extensions, the flag may +* not be under control of the kernel; for this reason we ignore the state of +* the FIQ disable flag CPSR.F as well. +*/ +#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) +/* * Macros for defining space directives spread over multiple lines. arch/arm/probes/kprobes/test-thumb.c +0
-0
arch/arm/probes/kprobes/test-thumb.c CONDITION_INSTRUCTIONS(22, · line 785
Quoted 10 lines
arch/arm/probes/kprobes/test-thumb.c +2
-2@@ -778,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, TEST_UNSUPPORTED("subs pc, lr, #4") - TEST("mrs r0, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr")TEST_UNSUPPORTED ("mrs r0, spsr" )
Well, I'm just working on a patch which introducing a TEST_INTOFF and disable interrupts for "MRS" testcase. Do you think it is inappropriate? I'll use your patch test for a night in my hardware, and will let you know the result tomorrow.
Thank you!
Re: [PATCH v3] ARM: kprobes: Add test cases for stack consuming instructions
On Wed, 2014-12-10 at 21:18 +0800, Wang Nan wrote:
[...]
Quoted 2 lines
Well, I'm just working on a patch which introducing a
TEST_INTOFFand disable interrupts for "MRS" testcase. Do you think it is inappropriate?
That's what I started to do, implementing in a similar way to DONT_TEST_IN_ITBLOCK, and thought the same ints off feature could be used for the stack consuming instructions checks as well.
Then I realised that for the MRS case it's no use turning ints off for a single iteration of a test, because the next iteration could see different results, so that would mean turning interrupts off for all iterations, which we can't do.
Also, the FIQ flag may not be under our control if Linux isn't running in secure mode, and I was worried that in such cases we could see the value of the flag change if secure mode code chose to do so. (Though perhaps non-secure mode will always read FIQ flag as zero in such a case?)
So in the end I thought the only robust way of writing the tests would be to ignore the values of the A and F flags.
Signature · 1 line
Tixy
Re: [PATCH v3] ARM: kprobes: Add test cases for stack consuming instructions
In reply to Wang NanQuoted 208 lines · Wang Nan
Quoted 192 lines · Jon Medhurst (Tixy)
Quoted 31 lines · Wang Nan
Hi Tixy,
I experienced another FAIL during test:
[11567.220477] Miscellaneous instructions [11567.265397] --------------------------------------------------------- [11567.342626] mrs r0, cpsr @ e10f0000 [11568.612656] FAIL: registers differ [11568.653414] FAIL: Test mrs r0, cpsr [11568.695210] FAIL: Scenario 5 [11568.729709] initial_regs: [11568.761083] r0 21522152 | r1 21522052 | r2 21522352 | r3 21522252 [11568.838301] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11568.915526] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11568.992748] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f590 [11569.069969] cpsr 58050013 [11569.101336] expected_regs: [11569.133750] r0 58050013 | r1 21522052 | r2 21522352 | r3 21522252 [11569.210975] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.288197] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.365417] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.442634] cpsr 58050013 [11569.474010] result_regs: [11569.504337] r0 58050113 | r1 21522052 | r2 21522352 | r3 21522252 <--- see R0 in this line [11569.581556] r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 [11569.658776] r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 [11569.736000] r12 21522d52 | sp ed343cf0 | lr 21522f52 | pc bf11f594 [11569.813222] cpsr 58050013 [11569.844593] mrspl r7, cpsr @ 510f7000 [11571.842652] mrs r14, cpsr @ e10fe000Quoted 5 lines
The failure is raise when testing in "mrs r0, cpsr". The added bit is
PSR_A_BIT, which should be ignored.So looks like this is also a problem in your test framework. If you don't have enough time, you can give me some hints to deal with it.
The problem is that the A bit can change randomly when interrupts or reschedules happen (I'm not sure it should, and it may be a bug). For the purposes of this test code, we can't disable interrupts and scheduling around all the iterations of a test case, because inserting and removing probes requires them to be enabled. So we need a method of ignoring bits in cpsr, how about the following patch...
----------------------------------------------------------------------------
From: Jon Medhurst <[email protected]>
Subject: [PATCH] ARM: kprobes: Fix unreliable MRS instruction testsFor the instruction 'mrs Rn, cpsr' the resulting value of Rn can vary due to external factors we can't control. So get the test code to mask out these indeterminate bits.
Signed-off-by Jon Medhurst <[email protected]>--- arch/arm/probes/kprobes/test-arm.c | 6 +++--- arch/arm/probes/kprobes/test-core.c | 19 ++++++++++--------- arch/arm/probes/kprobes/test-core.h | 33 ++++++++++++++++++++++++++++----- arch/arm/probes/kprobes/test-thumb.c | 4 ++-- 4 files changed, 43 insertions(+), 19 deletions(-)arch/arm/probes/kprobes/test-arm.c +3
-3@@ -204,9 +204,9 @@ void kprobe_arm_test_cases(void)#endif TEST_GROUP("Miscellaneous instructions") - TEST("mrs r0, cpsr") - TEST("mrspl r7, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") TEST_UNSUPPORTED("mrs r0, spsr")TEST_UNSUPPORTED ("mrs lr, spsr" )arch/arm/probes/kprobes/test-core.c +10
-9@@ -1056,15 +1056,6 @@ static int test_case_run_count;static bool test_case_is_thumb;static int test_instance; -/* -* We ignore the state of the imprecise abort disable flag (CPSR.A) because this -* can change randomly as the kernel doesn't take care to preserve or initialise -* this across context switches. Also, with Security Extentions, the flag may -* not be under control of the kernel; for this reason we ignore the state of -* the FIQ disable flag CPSR.F as well. -*/ -#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) -static unsigned long test_check_cc (int cc,unsigned long cpsr) {int ret =arm_check_condition (cc <<28 , cpsr);@@ -1271,11 +1262,21 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)static int __kprobes test_after_pre_handler (struct kprobe *p,struct pt_regs *regs) { +struct test_arg *args; + if (container_of(p, struct test_probe, kprobe)->hit == test_instance)return 0 ;/* Already run for this test instance */ result_regs = *regs; + +/* Mask out results which are indeterminate */ result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS ; +for (args = current_args; args[0 ].type !=ARG_TYPE_END ; ++args) +if (args[0 ].type ==ARG_TYPE_REG_MASKED ) { +struct test_arg_regptr *arg = + (struct test_arg_regptr *)args; + result_regs.uregs[arg->reg] &= arg->val; + }/* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long )current_stack;arch/arm/probes/kprobes/test-core.h +28
-5@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position;* */ -#define ARG_TYPE_END 0 -#define ARG_TYPE_REG 1 -#define ARG_TYPE_PTR 2 -#define ARG_TYPE_MEM 3 +#define ARG_TYPE_END 0 +#define ARG_TYPE_REG 1 +#define ARG_TYPE_PTR 2 +#define ARG_TYPE_MEM 3 +#define ARG_TYPE_REG_MASKED 4#define ARG_FLAG_UNSUPPORTED 0x01#define ARG_FLAG_SUPPORTED 0x02@@ -61,7 +62,7 @@ struct test_arg { };struct test_arg_regptr { -u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR */ +u8 type;/* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */ u8 reg;u8 _padding[2 ];u32 val;@@ -138,6 +139,12 @@ struct test_arg_end {".short 0 \n\t" \ ".word "#val" \n\t" +#define TEST_ARG_REG_MASKED (reg, val) \ + ".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \ + ".byte "#reg" \n\t" \ + ".short 0 \n\t" \ + ".word "#val" \n\t" +#define TEST_ARG_END (flags) \ ".byte "__stringify(ARG_TYPE_END)" \n\t" \ ".byte "TEST_ISA flags" \n\t" \@@ -395,6 +402,22 @@ struct test_arg_end {" " codex" \n\t" \ TESTCASE_END +#define TEST_RMASKED (code1, reg, mask, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG_MASKED(reg, mask) \ + TEST_ARG_END("") \ + TEST_INSTRUCTION(code1 #reg code2) \ + TESTCASE_END + +/* +* We ignore the state of the imprecise abort disable flag (CPSR.A) because this +* can change randomly as the kernel doesn't take care to preserve or initialise +* this across context switches. Also, with Security Extensions, the flag may +* not be under control of the kernel; for this reason we ignore the state of +* the FIQ disable flag CPSR.F as well. +*/ +#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) +/* * Macros for defining space directives spread over multiple lines. arch/arm/probes/kprobes/test-thumb.c +0
-0arch/arm/probes/kprobes/test-thumb.c CONDITION_INSTRUCTIONS(22, · line 785
Quoted 10 lines
arch/arm/probes/kprobes/test-thumb.c +2
-2@@ -778,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, TEST_UNSUPPORTED("subs pc, lr, #4") - TEST("mrs r0, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr")TEST_UNSUPPORTED ("mrs r0, spsr" )Well, I'm just working on a patch which introducing a
TEST_INTOFFand disable interrupts for "MRS" testcase. Do you think it is inappropriate? I'll use your patch test for a night in my hardware, and will let you know the result tomorrow.
Quoted 2 lines
Thank you!
Hi Tixy,
I'd like to let you know that I have tested your v3 patch in an ARM cortex A15 board for 8 hours and nothing bad happened. I'll post a v16 patch series to merge your patch.
Thank you!
Quoted 6 lines
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH RESEND v15 6/7 kprobes: Pass the original kprobe for preparing optimized kprobe
In reply to Wang NanFrom: Masami Hiramatsu <[email protected]>
Pass the original kprobe for preparing an optimized kprobe arch-dep part, since for some architecture (e.g. ARM32) requires the information in original kprobe.
--- arch/x86/kernel/kprobes/opt.c | 3 ++- include/linux/kprobes.h | 3 ++- kernel/kprobes.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-)
arch/x86/kernel/kprobes/opt.c +2 -1
@@ -320,7 +320,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)* Target instructions MUST be relocatable (checked inside) * This is called when new aggr(opt)probe is allocated or reused. */ -int arch_prepare_optimized_kprobe (struct optimized_kprobe *op) +int arch_prepare_optimized_kprobe (struct optimized_kprobe *op, +struct kprobe *__unused) {u8 *buf;int ret;
include/linux/kprobes.h +2 -1
@@ -308,7 +308,8 @@ struct optimized_kprobe {/* Architecture dependent functions for direct jump optimization */ extern int arch_prepared_optinsn (struct arch_optimized_insn *optinsn);extern int arch_check_optimized_kprobe (struct optimized_kprobe *op); -extern int arch_prepare_optimized_kprobe (struct optimized_kprobe *op); +extern int arch_prepare_optimized_kprobe (struct optimized_kprobe *op, +struct kprobe *orig);extern void arch_remove_optimized_kprobe (struct optimized_kprobe *op);extern void arch_optimize_kprobes (struct list_head *oplist); extern void arch_unoptimize_kprobes(struct list_head *oplist,
kernel/kprobes.c +2 -2
@@ -717,7 +717,7 @@ static void prepare_optimized_kprobe(struct kprobe *p)struct optimized_kprobe *op; op = container_of(p, struct optimized_kprobe, kp); -arch_prepare_optimized_kprobe (op); +arch_prepare_optimized_kprobe (op, p); }/* Allocate new optimized_kprobe and try to prepare optimized instructions */
@@ -731,7 +731,7 @@ static struct kprobe *alloc_aggr_kprobe(struct kprobe *p)INIT_LIST_HEAD (&op->list); op->kp.addr = p->addr; -arch_prepare_optimized_kprobe (op); +arch_prepare_optimized_kprobe (op, p);return &op->kp; }
Signature · 1 line
1.8.4
Re: [RESEND][PATCH v15 6/7] kprobes: Pass the original kprobe for preparing optimized kprobe
Hi Masami Hiramatsu
How should this patch find its way into the mainline? Is it OK to submit this as part of the ARM kprobe changes (which presumably will go in via Russell's tree)?
Signature · 1 line
Tixy
Quoted 64 lines · Wang Nan
From: Masami Hiramatsu <[email protected]>
Pass the original kprobe for preparing an optimized kprobe arch-dep part, since for some architecture (e.g. ARM32) requires the information in original kprobe.
Signed-off-by Masami Hiramatsu <[email protected]>Signed-off-by Wang Nan <[email protected]>--- arch/x86/kernel/kprobes/opt.c | 3 ++- include/linux/kprobes.h | 3 ++- kernel/kprobes.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-)arch/x86/kernel/kprobes/opt.c +2
-1@@ -320,7 +320,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)* Target instructions MUST be relocatable (checked inside) * This is called when new aggr(opt)probe is allocated or reused. */ -int arch_prepare_optimized_kprobe (struct optimized_kprobe *op) +int arch_prepare_optimized_kprobe (struct optimized_kprobe *op, +struct kprobe *__unused) {u8 *buf;int ret;include/linux/kprobes.h +2
-1@@ -308,7 +308,8 @@ struct optimized_kprobe {/* Architecture dependent functions for direct jump optimization */ extern int arch_prepared_optinsn (struct arch_optimized_insn *optinsn);extern int arch_check_optimized_kprobe (struct optimized_kprobe *op); -extern int arch_prepare_optimized_kprobe (struct optimized_kprobe *op); +extern int arch_prepare_optimized_kprobe (struct optimized_kprobe *op, +struct kprobe *orig);extern void arch_remove_optimized_kprobe (struct optimized_kprobe *op);extern void arch_optimize_kprobes (struct list_head *oplist); extern void arch_unoptimize_kprobes(struct list_head *oplist,kernel/kprobes.c +2
-2@@ -717,7 +717,7 @@ static void prepare_optimized_kprobe(struct kprobe *p)struct optimized_kprobe *op; op = container_of(p, struct optimized_kprobe, kp); -arch_prepare_optimized_kprobe (op); +arch_prepare_optimized_kprobe (op, p); }/* Allocate new optimized_kprobe and try to prepare optimized instructions */ @@ -731,7 +731,7 @@ static struct kprobe *alloc_aggr_kprobe(struct kprobe *p)INIT_LIST_HEAD (&op->list); op->kp.addr = p->addr; -arch_prepare_optimized_kprobe (op); +arch_prepare_optimized_kprobe (op, p);return &op->kp; }
PATCH RESEND v15 7/7 ARM: kprobes: enable OPTPROBES for ARM 32
In reply to Wang NanThis patch introduce kprobeopt for ARM 32.
Limitations:
- Currently only kernel compiled with ARM ISA is supported.
- Offset between probe point and optinsn slot must not larger than 32MiB. Masami Hiramatsu suggests replacing 2 words, it will make things complex. Futher patch can make such optimization.
Kprobe opt on ARM is relatively simpler than kprobe opt on x86 because ARM instruction is always 4 bytes aligned and 4 bytes long. This patch replace probed instruction by a 'b', branch to trampoline code and then calls optimized_callback(). optimized_callback() calls opt_pre_handler() to execute kprobe handler. It also emulate/simulate replaced instruction.
When unregistering kprobe, the deferred manner of unoptimizer may leave branch instruction before optimizer is called. Different from x86_64, which only copy the probed insn after optprobe_template_end and reexecute them, this patch call singlestep to emulate/simulate the insn directly. Futher patch can optimize this behavior.
---
v1 -> v2:
- Improvement: if replaced instruction is conditional, generate a conditional branch instruction for it;
- Introduces RELATIVEJUMP_OPCODES due to ARM kprobe_opcode_t is 4 bytes;
- Removes size field in struct arch_optimized_insn;
- Use arm_gen_branch() to generate branch instruction;
- Remove all recover logic: ARM doesn't use tail buffer, no need recover replaced instructions like x86;
- Remove incorrect CONFIG_THUMB checking;
- can_optimize() always returns true if address is well aligned;
- Improve optimized_callback: using opt_pre_handler();
- Bugfix: correct range checking code and improve comments;
- Fix commit message.
v2 -> v3:
- Rename RELATIVEJUMP_OPCODES to MAX_COPIED_INSNS;
- Remove unneeded checking:
arch_check_optimized_kprobe(), can_optimize();
- Add missing flush_icache_range() in arch_prepare_optimized_kprobe();
- Remove unneeded 'return;'.
v3 -> v4:
- Use __mem_to_opcode_arm() to translate copied_insn to ensure it works in big endian kernel;
- Replace 'nop' placeholder in trampoline code template with '.long 0' to avoid confusion: reader may regard 'nop' as an instruction, but it is value in fact.
v4 -> v5:
- Don't optimize stack store operations.
- Introduce prepared field to arch_optimized_insn to indicate whether it is prepared. Similar to size field with x86. See v1 -> v2.
v5 -> v6:
- Dynamically reserve stack according to instruction.
- Rename: kprobes-opt.c -> kprobes-opt-arm.c.
- Set op->optinsn.insn after all works are done.
v6 -> v7:
- Using checker to check stack consumption.
v7 -> v8:
- Small code adjustments.
v8 -> v9:
- Utilize original kprobe passed to arch_prepare_optimized_kprobe() to avoid copy ainsn twice.
- A bug in arch_prepare_optimized_kprobe() is found and fixed.
v9 -> v10:
- Commit message improvements.
v10 -> v11:
- Move to arch/arm/probes/, insn.h is moved to arch/arm/include/asm.
- Code cleanup.
- Bugfix based on Tixy's test result:
- Trampoline deal with ARM -> Thumb transision instructions and AEABI stack alignment requirement correctly.
- Trampoline code buffer should start at 4 byte aligned address. We enforces it in this series by using macro to wrap 'code' var.
v11 -> v12:
- Remove trampoline code stack trick and use r4 to save original stack.
- Remove trampoline code buffer alignment trick.
- Names of files are changed.
v12 -> v13:
- Assume stack always aligned by 4-bytes in any case.
- Comments update.
v13 -> v14:
- Use stop_machine to wrap arch_optimize_kprobes to avoid a racing.
v14 -> v15:
- In v14, stop_machine() wraps a coarse-grained piece of code which makes things complex than it should be. In this version, kprobes_remove_breakpoint() is extracted, core.c and opt-arm.c use it to replace breakpoint to valid instruction. stop_machine() used inside in kprobes_remove_breakpoint().
---
arch/arm/Kconfig | 1 +
arch/arm/{kernel => include/asm}/insn.h | 0
arch/arm/include/asm/kprobes.h | 29 +++
arch/arm/kernel/Makefile | 2 +-
arch/arm/kernel/ftrace.c | 3 +-
arch/arm/kernel/jump_label.c | 3 +-
arch/arm/probes/kprobes/Makefile | 1 +
arch/arm/probes/kprobes/core.c | 26 ++-
arch/arm/probes/kprobes/core.h | 2 +
arch/arm/probes/kprobes/opt-arm.c | 317 ++++++++++++++++++++++++++++++++
10 files changed, 372 insertions(+), 12 deletions(-)
rename arch/arm/{kernel => include/asm}/insn.h (100%)
create mode 100644 arch/arm/probes/kprobes/opt-arm.carch/arm/Kconfig +1 -0
@@ -59,6 +59,7 @@ config ARM select HAVE_MEMBLOCK select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP
arch/arm/include/asm/insn.h renamed from arch/arm/kernel/insn.h +0 -0
arch/arm/include/asm/kprobes.h +29 -0
@@ -50,5 +50,34 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +/* optinsn template addresses */ +extern __visible kprobe_opcode_t optprobe_template_entry; +extern __visible kprobe_opcode_t optprobe_template_val; +extern __visible kprobe_opcode_t optprobe_template_call; +extern __visible kprobe_opcode_t optprobe_template_end; +extern __visible kprobe_opcode_t optprobe_template_sub_sp; +extern __visible kprobe_opcode_t optprobe_template_add_sp; + +#define MAX_OPTIMIZED_LENGTH 4 +#define MAX_OPTINSN_SIZE \ + ((unsigned long)&optprobe_template_end - \ + (unsigned long)&optprobe_template_entry) +#define RELATIVEJUMP_SIZE 4 + +struct arch_optimized_insn { +/* +* copy of the original instructions. +* Different from x86, ARM kprobe_opcode_t is u32. +*/ +#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) +kprobe_opcode_t copied_insn[MAX_COPIED_INSN ]; +/* detour code buffer */ +kprobe_opcode_t *insn; +/* +* We always copy one instruction on ARM, +* so size will always be 4, and unlike x86, there is no +* need for a size field. +*/ +};#endif /* _ARM_KPROBES_H */
arch/arm/kernel/Makefile +1 -1
@@ -52,7 +52,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o # Main staffs in KPROBES are in arch/arm/probes/ . -obj-$(CONFIG_KPROBES) += patch.o +obj-$(CONFIG_KPROBES) += patch.o insn.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.o
arch/arm/kernel/ftrace.c +1 -2
@@ -19,8 +19,7 @@#include <asm/cacheflush.h> #include <asm/opcodes.h> #include <asm/ftrace.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef CONFIG_THUMB2_KERNEL #define NOP 0xf85deb04/* pop.w {lr} */
arch/arm/kernel/jump_label.c +1 -2
@@ -1,8 +1,7 @@#include <linux/kernel.h> #include <linux/jump_label.h> #include <asm/patch.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef HAVE_JUMP_LABEL
arch/arm/probes/kprobes/Makefile +1 -0
@@ -7,5 +7,6 @@ obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o test-kprobes-objs += test-thumb.o else obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o +obj-$(CONFIG_OPTPROBES) += opt-arm.o test-kprobes-objs += test-arm.o endif
arch/arm/probes/kprobes/core.c +19 -7
@@ -163,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)* memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe (void *p) -{ -struct kprobe *kp = p; -void *addr = (void *)((uintptr_t )kp->addr & ~1 ); - -__patch_text (addr, kp->opcode); +struct patch { +void *addr; +unsigned int insn; +}; +static int __kprobes_remove_breakpoint (void *data) +{ +struct patch *p = data; +__patch_text (p->addr, p->insn);return 0 ; } +void __kprobes kprobes_remove_breakpoint (void *addr,unsigned int insn) +{ +struct patch p = { + .addr = addr, + .insn = insn, + }; +stop_machine (__kprobes_remove_breakpoint, &p, cpu_online_mask); +} +void __kprobes arch_disarm_kprobe (struct kprobe *p) { -stop_machine (__arch_disarm_kprobe, p, cpu_online_mask); +kprobes_remove_breakpoint ((void *)((uintptr_t )p->addr & ~1 ), + p->opcode); }void __kprobes arch_remove_kprobe (struct kprobe *p)
arch/arm/probes/kprobes/core.h +2 -0
@@ -30,6 +30,8 @@#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 +extern void kprobes_remove_breakpoint (void *addr,unsigned int insn); +enum probes_insn __kprobes kprobe_decode_ldmstm (kprobe_opcode_t insn,struct arch_probes_insn *asi,const struct decode_header *h);
arch/arm/probes/kprobes/opt-arm.c new file +317 -0
317 lines not on this page · raw message
Signature · 1 line
1.8.4
Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
Hi all,
Looks like v15 patch solves the problems found in patch v13 and v14. I run Tixy's test cases in a loop for a whole night on two real unpublished Hisilicon ARM A15 SoCs (I backported kprobes to 3.10 kernel), no problem arise, they are still running now.
Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
Quoted 5 lines · Wang Nan
Hi all,
Looks like v15 patch solves the problems found in patch v13 and v14. I run Tixy's test cases in a loop for a whole night on two real unpublished Hisilicon ARM A15 SoCs (I backported kprobes to 3.10 kernel), no problem arise, they are still running now.
I get a reproducible failure (below), but I believe it is a flaw in the test code. Now that we have optimised probes there is a window of opportunity for and interrupt to happen between the the kprobe which sets up the test preconditions and the tested probe executing. That will change the contents of stack memory below SP and make it inconsistent between test runs.
This recent flurry of kprobes work has been eating up my time somewhat and I have other urgent matters I should attend to, so I won't be looking at this problem for a few days.
That test failure...
strh r3, [r13, #-64]! @ e16d34b0
FAIL: test memory differs
FAIL: Test strh r3, [r13, #-64]!
FAIL: Scenario 1initial_regs:
r0 21522152 | r1 21522052 | r2 21522352 | r3 12345678 r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 r12 21522d52 | sp bf053ea0 | lr 21522f52 | pc 80028cf0 cpsr 18010013 expected_regs: r0 21522152 | r1 21522052 | r2 21522352 | r3 12345678 r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 r12 21522d52 | sp bf053e60 | lr 21522f52 | pc 80028cf4 cpsr 18010013 result_regs: r0 21522152 | r1 21522052 | r2 21522352 | r3 12345678 r4 21522552 | r5 21522452 | r6 21522752 | r7 21522652 r8 21522952 | r9 21522852 | r10 21522b52 | r11 21522a52 r12 21522d52 | sp bf053e60 | lr 21522f52 | pc 80028cf4
cpsr 18010013
current_stack=bf053da0expected_memory:
21525678 12345678 21522552 21522452
21522752 21522652 21522952 2152285221522b52 21522a52 21522d52 bf053ea021522f52 80028cf0 18010113 ffffffffresult_memory:
45675678 4567baab 4567bbab 4567bcab4567bdab 4567beab 4567bfab 4567c0ab4567c1ab 4567c2ab 4567c3ab 4567c4ab4567c5ab 4567c6ab 4567c7ab 4567c8ab
strh r3, [r13, #-64-8]! @ e16d34b8
strh r4, [r14, #-64-8]! @ e16e44b8
Signature · 1 line
Tixy
Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
In reply to Wang NanQuoted 254 lines · Wang Nan
This patch introduce kprobeopt for ARM 32.
Limitations:
- Currently only kernel compiled with ARM ISA is supported.- Offset between probe point and optinsn slot must not larger than 32MiB. Masami Hiramatsu suggests replacing 2 words, it will make things complex. Futher patch can make such optimization.
Kprobe opt on ARM is relatively simpler than kprobe opt on x86 because ARM instruction is always 4 bytes aligned and 4 bytes long. This patch replace probed instruction by a 'b', branch to trampoline code and then calls
optimized_callback().optimized_callback()callsopt_pre_handler()to execute kprobe handler. It also emulate/simulate replaced instruction.When unregistering kprobe, the deferred manner of unoptimizer may leave branch instruction before optimizer is called. Different from
x86_64, which only copy the probed insn afteroptprobe_template_endand reexecute them, this patch call singlestep to emulate/simulate the insn directly. Futher patch can optimize this behavior.Signed-off-by Wang Nan <[email protected]>Acked-by Masami Hiramatsu <[email protected]>Cc Jon Medhurst (Tixy) <[email protected]>Cc Russell King - ARM Linux <[email protected]>Cc Will Deacon <[email protected]>---
v1 -> v2:
- Improvement: if replaced instruction is conditional, generate a conditional branch instruction for it;
- IntroducesRELATIVEJUMP_OPCODESdue to ARMkprobe_opcode_tis 4 bytes;
- Removes size field in structarch_optimized_insn;
- Usearm_gen_branch()to generate branch instruction;
- Remove all recover logic: ARM doesn't use tail buffer, no need recover replaced instructions like x86;
- Remove incorrectCONFIG_THUMBchecking;
-can_optimize()always returns true if address is well aligned;
- Improveoptimized_callback: usingopt_pre_handler();
- Bugfix: correct range checking code and improve comments;
- Fix commit message.v2 -> v3:
- RenameRELATIVEJUMP_OPCODEStoMAX_COPIED_INSNS;
- Remove unneeded checking:arch_check_optimized_kprobe(), can_optimize();- Add missing
flush_icache_range()inarch_prepare_optimized_kprobe();
- Remove unneeded 'return;'.v3 -> v4:
- Use__mem_to_opcode_arm()to translatecopied_insnto ensure it works in big endian kernel;
- Replace 'nop' placeholder in trampoline code template with '.long 0' to avoid confusion: reader may regard 'nop' as an instruction, but it is value in fact.v4 -> v5:
- Don't optimize stack store operations.
- Introduce prepared field toarch_optimized_insnto indicate whether it is prepared. Similar to size field with x86. See v1 -> v2.v5 -> v6:
- Dynamically reserve stack according to instruction.
- Rename:kprobes-opt.c->kprobes-opt-arm.c.
- Setop->optinsn.insnafter all works are done.v6 -> v7:
- Using checker to check stack consumption.v7 -> v8:
- Small code adjustments.v8 -> v9:
- Utilize original kprobe passed toarch_prepare_optimized_kprobe()to avoid copy ainsn twice.
- A bug inarch_prepare_optimized_kprobe()is found and fixed.v9 -> v10:
- Commit message improvements.v10 -> v11:
- Move toarch/arm/probes/,insn.his moved toarch/arm/include/asm.
- Code cleanup.
- Bugfix based on Tixy's test result:
- Trampoline deal with ARM -> Thumb transision instructions and AEABI stack alignment requirement correctly.
- Trampoline code buffer should start at 4 byte aligned address. We enforces it in this series by using macro to wrap 'code' var.v11 -> v12:
- Remove trampoline code stack trick and use r4 to save original stack.
- Remove trampoline code buffer alignment trick.
- Names of files are changed.v12 -> v13:
- Assume stack always aligned by 4-bytes in any case.
- Comments update.v13 -> v14:
- Usestop_machineto wraparch_optimize_kprobesto avoid a racing.v14 -> v15:
- In v14,stop_machine()wraps a coarse-grained piece of code which makes things complex than it should be. In this version,kprobes_remove_breakpoint()is extracted,core.candopt-arm.cuse it to replace breakpoint to valid instruction.stop_machine()used inside inkprobes_remove_breakpoint().--- arch/arm/Kconfig | 1 + arch/arm/{kernel => include/asm}/insn.h | 0 arch/arm/include/asm/kprobes.h | 29 +++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/ftrace.c | 3 +- arch/arm/kernel/jump_label.c | 3 +- arch/arm/probes/kprobes/Makefile | 1 + arch/arm/probes/kprobes/core.c | 26 ++- arch/arm/probes/kprobes/core.h | 2 + arch/arm/probes/kprobes/opt-arm.c | 317 ++++++++++++++++++++++++++++++++ 10 files changed, 372 insertions(+), 12 deletions(-) rename arch/arm/{kernel => include/asm}/insn.h (100%) create mode 100644 arch/arm/probes/kprobes/opt-arm.carch/arm/Kconfig +1
-0@@ -59,6 +59,7 @@ config ARM select HAVE_MEMBLOCK select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMParch/arm/include/asm/insn.h renamed from arch/arm/kernel/insn.h +0
-0arch/arm/include/asm/kprobes.h +29
-0@@ -50,5 +50,34 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +/* optinsn template addresses */ +extern __visible kprobe_opcode_t optprobe_template_entry; +extern __visible kprobe_opcode_t optprobe_template_val; +extern __visible kprobe_opcode_t optprobe_template_call; +extern __visible kprobe_opcode_t optprobe_template_end; +extern __visible kprobe_opcode_t optprobe_template_sub_sp; +extern __visible kprobe_opcode_t optprobe_template_add_sp; + +#define MAX_OPTIMIZED_LENGTH 4 +#define MAX_OPTINSN_SIZE \ + ((unsigned long)&optprobe_template_end - \ + (unsigned long)&optprobe_template_entry) +#define RELATIVEJUMP_SIZE 4 + +struct arch_optimized_insn { +/* +* copy of the original instructions. +* Different from x86, ARM kprobe_opcode_t is u32. +*/ +#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) +kprobe_opcode_t copied_insn[MAX_COPIED_INSN ]; +/* detour code buffer */ +kprobe_opcode_t *insn; +/* +* We always copy one instruction on ARM, +* so size will always be 4, and unlike x86, there is no +* need for a size field. +*/ +};#endif /* _ARM_KPROBES_H */ arch/arm/kernel/Makefile +1
-1@@ -52,7 +52,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o # Main staffs in KPROBES are in arch/arm/probes/ . -obj-$(CONFIG_KPROBES) += patch.o +obj-$(CONFIG_KPROBES) += patch.o insn.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.oarch/arm/kernel/ftrace.c +1
-2@@ -19,8 +19,7 @@#include <asm/cacheflush.h> #include <asm/opcodes.h> #include <asm/ftrace.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef CONFIG_THUMB2_KERNEL #define NOP 0xf85deb04/* pop.w {lr} */ arch/arm/kernel/jump_label.c +1
-2@@ -1,8 +1,7 @@#include <linux/kernel.h> #include <linux/jump_label.h> #include <asm/patch.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef HAVE_JUMP_LABEL arch/arm/probes/kprobes/Makefile +1
-0@@ -7,5 +7,6 @@ obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o test-kprobes-objs += test-thumb.o else obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o +obj-$(CONFIG_OPTPROBES) += opt-arm.o test-kprobes-objs += test-arm.o endifarch/arm/probes/kprobes/core.c +8
-6@@ -163,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)* memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe (void *p) -{ -struct kprobe *kp = p; -void *addr = (void *)((uintptr_t )kp->addr & ~1 ); - -__patch_text (addr, kp->opcode); +struct patch { +void *addr; +unsigned int insn; +}; +static int __kprobes_remove_breakpoint (void *data) +{ +struct patch *p = data; +__patch_text (p->addr, p->insn);return 0 ;
arch/arm/probes/kprobes/core.c void __kprobes arch_arm_kprobe(struct kprobe *p) · line 185
Quoted 10 lines
arch/arm/probes/kprobes/core.c +8
-0} +void __kprobes kprobes_remove_breakpoint (void *addr,unsigned int insn) +{ +struct patch p = { + .addr = addr, + .insn = insn, + }; +stop_machine (__kprobes_remove_breakpoint, &p, cpu_online_mask); +}
Hmm, I think finally we should fix patch_text() in patch.c to forcibly use stop_machine by adding "bool stop" parameter, instead of introducing new another patch_text() implementation, because we'd better avoid two private "patch" data structures. Maybe someday we can find another better solution for self modifying.
(I actually doesn't like stop_machine() which disturbs real-time processing)
The other parts look good to me :)
Thank you!
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Research Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: masami.hiramatsu.pt at hitachi.com
Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
Quoted 257 lines · Masami Hiramatsu
Quoted 256 lines · Wang Nan
This patch introduce kprobeopt for ARM 32.
Limitations:
- Currently only kernel compiled with ARM ISA is supported.- Offset between probe point and optinsn slot must not larger than 32MiB. Masami Hiramatsu suggests replacing 2 words, it will make things complex. Futher patch can make such optimization.
Kprobe opt on ARM is relatively simpler than kprobe opt on x86 because ARM instruction is always 4 bytes aligned and 4 bytes long. This patch replace probed instruction by a 'b', branch to trampoline code and then calls
optimized_callback().optimized_callback()callsopt_pre_handler()to execute kprobe handler. It also emulate/simulate replaced instruction.When unregistering kprobe, the deferred manner of unoptimizer may leave branch instruction before optimizer is called. Different from
x86_64, which only copy the probed insn afteroptprobe_template_endand reexecute them, this patch call singlestep to emulate/simulate the insn directly. Futher patch can optimize this behavior.Signed-off-by Wang Nan <[email protected]>Acked-by Masami Hiramatsu <[email protected]>Cc Jon Medhurst (Tixy) <[email protected]>Cc Russell King - ARM Linux <[email protected]>Cc Will Deacon <[email protected]>---
v1 -> v2:
- Improvement: if replaced instruction is conditional, generate a conditional branch instruction for it;
- IntroducesRELATIVEJUMP_OPCODESdue to ARMkprobe_opcode_tis 4 bytes;
- Removes size field in structarch_optimized_insn;
- Usearm_gen_branch()to generate branch instruction;
- Remove all recover logic: ARM doesn't use tail buffer, no need recover replaced instructions like x86;
- Remove incorrectCONFIG_THUMBchecking;
-can_optimize()always returns true if address is well aligned;
- Improveoptimized_callback: usingopt_pre_handler();
- Bugfix: correct range checking code and improve comments;
- Fix commit message.v2 -> v3:
- RenameRELATIVEJUMP_OPCODEStoMAX_COPIED_INSNS;
- Remove unneeded checking:arch_check_optimized_kprobe(), can_optimize();- Add missing
flush_icache_range()inarch_prepare_optimized_kprobe();
- Remove unneeded 'return;'.v3 -> v4:
- Use__mem_to_opcode_arm()to translatecopied_insnto ensure it works in big endian kernel;
- Replace 'nop' placeholder in trampoline code template with '.long 0' to avoid confusion: reader may regard 'nop' as an instruction, but it is value in fact.v4 -> v5:
- Don't optimize stack store operations.
- Introduce prepared field toarch_optimized_insnto indicate whether it is prepared. Similar to size field with x86. See v1 -> v2.v5 -> v6:
- Dynamically reserve stack according to instruction.
- Rename:kprobes-opt.c->kprobes-opt-arm.c.
- Setop->optinsn.insnafter all works are done.v6 -> v7:
- Using checker to check stack consumption.v7 -> v8:
- Small code adjustments.v8 -> v9:
- Utilize original kprobe passed toarch_prepare_optimized_kprobe()to avoid copy ainsn twice.
- A bug inarch_prepare_optimized_kprobe()is found and fixed.v9 -> v10:
- Commit message improvements.v10 -> v11:
- Move toarch/arm/probes/,insn.his moved toarch/arm/include/asm.
- Code cleanup.
- Bugfix based on Tixy's test result:
- Trampoline deal with ARM -> Thumb transision instructions and AEABI stack alignment requirement correctly.
- Trampoline code buffer should start at 4 byte aligned address. We enforces it in this series by using macro to wrap 'code' var.v11 -> v12:
- Remove trampoline code stack trick and use r4 to save original stack.
- Remove trampoline code buffer alignment trick.
- Names of files are changed.v12 -> v13:
- Assume stack always aligned by 4-bytes in any case.
- Comments update.v13 -> v14:
- Usestop_machineto wraparch_optimize_kprobesto avoid a racing.v14 -> v15:
- In v14,stop_machine()wraps a coarse-grained piece of code which makes things complex than it should be. In this version,kprobes_remove_breakpoint()is extracted,core.candopt-arm.cuse it to replace breakpoint to valid instruction.stop_machine()used inside inkprobes_remove_breakpoint().--- arch/arm/Kconfig | 1 + arch/arm/{kernel => include/asm}/insn.h | 0 arch/arm/include/asm/kprobes.h | 29 +++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/ftrace.c | 3 +- arch/arm/kernel/jump_label.c | 3 +- arch/arm/probes/kprobes/Makefile | 1 + arch/arm/probes/kprobes/core.c | 26 ++- arch/arm/probes/kprobes/core.h | 2 + arch/arm/probes/kprobes/opt-arm.c | 317 ++++++++++++++++++++++++++++++++ 10 files changed, 372 insertions(+), 12 deletions(-) rename arch/arm/{kernel => include/asm}/insn.h (100%) create mode 100644 arch/arm/probes/kprobes/opt-arm.carch/arm/Kconfig +1
-0@@ -59,6 +59,7 @@ config ARM select HAVE_MEMBLOCK select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMParch/arm/include/asm/insn.h renamed from arch/arm/kernel/insn.h +0
-0arch/arm/include/asm/kprobes.h +29
-0@@ -50,5 +50,34 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +/* optinsn template addresses */ +extern __visible kprobe_opcode_t optprobe_template_entry; +extern __visible kprobe_opcode_t optprobe_template_val; +extern __visible kprobe_opcode_t optprobe_template_call; +extern __visible kprobe_opcode_t optprobe_template_end; +extern __visible kprobe_opcode_t optprobe_template_sub_sp; +extern __visible kprobe_opcode_t optprobe_template_add_sp; + +#define MAX_OPTIMIZED_LENGTH 4 +#define MAX_OPTINSN_SIZE \ + ((unsigned long)&optprobe_template_end - \ + (unsigned long)&optprobe_template_entry) +#define RELATIVEJUMP_SIZE 4 + +struct arch_optimized_insn { +/* +* copy of the original instructions. +* Different from x86, ARM kprobe_opcode_t is u32. +*/ +#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) +kprobe_opcode_t copied_insn[MAX_COPIED_INSN ]; +/* detour code buffer */ +kprobe_opcode_t *insn; +/* +* We always copy one instruction on ARM, +* so size will always be 4, and unlike x86, there is no +* need for a size field. +*/ +};#endif /* _ARM_KPROBES_H */ arch/arm/kernel/Makefile +1
-1@@ -52,7 +52,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o # Main staffs in KPROBES are in arch/arm/probes/ . -obj-$(CONFIG_KPROBES) += patch.o +obj-$(CONFIG_KPROBES) += patch.o insn.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.oarch/arm/kernel/ftrace.c +1
-2@@ -19,8 +19,7 @@#include <asm/cacheflush.h> #include <asm/opcodes.h> #include <asm/ftrace.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef CONFIG_THUMB2_KERNEL #define NOP 0xf85deb04/* pop.w {lr} */ arch/arm/kernel/jump_label.c +1
-2@@ -1,8 +1,7 @@#include <linux/kernel.h> #include <linux/jump_label.h> #include <asm/patch.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef HAVE_JUMP_LABEL arch/arm/probes/kprobes/Makefile +1
-0@@ -7,5 +7,6 @@ obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o test-kprobes-objs += test-thumb.o else obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o +obj-$(CONFIG_OPTPROBES) += opt-arm.o test-kprobes-objs += test-arm.o endifarch/arm/probes/kprobes/core.c +8
-6@@ -163,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)* memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe (void *p) -{ -struct kprobe *kp = p; -void *addr = (void *)((uintptr_t )kp->addr & ~1 ); - -__patch_text (addr, kp->opcode); +struct patch { +void *addr; +unsigned int insn; +}; +static int __kprobes_remove_breakpoint (void *data) +{ +struct patch *p = data; +__patch_text (p->addr, p->insn);return 0 ; }
Quoted 12 lines
arch/arm/probes/kprobes/core.c void __kprobes arch_arm_kprobe(struct kprobe *p) · line 185
Quoted 8 lines
arch/arm/probes/kprobes/core.c +8
-0+void __kprobes kprobes_remove_breakpoint (void *addr,unsigned int insn) +{ +struct patch p = { + .addr = addr, + .insn = insn, + }; +stop_machine (__kprobes_remove_breakpoint, &p, cpu_online_mask); +}Hmm, I think finally we should fix
patch_text()inpatch.cto forcibly usestop_machineby adding "bool stop" parameter, instead of introducing new anotherpatch_text()implementation, because we'd better avoid two private "patch" data structures.
That was my first thought too, then I realised that breaks encapsulation of the patch_text implementation, because its use of stop_machine is an implementation detail and it could be rewritten to not use stop machine. (That is sort of on my long term todo list
https://lkml.org/lkml/2014/9/4/188)
Whereas stop machine is used by kprobes to avoid race conditions with the undefined instruction exception handler and something like that would be needed even if patch_text didn't use stop_machine.
Signature · 1 line
Tixy
Re: Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
(2014/12/09 18:14), Jon Medhurst (Tixy) wrote:
[...]
Quoted 39 lines
Quoted 26 lines
Quoted 26 lines
arch/arm/probes/kprobes/core.c +8
-6@@ -163,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)* memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe (void *p) -{ -struct kprobe *kp = p; -void *addr = (void *)((uintptr_t )kp->addr & ~1 ); - -__patch_text (addr, kp->opcode); +struct patch { +void *addr; +unsigned int insn; +}; +static int __kprobes_remove_breakpoint (void *data) +{ +struct patch *p = data; +__patch_text (p->addr, p->insn);return 0 ; }Quoted 12 lines
arch/arm/probes/kprobes/core.c void __kprobes arch_arm_kprobe(struct kprobe *p) · line 185
Quoted 8 lines
arch/arm/probes/kprobes/core.c +8
-0+void __kprobes kprobes_remove_breakpoint (void *addr,unsigned int insn) +{ +struct patch p = { + .addr = addr, + .insn = insn, + }; +stop_machine (__kprobes_remove_breakpoint, &p, cpu_online_mask); +}Hmm, I think finally we should fix
patch_text()inpatch.cto forcibly usestop_machineby adding "bool stop" parameter, instead of introducing new anotherpatch_text()implementation, because we'd better avoid two private "patch" data structures.
Quoted 5 lines
That was my first thought too, then I realised that breaks encapsulation of the
patch_textimplementation, because its use ofstop_machineis an implementation detail and it could be rewritten to not use stop machine. (That is sort of on my long term todo list
https://lkml.org/lkml/2014/9/4/188)
Indeed. OK, now let it goes. :)
Quoted 3 lines
Whereas stop machine is used by kprobes to avoid race conditions with the undefined instruction exception handler and something like that would be needed even if
patch_textdidn't usestop_machine.
At this point, it's OK.
However, I'm not convinced completely. Perhaps, it depends on cache-coherent bus implementation, but there may be some implementations which can allow us to change one instruction atomically without stop_machine.
I'm actually interested in PREEMPT_RT on arm32, and this stop_machine() is a barrier to apply kprobes on real-time systems.
Thank you,
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Research Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: masami.hiramatsu.pt at hitachi.com
Re: [RESEND][PATCH v15 7/7] ARM: kprobes: enable OPTPROBES for ARM 32
In reply to Masami HiramatsuQuoted 272 lines · Masami Hiramatsu
Quoted 254 lines · Wang Nan
This patch introduce kprobeopt for ARM 32.
Limitations:
- Currently only kernel compiled with ARM ISA is supported.- Offset between probe point and optinsn slot must not larger than 32MiB. Masami Hiramatsu suggests replacing 2 words, it will make things complex. Futher patch can make such optimization.
Kprobe opt on ARM is relatively simpler than kprobe opt on x86 because ARM instruction is always 4 bytes aligned and 4 bytes long. This patch replace probed instruction by a 'b', branch to trampoline code and then calls
optimized_callback().optimized_callback()callsopt_pre_handler()to execute kprobe handler. It also emulate/simulate replaced instruction.When unregistering kprobe, the deferred manner of unoptimizer may leave branch instruction before optimizer is called. Different from
x86_64, which only copy the probed insn afteroptprobe_template_endand reexecute them, this patch call singlestep to emulate/simulate the insn directly. Futher patch can optimize this behavior.Signed-off-by Wang Nan <[email protected]>Acked-by Masami Hiramatsu <[email protected]>Cc Jon Medhurst (Tixy) <[email protected]>Cc Russell King - ARM Linux <[email protected]>Cc Will Deacon <[email protected]>---
v1 -> v2:
- Improvement: if replaced instruction is conditional, generate a conditional branch instruction for it;
- IntroducesRELATIVEJUMP_OPCODESdue to ARMkprobe_opcode_tis 4 bytes;
- Removes size field in structarch_optimized_insn;
- Usearm_gen_branch()to generate branch instruction;
- Remove all recover logic: ARM doesn't use tail buffer, no need recover replaced instructions like x86;
- Remove incorrectCONFIG_THUMBchecking;
-can_optimize()always returns true if address is well aligned;
- Improveoptimized_callback: usingopt_pre_handler();
- Bugfix: correct range checking code and improve comments;
- Fix commit message.v2 -> v3:
- RenameRELATIVEJUMP_OPCODEStoMAX_COPIED_INSNS;
- Remove unneeded checking:arch_check_optimized_kprobe(), can_optimize();- Add missing
flush_icache_range()inarch_prepare_optimized_kprobe();
- Remove unneeded 'return;'.v3 -> v4:
- Use__mem_to_opcode_arm()to translatecopied_insnto ensure it works in big endian kernel;
- Replace 'nop' placeholder in trampoline code template with '.long 0' to avoid confusion: reader may regard 'nop' as an instruction, but it is value in fact.v4 -> v5:
- Don't optimize stack store operations.
- Introduce prepared field toarch_optimized_insnto indicate whether it is prepared. Similar to size field with x86. See v1 -> v2.v5 -> v6:
- Dynamically reserve stack according to instruction.
- Rename:kprobes-opt.c->kprobes-opt-arm.c.
- Setop->optinsn.insnafter all works are done.v6 -> v7:
- Using checker to check stack consumption.v7 -> v8:
- Small code adjustments.v8 -> v9:
- Utilize original kprobe passed toarch_prepare_optimized_kprobe()to avoid copy ainsn twice.
- A bug inarch_prepare_optimized_kprobe()is found and fixed.v9 -> v10:
- Commit message improvements.v10 -> v11:
- Move toarch/arm/probes/,insn.his moved toarch/arm/include/asm.
- Code cleanup.
- Bugfix based on Tixy's test result:
- Trampoline deal with ARM -> Thumb transision instructions and AEABI stack alignment requirement correctly.
- Trampoline code buffer should start at 4 byte aligned address. We enforces it in this series by using macro to wrap 'code' var.v11 -> v12:
- Remove trampoline code stack trick and use r4 to save original stack.
- Remove trampoline code buffer alignment trick.
- Names of files are changed.v12 -> v13:
- Assume stack always aligned by 4-bytes in any case.
- Comments update.v13 -> v14:
- Usestop_machineto wraparch_optimize_kprobesto avoid a racing.v14 -> v15:
- In v14,stop_machine()wraps a coarse-grained piece of code which makes things complex than it should be. In this version,kprobes_remove_breakpoint()is extracted,core.candopt-arm.cuse it to replace breakpoint to valid instruction.stop_machine()used inside inkprobes_remove_breakpoint().--- arch/arm/Kconfig | 1 + arch/arm/{kernel => include/asm}/insn.h | 0 arch/arm/include/asm/kprobes.h | 29 +++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/ftrace.c | 3 +- arch/arm/kernel/jump_label.c | 3 +- arch/arm/probes/kprobes/Makefile | 1 + arch/arm/probes/kprobes/core.c | 26 ++- arch/arm/probes/kprobes/core.h | 2 + arch/arm/probes/kprobes/opt-arm.c | 317 ++++++++++++++++++++++++++++++++ 10 files changed, 372 insertions(+), 12 deletions(-) rename arch/arm/{kernel => include/asm}/insn.h (100%) create mode 100644 arch/arm/probes/kprobes/opt-arm.carch/arm/Kconfig +1
-0@@ -59,6 +59,7 @@ config ARM select HAVE_MEMBLOCK select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMParch/arm/include/asm/insn.h renamed from arch/arm/kernel/insn.h +0
-0arch/arm/include/asm/kprobes.h +29
-0@@ -50,5 +50,34 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +/* optinsn template addresses */ +extern __visible kprobe_opcode_t optprobe_template_entry; +extern __visible kprobe_opcode_t optprobe_template_val; +extern __visible kprobe_opcode_t optprobe_template_call; +extern __visible kprobe_opcode_t optprobe_template_end; +extern __visible kprobe_opcode_t optprobe_template_sub_sp; +extern __visible kprobe_opcode_t optprobe_template_add_sp; + +#define MAX_OPTIMIZED_LENGTH 4 +#define MAX_OPTINSN_SIZE \ + ((unsigned long)&optprobe_template_end - \ + (unsigned long)&optprobe_template_entry) +#define RELATIVEJUMP_SIZE 4 + +struct arch_optimized_insn { +/* +* copy of the original instructions. +* Different from x86, ARM kprobe_opcode_t is u32. +*/ +#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) +kprobe_opcode_t copied_insn[MAX_COPIED_INSN ]; +/* detour code buffer */ +kprobe_opcode_t *insn; +/* +* We always copy one instruction on ARM, +* so size will always be 4, and unlike x86, there is no +* need for a size field. +*/ +};#endif /* _ARM_KPROBES_H */ arch/arm/kernel/Makefile +1
-1@@ -52,7 +52,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o # Main staffs in KPROBES are in arch/arm/probes/ . -obj-$(CONFIG_KPROBES) += patch.o +obj-$(CONFIG_KPROBES) += patch.o insn.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.oarch/arm/kernel/ftrace.c +1
-2@@ -19,8 +19,7 @@#include <asm/cacheflush.h> #include <asm/opcodes.h> #include <asm/ftrace.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef CONFIG_THUMB2_KERNEL #define NOP 0xf85deb04/* pop.w {lr} */ arch/arm/kernel/jump_label.c +1
-2@@ -1,8 +1,7 @@#include <linux/kernel.h> #include <linux/jump_label.h> #include <asm/patch.h> - -#include "insn.h" +#include <asm/insn.h> #ifdef HAVE_JUMP_LABEL arch/arm/probes/kprobes/Makefile +1
-0@@ -7,5 +7,6 @@ obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o test-kprobes-objs += test-thumb.o else obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o +obj-$(CONFIG_OPTPROBES) += opt-arm.o test-kprobes-objs += test-arm.o endifarch/arm/probes/kprobes/core.c +8
-6@@ -163,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)* memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe (void *p) -{ -struct kprobe *kp = p; -void *addr = (void *)((uintptr_t )kp->addr & ~1 ); - -__patch_text (addr, kp->opcode); +struct patch { +void *addr; +unsigned int insn; +}; +static int __kprobes_remove_breakpoint (void *data) +{ +struct patch *p = data; +__patch_text (p->addr, p->insn);return 0 ;arch/arm/probes/kprobes/core.c void __kprobes arch_arm_kprobe(struct kprobe *p) · line 185
Quoted 10 lines
arch/arm/probes/kprobes/core.c +8
-0} +void __kprobes kprobes_remove_breakpoint (void *addr,unsigned int insn) +{ +struct patch p = { + .addr = addr, + .insn = insn, + }; +stop_machine (__kprobes_remove_breakpoint, &p, cpu_online_mask); +}Hmm, I think finally we should fix
patch_text()inpatch.cto forcibly usestop_machineby adding "bool stop" parameter, instead of introducing new anotherpatch_text()implementation, because we'd better avoid two private "patch" data structures. Maybe someday we can find another better solution for self modifying.
(I actually doesn't likestop_machine()which disturbs real-time processing)
Quoted 2 lines
The other parts look good to me :)
So what's your opinion about this series of patches? Do you think they can be merged into upstream code already? Or do you think we should eliminate stop_machine() first?
Quoted 3 lines
Thank you!