-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch adds support for uprobes on riscv architecture. Just like kprobe, it support single-step and simulate instructions. Signed-off-by: Guo Ren <guoren@linux.alibaba.com> Reviewed-by: Pekka Enberg <penberg@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Palmer Dabbelt <palmerdabbelt@google.com> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
- Loading branch information
Guo Ren
authored and
Palmer Dabbelt
committed
Jan 14, 2021
1 parent
829adda
commit 7478408
Showing
9 changed files
with
253 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
||
#ifndef _ASM_RISCV_UPROBES_H | ||
#define _ASM_RISCV_UPROBES_H | ||
|
||
#include <asm/probes.h> | ||
#include <asm/patch.h> | ||
#include <asm/bug.h> | ||
|
||
#define MAX_UINSN_BYTES 8 | ||
|
||
#ifdef CONFIG_RISCV_ISA_C | ||
#define UPROBE_SWBP_INSN __BUG_INSN_16 | ||
#define UPROBE_SWBP_INSN_SIZE 2 | ||
#else | ||
#define UPROBE_SWBP_INSN __BUG_INSN_32 | ||
#define UPROBE_SWBP_INSN_SIZE 4 | ||
#endif | ||
#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES | ||
|
||
typedef u32 uprobe_opcode_t; | ||
|
||
struct arch_uprobe_task { | ||
unsigned long saved_cause; | ||
}; | ||
|
||
struct arch_uprobe { | ||
union { | ||
u8 insn[MAX_UINSN_BYTES]; | ||
u8 ixol[MAX_UINSN_BYTES]; | ||
}; | ||
struct arch_probe_insn api; | ||
unsigned long insn_size; | ||
bool simulate; | ||
}; | ||
|
||
bool uprobe_breakpoint_handler(struct pt_regs *regs); | ||
bool uprobe_single_step_handler(struct pt_regs *regs); | ||
|
||
#endif /* _ASM_RISCV_UPROBES_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
|
||
#include <linux/highmem.h> | ||
#include <linux/ptrace.h> | ||
#include <linux/uprobes.h> | ||
|
||
#include "decode-insn.h" | ||
|
||
#define UPROBE_TRAP_NR UINT_MAX | ||
|
||
bool is_swbp_insn(uprobe_opcode_t *insn) | ||
{ | ||
#ifdef CONFIG_RISCV_ISA_C | ||
return (*insn & 0xffff) == UPROBE_SWBP_INSN; | ||
#else | ||
return *insn == UPROBE_SWBP_INSN; | ||
#endif | ||
} | ||
|
||
unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) | ||
{ | ||
return instruction_pointer(regs); | ||
} | ||
|
||
int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | ||
unsigned long addr) | ||
{ | ||
probe_opcode_t opcode; | ||
|
||
opcode = *(probe_opcode_t *)(&auprobe->insn[0]); | ||
|
||
auprobe->insn_size = GET_INSN_LENGTH(opcode); | ||
|
||
switch (riscv_probe_decode_insn(&opcode, &auprobe->api)) { | ||
case INSN_REJECTED: | ||
return -EINVAL; | ||
|
||
case INSN_GOOD_NO_SLOT: | ||
auprobe->simulate = true; | ||
break; | ||
|
||
case INSN_GOOD: | ||
auprobe->simulate = false; | ||
break; | ||
|
||
default: | ||
return -EINVAL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
{ | ||
struct uprobe_task *utask = current->utask; | ||
|
||
utask->autask.saved_cause = current->thread.bad_cause; | ||
current->thread.bad_cause = UPROBE_TRAP_NR; | ||
|
||
instruction_pointer_set(regs, utask->xol_vaddr); | ||
|
||
regs->status &= ~SR_SPIE; | ||
|
||
return 0; | ||
} | ||
|
||
int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
{ | ||
struct uprobe_task *utask = current->utask; | ||
|
||
WARN_ON_ONCE(current->thread.bad_cause != UPROBE_TRAP_NR); | ||
|
||
instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size); | ||
|
||
regs->status |= SR_SPIE; | ||
|
||
return 0; | ||
} | ||
|
||
bool arch_uprobe_xol_was_trapped(struct task_struct *t) | ||
{ | ||
if (t->thread.bad_cause != UPROBE_TRAP_NR) | ||
return true; | ||
|
||
return false; | ||
} | ||
|
||
bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
{ | ||
probe_opcode_t insn; | ||
unsigned long addr; | ||
|
||
if (!auprobe->simulate) | ||
return false; | ||
|
||
insn = *(probe_opcode_t *)(&auprobe->insn[0]); | ||
addr = instruction_pointer(regs); | ||
|
||
if (auprobe->api.handler) | ||
auprobe->api.handler(insn, addr, regs); | ||
|
||
return true; | ||
} | ||
|
||
void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
{ | ||
struct uprobe_task *utask = current->utask; | ||
|
||
/* | ||
* Task has received a fatal signal, so reset back to probbed | ||
* address. | ||
*/ | ||
instruction_pointer_set(regs, utask->vaddr); | ||
|
||
regs->status &= ~SR_SPIE; | ||
} | ||
|
||
bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, | ||
struct pt_regs *regs) | ||
{ | ||
if (ctx == RP_CHECK_CHAIN_CALL) | ||
return regs->sp <= ret->stack; | ||
else | ||
return regs->sp < ret->stack; | ||
} | ||
|
||
unsigned long | ||
arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, | ||
struct pt_regs *regs) | ||
{ | ||
unsigned long ra; | ||
|
||
ra = regs->ra; | ||
|
||
regs->ra = trampoline_vaddr; | ||
|
||
return ra; | ||
} | ||
|
||
int arch_uprobe_exception_notify(struct notifier_block *self, | ||
unsigned long val, void *data) | ||
{ | ||
return NOTIFY_DONE; | ||
} | ||
|
||
bool uprobe_breakpoint_handler(struct pt_regs *regs) | ||
{ | ||
if (uprobe_pre_sstep_notifier(regs)) | ||
return true; | ||
|
||
return false; | ||
} | ||
|
||
bool uprobe_single_step_handler(struct pt_regs *regs) | ||
{ | ||
if (uprobe_post_sstep_notifier(regs)) | ||
return true; | ||
|
||
return false; | ||
} | ||
|
||
void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, | ||
void *src, unsigned long len) | ||
{ | ||
/* Initialize the slot */ | ||
void *kaddr = kmap_atomic(page); | ||
void *dst = kaddr + (vaddr & ~PAGE_MASK); | ||
|
||
memcpy(dst, src, len); | ||
|
||
/* Add ebreak behind opcode to simulate singlestep */ | ||
if (vaddr) { | ||
dst += GET_INSN_LENGTH(*(probe_opcode_t *)src); | ||
*(uprobe_opcode_t *)dst = __BUG_INSN_32; | ||
} | ||
|
||
kunmap_atomic(kaddr); | ||
|
||
/* | ||
* We probably need flush_icache_user_page() but it needs vma. | ||
* This should work on most of architectures by default. If | ||
* architecture needs to do something different it can define | ||
* its own version of the function. | ||
*/ | ||
flush_dcache_page(page); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters