LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements.
@ 2015-01-05 11:28 Wang Nan
  2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
                   ` (11 more replies)
  0 siblings, 12 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:28 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

According to Masami Hiramatsu's suggestion, there are some small code
adjustments in this series of patch.

Jon Medhurst (Tixy) (2):
  ARM: kprobes: Add test cases for stack consuming instructions
  ARM: kprobes: Fix unreliable MRS instruction tests

Masami Hiramatsu (1):
  kprobes: Pass the original kprobe for preparing optimized kprobe

Wang Nan (8):
  ARM: probes: move all probe code to dedicate directory
  ARM: kprobes: remove unused ARM decoder actions.
  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
  ARM: kprobes: check register usage for probed instruction.
  ARM: optprobes: execute instruction during restoring if possible.

 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                      |  23 ++
 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}   |  10 +-
 .../probes-thumb.c => probes/decode-thumb.c}       |  16 +-
 .../probes-thumb.h => probes/decode-thumb.h}       |  10 +-
 arch/arm/{kernel/probes.c => probes/decode.c}      |  81 +++++-
 arch/arm/{kernel/probes.h => probes/decode.h}      |  13 +-
 arch/arm/probes/kprobes/Makefile                   |  12 +
 .../kprobes-arm.c => probes/kprobes/actions-arm.c} |  12 +-
 .../kprobes/actions-common.c}                      |   4 +-
 .../kprobes/actions-thumb.c}                       |  10 +-
 arch/arm/probes/kprobes/checkers-arm.c             | 223 +++++++++++++++
 arch/arm/probes/kprobes/checkers-common.c          | 101 +++++++
 arch/arm/probes/kprobes/checkers-thumb.c           | 110 +++++++
 arch/arm/probes/kprobes/checkers.h                 |  55 ++++
 .../{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}                            |  37 ++-
 .../kprobes-test.c => probes/kprobes/test-core.c}  |  36 ++-
 .../kprobes-test.h => probes/kprobes/test-core.h}  |  35 ++-
 .../kprobes/test-thumb.c}                          |  20 +-
 arch/arm/probes/uprobes/Makefile                   |   1 +
 .../uprobes-arm.c => probes/uprobes/actions-arm.c} |   9 +-
 .../{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, 1169 insertions(+), 126 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} (92%)
 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} (84%)
 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} (97%)
 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} (98%)
 rename arch/arm/{kernel/kprobes-test.h => probes/kprobes/test-core.h} (92%)
 rename arch/arm/{kernel/kprobes-test-thumb.c => probes/kprobes/test-thumb.c} (97%)
 create mode 100644 arch/arm/probes/uprobes/Makefile
 rename arch/arm/{kernel/uprobes-arm.c => probes/uprobes/actions-arm.c} (96%)
 rename arch/arm/{kernel/uprobes.c => probes/uprobes/core.c} (97%)
 rename arch/arm/{kernel/uprobes.h => probes/uprobes/core.h} (100%)

-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-09  2:19   ` [PATCH v20 " Wang Nan
  2015-01-09  2:28   ` [PATCH v19 " Wang Nan
  2015-01-05 11:29 ` [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions Wang Nan
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

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

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 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                         |  1 +
 .../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, 68 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%)

diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c1785ee..7f99cd6 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -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/
diff --git a/arch/arm/kernel/patch.h b/arch/arm/include/asm/patch.h
similarity index 100%
rename from arch/arm/kernel/patch.h
rename to arch/arm/include/asm/patch.h
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index fb2b71e..9c51a43 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -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 patch.o
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
index afeeb9e..d8da075 100644
--- a/arch/arm/kernel/jump_label.c
+++ b/arch/arm/kernel/jump_label.c
@@ -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
 
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c
index 5038960..69bda1a 100644
--- a/arch/arm/kernel/patch.c
+++ b/arch/arm/kernel/patch.c
@@ -8,8 +8,7 @@
 #include <asm/fixmap.h>
 #include <asm/smp_plat.h>
 #include <asm/opcodes.h>
-
-#include "patch.h"
+#include <asm/patch.h>
 
 struct patch {
 	void *addr;
diff --git a/arch/arm/probes/Makefile b/arch/arm/probes/Makefile
new file mode 100644
index 0000000..aa1f859
--- /dev/null
+++ b/arch/arm/probes/Makefile
@@ -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
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/probes/decode-arm.c
similarity index 99%
rename from arch/arm/kernel/probes-arm.c
rename to arch/arm/probes/decode-arm.c
index 8eaef81..e39cc75 100644
--- a/arch/arm/kernel/probes-arm.c
+++ b/arch/arm/probes/decode-arm.c
@@ -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)))))
 
diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/probes/decode-arm.h
similarity index 97%
rename from arch/arm/kernel/probes-arm.h
rename to arch/arm/probes/decode-arm.h
index ace6572..9c56b40 100644
--- a/arch/arm/kernel/probes-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -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,
diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/probes/decode-thumb.c
similarity index 99%
rename from arch/arm/kernel/probes-thumb.c
rename to arch/arm/probes/decode-thumb.c
index 4131351..2f0453a 100644
--- a/arch/arm/kernel/probes-thumb.c
+++ b/arch/arm/probes/decode-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes-thumb.c
+ * arch/arm/probes/decode-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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[] = {
diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/probes/decode-thumb.h
similarity index 97%
rename from arch/arm/kernel/probes-thumb.h
rename to arch/arm/probes/decode-thumb.h
index 7c6f6eb..039013c 100644
--- a/arch/arm/kernel/probes-thumb.h
+++ b/arch/arm/probes/decode-thumb.h
@@ -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.
  */
diff --git a/arch/arm/kernel/probes.c b/arch/arm/probes/decode.c
similarity index 99%
rename from arch/arm/kernel/probes.c
rename to arch/arm/probes/decode.c
index a8ab540..3b05d57 100644
--- a/arch/arm/kernel/probes.c
+++ b/arch/arm/probes/decode.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes.c
+ * arch/arm/probes/decode.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -17,7 +17,7 @@
 #include <asm/ptrace.h>
 #include <linux/bug.h>
 
-#include "probes.h"
+#include "decode.h"
 
 
 #ifndef find_str_pc_offset
diff --git a/arch/arm/kernel/probes.h b/arch/arm/probes/decode.h
similarity index 99%
rename from arch/arm/kernel/probes.h
rename to arch/arm/probes/decode.h
index dba9f24..1d0b531 100644
--- a/arch/arm/kernel/probes.h
+++ b/arch/arm/probes/decode.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes.h
+ * arch/arm/probes/decode.h
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
new file mode 100644
index 0000000..eb38a42
--- /dev/null
+++ b/arch/arm/probes/kprobes/Makefile
@@ -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
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/probes/kprobes/actions-arm.c
similarity index 99%
rename from arch/arm/kernel/kprobes-arm.c
rename to arch/arm/probes/kprobes/actions-arm.c
index ac300c6..8797879 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -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"
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/probes/kprobes/actions-common.c
similarity index 98%
rename from arch/arm/kernel/kprobes-common.c
rename to arch/arm/probes/kprobes/actions-common.c
index 0bf5d64..bd20a71 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/probes/kprobes/actions-common.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-common.c
+ * arch/arm/probes/kprobes/actions-common.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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,
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
similarity index 99%
rename from arch/arm/kernel/kprobes-thumb.c
rename to arch/arm/probes/kprobes/actions-thumb.c
index 9495d7f..6c4e60b 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/probes/kprobes/actions-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-thumb.c
+ * arch/arm/probes/kprobes/actions-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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 \
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/probes/kprobes/core.c
similarity index 99%
rename from arch/arm/kernel/kprobes.c
rename to arch/arm/probes/kprobes/core.c
index 6d64420..701f49d 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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,		\
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/probes/kprobes/core.h
similarity index 96%
rename from arch/arm/kernel/kprobes.h
rename to arch/arm/probes/kprobes/core.h
index 9a2712e..2e1e5a3 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -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
diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/probes/kprobes/test-arm.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test-arm.c
rename to arch/arm/probes/kprobes/test-arm.c
index cb14242..d9a1255 100644
--- a/arch/arm/kernel/kprobes-test-arm.c
+++ b/arch/arm/probes/kprobes/test-arm.c
@@ -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"
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/probes/kprobes/test-core.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test.c
rename to arch/arm/probes/kprobes/test-core.c
index b206d77..7ab633d 100644
--- a/arch/arm/kernel/kprobes-test.c
+++ b/arch/arm/probes/kprobes/test-core.c
@@ -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
diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/probes/kprobes/test-core.h
similarity index 99%
rename from arch/arm/kernel/kprobes-test.h
rename to arch/arm/probes/kprobes/test-core.h
index 4430990..9991754 100644
--- a/arch/arm/kernel/kprobes-test.h
+++ b/arch/arm/probes/kprobes/test-core.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-test.h
+ * arch/arm/probes/kprobes/test-core.h
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test-thumb.c
rename to arch/arm/probes/kprobes/test-thumb.c
index 844dd10..6c6e9a9 100644
--- a/arch/arm/kernel/kprobes-test-thumb.c
+++ b/arch/arm/probes/kprobes/test-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-test-thumb.c
+ * arch/arm/probes/kprobes/test-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 #include <asm/opcodes.h>
 
-#include "kprobes-test.h"
+#include "test-core.h"
 
 
 #define TEST_ISA "16"
diff --git a/arch/arm/probes/uprobes/Makefile b/arch/arm/probes/uprobes/Makefile
new file mode 100644
index 0000000..e1dc3d0
--- /dev/null
+++ b/arch/arm/probes/uprobes/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_UPROBES)		+= core.o actions-arm.o
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/probes/uprobes/actions-arm.c
similarity index 98%
rename from arch/arm/kernel/uprobes-arm.c
rename to arch/arm/probes/uprobes/actions-arm.c
index d3b655f..1dd4916 100644
--- a/arch/arm/kernel/uprobes-arm.c
+++ b/arch/arm/probes/uprobes/actions-arm.c
@@ -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)
 {
diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/probes/uprobes/core.c
similarity index 98%
rename from arch/arm/kernel/uprobes.c
rename to arch/arm/probes/uprobes/core.c
index 56adf9c..b2954f6 100644
--- a/arch/arm/kernel/uprobes.c
+++ b/arch/arm/probes/uprobes/core.c
@@ -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
 
diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/probes/uprobes/core.h
similarity index 100%
rename from arch/arm/kernel/uprobes.h
rename to arch/arm/probes/uprobes/core.h
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions.
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
  2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-07 11:50   ` Jon Medhurst (Tixy)
  2015-01-05 11:29 ` [PATCH v19 03/11] ARM: kprobes: introduces checker Wang Nan
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

There are 3 actions which is never used:

 PROBES_MOV_HALFWORD,
 PROBES_SEV,
 PROBES_WFE,

This patch removes them.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 arch/arm/probes/decode-arm.h          | 3 ---
 arch/arm/probes/kprobes/actions-arm.c | 3 ---
 arch/arm/probes/uprobes/actions-arm.c | 3 ---
 3 files changed, 9 deletions(-)

diff --git a/arch/arm/probes/decode-arm.h b/arch/arm/probes/decode-arm.h
index 9c56b40..f0dbc5a 100644
--- a/arch/arm/probes/decode-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -38,9 +38,6 @@ enum probes_arm_action {
 	PROBES_MOV_IP_SP,
 	PROBES_DATA_PROCESSING_REG,
 	PROBES_DATA_PROCESSING_IMM,
-	PROBES_MOV_HALFWORD,
-	PROBES_SEV,
-	PROBES_WFE,
 	PROBES_SATURATE,
 	PROBES_REV,
 	PROBES_MMI,
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 8797879..099aeb0 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -325,9 +325,6 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
 		.handler = emulate_rd12rn16rm0rs8_rwflags},
 	[PROBES_DATA_PROCESSING_IMM] = {
 		.handler = emulate_rd12rn16rm0rs8_rwflags},
-	[PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
-	[PROBES_SEV] = {.handler = probes_emulate_none},
-	[PROBES_WFE] = {.handler = probes_simulate_nop},
 	[PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 	[PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
 	[PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
diff --git a/arch/arm/probes/uprobes/actions-arm.c b/arch/arm/probes/uprobes/actions-arm.c
index 1dd4916..6a271d6 100644
--- a/arch/arm/probes/uprobes/actions-arm.c
+++ b/arch/arm/probes/uprobes/actions-arm.c
@@ -217,9 +217,6 @@ const union decode_action uprobes_probes_actions[] = {
 		.decoder = decode_rd12rn16rm0rs8_rwflags},
 	[PROBES_DATA_PROCESSING_IMM] = {
 		.decoder = decode_rd12rn16rm0rs8_rwflags},
-	[PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
-	[PROBES_SEV] = {.handler = probes_simulate_nop},
-	[PROBES_WFE] = {.handler = probes_simulate_nop},
 	[PROBES_SATURATE] = {.handler = probes_simulate_nop},
 	[PROBES_REV] = {.handler = probes_simulate_nop},
 	[PROBES_MMI] = {.handler = probes_simulate_nop},
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 03/11] ARM: kprobes: introduces checker
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
  2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
  2015-01-05 11:29 ` [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 04/11] ARM: kprobes: collects stack consumption for store instructions Wang Nan
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

This 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.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 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(-)

diff --git a/arch/arm/probes/decode-arm.c b/arch/arm/probes/decode-arm.c
index e39cc75..f46d8fc 100644
--- a/arch/arm/probes/decode-arm.c
+++ b/arch/arm/probes/decode-arm.c
@@ -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);
 }
diff --git a/arch/arm/probes/decode-arm.h b/arch/arm/probes/decode-arm.h
index f0dbc5a..e4b87fe 100644
--- a/arch/arm/probes/decode-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -67,6 +67,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
diff --git a/arch/arm/probes/decode-thumb.c b/arch/arm/probes/decode-thumb.c
index 2f0453a..985e7dd 100644
--- a/arch/arm/probes/decode-thumb.c
+++ b/arch/arm/probes/decode-thumb.c
@@ -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);
 }
diff --git a/arch/arm/probes/decode-thumb.h b/arch/arm/probes/decode-thumb.h
index 039013c..8457add 100644
--- a/arch/arm/probes/decode-thumb.h
+++ b/arch/arm/probes/decode-thumb.h
@@ -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
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
index 3b05d57..c7d4420 100644
--- a/arch/arm/probes/decode.c
+++ b/arch/arm/probes/decode.c
@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
 	[DECODE_TYPE_REJECT]	= sizeof(struct decode_reject)
 };
 
+static int run_checkers(const struct decode_checker *checkers[],
+		int action, probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	const struct decode_checker **p;
+
+	if (!checkers)
+		return INSN_GOOD;
+
+	p = checkers;
+	while (*p != NULL) {
+		int retval;
+		probes_check_t *checker_func = (*p)[action].checker;
+
+		retval = INSN_GOOD;
+		if (checker_func)
+			retval = checker_func(insn, asi, h);
+		if (retval == INSN_REJECTED)
+			return retval;
+		p++;
+	}
+	return INSN_GOOD;
+}
+
 /*
  * probes_decode_insn operates on data tables in order to decode an ARM
  * architecture instruction onto which a kprobe has been placed.
@@ -388,11 +413,17 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
 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)
+		   bool emulate, const union decode_action *actions,
+		   const struct decode_checker *checkers[])
 {
 	const struct decode_header *h = (struct decode_header *)table;
 	const struct decode_header *next;
 	bool matched = false;
+	/*
+	 * @insn can be modified by decode_regs. Save its original
+	 * value for checkers.
+	 */
+	probes_opcode_t origin_insn = insn;
 
 	if (emulate)
 		insn = prepare_emulated_insn(insn, asi, thumb);
@@ -422,24 +453,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
 		}
 
 		case DECODE_TYPE_CUSTOM: {
+			int err;
 			struct decode_custom *d = (struct decode_custom *)h;
-			return actions[d->decoder.action].decoder(insn, asi, h);
+			int action = d->decoder.action;
+
+			err = run_checkers(checkers, action, origin_insn, asi, h);
+			if (err == INSN_REJECTED)
+				return INSN_REJECTED;
+			return actions[action].decoder(insn, asi, h);
 		}
 
 		case DECODE_TYPE_SIMULATE: {
+			int err;
 			struct decode_simulate *d = (struct decode_simulate *)h;
-			asi->insn_handler = actions[d->handler.action].handler;
+			int action = d->handler.action;
+
+			err = run_checkers(checkers, action, origin_insn, asi, h);
+			if (err == INSN_REJECTED)
+				return INSN_REJECTED;
+			asi->insn_handler = actions[action].handler;
 			return INSN_GOOD_NO_SLOT;
 		}
 
 		case DECODE_TYPE_EMULATE: {
+			int err;
 			struct decode_emulate *d = (struct decode_emulate *)h;
+			int action = d->handler.action;
+
+			err = run_checkers(checkers, action, origin_insn, asi, h);
+			if (err == INSN_REJECTED)
+				return INSN_REJECTED;
 
 			if (!emulate)
-				return actions[d->handler.action].decoder(insn,
-					asi, h);
+				return actions[action].decoder(insn, asi, h);
 
-			asi->insn_handler = actions[d->handler.action].handler;
+			asi->insn_handler = actions[action].handler;
 			set_emulated_insn(insn, asi, thumb);
 			return INSN_GOOD;
 		}
diff --git a/arch/arm/probes/decode.h b/arch/arm/probes/decode.h
index 1d0b531..f9b08ba 100644
--- a/arch/arm/probes/decode.h
+++ b/arch/arm/probes/decode.h
@@ -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
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 099aeb0..c3e7200 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -338,3 +338,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};
diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
index 6c4e60b..2796121 100644
--- a/arch/arm/probes/kprobes/actions-thumb.c
+++ b/arch/arm/probes/kprobes/actions-thumb.c
@@ -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};
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 701f49d..74f3dc3 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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;
 
diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
index 2e1e5a3..f88c79f 100644
--- a/arch/arm/probes/kprobes/core.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -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
 
diff --git a/arch/arm/probes/uprobes/core.c b/arch/arm/probes/uprobes/core.c
index b2954f6..d1329f1 100644
--- a/arch/arm/probes/uprobes/core.c
+++ b/arch/arm/probes/uprobes/core.c
@@ -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;
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 04/11] ARM: kprobes: collects stack consumption for store instructions
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (2 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 03/11] ARM: kprobes: introduces checker Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 05/11] ARM: kprobes: disallow probing stack consuming instructions Wang Nan
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

This patch uses the previously introduced checker functionality on
store instructions to record their stack consumption information to
arch_probes_insn.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
---
 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

diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index 806cfe6..ccf9af3 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -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
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
index c7d4420..f9d7c42 100644
--- a/arch/arm/probes/decode.c
+++ b/arch/arm/probes/decode.c
@@ -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);
 
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
index eb38a42..bc8d504 100644
--- a/arch/arm/probes/kprobes/Makefile
+++ b/arch/arm/probes/kprobes/Makefile
@@ -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
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index c3e7200..4fedd4c 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -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"
@@ -339,4 +340,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};
diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
index 2796121..07cfd9b 100644
--- a/arch/arm/probes/kprobes/actions-thumb.c
+++ b/arch/arm/probes/kprobes/actions-thumb.c
@@ -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};
diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c
new file mode 100644
index 0000000..f817663
--- /dev/null
+++ b/arch/arm/probes/kprobes/checkers-arm.c
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/probes/kprobes/checkers-arm.c
+ *
+ * Copyright (C) 2014 Huawei Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "../decode.h"
+#include "../decode-arm.h"
+#include "checkers.h"
+
+static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	/*
+	 * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE,
+	 * PROBES_STORE_EXTRA may get here. Simply mark all normal
+	 * insns as STACK_USE_NONE.
+	 */
+	static const union decode_item table[] = {
+		/*
+		 * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN
+		 * if Rn or Rm is SP.
+		 *                                 x
+		 * STR (register)	cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx
+		 * STRB (register)	cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx
+		 */
+		DECODE_OR	(0x0e10000f, 0x0600000d),
+		DECODE_OR	(0x0e1f0000, 0x060d0000),
+
+		/*
+		 *                                                     x
+		 * STRD (register)	cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
+		 * STRH (register)	cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx
+		 */
+		DECODE_OR	(0x0e5000bf, 0x000000bd),
+		DECODE_CUSTOM	(0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN),
+
+		/*
+		 * For PROBES_LDMSTM, only stmdx sp, [...] need to examine
+		 *
+		 * Bit B/A (bit 24) encodes arithmetic operation order. 1 means
+		 * before, 0 means after.
+		 * Bit I/D (bit 23) encodes arithmetic operation. 1 means
+		 * increment, 0 means decrement.
+		 *
+		 * So:
+		 *                              B I
+		 *                              / /
+		 *                              A D   | Rn |
+		 * STMDX SP, [...]	cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx
+		 */
+		DECODE_CUSTOM	(0x0edf0000, 0x080d0000, STACK_USE_STMDX),
+
+		/*                              P U W | Rn | Rt |     imm12    |*/
+		/* STR (immediate)	cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */
+		/* STRB (immediate)	cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */
+		/*                              P U W | Rn | Rt |imm4|    |imm4|*/
+		/* STRD (immediate)	cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */
+		/* STRH (immediate)	cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */
+		/*
+		 * index = (P == '1'); add = (U == '1').
+		 * Above insns with:
+		 *    index == 0 (str{,d,h} rx, [sp], #+/-imm) or
+		 *    add == 1 (str{,d,h} rx, [sp, #+<imm>])
+		 * should be STACK_USE_NONE.
+		 * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are
+		 * required to be examined.
+		 */
+		/* STR{,B} Rt,[SP,#-n]	cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */
+		DECODE_CUSTOM	(0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX),
+
+		/* STR{D,H} Rt,[SP,#-n]	cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */
+		DECODE_CUSTOM	(0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X),
+
+		/* fall through */
+		DECODE_CUSTOM	(0, 0, STACK_USE_NONE),
+		DECODE_END
+	};
+
+	return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
+}
+
+const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
+	[PROBES_LDRSTRD] = {.checker = arm_check_stack},
+	[PROBES_STORE_EXTRA] = {.checker = arm_check_stack},
+	[PROBES_STORE] = {.checker = arm_check_stack},
+	[PROBES_LDMSTM] = {.checker = arm_check_stack},
+};
diff --git a/arch/arm/probes/kprobes/checkers-common.c b/arch/arm/probes/kprobes/checkers-common.c
new file mode 100644
index 0000000..971119c
--- /dev/null
+++ b/arch/arm/probes/kprobes/checkers-common.c
@@ -0,0 +1,101 @@
+/*
+ * arch/arm/probes/kprobes/checkers-common.c
+ *
+ * Copyright (C) 2014 Huawei Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "../decode.h"
+#include "../decode-arm.h"
+#include "checkers.h"
+
+enum probes_insn checker_stack_use_none(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	asi->stack_space = 0;
+	return INSN_GOOD_NO_SLOT;
+}
+
+enum probes_insn checker_stack_use_unknown(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	asi->stack_space = -1;
+	return INSN_GOOD_NO_SLOT;
+}
+
+#ifdef CONFIG_THUMB2_KERNEL
+enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int imm = insn & 0xff;
+	asi->stack_space = imm;
+	return INSN_GOOD_NO_SLOT;
+}
+
+/*
+ * Different from other insn uses imm8, the real addressing offset of
+ * STRD in T32 encoding should be imm8 * 4. See ARMARM description.
+ */
+enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int imm = insn & 0xff;
+	asi->stack_space = imm << 2;
+	return INSN_GOOD_NO_SLOT;
+}
+#else
+enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int imm = ((insn & 0xf00) >> 4) + (insn & 0xf);
+	asi->stack_space = imm;
+	return INSN_GOOD_NO_SLOT;
+}
+#endif
+
+enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int imm = insn & 0xfff;
+	asi->stack_space = imm;
+	return INSN_GOOD_NO_SLOT;
+}
+
+enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	unsigned int reglist = insn & 0xffff;
+	int pbit = insn & (1 << 24);
+	asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4;
+
+	return INSN_GOOD_NO_SLOT;
+}
+
+const union decode_action stack_check_actions[] = {
+	[STACK_USE_NONE] = {.decoder = checker_stack_use_none},
+	[STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown},
+#ifdef CONFIG_THUMB2_KERNEL
+	[STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx},
+	[STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd},
+#else
+	[STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x},
+#endif
+	[STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx},
+	[STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx},
+};
diff --git a/arch/arm/probes/kprobes/checkers-thumb.c b/arch/arm/probes/kprobes/checkers-thumb.c
new file mode 100644
index 0000000..d608e3b
--- /dev/null
+++ b/arch/arm/probes/kprobes/checkers-thumb.c
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/probes/kprobes/checkers-thumb.c
+ *
+ * Copyright (C) 2014 Huawei Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "../decode.h"
+#include "../decode-thumb.h"
+#include "checkers.h"
+
+static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	/*
+	 * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR
+	 * may get here. Simply mark all normal insns as STACK_USE_NONE.
+	 */
+	static const union decode_item table[] = {
+
+		/*
+		 * First, filter out all ldr insns to make our life easier.
+		 * Following load insns may come here:
+		 * LDM, LDRD, LDR.
+		 * In T32 encoding, bit 20 is enough for distinguishing
+		 * load and store. All load insns have this bit set, when
+		 * all store insns have this bit clear.
+		 */
+		DECODE_CUSTOM	(0x00100000, 0x00100000, STACK_USE_NONE),
+
+		/*
+		 * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN
+		 * if Rn or Rm is SP. T32 doesn't encode STRD.
+		 */
+		/*                                 xx | Rn | Rt |         | Rm |*/
+		/* STR (register)	1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
+		/* STRB (register)	1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
+		/* STRH (register)	1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
+		/* INVALID INSN		1111 1000 0110 xxxx xxxx 0000 00xx xxxx */
+		/* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */
+		DECODE_OR	(0xff9f0fc0, 0xf80d0000),
+		DECODE_CUSTOM	(0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN),
+
+
+		/*                                 xx | Rn | Rt | PUW|   imm8  |*/
+		/* STR (imm 8)		1111 1000 0100 1101 xxxx 110x xxxx xxxx */
+		/* STRB (imm 8)		1111 1000 0000 1101 xxxx 110x xxxx xxxx */
+		/* STRH (imm 8)		1111 1000 0010 1101 xxxx 110x xxxx xxxx */
+		/* INVALID INSN		1111 1000 0110 1101 xxxx 110x xxxx xxxx */
+		/* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */
+		DECODE_CUSTOM	(0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX),
+
+		/* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */
+
+		/*                              P U W | Rn | Rt | Rt2|   imm8  |*/
+		/* STRD (immediate)	1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */
+		/*
+		 * Only consider U == 0 and P == 1.
+		 * Also note that STRD in T32 encoding is special:
+		 * imm = ZeroExtend(imm8:'00', 32)
+		 */
+		DECODE_CUSTOM	(0xffdf0000, 0xe94d0000, STACK_USE_T32STRD),
+
+		/*                                    | Rn | */
+		/* STMDB		1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */
+		DECODE_CUSTOM	(0xffdf0000, 0xe90d0000, STACK_USE_STMDX),
+
+		/* fall through */
+		DECODE_CUSTOM	(0, 0, STACK_USE_NONE),
+		DECODE_END
+	};
+
+	return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
+}
+
+const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = {
+	[PROBES_T32_LDMSTM] = {.checker = t32_check_stack},
+	[PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack},
+	[PROBES_T32_LDRSTR] = {.checker = t32_check_stack},
+};
+
+/*
+ * See following comments. This insn must be 'push'.
+ */
+static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	unsigned int reglist = insn & 0x1ff;
+	asi->stack_space = hweight32(reglist) * 4;
+	return INSN_GOOD;
+}
+
+/*
+ * T16 encoding is simple: only the 'push' insn can need extra stack space.
+ * Other insns, like str, can only use r0-r7 as Rn.
+ */
+const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = {
+	[PROBES_T16_PUSH] = {.checker = t16_check_stack},
+};
diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h
new file mode 100644
index 0000000..bddfa0e
--- /dev/null
+++ b/arch/arm/probes/kprobes/checkers.h
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/probes/kprobes/checkers.h
+ *
+ * Copyright (C) 2014 Huawei Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef _ARM_KERNEL_PROBES_CHECKERS_H
+#define _ARM_KERNEL_PROBES_CHECKERS_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include "../decode.h"
+
+extern probes_check_t checker_stack_use_none;
+extern probes_check_t checker_stack_use_unknown;
+#ifdef CONFIG_THUMB2_KERNEL
+extern probes_check_t checker_stack_use_imm_0xx;
+#else
+extern probes_check_t checker_stack_use_imm_x0x;
+#endif
+extern probes_check_t checker_stack_use_imm_xxx;
+extern probes_check_t checker_stack_use_stmdx;
+
+enum {
+	STACK_USE_NONE,
+	STACK_USE_UNKNOWN,
+#ifdef CONFIG_THUMB2_KERNEL
+	STACK_USE_FIXED_0XX,
+	STACK_USE_T32STRD,
+#else
+	STACK_USE_FIXED_X0X,
+#endif
+	STACK_USE_FIXED_XXX,
+	STACK_USE_STMDX,
+	NUM_STACK_USE_TYPES
+};
+
+extern const union decode_action stack_check_actions[];
+
+#ifndef CONFIG_THUMB2_KERNEL
+extern const struct decode_checker arm_stack_checker[];
+#else
+#endif
+extern const struct decode_checker t32_stack_checker[];
+extern const struct decode_checker t16_stack_checker[];
+#endif
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 05/11] ARM: kprobes: disallow probing stack consuming instructions
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (3 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 04/11] ARM: kprobes: collects stack consumption for store instructions Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 06/11] ARM: kprobes: Add test cases for " Wang Nan
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

This 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.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
---
 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(-)

diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index 49fa0df..56f9ac6 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -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
diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index ccf9af3..f0a1ee8 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -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
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 2f5555d..672b219 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -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
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 74f3dc3..3a58db4 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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;
 }
 
diff --git a/arch/arm/probes/kprobes/test-arm.c b/arch/arm/probes/kprobes/test-arm.c
index d9a1255..fdeb300 100644
--- a/arch/arm/probes/kprobes/test-arm.c
+++ b/arch/arm/probes/kprobes/test-arm.c
@@ -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,"]")
 
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 06/11] ARM: kprobes: Add test cases for stack consuming instructions
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (4 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 05/11] ARM: kprobes: disallow probing stack consuming instructions Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 07/11] kprobes: Pass the original kprobe for preparing optimized kprobe Wang Nan
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

From: "Jon Medhurst (Tixy)" <tixy@linaro.org>

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 <tixy@linaro.org>
---
 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(-)

diff --git a/arch/arm/probes/kprobes/test-arm.c b/arch/arm/probes/kprobes/test-arm.c
index fdeb300..9b3b1b4 100644
--- a/arch/arm/probes/kprobes/test-arm.c
+++ b/arch/arm/probes/kprobes/test-arm.c
@@ -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]")			\
diff --git a/arch/arm/probes/kprobes/test-core.c b/arch/arm/probes/kprobes/test-core.c
index 7ab633d..7c5ddd5 100644
--- a/arch/arm/probes/kprobes/test-core.c
+++ b/arch/arm/probes/kprobes/test-core.c
@@ -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;
diff --git a/arch/arm/probes/kprobes/test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c
index 6c6e9a9..e8cf193 100644
--- a/arch/arm/probes/kprobes/test-thumb.c
+++ b/arch/arm/probes/kprobes/test-thumb.c
@@ -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]")
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 07/11] kprobes: Pass the original kprobe for preparing optimized kprobe
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (5 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 06/11] ARM: kprobes: Add test cases for " Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

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 <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 arch/x86/kernel/kprobes/opt.c | 3 ++-
 include/linux/kprobes.h       | 3 ++-
 kernel/kprobes.c              | 4 ++--
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 7c523bb..0dd8d08 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -322,7 +322,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;
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 5297f9f..1ab5475 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -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,
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 06f5830..bad4e95 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -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;
 }
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (6 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 07/11] kprobes: Pass the original kprobe for preparing optimized kprobe Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-07 13:01   ` Jon Medhurst (Tixy)
                     ` (2 more replies)
  2015-01-05 11:29 ` [PATCH v19 09/11] ARM: kprobes: Fix unreliable MRS instruction tests Wang Nan
                   ` (3 subsequent siblings)
  11 siblings, 3 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

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() 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.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Jon Medhurst (Tixy) <tixy@linaro.org>
Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
Cc: Will Deacon <will.deacon@arm.com>
---
 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.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 97d07ed..3d5dc2d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -60,6 +60,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
diff --git a/arch/arm/kernel/insn.h b/arch/arm/include/asm/insn.h
similarity index 100%
rename from arch/arm/kernel/insn.h
rename to arch/arm/include/asm/insn.h
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index 56f9ac6..50ff3bc 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -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 */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 9c51a43..902397d 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -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 patch.o
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index b8c75e4..709ee1d 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -20,8 +20,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} */
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
index d8da075..e39cbf4 100644
--- a/arch/arm/kernel/jump_label.c
+++ b/arch/arm/kernel/jump_label.c
@@ -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
 
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
index bc8d504..76a36bf 100644
--- a/arch/arm/probes/kprobes/Makefile
+++ b/arch/arm/probes/kprobes/Makefile
@@ -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
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 3a58db4..a4ec240 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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)
diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
index f88c79f..b3036c5 100644
--- a/arch/arm/probes/kprobes/core.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -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);
diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c
new file mode 100644
index 0000000..6a60df3
--- /dev/null
+++ b/arch/arm/probes/kprobes/opt-arm.c
@@ -0,0 +1,317 @@
+/*
+ *  Kernel Probes Jump Optimization (Optprobes)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ * Copyright (C) Hitachi Ltd., 2012
+ * Copyright (C) Huawei Inc., 2014
+ */
+
+#include <linux/kprobes.h>
+#include <linux/jump_label.h>
+#include <asm/kprobes.h>
+#include <asm/cacheflush.h>
+/* for arm_gen_branch */
+#include <asm/insn.h>
+/* for patch_text */
+#include <asm/patch.h>
+
+#include "core.h"
+
+/*
+ * NOTE: the first sub and add instruction will be modified according
+ * to the stack cost of the instruction.
+ */
+asm (
+			".global optprobe_template_entry\n"
+			"optprobe_template_entry:\n"
+			".global optprobe_template_sub_sp\n"
+			"optprobe_template_sub_sp:"
+			"	sub	sp, sp, #0xff\n"
+			"	stmia	sp, {r0 - r14} \n"
+			".global optprobe_template_add_sp\n"
+			"optprobe_template_add_sp:"
+			"	add	r3, sp, #0xff\n"
+			"	str	r3, [sp, #52]\n"
+			"	mrs	r4, cpsr\n"
+			"	str	r4, [sp, #64]\n"
+			"	mov	r1, sp\n"
+			"	ldr	r0, 1f\n"
+			"	ldr	r2, 2f\n"
+			/*
+			 * AEABI requires an 8-bytes alignment stack. If
+			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
+			 * alloc more bytes here.
+			 */
+			"	and	r4, sp, #4\n"
+			"	sub	sp, sp, r4\n"
+			"	blx	r2\n"
+			"	add	sp, sp, r4\n"
+			"	ldr	r1, [sp, #64]\n"
+			"	tst	r1, #"__stringify(PSR_T_BIT)"\n"
+			"	ldrne	r2, [sp, #60]\n"
+			"	orrne	r2, #1\n"
+			"	strne	r2, [sp, #60] @ set bit0 of PC for thumb\n"
+			"	msr	cpsr_cxsf, r1\n"
+			"	ldmia	sp, {r0 - r15}\n"
+			".global optprobe_template_val\n"
+			"optprobe_template_val:\n"
+			"1:	.long 0\n"
+			".global optprobe_template_call\n"
+			"optprobe_template_call:\n"
+			"2:	.long 0\n"
+			".global optprobe_template_end\n"
+			"optprobe_template_end:\n");
+
+#define TMPL_VAL_IDX \
+	((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry)
+#define TMPL_CALL_IDX \
+	((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry)
+#define TMPL_END_IDX \
+	((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry)
+#define TMPL_ADD_SP \
+	((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
+#define TMPL_SUB_SP \
+	((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
+
+/*
+ * ARM can always optimize an instruction when using ARM ISA, except
+ * instructions like 'str r0, [sp, r1]' which store to stack and unable
+ * to determine stack space consumption statically.
+ */
+int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
+{
+	return optinsn->insn != NULL;
+}
+
+/*
+ * In ARM ISA, kprobe opt always replace one instruction (4 bytes
+ * aligned and 4 bytes long). It is impossible to encounter another
+ * kprobe in the address range. So always return 0.
+ */
+int arch_check_optimized_kprobe(struct optimized_kprobe *op)
+{
+	return 0;
+}
+
+/* Caller must ensure addr & 3 == 0 */
+static int can_optimize(struct kprobe *kp)
+{
+	if (kp->ainsn.stack_space < 0)
+		return 0;
+	/*
+	 * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'.
+	 * Number larger than 255 needs special encoding.
+	 */
+	if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs))
+		return 0;
+	return 1;
+}
+
+/* Free optimized instruction slot */
+static void
+__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
+{
+	if (op->optinsn.insn) {
+		free_optinsn_slot(op->optinsn.insn, dirty);
+		op->optinsn.insn = NULL;
+	}
+}
+
+extern void kprobe_handler(struct pt_regs *regs);
+
+static void
+optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct kprobe *p = &op->kp;
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	/* Save skipped registers */
+	regs->ARM_pc = (unsigned long)op->kp.addr;
+	regs->ARM_ORIG_r0 = ~0UL;
+
+	local_irq_save(flags);
+
+	if (kprobe_running()) {
+		kprobes_inc_nmissed_count(&op->kp);
+	} else {
+		__this_cpu_write(current_kprobe, &op->kp);
+		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+		opt_pre_handler(&op->kp, regs);
+		__this_cpu_write(current_kprobe, NULL);
+	}
+
+	/* In each case, we must singlestep the replaced instruction. */
+	op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
+
+	local_irq_restore(flags);
+}
+
+int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
+{
+	kprobe_opcode_t *code;
+	unsigned long rel_chk;
+	unsigned long val;
+	unsigned long stack_protect = sizeof(struct pt_regs);
+
+	if (!can_optimize(orig))
+		return -EILSEQ;
+
+	code = get_optinsn_slot();
+	if (!code)
+		return -ENOMEM;
+
+	/*
+	 * Verify if the address gap is in 32MiB range, because this uses
+	 * a relative jump.
+	 *
+	 * kprobe opt use a 'b' instruction to branch to optinsn.insn.
+	 * According to ARM manual, branch instruction is:
+	 *
+	 *   31  28 27           24 23             0
+	 *  +------+---+---+---+---+----------------+
+	 *  | cond | 1 | 0 | 1 | 0 |      imm24     |
+	 *  +------+---+---+---+---+----------------+
+	 *
+	 * imm24 is a signed 24 bits integer. The real branch offset is computed
+	 * by: imm32 = SignExtend(imm24:'00', 32);
+	 *
+	 * So the maximum forward branch should be:
+	 *   (0x007fffff << 2) = 0x01fffffc =  0x1fffffc
+	 * The maximum backword branch should be:
+	 *   (0xff800000 << 2) = 0xfe000000 = -0x2000000
+	 *
+	 * We can simply check (rel & 0xfe000003):
+	 *  if rel is positive, (rel & 0xfe000000) shoule be 0
+	 *  if rel is negitive, (rel & 0xfe000000) should be 0xfe000000
+	 *  the last '3' is used for alignment checking.
+	 */
+	rel_chk = (unsigned long)((long)code -
+			(long)orig->addr + 8) & 0xfe000003;
+
+	if ((rel_chk != 0) && (rel_chk != 0xfe000000)) {
+		/*
+		 * Different from x86, we free code buf directly instead of
+		 * calling __arch_remove_optimized_kprobe() because
+		 * we have not fill any field in op.
+		 */
+		free_optinsn_slot(code, 0);
+		return -ERANGE;
+	}
+
+	/* Copy arch-dep-instance from template. */
+	memcpy(code, &optprobe_template_entry,
+			TMPL_END_IDX * sizeof(kprobe_opcode_t));
+
+	/* Adjust buffer according to instruction. */
+	BUG_ON(orig->ainsn.stack_space < 0);
+
+	stack_protect += orig->ainsn.stack_space;
+
+	/* Should have been filtered by can_optimize(). */
+	BUG_ON(stack_protect > 255);
+
+	/* Create a 'sub sp, sp, #<stack_protect>' */
+	code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect);
+	/* Create a 'add r3, sp, #<stack_protect>' */
+	code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect);
+
+	/* Set probe information */
+	val = (unsigned long)op;
+	code[TMPL_VAL_IDX] = val;
+
+	/* Set probe function call */
+	val = (unsigned long)optimized_callback;
+	code[TMPL_CALL_IDX] = val;
+
+	flush_icache_range((unsigned long)code,
+			   (unsigned long)(&code[TMPL_END_IDX]));
+
+	/* Set op->optinsn.insn means prepared. */
+	op->optinsn.insn = code;
+	return 0;
+}
+
+void __kprobes arch_optimize_kprobes(struct list_head *oplist)
+{
+	struct optimized_kprobe *op, *tmp;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		unsigned long insn;
+		WARN_ON(kprobe_disabled(&op->kp));
+
+		/*
+		 * Backup instructions which will be replaced
+		 * by jump address
+		 */
+		memcpy(op->optinsn.copied_insn, op->kp.addr,
+				RELATIVEJUMP_SIZE);
+
+		insn = arm_gen_branch((unsigned long)op->kp.addr,
+				(unsigned long)op->optinsn.insn);
+		BUG_ON(insn == 0);
+
+		/*
+		 * Make it a conditional branch if replaced insn
+		 * is consitional
+		 */
+		insn = (__mem_to_opcode_arm(
+			  op->optinsn.copied_insn[0]) & 0xf0000000) |
+			(insn & 0x0fffffff);
+
+		/*
+		 * Similar to __arch_disarm_kprobe, operations which
+		 * removing breakpoints must be wrapped by stop_machine
+		 * to avoid racing.
+		 */
+		kprobes_remove_breakpoint(op->kp.addr, insn);
+
+		list_del_init(&op->list);
+	}
+}
+
+void arch_unoptimize_kprobe(struct optimized_kprobe *op)
+{
+	arch_arm_kprobe(&op->kp);
+}
+
+/*
+ * Recover original instructions and breakpoints from relative jumps.
+ * Caller must call with locking kprobe_mutex.
+ */
+void arch_unoptimize_kprobes(struct list_head *oplist,
+			    struct list_head *done_list)
+{
+	struct optimized_kprobe *op, *tmp;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		arch_unoptimize_kprobe(op);
+		list_move(&op->list, done_list);
+	}
+}
+
+int arch_within_optimized_kprobe(struct optimized_kprobe *op,
+				unsigned long addr)
+{
+	return ((unsigned long)op->kp.addr <= addr &&
+		(unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr);
+}
+
+void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
+{
+	__arch_remove_optimized_kprobe(op, 1);
+}
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 09/11] ARM: kprobes: Fix unreliable MRS instruction tests
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (7 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-05 11:29 ` [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction Wang Nan
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

From: "Jon Medhurst (Tixy)" <tixy@linaro.org>

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.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
---
 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(-)

diff --git a/arch/arm/probes/kprobes/test-arm.c b/arch/arm/probes/kprobes/test-arm.c
index 9b3b1b4..e72b07e 100644
--- a/arch/arm/probes/kprobes/test-arm.c
+++ b/arch/arm/probes/kprobes/test-arm.c
@@ -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")
diff --git a/arch/arm/probes/kprobes/test-core.c b/arch/arm/probes/kprobes/test-core.c
index 7c5ddd5..e495127 100644
--- a/arch/arm/probes/kprobes/test-core.c
+++ b/arch/arm/probes/kprobes/test-core.c
@@ -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;
diff --git a/arch/arm/probes/kprobes/test-core.h b/arch/arm/probes/kprobes/test-core.h
index 9991754..9428520 100644
--- a/arch/arm/probes/kprobes/test-core.h
+++ b/arch/arm/probes/kprobes/test-core.h
@@ -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.
diff --git a/arch/arm/probes/kprobes/test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c
index e8cf193..b683b45 100644
--- a/arch/arm/probes/kprobes/test-thumb.c
+++ b/arch/arm/probes/kprobes/test-thumb.c
@@ -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")
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction.
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (8 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 09/11] ARM: kprobes: Fix unreliable MRS instruction tests Wang Nan
@ 2015-01-05 11:29 ` Wang Nan
  2015-01-13 15:01   ` Jon Medhurst (Tixy)
  2015-01-05 11:34 ` [PATCH v19 11/11] ARM: optprobes: execute instruction during restoring if possible Wang Nan
  2015-01-07 13:40 ` [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Jon Medhurst (Tixy)
  11 siblings, 1 reply; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:29 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

This patch utilizes previous introduced checker to check register usage
for probed ARM instruction and saves it in a mask. Futher patch will
use such information to avoid simuation or emulation.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 arch/arm/include/asm/probes.h          |  10 +++
 arch/arm/probes/decode.c               |   7 ++
 arch/arm/probes/kprobes/actions-arm.c  |   2 +-
 arch/arm/probes/kprobes/checkers-arm.c | 124 +++++++++++++++++++++++++++++++++
 arch/arm/probes/kprobes/checkers.h     |   1 +
 5 files changed, 143 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index f0a1ee8..27b65b7 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -41,6 +41,16 @@ struct arch_probes_insn {
 	probes_insn_singlestep_t	*insn_singlestep;
 	probes_insn_fn_t		*insn_fn;
 	int stack_space;
+
+	/* Use 1 bit for a register. */
+#define REG_NO_USE	(0)
+#define REG_USE		(1)
+#define __register_usage_flag(n, f)	((f) << (n))
+#define __clean_register_flag(m, n)	((m) & (~(1 << (n))))
+#define __set_register_flag(m, n, f)	(__clean_register_flag(m, n) | __register_usage_flag(n, f))
+#define set_register_nouse(m, n)	do {(m) = __set_register_flag(m, n, REG_NO_USE);} while(0)
+#define set_register_use(m, n)		do {(m) = __set_register_flag(m, n, REG_USE);} while(0)
+	unsigned long register_usage_flag;
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
index f9d7c42..40f9402 100644
--- a/arch/arm/probes/decode.c
+++ b/arch/arm/probes/decode.c
@@ -435,6 +435,13 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
 	 */
 	asi->stack_space = 0;
 
+	/*
+	 * Similay to stack_space, register_usage_flag is filled by
+	 * checkers. Its default value is set to ~0, which is 'all
+	 * registers are used', to prevent any potential optimization.
+	 */
+	asi->register_usage_flag = ~(0UL);
+
 	if (emulate)
 		insn = prepare_emulated_insn(insn, asi, thumb);
 
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 4fedd4c..26e435b 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -340,4 +340,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[] = {arm_stack_checker, NULL};
+const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c
index f817663..1929225 100644
--- a/arch/arm/probes/kprobes/checkers-arm.c
+++ b/arch/arm/probes/kprobes/checkers-arm.c
@@ -97,3 +97,127 @@ const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
 	[PROBES_STORE] = {.checker = arm_check_stack},
 	[PROBES_LDMSTM] = {.checker = arm_check_stack},
 };
+
+static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	asi->register_usage_flag = 0;
+	return INSN_GOOD;
+}
+
+static void __arm_check_regs(probes_opcode_t insn,
+		const struct decode_header *h,
+		int *quintuple)
+{
+	int i;
+	u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
+	probes_opcode_t mask, shifted;
+
+	memset(quintuple, 0xff, sizeof(int) * 5);
+	for (i = 0, shifted = insn, mask = 0xf; regs != 0;
+			regs >>= 4, mask <<= 4, shifted >>= 4, i++)
+		if (regs & 0xf)
+			quintuple[i] = shifted & 0xf;
+}
+
+static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int quintuple[5], i;
+	asi->register_usage_flag = 0;
+	__arm_check_regs(insn, h, quintuple);
+	for (i = 0; i < 5; i++) {
+		int r = quintuple[i];
+		if (r < 0)
+			continue;
+		set_register_use(asi->register_usage_flag, r);
+	}
+
+	return INSN_GOOD;
+}
+
+static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	unsigned int reglist = insn & 0xffff;
+	unsigned int rn = (insn >> 16) & 0xf;
+	int i;
+
+	set_register_use(asi->register_usage_flag, rn);
+	for (i = 0; reglist > 0; i++, reglist >>= 1)
+		if (reglist & 1)
+			set_register_use(asi->register_usage_flag, i);
+	return INSN_GOOD;
+}
+
+static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	/* should be 'mov ip, sp' */
+	set_register_use(asi->register_usage_flag, 12);
+	set_register_use(asi->register_usage_flag, 13);
+	return INSN_GOOD;
+}
+
+/*
+ *                                    | Rn |Rt/d|         | Rm |
+ * LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
+ * STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
+ *                                    | Rn |Rt/d|         |imm4L|
+ * LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
+ * STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
+ *
+ * Such instructions access Rt/d and its next register, so different
+ * from others, a specific checker is required for Rt/d and Rt2/d2.
+ */
+static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int quintuple[5], rn, rdt, rm;
+	asi->register_usage_flag = 0;
+	__arm_check_regs(insn, h, quintuple);
+
+	rn = quintuple[4];
+	rdt = quintuple[3];
+	rm = quintuple[0];
+        set_register_use(asi->register_usage_flag, rn);
+        set_register_use(asi->register_usage_flag, rdt);
+        set_register_use(asi->register_usage_flag, rdt + 1);
+	if (rm >= 0)
+		set_register_use(asi->register_usage_flag, rm);
+
+	return INSN_GOOD;
+}
+
+
+const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
+	[PROBES_EMULATE_NONE] = {.checker = arm_check_regs_nouse},
+	[PROBES_SIMULATE_NOP] = {.checker = arm_check_regs_nouse},
+	[PROBES_MRS] = {.checker = arm_check_regs_normal},
+	[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL1] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL2] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
+	[PROBES_LOAD] = {.checker = arm_check_regs_normal},
+	[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
+	[PROBES_STORE] = {.checker = arm_check_regs_normal},
+	[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
+	[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
+	[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
+	[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
+	[PROBES_REV] = {.checker = arm_check_regs_normal},
+	[PROBES_MMI] = {.checker = arm_check_regs_normal},
+	[PROBES_PACK] = {.checker = arm_check_regs_normal},
+	[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
+	[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
+	[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
+	[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
+	[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
+	[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
+};
diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h
index bddfa0e..cf6c9e7 100644
--- a/arch/arm/probes/kprobes/checkers.h
+++ b/arch/arm/probes/kprobes/checkers.h
@@ -47,6 +47,7 @@ extern const union decode_action stack_check_actions[];
 
 #ifndef CONFIG_THUMB2_KERNEL
 extern const struct decode_checker arm_stack_checker[];
+extern const struct decode_checker arm_regs_checker[];
 #else
 #endif
 extern const struct decode_checker t32_stack_checker[];
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v19 11/11] ARM: optprobes: execute instruction during restoring if possible.
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (9 preceding siblings ...)
  2015-01-05 11:29 ` [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction Wang Nan
@ 2015-01-05 11:34 ` Wang Nan
  2015-01-07 13:40 ` [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Jon Medhurst (Tixy)
  11 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-05 11:34 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

This patch removes software emulation or simulation for most of probed
instructions. If the instruction doesn't use PC relative addressing,
it will be translated into following instructions in the restore code
in code template:

 ldmia {r0 - r14}  // restore all instruction except PC
 <instruction>     // direct execute the probed instruction
 b next_insn       // branch to next instruction.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 arch/arm/include/asm/kprobes.h    |  3 +++
 arch/arm/include/asm/probes.h     |  1 +
 arch/arm/probes/kprobes/opt-arm.c | 52 +++++++++++++++++++++++++++++++++++++--
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index 50ff3bc..3ea9be5 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -57,6 +57,9 @@ 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;
+extern __visible kprobe_opcode_t optprobe_template_restore_begin;
+extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn;
+extern __visible kprobe_opcode_t optprobe_template_restore_end;
 
 #define MAX_OPTIMIZED_LENGTH	4
 #define MAX_OPTINSN_SIZE				\
diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index 27b65b7..f6b0bad 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -51,6 +51,7 @@ struct arch_probes_insn {
 #define set_register_nouse(m, n)	do {(m) = __set_register_flag(m, n, REG_NO_USE);} while(0)
 #define set_register_use(m, n)		do {(m) = __set_register_flag(m, n, REG_USE);} while(0)
 	unsigned long register_usage_flag;
+	bool kprobe_direct_exec;
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c
index 6a60df3..15b37c0 100644
--- a/arch/arm/probes/kprobes/opt-arm.c
+++ b/arch/arm/probes/kprobes/opt-arm.c
@@ -32,6 +32,14 @@
 #include "core.h"
 
 /*
+ * See register_usage_flag. If the probed instruction doesn't use PC,
+ * we can copy it into template and have it executed directly without
+ * simulation or emulation.
+ */
+#define ARM_REG_PC	15
+#define can_kprobe_direct_exec(m)	(!test_bit(ARM_REG_PC, &(m)))
+
+/*
  * NOTE: the first sub and add instruction will be modified according
  * to the stack cost of the instruction.
  */
@@ -66,7 +74,15 @@ asm (
 			"	orrne	r2, #1\n"
 			"	strne	r2, [sp, #60] @ set bit0 of PC for thumb\n"
 			"	msr	cpsr_cxsf, r1\n"
+			".global optprobe_template_restore_begin\n"
+			"optprobe_template_restore_begin:\n"
 			"	ldmia	sp, {r0 - r15}\n"
+			".global optprobe_template_restore_orig_insn\n"
+			"optprobe_template_restore_orig_insn:\n"
+			"	nop\n"
+			".global optprobe_template_restore_end\n"
+			"optprobe_template_restore_end:\n"
+			"	nop\n"
 			".global optprobe_template_val\n"
 			"optprobe_template_val:\n"
 			"1:	.long 0\n"
@@ -86,6 +102,12 @@ asm (
 	((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
 #define TMPL_SUB_SP \
 	((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
+#define TMPL_RESTORE_BEGIN \
+	((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry)
+#define TMPL_RESTORE_ORIGN_INSN \
+	((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry)
+#define TMPL_RESTORE_END \
+	((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry)
 
 /*
  * ARM can always optimize an instruction when using ARM ISA, except
@@ -155,8 +177,12 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
 		__this_cpu_write(current_kprobe, NULL);
 	}
 
-	/* In each case, we must singlestep the replaced instruction. */
-	op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
+	/*
+	 * We singlestep the replaced instruction only when it can't be
+	 * executed directly during restore.
+	 */
+	if (!p->ainsn.kprobe_direct_exec)
+		op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
 
 	local_irq_restore(flags);
 }
@@ -238,6 +264,28 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *or
 	val = (unsigned long)optimized_callback;
 	code[TMPL_CALL_IDX] = val;
 
+	/* If possible, copy insn and have it executed during restore */
+	orig->ainsn.kprobe_direct_exec = false;
+	if (can_kprobe_direct_exec(orig->ainsn.register_usage_flag)) {
+		kprobe_opcode_t final_branch = arm_gen_branch(
+				(unsigned long)(&code[TMPL_RESTORE_END]),
+				(unsigned long)(op->kp.addr) + 4);
+		if (final_branch != 0) {
+			/*
+			 * Replace original 'ldmia sp, {r0 - r15}' with
+			 * 'ldmia {r0 - r14}', restore all registers except pc.
+			 */
+			code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff);
+
+			/* The original probed instruction */
+			code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode);
+
+			/* Jump back to next instruction */
+			code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch);
+			orig->ainsn.kprobe_direct_exec = true;
+		}
+	}
+
 	flush_icache_range((unsigned long)code,
 			   (unsigned long)(&code[TMPL_END_IDX]));
 
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions.
  2015-01-05 11:29 ` [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions Wang Nan
@ 2015-01-07 11:50   ` Jon Medhurst (Tixy)
  0 siblings, 0 replies; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-07 11:50 UTC (permalink / raw)
  To: Wang Nan, David Long
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On Mon, 2015-01-05 at 19:29 +0800, Wang Nan wrote:
> There are 3 actions which is never used:
> 
>  PROBES_MOV_HALFWORD,
>  PROBES_SEV,
>  PROBES_WFE,
> 
> This patch removes them.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>

I think that PROBES_MOV_HALFWORD should be used, for MOVW and MOVT.
Currently those instructions use PROBES_DATA_PROCESSING_IMM which,
whilst it will work it ends up using a less efficient emulation routine
than necessary.

The other unused actions, PROBES_SEV and PROBES_WFE, could possibly be
removed as redundant, but there are are Thumb equivalents for those
which are used, so for symmetry I think we should use them. That will
let us remove PROBES_EMULATE_NONE and PROBES_SIMULATE_NOP.

So how about the following patch instead...

----------------------------------------------------------------------------

From: Jon Medhurst <tixy@linaro.org>
Date: Wed, 7 Jan 2015 11:42:30 +0000
Subject: [PATCH] ARM: probes: Use correct action types for MOVW, SEV and WFI

This doesn't correct any bugs when probing these instructions but makes
MOVW slightly faster and makes everything more symmetric with the Thumb
instruction cases.

We can also remove the now redundant PROBES_EMULATE_NONE and
PROBES_SIMULATE_NOP actions.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
---
 arch/arm/probes/decode-arm.c          | 6 +++---
 arch/arm/probes/decode-arm.h          | 2 --
 arch/arm/probes/kprobes/actions-arm.c | 2 --
 arch/arm/probes/uprobes/actions-arm.c | 2 --
 4 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/arch/arm/probes/decode-arm.c b/arch/arm/probes/decode-arm.c
index f46d8fc..f72c33a 100644
--- a/arch/arm/probes/decode-arm.c
+++ b/arch/arm/probes/decode-arm.c
@@ -370,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = {
 
 	/* MOVW			cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
 	/* MOVT			cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
-	DECODE_EMULATEX	(0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM,
+	DECODE_EMULATEX	(0x0fb00000, 0x03000000, PROBES_MOV_HALFWORD,
 						 REGS(0, NOPC, 0, 0, 0)),
 
 	/* YIELD		cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
 	DECODE_OR	(0x0fff00ff, 0x03200001),
 	/* SEV			cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
-	DECODE_EMULATE	(0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE),
+	DECODE_EMULATE	(0x0fff00ff, 0x03200004, PROBES_SEV),
 	/* NOP			cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
 	/* WFE			cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
 	/* WFI			cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
-	DECODE_SIMULATE	(0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP),
+	DECODE_SIMULATE	(0x0fff00fc, 0x03200000, PROBES_WFE),
 	/* DBG			cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
 	/* unallocated hints	cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
 	/* MSR (immediate)	cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
diff --git a/arch/arm/probes/decode-arm.h b/arch/arm/probes/decode-arm.h
index a7b0398..b3b80f6 100644
--- a/arch/arm/probes/decode-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -18,8 +18,6 @@
 #include "decode.h"
 
 enum probes_arm_action {
-	PROBES_EMULATE_NONE,
-	PROBES_SIMULATE_NOP,
 	PROBES_PRELOAD_IMM,
 	PROBES_PRELOAD_REG,
 	PROBES_BRANCH_IMM,
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 1e67839..06988ef 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -303,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
 }
 
 const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
-	[PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
-	[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
 	[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
 	[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
 	[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
diff --git a/arch/arm/probes/uprobes/actions-arm.c b/arch/arm/probes/uprobes/actions-arm.c
index 1dd4916..76eb449 100644
--- a/arch/arm/probes/uprobes/actions-arm.c
+++ b/arch/arm/probes/uprobes/actions-arm.c
@@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn,
 }
 
 const union decode_action uprobes_probes_actions[] = {
-	[PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
-	[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
 	[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
 	[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
 	[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
-- 
2.1.4




^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
@ 2015-01-07 13:01   ` Jon Medhurst (Tixy)
  2015-01-09  6:37   ` [PATCH v20 " Wang Nan
  2015-01-09  6:51   ` [PATCH v19 " Wang Nan
  2 siblings, 0 replies; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-07 13:01 UTC (permalink / raw)
  To: Wang Nan
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On Mon, 2015-01-05 at 19:29 +0800, Wang Nan wrote:
> 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() 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.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Jon Medhurst (Tixy) <tixy@linaro.org>

Reviewed-by: Jon Medhurst (<tixy@linaro.org>


> Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
>  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.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 97d07ed..3d5dc2d 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -60,6 +60,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
> diff --git a/arch/arm/kernel/insn.h b/arch/arm/include/asm/insn.h
> similarity index 100%
> rename from arch/arm/kernel/insn.h
> rename to arch/arm/include/asm/insn.h
> diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
> index 56f9ac6..50ff3bc 100644
> --- a/arch/arm/include/asm/kprobes.h
> +++ b/arch/arm/include/asm/kprobes.h
> @@ -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 */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 9c51a43..902397d 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -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 patch.o
> diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
> index b8c75e4..709ee1d 100644
> --- a/arch/arm/kernel/ftrace.c
> +++ b/arch/arm/kernel/ftrace.c
> @@ -20,8 +20,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} */
> diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
> index d8da075..e39cbf4 100644
> --- a/arch/arm/kernel/jump_label.c
> +++ b/arch/arm/kernel/jump_label.c
> @@ -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
>  
> diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
> index bc8d504..76a36bf 100644
> --- a/arch/arm/probes/kprobes/Makefile
> +++ b/arch/arm/probes/kprobes/Makefile
> @@ -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
> diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
> index 3a58db4..a4ec240 100644
> --- a/arch/arm/probes/kprobes/core.c
> +++ b/arch/arm/probes/kprobes/core.c
> @@ -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)
> diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
> index f88c79f..b3036c5 100644
> --- a/arch/arm/probes/kprobes/core.h
> +++ b/arch/arm/probes/kprobes/core.h
> @@ -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);
> diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c
> new file mode 100644
> index 0000000..6a60df3
> --- /dev/null
> +++ b/arch/arm/probes/kprobes/opt-arm.c
> @@ -0,0 +1,317 @@
> +/*
> + *  Kernel Probes Jump Optimization (Optprobes)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + *
> + * Copyright (C) IBM Corporation, 2002, 2004
> + * Copyright (C) Hitachi Ltd., 2012
> + * Copyright (C) Huawei Inc., 2014
> + */
> +
> +#include <linux/kprobes.h>
> +#include <linux/jump_label.h>
> +#include <asm/kprobes.h>
> +#include <asm/cacheflush.h>
> +/* for arm_gen_branch */
> +#include <asm/insn.h>
> +/* for patch_text */
> +#include <asm/patch.h>
> +
> +#include "core.h"
> +
> +/*
> + * NOTE: the first sub and add instruction will be modified according
> + * to the stack cost of the instruction.
> + */
> +asm (
> +			".global optprobe_template_entry\n"
> +			"optprobe_template_entry:\n"
> +			".global optprobe_template_sub_sp\n"
> +			"optprobe_template_sub_sp:"
> +			"	sub	sp, sp, #0xff\n"
> +			"	stmia	sp, {r0 - r14} \n"
> +			".global optprobe_template_add_sp\n"
> +			"optprobe_template_add_sp:"
> +			"	add	r3, sp, #0xff\n"
> +			"	str	r3, [sp, #52]\n"
> +			"	mrs	r4, cpsr\n"
> +			"	str	r4, [sp, #64]\n"
> +			"	mov	r1, sp\n"
> +			"	ldr	r0, 1f\n"
> +			"	ldr	r2, 2f\n"
> +			/*
> +			 * AEABI requires an 8-bytes alignment stack. If
> +			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
> +			 * alloc more bytes here.
> +			 */
> +			"	and	r4, sp, #4\n"
> +			"	sub	sp, sp, r4\n"
> +			"	blx	r2\n"
> +			"	add	sp, sp, r4\n"
> +			"	ldr	r1, [sp, #64]\n"
> +			"	tst	r1, #"__stringify(PSR_T_BIT)"\n"
> +			"	ldrne	r2, [sp, #60]\n"
> +			"	orrne	r2, #1\n"
> +			"	strne	r2, [sp, #60] @ set bit0 of PC for thumb\n"
> +			"	msr	cpsr_cxsf, r1\n"
> +			"	ldmia	sp, {r0 - r15}\n"
> +			".global optprobe_template_val\n"
> +			"optprobe_template_val:\n"
> +			"1:	.long 0\n"
> +			".global optprobe_template_call\n"
> +			"optprobe_template_call:\n"
> +			"2:	.long 0\n"
> +			".global optprobe_template_end\n"
> +			"optprobe_template_end:\n");
> +
> +#define TMPL_VAL_IDX \
> +	((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry)
> +#define TMPL_CALL_IDX \
> +	((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry)
> +#define TMPL_END_IDX \
> +	((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry)
> +#define TMPL_ADD_SP \
> +	((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
> +#define TMPL_SUB_SP \
> +	((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
> +
> +/*
> + * ARM can always optimize an instruction when using ARM ISA, except
> + * instructions like 'str r0, [sp, r1]' which store to stack and unable
> + * to determine stack space consumption statically.
> + */
> +int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
> +{
> +	return optinsn->insn != NULL;
> +}
> +
> +/*
> + * In ARM ISA, kprobe opt always replace one instruction (4 bytes
> + * aligned and 4 bytes long). It is impossible to encounter another
> + * kprobe in the address range. So always return 0.
> + */
> +int arch_check_optimized_kprobe(struct optimized_kprobe *op)
> +{
> +	return 0;
> +}
> +
> +/* Caller must ensure addr & 3 == 0 */
> +static int can_optimize(struct kprobe *kp)
> +{
> +	if (kp->ainsn.stack_space < 0)
> +		return 0;
> +	/*
> +	 * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'.
> +	 * Number larger than 255 needs special encoding.
> +	 */
> +	if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs))
> +		return 0;
> +	return 1;
> +}
> +
> +/* Free optimized instruction slot */
> +static void
> +__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
> +{
> +	if (op->optinsn.insn) {
> +		free_optinsn_slot(op->optinsn.insn, dirty);
> +		op->optinsn.insn = NULL;
> +	}
> +}
> +
> +extern void kprobe_handler(struct pt_regs *regs);
> +
> +static void
> +optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
> +{
> +	unsigned long flags;
> +	struct kprobe *p = &op->kp;
> +	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
> +
> +	/* Save skipped registers */
> +	regs->ARM_pc = (unsigned long)op->kp.addr;
> +	regs->ARM_ORIG_r0 = ~0UL;
> +
> +	local_irq_save(flags);
> +
> +	if (kprobe_running()) {
> +		kprobes_inc_nmissed_count(&op->kp);
> +	} else {
> +		__this_cpu_write(current_kprobe, &op->kp);
> +		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> +		opt_pre_handler(&op->kp, regs);
> +		__this_cpu_write(current_kprobe, NULL);
> +	}
> +
> +	/* In each case, we must singlestep the replaced instruction. */
> +	op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
> +
> +	local_irq_restore(flags);
> +}
> +
> +int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
> +{
> +	kprobe_opcode_t *code;
> +	unsigned long rel_chk;
> +	unsigned long val;
> +	unsigned long stack_protect = sizeof(struct pt_regs);
> +
> +	if (!can_optimize(orig))
> +		return -EILSEQ;
> +
> +	code = get_optinsn_slot();
> +	if (!code)
> +		return -ENOMEM;
> +
> +	/*
> +	 * Verify if the address gap is in 32MiB range, because this uses
> +	 * a relative jump.
> +	 *
> +	 * kprobe opt use a 'b' instruction to branch to optinsn.insn.
> +	 * According to ARM manual, branch instruction is:
> +	 *
> +	 *   31  28 27           24 23             0
> +	 *  +------+---+---+---+---+----------------+
> +	 *  | cond | 1 | 0 | 1 | 0 |      imm24     |
> +	 *  +------+---+---+---+---+----------------+
> +	 *
> +	 * imm24 is a signed 24 bits integer. The real branch offset is computed
> +	 * by: imm32 = SignExtend(imm24:'00', 32);
> +	 *
> +	 * So the maximum forward branch should be:
> +	 *   (0x007fffff << 2) = 0x01fffffc =  0x1fffffc
> +	 * The maximum backword branch should be:
> +	 *   (0xff800000 << 2) = 0xfe000000 = -0x2000000
> +	 *
> +	 * We can simply check (rel & 0xfe000003):
> +	 *  if rel is positive, (rel & 0xfe000000) shoule be 0
> +	 *  if rel is negitive, (rel & 0xfe000000) should be 0xfe000000
> +	 *  the last '3' is used for alignment checking.
> +	 */
> +	rel_chk = (unsigned long)((long)code -
> +			(long)orig->addr + 8) & 0xfe000003;
> +
> +	if ((rel_chk != 0) && (rel_chk != 0xfe000000)) {
> +		/*
> +		 * Different from x86, we free code buf directly instead of
> +		 * calling __arch_remove_optimized_kprobe() because
> +		 * we have not fill any field in op.
> +		 */
> +		free_optinsn_slot(code, 0);
> +		return -ERANGE;
> +	}
> +
> +	/* Copy arch-dep-instance from template. */
> +	memcpy(code, &optprobe_template_entry,
> +			TMPL_END_IDX * sizeof(kprobe_opcode_t));
> +
> +	/* Adjust buffer according to instruction. */
> +	BUG_ON(orig->ainsn.stack_space < 0);
> +
> +	stack_protect += orig->ainsn.stack_space;
> +
> +	/* Should have been filtered by can_optimize(). */
> +	BUG_ON(stack_protect > 255);
> +
> +	/* Create a 'sub sp, sp, #<stack_protect>' */
> +	code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect);
> +	/* Create a 'add r3, sp, #<stack_protect>' */
> +	code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect);
> +
> +	/* Set probe information */
> +	val = (unsigned long)op;
> +	code[TMPL_VAL_IDX] = val;
> +
> +	/* Set probe function call */
> +	val = (unsigned long)optimized_callback;
> +	code[TMPL_CALL_IDX] = val;
> +
> +	flush_icache_range((unsigned long)code,
> +			   (unsigned long)(&code[TMPL_END_IDX]));
> +
> +	/* Set op->optinsn.insn means prepared. */
> +	op->optinsn.insn = code;
> +	return 0;
> +}
> +
> +void __kprobes arch_optimize_kprobes(struct list_head *oplist)
> +{
> +	struct optimized_kprobe *op, *tmp;
> +
> +	list_for_each_entry_safe(op, tmp, oplist, list) {
> +		unsigned long insn;
> +		WARN_ON(kprobe_disabled(&op->kp));
> +
> +		/*
> +		 * Backup instructions which will be replaced
> +		 * by jump address
> +		 */
> +		memcpy(op->optinsn.copied_insn, op->kp.addr,
> +				RELATIVEJUMP_SIZE);
> +
> +		insn = arm_gen_branch((unsigned long)op->kp.addr,
> +				(unsigned long)op->optinsn.insn);
> +		BUG_ON(insn == 0);
> +
> +		/*
> +		 * Make it a conditional branch if replaced insn
> +		 * is consitional
> +		 */
> +		insn = (__mem_to_opcode_arm(
> +			  op->optinsn.copied_insn[0]) & 0xf0000000) |
> +			(insn & 0x0fffffff);
> +
> +		/*
> +		 * Similar to __arch_disarm_kprobe, operations which
> +		 * removing breakpoints must be wrapped by stop_machine
> +		 * to avoid racing.
> +		 */
> +		kprobes_remove_breakpoint(op->kp.addr, insn);
> +
> +		list_del_init(&op->list);
> +	}
> +}
> +
> +void arch_unoptimize_kprobe(struct optimized_kprobe *op)
> +{
> +	arch_arm_kprobe(&op->kp);
> +}
> +
> +/*
> + * Recover original instructions and breakpoints from relative jumps.
> + * Caller must call with locking kprobe_mutex.
> + */
> +void arch_unoptimize_kprobes(struct list_head *oplist,
> +			    struct list_head *done_list)
> +{
> +	struct optimized_kprobe *op, *tmp;
> +
> +	list_for_each_entry_safe(op, tmp, oplist, list) {
> +		arch_unoptimize_kprobe(op);
> +		list_move(&op->list, done_list);
> +	}
> +}
> +
> +int arch_within_optimized_kprobe(struct optimized_kprobe *op,
> +				unsigned long addr)
> +{
> +	return ((unsigned long)op->kp.addr <= addr &&
> +		(unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr);
> +}
> +
> +void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
> +{
> +	__arch_remove_optimized_kprobe(op, 1);
> +}



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements.
  2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
                   ` (10 preceding siblings ...)
  2015-01-05 11:34 ` [PATCH v19 11/11] ARM: optprobes: execute instruction during restoring if possible Wang Nan
@ 2015-01-07 13:40 ` Jon Medhurst (Tixy)
  2015-01-20  2:17   ` Masami Hiramatsu
  11 siblings, 1 reply; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-07 13:40 UTC (permalink / raw)
  To: Wang Nan, Masami Hiramatsu; +Cc: linux, lizefan, linux-kernel, linux-arm-kernel

I think that the patches up to 09/11 inclusive have been though more
that enough review and revisions to think about getting them merged,
there doesn't seem much point in continuously resending them whilst new
features are built on top of them.

Masami Hiramatsu, are you happy for your patch to generic+X86 kprobes
code [1] to go through the ARM maintainers tree, assuming Russell is
also happy with that. Or should that go via a different route?

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/313218.html

Wang Nan, assuming everyone is happy, can you put together a branch in a
git repository for those patches, or I'm more than happy to do that if
you like. Then I can give the series a final test and we can send a pull
request to Russell King.

Thanks all

-- 
Tixy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v20 01/11] ARM: probes: move all probe code to dedicate directory
  2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
@ 2015-01-09  2:19   ` Wang Nan
  2015-01-09  9:47     ` Jon Medhurst (Tixy)
  2015-01-09  2:28   ` [PATCH v19 " Wang Nan
  1 sibling, 1 reply; 31+ messages in thread
From: Wang Nan @ 2015-01-09  2:19 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

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

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 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/kgdb.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                         |  1 +
 .../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
 27 files changed, 69 insertions(+), 56 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%)

diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c1785ee..7f99cd6 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -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/
diff --git a/arch/arm/kernel/patch.h b/arch/arm/include/asm/patch.h
similarity index 100%
rename from arch/arm/kernel/patch.h
rename to arch/arm/include/asm/patch.h
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index fb2b71e..9c51a43 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -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 patch.o
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
index afeeb9e..d8da075 100644
--- a/arch/arm/kernel/jump_label.c
+++ b/arch/arm/kernel/jump_label.c
@@ -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
 
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index 07db2f8..f3eb83f 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -16,7 +16,7 @@
 
 #include <asm/traps.h>
 
-#include "patch.h"
+#include <asm/patch.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c
index 5038960..69bda1a 100644
--- a/arch/arm/kernel/patch.c
+++ b/arch/arm/kernel/patch.c
@@ -8,8 +8,7 @@
 #include <asm/fixmap.h>
 #include <asm/smp_plat.h>
 #include <asm/opcodes.h>
-
-#include "patch.h"
+#include <asm/patch.h>
 
 struct patch {
 	void *addr;
diff --git a/arch/arm/probes/Makefile b/arch/arm/probes/Makefile
new file mode 100644
index 0000000..aa1f859
--- /dev/null
+++ b/arch/arm/probes/Makefile
@@ -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
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/probes/decode-arm.c
similarity index 99%
rename from arch/arm/kernel/probes-arm.c
rename to arch/arm/probes/decode-arm.c
index 8eaef81..e39cc75 100644
--- a/arch/arm/kernel/probes-arm.c
+++ b/arch/arm/probes/decode-arm.c
@@ -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)))))
 
diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/probes/decode-arm.h
similarity index 97%
rename from arch/arm/kernel/probes-arm.h
rename to arch/arm/probes/decode-arm.h
index ace6572..9c56b40 100644
--- a/arch/arm/kernel/probes-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -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,
diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/probes/decode-thumb.c
similarity index 99%
rename from arch/arm/kernel/probes-thumb.c
rename to arch/arm/probes/decode-thumb.c
index 4131351..2f0453a 100644
--- a/arch/arm/kernel/probes-thumb.c
+++ b/arch/arm/probes/decode-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes-thumb.c
+ * arch/arm/probes/decode-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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[] = {
diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/probes/decode-thumb.h
similarity index 97%
rename from arch/arm/kernel/probes-thumb.h
rename to arch/arm/probes/decode-thumb.h
index 7c6f6eb..039013c 100644
--- a/arch/arm/kernel/probes-thumb.h
+++ b/arch/arm/probes/decode-thumb.h
@@ -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.
  */
diff --git a/arch/arm/kernel/probes.c b/arch/arm/probes/decode.c
similarity index 99%
rename from arch/arm/kernel/probes.c
rename to arch/arm/probes/decode.c
index a8ab540..3b05d57 100644
--- a/arch/arm/kernel/probes.c
+++ b/arch/arm/probes/decode.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes.c
+ * arch/arm/probes/decode.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -17,7 +17,7 @@
 #include <asm/ptrace.h>
 #include <linux/bug.h>
 
-#include "probes.h"
+#include "decode.h"
 
 
 #ifndef find_str_pc_offset
diff --git a/arch/arm/kernel/probes.h b/arch/arm/probes/decode.h
similarity index 99%
rename from arch/arm/kernel/probes.h
rename to arch/arm/probes/decode.h
index dba9f24..1d0b531 100644
--- a/arch/arm/kernel/probes.h
+++ b/arch/arm/probes/decode.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/probes.h
+ * arch/arm/probes/decode.h
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
new file mode 100644
index 0000000..eb38a42
--- /dev/null
+++ b/arch/arm/probes/kprobes/Makefile
@@ -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
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/probes/kprobes/actions-arm.c
similarity index 99%
rename from arch/arm/kernel/kprobes-arm.c
rename to arch/arm/probes/kprobes/actions-arm.c
index ac300c6..8797879 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -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"
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/probes/kprobes/actions-common.c
similarity index 98%
rename from arch/arm/kernel/kprobes-common.c
rename to arch/arm/probes/kprobes/actions-common.c
index 0bf5d64..bd20a71 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/probes/kprobes/actions-common.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-common.c
+ * arch/arm/probes/kprobes/actions-common.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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,
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
similarity index 99%
rename from arch/arm/kernel/kprobes-thumb.c
rename to arch/arm/probes/kprobes/actions-thumb.c
index 9495d7f..6c4e60b 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/probes/kprobes/actions-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-thumb.c
+ * arch/arm/probes/kprobes/actions-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -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 \
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/probes/kprobes/core.c
similarity index 99%
rename from arch/arm/kernel/kprobes.c
rename to arch/arm/probes/kprobes/core.c
index 6d64420..701f49d 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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,		\
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/probes/kprobes/core.h
similarity index 96%
rename from arch/arm/kernel/kprobes.h
rename to arch/arm/probes/kprobes/core.h
index 9a2712e..2e1e5a3 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -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
diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/probes/kprobes/test-arm.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test-arm.c
rename to arch/arm/probes/kprobes/test-arm.c
index cb14242..d9a1255 100644
--- a/arch/arm/kernel/kprobes-test-arm.c
+++ b/arch/arm/probes/kprobes/test-arm.c
@@ -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"
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/probes/kprobes/test-core.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test.c
rename to arch/arm/probes/kprobes/test-core.c
index b206d77..7ab633d 100644
--- a/arch/arm/kernel/kprobes-test.c
+++ b/arch/arm/probes/kprobes/test-core.c
@@ -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
diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/probes/kprobes/test-core.h
similarity index 99%
rename from arch/arm/kernel/kprobes-test.h
rename to arch/arm/probes/kprobes/test-core.h
index 4430990..9991754 100644
--- a/arch/arm/kernel/kprobes-test.h
+++ b/arch/arm/probes/kprobes/test-core.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-test.h
+ * arch/arm/probes/kprobes/test-core.h
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c
similarity index 99%
rename from arch/arm/kernel/kprobes-test-thumb.c
rename to arch/arm/probes/kprobes/test-thumb.c
index 844dd10..6c6e9a9 100644
--- a/arch/arm/kernel/kprobes-test-thumb.c
+++ b/arch/arm/probes/kprobes/test-thumb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/kprobes-test-thumb.c
+ * arch/arm/probes/kprobes/test-thumb.c
  *
  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
  *
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 #include <asm/opcodes.h>
 
-#include "kprobes-test.h"
+#include "test-core.h"
 
 
 #define TEST_ISA "16"
diff --git a/arch/arm/probes/uprobes/Makefile b/arch/arm/probes/uprobes/Makefile
new file mode 100644
index 0000000..e1dc3d0
--- /dev/null
+++ b/arch/arm/probes/uprobes/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_UPROBES)		+= core.o actions-arm.o
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/probes/uprobes/actions-arm.c
similarity index 98%
rename from arch/arm/kernel/uprobes-arm.c
rename to arch/arm/probes/uprobes/actions-arm.c
index d3b655f..1dd4916 100644
--- a/arch/arm/kernel/uprobes-arm.c
+++ b/arch/arm/probes/uprobes/actions-arm.c
@@ -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)
 {
diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/probes/uprobes/core.c
similarity index 98%
rename from arch/arm/kernel/uprobes.c
rename to arch/arm/probes/uprobes/core.c
index 56adf9c..b2954f6 100644
--- a/arch/arm/kernel/uprobes.c
+++ b/arch/arm/probes/uprobes/core.c
@@ -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
 
diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/probes/uprobes/core.h
similarity index 100%
rename from arch/arm/kernel/uprobes.h
rename to arch/arm/probes/uprobes/core.h
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory
  2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
  2015-01-09  2:19   ` [PATCH v20 " Wang Nan
@ 2015-01-09  2:28   ` Wang Nan
  1 sibling, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-09  2:28 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

On 2015/1/5 19:29, Wang Nan wrote:
> 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
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Hi,

Thanks to Tixy and his test robot, a bug is found in this patch: I forgot to change
arch/arm/kernel/kgdb.c, which also includes patch.h. A small code modification
is required.

I have posted a new version of this patch by replying.

Tixy, could you please collect it into your git repository and help me test it
again?

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/314520.html

Thanks.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
  2015-01-07 13:01   ` Jon Medhurst (Tixy)
@ 2015-01-09  6:37   ` Wang Nan
  2015-01-09 10:25     ` Jon Medhurst (Tixy)
  2015-01-09  6:51   ` [PATCH v19 " Wang Nan
  2 siblings, 1 reply; 31+ messages in thread
From: Wang Nan @ 2015-01-09  6:37 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

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() 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.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Jon Medhurst (Tixy) <tixy@linaro.org>
Reviewed-by: Jon Medhurst (Tixy) <tixy@linaro.org>
Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
Cc: Will Deacon <will.deacon@arm.com>
---
 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       | 322 ++++++++++++++++++++++++++++++++
 10 files changed, 377 insertions(+), 12 deletions(-)
 rename arch/arm/{kernel => include/asm}/insn.h (100%)
 create mode 100644 arch/arm/probes/kprobes/opt-arm.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 97d07ed..3d5dc2d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -60,6 +60,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
diff --git a/arch/arm/kernel/insn.h b/arch/arm/include/asm/insn.h
similarity index 100%
rename from arch/arm/kernel/insn.h
rename to arch/arm/include/asm/insn.h
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index 56f9ac6..50ff3bc 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -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 */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 9c51a43..902397d 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -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 patch.o
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index b8c75e4..709ee1d 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -20,8 +20,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} */
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
index d8da075..e39cbf4 100644
--- a/arch/arm/kernel/jump_label.c
+++ b/arch/arm/kernel/jump_label.c
@@ -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
 
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
index bc8d504..76a36bf 100644
--- a/arch/arm/probes/kprobes/Makefile
+++ b/arch/arm/probes/kprobes/Makefile
@@ -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
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 3a58db4..a4ec240 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -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)
diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
index f88c79f..b3036c5 100644
--- a/arch/arm/probes/kprobes/core.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -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);
diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c
new file mode 100644
index 0000000..cb47eff
--- /dev/null
+++ b/arch/arm/probes/kprobes/opt-arm.c
@@ -0,0 +1,322 @@
+/*
+ *  Kernel Probes Jump Optimization (Optprobes)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ * Copyright (C) Hitachi Ltd., 2012
+ * Copyright (C) Huawei Inc., 2014
+ */
+
+#include <linux/kprobes.h>
+#include <linux/jump_label.h>
+#include <asm/kprobes.h>
+#include <asm/cacheflush.h>
+/* for arm_gen_branch */
+#include <asm/insn.h>
+/* for patch_text */
+#include <asm/patch.h>
+
+#include "core.h"
+
+/*
+ * NOTE: the first sub and add instruction will be modified according
+ * to the stack cost of the instruction.
+ */
+asm (
+			".global optprobe_template_entry\n"
+			"optprobe_template_entry:\n"
+			".global optprobe_template_sub_sp\n"
+			"optprobe_template_sub_sp:"
+			"	sub	sp, sp, #0xff\n"
+			"	stmia	sp, {r0 - r14} \n"
+			".global optprobe_template_add_sp\n"
+			"optprobe_template_add_sp:"
+			"	add	r3, sp, #0xff\n"
+			"	str	r3, [sp, #52]\n"
+			"	mrs	r4, cpsr\n"
+			"	str	r4, [sp, #64]\n"
+			"	mov	r1, sp\n"
+			"	ldr	r0, 1f\n"
+			"	ldr	r2, 2f\n"
+			/*
+			 * AEABI requires an 8-bytes alignment stack. If
+			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
+			 * alloc more bytes here.
+			 */
+			"	and	r4, sp, #4\n"
+			"	sub	sp, sp, r4\n"
+#if __LINUX_ARM_ARCH__ >= 5
+			"	blx	r2\n"
+#else
+			"	mov     lr, pc\n"
+			"	bx	r2\n"
+#endif
+			"	add	sp, sp, r4\n"
+			"	ldr	r1, [sp, #64]\n"
+			"	tst	r1, #"__stringify(PSR_T_BIT)"\n"
+			"	ldrne	r2, [sp, #60]\n"
+			"	orrne	r2, #1\n"
+			"	strne	r2, [sp, #60] @ set bit0 of PC for thumb\n"
+			"	msr	cpsr_cxsf, r1\n"
+			"	ldmia	sp, {r0 - r15}\n"
+			".global optprobe_template_val\n"
+			"optprobe_template_val:\n"
+			"1:	.long 0\n"
+			".global optprobe_template_call\n"
+			"optprobe_template_call:\n"
+			"2:	.long 0\n"
+			".global optprobe_template_end\n"
+			"optprobe_template_end:\n");
+
+#define TMPL_VAL_IDX \
+	((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry)
+#define TMPL_CALL_IDX \
+	((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry)
+#define TMPL_END_IDX \
+	((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry)
+#define TMPL_ADD_SP \
+	((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
+#define TMPL_SUB_SP \
+	((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
+
+/*
+ * ARM can always optimize an instruction when using ARM ISA, except
+ * instructions like 'str r0, [sp, r1]' which store to stack and unable
+ * to determine stack space consumption statically.
+ */
+int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
+{
+	return optinsn->insn != NULL;
+}
+
+/*
+ * In ARM ISA, kprobe opt always replace one instruction (4 bytes
+ * aligned and 4 bytes long). It is impossible to encounter another
+ * kprobe in the address range. So always return 0.
+ */
+int arch_check_optimized_kprobe(struct optimized_kprobe *op)
+{
+	return 0;
+}
+
+/* Caller must ensure addr & 3 == 0 */
+static int can_optimize(struct kprobe *kp)
+{
+	if (kp->ainsn.stack_space < 0)
+		return 0;
+	/*
+	 * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'.
+	 * Number larger than 255 needs special encoding.
+	 */
+	if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs))
+		return 0;
+	return 1;
+}
+
+/* Free optimized instruction slot */
+static void
+__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
+{
+	if (op->optinsn.insn) {
+		free_optinsn_slot(op->optinsn.insn, dirty);
+		op->optinsn.insn = NULL;
+	}
+}
+
+extern void kprobe_handler(struct pt_regs *regs);
+
+static void
+optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct kprobe *p = &op->kp;
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	/* Save skipped registers */
+	regs->ARM_pc = (unsigned long)op->kp.addr;
+	regs->ARM_ORIG_r0 = ~0UL;
+
+	local_irq_save(flags);
+
+	if (kprobe_running()) {
+		kprobes_inc_nmissed_count(&op->kp);
+	} else {
+		__this_cpu_write(current_kprobe, &op->kp);
+		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+		opt_pre_handler(&op->kp, regs);
+		__this_cpu_write(current_kprobe, NULL);
+	}
+
+	/* In each case, we must singlestep the replaced instruction. */
+	op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
+
+	local_irq_restore(flags);
+}
+
+int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
+{
+	kprobe_opcode_t *code;
+	unsigned long rel_chk;
+	unsigned long val;
+	unsigned long stack_protect = sizeof(struct pt_regs);
+
+	if (!can_optimize(orig))
+		return -EILSEQ;
+
+	code = get_optinsn_slot();
+	if (!code)
+		return -ENOMEM;
+
+	/*
+	 * Verify if the address gap is in 32MiB range, because this uses
+	 * a relative jump.
+	 *
+	 * kprobe opt use a 'b' instruction to branch to optinsn.insn.
+	 * According to ARM manual, branch instruction is:
+	 *
+	 *   31  28 27           24 23             0
+	 *  +------+---+---+---+---+----------------+
+	 *  | cond | 1 | 0 | 1 | 0 |      imm24     |
+	 *  +------+---+---+---+---+----------------+
+	 *
+	 * imm24 is a signed 24 bits integer. The real branch offset is computed
+	 * by: imm32 = SignExtend(imm24:'00', 32);
+	 *
+	 * So the maximum forward branch should be:
+	 *   (0x007fffff << 2) = 0x01fffffc =  0x1fffffc
+	 * The maximum backword branch should be:
+	 *   (0xff800000 << 2) = 0xfe000000 = -0x2000000
+	 *
+	 * We can simply check (rel & 0xfe000003):
+	 *  if rel is positive, (rel & 0xfe000000) shoule be 0
+	 *  if rel is negitive, (rel & 0xfe000000) should be 0xfe000000
+	 *  the last '3' is used for alignment checking.
+	 */
+	rel_chk = (unsigned long)((long)code -
+			(long)orig->addr + 8) & 0xfe000003;
+
+	if ((rel_chk != 0) && (rel_chk != 0xfe000000)) {
+		/*
+		 * Different from x86, we free code buf directly instead of
+		 * calling __arch_remove_optimized_kprobe() because
+		 * we have not fill any field in op.
+		 */
+		free_optinsn_slot(code, 0);
+		return -ERANGE;
+	}
+
+	/* Copy arch-dep-instance from template. */
+	memcpy(code, &optprobe_template_entry,
+			TMPL_END_IDX * sizeof(kprobe_opcode_t));
+
+	/* Adjust buffer according to instruction. */
+	BUG_ON(orig->ainsn.stack_space < 0);
+
+	stack_protect += orig->ainsn.stack_space;
+
+	/* Should have been filtered by can_optimize(). */
+	BUG_ON(stack_protect > 255);
+
+	/* Create a 'sub sp, sp, #<stack_protect>' */
+	code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect);
+	/* Create a 'add r3, sp, #<stack_protect>' */
+	code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect);
+
+	/* Set probe information */
+	val = (unsigned long)op;
+	code[TMPL_VAL_IDX] = val;
+
+	/* Set probe function call */
+	val = (unsigned long)optimized_callback;
+	code[TMPL_CALL_IDX] = val;
+
+	flush_icache_range((unsigned long)code,
+			   (unsigned long)(&code[TMPL_END_IDX]));
+
+	/* Set op->optinsn.insn means prepared. */
+	op->optinsn.insn = code;
+	return 0;
+}
+
+void __kprobes arch_optimize_kprobes(struct list_head *oplist)
+{
+	struct optimized_kprobe *op, *tmp;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		unsigned long insn;
+		WARN_ON(kprobe_disabled(&op->kp));
+
+		/*
+		 * Backup instructions which will be replaced
+		 * by jump address
+		 */
+		memcpy(op->optinsn.copied_insn, op->kp.addr,
+				RELATIVEJUMP_SIZE);
+
+		insn = arm_gen_branch((unsigned long)op->kp.addr,
+				(unsigned long)op->optinsn.insn);
+		BUG_ON(insn == 0);
+
+		/*
+		 * Make it a conditional branch if replaced insn
+		 * is consitional
+		 */
+		insn = (__mem_to_opcode_arm(
+			  op->optinsn.copied_insn[0]) & 0xf0000000) |
+			(insn & 0x0fffffff);
+
+		/*
+		 * Similar to __arch_disarm_kprobe, operations which
+		 * removing breakpoints must be wrapped by stop_machine
+		 * to avoid racing.
+		 */
+		kprobes_remove_breakpoint(op->kp.addr, insn);
+
+		list_del_init(&op->list);
+	}
+}
+
+void arch_unoptimize_kprobe(struct optimized_kprobe *op)
+{
+	arch_arm_kprobe(&op->kp);
+}
+
+/*
+ * Recover original instructions and breakpoints from relative jumps.
+ * Caller must call with locking kprobe_mutex.
+ */
+void arch_unoptimize_kprobes(struct list_head *oplist,
+			    struct list_head *done_list)
+{
+	struct optimized_kprobe *op, *tmp;
+
+	list_for_each_entry_safe(op, tmp, oplist, list) {
+		arch_unoptimize_kprobe(op);
+		list_move(&op->list, done_list);
+	}
+}
+
+int arch_within_optimized_kprobe(struct optimized_kprobe *op,
+				unsigned long addr)
+{
+	return ((unsigned long)op->kp.addr <= addr &&
+		(unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr);
+}
+
+void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
+{
+	__arch_remove_optimized_kprobe(op, 1);
+}
-- 
1.8.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
  2015-01-07 13:01   ` Jon Medhurst (Tixy)
  2015-01-09  6:37   ` [PATCH v20 " Wang Nan
@ 2015-01-09  6:51   ` Wang Nan
  2 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-09  6:51 UTC (permalink / raw)
  To: masami.hiramatsu.pt, tixy, linux; +Cc: lizefan, linux-kernel, linux-arm-kernel

Hi Tixy and other,

Similar to patch 01/11, build robot found a building error in this patch when ARM version
is lower than 4. In such processors 'blx' instruction is unusable.

I have posted a new version of this patch, which has following code change:

diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c
index 6a60df3..cb47eff 100644
--- a/arch/arm/probes/kprobes/opt-arm.c
+++ b/arch/arm/probes/kprobes/opt-arm.c
@@ -58,7 +58,12 @@ asm (
 			 */
 			"	and	r4, sp, #4\n"
 			"	sub	sp, sp, r4\n"
+#if __LINUX_ARM_ARCH__ >= 5
 			"	blx	r2\n"
+#else
+			"	mov     lr, pc\n"
+			"	bx	r2\n"
+#endif
 			"	add	sp, sp, r4\n"
 			"	ldr	r1, [sp, #64]\n"
 			"	tst	r1, #"__stringify(PSR_T_BIT)"\n"

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/314542.html

Tixy, could you please collect it into your repository and test again?

Thank you!


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 01/11] ARM: probes: move all probe code to dedicate directory
  2015-01-09  2:19   ` [PATCH v20 " Wang Nan
@ 2015-01-09  9:47     ` Jon Medhurst (Tixy)
  2015-01-09  9:50       ` Wang Nan
  0 siblings, 1 reply; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-09  9:47 UTC (permalink / raw)
  To: Wang Nan
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On Fri, 2015-01-09 at 10:19 +0800, Wang Nan wrote:
> 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
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> ---

Might have been good to mention what's changed in this version, I worked
out its kgdb.c, comments below...

[...]

> diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
> index 07db2f8..f3eb83f 100644
> --- a/arch/arm/kernel/kgdb.c
> +++ b/arch/arm/kernel/kgdb.c
> @@ -16,7 +16,7 @@
>  
>  #include <asm/traps.h>
>  
> -#include "patch.h"
> +#include <asm/patch.h>

To keep alphabetical ordering of headers this should be above the
#include <asm/traps.h>

Don't bother resending the patch, I'll just update the patch in the git
branch I'm putting together.

-- 
Tixy
 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 01/11] ARM: probes: move all probe code to dedicate directory
  2015-01-09  9:47     ` Jon Medhurst (Tixy)
@ 2015-01-09  9:50       ` Wang Nan
  0 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-09  9:50 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel,
	linux-arm-kernel, Li Zefan

On 2015/1/9 17:47, Jon Medhurst (Tixy) wrote:
> On Fri, 2015-01-09 at 10:19 +0800, Wang Nan wrote:
>> 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
>>
>> Signed-off-by: Wang Nan <wangnan0@huawei.com>
>> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>> ---
> 
> Might have been good to mention what's changed in this version, I worked
> out its kgdb.c, comments below...
> 
> [...]
> 
>> diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
>> index 07db2f8..f3eb83f 100644
>> --- a/arch/arm/kernel/kgdb.c
>> +++ b/arch/arm/kernel/kgdb.c
>> @@ -16,7 +16,7 @@
>>  
>>  #include <asm/traps.h>
>>  
>> -#include "patch.h"
>> +#include <asm/patch.h>
> 
> To keep alphabetical ordering of headers this should be above the
> #include <asm/traps.h>
> 
> Don't bother resending the patch, I'll just update the patch in the git
> branch I'm putting together.
> 
Thanks a lot!


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09  6:37   ` [PATCH v20 " Wang Nan
@ 2015-01-09 10:25     ` Jon Medhurst (Tixy)
  2015-01-09 10:55       ` Wang Nan
  2015-01-09 16:35       ` Russell King - ARM Linux
  0 siblings, 2 replies; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-09 10:25 UTC (permalink / raw)
  To: Wang Nan
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On Fri, 2015-01-09 at 14:37 +0800, Wang Nan wrote:
> 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() 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.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Jon Medhurst (Tixy) <tixy@linaro.org>
> Reviewed-by: Jon Medhurst (Tixy) <tixy@linaro.org>
> Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
> Cc: Will Deacon <will.deacon@arm.com>
> ---

[...]

> +asm (
> +			".global optprobe_template_entry\n"
> +			"optprobe_template_entry:\n"
> +			".global optprobe_template_sub_sp\n"
> +			"optprobe_template_sub_sp:"
> +			"	sub	sp, sp, #0xff\n"
> +			"	stmia	sp, {r0 - r14} \n"
> +			".global optprobe_template_add_sp\n"
> +			"optprobe_template_add_sp:"
> +			"	add	r3, sp, #0xff\n"
> +			"	str	r3, [sp, #52]\n"
> +			"	mrs	r4, cpsr\n"
> +			"	str	r4, [sp, #64]\n"
> +			"	mov	r1, sp\n"
> +			"	ldr	r0, 1f\n"
> +			"	ldr	r2, 2f\n"
> +			/*
> +			 * AEABI requires an 8-bytes alignment stack. If
> +			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
> +			 * alloc more bytes here.
> +			 */
> +			"	and	r4, sp, #4\n"
> +			"	sub	sp, sp, r4\n"
> +#if __LINUX_ARM_ARCH__ >= 5
> +			"	blx	r2\n"
> +#else
> +			"	mov     lr, pc\n"
> +			"	bx	r2\n"

I think the BX instruction is not supported for ARMv4 chips that don't
have Thumb support (e.g. SA110), at least an old ARM ARM I have says BX
is supported on "Version 5 and above, and T variants of version 4".
Though building assabet_defconfig with kprobes enabled doesn't produce
an error for the BX instruction (!?)

To be safe I would be tempted to use "mov pc, r2" instead. Again, if you
agree, I'll change this in the patch in the branch I'm putting together.

[...]

-- 
Tixy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09 10:25     ` Jon Medhurst (Tixy)
@ 2015-01-09 10:55       ` Wang Nan
  2015-01-09 16:35       ` Russell King - ARM Linux
  1 sibling, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-09 10:55 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On 2015/1/9 18:25, Jon Medhurst (Tixy) wrote:
> On Fri, 2015-01-09 at 14:37 +0800, Wang Nan wrote:
>> 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() 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.
>>
>> Signed-off-by: Wang Nan <wangnan0@huawei.com>
>> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>> Cc: Jon Medhurst (Tixy) <tixy@linaro.org>
>> Reviewed-by: Jon Medhurst (Tixy) <tixy@linaro.org>
>> Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
>> Cc: Will Deacon <will.deacon@arm.com>
>> ---
> 
> [...]
> 
>> +asm (
>> +			".global optprobe_template_entry\n"
>> +			"optprobe_template_entry:\n"
>> +			".global optprobe_template_sub_sp\n"
>> +			"optprobe_template_sub_sp:"
>> +			"	sub	sp, sp, #0xff\n"
>> +			"	stmia	sp, {r0 - r14} \n"
>> +			".global optprobe_template_add_sp\n"
>> +			"optprobe_template_add_sp:"
>> +			"	add	r3, sp, #0xff\n"
>> +			"	str	r3, [sp, #52]\n"
>> +			"	mrs	r4, cpsr\n"
>> +			"	str	r4, [sp, #64]\n"
>> +			"	mov	r1, sp\n"
>> +			"	ldr	r0, 1f\n"
>> +			"	ldr	r2, 2f\n"
>> +			/*
>> +			 * AEABI requires an 8-bytes alignment stack. If
>> +			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
>> +			 * alloc more bytes here.
>> +			 */
>> +			"	and	r4, sp, #4\n"
>> +			"	sub	sp, sp, r4\n"
>> +#if __LINUX_ARM_ARCH__ >= 5
>> +			"	blx	r2\n"
>> +#else
>> +			"	mov     lr, pc\n"
>> +			"	bx	r2\n"
> 
> I think the BX instruction is not supported for ARMv4 chips that don't
> have Thumb support (e.g. SA110), at least an old ARM ARM I have says BX
> is supported on "Version 5 and above, and T variants of version 4".
> Though building assabet_defconfig with kprobes enabled doesn't produce
> an error for the BX instruction (!?)
> 
> To be safe I would be tempted to use "mov pc, r2" instead. Again, if you
> agree, I'll change this in the patch in the branch I'm putting together.
> 
> [...]
> 
Sure. I tested a function pointer calling and found that gcc generates
'mov pc, r2', and there is no need for ISA switching.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09 10:25     ` Jon Medhurst (Tixy)
  2015-01-09 10:55       ` Wang Nan
@ 2015-01-09 16:35       ` Russell King - ARM Linux
  2015-01-09 17:28         ` Jon Medhurst (Tixy)
  1 sibling, 1 reply; 31+ messages in thread
From: Russell King - ARM Linux @ 2015-01-09 16:35 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: Wang Nan, masami.hiramatsu.pt, lizefan, linux-kernel, linux-arm-kernel

On Fri, Jan 09, 2015 at 10:25:54AM +0000, Jon Medhurst (Tixy) wrote:
> On Fri, 2015-01-09 at 14:37 +0800, Wang Nan wrote:
> > +			"	and	r4, sp, #4\n"
> > +			"	sub	sp, sp, r4\n"
> > +#if __LINUX_ARM_ARCH__ >= 5
> > +			"	blx	r2\n"
> > +#else
> > +			"	mov     lr, pc\n"
> > +			"	bx	r2\n"
> 
> I think the BX instruction is not supported for ARMv4 chips that don't
> have Thumb support (e.g. SA110), at least an old ARM ARM I have says BX
> is supported on "Version 5 and above, and T variants of version 4".

Correct.

> Though building assabet_defconfig with kprobes enabled doesn't produce
> an error for the BX instruction (!?)

Which config are you using?  Does it have CONFIG_CPU_32v4 enabled?
That should result in "-D__LINUX_ARM_ARCH__=4 -march=armv4" being
passed to the compiler (please check with make V=1).

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09 16:35       ` Russell King - ARM Linux
@ 2015-01-09 17:28         ` Jon Medhurst (Tixy)
  2015-01-09 17:57           ` Russell King - ARM Linux
  0 siblings, 1 reply; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-09 17:28 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Wang Nan, masami.hiramatsu.pt, lizefan, linux-kernel, linux-arm-kernel

On Fri, 2015-01-09 at 16:35 +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 09, 2015 at 10:25:54AM +0000, Jon Medhurst (Tixy) wrote:
> > On Fri, 2015-01-09 at 14:37 +0800, Wang Nan wrote:
> > > +			"	and	r4, sp, #4\n"
> > > +			"	sub	sp, sp, r4\n"
> > > +#if __LINUX_ARM_ARCH__ >= 5
> > > +			"	blx	r2\n"
> > > +#else
> > > +			"	mov     lr, pc\n"
> > > +			"	bx	r2\n"
> > 
> > I think the BX instruction is not supported for ARMv4 chips that don't
> > have Thumb support (e.g. SA110), at least an old ARM ARM I have says BX
> > is supported on "Version 5 and above, and T variants of version 4".
> 
> Correct.
> 
> > Though building assabet_defconfig with kprobes enabled doesn't produce
> > an error for the BX instruction (!?)
> 
> Which config are you using?  Does it have CONFIG_CPU_32v4 enabled?

Yes

> That should result in "-D__LINUX_ARM_ARCH__=4 -march=armv4" being
> passed to the compiler (please check with make V=1).

I does have that, the arguments for compiling this source file
include...

-mno-thumb-interwork -marm -D__LINUX_ARM_ARCH__=4 -march=armv4 -mtune=strongarm1100

Using objdump I can see that the BX instruction does indeed end up in
the code, it hasn't been auto-magically turned into a MOV PC,R2.

Adding in a ".code 16" to the assembler produces "Error: selected
processor does not support THUMB opcodes", so at least it's got that
right. 

I have "gcc version 4.9.1 (Ubuntu/Linaro 4.9.1-16ubuntu6)"

Interestingly...

$ echo 'asm ("bx r2\n");' | arm-linux-gnueabihf-gcc -x c -S -march=armv4 -
<stdin>:1:0: warning: target CPU does not support THUMB instructions
$

but adding -marm gets rid of that error.

$ echo 'asm ("bx r2\n");' | arm-linux-gnueabihf-gcc -x c -S -marm -march=armv4 -
$

-- 
Tixy



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09 17:28         ` Jon Medhurst (Tixy)
@ 2015-01-09 17:57           ` Russell King - ARM Linux
  2015-01-09 19:18             ` Jon Medhurst (Tixy)
  0 siblings, 1 reply; 31+ messages in thread
From: Russell King - ARM Linux @ 2015-01-09 17:57 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: Wang Nan, masami.hiramatsu.pt, lizefan, linux-kernel, linux-arm-kernel

On Fri, Jan 09, 2015 at 05:28:22PM +0000, Jon Medhurst (Tixy) wrote:
> Using objdump I can see that the BX instruction does indeed end up in
> the code, it hasn't been auto-magically turned into a MOV PC,R2.
> 
> Adding in a ".code 16" to the assembler produces "Error: selected
> processor does not support THUMB opcodes", so at least it's got that
> right. 
> 
> I have "gcc version 4.9.1 (Ubuntu/Linaro 4.9.1-16ubuntu6)"

Remember that it's binutils which issues the errors about the assembly.

> Interestingly...
> 
> $ echo 'asm ("bx r2\n");' | arm-linux-gnueabihf-gcc -x c -S -march=armv4 -
> <stdin>:1:0: warning: target CPU does not support THUMB instructions
> $

Mine doesn't do that.

> but adding -marm gets rid of that error.
> 
> $ echo 'asm ("bx r2\n");' | arm-linux-gnueabihf-gcc -x c -S -marm -march=armv4 -
> $

Yes - but check the -.s file for the output... this won't run the assembler
so the assembler won't check that the instruction is legal.

For me:

$ echo 'asm ("bx r2\n");' | arm-linux-gcc -x c -c -marm -march=armv4 -v - -o o.o

calls the assembler thusly:

/usr/local/lib/gcc/arm-linux-gnueabi/4.7.4/../../../../arm-linux-gnueabi/bin/as \
-v -march=armv4 -meabi=5 --fix-v4bx -o o.o /tmp/ccB0cZgO.s

Sure enough, the object file contains:

00000000 <.text>:
   0:   e12fff12        bx      r2
                        0: R_ARM_V4BX   *ABS*

so it looks like it's been told...  Then if you do:

$ arm-linux-ld --fix-v4bx -o o1.o o.o
$ arm-linux-objdump -dr o1.o

you get:

    8074:       e1a0f002        mov     pc, r2

Hmm, I wonder if this means we should have the kernel linker deal with
V4BX relocations on ARMv4, converting them to their mov pc, X variant.

Also, do we need --fix-v4bx for the link of vmlinux?

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v20 08/11] ARM: kprobes: enable OPTPROBES for ARM 32
  2015-01-09 17:57           ` Russell King - ARM Linux
@ 2015-01-09 19:18             ` Jon Medhurst (Tixy)
  0 siblings, 0 replies; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-09 19:18 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Wang Nan, masami.hiramatsu.pt, lizefan, linux-kernel, linux-arm-kernel

On Fri, 2015-01-09 at 17:57 +0000, Russell King - ARM Linux wrote:
[...]
> For me:
> 
> $ echo 'asm ("bx r2\n");' | arm-linux-gcc -x c -c -marm -march=armv4 -v - -o o.o
> 
> calls the assembler thusly:
> 
> /usr/local/lib/gcc/arm-linux-gnueabi/4.7.4/../../../../arm-linux-gnueabi/bin/as \
> -v -march=armv4 -meabi=5 --fix-v4bx -o o.o /tmp/ccB0cZgO.s
> 
> Sure enough, the object file contains:
> 
> 00000000 <.text>:
>    0:   e12fff12        bx      r2
>                         0: R_ARM_V4BX   *ABS*
> 
> so it looks like it's been told...  Then if you do:
> 
> $ arm-linux-ld --fix-v4bx -o o1.o o.o
> $ arm-linux-objdump -dr o1.o
> 
> you get:
> 
>     8074:       e1a0f002        mov     pc, r2

I get results consistent with what you get above. A bit of googling
seems to indicate the generate-BX-and-fix-it-in-the-linker came in many
years ago with AEABI support.

> Hmm, I wonder if this means we should have the kernel linker deal with
> V4BX relocations on ARMv4, converting them to their mov pc, X variant.
> 
> Also, do we need --fix-v4bx for the link of vmlinux?

I guess the answer is yes if we want to catch uses of BX in inline
assembly. A quick and not very thorough grep of arch/arm for 'bx'
doesn't seem to turn up any existing dodgy uses, except in the kprobes
test code I wrote :-(

-- 
Tixy



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction.
  2015-01-05 11:29 ` [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction Wang Nan
@ 2015-01-13 15:01   ` Jon Medhurst (Tixy)
  2015-01-13 16:13     ` [PATCH] " Jon Medhurst (Tixy)
  0 siblings, 1 reply; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-13 15:01 UTC (permalink / raw)
  To: Wang Nan
  Cc: masami.hiramatsu.pt, linux, lizefan, linux-kernel, linux-arm-kernel

On Mon, 2015-01-05 at 19:29 +0800, Wang Nan wrote:
> This patch utilizes previous introduced checker to check register usage
> for probed ARM instruction and saves it in a mask. Futher patch will
> use such information to avoid simuation or emulation.

There's a couple of spelling mistakes above and minor grammar nitpicks,
my suggestion to improve those would be to add the bits in [] in the
following...

  This patch utilizes [the] previous[ly] introduced checker to check
  register usage for probed ARM instruction and saves it in a mask. [A]
  fu[r]ther patch will use such information to avoid simu[l]ation or
  emulation.

My comments on the code below are mostly suggestions on how to simplify
things, though the code is already quite re is one bug.

> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> ---
>  arch/arm/include/asm/probes.h          |  10 +++
>  arch/arm/probes/decode.c               |   7 ++
>  arch/arm/probes/kprobes/actions-arm.c  |   2 +-
>  arch/arm/probes/kprobes/checkers-arm.c | 124 +++++++++++++++++++++++++++++++++
>  arch/arm/probes/kprobes/checkers.h     |   1 +
>  5 files changed, 143 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
> index f0a1ee8..27b65b7 100644
> --- a/arch/arm/include/asm/probes.h
> +++ b/arch/arm/include/asm/probes.h
> @@ -41,6 +41,16 @@ struct arch_probes_insn {
>  	probes_insn_singlestep_t	*insn_singlestep;
>  	probes_insn_fn_t		*insn_fn;
>  	int stack_space;
> +
> +	/* Use 1 bit for a register. */
> +#define REG_NO_USE	(0)
> +#define REG_USE		(1)

No need for () around the 0 and 1

> +#define __register_usage_flag(n, f)	((f) << (n))
> +#define __clean_register_flag(m, n)	((m) & (~(1 << (n))))
> +#define __set_register_flag(m, n, f)	(__clean_register_flag(m, n) | __register_usage_flag(n, f))
> +#define set_register_nouse(m, n)	do {(m) = __set_register_flag(m, n, REG_NO_USE);} while(0)
> +#define set_register_use(m, n)		do {(m) = __set_register_flag(m, n, REG_USE);} while(0)

All these macros seem a bit convoluted to me, and I don't think it makes
things any clearer than open coding a bit set operation like

	|= 1 << reg

especially as I don't thing those macros will end up getting much use.

> +	unsigned long register_usage_flag;

To nit-pick, as this isn't a single flag I would add an 's' to make the
name plural, i.e. 'register_usage_flags'

>  };
>  
>  #endif /* __ASSEMBLY__ */
> diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
> index f9d7c42..40f9402 100644
> --- a/arch/arm/probes/decode.c
> +++ b/arch/arm/probes/decode.c
> @@ -435,6 +435,13 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
>  	 */
>  	asi->stack_space = 0;
>  
> +	/*
> +	 * Similay to stack_space, register_usage_flag is filled by

Typo, s/Similay/Similarly/

> +	 * checkers. Its default value is set to ~0, which is 'all
> +	 * registers are used', to prevent any potential optimization.
> +	 */
> +	asi->register_usage_flag = ~(0UL);

No need for () around 0UL

> +
>  	if (emulate)
>  		insn = prepare_emulated_insn(insn, asi, thumb);
>  
> diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
> index 4fedd4c..26e435b 100644
> --- a/arch/arm/probes/kprobes/actions-arm.c
> +++ b/arch/arm/probes/kprobes/actions-arm.c
> @@ -340,4 +340,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[] = {arm_stack_checker, NULL};
> +const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
> diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c
> index f817663..1929225 100644
> --- a/arch/arm/probes/kprobes/checkers-arm.c
> +++ b/arch/arm/probes/kprobes/checkers-arm.c
> @@ -97,3 +97,127 @@ const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
>  	[PROBES_STORE] = {.checker = arm_check_stack},
>  	[PROBES_LDMSTM] = {.checker = arm_check_stack},
>  };
> +
> +static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	asi->register_usage_flag = 0;
> +	return INSN_GOOD;
> +}
> +
> +static void __arm_check_regs(probes_opcode_t insn,
> +		const struct decode_header *h,
> +		int *quintuple)
> +{
> +	int i;
> +	u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
> +	probes_opcode_t mask, shifted;
> +
> +	memset(quintuple, 0xff, sizeof(int) * 5);

Not sure that filling with 0xff is a C standard compliant way of
initialising int's to a negative value. Anyway, memset isn't really
needed, see next comment.

> +	for (i = 0, shifted = insn, mask = 0xf; regs != 0;
> +			regs >>= 4, mask <<= 4, shifted >>= 4, i++)
> +		if (regs & 0xf)
> +			quintuple[i] = shifted & 0xf;

Looks a bit complicated, the last 6 lines could be more simply expressed
as:
	for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
		quintuple[i] = regs & 0xf ? insn & 0xf : -1;

Though I think that this function may be a bit overkill anyway, it is
only really needed in one place, so may as well be inlined there, that
is the function below... 

> +}
> +
> +static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	int quintuple[5], i;
> +	asi->register_usage_flag = 0;
> +	__arm_check_regs(insn, h, quintuple);
> +	for (i = 0; i < 5; i++) {
> +		int r = quintuple[i];
> +		if (r < 0)
> +			continue;
> +		set_register_use(asi->register_usage_flag, r);
> +	}
> +

The above can be as simply written without using _arm_check_regs like...

	u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
	int i;

	asi->register_usage_flag = 0;
	for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
		if (regs & 0xf)
			asi->register_usage_flag |= 1 << (insn & 0xf);


> +	return INSN_GOOD;
> +}
> +
> +static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	unsigned int reglist = insn & 0xffff;
> +	unsigned int rn = (insn >> 16) & 0xf;
> +	int i;
> +

Think you forgot to clear asi->register_usage_flag here, it will still
contain 0xffffffff set by from probes_decode_insn(). However, we don't
need this if we follow my next suggestion.

> +	set_register_use(asi->register_usage_flag, rn);
> +	for (i = 0; reglist > 0; i++, reglist >>= 1)
> +		if (reglist & 1)
> +			set_register_use(asi->register_usage_flag, i);

The preceding 5 lines are equivalent to

	asi->register_usage_flag = reglist | (1 << rn);

so how about we just use that?

> +	return INSN_GOOD;
> +}
> +
> +static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	/* should be 'mov ip, sp' */
> +	set_register_use(asi->register_usage_flag, 12);
> +	set_register_use(asi->register_usage_flag, 13);

register_usage_flag needs setting to zero before setting the flags. Or
we could just write this function as

	/* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */
	asi->register_usage_flag = (1 << 12) | (1<< 13);

> +	return INSN_GOOD;
> +}
> +
> +/*
> + *                                    | Rn |Rt/d|         | Rm |
> + * LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
> + * STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
> + *                                    | Rn |Rt/d|         |imm4L|
> + * LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
> + * STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
> + *
> + * Such instructions access Rt/d and its next register, so different
> + * from others, a specific checker is required for Rt/d and Rt2/d2.
> + */
> +static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	int quintuple[5], rn, rdt, rm;
> +	asi->register_usage_flag = 0;
> +	__arm_check_regs(insn, h, quintuple);
> +
> +	rn = quintuple[4];
> +	rdt = quintuple[3];
> +	rm = quintuple[0];
> +        set_register_use(asi->register_usage_flag, rn);
> +        set_register_use(asi->register_usage_flag, rdt);
> +        set_register_use(asi->register_usage_flag, rdt + 1);
> +	if (rm >= 0)
> +		set_register_use(asi->register_usage_flag, rm);
> +

We can avoid most of this code if we reuse arm_check_regs_normal and
then add in the use of rdt+1, i.e. this function can be simply...

	int rdt = (insn >> 12) & 0xf;
	arm_check_regs_normal(insn, asi, h);
	asi->register_usage_flag |= 1 << (rdt + 1);


> +	return INSN_GOOD;
> +}
> +
> +
> +const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
> +	[PROBES_EMULATE_NONE] = {.checker = arm_check_regs_nouse},
> +	[PROBES_SIMULATE_NOP] = {.checker = arm_check_regs_nouse},
> +	[PROBES_MRS] = {.checker = arm_check_regs_normal},
> +	[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL1] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL2] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LOAD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
> +	[PROBES_STORE] = {.checker = arm_check_regs_normal},
> +	[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
> +	[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
> +	[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
> +	[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
> +	[PROBES_REV] = {.checker = arm_check_regs_normal},
> +	[PROBES_MMI] = {.checker = arm_check_regs_normal},
> +	[PROBES_PACK] = {.checker = arm_check_regs_normal},
> +	[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
> +	[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
> +	[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
> +	[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
> +	[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
> +};
> diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h
> index bddfa0e..cf6c9e7 100644
> --- a/arch/arm/probes/kprobes/checkers.h
> +++ b/arch/arm/probes/kprobes/checkers.h
> @@ -47,6 +47,7 @@ extern const union decode_action stack_check_actions[];
>  
>  #ifndef CONFIG_THUMB2_KERNEL
>  extern const struct decode_checker arm_stack_checker[];
> +extern const struct decode_checker arm_regs_checker[];
>  #else
>  #endif
>  extern const struct decode_checker t32_stack_checker[];

I've made a lot, of suggestions for code changes, so I think it's best
if I follow up to this email with a new version of this patch which
applies them all so we can see what the bigger picture is...

-- 
Tixy



^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] ARM: kprobes: check register usage for probed instruction
  2015-01-13 15:01   ` Jon Medhurst (Tixy)
@ 2015-01-13 16:13     ` Jon Medhurst (Tixy)
  2015-01-19 10:37       ` Wang Nan
  0 siblings, 1 reply; 31+ messages in thread
From: Jon Medhurst (Tixy) @ 2015-01-13 16:13 UTC (permalink / raw)
  To: Wang Nan
  Cc: masami.hiramatsu.pt, lizefan, linux, linux-kernel, linux-arm-kernel

This patch utilizes the previously introduced checker to check
register usage for probed ARM instruction and saves it in a mask.
A further patch will use such information to avoid simulation or
emulation.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
---

This patch applies my review comments on "[PATCH v19 10/11] ARM:
kprobes: check register usage for probed instruction."

It is also rebased on top of the kprobes-opt branch at
git://git.linaro.org/people/tixy/kernel.git

 arch/arm/include/asm/probes.h          |  1 +
 arch/arm/probes/decode.c               |  7 +++
 arch/arm/probes/kprobes/actions-arm.c  |  2 +-
 arch/arm/probes/kprobes/checkers-arm.c | 93 ++++++++++++++++++++++++++++++++++
 arch/arm/probes/kprobes/checkers.h     |  1 +
 5 files changed, 103 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index cd9e815..b668e60 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -41,6 +41,7 @@ struct arch_probes_insn {
 	probes_insn_singlestep_t	*insn_singlestep;
 	probes_insn_fn_t		*insn_fn;
 	int				stack_space;
+	unsigned long			register_usage_flags;
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
index f9d7c42..880ebe0 100644
--- a/arch/arm/probes/decode.c
+++ b/arch/arm/probes/decode.c
@@ -435,6 +435,13 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
 	 */
 	asi->stack_space = 0;
 
+	/*
+	 * Similarly to stack_space, register_usage_flags is filled by
+	 * checkers. Its default value is set to ~0, which is 'all
+	 * registers are used', to prevent any potential optimization.
+	 */
+	asi->register_usage_flags = ~0UL;
+
 	if (emulate)
 		insn = prepare_emulated_insn(insn, asi, thumb);
 
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 06988ef..b9056d6 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -341,4 +341,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[] = {arm_stack_checker, NULL};
+const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c
index f817663..7b98173 100644
--- a/arch/arm/probes/kprobes/checkers-arm.c
+++ b/arch/arm/probes/kprobes/checkers-arm.c
@@ -97,3 +97,96 @@ const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
 	[PROBES_STORE] = {.checker = arm_check_stack},
 	[PROBES_LDMSTM] = {.checker = arm_check_stack},
 };
+
+static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	asi->register_usage_flags = 0;
+	return INSN_GOOD;
+}
+
+static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
+	int i;
+
+	asi->register_usage_flags = 0;
+	for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
+		if (regs & 0xf)
+			asi->register_usage_flags |= 1 << (insn & 0xf);
+
+	return INSN_GOOD;
+}
+
+
+static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	unsigned int reglist = insn & 0xffff;
+	unsigned int rn = (insn >> 16) & 0xf;
+	asi->register_usage_flags = reglist | (1 << rn);
+	return INSN_GOOD;
+}
+
+static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	/* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */
+	asi->register_usage_flags = (1 << 12) | (1<< 13);
+	return INSN_GOOD;
+}
+
+/*
+ *                                    | Rn |Rt/d|         | Rm |
+ * LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
+ * STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
+ *                                    | Rn |Rt/d|         |imm4L|
+ * LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
+ * STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
+ *
+ * Such instructions access Rt/d and its next register, so different
+ * from others, a specific checker is required to handle this extra
+ * implicit register usage.
+ */
+static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
+		struct arch_probes_insn *asi,
+		const struct decode_header *h)
+{
+	int rdt = (insn >> 12) & 0xf;
+	arm_check_regs_normal(insn, asi, h);
+	asi->register_usage_flags |= 1 << (rdt + 1);
+	return INSN_GOOD;
+}
+
+
+const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
+	[PROBES_MRS] = {.checker = arm_check_regs_normal},
+	[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL1] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL2] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
+	[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
+	[PROBES_LOAD] = {.checker = arm_check_regs_normal},
+	[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
+	[PROBES_STORE] = {.checker = arm_check_regs_normal},
+	[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
+	[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
+	[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
+	[PROBES_SEV] = {.checker = arm_check_regs_nouse},
+	[PROBES_WFE] = {.checker = arm_check_regs_nouse},
+	[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
+	[PROBES_REV] = {.checker = arm_check_regs_normal},
+	[PROBES_MMI] = {.checker = arm_check_regs_normal},
+	[PROBES_PACK] = {.checker = arm_check_regs_normal},
+	[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
+	[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
+	[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
+	[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
+	[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
+	[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
+};
diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h
index bddfa0e..cf6c9e7 100644
--- a/arch/arm/probes/kprobes/checkers.h
+++ b/arch/arm/probes/kprobes/checkers.h
@@ -47,6 +47,7 @@ extern const union decode_action stack_check_actions[];
 
 #ifndef CONFIG_THUMB2_KERNEL
 extern const struct decode_checker arm_stack_checker[];
+extern const struct decode_checker arm_regs_checker[];
 #else
 #endif
 extern const struct decode_checker t32_stack_checker[];
-- 
2.1.4




^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] ARM: kprobes: check register usage for probed instruction
  2015-01-13 16:13     ` [PATCH] " Jon Medhurst (Tixy)
@ 2015-01-19 10:37       ` Wang Nan
  0 siblings, 0 replies; 31+ messages in thread
From: Wang Nan @ 2015-01-19 10:37 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: masami.hiramatsu.pt, lizefan, linux, linux-kernel, linux-arm-kernel

I think this patch is better than mo original one.

Thanks to Tixy.

On 2015/1/14 0:13, Jon Medhurst (Tixy) wrote:
> This patch utilizes the previously introduced checker to check
> register usage for probed ARM instruction and saves it in a mask.
> A further patch will use such information to avoid simulation or
> emulation.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Reviewed-by: Jon Medhurst <tixy@linaro.org>
> Signed-off-by: Jon Medhurst <tixy@linaro.org>
> ---
> 
> This patch applies my review comments on "[PATCH v19 10/11] ARM:
> kprobes: check register usage for probed instruction."
> 
> It is also rebased on top of the kprobes-opt branch at
> git://git.linaro.org/people/tixy/kernel.git
> 
>  arch/arm/include/asm/probes.h          |  1 +
>  arch/arm/probes/decode.c               |  7 +++
>  arch/arm/probes/kprobes/actions-arm.c  |  2 +-
>  arch/arm/probes/kprobes/checkers-arm.c | 93 ++++++++++++++++++++++++++++++++++
>  arch/arm/probes/kprobes/checkers.h     |  1 +
>  5 files changed, 103 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
> index cd9e815..b668e60 100644
> --- a/arch/arm/include/asm/probes.h
> +++ b/arch/arm/include/asm/probes.h
> @@ -41,6 +41,7 @@ struct arch_probes_insn {
>  	probes_insn_singlestep_t	*insn_singlestep;
>  	probes_insn_fn_t		*insn_fn;
>  	int				stack_space;
> +	unsigned long			register_usage_flags;
>  };
>  
>  #endif /* __ASSEMBLY__ */
> diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
> index f9d7c42..880ebe0 100644
> --- a/arch/arm/probes/decode.c
> +++ b/arch/arm/probes/decode.c
> @@ -435,6 +435,13 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
>  	 */
>  	asi->stack_space = 0;
>  
> +	/*
> +	 * Similarly to stack_space, register_usage_flags is filled by
> +	 * checkers. Its default value is set to ~0, which is 'all
> +	 * registers are used', to prevent any potential optimization.
> +	 */
> +	asi->register_usage_flags = ~0UL;
> +
>  	if (emulate)
>  		insn = prepare_emulated_insn(insn, asi, thumb);
>  
> diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
> index 06988ef..b9056d6 100644
> --- a/arch/arm/probes/kprobes/actions-arm.c
> +++ b/arch/arm/probes/kprobes/actions-arm.c
> @@ -341,4 +341,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[] = {arm_stack_checker, NULL};
> +const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
> diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c
> index f817663..7b98173 100644
> --- a/arch/arm/probes/kprobes/checkers-arm.c
> +++ b/arch/arm/probes/kprobes/checkers-arm.c
> @@ -97,3 +97,96 @@ const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
>  	[PROBES_STORE] = {.checker = arm_check_stack},
>  	[PROBES_LDMSTM] = {.checker = arm_check_stack},
>  };
> +
> +static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	asi->register_usage_flags = 0;
> +	return INSN_GOOD;
> +}
> +
> +static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
> +	int i;
> +
> +	asi->register_usage_flags = 0;
> +	for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
> +		if (regs & 0xf)
> +			asi->register_usage_flags |= 1 << (insn & 0xf);
> +
> +	return INSN_GOOD;
> +}
> +
> +
> +static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	unsigned int reglist = insn & 0xffff;
> +	unsigned int rn = (insn >> 16) & 0xf;
> +	asi->register_usage_flags = reglist | (1 << rn);
> +	return INSN_GOOD;
> +}
> +
> +static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	/* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */
> +	asi->register_usage_flags = (1 << 12) | (1<< 13);
> +	return INSN_GOOD;
> +}
> +
> +/*
> + *                                    | Rn |Rt/d|         | Rm |
> + * LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
> + * STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
> + *                                    | Rn |Rt/d|         |imm4L|
> + * LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
> + * STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
> + *
> + * Such instructions access Rt/d and its next register, so different
> + * from others, a specific checker is required to handle this extra
> + * implicit register usage.
> + */
> +static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
> +		struct arch_probes_insn *asi,
> +		const struct decode_header *h)
> +{
> +	int rdt = (insn >> 12) & 0xf;
> +	arm_check_regs_normal(insn, asi, h);
> +	asi->register_usage_flags |= 1 << (rdt + 1);
> +	return INSN_GOOD;
> +}
> +
> +
> +const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
> +	[PROBES_MRS] = {.checker = arm_check_regs_normal},
> +	[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL1] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL2] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
> +	[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LOAD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
> +	[PROBES_STORE] = {.checker = arm_check_regs_normal},
> +	[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
> +	[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
> +	[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
> +	[PROBES_SEV] = {.checker = arm_check_regs_nouse},
> +	[PROBES_WFE] = {.checker = arm_check_regs_nouse},
> +	[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
> +	[PROBES_REV] = {.checker = arm_check_regs_normal},
> +	[PROBES_MMI] = {.checker = arm_check_regs_normal},
> +	[PROBES_PACK] = {.checker = arm_check_regs_normal},
> +	[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
> +	[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
> +	[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
> +	[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
> +	[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
> +	[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
> +};
> diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h
> index bddfa0e..cf6c9e7 100644
> --- a/arch/arm/probes/kprobes/checkers.h
> +++ b/arch/arm/probes/kprobes/checkers.h
> @@ -47,6 +47,7 @@ extern const union decode_action stack_check_actions[];
>  
>  #ifndef CONFIG_THUMB2_KERNEL
>  extern const struct decode_checker arm_stack_checker[];
> +extern const struct decode_checker arm_regs_checker[];
>  #else
>  #endif
>  extern const struct decode_checker t32_stack_checker[];
> 



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Re: [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements.
  2015-01-07 13:40 ` [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Jon Medhurst (Tixy)
@ 2015-01-20  2:17   ` Masami Hiramatsu
  0 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2015-01-20  2:17 UTC (permalink / raw)
  To: Jon Medhurst (Tixy)
  Cc: Wang Nan, linux, lizefan, linux-kernel, linux-arm-kernel

(2015/01/07 22:40), Jon Medhurst (Tixy) wrote:
> I think that the patches up to 09/11 inclusive have been though more
> that enough review and revisions to think about getting them merged,
> there doesn't seem much point in continuously resending them whilst new
> features are built on top of them.
> 
> Masami Hiramatsu, are you happy for your patch to generic+X86 kprobes
> code [1] to go through the ARM maintainers tree, assuming Russell is
> also happy with that. Or should that go via a different route?

Yes, I'm OK to go it through the ARM maintainers tree :)

Thank you,

> 
> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/313218.html
> 
> Wang Nan, assuming everyone is happy, can you put together a branch in a
> git repository for those patches, or I'm more than happy to do that if
> you like. Then I can give the series a final test and we can send a pull
> request to Russell King.
> 
> Thanks all
> 


-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com



^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2015-01-20  2:17 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-05 11:28 [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Wang Nan
2015-01-05 11:29 ` [PATCH v19 01/11] ARM: probes: move all probe code to dedicate directory Wang Nan
2015-01-09  2:19   ` [PATCH v20 " Wang Nan
2015-01-09  9:47     ` Jon Medhurst (Tixy)
2015-01-09  9:50       ` Wang Nan
2015-01-09  2:28   ` [PATCH v19 " Wang Nan
2015-01-05 11:29 ` [PATCH v19 02/11] ARM: kprobes: remove unused ARM decoder actions Wang Nan
2015-01-07 11:50   ` Jon Medhurst (Tixy)
2015-01-05 11:29 ` [PATCH v19 03/11] ARM: kprobes: introduces checker Wang Nan
2015-01-05 11:29 ` [PATCH v19 04/11] ARM: kprobes: collects stack consumption for store instructions Wang Nan
2015-01-05 11:29 ` [PATCH v19 05/11] ARM: kprobes: disallow probing stack consuming instructions Wang Nan
2015-01-05 11:29 ` [PATCH v19 06/11] ARM: kprobes: Add test cases for " Wang Nan
2015-01-05 11:29 ` [PATCH v19 07/11] kprobes: Pass the original kprobe for preparing optimized kprobe Wang Nan
2015-01-05 11:29 ` [PATCH v19 08/11] ARM: kprobes: enable OPTPROBES for ARM 32 Wang Nan
2015-01-07 13:01   ` Jon Medhurst (Tixy)
2015-01-09  6:37   ` [PATCH v20 " Wang Nan
2015-01-09 10:25     ` Jon Medhurst (Tixy)
2015-01-09 10:55       ` Wang Nan
2015-01-09 16:35       ` Russell King - ARM Linux
2015-01-09 17:28         ` Jon Medhurst (Tixy)
2015-01-09 17:57           ` Russell King - ARM Linux
2015-01-09 19:18             ` Jon Medhurst (Tixy)
2015-01-09  6:51   ` [PATCH v19 " Wang Nan
2015-01-05 11:29 ` [PATCH v19 09/11] ARM: kprobes: Fix unreliable MRS instruction tests Wang Nan
2015-01-05 11:29 ` [PATCH v19 10/11] ARM: kprobes: check register usage for probed instruction Wang Nan
2015-01-13 15:01   ` Jon Medhurst (Tixy)
2015-01-13 16:13     ` [PATCH] " Jon Medhurst (Tixy)
2015-01-19 10:37       ` Wang Nan
2015-01-05 11:34 ` [PATCH v19 11/11] ARM: optprobes: execute instruction during restoring if possible Wang Nan
2015-01-07 13:40 ` [PATCH v19 00/11] ARM: kprobes: OPTPROBES and other improvements Jon Medhurst (Tixy)
2015-01-20  2:17   ` Masami Hiramatsu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).