Skip to content

Commit 9b046d0

Browse files
committed
parisc: Avoid using hardware single-step in kprobes
This patch changes the kprobe and kretprobe feature to use another break instruction instead of relying on the hardware single-step feature. That way those kprobes now work in qemu as well, because in qemu we don't emulate yet single-stepping. Signed-off-by: Helge Deller <deller@gmx.de>
1 parent 46162ac commit 9b046d0

3 files changed

Lines changed: 24 additions & 19 deletions

File tree

arch/parisc/include/asm/kprobes.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
#include <linux/notifier.h>
1919

2020
#define PARISC_KPROBES_BREAK_INSN 0x3ff801f
21+
#define PARISC_KPROBES_BREAK_INSN2 0x3ff801e
2122
#define __ARCH_WANT_KPROBES_INSN_SLOT
22-
#define MAX_INSN_SIZE 1
23+
#define MAX_INSN_SIZE 2
2324

2425
typedef u32 kprobe_opcode_t;
2526
struct kprobe;
@@ -29,7 +30,7 @@ void arch_remove_kprobe(struct kprobe *p);
2930
#define flush_insn_slot(p) \
3031
flush_icache_range((unsigned long)&(p)->ainsn.insn[0], \
3132
(unsigned long)&(p)->ainsn.insn[0] + \
32-
sizeof(kprobe_opcode_t))
33+
MAX_INSN_SIZE*sizeof(kprobe_opcode_t))
3334

3435
#define kretprobe_blacklist_size 0
3536

arch/parisc/kernel/kprobes.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* PA-RISC kprobes implementation
66
*
77
* Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
8+
* Copyright (c) 2022 Helge Deller <deller@gmx.de>
89
*/
910

1011
#include <linux/types.h>
@@ -25,9 +26,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
2526
if (!p->ainsn.insn)
2627
return -ENOMEM;
2728

28-
memcpy(p->ainsn.insn, p->addr,
29-
MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
29+
/*
30+
* Set up new instructions. Second break instruction will
31+
* trigger call of parisc_kprobe_ss_handler().
32+
*/
3033
p->opcode = *p->addr;
34+
p->ainsn.insn[0] = p->opcode;
35+
p->ainsn.insn[1] = PARISC_KPROBES_BREAK_INSN2;
36+
3137
flush_insn_slot(p);
3238
return 0;
3339
}
@@ -73,9 +79,7 @@ static void __kprobes setup_singlestep(struct kprobe *p,
7379
{
7480
kcb->iaoq[0] = regs->iaoq[0];
7581
kcb->iaoq[1] = regs->iaoq[1];
76-
regs->iaoq[0] = (unsigned long)p->ainsn.insn;
77-
mtctl(0, 0);
78-
regs->gr[0] |= PSW_R;
82+
instruction_pointer_set(regs, (unsigned long)p->ainsn.insn);
7983
}
8084

8185
int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs)
@@ -165,9 +169,8 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
165169
regs->iaoq[0] = kcb->iaoq[1];
166170
break;
167171
default:
168-
regs->iaoq[1] = kcb->iaoq[0];
169-
regs->iaoq[1] += (regs->iaoq[1] - regs->iaoq[0]) + 4;
170172
regs->iaoq[0] = kcb->iaoq[1];
173+
regs->iaoq[1] = regs->iaoq[0] + 4;
171174
break;
172175
}
173176
kcb->kprobe_status = KPROBE_HIT_SSDONE;
@@ -191,14 +194,17 @@ static struct kprobe trampoline_p = {
191194
static int __kprobes trampoline_probe_handler(struct kprobe *p,
192195
struct pt_regs *regs)
193196
{
194-
unsigned long orig_ret_address;
195-
196-
orig_ret_address = __kretprobe_trampoline_handler(regs, NULL);
197-
instruction_pointer_set(regs, orig_ret_address);
197+
__kretprobe_trampoline_handler(regs, NULL);
198198

199199
return 1;
200200
}
201201

202+
void arch_kretprobe_fixup_return(struct pt_regs *regs,
203+
kprobe_opcode_t *correct_ret_addr)
204+
{
205+
regs->gr[2] = (unsigned long)correct_ret_addr;
206+
}
207+
202208
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
203209
struct pt_regs *regs)
204210
{

arch/parisc/kernel/traps.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,10 @@ static void handle_break(struct pt_regs *regs)
302302
parisc_kprobe_break_handler(regs);
303303
return;
304304
}
305-
305+
if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2)) {
306+
parisc_kprobe_ss_handler(regs);
307+
return;
308+
}
306309
#endif
307310

308311
#ifdef CONFIG_KGDB
@@ -539,11 +542,6 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
539542
/* Recovery counter trap */
540543
regs->gr[0] &= ~PSW_R;
541544

542-
#ifdef CONFIG_KPROBES
543-
if (parisc_kprobe_ss_handler(regs))
544-
return;
545-
#endif
546-
547545
#ifdef CONFIG_KGDB
548546
if (kgdb_single_step) {
549547
kgdb_handle_exception(0, SIGTRAP, 0, regs);

0 commit comments

Comments
 (0)