]>
Commit | Line | Data |
---|---|---|
fabf5ed4 MH |
1 | /* -*- linux-c -*- |
2 | * Stack tracing functions | |
1b276fc2 | 3 | * Copyright (C) 2005, 2006, 2007 Red Hat Inc. |
1c9db4fd AK |
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 | ||
fabf5ed4 | 12 | #ifndef _STACK_C_ |
e32551b1 | 13 | #define _STACK_C_ |
3d4bc8be | 14 | |
e32551b1 MH |
15 | /** @file stack.c |
16 | * @brief Stack Tracing Functions | |
17 | */ | |
18 | ||
19 | /** @addtogroup stack Stack Tracing Functions | |
abedf3db | 20 | * |
e32551b1 MH |
21 | * @{ |
22 | */ | |
23 | ||
24 | #include "sym.c" | |
abedf3db | 25 | #include "regs.h" |
fabf5ed4 | 26 | static int _stp_kta(unsigned long addr); |
a0ccc04f | 27 | |
7d678473 MH |
28 | #define MAXBACKTRACE 20 |
29 | ||
abedf3db | 30 | #if defined (__x86_64__) |
fabf5ed4 | 31 | #include "stack-x86_64.c" |
1c9db4fd | 32 | #elif defined (__ia64__) |
fabf5ed4 | 33 | #include "stack-ia64.c" |
abedf3db | 34 | #elif defined (__i386__) |
fabf5ed4 MH |
35 | #include "stack-i386.c" |
36 | #elif defined (__powerpc64__) | |
37 | #include "stack-ppc64.c" | |
24cb8c3b DW |
38 | #elif defined (__s390__) || defined (__s390x__) |
39 | #include "stack-s390.c" | |
e32551b1 | 40 | #else |
fabf5ed4 | 41 | #error "Unsupported architecture" |
e32551b1 | 42 | #endif |
e32551b1 | 43 | |
e32551b1 | 44 | |
fabf5ed4 MH |
45 | /* our copy of kernel_text_address() */ |
46 | static int _stp_kta(unsigned long addr) | |
47 | { | |
48 | static unsigned long stext, etext, sinittext, einittext; | |
49 | static int init = 0; | |
50 | ||
51 | if (init == 0) { | |
52 | init = 1; | |
53 | etext = _stp_kallsyms_lookup_name("_etext"); | |
54 | stext = _stp_kallsyms_lookup_name("_stext"); | |
55 | sinittext = _stp_kallsyms_lookup_name("_sinittext"); | |
56 | einittext = _stp_kallsyms_lookup_name("_einittext"); | |
e32551b1 | 57 | } |
e32551b1 | 58 | |
fabf5ed4 MH |
59 | if (addr >= stext && addr <= etext) |
60 | return 1; | |
3c9dd85f | 61 | |
fabf5ed4 MH |
62 | if (addr >= sinittext && addr <= einittext) |
63 | return 1; | |
3c9dd85f | 64 | |
fabf5ed4 | 65 | return 0; |
3c9dd85f | 66 | } |
e32551b1 | 67 | |
1b276fc2 | 68 | /** Prints the stack backtrace |
abedf3db | 69 | * @param regs A pointer to the struct pt_regs. |
3d4bc8be | 70 | */ |
1b276fc2 MH |
71 | |
72 | void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi) | |
e32551b1 | 73 | { |
9acc3200 | 74 | if (verbose) { |
fabf5ed4 MH |
75 | /* print the current address */ |
76 | if (pi) { | |
1b276fc2 MH |
77 | _stp_print("Returning from: "); |
78 | _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi)); | |
79 | _stp_print("\nReturning to : "); | |
80 | _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi)); | |
81 | } else { | |
82 | _stp_print_char(' '); | |
83 | _stp_symbol_print (REG_IP(regs)); | |
84 | } | |
85 | _stp_print_char('\n'); | |
9acc3200 | 86 | } else |
4f295b51 | 87 | _stp_printf ("%p ", (int64_t)REG_IP(regs)); |
1b276fc2 | 88 | __stp_stack_print (regs, verbose, 0); |
e32551b1 MH |
89 | } |
90 | ||
1b276fc2 MH |
91 | /** Writes stack backtrace to a string |
92 | * | |
93 | * @param str string | |
abedf3db | 94 | * @param regs A pointer to the struct pt_regs. |
1b276fc2 | 95 | * @returns void |
abedf3db | 96 | */ |
1b276fc2 | 97 | void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi) |
abedf3db | 98 | { |
1b276fc2 MH |
99 | /* To get a string, we use a simple trick. First flush the print buffer, */ |
100 | /* then call _stp_stack_print, then copy the result into the output string */ | |
101 | /* and clear the print buffer. */ | |
102 | _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id()); | |
103 | _stp_print_flush(); | |
104 | _stp_stack_print(regs, verbose, pi); | |
c3e51a48 | 105 | strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len); |
1b276fc2 | 106 | pb->len = 0; |
abedf3db MH |
107 | } |
108 | ||
655ee282 | 109 | |
1b276fc2 MH |
110 | /** Prints the user stack backtrace |
111 | * @param str string | |
112 | * @returns Same string as was input with trace info appended, | |
abedf3db MH |
113 | * @note Currently limited to a depth of two. Works from jprobes and kprobes. |
114 | */ | |
1b276fc2 MH |
115 | #if 0 |
116 | void _stp_ustack_print (char *str) | |
e32551b1 | 117 | { |
abedf3db | 118 | struct pt_regs *nregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1; |
4f295b51 | 119 | _stp_printf ("%p : [user]\n", (int64_t)REG_IP(nregs)); |
abedf3db | 120 | if (REG_SP(nregs)) |
4f295b51 | 121 | _stp_printf ("%p : [user]\n", (int64_t)(*(unsigned long *)REG_SP(nregs))); |
e32551b1 | 122 | } |
1b276fc2 | 123 | #endif /* 0 */ |
abedf3db | 124 | |
e32551b1 MH |
125 | /** @} */ |
126 | #endif /* _STACK_C_ */ |