All of lore.kernel.org
 help / color / mirror / Atom feed
* [RESEND PATCH] arm64: Store breakpoint single step state into pstate
@ 2015-12-23  8:52 ` Wang Nan
  0 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2015-12-23  8:52 UTC (permalink / raw)
  To: takahiro.akashi, guohanjun, jolsa, will.deacon
  Cc: linux-arm-kernel, linux-kernel, pi3orama, Wang Nan

Two 'perf test' fail on arm64:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : FAILED!
 18: Test breakpoint overflow sampling                        : FAILED!

When breakpoint raises, after perf_bp_event, breakpoint_handler()
temporary disables breakpoint and enables single step. Then in
single_step_handler(), reenable breakpoint. Without doing this
the breakpoint would be triggered again.

However, if there's a pending signal and it have signal handler,
control would be transfer to signal handler, so single step handler
would be applied to the first instruction of signal handler. After
the handler return, the instruction triggered the breakpoint would be
executed again. At this time the breakpoint is enabled, so the
breakpoint is triggered again.

There was similar problem on x86, so we have following two commits:

commit 24cda10996f5420ab962f91cd03c15869a3a94b1("x86/signals: Clear RF
EFLAGS bit for signal handler"),

commit 5e219b3c671b34b2d79468fe89c44c0460c0f02b("x86/signals: Propagate
RF EFLAGS bit through the signal restore call").

When breakpoint handler enables single step, task is in a special state
that, the breakpoint should be disabled, the single step should be
enabled, and they should be toggled in single step handler.
This state should be cleared when entering signal handler and restored
after signal return like other program state. Considering the
situation that signal raises inside signal handler, the only safe way
to avoid the problem is to save this state into signal frame, like what
x86 does.

Different from x86 which has an RF EFLAGS bit to control debug
behavior, there's no such bits on ARM64. Creating new fields in signal
frame makes trouble because it is part of user API. Fortunately, on
ARM64, we use a 64 bits pstate but the hardware only utilises the
lowest 32 bits. The other 32 bits can be used by kernel to record this
state.

This patch create two bits in pstate to record the special state caused
by breakpoint and watchpoint. In handle_signal, the state is checked
and the bits are set accordingly, then the hardware is restored.
When signal return, single step can be reenabled based on these bits.

After this patch:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : Ok
 18: Test breakpoint overflow sampling                        : Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Hanjun Guo <guohanjun@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
---

Resend due to wrong email address.

---
 arch/arm64/include/asm/debug-monitors.h |  9 ++++++
 arch/arm64/include/uapi/asm/ptrace.h    | 12 ++++++++
 arch/arm64/kernel/hw_breakpoint.c       | 50 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/signal.c              |  2 ++
 4 files changed, 73 insertions(+)

diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 279c85b5..bd6f873 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -132,11 +132,20 @@ int kernel_active_single_step(void);
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 int reinstall_suspended_bps(struct pt_regs *regs);
+u64 signal_toggle_single_step(void);
+void signal_reinstall_single_step(u64 pstate);
 #else
 static inline int reinstall_suspended_bps(struct pt_regs *regs)
 {
 	return -ENODEV;
 }
+static u64 signal_toggle_single_step(void)
+{
+	return 0;
+}
+void signal_reinstall_single_step(void)
+{
+}
 #endif
 
 int aarch32_break_handler(struct pt_regs *regs);
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 208db3d..bfb90f6 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -52,6 +52,18 @@
 #define PSR_N_BIT	0x80000000
 
 /*
+ * pstat in pt_regs and user_pt_regs are 64 bits. The highest 32 bits
+ * of it can be utilized by other. One user of them is signal handler.
+ */
+#define PSR_LINUX_MASK		(0xffffffffUL << 32)
+/* Single step and disable breakpoints */
+#define PSR_LINUX_HW_BP_SS	(1UL << 32)
+/* Single step and disable watchpoints */
+#define PSR_LINUX_HW_WP_SS	(2UL << 32)
+
+#define PSR_LINUX_HW_SS	(PSR_LINUX_HW_BP_SS | PSR_LINUX_HW_WP_SS)
+
+/*
  * Groups of PSR bits
  */
 #define PSR_f		0xff000000	/* Flags		*/
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index b45c95d..e5a0998 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -954,3 +954,53 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 {
 	return NOTIFY_DONE;
 }
+
+u64 signal_toggle_single_step(void)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+	u64 retval = 0;
+
+	if (likely(!debug_info->bps_disabled && !debug_info->wps_disabled))
+		return 0;
+
+	if (debug_info->bps_disabled) {
+		retval |= PSR_LINUX_HW_BP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1);
+		debug_info->bps_disabled = 0;
+	}
+
+	if (debug_info->wps_disabled) {
+		retval |= PSR_LINUX_HW_WP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+		debug_info->wps_disabled = 0;
+	}
+
+	if (debug_info->suspended_step)
+		debug_info->suspended_step = 0;
+	else
+		user_disable_single_step(current);
+	return retval;
+}
+
+void signal_reinstall_single_step(u64 pstate)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+
+	if (likely(!(pstate & PSR_LINUX_HW_SS)))
+		return;
+
+	if (pstate & PSR_LINUX_HW_BP_SS) {
+		debug_info->bps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (pstate & PSR_LINUX_HW_WP_SS) {
+		debug_info->wps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (test_thread_flag(TIF_SINGLESTEP))
+		debug_info->suspended_step = 1;
+	else
+		user_enable_single_step(current);
+}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e18c48c..1737710 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -151,6 +151,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
+	signal_reinstall_single_step(regs->pstate);
 	return regs->regs[0];
 
 badframe:
@@ -292,6 +293,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 	int usig = ksig->sig;
 	int ret;
 
+	regs->pstate |= signal_toggle_single_step();
 	/*
 	 * Set up the stack frame
 	 */
-- 
1.8.3.4


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

* [RESEND PATCH] arm64: Store breakpoint single step state into pstate
@ 2015-12-23  8:52 ` Wang Nan
  0 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2015-12-23  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

Two 'perf test' fail on arm64:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : FAILED!
 18: Test breakpoint overflow sampling                        : FAILED!

When breakpoint raises, after perf_bp_event, breakpoint_handler()
temporary disables breakpoint and enables single step. Then in
single_step_handler(), reenable breakpoint. Without doing this
the breakpoint would be triggered again.

However, if there's a pending signal and it have signal handler,
control would be transfer to signal handler, so single step handler
would be applied to the first instruction of signal handler. After
the handler return, the instruction triggered the breakpoint would be
executed again. At this time the breakpoint is enabled, so the
breakpoint is triggered again.

There was similar problem on x86, so we have following two commits:

commit 24cda10996f5420ab962f91cd03c15869a3a94b1("x86/signals: Clear RF
EFLAGS bit for signal handler"),

commit 5e219b3c671b34b2d79468fe89c44c0460c0f02b("x86/signals: Propagate
RF EFLAGS bit through the signal restore call").

When breakpoint handler enables single step, task is in a special state
that, the breakpoint should be disabled, the single step should be
enabled, and they should be toggled in single step handler.
This state should be cleared when entering signal handler and restored
after signal return like other program state. Considering the
situation that signal raises inside signal handler, the only safe way
to avoid the problem is to save this state into signal frame, like what
x86 does.

Different from x86 which has an RF EFLAGS bit to control debug
behavior, there's no such bits on ARM64. Creating new fields in signal
frame makes trouble because it is part of user API. Fortunately, on
ARM64, we use a 64 bits pstate but the hardware only utilises the
lowest 32 bits. The other 32 bits can be used by kernel to record this
state.

This patch create two bits in pstate to record the special state caused
by breakpoint and watchpoint. In handle_signal, the state is checked
and the bits are set accordingly, then the hardware is restored.
When signal return, single step can be reenabled based on these bits.

After this patch:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : Ok
 18: Test breakpoint overflow sampling                        : Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Hanjun Guo <guohanjun@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
---

Resend due to wrong email address.

---
 arch/arm64/include/asm/debug-monitors.h |  9 ++++++
 arch/arm64/include/uapi/asm/ptrace.h    | 12 ++++++++
 arch/arm64/kernel/hw_breakpoint.c       | 50 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/signal.c              |  2 ++
 4 files changed, 73 insertions(+)

diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 279c85b5..bd6f873 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -132,11 +132,20 @@ int kernel_active_single_step(void);
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 int reinstall_suspended_bps(struct pt_regs *regs);
+u64 signal_toggle_single_step(void);
+void signal_reinstall_single_step(u64 pstate);
 #else
 static inline int reinstall_suspended_bps(struct pt_regs *regs)
 {
 	return -ENODEV;
 }
+static u64 signal_toggle_single_step(void)
+{
+	return 0;
+}
+void signal_reinstall_single_step(void)
+{
+}
 #endif
 
 int aarch32_break_handler(struct pt_regs *regs);
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 208db3d..bfb90f6 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -52,6 +52,18 @@
 #define PSR_N_BIT	0x80000000
 
 /*
+ * pstat in pt_regs and user_pt_regs are 64 bits. The highest 32 bits
+ * of it can be utilized by other. One user of them is signal handler.
+ */
+#define PSR_LINUX_MASK		(0xffffffffUL << 32)
+/* Single step and disable breakpoints */
+#define PSR_LINUX_HW_BP_SS	(1UL << 32)
+/* Single step and disable watchpoints */
+#define PSR_LINUX_HW_WP_SS	(2UL << 32)
+
+#define PSR_LINUX_HW_SS	(PSR_LINUX_HW_BP_SS | PSR_LINUX_HW_WP_SS)
+
+/*
  * Groups of PSR bits
  */
 #define PSR_f		0xff000000	/* Flags		*/
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index b45c95d..e5a0998 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -954,3 +954,53 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 {
 	return NOTIFY_DONE;
 }
+
+u64 signal_toggle_single_step(void)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+	u64 retval = 0;
+
+	if (likely(!debug_info->bps_disabled && !debug_info->wps_disabled))
+		return 0;
+
+	if (debug_info->bps_disabled) {
+		retval |= PSR_LINUX_HW_BP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1);
+		debug_info->bps_disabled = 0;
+	}
+
+	if (debug_info->wps_disabled) {
+		retval |= PSR_LINUX_HW_WP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+		debug_info->wps_disabled = 0;
+	}
+
+	if (debug_info->suspended_step)
+		debug_info->suspended_step = 0;
+	else
+		user_disable_single_step(current);
+	return retval;
+}
+
+void signal_reinstall_single_step(u64 pstate)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+
+	if (likely(!(pstate & PSR_LINUX_HW_SS)))
+		return;
+
+	if (pstate & PSR_LINUX_HW_BP_SS) {
+		debug_info->bps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (pstate & PSR_LINUX_HW_WP_SS) {
+		debug_info->wps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (test_thread_flag(TIF_SINGLESTEP))
+		debug_info->suspended_step = 1;
+	else
+		user_enable_single_step(current);
+}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e18c48c..1737710 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -151,6 +151,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
+	signal_reinstall_single_step(regs->pstate);
 	return regs->regs[0];
 
 badframe:
@@ -292,6 +293,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 	int usig = ksig->sig;
 	int ret;
 
+	regs->pstate |= signal_toggle_single_step();
 	/*
 	 * Set up the stack frame
 	 */
-- 
1.8.3.4

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

* Re: [RESEND PATCH] arm64: Store breakpoint single step state into pstate
  2015-12-23  8:52 ` Wang Nan
@ 2015-12-23 10:44   ` kbuild test robot
  -1 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-23 10:44 UTC (permalink / raw)
  To: Wang Nan
  Cc: kbuild-all, takahiro.akashi, guohanjun, jolsa, will.deacon,
	linux-arm-kernel, linux-kernel, pi3orama, Wang Nan

[-- Attachment #1: Type: text/plain, Size: 7166 bytes --]

Hi Wang,

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on v4.4-rc6 next-20151223]

url:    https://github.com/0day-ci/linux/commits/Wang-Nan/arm64-Store-breakpoint-single-step-state-into-pstate/20151223-165432
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux for-next/core
config: arm64-allnoconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   arch/arm64/kernel//irq.o: In function `signal_reinstall_single_step':
>> irq.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//fpsimd.o: In function `signal_reinstall_single_step':
   fpsimd.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//process.o: In function `signal_reinstall_single_step':
   process.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//ptrace.o: In function `signal_reinstall_single_step':
   ptrace.c:(.text+0x368): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//setup.o: In function `signal_reinstall_single_step':
   setup.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   aarch64-linux-gnu-ld: cannot find arch/arm64/kernel//signal.o: No such file or directory
   arch/arm64/kernel//sys.o: In function `signal_reinstall_single_step':
   sys.c:(.text+0x28): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//stacktrace.o: In function `signal_reinstall_single_step':
   stacktrace.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//time.o: In function `signal_reinstall_single_step':
   time.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//traps.o: In function `signal_reinstall_single_step':
   traps.c:(.text+0x2c0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//io.o: In function `signal_reinstall_single_step':
   io.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//vdso.o: In function `signal_reinstall_single_step':
   vdso.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//psci.o: In function `signal_reinstall_single_step':
   psci.c:(.text+0x44): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpu_ops.o: In function `signal_reinstall_single_step':
   cpu_ops.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//insn.o: In function `signal_reinstall_single_step':
   insn.c:(.text+0x250): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//return_address.o: In function `signal_reinstall_single_step':
   return_address.c:(.text+0x90): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpuinfo.o: In function `signal_reinstall_single_step':
   cpuinfo.c:(.text+0x3dc): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpu_errata.o: In function `signal_reinstall_single_step':
   cpu_errata.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpufeature.o: In function `signal_reinstall_single_step':
   cpufeature.c:(.text+0x1c8): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//alternative.o: In function `signal_reinstall_single_step':
   alternative.c:(.text+0x13c): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cacheinfo.o: In function `signal_reinstall_single_step':
   cacheinfo.c:(.text+0x230): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//smp.o: In function `signal_reinstall_single_step':
   smp.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//smp_spin_table.o: In function `signal_reinstall_single_step':
   smp_spin_table.c:(.text+0x108): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//topology.o: In function `signal_reinstall_single_step':
   topology.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
--
   arch/arm64/kernel/signal.c: In function 'sys_rt_sigreturn':
>> arch/arm64/kernel/signal.c:154:2: error: too many arguments to function 'signal_reinstall_single_step'
     signal_reinstall_single_step(regs->pstate);
     ^
   In file included from arch/arm64/include/asm/bug.h:21:0,
                    from include/linux/bug.h:4,
                    from include/linux/signal.h:5,
                    from arch/arm64/kernel/signal.c:22:
   arch/arm64/include/asm/debug-monitors.h:146:6: note: declared here
    void signal_reinstall_single_step(void)
         ^

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 5635 bytes --]

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

* [RESEND PATCH] arm64: Store breakpoint single step state into pstate
@ 2015-12-23 10:44   ` kbuild test robot
  0 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-23 10:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Wang,

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on v4.4-rc6 next-20151223]

url:    https://github.com/0day-ci/linux/commits/Wang-Nan/arm64-Store-breakpoint-single-step-state-into-pstate/20151223-165432
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux for-next/core
config: arm64-allnoconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   arch/arm64/kernel//irq.o: In function `signal_reinstall_single_step':
>> irq.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//fpsimd.o: In function `signal_reinstall_single_step':
   fpsimd.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//process.o: In function `signal_reinstall_single_step':
   process.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//ptrace.o: In function `signal_reinstall_single_step':
   ptrace.c:(.text+0x368): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//setup.o: In function `signal_reinstall_single_step':
   setup.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   aarch64-linux-gnu-ld: cannot find arch/arm64/kernel//signal.o: No such file or directory
   arch/arm64/kernel//sys.o: In function `signal_reinstall_single_step':
   sys.c:(.text+0x28): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//stacktrace.o: In function `signal_reinstall_single_step':
   stacktrace.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//time.o: In function `signal_reinstall_single_step':
   time.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//traps.o: In function `signal_reinstall_single_step':
   traps.c:(.text+0x2c0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//io.o: In function `signal_reinstall_single_step':
   io.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//vdso.o: In function `signal_reinstall_single_step':
   vdso.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//psci.o: In function `signal_reinstall_single_step':
   psci.c:(.text+0x44): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpu_ops.o: In function `signal_reinstall_single_step':
   cpu_ops.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//insn.o: In function `signal_reinstall_single_step':
   insn.c:(.text+0x250): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//return_address.o: In function `signal_reinstall_single_step':
   return_address.c:(.text+0x90): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpuinfo.o: In function `signal_reinstall_single_step':
   cpuinfo.c:(.text+0x3dc): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpu_errata.o: In function `signal_reinstall_single_step':
   cpu_errata.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cpufeature.o: In function `signal_reinstall_single_step':
   cpufeature.c:(.text+0x1c8): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//alternative.o: In function `signal_reinstall_single_step':
   alternative.c:(.text+0x13c): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//cacheinfo.o: In function `signal_reinstall_single_step':
   cacheinfo.c:(.text+0x230): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//smp.o: In function `signal_reinstall_single_step':
   smp.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//smp_spin_table.o: In function `signal_reinstall_single_step':
   smp_spin_table.c:(.text+0x108): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
   arch/arm64/kernel//topology.o: In function `signal_reinstall_single_step':
   topology.c:(.text+0x0): multiple definition of `signal_reinstall_single_step'
   arch/arm64/kernel//debug-monitors.o:debug-monitors.c:(.text+0x2b4): first defined here
--
   arch/arm64/kernel/signal.c: In function 'sys_rt_sigreturn':
>> arch/arm64/kernel/signal.c:154:2: error: too many arguments to function 'signal_reinstall_single_step'
     signal_reinstall_single_step(regs->pstate);
     ^
   In file included from arch/arm64/include/asm/bug.h:21:0,
                    from include/linux/bug.h:4,
                    from include/linux/signal.h:5,
                    from arch/arm64/kernel/signal.c:22:
   arch/arm64/include/asm/debug-monitors.h:146:6: note: declared here
    void signal_reinstall_single_step(void)
         ^

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 5635 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20151223/0ac60ff7/attachment-0001.obj>

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
  2015-12-23  8:52 ` Wang Nan
@ 2015-12-24  1:42   ` Wang Nan
  -1 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2015-12-24  1:42 UTC (permalink / raw)
  To: takahiro.akashi, guohanjun, will.deacon
  Cc: linux-arm-kernel, linux-kernel, pi3orama, Wang Nan, Fengguang Wu,
	Jiri Olsa

Two 'perf test' fail on arm64:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : FAILED!
 18: Test breakpoint overflow sampling                        : FAILED!

When breakpoint raises, after perf_bp_event, breakpoint_handler()
temporary disables breakpoint and enables single step. Then in
single_step_handler(), reenable breakpoint. Without doing this
the breakpoint would be triggered again.

However, if there's a pending signal and it have signal handler,
control would be transfer to signal handler, so single step handler
would be applied to the first instruction of signal handler. After
the handler return, the instruction triggered the breakpoint would be
executed again. At this time the breakpoint is enabled, so the
breakpoint is triggered again.

There was similar problem on x86, so we have following two commits:

commit 24cda10996f5420ab962f91cd03c15869a3a94b1("x86/signals: Clear RF
EFLAGS bit for signal handler"),

commit 5e219b3c671b34b2d79468fe89c44c0460c0f02b("x86/signals: Propagate
RF EFLAGS bit through the signal restore call").

When breakpoint handler enables single step, task is in a special state
that, the breakpoint should be disabled, the single step should be
enabled, and they should be toggled in single step handler.
This state should be cleared when entering signal handler and restored
after signal return like other program state. Considering the
situation that signal raises inside signal handler, the only safe way
to avoid the problem is to save this state into signal frame, like what
x86 does.

Different from x86 which has an RF EFLAGS bit to control debug
behavior, there's no such bits on ARM64. Creating new fields in signal
frame makes trouble because it is part of user API. Fortunately, on
ARM64, we use a 64 bits pstate but the hardware only utilises the
lowest 32 bits. The other 32 bits can be used by kernel to record this
state.

This patch create two bits in pstate to record the special state caused
by breakpoint and watchpoint. In handle_signal, the state is checked
and the bits are set accordingly, then the hardware is restored.
When signal return, single step can be reenabled based on these bits.

After this patch:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : Ok
 18: Test breakpoint overflow sampling                        : Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Hanjun Guo <guohanjun@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
---

v1 -> v2: Fix !CONFIG_HAVE_HW_BREAKPOINT build: add missing 'static inline'.

 arch/arm64/include/asm/debug-monitors.h |  9 ++++++
 arch/arm64/include/uapi/asm/ptrace.h    | 12 ++++++++
 arch/arm64/kernel/hw_breakpoint.c       | 50 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/signal.c              |  2 ++
 4 files changed, 73 insertions(+)

diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 279c85b5..5529060 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -132,11 +132,20 @@ int kernel_active_single_step(void);
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 int reinstall_suspended_bps(struct pt_regs *regs);
+u64 signal_toggle_single_step(void);
+void signal_reinstall_single_step(u64 pstate);
 #else
 static inline int reinstall_suspended_bps(struct pt_regs *regs)
 {
 	return -ENODEV;
 }
+static inline u64 signal_toggle_single_step(void)
+{
+	return 0;
+}
+static inline void signal_reinstall_single_step(u64 pstate)
+{
+}
 #endif
 
 int aarch32_break_handler(struct pt_regs *regs);
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 208db3d..bfb90f6 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -52,6 +52,18 @@
 #define PSR_N_BIT	0x80000000
 
 /*
+ * pstat in pt_regs and user_pt_regs are 64 bits. The highest 32 bits
+ * of it can be utilized by other. One user of them is signal handler.
+ */
+#define PSR_LINUX_MASK		(0xffffffffUL << 32)
+/* Single step and disable breakpoints */
+#define PSR_LINUX_HW_BP_SS	(1UL << 32)
+/* Single step and disable watchpoints */
+#define PSR_LINUX_HW_WP_SS	(2UL << 32)
+
+#define PSR_LINUX_HW_SS	(PSR_LINUX_HW_BP_SS | PSR_LINUX_HW_WP_SS)
+
+/*
  * Groups of PSR bits
  */
 #define PSR_f		0xff000000	/* Flags		*/
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index b45c95d..e5a0998 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -954,3 +954,53 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 {
 	return NOTIFY_DONE;
 }
+
+u64 signal_toggle_single_step(void)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+	u64 retval = 0;
+
+	if (likely(!debug_info->bps_disabled && !debug_info->wps_disabled))
+		return 0;
+
+	if (debug_info->bps_disabled) {
+		retval |= PSR_LINUX_HW_BP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1);
+		debug_info->bps_disabled = 0;
+	}
+
+	if (debug_info->wps_disabled) {
+		retval |= PSR_LINUX_HW_WP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+		debug_info->wps_disabled = 0;
+	}
+
+	if (debug_info->suspended_step)
+		debug_info->suspended_step = 0;
+	else
+		user_disable_single_step(current);
+	return retval;
+}
+
+void signal_reinstall_single_step(u64 pstate)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+
+	if (likely(!(pstate & PSR_LINUX_HW_SS)))
+		return;
+
+	if (pstate & PSR_LINUX_HW_BP_SS) {
+		debug_info->bps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (pstate & PSR_LINUX_HW_WP_SS) {
+		debug_info->wps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (test_thread_flag(TIF_SINGLESTEP))
+		debug_info->suspended_step = 1;
+	else
+		user_enable_single_step(current);
+}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e18c48c..1737710 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -151,6 +151,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
+	signal_reinstall_single_step(regs->pstate);
 	return regs->regs[0];
 
 badframe:
@@ -292,6 +293,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 	int usig = ksig->sig;
 	int ret;
 
+	regs->pstate |= signal_toggle_single_step();
 	/*
 	 * Set up the stack frame
 	 */
-- 
1.8.3.4


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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2015-12-24  1:42   ` Wang Nan
  0 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2015-12-24  1:42 UTC (permalink / raw)
  To: linux-arm-kernel

Two 'perf test' fail on arm64:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : FAILED!
 18: Test breakpoint overflow sampling                        : FAILED!

When breakpoint raises, after perf_bp_event, breakpoint_handler()
temporary disables breakpoint and enables single step. Then in
single_step_handler(), reenable breakpoint. Without doing this
the breakpoint would be triggered again.

However, if there's a pending signal and it have signal handler,
control would be transfer to signal handler, so single step handler
would be applied to the first instruction of signal handler. After
the handler return, the instruction triggered the breakpoint would be
executed again. At this time the breakpoint is enabled, so the
breakpoint is triggered again.

There was similar problem on x86, so we have following two commits:

commit 24cda10996f5420ab962f91cd03c15869a3a94b1("x86/signals: Clear RF
EFLAGS bit for signal handler"),

commit 5e219b3c671b34b2d79468fe89c44c0460c0f02b("x86/signals: Propagate
RF EFLAGS bit through the signal restore call").

When breakpoint handler enables single step, task is in a special state
that, the breakpoint should be disabled, the single step should be
enabled, and they should be toggled in single step handler.
This state should be cleared when entering signal handler and restored
after signal return like other program state. Considering the
situation that signal raises inside signal handler, the only safe way
to avoid the problem is to save this state into signal frame, like what
x86 does.

Different from x86 which has an RF EFLAGS bit to control debug
behavior, there's no such bits on ARM64. Creating new fields in signal
frame makes trouble because it is part of user API. Fortunately, on
ARM64, we use a 64 bits pstate but the hardware only utilises the
lowest 32 bits. The other 32 bits can be used by kernel to record this
state.

This patch create two bits in pstate to record the special state caused
by breakpoint and watchpoint. In handle_signal, the state is checked
and the bits are set accordingly, then the hardware is restored.
When signal return, single step can be reenabled based on these bits.

After this patch:

 # perf test overflow
 17: Test breakpoint overflow signal handler                  : Ok
 18: Test breakpoint overflow sampling                        : Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Hanjun Guo <guohanjun@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
---

v1 -> v2: Fix !CONFIG_HAVE_HW_BREAKPOINT build: add missing 'static inline'.

 arch/arm64/include/asm/debug-monitors.h |  9 ++++++
 arch/arm64/include/uapi/asm/ptrace.h    | 12 ++++++++
 arch/arm64/kernel/hw_breakpoint.c       | 50 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/signal.c              |  2 ++
 4 files changed, 73 insertions(+)

diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 279c85b5..5529060 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -132,11 +132,20 @@ int kernel_active_single_step(void);
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 int reinstall_suspended_bps(struct pt_regs *regs);
+u64 signal_toggle_single_step(void);
+void signal_reinstall_single_step(u64 pstate);
 #else
 static inline int reinstall_suspended_bps(struct pt_regs *regs)
 {
 	return -ENODEV;
 }
+static inline u64 signal_toggle_single_step(void)
+{
+	return 0;
+}
+static inline void signal_reinstall_single_step(u64 pstate)
+{
+}
 #endif
 
 int aarch32_break_handler(struct pt_regs *regs);
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 208db3d..bfb90f6 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -52,6 +52,18 @@
 #define PSR_N_BIT	0x80000000
 
 /*
+ * pstat in pt_regs and user_pt_regs are 64 bits. The highest 32 bits
+ * of it can be utilized by other. One user of them is signal handler.
+ */
+#define PSR_LINUX_MASK		(0xffffffffUL << 32)
+/* Single step and disable breakpoints */
+#define PSR_LINUX_HW_BP_SS	(1UL << 32)
+/* Single step and disable watchpoints */
+#define PSR_LINUX_HW_WP_SS	(2UL << 32)
+
+#define PSR_LINUX_HW_SS	(PSR_LINUX_HW_BP_SS | PSR_LINUX_HW_WP_SS)
+
+/*
  * Groups of PSR bits
  */
 #define PSR_f		0xff000000	/* Flags		*/
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index b45c95d..e5a0998 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -954,3 +954,53 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 {
 	return NOTIFY_DONE;
 }
+
+u64 signal_toggle_single_step(void)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+	u64 retval = 0;
+
+	if (likely(!debug_info->bps_disabled && !debug_info->wps_disabled))
+		return 0;
+
+	if (debug_info->bps_disabled) {
+		retval |= PSR_LINUX_HW_BP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1);
+		debug_info->bps_disabled = 0;
+	}
+
+	if (debug_info->wps_disabled) {
+		retval |= PSR_LINUX_HW_WP_SS;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1);
+		debug_info->wps_disabled = 0;
+	}
+
+	if (debug_info->suspended_step)
+		debug_info->suspended_step = 0;
+	else
+		user_disable_single_step(current);
+	return retval;
+}
+
+void signal_reinstall_single_step(u64 pstate)
+{
+	struct debug_info *debug_info = &current->thread.debug;
+
+	if (likely(!(pstate & PSR_LINUX_HW_SS)))
+		return;
+
+	if (pstate & PSR_LINUX_HW_BP_SS) {
+		debug_info->bps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (pstate & PSR_LINUX_HW_WP_SS) {
+		debug_info->wps_disabled = 1;
+		toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0);
+	}
+
+	if (test_thread_flag(TIF_SINGLESTEP))
+		debug_info->suspended_step = 1;
+	else
+		user_enable_single_step(current);
+}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e18c48c..1737710 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -151,6 +151,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
+	signal_reinstall_single_step(regs->pstate);
 	return regs->regs[0];
 
 badframe:
@@ -292,6 +293,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 	int usig = ksig->sig;
 	int ret;
 
+	regs->pstate |= signal_toggle_single_step();
 	/*
 	 * Set up the stack frame
 	 */
-- 
1.8.3.4

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2015-12-24  1:42   ` Wang Nan
@ 2016-01-04 16:55     ` Will Deacon
  -1 siblings, 0 replies; 36+ messages in thread
From: Will Deacon @ 2016-01-04 16:55 UTC (permalink / raw)
  To: Wang Nan
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa

Hello,

On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:
> Two 'perf test' fail on arm64:
> 
>  # perf test overflow
>  17: Test breakpoint overflow signal handler                  : FAILED!
>  18: Test breakpoint overflow sampling                        : FAILED!
> 
> When breakpoint raises, after perf_bp_event, breakpoint_handler()
> temporary disables breakpoint and enables single step. Then in
> single_step_handler(), reenable breakpoint. Without doing this
> the breakpoint would be triggered again.
> 
> However, if there's a pending signal and it have signal handler,
> control would be transfer to signal handler, so single step handler
> would be applied to the first instruction of signal handler. After
> the handler return, the instruction triggered the breakpoint would be
> executed again. At this time the breakpoint is enabled, so the
> breakpoint is triggered again.

Whilst I appreciate that you're just trying to get those tests passing
on arm64, I really don't think its a good idea for us to try and emulate
the x86 debug semantics here. This doesn't happen for ptrace, and I think
we're likely to break more than we fix if we try to do it for perf too.

The problem seems to be that we take the debug exception before the
breakpointed instruction has been executed and call perf_bp_event at
that moment, so when we single-step the faulting instruction we actually
step into the SIGIO handler and end up getting stuck.

Your fix doesn't really address this afaict, in that you don't (can't?)
handle:

  * A longjmp out of a signal handler
  * A watchpoint and a breakpoint that fire on the same instruction
  * User-controlled single-step from a signal handler that enables a
    breakpoint explicitly
  * Nested signals

so I'd really rather leave the code as-is.

Will

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-04 16:55     ` Will Deacon
  0 siblings, 0 replies; 36+ messages in thread
From: Will Deacon @ 2016-01-04 16:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:
> Two 'perf test' fail on arm64:
> 
>  # perf test overflow
>  17: Test breakpoint overflow signal handler                  : FAILED!
>  18: Test breakpoint overflow sampling                        : FAILED!
> 
> When breakpoint raises, after perf_bp_event, breakpoint_handler()
> temporary disables breakpoint and enables single step. Then in
> single_step_handler(), reenable breakpoint. Without doing this
> the breakpoint would be triggered again.
> 
> However, if there's a pending signal and it have signal handler,
> control would be transfer to signal handler, so single step handler
> would be applied to the first instruction of signal handler. After
> the handler return, the instruction triggered the breakpoint would be
> executed again. At this time the breakpoint is enabled, so the
> breakpoint is triggered again.

Whilst I appreciate that you're just trying to get those tests passing
on arm64, I really don't think its a good idea for us to try and emulate
the x86 debug semantics here. This doesn't happen for ptrace, and I think
we're likely to break more than we fix if we try to do it for perf too.

The problem seems to be that we take the debug exception before the
breakpointed instruction has been executed and call perf_bp_event at
that moment, so when we single-step the faulting instruction we actually
step into the SIGIO handler and end up getting stuck.

Your fix doesn't really address this afaict, in that you don't (can't?)
handle:

  * A longjmp out of a signal handler
  * A watchpoint and a breakpoint that fire on the same instruction
  * User-controlled single-step from a signal handler that enables a
    breakpoint explicitly
  * Nested signals

so I'd really rather leave the code as-is.

Will

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-04 16:55     ` Will Deacon
@ 2016-01-05  1:41       ` Wangnan (F)
  -1 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  1:41 UTC (permalink / raw)
  To: Will Deacon
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa



On 2016/1/5 0:55, Will Deacon wrote:
> Hello,
>
> On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:
>> Two 'perf test' fail on arm64:
>>
>>   # perf test overflow
>>   17: Test breakpoint overflow signal handler                  : FAILED!
>>   18: Test breakpoint overflow sampling                        : FAILED!
>>
>> When breakpoint raises, after perf_bp_event, breakpoint_handler()
>> temporary disables breakpoint and enables single step. Then in
>> single_step_handler(), reenable breakpoint. Without doing this
>> the breakpoint would be triggered again.
>>
>> However, if there's a pending signal and it have signal handler,
>> control would be transfer to signal handler, so single step handler
>> would be applied to the first instruction of signal handler. After
>> the handler return, the instruction triggered the breakpoint would be
>> executed again. At this time the breakpoint is enabled, so the
>> breakpoint is triggered again.
> Whilst I appreciate that you're just trying to get those tests passing
> on arm64, I really don't think its a good idea for us to try and emulate
> the x86 debug semantics here. This doesn't happen for ptrace, and I think
> we're likely to break more than we fix if we try to do it for perf too.
>
> The problem seems to be that we take the debug exception before the
> breakpointed instruction has been executed and call perf_bp_event at
> that moment, so when we single-step the faulting instruction we actually
> step into the SIGIO handler and end up getting stuck.

Understand.

> Your fix doesn't really address this afaict,

I don't think so. After applying my patch, the entry of signal handler won't
be single-stepped. Please have a look at signal_toggle_single_step(): when
signal arises, single step handler is turned off, so signal handler won't
be stepped.

I thing the following 4 cases you mentioned should not causes error in 
theory:

>   in that you don't (can't?)
> handle:
>
>    * A longjmp out of a signal handler

The signal frame is dropped so stepping is omitted.

>    * A watchpoint and a breakpoint that fire on the same instruction

Watchpoints and breakpoints are controlled separatly. In this case it would
generated twp nested signals. I will try this.

>    * User-controlled single-step from a signal handler that enables a
>      breakpoint explicitly

debug_info->suspended_step controls this.

>    * Nested signals

I think nested signals can be dealt correctly because we save state in 
signal frame.

However I'll try the above cases you mentioned above.

Thank you.


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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-05  1:41       ` Wangnan (F)
  0 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  1:41 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016/1/5 0:55, Will Deacon wrote:
> Hello,
>
> On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:
>> Two 'perf test' fail on arm64:
>>
>>   # perf test overflow
>>   17: Test breakpoint overflow signal handler                  : FAILED!
>>   18: Test breakpoint overflow sampling                        : FAILED!
>>
>> When breakpoint raises, after perf_bp_event, breakpoint_handler()
>> temporary disables breakpoint and enables single step. Then in
>> single_step_handler(), reenable breakpoint. Without doing this
>> the breakpoint would be triggered again.
>>
>> However, if there's a pending signal and it have signal handler,
>> control would be transfer to signal handler, so single step handler
>> would be applied to the first instruction of signal handler. After
>> the handler return, the instruction triggered the breakpoint would be
>> executed again. At this time the breakpoint is enabled, so the
>> breakpoint is triggered again.
> Whilst I appreciate that you're just trying to get those tests passing
> on arm64, I really don't think its a good idea for us to try and emulate
> the x86 debug semantics here. This doesn't happen for ptrace, and I think
> we're likely to break more than we fix if we try to do it for perf too.
>
> The problem seems to be that we take the debug exception before the
> breakpointed instruction has been executed and call perf_bp_event at
> that moment, so when we single-step the faulting instruction we actually
> step into the SIGIO handler and end up getting stuck.

Understand.

> Your fix doesn't really address this afaict,

I don't think so. After applying my patch, the entry of signal handler won't
be single-stepped. Please have a look at signal_toggle_single_step(): when
signal arises, single step handler is turned off, so signal handler won't
be stepped.

I thing the following 4 cases you mentioned should not causes error in 
theory:

>   in that you don't (can't?)
> handle:
>
>    * A longjmp out of a signal handler

The signal frame is dropped so stepping is omitted.

>    * A watchpoint and a breakpoint that fire on the same instruction

Watchpoints and breakpoints are controlled separatly. In this case it would
generated twp nested signals. I will try this.

>    * User-controlled single-step from a signal handler that enables a
>      breakpoint explicitly

debug_info->suspended_step controls this.

>    * Nested signals

I think nested signals can be dealt correctly because we save state in 
signal frame.

However I'll try the above cases you mentioned above.

Thank you.

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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-04 16:55     ` Will Deacon
@ 2016-01-05  4:58       ` Wang Nan
  -1 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2016-01-05  4:58 UTC (permalink / raw)
  To: will.deacon
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	fengguang.wu, pi3orama, Wang Nan, Jiri Olsa,
	Arnaldo Carvalho de Melo

Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:

 1. A watchpoint and a breakpoint that fire on the same instruction
 2. Nested signals

For detail of this patch see the comment in patch body.

Test result:

 On both x86_64:

 # ./perf test -v signal
 17: Test breakpoint overflow signal handler                  :
 --- start ---
 test child forked, pid 10213
 count1 1, count2 3, count3 2, overflow 3, overflows_2 3
 test child finished with 0
 ---- end ----
 Test breakpoint overflow signal handler: Ok

So at least 2 cases Will doubted are handled correctly.

[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/bp_signal.c | 114 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 101 insertions(+), 13 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9e..0bc4f76 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,55 @@
 
 static int fd1;
 static int fd2;
+static int fd3;
 static int overflows;
+static int overflows_2;
+
+volatile long the_var;
+
+
+#if defined (__x86_64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"incq (%rdi)\n"
+	"ret\n");
+#elif defined (__aarch64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"str x30, [x0]\n"
+	"ret\n");
+
+#else
+static void __test_function(volatile long *ptr)
+{
+	*ptr++;
+}
+#endif
 
 __attribute__ ((noinline))
 static int test_function(void)
 {
+	__test_function(&the_var);
+	the_var++;
 	return time(NULL);
 }
 
