History

unicore32 core architecture: process/thread related codes

This patch implements process/thread related codes. Backtrace and stacktrace are here.

GuanXuetao committed 15 years ago

Commit f73670e1 parent 141c9436 files · +912 −0Browse files

Showing the changes to arch/unicore32/kernel/stacktrace.c (1 of 6 files). Show all

Unified · Split

arch/unicore32/kernel/stacktrace.c+131−0
@@ -0,0 +1,131 @@
1+/*
2+ * linux/arch/unicore32/kernel/stacktrace.c
3+ *
4+ * Code specific to PKUnity SoC and UniCore ISA
5+ *
6+ * Copyright (C) 2001-2010 GUAN Xue-tao
7+ *
8+ * This program is free software; you can redistribute it and/or modify
9+ * it under the terms of the GNU General Public License version 2 as
10+ * published by the Free Software Foundation.
11+ */
12+#include <linux/module.h>
13+#include <linux/sched.h>
14+#include <linux/stacktrace.h>
15+
16+#include <asm/stacktrace.h>
17+
18+#if defined(CONFIG_FRAME_POINTER)
19+/*
20+ * Unwind the current stack frame and store the new register values in the
21+ * structure passed as argument. Unwinding is equivalent to a function return,
22+ * hence the new PC value rather than LR should be used for backtrace.
23+ *
24+ * With framepointer enabled, a simple function prologue looks like this:
25+ * mov ip, sp
26+ * stmdb sp!, {fp, ip, lr, pc}
27+ * sub fp, ip, #4
28+ *
29+ * A simple function epilogue looks like this:
30+ * ldm sp, {fp, sp, pc}
31+ *
32+ * Note that with framepointer enabled, even the leaf functions have the same
33+ * prologue and epilogue, therefore we can ignore the LR value in this case.
34+ */
35+int notrace unwind_frame(struct stackframe *frame)
36+{
37+ unsigned long high, low;
38+ unsigned long fp = frame->fp;
39+
40+ /* only go to a higher address on the stack */
41+ low = frame->sp;
42+ high = ALIGN(low, THREAD_SIZE);
43+
44+ /* check current frame pointer is within bounds */
45+ if (fp < (low + 12) || fp + 4 >= high)
46+ return -EINVAL;
47+
48+ /* restore the registers from the stack frame */
49+ frame->fp = *(unsigned long *)(fp - 12);
50+ frame->sp = *(unsigned long *)(fp - 8);
51+ frame->pc = *(unsigned long *)(fp - 4);
52+
53+ return 0;
54+}
55+#endif
56+
57+void notrace walk_stackframe(struct stackframe *frame,
58+ int (*fn)(struct stackframe *, void *), void *data)
59+{
60+ while (1) {
61+ int ret;
62+
63+ if (fn(frame, data))
64+ break;
65+ ret = unwind_frame(frame);
66+ if (ret < 0)
67+ break;
68+ }
69+}
70+EXPORT_SYMBOL(walk_stackframe);
71+
72+#ifdef CONFIG_STACKTRACE
73+struct stack_trace_data {
74+ struct stack_trace *trace;
75+ unsigned int no_sched_functions;
76+ unsigned int skip;
77+};
78+
79+static int save_trace(struct stackframe *frame, void *d)
80+{
81+ struct stack_trace_data *data = d;
82+ struct stack_trace *trace = data->trace;
83+ unsigned long addr = frame->pc;
84+
85+ if (data->no_sched_functions && in_sched_functions(addr))
86+ return 0;
87+ if (data->skip) {
88+ data->skip--;
89+ return 0;
90+ }
91+
92+ trace->entries[trace->nr_entries++] = addr;
93+
94+ return trace->nr_entries >= trace->max_entries;
95+}
96+
97+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
98+{
99+ struct stack_trace_data data;
100+ struct stackframe frame;
101+
102+ data.trace = trace;
103+ data.skip = trace->skip;
104+
105+ if (tsk != current) {
106+ data.no_sched_functions = 1;
107+ frame.fp = thread_saved_fp(tsk);
108+ frame.sp = thread_saved_sp(tsk);
109+ frame.lr = 0; /* recovered from the stack */
110+ frame.pc = thread_saved_pc(tsk);
111+ } else {
112+ register unsigned long current_sp asm("sp");
113+
114+ data.no_sched_functions = 0;
115+ frame.fp = (unsigned long)__builtin_frame_address(0);
116+ frame.sp = current_sp;
117+ frame.lr = (unsigned long)__builtin_return_address(0);
118+ frame.pc = (unsigned long)save_stack_trace_tsk;
119+ }
120+
121+ walk_stackframe(&frame, save_trace, &data);
122+ if (trace->nr_entries < trace->max_entries)
123+ trace->entries[trace->nr_entries++] = ULONG_MAX;
124+}
125+
126+void save_stack_trace(struct stack_trace *trace)
127+{
128+ save_stack_trace_tsk(current, trace);
129+}
130+EXPORT_SYMBOL_GPL(save_stack_trace);
131+#endif