]> sourceware.org Git - systemtap.git/blame - runtime/stack.c
Document generated functions for maps.
[systemtap.git] / runtime / stack.c
CommitLineData
3d4bc8be 1#ifndef _STACK_C_ /* -*- linux-c -*- */
e32551b1 2#define _STACK_C_
3d4bc8be 3
e32551b1
MH
4
5/** @file stack.c
6 * @brief Stack Tracing Functions
7 */
8
9/** @addtogroup stack Stack Tracing Functions
10 * @{
11 */
12
13#include "sym.c"
14
15static int (*_stp_kta)(unsigned long addr)=(void *)KTA;
16
43614f5d
MH
17
18struct frame_head {
19 struct frame_head * ebp;
20 unsigned long ret;
21} __attribute__((packed));
22
23static struct frame_head *
24dump_backtrace(struct frame_head * head)
25{
26 _stp_printf ("db: %lx\n", head->ret);
27
28 /* frame pointers should strictly progress back up the stack
29 * (towards higher addresses) */
30 if (head >= head->ebp)
31 return NULL;
32
33 return head->ebp;
34}
35
36static int pages_present(struct frame_head * head)
37{
38 struct mm_struct * mm = current->mm;
39
40 /* FIXME: only necessary once per page */
41 if (!check_user_page_readable(mm, (unsigned long)head))
42 return 0;
43
44 return check_user_page_readable(mm, (unsigned long)(head + 1));
45}
46
47static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
48{
49 unsigned long headaddr = (unsigned long)head;
50 unsigned long stack = (unsigned long)regs;
51 unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
52 _stp_log ("%lx %lx %lx\n", headaddr, stack, stack_base);
53 return headaddr < stack_base;
54}
55
56void
57x86_backtrace(struct pt_regs * const regs, unsigned int depth)
58{
59 struct frame_head *head;
60
61#ifdef CONFIG_X86_64
62 head = (struct frame_head *)regs->rbp;
63#else
64 head = (struct frame_head *)regs->ebp;
65#endif
66
67 if (!user_mode(regs)) {
68 _stp_log ("kernel mode\n");
69 while (depth-- && valid_kernel_stack(head, regs))
70 head = dump_backtrace(head);
71 _stp_print_flush();
72 return;
73 }
74
75#ifdef CONFIG_SMP
76 if (!spin_trylock(&current->mm->page_table_lock))
77 return;
78#endif
79
80 while (depth-- && head && pages_present(head))
81 head = dump_backtrace(head);
82
83#ifdef CONFIG_SMP
84 spin_unlock(&current->mm->page_table_lock);
85#endif
86 _stp_print_flush();
87}
88
89
e32551b1
MH
90#ifdef __x86_64__
91static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
92{
93 unsigned long addr;
e32551b1 94 while (((long) stack & (THREAD_SIZE-1)) != 0) {
43614f5d 95 addr = *stack;
e32551b1 96 if (_stp_kta(addr)) {
3d4bc8be 97 if (verbose) {
e32551b1 98 _stp_symbol_print (addr);
3d4bc8be
MH
99 _stp_print ("\n");
100 } else
101 _stp_printf ("0x%lx ", addr);
e32551b1 102 }
43614f5d 103 stack++;
e32551b1 104 }
3d4bc8be 105 _stp_print_flush();
e32551b1
MH
106}
107
108
3d4bc8be 109static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
e32551b1
MH
110{
111 unsigned long addr;
e32551b1
MH
112 while (((long) stack & (THREAD_SIZE-1)) != 0) {
113 addr = *stack++;
114 if (_stp_kta(addr)) {
43614f5d 115 if (verbose) {
3d4bc8be 116 _stp_symbol_sprint (str, addr);
43614f5d
MH
117 _stp_sprintf (str, "\n");
118 } else
119 _stp_sprintf (str, "0x%lx\n", addr);
e32551b1
MH
120 }
121 }
e32551b1
MH
122}
123
124#else /* i386 */
125
126static inline int valid_stack_ptr (struct thread_info *tinfo, void *p)
127{
128 return p > (void *)tinfo &&
129 p < (void *)tinfo + THREAD_SIZE - 3;
130}
131
132static inline unsigned long _stp_print_context_stack (
133 struct thread_info *tinfo,
134 unsigned long *stack,
135 unsigned long ebp )
136{
137 unsigned long addr;
138
139#ifdef CONFIG_FRAME_POINTER
140 while (valid_stack_ptr(tinfo, (void *)ebp)) {
141 addr = *(unsigned long *)(ebp + 4);
142 _stp_symbol_print (addr);
3d4bc8be 143 _stp_print_cstr("\n");
e32551b1
MH
144 ebp = *(unsigned long *)ebp;
145 }
146#else
147 while (valid_stack_ptr(tinfo, stack)) {
148 addr = *stack++;
149 if (_stp_kta (addr)) {
150 _stp_symbol_print (addr);
3d4bc8be 151 _stp_print_cstr ("\n");
e32551b1
MH
152 }
153 }
154#endif
3d4bc8be 155 _stp_print_flush();
e32551b1
MH
156 return ebp;
157}
158
159static inline unsigned long _stp_sprint_context_stack (
3d4bc8be 160 String str,
e32551b1
MH
161 struct thread_info *tinfo,
162 unsigned long *stack,
163 unsigned long ebp )
164{
165 unsigned long addr;
166
167#ifdef CONFIG_FRAME_POINTER
168 while (valid_stack_ptr(tinfo, (void *)ebp)) {
169 addr = *(unsigned long *)(ebp + 4);
3d4bc8be 170 _stp_symbol_sprint (str, addr);
ac902b1d 171 _stp_string_cat (str, "\n");
e32551b1
MH
172 ebp = *(unsigned long *)ebp;
173 }
174#else
175 while (valid_stack_ptr(tinfo, stack)) {
176 addr = *stack++;
177 if (_stp_kta (addr)) {
ac902b1d
MH
178 _stp_symbol_sprint (str, addr);
179 _stp_string_cat (str, "\n");
e32551b1
MH
180 }
181 }
182#endif
183 return ebp;
184}
185
186static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
187{
188 unsigned long ebp;
189
190 /* Grab ebp right from our regs */
191 asm ("movl %%ebp, %0" : "=r" (ebp) : );
192
193 while (stack) {
194 struct thread_info *context = (struct thread_info *)
195 ((unsigned long)stack & (~(THREAD_SIZE - 1)));
196 ebp = _stp_print_context_stack (context, stack, ebp);
197 stack = (unsigned long*)context->previous_esp;
198 }
ac902b1d 199 _stp_print_flush ();
e32551b1
MH
200}
201
3d4bc8be 202static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
e32551b1
MH
203{
204 unsigned long ebp;
205
206 /* Grab ebp right from our regs */
207 asm ("movl %%ebp, %0" : "=r" (ebp) : );
208
209 while (stack) {
210 struct thread_info *context = (struct thread_info *)
211 ((unsigned long)stack & (~(THREAD_SIZE - 1)));
3d4bc8be 212 ebp = _stp_sprint_context_stack (str, context, stack, ebp);
e32551b1
MH
213 stack = (unsigned long*)context->previous_esp;
214 }
215}
216
217#endif /* i386 */
218
3d4bc8be 219/** Print stack dump.
655ee282
MH
220 * Prints a stack dump to the print buffer.
221 * @param verbose Verbosity
222 * @param levels Number of levels to trace.
223 * @todo Implement verbosity and levels parameters.
224 * @bug levels parameter is not functional
3d4bc8be
MH
225 */
226
43614f5d 227void _stp_stack_jprint (int verbose, int levels)
e32551b1
MH
228{
229 unsigned long stack;
3d4bc8be 230 __stp_stack_print (&stack, verbose, levels);
e32551b1
MH
231}
232
43614f5d
MH
233void _stp_stack_print (struct pt_regs *regs, int verbose, int levels)
234{
235 if (verbose) {
236 _stp_printf ("trace for %d (%s)\n", current->pid, current->comm);
237 _stp_symbol_print (regs->rip);
238 _stp_print ("\n");
239 } else
240 _stp_printf ("0x%lx ", regs->rip);
241
242 __stp_stack_print ((unsigned long *)regs->rsp, verbose, levels);
243}
244
655ee282
MH
245/** Writes stack dump to a String
246 *
247 * @param str String
248 * @param verbose Verbosity
249 * @param levels Number of levels to trace.
250 * @returns Same String as was input.
251 * @todo Implement verbosity and levels parameters.
252 * @bug levels parameter is not functional
253 */
254
3d4bc8be 255String _stp_stack_sprint (String str, int verbose, int levels)
e32551b1
MH
256{
257 unsigned long stack;
3d4bc8be 258 __stp_stack_sprint (str, &stack, verbose, levels);
3d4bc8be 259 return str;
e32551b1
MH
260}
261
262/** @} */
263#endif /* _STACK_C_ */
This page took 0.048522 seconds and 5 git commands to generate.