+static void sig_handler_2(int signum __maybe_unused,
+			  siginfo_t *oh __maybe_unused,
+			  void *uc __maybe_unused)
+{
+	overflows_2++;
+	if (overflows_2 > 10) {
+		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
+	}
+}
+
 static void sig_handler(int signum __maybe_unused,
 			siginfo_t *oh __maybe_unused,
 			void *uc __maybe_unused)
@@ -54,10 +95,11 @@ static void sig_handler(int signum __maybe_unused,
 		 */
 		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 	}
 }
 
-static int bp_event(void *fn, int setup_signal)
+static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -67,8 +109,8 @@ static int bp_event(void *fn, int setup_signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = HW_BREAKPOINT_X;
-	pe.bp_addr = (unsigned long) fn;
+	pe.bp_type = is_bp ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
 	pe.sample_period = 1;
@@ -88,7 +130,7 @@ static int bp_event(void *fn, int setup_signal)
 
 	if (setup_signal) {
 		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, SIGIO);
+		fcntl(fd, F_SETSIG, signal);
 		fcntl(fd, F_SETOWN, getpid());
 	}
 
@@ -97,6 +139,16 @@ static int bp_event(void *fn, int setup_signal)
 	return fd;
 }
 
+static int bp_event(void *addr, int setup_signal)
+{
+	return __xp_event(true, addr, setup_signal, SIGIO);
+}
+
+static int wp_event(void *addr, int setup_signal)
+{
+	return __xp_event(false, addr, setup_signal, SIGIO);
+}
+
 static long long bp_count(int fd)
 {
 	long long count;
@@ -114,7 +166,7 @@ static long long bp_count(int fd)
 int test__bp_signal(int subtest __maybe_unused)
 {
 	struct sigaction sa;
-	long long count1, count2;
+	long long count1, count2, count3;
 
 	/* setup SIGIO signal handler */
 	memset(&sa, 0, sizeof(struct sigaction));
@@ -126,6 +178,12 @@ int test__bp_signal(int subtest __maybe_unused)
 		return TEST_FAIL;
 	}
 
+	sa.sa_sigaction = (void *) sig_handler_2;
+	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+		pr_debug("failed setting up signal handler 2\n");
+		return TEST_FAIL;
+	}
+
 	/*
 	 * We create following events:
 	 *
@@ -133,7 +191,11 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *       signal configured. We should get signal
 	 *       notification each time the breakpoint is hit
 	 *
-	 * fd2 - breakpoint event on sig_handler without SIGIO
+	 * fd2 - breakpoint event on sig_handler with SIGUSR1
+	 *       configured. We should get SIGUSR1 each time when
+	 *       breakpoint is hit
+	 *
+	 * fd3 - watchpoint event on test_function with SIGIO
 	 *       configured.
 	 *
 	 * Following processing should happen:
@@ -141,6 +203,21 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *   - fd1 event breakpoint hit -> count1 == 1
 	 *   - SIGIO is delivered       -> overflows == 1
 	 *   - fd2 event breakpoint hit -> count2 == 1
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
+	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
+	 *   - SIGIO is delivered       -> overflows == 2
+	 *   - fd2 event breakpoint hit -> count2 == 2
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
+	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
+	 *   - SIGIO is delivered       -> overflows = 3
+	 *   - fd2 event breakpoint hit -> count2 == 3
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
 	 *
 	 * The test case check following error conditions:
 	 * - we get stuck in signal handler because of debug
@@ -152,11 +229,13 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(test_function, 1);
-	fd2 = bp_event(sig_handler, 0);
+	fd1 = bp_event(__test_function, 1);
+	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, 1);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
 
 	/*
 	 * Kick off the test by trigering 'fd1'
@@ -166,15 +245,18 @@ int test__bp_signal(int subtest __maybe_unused)
 
 	ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 
 	count1 = bp_count(fd1);
 	count2 = bp_count(fd2);
+	count3 = bp_count(fd3);
 
 	close(fd1);
 	close(fd2);
+	close(fd3);
 
-	pr_debug("count1 %lld, count2 %lld, overflow %d\n",
-		 count1, count2, overflows);
+	pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
+		 count1, count2, count3, overflows, overflows_2);
 
 	if (count1 != 1) {
 		if (count1 == 11)
@@ -183,12 +265,18 @@ int test__bp_signal(int subtest __maybe_unused)
 			pr_debug("failed: wrong count for bp1%lld\n", count1);
 	}
 
-	if (overflows != 1)
+	if (overflows != 3)
 		pr_debug("failed: wrong overflow hit\n");
 
-	if (count2 != 1)
+	if (overflows_2 != 3)
+		pr_debug("failed: wrong overflow_2 hit\n");
+
+	if (count2 != 3)
 		pr_debug("failed: wrong count for bp2\n");
 
-	return count1 == 1 && overflows == 1 && count2 == 1 ?
+	if (count3 != 2)
+		pr_debug("failed: wrong count for bp3\n");
+
+	return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
 		TEST_OK : TEST_FAIL;
 }
-- 
1.8.3.4


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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  4:58       ` Wang Nan
  0 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2016-01-05  4:58 UTC (permalink / raw)
  To: linux-arm-kernel

Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:

 1. A watchpoint and a breakpoint that fire on the same instruction
 2. Nested signals

For detail of this patch see the comment in patch body.

Test result:

 On both x86_64:

 # ./perf test -v signal
 17: Test breakpoint overflow signal handler                  :
 --- start ---
 test child forked, pid 10213
 count1 1, count2 3, count3 2, overflow 3, overflows_2 3
 test child finished with 0
 ---- end ----
 Test breakpoint overflow signal handler: Ok

So at least 2 cases Will doubted are handled correctly.

[1] http://lkml.kernel.org/g/20160104165535.GI1616 at arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0 at huawei.com

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/bp_signal.c | 114 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 101 insertions(+), 13 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9e..0bc4f76 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,55 @@
 
 static int fd1;
 static int fd2;
+static int fd3;
 static int overflows;
+static int overflows_2;
+
+volatile long the_var;
+
+
+#if defined (__x86_64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"incq (%rdi)\n"
+	"ret\n");
+#elif defined (__aarch64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"str x30, [x0]\n"
+	"ret\n");
+
+#else
+static void __test_function(volatile long *ptr)
+{
+	*ptr++;
+}
+#endif
 
 __attribute__ ((noinline))
 static int test_function(void)
 {
+	__test_function(&the_var);
+	the_var++;
 	return time(NULL);
 }
 
+static void sig_handler_2(int signum __maybe_unused,
+			  siginfo_t *oh __maybe_unused,
+			  void *uc __maybe_unused)
+{
+	overflows_2++;
+	if (overflows_2 > 10) {
+		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
+	}
+}
+
 static void sig_handler(int signum __maybe_unused,
 			siginfo_t *oh __maybe_unused,
 			void *uc __maybe_unused)
@@ -54,10 +95,11 @@ static void sig_handler(int signum __maybe_unused,
 		 */
 		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 	}
 }
 
-static int bp_event(void *fn, int setup_signal)
+static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -67,8 +109,8 @@ static int bp_event(void *fn, int setup_signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = HW_BREAKPOINT_X;
-	pe.bp_addr = (unsigned long) fn;
+	pe.bp_type = is_bp ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
 	pe.sample_period = 1;
@@ -88,7 +130,7 @@ static int bp_event(void *fn, int setup_signal)
 
 	if (setup_signal) {
 		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, SIGIO);
+		fcntl(fd, F_SETSIG, signal);
 		fcntl(fd, F_SETOWN, getpid());
 	}
 
@@ -97,6 +139,16 @@ static int bp_event(void *fn, int setup_signal)
 	return fd;
 }
 
+static int bp_event(void *addr, int setup_signal)
+{
+	return __xp_event(true, addr, setup_signal, SIGIO);
+}
+
+static int wp_event(void *addr, int setup_signal)
+{
+	return __xp_event(false, addr, setup_signal, SIGIO);
+}
+
 static long long bp_count(int fd)
 {
 	long long count;
@@ -114,7 +166,7 @@ static long long bp_count(int fd)
 int test__bp_signal(int subtest __maybe_unused)
 {
 	struct sigaction sa;
-	long long count1, count2;
+	long long count1, count2, count3;
 
 	/* setup SIGIO signal handler */
 	memset(&sa, 0, sizeof(struct sigaction));
@@ -126,6 +178,12 @@ int test__bp_signal(int subtest __maybe_unused)
 		return TEST_FAIL;
 	}
 
+	sa.sa_sigaction = (void *) sig_handler_2;
+	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+		pr_debug("failed setting up signal handler 2\n");
+		return TEST_FAIL;
+	}
+
 	/*
 	 * We create following events:
 	 *
@@ -133,7 +191,11 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *       signal configured. We should get signal
 	 *       notification each time the breakpoint is hit
 	 *
-	 * fd2 - breakpoint event on sig_handler without SIGIO
+	 * fd2 - breakpoint event on sig_handler with SIGUSR1
+	 *       configured. We should get SIGUSR1 each time when
+	 *       breakpoint is hit
+	 *
+	 * fd3 - watchpoint event on test_function with SIGIO
 	 *       configured.
 	 *
 	 * Following processing should happen:
@@ -141,6 +203,21 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *   - fd1 event breakpoint hit -> count1 == 1
 	 *   - SIGIO is delivered       -> overflows == 1
 	 *   - fd2 event breakpoint hit -> count2 == 1
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
+	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
+	 *   - SIGIO is delivered       -> overflows == 2
+	 *   - fd2 event breakpoint hit -> count2 == 2
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
+	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
+	 *   - SIGIO is delivered       -> overflows = 3
+	 *   - fd2 event breakpoint hit -> count2 == 3
+	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
+	 *   - sig_handler_2 return
+	 *   - sig_handler return
 	 *
 	 * The test case check following error conditions:
 	 * - we get stuck in signal handler because of debug
@@ -152,11 +229,13 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(test_function, 1);
-	fd2 = bp_event(sig_handler, 0);
+	fd1 = bp_event(__test_function, 1);
+	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, 1);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
 
 	/*
 	 * Kick off the test by trigering 'fd1'
@@ -166,15 +245,18 @@ int test__bp_signal(int subtest __maybe_unused)
 
 	ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 
 	count1 = bp_count(fd1);
 	count2 = bp_count(fd2);
+	count3 = bp_count(fd3);
 
 	close(fd1);
 	close(fd2);
+	close(fd3);
 
-	pr_debug("count1 %lld, count2 %lld, overflow %d\n",
-		 count1, count2, overflows);
+	pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
+		 count1, count2, count3, overflows, overflows_2);
 
 	if (count1 != 1) {
 		if (count1 == 11)
@@ -183,12 +265,18 @@ int test__bp_signal(int subtest __maybe_unused)
 			pr_debug("failed: wrong count for bp1%lld\n", count1);
 	}
 
-	if (overflows != 1)
+	if (overflows != 3)
 		pr_debug("failed: wrong overflow hit\n");
 
-	if (count2 != 1)
+	if (overflows_2 != 3)
+		pr_debug("failed: wrong overflow_2 hit\n");
+
+	if (count2 != 3)
 		pr_debug("failed: wrong count for bp2\n");
 
-	return count1 == 1 && overflows == 1 && count2 == 1 ?
+	if (count3 != 2)
+		pr_debug("failed: wrong count for bp3\n");
+
+	return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
 		TEST_OK : TEST_FAIL;
 }
-- 
1.8.3.4

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-04 16:55     ` Will Deacon
@ 2016-01-05  5:06       ` Wangnan (F)
  -1 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  5:06 UTC (permalink / raw)
  To: Will Deacon
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa

Hi Will,

On 2016/1/5 0:55, Will Deacon wrote:
> Hello,
>
> On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:

[SNIP]

> The problem seems to be that we take the debug exception before the
> breakpointed instruction has been executed and call perf_bp_event at
> that moment, so when we single-step the faulting instruction we actually
> step into the SIGIO handler and end up getting stuck.
>
> Your fix doesn't really address this afaict, in that you don't (can't?)
> handle:
>
>    * A longjmp out of a signal handler
>    * A watchpoint and a breakpoint that fire on the same instruction
>    * User-controlled single-step from a signal handler that enables a
>      breakpoint explicitly
>    * Nested signals

Please have a look at [1], which I improve test__bp_signal() to
check bullet 2 and 4 you mentioned above. Seems my fix is correct.

[1] 
http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0@huawei.com

Thank you.



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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-05  5:06       ` Wangnan (F)
  0 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  5:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Will,

On 2016/1/5 0:55, Will Deacon wrote:
> Hello,
>
> On Thu, Dec 24, 2015 at 01:42:42AM +0000, Wang Nan wrote:

[SNIP]

> The problem seems to be that we take the debug exception before the
> breakpointed instruction has been executed and call perf_bp_event at
> that moment, so when we single-step the faulting instruction we actually
> step into the SIGIO handler and end up getting stuck.
>
> Your fix doesn't really address this afaict, in that you don't (can't?)
> handle:
>
>    * A longjmp out of a signal handler
>    * A watchpoint and a breakpoint that fire on the same instruction
>    * User-controlled single-step from a signal handler that enables a
>      breakpoint explicitly
>    * Nested signals

Please have a look at [1], which I improve test__bp_signal() to
check bullet 2 and 4 you mentioned above. Seems my fix is correct.

[1] 
http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0 at huawei.com

Thank you.

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

* Re: [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-05  4:58       ` Wang Nan
@ 2016-01-05  5:09         ` Wangnan (F)
  -1 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  5:09 UTC (permalink / raw)
  To: will.deacon
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	fengguang.wu, pi3orama, Jiri Olsa, Arnaldo Carvalho de Melo



On 2016/1/5 12:58, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:
>
>   1. A watchpoint and a breakpoint that fire on the same instruction
>   2. Nested signals
>
> For detail of this patch see the comment in patch body.
>
> Test result:
>
>   On both x86_64:

On x86_64 and arm64.

Sorry.


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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  5:09         ` Wangnan (F)
  0 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-05  5:09 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016/1/5 12:58, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:
>
>   1. A watchpoint and a breakpoint that fire on the same instruction
>   2. Nested signals
>
> For detail of this patch see the comment in patch body.
>
> Test result:
>
>   On both x86_64:

On x86_64 and arm64.

Sorry.

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

* Re: [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-05  4:58       ` Wang Nan
@ 2016-01-05  8:53         ` Jiri Olsa
  -1 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  8:53 UTC (permalink / raw)
  To: Wang Nan
  Cc: will.deacon, takahiro.akashi, guohanjun, linux-arm-kernel,
	linux-kernel, fengguang.wu, pi3orama, Jiri Olsa,
	Arnaldo Carvalho de Melo

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

> diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
> index fb80c9e..0bc4f76 100644
> --- a/tools/perf/tests/bp_signal.c
> +++ b/tools/perf/tests/bp_signal.c
> @@ -29,14 +29,55 @@
>  
>  static int fd1;
>  static int fd2;
> +static int fd3;
>  static int overflows;
> +static int overflows_2;
> +
> +volatile long the_var;
> +
> +

please put comment in here explaning the assembly is used
to have watchpoint and breakpoint on single instruction

IIUC ;-)

thanks,
jirka

> +#if defined (__x86_64__)
> +extern void __test_function(volatile long *ptr);
> +asm (
> +	".globl __test_function\n"
> +	"__test_function:\n"
> +	"incq (%rdi)\n"
> +	"ret\n");
> +#elif defined (__aarch64__)
> +extern void __test_function(volatile long *ptr);
> +asm (
> +	".globl __test_function\n"
> +	"__test_function:\n"
> +	"str x30, [x0]\n"
> +	"ret\n");
> +
> +#else
> +static void __test_function(volatile long *ptr)
> +{
> +	*ptr++;
> +}
> +#endif
>  
>  __attribute__ ((noinline))
>  static int test_function(void)
>  {
> +	__test_function(&the_var);
> +	the_var++;
>  	return time(NULL);
>  }

SNIP

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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  8:53         ` Jiri Olsa
  0 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

> diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
> index fb80c9e..0bc4f76 100644
> --- a/tools/perf/tests/bp_signal.c
> +++ b/tools/perf/tests/bp_signal.c
> @@ -29,14 +29,55 @@
>  
>  static int fd1;
>  static int fd2;
> +static int fd3;
>  static int overflows;
> +static int overflows_2;
> +
> +volatile long the_var;
> +
> +

please put comment in here explaning the assembly is used
to have watchpoint and breakpoint on single instruction

IIUC ;-)

thanks,
jirka

> +#if defined (__x86_64__)
> +extern void __test_function(volatile long *ptr);
> +asm (
> +	".globl __test_function\n"
> +	"__test_function:\n"
> +	"incq (%rdi)\n"
> +	"ret\n");
> +#elif defined (__aarch64__)
> +extern void __test_function(volatile long *ptr);
> +asm (
> +	".globl __test_function\n"
> +	"__test_function:\n"
> +	"str x30, [x0]\n"
> +	"ret\n");
> +
> +#else
> +static void __test_function(volatile long *ptr)
> +{
> +	*ptr++;
> +}
> +#endif
>  
>  __attribute__ ((noinline))
>  static int test_function(void)
>  {
> +	__test_function(&the_var);
> +	the_var++;
>  	return time(NULL);
>  }

SNIP

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

* Re: [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-05  4:58       ` Wang Nan
@ 2016-01-05  9:00         ` Jiri Olsa
  -1 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:00 UTC (permalink / raw)
  To: Wang Nan
  Cc: will.deacon, takahiro.akashi, guohanjun, linux-arm-kernel,
	linux-kernel, fengguang.wu, pi3orama, Jiri Olsa,
	Arnaldo Carvalho de Melo

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
> +	 *   - SIGIO is delivered       -> overflows == 2
> +	 *   - fd2 event breakpoint hit -> count2 == 2
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
> +	 *   - SIGIO is delivered       -> overflows = 3
> +	 *   - fd2 event breakpoint hit -> count2 == 3
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
>  	 *
>  	 * The test case check following error conditions:
>  	 * - we get stuck in signal handler because of debug
> @@ -152,11 +229,13 @@ int test__bp_signal(int subtest __maybe_unused)
>  	 *
>  	 */
>  
> -	fd1 = bp_event(test_function, 1);
> -	fd2 = bp_event(sig_handler, 0);
> +	fd1 = bp_event(__test_function, 1);
> +	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
> +	fd3 = wp_event((void *)&the_var, 1);
>  

