Skip to content

Commit 63bf38f

Browse files
tobias-huschleVasily Gorbik
authored andcommitted
s390/kprobes: Avoid additional kprobe in kretprobe handling
So far, s390 registered a krobe on __kretprobe_trampoline which is called everytime a kretprobe fires. This kprobe would then determine the correct return address and adjust the psw accordingly, such that the kretprobe would branch to the appropriate address after completion. Some other archs handle kretprobes without such an additional kprobe. This approach is adopted to s390 with this patch. Furthermore, the __kretprobe_trampoline now uses an assembler function to correctly gather the register and psw content to be passed to the registered kretprobe handler as struct pt_regs. After completion, the register content and the psw are set based on the contents of said pt_regs struct. Note that a change to the psw address in struct pt_regs will not have an impact, as the probe will still return to the original return address of the probed function. The return address is now recovered by using the appropriate function arch_kretprobe_fixup_return. The no longer needed kprobe is removed. Reviewed-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Tobias Huschle <huschle@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 731efc9 commit 63bf38f

4 files changed

Lines changed: 60 additions & 34 deletions

File tree

arch/s390/include/asm/kprobes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct kprobe_ctlblk {
7171

7272
void arch_remove_kprobe(struct kprobe *p);
7373
void __kretprobe_trampoline(void);
74+
void trampoline_probe_handler(struct pt_regs *regs);
7475

7576
int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
7677
int kprobe_exceptions_notify(struct notifier_block *self,

arch/s390/kernel/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ obj-$(CONFIG_COMPAT) += $(compat-obj-y)
5757
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
5858
obj-$(CONFIG_KPROBES) += kprobes.o
5959
obj-$(CONFIG_KPROBES) += kprobes_insn_page.o
60-
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
60+
obj-$(CONFIG_KPROBES) += mcount.o
61+
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
62+
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
6163
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
6264
obj-$(CONFIG_UPROBES) += uprobes.o
6365
obj-$(CONFIG_JUMP_LABEL) += jump_label.o

arch/s390/kernel/kprobes.c

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -372,33 +372,26 @@ static int kprobe_handler(struct pt_regs *regs)
372372
}
373373
NOKPROBE_SYMBOL(kprobe_handler);
374374

375-
/*
376-
* Function return probe trampoline:
377-
* - init_kprobes() establishes a probepoint here
378-
* - When the probed function returns, this probe
379-
* causes the handlers to fire
380-
*/
381-
static void __used kretprobe_trampoline_holder(void)
375+
void arch_kretprobe_fixup_return(struct pt_regs *regs,
376+
kprobe_opcode_t *correct_ret_addr)
382377
{
383-
asm volatile(".global __kretprobe_trampoline\n"
384-
"__kretprobe_trampoline: bcr 0,0\n");
378+
/* Replace fake return address with real one. */
379+
regs->gprs[14] = (unsigned long)correct_ret_addr;
385380
}
381+
NOKPROBE_SYMBOL(arch_kretprobe_fixup_return);
386382

387383
/*
388-
* Called when the probe at kretprobe trampoline is hit
384+
* Called from __kretprobe_trampoline
389385
*/
390-
static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
386+
void trampoline_probe_handler(struct pt_regs *regs)
391387
{
392-
regs->psw.addr = __kretprobe_trampoline_handler(regs, NULL);
393-
/*
394-
* By returning a non-zero value, we are telling
395-
* kprobe_handler() that we don't want the post_handler
396-
* to run (and have re-enabled preemption)
397-
*/
398-
return 1;
388+
kretprobe_trampoline_handler(regs, NULL);
399389
}
400390
NOKPROBE_SYMBOL(trampoline_probe_handler);
401391

392+
/* assembler function that handles the kretprobes must not be probed itself */
393+
NOKPROBE_SYMBOL(__kretprobe_trampoline);
394+
402395
/*
403396
* Called after single-stepping. p->addr is the address of the
404397
* instruction whose first byte has been replaced by the "breakpoint"
@@ -551,18 +544,13 @@ int kprobe_exceptions_notify(struct notifier_block *self,
551544
}
552545
NOKPROBE_SYMBOL(kprobe_exceptions_notify);
553546

554-
static struct kprobe trampoline = {
555-
.addr = (kprobe_opcode_t *) &__kretprobe_trampoline,
556-
.pre_handler = trampoline_probe_handler
557-
};
558-
559547
int __init arch_init_kprobes(void)
560548
{
561-
return register_kprobe(&trampoline);
549+
return 0;
562550
}
563551

564552
int arch_trampoline_kprobe(struct kprobe *p)
565553
{
566-
return p->addr == (kprobe_opcode_t *) &__kretprobe_trampoline;
554+
return 0;
567555
}
568556
NOKPROBE_SYMBOL(arch_trampoline_kprobe);

arch/s390/kernel/mcount.S

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,6 @@
1111
#include <asm/ptrace.h>
1212
#include <asm/export.h>
1313

14-
GEN_BR_THUNK %r1
15-
GEN_BR_THUNK %r14
16-
17-
.section .kprobes.text, "ax"
18-
19-
ENTRY(ftrace_stub)
20-
BR_EX %r14
21-
ENDPROC(ftrace_stub)
2214

2315
#define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE)
2416
#define STACK_PTREGS (STACK_FRAME_OVERHEAD)
@@ -29,6 +21,17 @@ ENDPROC(ftrace_stub)
2921
/* packed stack: allocate just enough for r14, r15 and backchain */
3022
#define TRACED_FUNC_FRAME_SIZE 24
3123

24+
#ifdef CONFIG_FUNCTION_TRACER
25+
26+
GEN_BR_THUNK %r1
27+
GEN_BR_THUNK %r14
28+
29+
.section .kprobes.text, "ax"
30+
31+
ENTRY(ftrace_stub)
32+
BR_EX %r14
33+
ENDPROC(ftrace_stub)
34+
3235
.macro ftrace_regs_entry, allregs=0
3336
stg %r14,(__SF_GPRS+8*8)(%r15) # save traced function caller
3437

@@ -130,3 +133,35 @@ SYM_FUNC_START(return_to_handler)
130133
SYM_FUNC_END(return_to_handler)
131134

132135
#endif
136+
#endif /* CONFIG_FUNCTION_TRACER */
137+
138+
#ifdef CONFIG_KPROBES
139+
140+
SYM_FUNC_START(__kretprobe_trampoline)
141+
142+
stg %r14,(__SF_GPRS+8*8)(%r15)
143+
lay %r15,-STACK_FRAME_SIZE(%r15)
144+
stmg %r0,%r14,STACK_PTREGS_GPRS(%r15)
145+
146+
# store original stack pointer in backchain and pt_regs
147+
lay %r7,STACK_FRAME_SIZE(%r15)
148+
stg %r7,__SF_BACKCHAIN(%r15)
149+
stg %r7,STACK_PTREGS_GPRS+(15*8)(%r15)
150+
151+
# store full psw
152+
epsw %r2,%r3
153+
risbg %r3,%r2,0,31,32
154+
stg %r3,STACK_PTREGS_PSW(%r15)
155+
larl %r1,__kretprobe_trampoline
156+
stg %r1,STACK_PTREGS_PSW+8(%r15)
157+
158+
lay %r2,STACK_PTREGS(%r15)
159+
brasl %r14,trampoline_probe_handler
160+
161+
mvc __SF_EMPTY(16,%r7),STACK_PTREGS_PSW(%r15)
162+
lmg %r0,%r15,STACK_PTREGS_GPRS(%r15)
163+
lpswe __SF_EMPTY(%r15)
164+
165+
SYM_FUNC_END(__kretprobe_trampoline)
166+
167+
#endif /* CONFIG_KPROBES */

0 commit comments

Comments
 (0)