]> sourceware.org Git - systemtap.git/blob - runtime/stack.c
Pass task from tapset, through stack and unwind functions for lookup.
[systemtap.git] / runtime / stack.c
1 /* -*- linux-c -*-
2 * Stack tracing functions
3 * Copyright (C) 2005-2009 Red Hat Inc.
4 * Copyright (C) 2005 Intel Corporation.
5 *
6 * This file is part of systemtap, and is free software. You can
7 * redistribute it and/or modify it under the terms of the GNU General
8 * Public License (GPL); either version 2, or (at your option) any
9 * later version.
10 */
11
12 #ifndef _STACK_C_
13 #define _STACK_C_
14
15 /** @file stack.c
16 * @brief Stack Tracing Functions
17 */
18
19 /** @addtogroup stack Stack Tracing Functions
20 *
21 * @{
22 */
23
24 #include "sym.c"
25 #include "regs.h"
26 #include "unwind.c"
27
28 #define MAXBACKTRACE 20
29
30 #if defined(STAPCONF_KERNEL_STACKTRACE)
31 #include <linux/stacktrace.h>
32 #include <asm/stacktrace.h>
33 #endif
34
35 static void _stp_stack_print_fallback(unsigned long, int, int);
36
37 #if defined (__x86_64__)
38 #include "stack-x86_64.c"
39 #elif defined (__ia64__)
40 #include "stack-ia64.c"
41 #elif defined (__i386__)
42 #include "stack-i386.c"
43 #elif defined (__powerpc64__)
44 #include "stack-ppc64.c"
45 #elif defined (__arm__)
46 #include "stack-arm.c"
47 #elif defined (__s390__) || defined (__s390x__)
48 #include "stack-s390.c"
49 #else
50 #error "Unsupported architecture"
51 #endif
52
53 #if defined(STAPCONF_KERNEL_STACKTRACE)
54
55 struct print_stack_data
56 {
57 int verbose;
58 int max_level;
59 int level;
60 };
61
62 static void print_stack_warning(void *data, char *msg)
63 {
64 }
65
66 static void
67 print_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
68 {
69 }
70
71 static int print_stack_stack(void *data, char *name)
72 {
73 return -1;
74 }
75
76 static void print_stack_address(void *data, unsigned long addr, int reliable)
77 {
78 struct print_stack_data *sdata = data;
79 if (sdata->level++ < sdata->max_level)
80 _stp_func_print(addr, sdata->verbose, 0, NULL);
81 }
82
83 static const struct stacktrace_ops print_stack_ops = {
84 .warning = print_stack_warning,
85 .warning_symbol = print_stack_warning_symbol,
86 .stack = print_stack_stack,
87 .address = print_stack_address,
88 };
89
90 static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels)
91 {
92 struct print_stack_data print_data;
93 print_data.verbose = verbose;
94 print_data.max_level = levels;
95 print_data.level = 0;
96 dump_trace(current, NULL, (long *)stack, 0, &print_stack_ops,
97 &print_data);
98 }
99 #endif
100
101 // Without KPROBES very little works atm.
102 // But this file is unconditionally imported, while these two functions are only
103 // used through context-unwind.stp.
104 #if defined (CONFIG_KPROBES)
105
106 /** Prints the stack backtrace
107 * @param regs A pointer to the struct pt_regs.
108 */
109
110 static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
111 {
112 if (verbose) {
113 /* print the current address */
114 if (pi) {
115 _stp_print("Returning from: ");
116 _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi));
117 _stp_print("\nReturning to : ");
118 _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
119 } else {
120 _stp_print_char(' ');
121 _stp_symbol_print(REG_IP(regs));
122 }
123 _stp_print_char('\n');
124 } else if (pi)
125 _stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
126 else
127 _stp_printf("%p ", (int64_t) REG_IP(regs));
128
129 __stp_stack_print(regs, verbose, levels, tsk);
130 }
131
132 /** Writes stack backtrace to a string
133 *
134 * @param str string
135 * @param regs A pointer to the struct pt_regs.
136 * @returns void
137 */
138 static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
139 {
140 /* To get a string, we use a simple trick. First flush the print buffer, */
141 /* then call _stp_stack_print, then copy the result into the output string */
142 /* and clear the print buffer. */
143 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
144 _stp_print_flush();
145 _stp_stack_print(regs, verbose, pi, levels, tsk);
146 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
147 pb->len = 0;
148 }
149
150 #endif /* CONFIG_KPROBES */
151
152 /** Prints the user stack backtrace
153 * @param str string
154 * @returns Same string as was input with trace info appended,
155 * @note Currently limited to a depth of two. Works from jprobes and kprobes.
156 */
157 #if 0
158 static void _stp_ustack_print(char *str)
159 {
160 struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
161 _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
162 if (REG_SP(nregs))
163 _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
164 }
165 #endif /* 0 */
166
167 /** @} */
168
169 void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
170 {
171 #if defined(STAPCONF_KERNEL_STACKTRACE)
172 int i;
173 unsigned long backtrace[MAXBACKTRACE];
174 struct stack_trace trace;
175 int maxLevels = min(levels, MAXBACKTRACE);
176 memset(&trace, 0, sizeof(trace));
177 trace.entries = &backtrace[0];
178 trace.max_entries = maxLevels;
179 trace.skip = 0;
180 save_stack_trace_tsk(tsk, &trace);
181 for (i = 0; i < maxLevels; ++i) {
182 if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
183 break;
184 _stp_printf("%lx ", backtrace[i]);
185 }
186 #endif
187 }
188
189 /** Writes a task stack backtrace to a string
190 *
191 * @param str string
192 * @param tsk A pointer to the task_struct
193 * @returns void
194 */
195 void _stp_stack_snprint_tsk(char *str, int size, struct task_struct *tsk, int verbose, int levels)
196 {
197 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
198 _stp_print_flush();
199 _stp_stack_print_tsk(tsk, verbose, levels);
200 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
201 pb->len = 0;
202 }
203 #endif /* _STACK_C_ */
This page took 0.046493 seconds and 6 git commands to generate.