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
);
68 instruction_pointer_set(regs
, utask
->vaddr
+ auprobe
->insn_size
);
70 user_disable_single_step(current
);
75 bool arch_uprobe_xol_was_trapped(struct task_struct
*t
)
77 if (t
->thread
.trap_no
!= UPROBE_TRAP_NR
)
83 bool arch_uprobe_skip_sstep(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
88 if (!auprobe
->simulate
)
91 insn
= *(probe_opcode_t
*)(&auprobe
->insn
[0]);
92 addr
= instruction_pointer(regs
);
94 if (auprobe
->api
.handler
)
95 auprobe
->api
.handler(insn
, addr
, regs
);
100 void arch_uprobe_abort_xol(struct arch_uprobe
*auprobe
, struct pt_regs
*regs
)
102 struct uprobe_task
*utask
= current
->utask
;
105 * Task has received a fatal signal, so reset back to probbed
108 instruction_pointer_set(regs
, utask
->vaddr
);
110 user_disable_single_step(current
);
113 bool arch_uretprobe_is_alive(struct return_instance
*ret
, enum rp_check ctx
,
114 struct pt_regs
*regs
)
116 if (ctx
== RP_CHECK_CHAIN_CALL
)
117 return regs
->usp
<= ret
->stack
;
119 return regs
->usp
< ret
->stack
;
123 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr
,
124 struct pt_regs
*regs
)
130 regs
->lr
= trampoline_vaddr
;
135 int arch_uprobe_exception_notify(struct notifier_block
*self
,
136 unsigned long val
, void *data
)
141 int uprobe_breakpoint_handler(struct pt_regs
*regs
)
143 if (uprobe_pre_sstep_notifier(regs
))
149 int uprobe_single_step_handler(struct pt_regs
*regs
)
151 if (uprobe_post_sstep_notifier(regs
))