Commit f7809daf authored by Frederic Weisbecker's avatar Frederic Weisbecker

x86: Support for instruction breakpoints

Instruction breakpoints need to have a specific length of 0 to
be working. Bring this support but also take care the user is not
trying to set an unsupported length, like a range breakpoint for
example.
Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Prasad <prasad@linux.vnet.ibm.com>
Cc: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Wessel <jason.wessel@windriver.com>
parent 0c4519e8
...@@ -20,10 +20,10 @@ struct arch_hw_breakpoint { ...@@ -20,10 +20,10 @@ struct arch_hw_breakpoint {
#include <linux/list.h> #include <linux/list.h>
/* Available HW breakpoint length encodings */ /* Available HW breakpoint length encodings */
#define X86_BREAKPOINT_LEN_X 0x00
#define X86_BREAKPOINT_LEN_1 0x40 #define X86_BREAKPOINT_LEN_1 0x40
#define X86_BREAKPOINT_LEN_2 0x44 #define X86_BREAKPOINT_LEN_2 0x44
#define X86_BREAKPOINT_LEN_4 0x4c #define X86_BREAKPOINT_LEN_4 0x4c
#define X86_BREAKPOINT_LEN_EXECUTE 0x40
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
#define X86_BREAKPOINT_LEN_8 0x48 #define X86_BREAKPOINT_LEN_8 0x48
......
...@@ -208,6 +208,9 @@ int arch_bp_generic_fields(int x86_len, int x86_type, ...@@ -208,6 +208,9 @@ int arch_bp_generic_fields(int x86_len, int x86_type,
{ {
/* Len */ /* Len */
switch (x86_len) { switch (x86_len) {
case X86_BREAKPOINT_LEN_X:
*gen_len = sizeof(long);
break;
case X86_BREAKPOINT_LEN_1: case X86_BREAKPOINT_LEN_1:
*gen_len = HW_BREAKPOINT_LEN_1; *gen_len = HW_BREAKPOINT_LEN_1;
break; break;
...@@ -251,6 +254,29 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -251,6 +254,29 @@ static int arch_build_bp_info(struct perf_event *bp)
info->address = bp->attr.bp_addr; info->address = bp->attr.bp_addr;
/* Type */
switch (bp->attr.bp_type) {
case HW_BREAKPOINT_W:
info->type = X86_BREAKPOINT_WRITE;
break;
case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
info->type = X86_BREAKPOINT_RW;
break;
case HW_BREAKPOINT_X:
info->type = X86_BREAKPOINT_EXECUTE;
/*
* x86 inst breakpoints need to have a specific undefined len.
* But we still need to check userspace is not trying to setup
* an unsupported length, to get a range breakpoint for example.
*/
if (bp->attr.bp_len == sizeof(long)) {
info->len = X86_BREAKPOINT_LEN_X;
return 0;
}
default:
return -EINVAL;
}
/* Len */ /* Len */
switch (bp->attr.bp_len) { switch (bp->attr.bp_len) {
case HW_BREAKPOINT_LEN_1: case HW_BREAKPOINT_LEN_1:
...@@ -271,21 +297,6 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -271,21 +297,6 @@ static int arch_build_bp_info(struct perf_event *bp)
return -EINVAL; return -EINVAL;
} }
/* Type */
switch (bp->attr.bp_type) {
case HW_BREAKPOINT_W:
info->type = X86_BREAKPOINT_WRITE;
break;
case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
info->type = X86_BREAKPOINT_RW;
break;
case HW_BREAKPOINT_X:
info->type = X86_BREAKPOINT_EXECUTE;
break;
default:
return -EINVAL;
}
return 0; return 0;
} }
/* /*
...@@ -305,6 +316,9 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ...@@ -305,6 +316,9 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
ret = -EINVAL; ret = -EINVAL;
switch (info->len) { switch (info->len) {
case X86_BREAKPOINT_LEN_X:
align = sizeof(long) -1;
break;
case X86_BREAKPOINT_LEN_1: case X86_BREAKPOINT_LEN_1:
align = 0; align = 0;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment