~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/perf/callchain_64.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 static int read_user_stack_64(const unsigned long __user *ptr, unsigned long *ret)
 22 {
 23         return __read_user_stack(ptr, ret, sizeof(*ret));
 24 }
 25 
 26 /*
 27  * 64-bit user processes use the same stack frame for RT and non-RT signals.
 28  */
 29 struct signal_frame_64 {
 30         char            dummy[__SIGNAL_FRAMESIZE];
 31         struct ucontext uc;
 32         unsigned long   unused[2];
 33         unsigned int    tramp[6];
 34         struct siginfo  *pinfo;
 35         void            *puc;
 36         struct siginfo  info;
 37         char            abigap[288];
 38 };
 39 
 40 static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
 41 {
 42         if (nip == fp + offsetof(struct signal_frame_64, tramp))
 43                 return 1;
 44         if (current->mm->context.vdso &&
 45             nip == VDSO64_SYMBOL(current->mm->context.vdso, sigtramp_rt64))
 46                 return 1;
 47         return 0;
 48 }
 49 
 50 /*
 51  * Do some sanity checking on the signal frame pointed to by sp.
 52  * We check the pinfo and puc pointers in the frame.
 53  */
 54 static int sane_signal_64_frame(unsigned long sp)
 55 {
 56         struct signal_frame_64 __user *sf;
 57         unsigned long pinfo, puc;
 58 
 59         sf = (struct signal_frame_64 __user *) sp;
 60         if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
 61             read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
 62                 return 0;
 63         return pinfo == (unsigned long) &sf->info &&
 64                 puc == (unsigned long) &sf->uc;
 65 }
 66 
 67 void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
 68                             struct pt_regs *regs)
 69 {
 70         unsigned long sp, next_sp;
 71         unsigned long next_ip;
 72         unsigned long lr;
 73         long level = 0;
 74         struct signal_frame_64 __user *sigframe;
 75         unsigned long __user *fp, *uregs;
 76 
 77         next_ip = perf_instruction_pointer(regs);
 78         lr = regs->link;
 79         sp = regs->gpr[1];
 80         perf_callchain_store(entry, next_ip);
 81 
 82         while (entry->nr < entry->max_stack) {
 83                 fp = (unsigned long __user *) sp;
 84                 if (invalid_user_sp(sp) || read_user_stack_64(fp, &next_sp))
 85                         return;
 86                 if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
 87                         return;
 88 
 89                 /*
 90                  * Note: the next_sp - sp >= signal frame size check
 91                  * is true when next_sp < sp, which can happen when
 92                  * transitioning from an alternate signal stack to the
 93                  * normal stack.
 94                  */
 95                 if (next_sp - sp >= sizeof(struct signal_frame_64) &&
 96                     (is_sigreturn_64_address(next_ip, sp) ||
 97                      (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
 98                     sane_signal_64_frame(sp)) {
 99                         /*
100                          * This looks like an signal frame
101                          */
102                         sigframe = (struct signal_frame_64 __user *) sp;
103                         uregs = sigframe->uc.uc_mcontext.gp_regs;
104                         if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
105                             read_user_stack_64(&uregs[PT_LNK], &lr) ||
106                             read_user_stack_64(&uregs[PT_R1], &sp))
107                                 return;
108                         level = 0;
109                         perf_callchain_store_context(entry, PERF_CONTEXT_USER);
110                         perf_callchain_store(entry, next_ip);
111                         continue;
112                 }
113 
114                 if (level == 0)
115                         next_ip = lr;
116                 perf_callchain_store(entry, next_ip);
117                 ++level;
118                 sp = next_sp;
119         }
120 }
121 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php