18c2ecf20Sopenharmony_ci/** 28c2ecf20Sopenharmony_ci * @file backtrace.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * @remark Copyright 2002 OProfile authors 58c2ecf20Sopenharmony_ci * @remark Read the file COPYING 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * @author John Levon 88c2ecf20Sopenharmony_ci * @author David Smith 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/oprofile.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/compat.h> 158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 188c2ecf20Sopenharmony_ci#include <asm/stacktrace.h> 198c2ecf20Sopenharmony_ci#include <asm/unwind.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 228c2ecf20Sopenharmony_cistatic struct stack_frame_ia32 * 238c2ecf20Sopenharmony_cidump_user_backtrace_32(struct stack_frame_ia32 *head) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci /* Also check accessibility of one struct frame_head beyond: */ 268c2ecf20Sopenharmony_ci struct stack_frame_ia32 bufhead[2]; 278c2ecf20Sopenharmony_ci struct stack_frame_ia32 *fp; 288c2ecf20Sopenharmony_ci unsigned long bytes; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); 318c2ecf20Sopenharmony_ci if (bytes != 0) 328c2ecf20Sopenharmony_ci return NULL; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci oprofile_add_trace(bufhead[0].return_address); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* frame pointers should strictly progress back up the stack 398c2ecf20Sopenharmony_ci * (towards higher addresses) */ 408c2ecf20Sopenharmony_ci if (head >= fp) 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return fp; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline int 478c2ecf20Sopenharmony_cix86_backtrace_32(struct pt_regs * const regs, unsigned int depth) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct stack_frame_ia32 *head; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* User process is IA32 */ 528c2ecf20Sopenharmony_ci if (!current || !test_thread_flag(TIF_IA32)) 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci head = (struct stack_frame_ia32 *) regs->bp; 568c2ecf20Sopenharmony_ci while (depth-- && head) 578c2ecf20Sopenharmony_ci head = dump_user_backtrace_32(head); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 1; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#else 638c2ecf20Sopenharmony_cistatic inline int 648c2ecf20Sopenharmony_cix86_backtrace_32(struct pt_regs * const regs, unsigned int depth) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic struct stack_frame *dump_user_backtrace(struct stack_frame *head) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci /* Also check accessibility of one struct frame_head beyond: */ 738c2ecf20Sopenharmony_ci struct stack_frame bufhead[2]; 748c2ecf20Sopenharmony_ci unsigned long bytes; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); 778c2ecf20Sopenharmony_ci if (bytes != 0) 788c2ecf20Sopenharmony_ci return NULL; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci oprofile_add_trace(bufhead[0].return_address); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* frame pointers should strictly progress back up the stack 838c2ecf20Sopenharmony_ci * (towards higher addresses) */ 848c2ecf20Sopenharmony_ci if (head >= bufhead[0].next_frame) 858c2ecf20Sopenharmony_ci return NULL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return bufhead[0].next_frame; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid 918c2ecf20Sopenharmony_cix86_backtrace(struct pt_regs * const regs, unsigned int depth) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct stack_frame *head = (struct stack_frame *)frame_pointer(regs); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!user_mode(regs)) { 968c2ecf20Sopenharmony_ci struct unwind_state state; 978c2ecf20Sopenharmony_ci unsigned long addr; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!depth) 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci oprofile_add_trace(regs->ip); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!--depth) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (unwind_start(&state, current, regs, NULL); 1088c2ecf20Sopenharmony_ci !unwind_done(&state); unwind_next_frame(&state)) { 1098c2ecf20Sopenharmony_ci addr = unwind_get_return_address(&state); 1108c2ecf20Sopenharmony_ci if (!addr) 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci oprofile_add_trace(addr); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (!--depth) 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (x86_backtrace_32(regs, depth)) 1238c2ecf20Sopenharmony_ci return; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci while (depth-- && head) 1268c2ecf20Sopenharmony_ci head = dump_user_backtrace(head); 1278c2ecf20Sopenharmony_ci} 128