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: Frederic 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>
This commit is contained in:
Родитель
0c4519e825
Коммит
f7809daf64
|
@ -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,
|
||||||
{
|
{
|
||||||
/* 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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче