Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 Luca Clementi <luca.clementi@gmail.com> |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 3 | * Copyright (c) 2013-2018 The strace developers. |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in the |
| 12 | * documentation and/or other materials provided with the distribution. |
| 13 | * 3. The name of the author may not be used to endorse or promote products |
| 14 | * derived from this software without specific prior written permission. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #include "defs.h" |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 29 | #include "unwind.h" |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 30 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 31 | #ifdef USE_DEMANGLE |
| 32 | # if defined HAVE_DEMANGLE_H |
| 33 | # include <demangle.h> |
| 34 | # elif defined HAVE_LIBIBERTY_DEMANGLE_H |
| 35 | # include <libiberty/demangle.h> |
| 36 | # endif |
| 37 | #endif |
| 38 | |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 39 | /* |
| 40 | * Type used in stacktrace capturing |
| 41 | */ |
| 42 | struct call_t { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 43 | struct call_t *next; |
| 44 | char *output_line; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 45 | }; |
| 46 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 47 | struct unwind_queue_t { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 48 | struct call_t *tail; |
| 49 | struct call_t *head; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 50 | }; |
Masatake YAMATO | 9bc6561 | 2014-04-16 15:33:07 +0900 | [diff] [blame] | 51 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 52 | static void queue_print(struct unwind_queue_t *queue); |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 53 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 54 | static const char asprintf_error_str[] = "???"; |
| 55 | |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 56 | void |
Masatake YAMATO | 6141392 | 2014-04-16 15:33:02 +0900 | [diff] [blame] | 57 | unwind_init(void) |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 58 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 59 | if (unwinder.init) |
| 60 | unwinder.init(); |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | void |
Masatake YAMATO | 6141392 | 2014-04-16 15:33:02 +0900 | [diff] [blame] | 64 | unwind_tcb_init(struct tcb *tcp) |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 65 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 66 | if (tcp->unwind_queue) |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 67 | return; |
| 68 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 69 | tcp->unwind_queue = xmalloc(sizeof(*tcp->unwind_queue)); |
| 70 | tcp->unwind_queue->head = NULL; |
| 71 | tcp->unwind_queue->tail = NULL; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 72 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 73 | tcp->unwind_ctx = unwinder.tcb_init(tcp); |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | void |
Masatake YAMATO | 6141392 | 2014-04-16 15:33:02 +0900 | [diff] [blame] | 77 | unwind_tcb_fin(struct tcb *tcp) |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 78 | { |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 79 | if (!tcp->unwind_queue) |
| 80 | return; |
| 81 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 82 | queue_print(tcp->unwind_queue); |
| 83 | free(tcp->unwind_queue); |
| 84 | tcp->unwind_queue = NULL; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 85 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 86 | unwinder.tcb_fin(tcp); |
| 87 | tcp->unwind_ctx = NULL; |
Luca Clementi | 327064b | 2013-07-23 00:11:35 -0700 | [diff] [blame] | 88 | } |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 89 | |
| 90 | /* |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 91 | * printing an entry in stack to stream or buffer |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 92 | */ |
| 93 | /* |
| 94 | * we want to keep the format used by backtrace_symbols from the glibc |
| 95 | * |
| 96 | * ./a.out() [0x40063d] |
| 97 | * ./a.out() [0x4006bb] |
| 98 | * ./a.out() [0x4006c6] |
| 99 | * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d] |
| 100 | * ./a.out() [0x400569] |
| 101 | */ |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 102 | #define STACK_ENTRY_SYMBOL_FMT(SYM) \ |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 103 | " > %s(%s+0x%lx) [0x%lx]\n", \ |
| 104 | binary_filename, \ |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 105 | (SYM), \ |
Dmitry V. Levin | 6555711 | 2014-06-05 21:44:40 +0000 | [diff] [blame] | 106 | (unsigned long) function_offset, \ |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 107 | true_offset |
| 108 | #define STACK_ENTRY_NOSYMBOL_FMT \ |
| 109 | " > %s() [0x%lx]\n", \ |
| 110 | binary_filename, true_offset |
| 111 | #define STACK_ENTRY_BUG_FMT \ |
| 112 | " > BUG IN %s\n" |
| 113 | #define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \ |
| 114 | " > %s [0x%lx]\n", error, true_offset |
| 115 | #define STACK_ENTRY_ERROR_FMT \ |
| 116 | " > %s\n", error |
| 117 | |
| 118 | static void |
| 119 | print_call_cb(void *dummy, |
Dmitry V. Levin | 806539c | 2014-06-05 22:37:09 +0000 | [diff] [blame] | 120 | const char *binary_filename, |
| 121 | const char *symbol_name, |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 122 | unwind_function_offset_t function_offset, |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 123 | unsigned long true_offset) |
| 124 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 125 | if (symbol_name && (symbol_name[0] != '\0')) { |
| 126 | #ifdef USE_DEMANGLE |
| 127 | char *demangled_name = |
| 128 | cplus_demangle(symbol_name, |
| 129 | DMGL_AUTO | DMGL_PARAMS); |
| 130 | #endif |
| 131 | tprintf(STACK_ENTRY_SYMBOL_FMT( |
| 132 | #ifdef USE_DEMANGLE |
| 133 | demangled_name ? demangled_name : |
| 134 | #endif |
| 135 | symbol_name)); |
| 136 | #ifdef USE_DEMANGLE |
| 137 | free(demangled_name); |
| 138 | #endif |
| 139 | } |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 140 | else if (binary_filename) |
| 141 | tprintf(STACK_ENTRY_NOSYMBOL_FMT); |
| 142 | else |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 143 | tprintf(STACK_ENTRY_BUG_FMT, __func__); |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 144 | |
| 145 | line_ended(); |
| 146 | } |
| 147 | |
| 148 | static void |
| 149 | print_error_cb(void *dummy, |
| 150 | const char *error, |
| 151 | unsigned long true_offset) |
| 152 | { |
| 153 | if (true_offset) |
| 154 | tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT); |
| 155 | else |
| 156 | tprintf(STACK_ENTRY_ERROR_FMT); |
| 157 | |
| 158 | line_ended(); |
| 159 | } |
| 160 | |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 161 | static char * |
Dmitry V. Levin | 806539c | 2014-06-05 22:37:09 +0000 | [diff] [blame] | 162 | sprint_call_or_error(const char *binary_filename, |
| 163 | const char *symbol_name, |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 164 | unwind_function_offset_t function_offset, |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 165 | unsigned long true_offset, |
| 166 | const char *error) |
| 167 | { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 168 | char *output_line = NULL; |
| 169 | int n; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 170 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 171 | if (symbol_name) { |
| 172 | #ifdef USE_DEMANGLE |
| 173 | char *demangled_name = |
| 174 | cplus_demangle(symbol_name, |
| 175 | DMGL_AUTO | DMGL_PARAMS); |
| 176 | #endif |
| 177 | n = asprintf(&output_line, |
| 178 | STACK_ENTRY_SYMBOL_FMT( |
| 179 | #ifdef USE_DEMANGLE |
| 180 | demangled_name ? demangled_name : |
| 181 | #endif |
| 182 | symbol_name)); |
| 183 | #ifdef USE_DEMANGLE |
| 184 | free(demangled_name); |
| 185 | #endif |
| 186 | } |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 187 | else if (binary_filename) |
| 188 | n = asprintf(&output_line, STACK_ENTRY_NOSYMBOL_FMT); |
| 189 | else if (error) |
| 190 | n = true_offset |
| 191 | ? asprintf(&output_line, STACK_ENTRY_ERROR_WITH_OFFSET_FMT) |
| 192 | : asprintf(&output_line, STACK_ENTRY_ERROR_FMT); |
| 193 | else |
| 194 | n = asprintf(&output_line, STACK_ENTRY_BUG_FMT, __func__); |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 195 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 196 | if (n < 0) { |
| 197 | perror_func_msg("asprintf"); |
| 198 | output_line = (char *) asprintf_error_str; |
| 199 | } |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 200 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 201 | return output_line; |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | /* |
| 205 | * queue manipulators |
| 206 | */ |
| 207 | static void |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 208 | queue_put(struct unwind_queue_t *queue, |
Dmitry V. Levin | 806539c | 2014-06-05 22:37:09 +0000 | [diff] [blame] | 209 | const char *binary_filename, |
| 210 | const char *symbol_name, |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 211 | unwind_function_offset_t function_offset, |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 212 | unsigned long true_offset, |
| 213 | const char *error) |
| 214 | { |
| 215 | struct call_t *call; |
| 216 | |
Dmitry V. Levin | 3e9d71f | 2015-05-25 20:41:02 +0000 | [diff] [blame] | 217 | call = xmalloc(sizeof(*call)); |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 218 | call->output_line = sprint_call_or_error(binary_filename, |
| 219 | symbol_name, |
Dmitry V. Levin | 6555711 | 2014-06-05 21:44:40 +0000 | [diff] [blame] | 220 | function_offset, |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 221 | true_offset, |
| 222 | error); |
| 223 | call->next = NULL; |
| 224 | |
| 225 | if (!queue->head) { |
| 226 | queue->head = call; |
| 227 | queue->tail = call; |
| 228 | } else { |
| 229 | queue->tail->next = call; |
| 230 | queue->tail = call; |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | static void |
| 235 | queue_put_call(void *queue, |
Dmitry V. Levin | 806539c | 2014-06-05 22:37:09 +0000 | [diff] [blame] | 236 | const char *binary_filename, |
| 237 | const char *symbol_name, |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 238 | unwind_function_offset_t function_offset, |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 239 | unsigned long true_offset) |
| 240 | { |
| 241 | queue_put(queue, |
| 242 | binary_filename, |
| 243 | symbol_name, |
Dmitry V. Levin | 6555711 | 2014-06-05 21:44:40 +0000 | [diff] [blame] | 244 | function_offset, |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 245 | true_offset, |
| 246 | NULL); |
| 247 | } |
| 248 | |
| 249 | static void |
| 250 | queue_put_error(void *queue, |
| 251 | const char *error, |
Dmitry V. Levin | e411397 | 2014-06-05 14:37:04 +0000 | [diff] [blame] | 252 | unsigned long ip) |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 253 | { |
| 254 | queue_put(queue, NULL, NULL, 0, ip, error); |
| 255 | } |
| 256 | |
| 257 | static void |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 258 | queue_print(struct unwind_queue_t *queue) |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 259 | { |
| 260 | struct call_t *call, *tmp; |
| 261 | |
| 262 | queue->tail = NULL; |
| 263 | call = queue->head; |
| 264 | queue->head = NULL; |
| 265 | while (call) { |
| 266 | tmp = call; |
| 267 | call = call->next; |
| 268 | |
| 269 | tprints(tmp->output_line); |
| 270 | line_ended(); |
| 271 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 272 | if (tmp->output_line != asprintf_error_str) |
| 273 | free(tmp->output_line); |
| 274 | |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 275 | tmp->output_line = NULL; |
| 276 | tmp->next = NULL; |
| 277 | free(tmp); |
| 278 | } |
| 279 | } |
| 280 | |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 281 | /* |
| 282 | * printing stack |
| 283 | */ |
| 284 | void |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 285 | unwind_tcb_print(struct tcb *tcp) |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 286 | { |
Luca Clementi | f1d7311 | 2014-06-09 22:05:38 -0700 | [diff] [blame] | 287 | #if SUPPORTED_PERSONALITIES > 1 |
| 288 | if (tcp->currpers != DEFAULT_PERSONALITY) { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 289 | /* disable stack trace */ |
Luca Clementi | f1d7311 | 2014-06-09 22:05:38 -0700 | [diff] [blame] | 290 | return; |
| 291 | } |
| 292 | #endif |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 293 | if (tcp->unwind_queue->head) { |
| 294 | debug_func_msg("head: tcp=%p, queue=%p", |
| 295 | tcp, tcp->unwind_queue->head); |
| 296 | queue_print(tcp->unwind_queue); |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 297 | } else |
| 298 | unwinder.tcb_walk(tcp, print_call_cb, print_error_cb, NULL); |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | /* |
| 302 | * capturing stack |
| 303 | */ |
| 304 | void |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 305 | unwind_tcb_capture(struct tcb *tcp) |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 306 | { |
Luca Clementi | f1d7311 | 2014-06-09 22:05:38 -0700 | [diff] [blame] | 307 | #if SUPPORTED_PERSONALITIES > 1 |
| 308 | if (tcp->currpers != DEFAULT_PERSONALITY) { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 309 | /* disable stack trace */ |
Luca Clementi | f1d7311 | 2014-06-09 22:05:38 -0700 | [diff] [blame] | 310 | return; |
| 311 | } |
| 312 | #endif |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 313 | if (tcp->unwind_queue->head) |
Masatake YAMATO | f8e39d7 | 2014-04-16 15:33:06 +0900 | [diff] [blame] | 314 | error_msg_and_die("bug: unprinted entries in queue"); |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 315 | else { |
| 316 | debug_func_msg("walk: tcp=%p, queue=%p", |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 317 | tcp, tcp->unwind_queue->head); |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 318 | unwinder.tcb_walk(tcp, queue_put_call, queue_put_error, |
| 319 | tcp->unwind_queue); |
Masatake YAMATO | 9bc6561 | 2014-04-16 15:33:07 +0900 | [diff] [blame] | 320 | } |
Masatake YAMATO | 2d534da | 2014-04-16 15:33:04 +0900 | [diff] [blame] | 321 | } |