15933f6d2SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
24e14dfc7SMatt Fleming /*
34e14dfc7SMatt Fleming * Copyright (C) 1991, 1992 Linus Torvalds
44e14dfc7SMatt Fleming * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
54e14dfc7SMatt Fleming * Copyright (C) 2009 Matt Fleming
649453264SPaul Mundt * Copyright (C) 2002 - 2012 Paul Mundt
74e14dfc7SMatt Fleming */
84e14dfc7SMatt Fleming #include <linux/kallsyms.h>
94e14dfc7SMatt Fleming #include <linux/ftrace.h>
104e14dfc7SMatt Fleming #include <linux/debug_locks.h>
11b17b0153SIngo Molnar #include <linux/sched/debug.h>
1268db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
1349453264SPaul Mundt #include <linux/kdebug.h>
1449453264SPaul Mundt #include <linux/export.h>
1549453264SPaul Mundt #include <linux/uaccess.h>
160eff9f66SMatt Fleming #include <asm/unwinder.h>
174e14dfc7SMatt Fleming #include <asm/stacktrace.h>
184e14dfc7SMatt Fleming
dump_mem(const char * str,const char * loglvl,unsigned long bottom,unsigned long top)19*0632a6d8SGeert Uytterhoeven void dump_mem(const char *str, const char *loglvl, unsigned long bottom,
20*0632a6d8SGeert Uytterhoeven unsigned long top)
2149453264SPaul Mundt {
2249453264SPaul Mundt unsigned long p;
2349453264SPaul Mundt int i;
2449453264SPaul Mundt
25ebf0a36aSDmitry Safonov printk("%s%s(0x%08lx to 0x%08lx)\n", loglvl, str, bottom, top);
2649453264SPaul Mundt
2749453264SPaul Mundt for (p = bottom & ~31; p < top; ) {
28ebf0a36aSDmitry Safonov printk("%s%04lx: ", loglvl, p & 0xffff);
2949453264SPaul Mundt
3049453264SPaul Mundt for (i = 0; i < 8; i++, p += 4) {
3149453264SPaul Mundt unsigned int val;
3249453264SPaul Mundt
3349453264SPaul Mundt if (p < bottom || p >= top)
34*0632a6d8SGeert Uytterhoeven pr_cont(" ");
3549453264SPaul Mundt else {
3649453264SPaul Mundt if (__get_user(val, (unsigned int __user *)p)) {
37*0632a6d8SGeert Uytterhoeven pr_cont("\n");
3849453264SPaul Mundt return;
3949453264SPaul Mundt }
40*0632a6d8SGeert Uytterhoeven pr_cont("%08x ", val);
4149453264SPaul Mundt }
4249453264SPaul Mundt }
43*0632a6d8SGeert Uytterhoeven pr_cont("\n");
4449453264SPaul Mundt }
4549453264SPaul Mundt }
4649453264SPaul Mundt
printk_address(unsigned long address,int reliable)47fd722f25SGeert Uytterhoeven void printk_address(unsigned long address, int reliable)
484e14dfc7SMatt Fleming {
49*0632a6d8SGeert Uytterhoeven pr_cont(" [<%px>] %s%pS\n", (void *) address,
504e14dfc7SMatt Fleming reliable ? "" : "? ", (void *) address);
514e14dfc7SMatt Fleming }
524e14dfc7SMatt Fleming
534e14dfc7SMatt Fleming #ifdef CONFIG_FUNCTION_GRAPH_TRACER
544e14dfc7SMatt Fleming static void
print_ftrace_graph_addr(unsigned long addr,void * data,const struct stacktrace_ops * ops,struct thread_info * tinfo,int * graph)554e14dfc7SMatt Fleming print_ftrace_graph_addr(unsigned long addr, void *data,
564e14dfc7SMatt Fleming const struct stacktrace_ops *ops,
574e14dfc7SMatt Fleming struct thread_info *tinfo, int *graph)
584e14dfc7SMatt Fleming {
594e14dfc7SMatt Fleming struct task_struct *task = tinfo->task;
60cec8d0e7SSteven Rostedt (VMware) struct ftrace_ret_stack *ret_stack;
614e14dfc7SMatt Fleming unsigned long ret_addr;
624e14dfc7SMatt Fleming
634e14dfc7SMatt Fleming if (addr != (unsigned long)return_to_handler)
644e14dfc7SMatt Fleming return;
654e14dfc7SMatt Fleming
66cec8d0e7SSteven Rostedt (VMware) if (!task->ret_stack)
674e14dfc7SMatt Fleming return;
684e14dfc7SMatt Fleming
69cec8d0e7SSteven Rostedt (VMware) ret_stack = ftrace_graph_get_ret_stack(task, *graph);
70cec8d0e7SSteven Rostedt (VMware) if (!ret_stack)
71cec8d0e7SSteven Rostedt (VMware) return;
72cec8d0e7SSteven Rostedt (VMware)
73cec8d0e7SSteven Rostedt (VMware) ret_addr = ret_stack->ret;
744e14dfc7SMatt Fleming
754e14dfc7SMatt Fleming ops->address(data, ret_addr, 1);
764e14dfc7SMatt Fleming
774e14dfc7SMatt Fleming (*graph)++;
784e14dfc7SMatt Fleming }
794e14dfc7SMatt Fleming #else
804e14dfc7SMatt Fleming static inline void
print_ftrace_graph_addr(unsigned long addr,void * data,const struct stacktrace_ops * ops,struct thread_info * tinfo,int * graph)814e14dfc7SMatt Fleming print_ftrace_graph_addr(unsigned long addr, void *data,
824e14dfc7SMatt Fleming const struct stacktrace_ops *ops,
834e14dfc7SMatt Fleming struct thread_info *tinfo, int *graph)
844e14dfc7SMatt Fleming { }
854e14dfc7SMatt Fleming #endif
864e14dfc7SMatt Fleming
870eff9f66SMatt Fleming void
stack_reader_dump(struct task_struct * task,struct pt_regs * regs,unsigned long * sp,const struct stacktrace_ops * ops,void * data)880eff9f66SMatt Fleming stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
894e14dfc7SMatt Fleming unsigned long *sp, const struct stacktrace_ops *ops,
904e14dfc7SMatt Fleming void *data)
914e14dfc7SMatt Fleming {
924e14dfc7SMatt Fleming struct thread_info *context;
934e14dfc7SMatt Fleming int graph = 0;
944e14dfc7SMatt Fleming
954e14dfc7SMatt Fleming context = (struct thread_info *)
964e14dfc7SMatt Fleming ((unsigned long)sp & (~(THREAD_SIZE - 1)));
974e14dfc7SMatt Fleming
984e14dfc7SMatt Fleming while (!kstack_end(sp)) {
994e14dfc7SMatt Fleming unsigned long addr = *sp++;
1004e14dfc7SMatt Fleming
1014e14dfc7SMatt Fleming if (__kernel_text_address(addr)) {
102f9967e23SPaul Mundt ops->address(data, addr, 1);
1034e14dfc7SMatt Fleming
1044e14dfc7SMatt Fleming print_ftrace_graph_addr(addr, data, ops,
1054e14dfc7SMatt Fleming context, &graph);
1064e14dfc7SMatt Fleming }
1074e14dfc7SMatt Fleming }
1084e14dfc7SMatt Fleming }
1094e14dfc7SMatt Fleming
1104e14dfc7SMatt Fleming /*
1114e14dfc7SMatt Fleming * Print one address/symbol entries per line.
1124e14dfc7SMatt Fleming */
print_trace_address(void * data,unsigned long addr,int reliable)1134e14dfc7SMatt Fleming static void print_trace_address(void *data, unsigned long addr, int reliable)
1144e14dfc7SMatt Fleming {
115f6bed866SGeert Uytterhoeven printk("%s", (char *)data);
116fd722f25SGeert Uytterhoeven printk_address(addr, reliable);
1174e14dfc7SMatt Fleming }
1184e14dfc7SMatt Fleming
1194e14dfc7SMatt Fleming static const struct stacktrace_ops print_trace_ops = {
1204e14dfc7SMatt Fleming .address = print_trace_address,
1214e14dfc7SMatt Fleming };
1224e14dfc7SMatt Fleming
show_trace(struct task_struct * tsk,unsigned long * sp,struct pt_regs * regs,const char * loglvl)1234e14dfc7SMatt Fleming void show_trace(struct task_struct *tsk, unsigned long *sp,
124539e786cSDmitry Safonov struct pt_regs *regs, const char *loglvl)
1254e14dfc7SMatt Fleming {
1264e14dfc7SMatt Fleming if (regs && user_mode(regs))
1274e14dfc7SMatt Fleming return;
1284e14dfc7SMatt Fleming
129539e786cSDmitry Safonov printk("%s\nCall trace:\n", loglvl);
1304e14dfc7SMatt Fleming
131539e786cSDmitry Safonov unwind_stack(tsk, regs, sp, &print_trace_ops, (void *)loglvl);
1324e14dfc7SMatt Fleming
133*0632a6d8SGeert Uytterhoeven pr_cont("\n");
1344e14dfc7SMatt Fleming
1354e14dfc7SMatt Fleming if (!tsk)
1364e14dfc7SMatt Fleming tsk = current;
1374e14dfc7SMatt Fleming
1384e14dfc7SMatt Fleming debug_show_held_locks(tsk);
1394e14dfc7SMatt Fleming }
14049453264SPaul Mundt
show_stack(struct task_struct * tsk,unsigned long * sp,const char * loglvl)1419cb8f069SDmitry Safonov void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
14249453264SPaul Mundt {
14349453264SPaul Mundt unsigned long stack;
14449453264SPaul Mundt
14549453264SPaul Mundt if (!tsk)
14649453264SPaul Mundt tsk = current;
14749453264SPaul Mundt if (tsk == current)
14849453264SPaul Mundt sp = (unsigned long *)current_stack_pointer;
14949453264SPaul Mundt else
15049453264SPaul Mundt sp = (unsigned long *)tsk->thread.sp;
15149453264SPaul Mundt
15249453264SPaul Mundt stack = (unsigned long)sp;
153e6e371c4SDmitry Safonov dump_mem("Stack: ", loglvl, stack, THREAD_SIZE +
15449453264SPaul Mundt (unsigned long)task_stack_page(tsk));
155e6e371c4SDmitry Safonov show_trace(tsk, sp, NULL, loglvl);
156e6e371c4SDmitry Safonov }
157