Skip to content

Commit 504b73d

Browse files
hcahcaVasily Gorbik
authored andcommitted
s390/perf: implement perf_callchain_user()
Daan De Meyer and Neal Gompa reported that s390 does not support perf user stack unwinding. This was never implemented since this requires user space to be compiled with the -mbackchain compile option, which until now no distribution did. However this is going to change with Fedora. Therefore provide a perf_callchain_user() implementation. Note that due to the way s390 sets up stack frames the provided call chains can contain invalid values. This is especially true for the first stack frame, where it is not possible to tell if the return address has been written to the stack already or not. Reported-by: Daan De Meyer <[email protected]> Reported-by: Neal Gompa <[email protected]> Closes: https://lore.kernel.org/all/CAO8sHcn3+_qrnvp0580aK7jN0Wion5F7KYeBAa4MnCY4mqABPA@mail.gmail.com/ Link: https://lore.kernel.org/all/[email protected] Reviewed-by: Neal Gompa <[email protected]> Acked-by: Ilya Leoshkevich <[email protected]> Signed-off-by: Heiko Carstens <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent e14aec2 commit 504b73d

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

arch/s390/include/asm/stacktrace.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
#include <linux/ptrace.h>
77
#include <asm/switch_to.h>
88

9+
struct stack_frame_user {
10+
unsigned long back_chain;
11+
unsigned long empty1[5];
12+
unsigned long gprs[10];
13+
unsigned long empty2[4];
14+
};
15+
916
enum stack_type {
1017
STACK_TYPE_UNKNOWN,
1118
STACK_TYPE_TASK,

arch/s390/kernel/perf_event.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
#include <linux/export.h>
1616
#include <linux/seq_file.h>
1717
#include <linux/spinlock.h>
18+
#include <linux/uaccess.h>
19+
#include <linux/compat.h>
1820
#include <linux/sysfs.h>
21+
#include <asm/stacktrace.h>
1922
#include <asm/irq.h>
2023
#include <asm/cpu_mf.h>
2124
#include <asm/lowcore.h>
@@ -212,6 +215,44 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
212215
}
213216
}
214217

218+
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
219+
struct pt_regs *regs)
220+
{
221+
struct stack_frame_user __user *sf;
222+
unsigned long ip, sp;
223+
bool first = true;
224+
225+
if (is_compat_task())
226+
return;
227+
perf_callchain_store(entry, instruction_pointer(regs));
228+
sf = (void __user *)user_stack_pointer(regs);
229+
pagefault_disable();
230+
while (entry->nr < entry->max_stack) {
231+
if (__get_user(sp, &sf->back_chain))
232+
break;
233+
if (__get_user(ip, &sf->gprs[8]))
234+
break;
235+
if (ip & 0x1) {
236+
/*
237+
* If the instruction address is invalid, and this
238+
* is the first stack frame, assume r14 has not
239+
* been written to the stack yet. Otherwise exit.
240+
*/
241+
if (first && !(regs->gprs[14] & 0x1))
242+
ip = regs->gprs[14];
243+
else
244+
break;
245+
}
246+
perf_callchain_store(entry, ip);
247+
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
248+
if (!sp || sp & 0x7)
249+
break;
250+
sf = (void __user *)sp;
251+
first = false;
252+
}
253+
pagefault_enable();
254+
}
255+
215256
/* Perf definitions for PMU event attributes in sysfs */
216257
ssize_t cpumf_events_sysfs_show(struct device *dev,
217258
struct device_attribute *attr, char *page)

0 commit comments

Comments
 (0)