spent some time to figure this out.. would attached change be more readable?

thanks,
jirka


---
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 0bc4f76c22ca..e5349616ac3f 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -99,7 +99,7 @@ static void sig_handler(int signum __maybe_unused,
 	}
 }
 
-static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
+static int __event(bool is_x, void *addr, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -109,7 +109,7 @@ static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = is_bp ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
 	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
@@ -128,25 +128,23 @@ static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 		return TEST_FAIL;
 	}
 
-	if (setup_signal) {
-		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, signal);
-		fcntl(fd, F_SETOWN, getpid());
-	}
+	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+	fcntl(fd, F_SETSIG, signal);
+	fcntl(fd, F_SETOWN, getpid());
 
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
 
 	return fd;
 }
 
-static int bp_event(void *addr, int setup_signal)
+static int bp_event(void *addr, int signal)
 {
-	return __xp_event(true, addr, setup_signal, SIGIO);
+	return __event(true, addr, signal);
 }
 
-static int wp_event(void *addr, int setup_signal)
+static int wp_event(void *addr, int signal)
 {
-	return __xp_event(false, addr, setup_signal, SIGIO);
+	return __event(false, addr, signal);
 }
 
 static long long bp_count(int fd)
@@ -229,9 +227,9 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(__test_function, 1);
-	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
-	fd3 = wp_event((void *)&the_var, 1);
+	fd1 = bp_event(__test_function, SIGIO);
+	fd2 = bp_event(sig_handler, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, SIGIO);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);

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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  9:00         ` Jiri Olsa
  0 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
> +	 *   - SIGIO is delivered       -> overflows == 2
> +	 *   - fd2 event breakpoint hit -> count2 == 2
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
> +	 *   - SIGIO is delivered       -> overflows = 3
> +	 *   - fd2 event breakpoint hit -> count2 == 3
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
>  	 *
>  	 * The test case check following error conditions:
>  	 * - we get stuck in signal handler because of debug
> @@ -152,11 +229,13 @@ int test__bp_signal(int subtest __maybe_unused)
>  	 *
>  	 */
>  
> -	fd1 = bp_event(test_function, 1);
> -	fd2 = bp_event(sig_handler, 0);
> +	fd1 = bp_event(__test_function, 1);
> +	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
> +	fd3 = wp_event((void *)&the_var, 1);
>  

spent some time to figure this out.. would attached change be more readable?

thanks,
jirka


---
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 0bc4f76c22ca..e5349616ac3f 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -99,7 +99,7 @@ static void sig_handler(int signum __maybe_unused,
 	}
 }
 
-static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
+static int __event(bool is_x, void *addr, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -109,7 +109,7 @@ static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = is_bp ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
 	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
@@ -128,25 +128,23 @@ static int __xp_event(bool is_bp, void *addr, int setup_signal, int signal)
 		return TEST_FAIL;
 	}
 
-	if (setup_signal) {
-		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, signal);
-		fcntl(fd, F_SETOWN, getpid());
-	}
+	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+	fcntl(fd, F_SETSIG, signal);
+	fcntl(fd, F_SETOWN, getpid());
 
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
 
 	return fd;
 }
 
-static int bp_event(void *addr, int setup_signal)
+static int bp_event(void *addr, int signal)
 {
-	return __xp_event(true, addr, setup_signal, SIGIO);
+	return __event(true, addr, signal);
 }
 
-static int wp_event(void *addr, int setup_signal)
+static int wp_event(void *addr, int signal)
 {
-	return __xp_event(false, addr, setup_signal, SIGIO);
+	return __event(false, addr, signal);
 }
 
 static long long bp_count(int fd)
@@ -229,9 +227,9 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(__test_function, 1);
-	fd2 = __xp_event(true, sig_handler, 1, SIGUSR1);
-	fd3 = wp_event((void *)&the_var, 1);
+	fd1 = bp_event(__test_function, SIGIO);
+	fd2 = bp_event(sig_handler, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, SIGIO);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);

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

* Re: [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-05  4:58       ` Wang Nan
@ 2016-01-05  9:05         ` Jiri Olsa
  -1 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:05 UTC (permalink / raw)
  To: Wang Nan
  Cc: will.deacon, takahiro.akashi, guohanjun, linux-arm-kernel,
	linux-kernel, fengguang.wu, pi3orama, Jiri Olsa,
	Arnaldo Carvalho de Melo

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:

there's typo (s/Improbe/Improve) in subject ;-)

jirka

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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  9:05         ` Jiri Olsa
  0 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:

there's typo (s/Improbe/Improve) in subject ;-)

jirka

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

* Re: [RFC PATCH] arm64: perf test: Improbe bp_signal
  2016-01-05  4:58       ` Wang Nan
@ 2016-01-05  9:09         ` Jiri Olsa
  -1 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:09 UTC (permalink / raw)
  To: Wang Nan
  Cc: will.deacon, takahiro.akashi, guohanjun, linux-arm-kernel,
	linux-kernel, fengguang.wu, pi3orama, Jiri Olsa,
	Arnaldo Carvalho de Melo

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

>  	 * Following processing should happen:
> @@ -141,6 +203,21 @@ int test__bp_signal(int subtest __maybe_unused)
>  	 *   - fd1 event breakpoint hit -> count1 == 1
>  	 *   - SIGIO is delivered       -> overflows == 1
>  	 *   - fd2 event breakpoint hit -> count2 == 1
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
> +	 *   - SIGIO is delivered       -> overflows == 2
> +	 *   - fd2 event breakpoint hit -> count2 == 2
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
> +	 *   - SIGIO is delivered       -> overflows = 3
> +	 *   - fd2 event breakpoint hit -> count2 == 3
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return

also each line in here could be prefixed with 'code action'
that led to the result on the line, like:


         * exec:              result:
         *
  	 * __test_function  - fd1 event breakpoint hit -> count1 == 1
         *                  - SIGIO is delivered       -> overflows == 1
         * sig_handler      - fd2 event breakpoint hit -> count2 == 1
         *                  - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
         *                  - sig_handler_2 return
         *                  - sig_handler return
         * incq (%rdi)      - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
         *                  - SIGIO is delivered       -> overflows == 2


hum.. but it might take all the fun out of it ;-)

jirka

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

* [RFC PATCH] arm64: perf test: Improbe bp_signal
@ 2016-01-05  9:09         ` Jiri Olsa
  0 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 04:58:00AM +0000, Wang Nan wrote:

SNIP

>  	 * Following processing should happen:
> @@ -141,6 +203,21 @@ int test__bp_signal(int subtest __maybe_unused)
>  	 *   - fd1 event breakpoint hit -> count1 == 1
>  	 *   - SIGIO is delivered       -> overflows == 1
>  	 *   - fd2 event breakpoint hit -> count2 == 1
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
> +	 *   - SIGIO is delivered       -> overflows == 2
> +	 *   - fd2 event breakpoint hit -> count2 == 2
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 2
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return
> +	 *   - fd3 event watchpoint hit -> count3 == 2       (standalone wp)
> +	 *   - SIGIO is delivered       -> overflows = 3
> +	 *   - fd2 event breakpoint hit -> count2 == 3
> +	 *   - SIGUSR1 is delivered     -> overflows_2 == 3
> +	 *   - sig_handler_2 return
> +	 *   - sig_handler return

also each line in here could be prefixed with 'code action'
that led to the result on the line, like:


         * exec:              result:
         *
  	 * __test_function  - fd1 event breakpoint hit -> count1 == 1
         *                  - SIGIO is delivered       -> overflows == 1
         * sig_handler      - fd2 event breakpoint hit -> count2 == 1
         *                  - SIGUSR1 is delivered     -> overflows_2 == 1  (nested signal)
         *                  - sig_handler_2 return
         *                  - sig_handler return
         * incq (%rdi)      - fd3 event watchpoint hit -> count3 == 1       (wp and bp in one insn)
         *                  - SIGIO is delivered       -> overflows == 2


hum.. but it might take all the fun out of it ;-)

jirka

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

* [RFC PATCH v2] perf test: Improve bp_signal
  2016-01-04 16:55     ` Will Deacon
