1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Performance counter callchain support - powerpc architecture code
4 *
5 * Copyright �� 2009 Paul Mackerras, IBM Corporation.
6 */
7#include <linux/kernel.h>
8#include <linux/sched.h>
9#include <linux/perf_event.h>
10#include <linux/percpu.h>
11#include <linux/uaccess.h>
12#include <linux/mm.h>
13#include <asm/ptrace.h>
14#include <asm/sigcontext.h>
15#include <asm/ucontext.h>
16#include <asm/vdso.h>
17#include <asm/pte-walk.h>
18
19#include "callchain.h"
20
21#ifdef CONFIG_PPC64
22#include <asm/syscalls_32.h>
23#else  /* CONFIG_PPC64 */
24
25#define __SIGNAL_FRAMESIZE32	__SIGNAL_FRAMESIZE
26#define sigcontext32		sigcontext
27#define mcontext32		mcontext
28#define ucontext32		ucontext
29#define compat_siginfo_t	struct siginfo
30
31#endif /* CONFIG_PPC64 */
32
33static int read_user_stack_32(const unsigned int __user *ptr, unsigned int *ret)
34{
35	return __read_user_stack(ptr, ret, sizeof(*ret));
36}
37
38/*
39 * Layout for non-RT signal frames
40 */
41struct signal_frame_32 {
42	char			dummy[__SIGNAL_FRAMESIZE32];
43	struct sigcontext32	sctx;
44	struct mcontext32	mctx;
45	int			abigap[56];
46};
47
48/*
49 * Layout for RT signal frames
50 */
51struct rt_signal_frame_32 {
52	char			dummy[__SIGNAL_FRAMESIZE32 + 16];
53	compat_siginfo_t	info;
54	struct ucontext32	uc;
55	int			abigap[56];
56};
57
58static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
59{
60	if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
61		return 1;
62	if (current->mm->context.vdso &&
63	    nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp32))
64		return 1;
65	return 0;
66}
67
68static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
69{
70	if (nip == fp + offsetof(struct rt_signal_frame_32,
71				 uc.uc_mcontext.mc_pad))
72		return 1;
73	if (current->mm->context.vdso &&
74	    nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp_rt32))
75		return 1;
76	return 0;
77}
78
79static int sane_signal_32_frame(unsigned int sp)
80{
81	struct signal_frame_32 __user *sf;
82	unsigned int regs;
83
84	sf = (struct signal_frame_32 __user *) (unsigned long) sp;
85	if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
86		return 0;
87	return regs == (unsigned long) &sf->mctx;
88}
89
90static int sane_rt_signal_32_frame(unsigned int sp)
91{
92	struct rt_signal_frame_32 __user *sf;
93	unsigned int regs;
94
95	sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
96	if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
97		return 0;
98	return regs == (unsigned long) &sf->uc.uc_mcontext;
99}
100
101static unsigned int __user *signal_frame_32_regs(unsigned int sp,
102				unsigned int next_sp, unsigned int next_ip)
103{
104	struct mcontext32 __user *mctx = NULL;
105	struct signal_frame_32 __user *sf;
106	struct rt_signal_frame_32 __user *rt_sf;
107
108	/*
109	 * Note: the next_sp - sp >= signal frame size check
110	 * is true when next_sp < sp, for example, when
111	 * transitioning from an alternate signal stack to the
112	 * normal stack.
113	 */
114	if (next_sp - sp >= sizeof(struct signal_frame_32) &&
115	    is_sigreturn_32_address(next_ip, sp) &&
116	    sane_signal_32_frame(sp)) {
117		sf = (struct signal_frame_32 __user *) (unsigned long) sp;
118		mctx = &sf->mctx;
119	}
120
121	if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
122	    is_rt_sigreturn_32_address(next_ip, sp) &&
123	    sane_rt_signal_32_frame(sp)) {
124		rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
125		mctx = &rt_sf->uc.uc_mcontext;
126	}
127
128	if (!mctx)
129		return NULL;
130	return mctx->mc_gregs;
131}
132
133void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
134			    struct pt_regs *regs)
135{
136	unsigned int sp, next_sp;
137	unsigned int next_ip;
138	unsigned int lr;
139	long level = 0;
140	unsigned int __user *fp, *uregs;
141
142	next_ip = perf_instruction_pointer(regs);
143	lr = regs->link;
144	sp = regs->gpr[1];
145	perf_callchain_store(entry, next_ip);
146
147	while (entry->nr < entry->max_stack) {
148		fp = (unsigned int __user *) (unsigned long) sp;
149		if (invalid_user_sp(sp) || read_user_stack_32(fp, &next_sp))
150			return;
151		if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
152			return;
153
154		uregs = signal_frame_32_regs(sp, next_sp, next_ip);
155		if (!uregs && level <= 1)
156			uregs = signal_frame_32_regs(sp, next_sp, lr);
157		if (uregs) {
158			/*
159			 * This looks like an signal frame, so restart
160			 * the stack trace with the values in it.
161			 */
162			if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
163			    read_user_stack_32(&uregs[PT_LNK], &lr) ||
164			    read_user_stack_32(&uregs[PT_R1], &sp))
165				return;
166			level = 0;
167			perf_callchain_store_context(entry, PERF_CONTEXT_USER);
168			perf_callchain_store(entry, next_ip);
169			continue;
170		}
171
172		if (level == 0)
173			next_ip = lr;
174		perf_callchain_store(entry, next_ip);
175		++level;
176		sp = next_sp;
177	}
178}
179