1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com>
5 #include <linux/highmem.h>
6 #include <linux/ptrace.h>
7 #include <linux/uprobes.h>
8 #include <asm/cacheflush.h>
10 #include "decode-insn.h"
12 #define UPROBE_TRAP_NR UINT_MAX
14 bool is_swbp_insn(uprobe_opcode_t
*insn
)
16 return (*insn
& 0xffff) == UPROBE_SWBP_INSN
;
19 unsigned long uprobe_get_swbp_addr(struct pt_regs
*regs
)
21 return instruction_pointer(regs
);
24 int arch_uprobe_analyze_insn(struct arch_uprobe
*auprobe
, struct mm_struct
*mm
,
29 insn
= *(probe_opcode_t
*)(&auprobe
->insn
[0]);
31 auprobe
->insn_size
= is_insn32(insn
) ? 4 : 2;
33 switch (csky_probe_decode_insn(&insn
, &auprobe
->api
)) {
37 case INSN_GOOD_NO_SLOT
:
38 auprobe
->simulate
= true;
48 int arch_uprobe_pre_xol(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
50 struct uprobe_task
*utask
= current
->utask
;
52 utask
->autask
.saved_trap_no
= current
->thread
.trap_no
;
53 current
->thread
.trap_no
= UPROBE_TRAP_NR
;
55 instruction_pointer_set(regs
, utask
->xol_vaddr
);
57 user_enable_single_step(current
);
62 int arch_uprobe_post_xol(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
64 struct uprobe_task
*utask
= current
->utask
;
66 WARN_ON_ONCE(current
->thread
.trap_no
!= UPROBE_TRAP_NR
);
67 current
->thread
.trap_no
= utask
->autask
.saved_trap_no
;
69 instruction_pointer_set(regs
, utask
->vaddr
+ auprobe
->insn_size
);
71 user_disable_single_step(current
);
76 bool arch_uprobe_xol_was_trapped(struct task_struct
*t
)
78 if (t
->thread
.trap_no
!= UPROBE_TRAP_NR
)
84 bool arch_uprobe_skip_sstep(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
89 if (!auprobe
->simulate
)
92 insn
= *(probe_opcode_t
*)(&auprobe
->insn
[0]);
93 addr
= instruction_pointer(regs
);
95 if (auprobe
->api
.handler
)
96 auprobe
->api
.handler(insn
, addr
, regs
);
101 void arch_uprobe_abort_xol(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
103 struct uprobe_task
*utask
= current
->utask
;
105 current
->thread
.trap_no
= utask
->autask
.saved_trap_no
;
108 * Task has received a fatal signal, so reset back to probed
111 instruction_pointer_set(regs
, utask
->vaddr
);
113 user_disable_single_step(current
);
116 bool arch_uretprobe_is_alive(struct return_instance
*ret
, enum rp_check ctx
,
117 struct pt_regs
*regs
)
119 if (ctx
== RP_CHECK_CHAIN_CALL
)
120 return regs
->usp
<= ret
->stack
;
122 return regs
->usp
< ret
->stack
;
126 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr
,
127 struct pt_regs
*regs
)
133 regs
->lr
= trampoline_vaddr
;
138 int arch_uprobe_exception_notify(struct notifier_block
*self
,
139 unsigned long val
, void *data
)
144 int uprobe_breakpoint_handler(struct pt_regs
*regs
)
146 if (uprobe_pre_sstep_notifier(regs
))
152 int uprobe_single_step_handler(struct pt_regs
*regs
)
154 if (uprobe_post_sstep_notifier(regs
))