@ 2016-01-05  9:57       ` Wang Nan
  -1 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2016-01-05  9:57 UTC (permalink / raw)
  To: will.deacon, jolsa
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	fengguang.wu, pi3orama, Wang Nan, Arnaldo Carvalho de Melo

Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:

 1. A watchpoint and a breakpoint that fire on the same instruction
 2. Nested signals

Test result:

 On x86_64 and ARM64 (result are similar with patch [2] on ARM64):

 # ./perf test -v signal
 17: Test breakpoint overflow signal handler                  :
 --- start ---
 test child forked, pid 10213
 count1 1, count2 3, count3 2, overflow 3, overflows_2 3
 test child finished with 0
 ---- end ----
 Test breakpoint overflow signal handler: Ok

So at least 2 cases Will doubted are handled correctly.

[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---

v1 -> v2: Improve readability, fix typo. Thanks to Jiri Olsa.

To Jiri: I guess you will be okay to provide your SOB for your code at [3],
         so I add it in this v2 patch.

[3] http://lkml.kernel.org/g/20160105090030.GC2192@krava.brq.redhat.com

---
 tools/perf/tests/bp_signal.c | 140 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 118 insertions(+), 22 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9e..1d1bb48 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,59 @@
 
 static int fd1;
 static int fd2;
+static int fd3;
 static int overflows;
+static int overflows_2;
+
+volatile long the_var;
+
+
+/*
+ * Use ASM to ensure watchpoint and breakpoint can be triggered
+ * at one instruction.
+ */
+#if defined (__x86_64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"incq (%rdi)\n"
+	"ret\n");
+#elif defined (__aarch64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"str x30, [x0]\n"
+	"ret\n");
+
+#else
+static void __test_function(volatile long *ptr)
+{
+	*ptr = 0x1234;
+}
+#endif
 
 __attribute__ ((noinline))
 static int test_function(void)
 {
+	__test_function(&the_var);
+	the_var++;
 	return time(NULL);
 }
 
+static void sig_handler_2(int signum __maybe_unused,
+			  siginfo_t *oh __maybe_unused,
+			  void *uc __maybe_unused)
+{
+	overflows_2++;
+	if (overflows_2 > 10) {
+		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
+	}
+}
+
 static void sig_handler(int signum __maybe_unused,
 			siginfo_t *oh __maybe_unused,
 			void *uc __maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
 		 */
 		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 	}
 }
 
-static int bp_event(void *fn, int setup_signal)
+static int __event(bool is_x, void *addr, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = HW_BREAKPOINT_X;
-	pe.bp_addr = (unsigned long) fn;
+	pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
 	pe.sample_period = 1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
 		return TEST_FAIL;
 	}
 
-	if (setup_signal) {
-		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, SIGIO);
-		fcntl(fd, F_SETOWN, getpid());
-	}
+	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+	fcntl(fd, F_SETSIG, signal);
+	fcntl(fd, F_SETOWN, getpid());
 
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
 
 	return fd;
 }
 
+static int bp_event(void *addr, int signal)
+{
+	return __event(true, addr, signal);
+}
+
+static int wp_event(void *addr, int signal)
+{
+	return __event(false, addr, signal);
+}
+
 static long long bp_count(int fd)
 {
 	long long count;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)
 int test__bp_signal(int subtest __maybe_unused)
 {
 	struct sigaction sa;
-	long long count1, count2;
+	long long count1, count2, count3;
 
 	/* setup SIGIO signal handler */
 	memset(&sa, 0, sizeof(struct sigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
 		return TEST_FAIL;
 	}
 
+	sa.sa_sigaction = (void *) sig_handler_2;
+	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+		pr_debug("failed setting up signal handler 2\n");
+		return TEST_FAIL;
+	}
+
 	/*
 	 * We create following events:
 	 *
-	 * fd1 - breakpoint event on test_function with SIGIO
+	 * fd1 - breakpoint event on __test_function with SIGIO
 	 *       signal configured. We should get signal
 	 *       notification each time the breakpoint is hit
 	 *
-	 * fd2 - breakpoint event on sig_handler without SIGIO
+	 * fd2 - breakpoint event on sig_handler with SIGUSR1
+	 *       configured. We should get SIGUSR1 each time when
+	 *       breakpoint is hit
+	 *
+	 * fd3 - watchpoint event on __test_function with SIGIO
 	 *       configured.
 	 *
 	 * Following processing should happen:
-	 *   - execute test_function
-	 *   - fd1 event breakpoint hit -> count1 == 1
-	 *   - SIGIO is delivered       -> overflows == 1
-	 *   - fd2 event breakpoint hit -> count2 == 1
+	 *   Exec:               Action:                       Result:
+	 *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows = 1
+	 *   sys_rt_sigreturn  - return from sig_handler
+	 *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows = 2
+	 *   sys_rt_sigreturn  - return from sig_handler
+	 *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows == 3
+	 *   sys_rt_sigreturn  - return from sig_handler
 	 *
 	 * The test case check following error conditions:
 	 * - we get stuck in signal handler because of debug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(test_function, 1);
-	fd2 = bp_event(sig_handler, 0);
+	fd1 = bp_event(__test_function, SIGIO);
+	fd2 = bp_event(sig_handler, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, SIGIO);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
 
 	/*
 	 * Kick off the test by trigering 'fd1'
@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
 
 	ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 
 	count1 = bp_count(fd1);
 	count2 = bp_count(fd2);
+	count3 = bp_count(fd3);
 
 	close(fd1);
 	close(fd2);
+	close(fd3);
 
-	pr_debug("count1 %lld, count2 %lld, overflow %d\n",
-		 count1, count2, overflows);
+	pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
+		 count1, count2, count3, overflows, overflows_2);
 
 	if (count1 != 1) {
 		if (count1 == 11)
@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
 			pr_debug("failed: wrong count for bp1%lld\n", count1);
 	}
 
-	if (overflows != 1)
+	if (overflows != 3)
 		pr_debug("failed: wrong overflow hit\n");
 
-	if (count2 != 1)
+	if (overflows_2 != 3)
+		pr_debug("failed: wrong overflow_2 hit\n");
+
+	if (count2 != 3)
 		pr_debug("failed: wrong count for bp2\n");
 
-	return count1 == 1 && overflows == 1 && count2 == 1 ?
+	if (count3 != 2)
+		pr_debug("failed: wrong count for bp3\n");
+
+	return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
 		TEST_OK : TEST_FAIL;
 }
-- 
1.8.3.4


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

* [RFC PATCH v2] perf test: Improve bp_signal
@ 2016-01-05  9:57       ` Wang Nan
  0 siblings, 0 replies; 36+ messages in thread
From: Wang Nan @ 2016-01-05  9:57 UTC (permalink / raw)
  To: linux-arm-kernel

Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:

 1. A watchpoint and a breakpoint that fire on the same instruction
 2. Nested signals

Test result:

 On x86_64 and ARM64 (result are similar with patch [2] on ARM64):

 # ./perf test -v signal
 17: Test breakpoint overflow signal handler                  :
 --- start ---
 test child forked, pid 10213
 count1 1, count2 3, count3 2, overflow 3, overflows_2 3
 test child finished with 0
 ---- end ----
 Test breakpoint overflow signal handler: Ok

So at least 2 cases Will doubted are handled correctly.

[1] http://lkml.kernel.org/g/20160104165535.GI1616 at arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0 at huawei.com

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---

v1 -> v2: Improve readability, fix typo. Thanks to Jiri Olsa.

To Jiri: I guess you will be okay to provide your SOB for your code at [3],
         so I add it in this v2 patch.

[3] http://lkml.kernel.org/g/20160105090030.GC2192 at krava.brq.redhat.com

---
 tools/perf/tests/bp_signal.c | 140 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 118 insertions(+), 22 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9e..1d1bb48 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,59 @@
 
 static int fd1;
 static int fd2;
+static int fd3;
 static int overflows;
+static int overflows_2;
+
+volatile long the_var;
+
+
+/*
+ * Use ASM to ensure watchpoint and breakpoint can be triggered
+ * at one instruction.
+ */
+#if defined (__x86_64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"incq (%rdi)\n"
+	"ret\n");
+#elif defined (__aarch64__)
+extern void __test_function(volatile long *ptr);
+asm (
+	".globl __test_function\n"
+	"__test_function:\n"
+	"str x30, [x0]\n"
+	"ret\n");
+
+#else
+static void __test_function(volatile long *ptr)
+{
+	*ptr = 0x1234;
+}
+#endif
 
 __attribute__ ((noinline))
 static int test_function(void)
 {
+	__test_function(&the_var);
+	the_var++;
 	return time(NULL);
 }
 
+static void sig_handler_2(int signum __maybe_unused,
+			  siginfo_t *oh __maybe_unused,
+			  void *uc __maybe_unused)
+{
+	overflows_2++;
+	if (overflows_2 > 10) {
+		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
+	}
+}
+
 static void sig_handler(int signum __maybe_unused,
 			siginfo_t *oh __maybe_unused,
 			void *uc __maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
 		 */
 		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 	}
 }
 
-static int bp_event(void *fn, int setup_signal)
+static int __event(bool is_x, void *addr, int signal)
 {
 	struct perf_event_attr pe;
 	int fd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
 	pe.size = sizeof(struct perf_event_attr);
 
 	pe.config = 0;
-	pe.bp_type = HW_BREAKPOINT_X;
-	pe.bp_addr = (unsigned long) fn;
+	pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
+	pe.bp_addr = (unsigned long) addr;
 	pe.bp_len = sizeof(long);
 
 	pe.sample_period = 1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
 		return TEST_FAIL;
 	}
 
-	if (setup_signal) {
-		fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-		fcntl(fd, F_SETSIG, SIGIO);
-		fcntl(fd, F_SETOWN, getpid());
-	}
+	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+	fcntl(fd, F_SETSIG, signal);
+	fcntl(fd, F_SETOWN, getpid());
 
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
 
 	return fd;
 }
 
+static int bp_event(void *addr, int signal)
+{
+	return __event(true, addr, signal);
+}
+
+static int wp_event(void *addr, int signal)
+{
+	return __event(false, addr, signal);
+}
+
 static long long bp_count(int fd)
 {
 	long long count;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)
 int test__bp_signal(int subtest __maybe_unused)
 {
 	struct sigaction sa;
-	long long count1, count2;
+	long long count1, count2, count3;
 
 	/* setup SIGIO signal handler */
 	memset(&sa, 0, sizeof(struct sigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
 		return TEST_FAIL;
 	}
 
+	sa.sa_sigaction = (void *) sig_handler_2;
+	if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+		pr_debug("failed setting up signal handler 2\n");
+		return TEST_FAIL;
+	}
+
 	/*
 	 * We create following events:
 	 *
-	 * fd1 - breakpoint event on test_function with SIGIO
+	 * fd1 - breakpoint event on __test_function with SIGIO
 	 *       signal configured. We should get signal
 	 *       notification each time the breakpoint is hit
 	 *
-	 * fd2 - breakpoint event on sig_handler without SIGIO
+	 * fd2 - breakpoint event on sig_handler with SIGUSR1
+	 *       configured. We should get SIGUSR1 each time when
+	 *       breakpoint is hit
+	 *
+	 * fd3 - watchpoint event on __test_function with SIGIO
 	 *       configured.
 	 *
 	 * Following processing should happen:
-	 *   - execute test_function
-	 *   - fd1 event breakpoint hit -> count1 == 1
-	 *   - SIGIO is delivered       -> overflows == 1
-	 *   - fd2 event breakpoint hit -> count2 == 1
+	 *   Exec:               Action:                       Result:
+	 *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows = 1
+	 *   sys_rt_sigreturn  - return from sig_handler
+	 *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows = 2
+	 *   sys_rt_sigreturn  - return from sig_handler
+	 *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
+	 *                     - SIGIO is delivered
+	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
+	 *                     - SIGUSR1 is delivered
+	 *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
+	 *   sys_rt_sigreturn  - return from sig_handler_2
+	 *   overflows++                                    -> overflows == 3
+	 *   sys_rt_sigreturn  - return from sig_handler
 	 *
 	 * The test case check following error conditions:
 	 * - we get stuck in signal handler because of debug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
 	 *
 	 */
 
-	fd1 = bp_event(test_function, 1);
-	fd2 = bp_event(sig_handler, 0);
+	fd1 = bp_event(__test_function, SIGIO);
+	fd2 = bp_event(sig_handler, SIGUSR1);
+	fd3 = wp_event((void *)&the_var, SIGIO);
 
 	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
 
 	/*
 	 * Kick off the test by trigering 'fd1'
@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
 
 	ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
 	ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+	ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
 
 	count1 = bp_count(fd1);
 	count2 = bp_count(fd2);
+	count3 = bp_count(fd3);
 
 	close(fd1);
 	close(fd2);
+	close(fd3);
 
-	pr_debug("count1 %lld, count2 %lld, overflow %d\n",
-		 count1, count2, overflows);
+	pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
+		 count1, count2, count3, overflows, overflows_2);
 
 	if (count1 != 1) {
 		if (count1 == 11)
@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
 			pr_debug("failed: wrong count for bp1%lld\n", count1);
 	}
 
-	if (overflows != 1)
+	if (overflows != 3)
 		pr_debug("failed: wrong overflow hit\n");
 
-	if (count2 != 1)
+	if (overflows_2 != 3)
+		pr_debug("failed: wrong overflow_2 hit\n");
+
+	if (count2 != 3)
 		pr_debug("failed: wrong count for bp2\n");
 
-	return count1 == 1 && overflows == 1 && count2 == 1 ?
+	if (count3 != 2)
+		pr_debug("failed: wrong count for bp3\n");
+
+	return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
 		TEST_OK : TEST_FAIL;
 }
-- 
1.8.3.4

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

* Re: [RFC PATCH v2] perf test: Improve bp_signal
  2016-01-05  9:57       ` Wang Nan
@ 2016-01-05 10:07         ` Jiri Olsa
  -1 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05 10:07 UTC (permalink / raw)
  To: Wang Nan
  Cc: will.deacon, jolsa, takahiro.akashi, guohanjun, linux-arm-kernel,
	linux-kernel, fengguang.wu, pi3orama, Arnaldo Carvalho de Melo

On Tue, Jan 05, 2016 at 09:57:55AM +0000, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:
> 
>  1. A watchpoint and a breakpoint that fire on the same instruction
>  2. Nested signals
> 
> Test result:
> 
>  On x86_64 and ARM64 (result are similar with patch [2] on ARM64):
> 
>  # ./perf test -v signal
>  17: Test breakpoint overflow signal handler                  :
>  --- start ---
>  test child forked, pid 10213
>  count1 1, count2 3, count3 2, overflow 3, overflows_2 3
>  test child finished with 0
>  ---- end ----
>  Test breakpoint overflow signal handler: Ok
> 
> So at least 2 cases Will doubted are handled correctly.
> 
> [1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
> [2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> 
> v1 -> v2: Improve readability, fix typo. Thanks to Jiri Olsa.
> 
> To Jiri: I guess you will be okay to provide your SOB for your code at [3],
>          so I add it in this v2 patch.

sure, patch looks good to me

thanks,
jirka

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

* [RFC PATCH v2] perf test: Improve bp_signal
@ 2016-01-05 10:07         ` Jiri Olsa
  0 siblings, 0 replies; 36+ messages in thread
From: Jiri Olsa @ 2016-01-05 10:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 09:57:55AM +0000, Wang Nan wrote:
> Will Deacon [1] has some question on patch [2]. This patch improves
> test__bp_signal so we can test:
> 
>  1. A watchpoint and a breakpoint that fire on the same instruction
>  2. Nested signals
> 
> Test result:
> 
>  On x86_64 and ARM64 (result are similar with patch [2] on ARM64):
> 
>  # ./perf test -v signal
>  17: Test breakpoint overflow signal handler                  :
>  --- start ---
>  test child forked, pid 10213
>  count1 1, count2 3, count3 2, overflow 3, overflows_2 3
>  test child finished with 0
>  ---- end ----
>  Test breakpoint overflow signal handler: Ok
> 
> So at least 2 cases Will doubted are handled correctly.
> 
> [1] http://lkml.kernel.org/g/20160104165535.GI1616 at arm.com
> [2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0 at huawei.com
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> 
> v1 -> v2: Improve readability, fix typo. Thanks to Jiri Olsa.
> 
> To Jiri: I guess you will be okay to provide your SOB for your code at [3],
>          so I add it in this v2 patch.

sure, patch looks good to me

thanks,
jirka

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-05  5:06       ` Wangnan (F)
@ 2016-01-12 17:06         ` Will Deacon
  -1 siblings, 0 replies; 36+ messages in thread
From: Will Deacon @ 2016-01-12 17:06 UTC (permalink / raw)
  To: Wangnan (F)
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa

On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
> On 2016/1/5 0:55, Will Deacon wrote:
> >The problem seems to be that we take the debug exception before the
> >breakpointed instruction has been executed and call perf_bp_event at
> >that moment, so when we single-step the faulting instruction we actually
> >step into the SIGIO handler and end up getting stuck.
> >
> >Your fix doesn't really address this afaict, in that you don't (can't?)
> >handle:
> >
> >   * A longjmp out of a signal handler
> >   * A watchpoint and a breakpoint that fire on the same instruction
> >   * User-controlled single-step from a signal handler that enables a
> >     breakpoint explicitly
> >   * Nested signals
> 
> Please have a look at [1], which I improve test__bp_signal() to
> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
> 
> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0@huawei.com

I'm still really uneasy about this change. Pairing up the signal delivery
with the sigreturn to keep track of the debug state is extremely fragile
and I'm not keen on adding this logic there. I also think we need to
track the address that the breakpoint is originally taken on so that we
can only perform the extra sigreturn work if we're returning to the same
instruction. Furthermore, I wouldn't want to do this for signals other
than those generated directly by a breakpoint.

An alternative would be to postpone the signal delivery until after the
stepping has been taken care of, but that's a change in ABI and I worry
we'll break somebody relying on the current behaviour.

What exactly does x86 do? I couldn't figure it out from the code.

Will

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-12 17:06         ` Will Deacon
  0 siblings, 0 replies; 36+ messages in thread
From: Will Deacon @ 2016-01-12 17:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
> On 2016/1/5 0:55, Will Deacon wrote:
> >The problem seems to be that we take the debug exception before the
> >breakpointed instruction has been executed and call perf_bp_event at
> >that moment, so when we single-step the faulting instruction we actually
> >step into the SIGIO handler and end up getting stuck.
> >
> >Your fix doesn't really address this afaict, in that you don't (can't?)
> >handle:
> >
> >   * A longjmp out of a signal handler
> >   * A watchpoint and a breakpoint that fire on the same instruction
> >   * User-controlled single-step from a signal handler that enables a
> >     breakpoint explicitly
> >   * Nested signals
> 
> Please have a look at [1], which I improve test__bp_signal() to
> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
> 
> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0 at huawei.com

I'm still really uneasy about this change. Pairing up the signal delivery
with the sigreturn to keep track of the debug state is extremely fragile
and I'm not keen on adding this logic there. I also think we need to
track the address that the breakpoint is originally taken on so that we
can only perform the extra sigreturn work if we're returning to the same
instruction. Furthermore, I wouldn't want to do this for signals other
than those generated directly by a breakpoint.

An alternative would be to postpone the signal delivery until after the
stepping has been taken care of, but that's a change in ABI and I worry
we'll break somebody relying on the current behaviour.

What exactly does x86 do? I couldn't figure it out from the code.

Will

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-12 17:06         ` Will Deacon
@ 2016-01-15  8:20           ` xiakaixu
  -1 siblings, 0 replies; 36+ messages in thread
From: xiakaixu @ 2016-01-15  8:20 UTC (permalink / raw)
  To: Will Deacon
  Cc: Wangnan (F),
	takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa

于 2016/1/13 1:06, Will Deacon 写道:
> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>> On 2016/1/5 0:55, Will Deacon wrote:
>>> The problem seems to be that we take the debug exception before the
>>> breakpointed instruction has been executed and call perf_bp_event at
>>> that moment, so when we single-step the faulting instruction we actually
>>> step into the SIGIO handler and end up getting stuck.
>>>
>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>> handle:
>>>
>>>   * A longjmp out of a signal handler
>>>   * A watchpoint and a breakpoint that fire on the same instruction
>>>   * User-controlled single-step from a signal handler that enables a
>>>     breakpoint explicitly
>>>   * Nested signals
>>
>> Please have a look at [1], which I improve test__bp_signal() to
>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>
>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0@huawei.com
> 
> I'm still really uneasy about this change. Pairing up the signal delivery
> with the sigreturn to keep track of the debug state is extremely fragile
> and I'm not keen on adding this logic there. I also think we need to
> track the address that the breakpoint is originally taken on so that we
> can only perform the extra sigreturn work if we're returning to the same
> instruction. Furthermore, I wouldn't want to do this for signals other
> than those generated directly by a breakpoint.
> 
> An alternative would be to postpone the signal delivery until after the
> stepping has been taken care of, but that's a change in ABI and I worry
> we'll break somebody relying on the current behaviour.
> 
> What exactly does x86 do? I couldn't figure it out from the code.

Hi Will,

I changed the signal SIGIO to SIGUSR2 according to the patch that Wang Nan
sent out about improving test__bp_signal() to check bullet 2 and 4 you mentioned.
I tested it with arm64 qemu and gdb. The single instruction execution on qemu
shows that the result is the same as the processing described in Wang Nan's patch[2].

I also tested the patch on x86 qemu and found that the result is the same as
arm64 qemu.

[1]
 tools/perf/tests/bp_signal.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 1d1bb48..3046cba 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -175,7 +175,7 @@ int test__bp_signal(int subtest __maybe_unused)
        sa.sa_sigaction = (void *) sig_handler;
        sa.sa_flags = SA_SIGINFO;

-       if (sigaction(SIGIO, &sa, NULL) < 0) {
+       if (sigaction(SIGUSR2, &sa, NULL) < 0) {
                pr_debug("failed setting up signal handler\n");
                return TEST_FAIL;
        }
@@ -237,9 +237,9 @@ int test__bp_signal(int subtest __maybe_unused)
         *
         */

-       fd1 = bp_event(__test_function, SIGIO);
+       fd1 = bp_event(__test_function, SIGUSR2);
        fd2 = bp_event(sig_handler, SIGUSR1);
-       fd3 = wp_event((void *)&the_var, SIGIO);
+       fd3 = wp_event((void *)&the_var, SIGUSR2);

        ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
        ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);

[2]
         * Following processing should happen:
         *   Exec:               Action:                       Result:
         *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows = 1
         *   sys_rt_sigreturn  - return from sig_handler
         *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows = 2
         *   sys_rt_sigreturn  - return from sig_handler
         *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows == 3
         *   sys_rt_sigreturn  - return from sig_handler
> 
> Will
> 
> .
> 


-- 
Regards
Kaixu Xia

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-15  8:20           ` xiakaixu
  0 siblings, 0 replies; 36+ messages in thread
From: xiakaixu @ 2016-01-15  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/1/13 1:06, Will Deacon ??:
> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>> On 2016/1/5 0:55, Will Deacon wrote:
>>> The problem seems to be that we take the debug exception before the
>>> breakpointed instruction has been executed and call perf_bp_event at
>>> that moment, so when we single-step the faulting instruction we actually
>>> step into the SIGIO handler and end up getting stuck.
>>>
>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>> handle:
>>>
>>>   * A longjmp out of a signal handler
>>>   * A watchpoint and a breakpoint that fire on the same instruction
>>>   * User-controlled single-step from a signal handler that enables a
>>>     breakpoint explicitly
>>>   * Nested signals
>>
>> Please have a look at [1], which I improve test__bp_signal() to
>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>
>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0 at huawei.com
> 
> I'm still really uneasy about this change. Pairing up the signal delivery
> with the sigreturn to keep track of the debug state is extremely fragile
> and I'm not keen on adding this logic there. I also think we need to
> track the address that the breakpoint is originally taken on so that we
> can only perform the extra sigreturn work if we're returning to the same
> instruction. Furthermore, I wouldn't want to do this for signals other
> than those generated directly by a breakpoint.
> 
> An alternative would be to postpone the signal delivery until after the
> stepping has been taken care of, but that's a change in ABI and I worry
> we'll break somebody relying on the current behaviour.
> 
> What exactly does x86 do? I couldn't figure it out from the code.

Hi Will,

I changed the signal SIGIO to SIGUSR2 according to the patch that Wang Nan
sent out about improving test__bp_signal() to check bullet 2 and 4 you mentioned.
I tested it with arm64 qemu and gdb. The single instruction execution on qemu
shows that the result is the same as the processing described in Wang Nan's patch[2].

I also tested the patch on x86 qemu and found that the result is the same as
arm64 qemu.

[1]
 tools/perf/tests/bp_signal.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 1d1bb48..3046cba 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -175,7 +175,7 @@ int test__bp_signal(int subtest __maybe_unused)
        sa.sa_sigaction = (void *) sig_handler;
        sa.sa_flags = SA_SIGINFO;

-       if (sigaction(SIGIO, &sa, NULL) < 0) {
+       if (sigaction(SIGUSR2, &sa, NULL) < 0) {
                pr_debug("failed setting up signal handler\n");
                return TEST_FAIL;
        }
@@ -237,9 +237,9 @@ int test__bp_signal(int subtest __maybe_unused)
         *
         */

-       fd1 = bp_event(__test_function, SIGIO);
+       fd1 = bp_event(__test_function, SIGUSR2);
        fd2 = bp_event(sig_handler, SIGUSR1);
-       fd3 = wp_event((void *)&the_var, SIGIO);
+       fd3 = wp_event((void *)&the_var, SIGUSR2);

        ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
        ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);

[2]
         * Following processing should happen:
         *   Exec:               Action:                       Result:
         *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows = 1
         *   sys_rt_sigreturn  - return from sig_handler
         *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows = 2
         *   sys_rt_sigreturn  - return from sig_handler
         *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
         *                     - SIGIO is delivered
         *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
         *                     - SIGUSR1 is delivered
         *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
         *   sys_rt_sigreturn  - return from sig_handler_2
         *   overflows++                                    -> overflows == 3
         *   sys_rt_sigreturn  - return from sig_handler
> 
> Will
> 
> .
> 


-- 
Regards
Kaixu Xia

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-12 17:06         ` Will Deacon
@ 2016-01-18 11:39           ` Wangnan (F)
  -1 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-18 11:39 UTC (permalink / raw)
  To: Will Deacon
  Cc: takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa



On 2016/1/13 1:06, Will Deacon wrote:
> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>> On 2016/1/5 0:55, Will Deacon wrote:
>>> The problem seems to be that we take the debug exception before the
>>> breakpointed instruction has been executed and call perf_bp_event at
>>> that moment, so when we single-step the faulting instruction we actually
>>> step into the SIGIO handler and end up getting stuck.
>>>
>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>> handle:
>>>
>>>    * A longjmp out of a signal handler
>>>    * A watchpoint and a breakpoint that fire on the same instruction
>>>    * User-controlled single-step from a signal handler that enables a
>>>      breakpoint explicitly
>>>    * Nested signals
>> Please have a look at [1], which I improve test__bp_signal() to
>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>
>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0@huawei.com
> I'm still really uneasy about this change. Pairing up the signal delivery
> with the sigreturn to keep track of the debug state is extremely fragile
> and I'm not keen on adding this logic there. I also think we need to
> track the address that the breakpoint is originally taken on so that we
> can only perform the extra sigreturn work if we're returning to the same
> instruction. Furthermore, I wouldn't want to do this for signals other
> than those generated directly by a breakpoint.
>
> An alternative would be to postpone the signal delivery until after the
> stepping has been taken care of, but that's a change in ABI and I worry
> we'll break somebody relying on the current behaviour.
>
> What exactly does x86 do? I couldn't figure it out from the code.

Actually x86 does similar thing as what this patch does.

RF bit in x86_64's eflags prohibit debug exception raises. It is set by
x86_64's debug handler to avoid recursion. x86_64 need setting this bit
in breakpoint handler because it needs to jump back to original
instruction and single-step on it, similar to ARM64.

The RF bit in eflags records a state that the process shouldn't generate
debug exception. It is part of the state of a process, and should be saved
and cleared if transfers to signal handler.

This patch does the same thing: create two bits in pstate to indicate
the states that 'a process should not raises watchpoint/breakpoint 
exceptions',
maintains them in kernel, cleans them for signal handler and save them 
in signal
frame.

Thank you.

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-18 11:39           ` Wangnan (F)
  0 siblings, 0 replies; 36+ messages in thread
