]> sourceware.org Git - systemtap.git/blob - runtime/stack.c
stap autoconf test for kernel stack trace support
[systemtap.git] / runtime / stack.c
1 /* -*- linux-c -*-
2 * Stack tracing functions
3 * Copyright (C) 2005-2008 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);
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 /** Prints the stack backtrace
101 * @param regs A pointer to the struct pt_regs.
102 */
103
104 static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
105 {
106 if (verbose) {
107 /* print the current address */
108 if (pi) {
109 _stp_print("Returning from: ");
110 _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi));
111 _stp_print("\nReturning to : ");
112 _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
113 } else {
114 _stp_print_char(' ');
115 _stp_symbol_print(REG_IP(regs));
116 }
117 _stp_print_char('\n');
118 } else if (pi)
119 _stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
120 else
121 _stp_printf("%p ", (int64_t) REG_IP(regs));
122
123 __stp_stack_print(regs, verbose, levels);
124 }
125
126 /** Writes stack backtrace to a string
127 *
128 * @param str string
129 * @param regs A pointer to the struct pt_regs.
130 * @returns void
131 */
132 static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
133 {
134 /* To get a string, we use a simple trick. First flush the print buffer, */
135 /* then call _stp_stack_print, then copy the result into the output string */
136 /* and clear the print buffer. */
137 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
138 _stp_print_flush();
139 _stp_stack_print(regs, verbose, pi, levels);
140 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
141 pb->len = 0;
142 }
143
144 /** Prints the user stack backtrace
145 * @param str string
146 * @returns Same string as was input with trace info appended,
147 * @note Currently limited to a depth of two. Works from jprobes and kprobes.
148 */
149 #if 0
150 static void _stp_ustack_print(char *str)
151 {
152 struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
153 _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
154 if (REG_SP(nregs))
155 _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
156 }
157 #endif /* 0 */
158
159 /** @} */
160
161 void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
162 {
163 #if defined(STAPCONF_KERNEL_STACKTRACE)
164 int i;
165 unsigned long backtrace[MAXBACKTRACE];
166 struct stack_trace trace;
167 int maxLevels = min(levels, MAXBACKTRACE);
168 memset(&trace, 0, sizeof(trace));
169 trace.entries = &backtrace[0];
170 trace.max_entries = maxLevels;
171 trace.skip = 0;
172 save_stack_trace_tsk(tsk, &trace);
173 for (i = 0; i < maxLevels; ++i) {
174 if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
175 break;
176 _stp_printf("%lx ", backtrace[i]);
177 }
178 #endif
179 }
180
181 /** Writes a task stack backtrace to a string
182 *
183 * @param str string
184 * @param tsk A pointer to the task_struct
185 * @returns void
186 */
187 void _stp_stack_snprint_tsk(char *str, int size, struct task_struct *tsk, int verbose, int levels)
188 {
189 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
190 _stp_print_flush();
191 _stp_stack_print_tsk(tsk, verbose, levels);
192 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
193 pb->len = 0;
194 }
195 #endif /* _STACK_C_ */
This page took 0.045156 seconds and 6 git commands to generate.