Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Performance counter callchain support - powerpc architecture code
0004  *
0005  * Copyright © 2009 Paul Mackerras, IBM Corporation.
0006  */
0007 #include <linux/kernel.h>
0008 #include <linux/sched.h>
0009 #include <linux/perf_event.h>
0010 #include <linux/percpu.h>
0011 #include <linux/uaccess.h>
0012 #include <linux/mm.h>
0013 #include <asm/ptrace.h>
0014 #include <asm/sigcontext.h>
0015 #include <asm/ucontext.h>
0016 #include <asm/vdso.h>
0017 #include <asm/pte-walk.h>
0018 
0019 #include "callchain.h"
0020 
0021 #ifdef CONFIG_PPC64
0022 #include "../kernel/ppc32.h"
0023 #else  /* CONFIG_PPC64 */
0024 
0025 #define __SIGNAL_FRAMESIZE32    __SIGNAL_FRAMESIZE
0026 #define sigcontext32        sigcontext
0027 #define mcontext32      mcontext
0028 #define ucontext32      ucontext
0029 #define compat_siginfo_t    struct siginfo
0030 
0031 #endif /* CONFIG_PPC64 */
0032 
0033 static int read_user_stack_32(const unsigned int __user *ptr, unsigned int *ret)
0034 {
0035     return __read_user_stack(ptr, ret, sizeof(*ret));
0036 }
0037 
0038 /*
0039  * Layout for non-RT signal frames
0040  */
0041 struct signal_frame_32 {
0042     char            dummy[__SIGNAL_FRAMESIZE32];
0043     struct sigcontext32 sctx;
0044     struct mcontext32   mctx;
0045     int         abigap[56];
0046 };
0047 
0048 /*
0049  * Layout for RT signal frames
0050  */
0051 struct rt_signal_frame_32 {
0052     char            dummy[__SIGNAL_FRAMESIZE32 + 16];
0053     compat_siginfo_t    info;
0054     struct ucontext32   uc;
0055     int         abigap[56];
0056 };
0057 
0058 static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
0059 {
0060     if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
0061         return 1;
0062     if (current->mm->context.vdso &&
0063         nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp32))
0064         return 1;
0065     return 0;
0066 }
0067 
0068 static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
0069 {
0070     if (nip == fp + offsetof(struct rt_signal_frame_32,
0071                  uc.uc_mcontext.mc_pad))
0072         return 1;
0073     if (current->mm->context.vdso &&
0074         nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp_rt32))
0075         return 1;
0076     return 0;
0077 }
0078 
0079 static int sane_signal_32_frame(unsigned int sp)
0080 {
0081     struct signal_frame_32 __user *sf;
0082     unsigned int regs;
0083 
0084     sf = (struct signal_frame_32 __user *) (unsigned long) sp;
0085     if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
0086         return 0;
0087     return regs == (unsigned long) &sf->mctx;
0088 }
0089 
0090 static int sane_rt_signal_32_frame(unsigned int sp)
0091 {
0092     struct rt_signal_frame_32 __user *sf;
0093     unsigned int regs;
0094 
0095     sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
0096     if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
0097         return 0;
0098     return regs == (unsigned long) &sf->uc.uc_mcontext;
0099 }
0100 
0101 static unsigned int __user *signal_frame_32_regs(unsigned int sp,
0102                 unsigned int next_sp, unsigned int next_ip)
0103 {
0104     struct mcontext32 __user *mctx = NULL;
0105     struct signal_frame_32 __user *sf;
0106     struct rt_signal_frame_32 __user *rt_sf;
0107 
0108     /*
0109      * Note: the next_sp - sp >= signal frame size check
0110      * is true when next_sp < sp, for example, when
0111      * transitioning from an alternate signal stack to the
0112      * normal stack.
0113      */
0114     if (next_sp - sp >= sizeof(struct signal_frame_32) &&
0115         is_sigreturn_32_address(next_ip, sp) &&
0116         sane_signal_32_frame(sp)) {
0117         sf = (struct signal_frame_32 __user *) (unsigned long) sp;
0118         mctx = &sf->mctx;
0119     }
0120 
0121     if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
0122         is_rt_sigreturn_32_address(next_ip, sp) &&
0123         sane_rt_signal_32_frame(sp)) {
0124         rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
0125         mctx = &rt_sf->uc.uc_mcontext;
0126     }
0127 
0128     if (!mctx)
0129         return NULL;
0130     return mctx->mc_gregs;
0131 }
0132 
0133 void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
0134                 struct pt_regs *regs)
0135 {
0136     unsigned int sp, next_sp;
0137     unsigned int next_ip;
0138     unsigned int lr;
0139     long level = 0;
0140     unsigned int __user *fp, *uregs;
0141 
0142     next_ip = perf_instruction_pointer(regs);
0143     lr = regs->link;
0144     sp = regs->gpr[1];
0145     perf_callchain_store(entry, next_ip);
0146 
0147     while (entry->nr < entry->max_stack) {
0148         fp = (unsigned int __user *) (unsigned long) sp;
0149         if (invalid_user_sp(sp) || read_user_stack_32(fp, &next_sp))
0150             return;
0151         if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
0152             return;
0153 
0154         uregs = signal_frame_32_regs(sp, next_sp, next_ip);
0155         if (!uregs && level <= 1)
0156             uregs = signal_frame_32_regs(sp, next_sp, lr);
0157         if (uregs) {
0158             /*
0159              * This looks like an signal frame, so restart
0160              * the stack trace with the values in it.
0161              */
0162             if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
0163                 read_user_stack_32(&uregs[PT_LNK], &lr) ||
0164                 read_user_stack_32(&uregs[PT_R1], &sp))
0165                 return;
0166             level = 0;
0167             perf_callchain_store_context(entry, PERF_CONTEXT_USER);
0168             perf_callchain_store(entry, next_ip);
0169             continue;
0170         }
0171 
0172         if (level == 0)
0173             next_ip = lr;
0174         perf_callchain_store(entry, next_ip);
0175         ++level;
0176         sp = next_sp;
0177     }
0178 }