From: Wangnan (F) @ 2016-01-18 11:39 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016/1/13 1:06, Will Deacon wrote:
> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>> On 2016/1/5 0:55, Will Deacon wrote:
>>> The problem seems to be that we take the debug exception before the
>>> breakpointed instruction has been executed and call perf_bp_event at
>>> that moment, so when we single-step the faulting instruction we actually
>>> step into the SIGIO handler and end up getting stuck.
>>>
>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>> handle:
>>>
>>>    * A longjmp out of a signal handler
>>>    * A watchpoint and a breakpoint that fire on the same instruction
>>>    * User-controlled single-step from a signal handler that enables a
>>>      breakpoint explicitly
>>>    * Nested signals
>> Please have a look at [1], which I improve test__bp_signal() to
>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>
>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0 at huawei.com
> I'm still really uneasy about this change. Pairing up the signal delivery
> with the sigreturn to keep track of the debug state is extremely fragile
> and I'm not keen on adding this logic there. I also think we need to
> track the address that the breakpoint is originally taken on so that we
> can only perform the extra sigreturn work if we're returning to the same
> instruction. Furthermore, I wouldn't want to do this for signals other
> than those generated directly by a breakpoint.
>
> An alternative would be to postpone the signal delivery until after the
> stepping has been taken care of, but that's a change in ABI and I worry
> we'll break somebody relying on the current behaviour.
>
> What exactly does x86 do? I couldn't figure it out from the code.

Actually x86 does similar thing as what this patch does.

RF bit in x86_64's eflags prohibit debug exception raises. It is set by
x86_64's debug handler to avoid recursion. x86_64 need setting this bit
in breakpoint handler because it needs to jump back to original
instruction and single-step on it, similar to ARM64.

The RF bit in eflags records a state that the process shouldn't generate
debug exception. It is part of the state of a process, and should be saved
and cleared if transfers to signal handler.

This patch does the same thing: create two bits in pstate to indicate
the states that 'a process should not raises watchpoint/breakpoint 
exceptions',
maintains them in kernel, cleans them for signal handler and save them 
in signal
frame.

Thank you.

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

* Re: [PATCH v2] arm64: Store breakpoint single step state into pstate
  2016-01-15  8:20           ` xiakaixu
@ 2016-01-21  8:06             ` xiakaixu
  -1 siblings, 0 replies; 36+ messages in thread
From: xiakaixu @ 2016-01-21  8:06 UTC (permalink / raw)
  To: Will Deacon
  Cc: Wangnan (F),
	takahiro.akashi, guohanjun, linux-arm-kernel, linux-kernel,
	pi3orama, Fengguang Wu, Jiri Olsa

ping...
于 2016/1/15 16:20, xiakaixu 写道:
> 于 2016/1/13 1:06, Will Deacon 写道:
>> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>>> On 2016/1/5 0:55, Will Deacon wrote:
>>>> The problem seems to be that we take the debug exception before the
>>>> breakpointed instruction has been executed and call perf_bp_event at
>>>> that moment, so when we single-step the faulting instruction we actually
>>>> step into the SIGIO handler and end up getting stuck.
>>>>
>>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>>> handle:
>>>>
>>>>   * A longjmp out of a signal handler
>>>>   * A watchpoint and a breakpoint that fire on the same instruction
>>>>   * User-controlled single-step from a signal handler that enables a
>>>>     breakpoint explicitly
>>>>   * Nested signals
>>>
>>> Please have a look at [1], which I improve test__bp_signal() to
>>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>>
>>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0@huawei.com
>>
>> I'm still really uneasy about this change. Pairing up the signal delivery
>> with the sigreturn to keep track of the debug state is extremely fragile
>> and I'm not keen on adding this logic there. I also think we need to
>> track the address that the breakpoint is originally taken on so that we
>> can only perform the extra sigreturn work if we're returning to the same
>> instruction. Furthermore, I wouldn't want to do this for signals other
>> than those generated directly by a breakpoint.
>>
>> An alternative would be to postpone the signal delivery until after the
>> stepping has been taken care of, but that's a change in ABI and I worry
>> we'll break somebody relying on the current behaviour.
>>
>> What exactly does x86 do? I couldn't figure it out from the code.
> 
> Hi Will,
> 
> I changed the signal SIGIO to SIGUSR2 according to the patch that Wang Nan
> sent out about improving test__bp_signal() to check bullet 2 and 4 you mentioned.
> I tested it with arm64 qemu and gdb. The single instruction execution on qemu
> shows that the result is the same as the processing described in Wang Nan's patch[2].
> 
> I also tested the patch on x86 qemu and found that the result is the same as
> arm64 qemu.
> 
> [1]
>  tools/perf/tests/bp_signal.c |    6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
> index 1d1bb48..3046cba 100644
> --- a/tools/perf/tests/bp_signal.c
> +++ b/tools/perf/tests/bp_signal.c
> @@ -175,7 +175,7 @@ int test__bp_signal(int subtest __maybe_unused)
>         sa.sa_sigaction = (void *) sig_handler;
>         sa.sa_flags = SA_SIGINFO;
> 
> -       if (sigaction(SIGIO, &sa, NULL) < 0) {
> +       if (sigaction(SIGUSR2, &sa, NULL) < 0) {
>                 pr_debug("failed setting up signal handler\n");
>                 return TEST_FAIL;
>         }
> @@ -237,9 +237,9 @@ int test__bp_signal(int subtest __maybe_unused)
>          *
>          */
> 
> -       fd1 = bp_event(__test_function, SIGIO);
> +       fd1 = bp_event(__test_function, SIGUSR2);
>         fd2 = bp_event(sig_handler, SIGUSR1);
> -       fd3 = wp_event((void *)&the_var, SIGIO);
> +       fd3 = wp_event((void *)&the_var, SIGUSR2);
>
>         ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
>         ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
> 
> [2]
>          * Following processing should happen:
>          *   Exec:               Action:                       Result:
>          *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows = 1
>          *   sys_rt_sigreturn  - return from sig_handler
>          *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows = 2
>          *   sys_rt_sigreturn  - return from sig_handler
>          *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows == 3
>          *   sys_rt_sigreturn  - return from sig_handler
>>
>> Will
>>
>> .
>>
> 
> 


-- 
Regards
Kaixu Xia

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

* [PATCH v2] arm64: Store breakpoint single step state into pstate
@ 2016-01-21  8:06             ` xiakaixu
  0 siblings, 0 replies; 36+ messages in thread
From: xiakaixu @ 2016-01-21  8:06 UTC (permalink / raw)
  To: linux-arm-kernel

ping...
? 2016/1/15 16:20, xiakaixu ??:
> ? 2016/1/13 1:06, Will Deacon ??:
>> On Tue, Jan 05, 2016 at 01:06:15PM +0800, Wangnan (F) wrote:
>>> On 2016/1/5 0:55, Will Deacon wrote:
>>>> The problem seems to be that we take the debug exception before the
>>>> breakpointed instruction has been executed and call perf_bp_event at
>>>> that moment, so when we single-step the faulting instruction we actually
>>>> step into the SIGIO handler and end up getting stuck.
>>>>
>>>> Your fix doesn't really address this afaict, in that you don't (can't?)
>>>> handle:
>>>>
>>>>   * A longjmp out of a signal handler
>>>>   * A watchpoint and a breakpoint that fire on the same instruction
>>>>   * User-controlled single-step from a signal handler that enables a
>>>>     breakpoint explicitly
>>>>   * Nested signals
>>>
>>> Please have a look at [1], which I improve test__bp_signal() to
>>> check bullet 2 and 4 you mentioned above. Seems my fix is correct.
>>>
>>> [1] http://lkml.kernel.org/g/1451969880-14877-1-git-send-email-wangnan0 at huawei.com
>>
>> I'm still really uneasy about this change. Pairing up the signal delivery
>> with the sigreturn to keep track of the debug state is extremely fragile
>> and I'm not keen on adding this logic there. I also think we need to
>> track the address that the breakpoint is originally taken on so that we
>> can only perform the extra sigreturn work if we're returning to the same
>> instruction. Furthermore, I wouldn't want to do this for signals other
>> than those generated directly by a breakpoint.
>>
>> An alternative would be to postpone the signal delivery until after the
>> stepping has been taken care of, but that's a change in ABI and I worry
>> we'll break somebody relying on the current behaviour.
>>
>> What exactly does x86 do? I couldn't figure it out from the code.
> 
> Hi Will,
> 
> I changed the signal SIGIO to SIGUSR2 according to the patch that Wang Nan
> sent out about improving test__bp_signal() to check bullet 2 and 4 you mentioned.
> I tested it with arm64 qemu and gdb. The single instruction execution on qemu
> shows that the result is the same as the processing described in Wang Nan's patch[2].
> 
> I also tested the patch on x86 qemu and found that the result is the same as
> arm64 qemu.
> 
> [1]
>  tools/perf/tests/bp_signal.c |    6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
> index 1d1bb48..3046cba 100644
> --- a/tools/perf/tests/bp_signal.c
> +++ b/tools/perf/tests/bp_signal.c
> @@ -175,7 +175,7 @@ int test__bp_signal(int subtest __maybe_unused)
>         sa.sa_sigaction = (void *) sig_handler;
>         sa.sa_flags = SA_SIGINFO;
> 
> -       if (sigaction(SIGIO, &sa, NULL) < 0) {
> +       if (sigaction(SIGUSR2, &sa, NULL) < 0) {
>                 pr_debug("failed setting up signal handler\n");
>                 return TEST_FAIL;
>         }
> @@ -237,9 +237,9 @@ int test__bp_signal(int subtest __maybe_unused)
>          *
>          */
> 
> -       fd1 = bp_event(__test_function, SIGIO);
> +       fd1 = bp_event(__test_function, SIGUSR2);
>         fd2 = bp_event(sig_handler, SIGUSR1);
> -       fd3 = wp_event((void *)&the_var, SIGIO);
> +       fd3 = wp_event((void *)&the_var, SIGUSR2);
>
>         ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
>         ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
> 
> [2]
>          * Following processing should happen:
>          *   Exec:               Action:                       Result:
>          *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows = 1
>          *   sys_rt_sigreturn  - return from sig_handler
>          *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows = 2
>          *   sys_rt_sigreturn  - return from sig_handler
>          *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)
>          *                     - SIGIO is delivered
>          *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3
>          *                     - SIGUSR1 is delivered
>          *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)
>          *   sys_rt_sigreturn  - return from sig_handler_2
>          *   overflows++                                    -> overflows == 3
>          *   sys_rt_sigreturn  - return from sig_handler
>>
>> Will
>>
>> .
>>
> 
> 


-- 
Regards
Kaixu Xia

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

end of thread, other threads:[~2016-01-21  8:06 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-23  8:52 [RESEND PATCH] arm64: Store breakpoint single step state into pstate Wang Nan
2015-12-23  8:52 ` Wang Nan
2015-12-23 10:44 ` kbuild test robot
2015-12-23 10:44   ` kbuild test robot
2015-12-24  1:42 ` [PATCH v2] " Wang Nan
2015-12-24  1:42   ` Wang Nan
2016-01-04 16:55   ` Will Deacon
2016-01-04 16:55     ` Will Deacon
2016-01-05  1:41     ` Wangnan (F)
2016-01-05  1:41       ` Wangnan (F)
2016-01-05  4:58     ` [RFC PATCH] arm64: perf test: Improbe bp_signal Wang Nan
2016-01-05  4:58       ` Wang Nan
2016-01-05  5:09       ` Wangnan (F)
2016-01-05  5:09         ` Wangnan (F)
2016-01-05  8:53       ` Jiri Olsa
2016-01-05  8:53         ` Jiri Olsa
2016-01-05  9:00       ` Jiri Olsa
2016-01-05  9:00         ` Jiri Olsa
2016-01-05  9:05       ` Jiri Olsa
2016-01-05  9:05         ` Jiri Olsa
2016-01-05  9:09       ` Jiri Olsa
2016-01-05  9:09         ` Jiri Olsa
2016-01-05  5:06     ` [PATCH v2] arm64: Store breakpoint single step state into pstate Wangnan (F)
2016-01-05  5:06       ` Wangnan (F)
2016-01-12 17:06       ` Will Deacon
2016-01-12 17:06         ` Will Deacon
2016-01-15  8:20         ` xiakaixu
2016-01-15  8:20           ` xiakaixu
2016-01-21  8:06           ` xiakaixu
2016-01-21  8:06             ` xiakaixu
2016-01-18 11:39         ` Wangnan (F)
2016-01-18 11:39           ` Wangnan (F)
2016-01-05  9:57     ` [RFC PATCH v2] perf test: Improve bp_signal Wang Nan
2016-01-05  9:57       ` Wang Nan
2016-01-05 10:07       ` Jiri Olsa
2016-01-05 10:07         ` Jiri Olsa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.