blob: 5794801aa0a518f8760364a35cfd7eabf1258b23 [file] [log] [blame]
Luca Clementi327064b2013-07-23 00:11:35 -07001/*
2 * Copyright (c) 2013 Luca Clementi <luca.clementi@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "defs.h"
28#include <limits.h>
29#include <libunwind-ptrace.h>
30
Masatake YAMATO4e121e52014-04-16 15:33:05 +090031#define DPRINTF(F, A, ...) if (debug_flag) fprintf(stderr, " [unwind(" A ")] " F "\n", __VA_ARGS__)
32
Luca Clementi327064b2013-07-23 00:11:35 -070033/*
34 * Кeep a sorted array of cache entries,
35 * so that we can binary search through it.
36 */
37struct mmap_cache_t {
38 /**
39 * example entry:
40 * 7fabbb09b000-7fabbb09f000 r--p 00179000 fc:00 1180246 /lib/libc-2.11.1.so
41 *
42 * start_addr is 0x7fabbb09b000
43 * end_addr is 0x7fabbb09f000
44 * mmap_offset is 0x179000
45 * binary_filename is "/lib/libc-2.11.1.so"
46 */
47 unsigned long start_addr;
48 unsigned long end_addr;
49 unsigned long mmap_offset;
50 char* binary_filename;
51};
52
Masatake YAMATO2d534da2014-04-16 15:33:04 +090053/*
54 * Type used in stacktrace walker
55 */
56typedef void (*call_action_fn)(void *data,
57 char *binary_filename,
58 char *symbol_name,
59 unw_word_t function_off_set,
60 unsigned long true_offset);
61typedef void (*error_action_fn)(void *data,
62 const char *error,
63 unsigned long true_offset);
64
Masatake YAMATOf8e39d72014-04-16 15:33:06 +090065/*
66 * Type used in stacktrace capturing
67 */
68struct call_t {
69 struct call_t* next;
70 char *output_line;
71};
72
73struct queue_t {
74 struct call_t *tail;
75 struct call_t *head;
76};
77static void queue_print(struct queue_t *queue);
Masatake YAMATO2d534da2014-04-16 15:33:04 +090078
Luca Clementi327064b2013-07-23 00:11:35 -070079static unw_addr_space_t libunwind_as;
80
81void
Masatake YAMATO61413922014-04-16 15:33:02 +090082unwind_init(void)
Luca Clementi327064b2013-07-23 00:11:35 -070083{
84 libunwind_as = unw_create_addr_space(&_UPT_accessors, 0);
85 if (!libunwind_as)
86 error_msg_and_die("failed to create address space for stack tracing");
87}
88
89void
Masatake YAMATO61413922014-04-16 15:33:02 +090090unwind_tcb_init(struct tcb *tcp)
Luca Clementi327064b2013-07-23 00:11:35 -070091{
92 tcp->libunwind_ui = _UPT_create(tcp->pid);
93 if (!tcp->libunwind_ui)
94 die_out_of_memory();
Masatake YAMATOf8e39d72014-04-16 15:33:06 +090095
96 tcp->queue = malloc(sizeof(*tcp->queue));
97 if (!tcp->queue)
98 die_out_of_memory();
99 tcp->queue->head = NULL;
100 tcp->queue->tail = NULL;
Luca Clementi327064b2013-07-23 00:11:35 -0700101}
102
103void
Masatake YAMATO61413922014-04-16 15:33:02 +0900104unwind_tcb_fin(struct tcb *tcp)
Luca Clementi327064b2013-07-23 00:11:35 -0700105{
Masatake YAMATOf8e39d72014-04-16 15:33:06 +0900106 queue_print(tcp->queue);
107 free(tcp->queue);
108 tcp->queue = NULL;
109
Masatake YAMATO61413922014-04-16 15:33:02 +0900110 unwind_cache_invalidate(tcp);
Masatake YAMATOf8e39d72014-04-16 15:33:06 +0900111
Luca Clementi327064b2013-07-23 00:11:35 -0700112 _UPT_destroy(tcp->libunwind_ui);
113 tcp->libunwind_ui = NULL;
114}
115
116/*
117 * caching of /proc/ID/maps for each process to speed up stack tracing
118 *
119 * The cache must be refreshed after some syscall: mmap, mprotect, munmap, execve
120 */
Masatake YAMATOb65042f2014-04-16 15:33:00 +0900121static void
Luca Clementi327064b2013-07-23 00:11:35 -0700122alloc_mmap_cache(struct tcb* tcp)
123{
124 unsigned long start_addr, end_addr, mmap_offset;
125 char filename[sizeof ("/proc/0123456789/maps")];
126 char buffer[PATH_MAX + 80];
127 char binary_path[PATH_MAX];
128 struct mmap_cache_t *cur_entry, *prev_entry;
129 /* start with a small dynamically-allocated array and then expand it */
130 size_t cur_array_size = 10;
131 struct mmap_cache_t *cache_head;
132 FILE *fp;
133
134 sprintf(filename, "/proc/%d/maps", tcp->pid);
135 fp = fopen(filename, "r");
136 if (!fp) {
137 perror_msg("fopen: %s", filename);
138 return;
139 }
140
141 cache_head = calloc(cur_array_size, sizeof(*cache_head));
142 if (!cache_head)
143 die_out_of_memory();
144
145 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
146 binary_path[0] = '\0'; // 'reset' it just to be paranoid
147
148 sscanf(buffer, "%lx-%lx %*c%*c%*c%*c %lx %*x:%*x %*d %[^\n]",
149 &start_addr, &end_addr, &mmap_offset, binary_path);
150
151 /* ignore special 'fake files' like "[vdso]", "[heap]", "[stack]", */
152 if (binary_path[0] == '[') {
153 continue;
154 }
155
156 if (binary_path[0] == '\0') {
157 continue;
158 }
159
160 if (end_addr < start_addr)
161 perror_msg_and_die("%s: unrecognized maps file format",
162 filename);
163
164 cur_entry = &cache_head[tcp->mmap_cache_size];
165 cur_entry->start_addr = start_addr;
166 cur_entry->end_addr = end_addr;
167 cur_entry->mmap_offset = mmap_offset;
168 cur_entry->binary_filename = strdup(binary_path);
169
170 /*
171 * sanity check to make sure that we're storing
172 * non-overlapping regions in ascending order
173 */
174 if (tcp->mmap_cache_size > 0) {
175 prev_entry = &cache_head[tcp->mmap_cache_size - 1];
176 if (prev_entry->start_addr >= cur_entry->start_addr)
177 perror_msg_and_die("Overlaying memory region in %s",
178 filename);
179 if (prev_entry->end_addr > cur_entry->start_addr)
180 perror_msg_and_die("Overlaying memory region in %s",
181 filename);
182 }
183 tcp->mmap_cache_size++;
184
185 /* resize doubling its size */
186 if (tcp->mmap_cache_size >= cur_array_size) {
187 cur_array_size *= 2;
188 cache_head = realloc(cache_head, cur_array_size * sizeof(*cache_head));
189 if (!cache_head)
190 die_out_of_memory();
191 }
192 }
193 fclose(fp);
194 tcp->mmap_cache = cache_head;
195}
196
197/* deleting the cache */
198void
Masatake YAMATO61413922014-04-16 15:33:02 +0900199unwind_cache_invalidate(struct tcb* tcp)
Luca Clementi327064b2013-07-23 00:11:35 -0700200{
201 unsigned int i;
202 for (i = 0; i < tcp->mmap_cache_size; i++) {
203 free(tcp->mmap_cache[i].binary_filename);
204 tcp->mmap_cache[i].binary_filename = NULL;
205 }
206 free(tcp->mmap_cache);
207 tcp->mmap_cache = NULL;
208 tcp->mmap_cache_size = 0;
209}
210
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900211/*
212 * walking the stack
213 */
214static void
215stacktrace_walk(struct tcb *tcp,
216 call_action_fn call_action,
217 error_action_fn error_action,
218 void *data)
Luca Clementi327064b2013-07-23 00:11:35 -0700219{
220 unw_word_t ip;
221 unw_cursor_t cursor;
222 unw_word_t function_off_set;
223 int stack_depth = 0, ret_val;
224 /* these are used for the binary search through the mmap_chace */
225 unsigned int lower, upper, mid;
226 size_t symbol_name_size = 40;
227 char * symbol_name;
228 struct mmap_cache_t* cur_mmap_cache;
229 unsigned long true_offset;
230
231 if (!tcp->mmap_cache)
232 alloc_mmap_cache(tcp);
233 if (!tcp->mmap_cache || !tcp->mmap_cache_size)
234 return;
235
236 symbol_name = malloc(symbol_name_size);
237 if (!symbol_name)
238 die_out_of_memory();
239
240 if (unw_init_remote(&cursor, libunwind_as, tcp->libunwind_ui) < 0)
241 perror_msg_and_die("Can't initiate libunwind");
242
243 do {
244 /* looping on the stack frame */
245 if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0) {
246 perror_msg("Can't walk the stack of process %d", tcp->pid);
247 break;
248 }
249
250 lower = 0;
251 upper = tcp->mmap_cache_size - 1;
252
253 while (lower <= upper) {
254 /* find the mmap_cache and print the stack frame */
255 mid = (upper + lower) / 2;
256 cur_mmap_cache = &tcp->mmap_cache[mid];
257
258 if (ip >= cur_mmap_cache->start_addr &&
259 ip < cur_mmap_cache->end_addr) {
260 for (;;) {
261 symbol_name[0] = '\0';
262 ret_val = unw_get_proc_name(&cursor, symbol_name,
263 symbol_name_size, &function_off_set);
264 if (ret_val != -UNW_ENOMEM)
265 break;
266 symbol_name_size *= 2;
267 symbol_name = realloc(symbol_name, symbol_name_size);
268 if (!symbol_name)
269 die_out_of_memory();
270 }
271
272 true_offset = ip - cur_mmap_cache->start_addr +
273 cur_mmap_cache->mmap_offset;
274 if (symbol_name[0]) {
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900275 call_action(data,
276 cur_mmap_cache->binary_filename,
277 symbol_name,
278 function_off_set,
279 true_offset);
Luca Clementi327064b2013-07-23 00:11:35 -0700280 } else {
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900281 call_action(data,
282 cur_mmap_cache->binary_filename,
283 symbol_name,
284 0,
285 true_offset);
Luca Clementi327064b2013-07-23 00:11:35 -0700286 }
Luca Clementi327064b2013-07-23 00:11:35 -0700287 break; /* stack frame printed */
288 }
289 else if (mid == 0) {
290 /*
291 * there is a bug in libunwind >= 1.0
292 * after a set_tid_address syscall
293 * unw_get_reg returns IP == 0
294 */
295 if(ip)
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900296 error_action(data,
297 "backtracing_error", 0);
Luca Clementi327064b2013-07-23 00:11:35 -0700298 goto ret;
299 }
300 else if (ip < cur_mmap_cache->start_addr)
Masatake YAMATOb4a2de82014-04-16 15:32:59 +0900301 upper = mid;
Luca Clementi327064b2013-07-23 00:11:35 -0700302 else
303 lower = mid + 1;
304
305 }
306 if (lower > upper) {
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900307 error_action(data,
308 "backtracing_error", ip);
Luca Clementi327064b2013-07-23 00:11:35 -0700309 goto ret;
310 }
311
312 ret_val = unw_step(&cursor);
313
314 if (++stack_depth > 255) {
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900315 error_action(data,
316 "too many stack frames", 0);
Luca Clementi327064b2013-07-23 00:11:35 -0700317 break;
318 }
319 } while (ret_val > 0);
320ret:
321 free(symbol_name);
322}
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900323
324/*
Masatake YAMATOf8e39d72014-04-16 15:33:06 +0900325 * printing an entry in stack to stream or buffer
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900326 */
327/*
328 * we want to keep the format used by backtrace_symbols from the glibc
329 *
330 * ./a.out() [0x40063d]
331 * ./a.out() [0x4006bb]
332 * ./a.out() [0x4006c6]
333 * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d]
334 * ./a.out() [0x400569]
335 */
336#define STACK_ENTRY_SYMBOL_FMT \
337 " > %s(%s+0x%lx) [0x%lx]\n", \
338 binary_filename, \
339 symbol_name, \
340 function_off_set, \
341 true_offset
342#define STACK_ENTRY_NOSYMBOL_FMT \
343 " > %s() [0x%lx]\n", \
344 binary_filename, true_offset
345#define STACK_ENTRY_BUG_FMT \
346 " > BUG IN %s\n"
347#define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \
348 " > %s [0x%lx]\n", error, true_offset
349#define STACK_ENTRY_ERROR_FMT \
350 " > %s\n", error
351
352static void
353print_call_cb(void *dummy,
354 char *binary_filename,
355 char *symbol_name,
356 unw_word_t function_off_set,
357 unsigned long true_offset)
358{
359 if (symbol_name)
360 tprintf(STACK_ENTRY_SYMBOL_FMT);
361 else if (binary_filename)
362 tprintf(STACK_ENTRY_NOSYMBOL_FMT);
363 else
364 tprintf(STACK_ENTRY_BUG_FMT, __FUNCTION__);
365
366 line_ended();
367}
368
369static void
370print_error_cb(void *dummy,
371 const char *error,
372 unsigned long true_offset)
373{
374 if (true_offset)
375 tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT);
376 else
377 tprintf(STACK_ENTRY_ERROR_FMT);
378
379 line_ended();
380}
381
Masatake YAMATOf8e39d72014-04-16 15:33:06 +0900382static char *
383sprint_call_or_error(char *binary_filename,
384 char *symbol_name,
385 unw_word_t function_off_set,
386 unsigned long true_offset,
387 const char *error)
388{
389 char *output_line = NULL;
390 int n;
391
392 if (symbol_name)
393 n = asprintf(&output_line, STACK_ENTRY_SYMBOL_FMT);
394 else if (binary_filename)
395 n = asprintf(&output_line, STACK_ENTRY_NOSYMBOL_FMT);
396 else if (error)
397 n = true_offset
398 ? asprintf(&output_line, STACK_ENTRY_ERROR_WITH_OFFSET_FMT)
399 : asprintf(&output_line, STACK_ENTRY_ERROR_FMT);
400 else
401 n = asprintf(&output_line, STACK_ENTRY_BUG_FMT, __FUNCTION__);
402
403 if (n < 0)
404 error_msg_and_die("error in asprintf");
405
406 return output_line;
407}
408
409/*
410 * queue manipulators
411 */
412static void
413queue_put(struct queue_t *queue,
414 char *binary_filename,
415 char *symbol_name,
416 unw_word_t function_off_set,
417 unsigned long true_offset,
418 const char *error)
419{
420 struct call_t *call;
421
422 call = malloc(sizeof(*call));
423 if (!call)
424 die_out_of_memory();
425
426 call->output_line = sprint_call_or_error(binary_filename,
427 symbol_name,
428 function_off_set,
429 true_offset,
430 error);
431 call->next = NULL;
432
433 if (!queue->head) {
434 queue->head = call;
435 queue->tail = call;
436 } else {
437 queue->tail->next = call;
438 queue->tail = call;
439 }
440}
441
442static void
443queue_put_call(void *queue,
444 char *binary_filename,
445 char *symbol_name,
446 unw_word_t function_off_set,
447 unsigned long true_offset)
448{
449 queue_put(queue,
450 binary_filename,
451 symbol_name,
452 function_off_set,
453 true_offset,
454 NULL);
455}
456
457static void
458queue_put_error(void *queue,
459 const char *error,
460 unw_word_t ip)
461{
462 queue_put(queue, NULL, NULL, 0, ip, error);
463}
464
465static void
466queue_print(struct queue_t *queue)
467{
468 struct call_t *call, *tmp;
469
470 queue->tail = NULL;
471 call = queue->head;
472 queue->head = NULL;
473 while (call) {
474 tmp = call;
475 call = call->next;
476
477 tprints(tmp->output_line);
478 line_ended();
479
480 free(tmp->output_line);
481 tmp->output_line = NULL;
482 tmp->next = NULL;
483 free(tmp);
484 }
485}
486
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900487/*
488 * printing stack
489 */
490void
491unwind_print_stacktrace(struct tcb* tcp)
492{
Masatake YAMATOf8e39d72014-04-16 15:33:06 +0900493 if (tcp->queue->head) {
494 DPRINTF("tcp=%p, queue=%p", "queueprint", tcp, tcp->queue->head);
495 queue_print(tcp->queue);
496 }
497 else {
498 DPRINTF("tcp=%p, queue=%p", "stackprint", tcp, tcp->queue->head);
499 stacktrace_walk(tcp, print_call_cb, print_error_cb, NULL);
500 }
501}
502
503/*
504 * capturing stack
505 */
506void
507unwind_capture_stacktrace(struct tcb *tcp)
508{
509 if (tcp->queue->head)
510 error_msg_and_die("bug: unprinted entries in queue");
511
512 stacktrace_walk(tcp, queue_put_call, queue_put_error,
513 tcp->queue);
514 DPRINTF("tcp=%p, queue=%p", "captured", tcp, tcp->queue->head);
Masatake YAMATO2d534da2014-04-16 15:33:04 +0900515}