xref: /openbmc/linux/arch/um/kernel/stacktrace.c (revision 23c2b932)
1 /*
2  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Copyright (C) 2013 Richard Weinberger <richard@nod.at>
4  * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/kallsyms.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/stacktrace.h>
15 #include <linux/module.h>
16 #include <linux/uaccess.h>
17 #include <asm/stacktrace.h>
18 
19 void dump_trace(struct task_struct *tsk,
20 		const struct stacktrace_ops *ops,
21 		void *data)
22 {
23 	int reliable = 0;
24 	unsigned long *sp, bp, addr;
25 	struct pt_regs *segv_regs = tsk->thread.segv_regs;
26 	struct stack_frame *frame;
27 
28 	bp = get_frame_pointer(tsk, segv_regs);
29 	sp = get_stack_pointer(tsk, segv_regs);
30 
31 	frame = (struct stack_frame *)bp;
32 	while (((long) sp & (THREAD_SIZE-1)) != 0) {
33 		addr = *sp;
34 		if (__kernel_text_address(addr)) {
35 			reliable = 0;
36 			if ((unsigned long) sp == bp + sizeof(long)) {
37 				frame = frame ? frame->next_frame : NULL;
38 				bp = (unsigned long)frame;
39 				reliable = 1;
40 			}
41 			ops->address(data, addr, reliable);
42 		}
43 		sp++;
44 	}
45 }
46 
47 static void save_addr(void *data, unsigned long address, int reliable)
48 {
49 	struct stack_trace *trace = data;
50 
51 	if (!reliable)
52 		return;
53 	if (trace->nr_entries >= trace->max_entries)
54 		return;
55 
56 	trace->entries[trace->nr_entries++] = address;
57 }
58 
59 static const struct stacktrace_ops dump_ops = {
60 	.address = save_addr
61 };
62 
63 static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace)
64 {
65 	dump_trace(tsk, &dump_ops, trace);
66 	if (trace->nr_entries < trace->max_entries)
67 		trace->entries[trace->nr_entries++] = ULONG_MAX;
68 }
69 
70 void save_stack_trace(struct stack_trace *trace)
71 {
72 	__save_stack_trace(current, trace);
73 }
74 EXPORT_SYMBOL_GPL(save_stack_trace);
75 
76 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
77 {
78 	__save_stack_trace(tsk, trace);
79 }
80 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
81