]> sourceware.org Git - systemtap.git/blob - runtime/stack.c
Merge commit 'origin/master'
[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 (__powerpc__)
44 #include "stack-ppc.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, struct uretprobe_instance *ri)
111 {
112 if (verbose) {
113 /* print the current address */
114 if (pi) {
115 if (verbose == SYM_VERBOSE_FULL) {
116 _stp_print("Returning from: ");
117 _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi));
118 _stp_print("\nReturning to : ");
119 }
120 _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
121 } else if (ri) {
122 if (verbose == SYM_VERBOSE_FULL) {
123 _stp_print("Returning from: ");
124 _stp_usymbol_print(ri->rp->u.vaddr, tsk);
125 _stp_print("\nReturning to : ");
126 _stp_usymbol_print(ri->ret_addr, tsk);
127 } else
128 _stp_func_print(ri->ret_addr, verbose, 0, tsk);
129 } else {
130 _stp_print_char(' ');
131 if (tsk)
132 _stp_usymbol_print(REG_IP(regs), tsk);
133 else
134 _stp_symbol_print(REG_IP(regs));
135 }
136 if (verbose != SYM_VERBOSE_BRIEF)
137 _stp_print_char('\n');
138 } else if (pi)
139 _stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
140 else
141 _stp_printf("%p ", (int64_t) REG_IP(regs));
142
143 __stp_stack_print(regs, verbose, levels, tsk, ri);
144 }
145
146 /** Writes stack backtrace to a string
147 *
148 * @param str string
149 * @param regs A pointer to the struct pt_regs.
150 * @returns void
151 */
152 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, struct uretprobe_instance *ri)
153 {
154 /* To get a string, we use a simple trick. First flush the print buffer, */
155 /* then call _stp_stack_print, then copy the result into the output string */
156 /* and clear the print buffer. */
157 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
158 _stp_print_flush();
159 _stp_stack_print(regs, verbose, pi, levels, tsk, ri);
160 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
161 pb->len = 0;
162 }
163
164 #endif /* CONFIG_KPROBES */
165
166 void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
167 {
168 #if defined(STAPCONF_KERNEL_STACKTRACE)
169 int i;
170 unsigned long backtrace[MAXBACKTRACE];
171 struct stack_trace trace;
172 int maxLevels = min(levels, MAXBACKTRACE);
173 memset(&trace, 0, sizeof(trace));
174 trace.entries = &backtrace[0];
175 trace.max_entries = maxLevels;
176 trace.skip = 0;
177 save_stack_trace_tsk(tsk, &trace);
178 for (i = 0; i < maxLevels; ++i) {
179 if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
180 break;
181 _stp_printf("%lx ", backtrace[i]);
182 }
183 #endif
184 }
185
186 /** Writes a task stack backtrace to a string
187 *
188 * @param str string
189 * @param tsk A pointer to the task_struct
190 * @returns void
191 */
192 void _stp_stack_snprint_tsk(char *str, int size, struct task_struct *tsk, int verbose, int levels)
193 {
194 _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
195 _stp_print_flush();
196 _stp_stack_print_tsk(tsk, verbose, levels);
197 strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
198 pb->len = 0;
199 }
200 #endif /* _STACK_C_ */
This page took 0.04978 seconds and 6 git commands to generate.