From acaadca080ff956a15c5901b37baad7e8114a8c9 Mon Sep 17 00:00:00 2001 From: Yuriy Vostrikov <vostrikov@corp.mail.ru> Date: Thu, 13 Jan 2011 12:08:13 +0300 Subject: [PATCH] [core] Cleanup backtrace priniting. --- core/coro.c | 2 - core/fiber.c | 39 +++++----- core/tarantool.c | 9 +-- core/util.c | 161 +++++++++++++++++++++++++++++----------- include/fiber.h | 5 +- include/tbuf.h | 1 - include/util.h | 26 +++---- third_party/coro/coro.c | 4 - 8 files changed, 153 insertions(+), 94 deletions(-) diff --git a/core/coro.c b/core/coro.c index 2d35cbe9b2..13d2b6f58b 100644 --- a/core/coro.c +++ b/core/coro.c @@ -38,8 +38,6 @@ #define MAP_ANONYMOUS MAP_ANON #endif -extern void *main_stack_frame; - struct tarantool_coro * tarantool_coro_create(struct tarantool_coro *coro, void (*f) (void *), void *data) { diff --git a/core/fiber.c b/core/fiber.c index 8968c3e926..c0fb5e04b8 100644 --- a/core/fiber.c +++ b/core/fiber.c @@ -89,6 +89,16 @@ fiber_msg(const struct tbuf *buf) KHASH_MAP_INIT_INT(fid2fiber, void *, realloc); static khash_t(fid2fiber) *fibers_registry; +static void +update_frame_address(struct fiber *fiber) +{ +#ifdef BACKTRACE + fiber->last_frame = frame_addess(); +#else + (void)fiber; +#endif +} + void fiber_call(struct fiber *callee) { @@ -100,7 +110,7 @@ fiber_call(struct fiber *callee) fiber = callee; *sp++ = caller; - save_rbp(caller->rbp); + update_frame_address(caller); callee->csw++; coro_transfer(&caller->coro.ctx, &callee->coro.ctx); @@ -117,7 +127,7 @@ fiber_raise(struct fiber *callee, jmp_buf exc, int value) fiber = callee; *sp++ = caller; - save_rbp(caller->rbp); + update_frame_address(caller); callee->csw++; coro_save_and_longjmp(&caller->coro.ctx, exc, value); @@ -130,7 +140,7 @@ yield(void) struct fiber *caller = fiber; fiber = callee; - save_rbp(caller->rbp); + update_frame_address(caller); callee->csw++; coro_transfer(&caller->coro.ctx, &callee->coro.ctx); @@ -1051,24 +1061,11 @@ fiber_info(struct tbuf *out) tbuf_printf(out, " fd: %4i\n", fiber->fd); tbuf_printf(out, " peer: %s\n", fiber_peer_name(fiber)); tbuf_printf(out, " stack: %p\n", stack_top); - -#if defined(__x86) || defined (__amd64) || defined(__i386) - tbuf_printf(out, " exc: %p, frame: %p\n", ((void **)fiber->exc)[3], ((void **)fiber->exc)[3] + 2 * sizeof(void *)); - - void *stack_bottom = fiber->coro.stack; - struct frame *frame = fiber->rbp; - tbuf_printf(out, " backtrace:\n"); - while (stack_bottom < (void *)frame && (void *)frame < stack_top) { - tbuf_printf(out, " - { rbp: %p, frame: %p, pc: %p", - frame, (void *)frame + 2 * sizeof(void *), frame->ret); -#ifdef RESOLVE_SYMBOLS - struct fsym *s = addr2sym(frame->ret); - if (s) - tbuf_printf(out, " <%s+%i>", s->name, frame->ret - s->addr); -#endif - tbuf_printf(out, " }\n"); - frame = frame->rbp; - } + tbuf_printf(out, " exc: %p, frame: %p\n", + ((void **)fiber->exc)[3], ((void **)fiber->exc)[3] + 2 * sizeof(void *)); +#ifdef BACKTRACE + tbuf_printf(out, " backtrace:\n%s", + backtrace(fiber->last_frame, fiber->coro.stack, fiber->coro.stack_size)); #endif } } diff --git a/core/tarantool.c b/core/tarantool.c index 908562ee53..b1ad3e7153 100644 --- a/core/tarantool.c +++ b/core/tarantool.c @@ -232,12 +232,14 @@ main(int argc, char **argv) int n_accepted, n_skipped; FILE *f; - save_rbp(main_stack_frame); - master_pid = getpid(); stat_init(); palloc_init(); +#ifdef RESOLVE_SYMBOLS + load_symbols(argv[0]); +#endif + const char *short_opt = "c:pvVD"; const struct option long_opt[] = { {.name = "config", @@ -443,9 +445,6 @@ main(int argc, char **argv) atexit(remove_pid); } -#ifdef RESOLVE_SYMBOLS - load_syms(argv[0]); -#endif argv = init_set_proc_title(argc, argv); #if defined(UTILITY) diff --git a/core/util.c b/core/util.c index 9d446eaaa2..5b9017f708 100644 --- a/core/util.c +++ b/core/util.c @@ -99,49 +99,106 @@ xrealloc(void *ptr, size_t size) return ret; } -void *main_stack_frame; -#if defined(__x86) || defined (__amd64) || defined(__i386) -static void -print_trace(FILE *f) +#ifdef BACKTRACE + +/* + * we use global static buffer because it is too late to do + * any allocation when we are printing bactrace and fiber's stacks are small + */ + +static char backtrace_buf[4096 * 4]; + +/* + * note, stack unwinding code assumes that binary is compiled with frame pointers + */ + +struct frame { + struct frame *rbp; + void *ret; +}; + +char * +backtrace(void *frame_, void *stack, size_t stack_size) { - void *dummy = NULL; - struct frame *frame; - save_rbp(dummy); - frame = dummy; - - void *stack_top = fiber->coro.stack + fiber->coro.stack_size; - void *stack_bottom = fiber->coro.stack; - if (strcmp(fiber->name, "sched") == 0) { - stack_top = main_stack_frame + 128; - stack_bottom = frame; - } - fprintf(f, "backtrace:\n"); + struct frame *frame = frame_; + void *stack_top = stack + stack_size; + void *stack_bottom = stack; + + char *p = backtrace_buf; + size_t r, len = sizeof(backtrace_buf); while (stack_bottom <= (void *)frame && (void *)frame < stack_top) { - fprintf(f, " - { frame: %p, pc: %p }\n", frame + 2 * sizeof(void *), frame->ret); + r = snprintf(p, len, " - { frame: %p, caller: %p", + (void *)frame + 2 * sizeof(void *), frame->ret); + + if (r >= len) + goto out; + p += r; + len -= r; + +#ifdef RESOLVE_SYMBOLS + struct symbol *s = addr2symbol(frame->ret); + if (s != NULL) { + r = snprintf(p, len, " <%s+%i> ", s->name, frame->ret - s->addr); + if (r >= len) + goto out; + p += r; + len -= r; + + } +#endif + r = snprintf(p, len, " }\r\n"); + if (r >= len) + goto out; + p += r; + len -= r; + +#ifdef RESOLVE_SYMBOLS + if (s != NULL && strcmp(s->name, "main") == 0) + break; + +#endif frame = frame->rbp; } + r = 0; +out: + p += MIN(len - 1, r); + *p = 0; + return backtrace_buf; } #endif void __attribute__ ((noreturn)) - assert_fail(const char *assertion, const char *file, unsigned int line, const char *function) +assert_fail(const char *assertion, const char *file, unsigned int line, const char *function) { fprintf(stderr, "%s:%i: %s: assertion %s failed.\n", file, line, function, assertion); -#if defined(__x86) || defined (__amd64) || defined(__i386) - print_trace(stderr); + +#ifdef BACKTRACE + void *frame = frame_addess(); + void *stack_top; + size_t stack_size; + + if (fiber == NULL || fiber->name == NULL || strcmp(fiber->name, "sched") == 0) { + stack_top = frame; /* we don't know where the system stack top is */ + stack_size = __libc_stack_end - frame; + } else { + stack_top = fiber->coro.stack; + stack_size = fiber->coro.stack_size; + } + + fprintf(stderr, "%s", backtrace(frame, stack_top, stack_size)); #endif close_all_xcpt(0); abort(); } #ifdef RESOLVE_SYMBOLS -struct fsym *fsyms; -size_t fsyms_count; +static struct symbol *symbols; +static size_t symbol_count; int -compare_fsym(const void *_a, const void *_b) +compare_symbol(const void *_a, const void *_b) { - const struct fsym *a = _a, *b = _b; + const struct symbol *a = _a, *b = _b; if (a->addr > b->addr) return 1; if (a->addr == b->addr) @@ -149,11 +206,11 @@ compare_fsym(const void *_a, const void *_b) return -1; } -void __attribute__((constructor)) -load_syms(const char *name) +void +load_symbols(const char *name) { long storage_needed; - asymbol **symbol_table; + asymbol **symbol_table = NULL; long number_of_symbols; bfd *h; char **matching; @@ -180,12 +237,24 @@ load_syms(const char *name) if (number_of_symbols < 0) goto out; - for (int i = 0; i < number_of_symbols; i++) + for (int i = 0; i < number_of_symbols; i++) { + struct bfd_section *section; + unsigned long int vma, size; + section = bfd_get_section(symbol_table[i]); + vma = bfd_get_section_vma(h, section); + size = bfd_get_section_size(section); + if (symbol_table[i]->flags & BSF_FUNCTION && - symbol_table[i]->value > 0) - fsyms_count++; + vma + symbol_table[i]->value > 0 && + symbol_table[i]->value < size) + symbol_count++; + } + + if (symbol_count == 0) + goto out; + j = 0; - fsyms = malloc(fsyms_count * sizeof(struct fsym)); + symbols = malloc(symbol_count * sizeof(struct symbol)); for (int i = 0; i < number_of_symbols; i++) { struct bfd_section *section; @@ -198,42 +267,48 @@ load_syms(const char *name) vma + symbol_table[i]->value > 0 && symbol_table[i]->value < size) { - fsyms[j].name = strdup(symbol_table[i]->name); - fsyms[j].addr = (void *)(uintptr_t)(vma + symbol_table[i]->value); - fsyms[j].end = (void *)(uintptr_t)(vma + size); + symbols[j].name = strdup(symbol_table[i]->name); + symbols[j].addr = (void *)(uintptr_t)(vma + symbol_table[i]->value); + symbols[j].end = (void *)(uintptr_t)(vma + size); j++; } } - qsort(fsyms, fsyms_count, sizeof(struct fsym), compare_fsym); + qsort(symbols, symbol_count, sizeof(struct symbol), compare_symbol); + + for (int j = 0; j < symbol_count - 1; j++) + symbols[j].end = MIN(symbols[j].end, symbols[j + 1].addr - 1); out: + if (symbol_count == 0) + say_warn("no symbols were loaded"); + if (symbol_table) free(symbol_table); } -struct fsym * -addr2sym(void *addr) +struct symbol * +addr2symbol(void *addr) { - uint low = 0, high = fsyms_count, middle = -1; - struct fsym *ret, key = {.addr = addr}; + int low = 0, high = symbol_count, middle = -1; + struct symbol *ret, key = {.addr = addr}; while(low < high) { middle = low + ((high - low) >> 1); - int diff = compare_fsym(fsyms + middle, &key); + int diff = compare_symbol(symbols + middle, &key); if (diff < 0) { low = middle + 1; } else if (diff > 0) { high = middle; } else { - ret = fsyms + middle; + ret = symbols + middle; goto out; } } - ret = fsyms + middle - 1; + ret = symbols + high - 1; out: - if (middle != -1 && ret->addr <= key.addr && key.addr < ret->end) + if (middle != -1 && ret->addr <= key.addr && key.addr <= ret->end) return ret; return NULL; } diff --git a/include/fiber.h b/include/fiber.h index eb68fc13db..b0af53bfa9 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -39,6 +39,7 @@ #include <tbuf.h> #include <say.h> #include <coro.h> +#include <util.h> #define FIBER_EXIT -1 @@ -54,8 +55,8 @@ struct ring { struct fiber { ev_io io; -#if CORO_ASM - void *rbp; +#ifdef BACKTRACE + void *last_frame; #endif int csw; struct tarantool_coro coro; diff --git a/include/tbuf.h b/include/tbuf.h index 729a8494dc..338ecada8b 100644 --- a/include/tbuf.h +++ b/include/tbuf.h @@ -63,7 +63,6 @@ size_t tbuf_reserve(struct tbuf *b, size_t count); void tbuf_reset(struct tbuf *b); void *tbuf_peek(struct tbuf *b, size_t count); -void tbuf_append(struct tbuf *b, const void *data, size_t len); void tbuf_append_field(struct tbuf *b, void *f); void tbuf_printf(struct tbuf *b, const char *format, ...) __attribute__ ((format(FORMAT_PRINTF, 2, 3))); diff --git a/include/util.h b/include/util.h index 8757f7a6a3..4f23a4df19 100644 --- a/include/util.h +++ b/include/util.h @@ -112,29 +112,23 @@ void *xrealloc(void *ptr, size_t size); void __gcov_flush(); -struct frame { - struct frame *rbp; - void *ret; -}; -#if __amd64 -# define save_rbp(rbp) asm("movq %%rbp, %0"::"m"(rbp)) -#elif __i386 -# define save_rbp(rbp) asm("movl %%ebp, %0"::"m"(rbp)) -#else -# define save_rbp(rbp) (void)0 -#endif +extern void *__libc_stack_end; -extern void *main_stack_frame; +#if __GNUC__ && (defined(__x86) || defined (__amd64) || defined(__i386)) +#define BACKTRACE +#define frame_addess() __builtin_frame_address(0) +char *backtrace(void *frame, void *stack, size_t stack_size); +#endif #ifdef RESOLVE_SYMBOLS -struct fsym { - void* addr; +struct symbol { + void *addr; const char *name; void *end; }; -struct fsym *addr2sym(void *addr); -void load_syms(const char *name); +struct symbol *addr2symbol(void *addr); +void load_symbols(const char *name); #endif #ifdef NDEBUG diff --git a/third_party/coro/coro.c b/third_party/coro/coro.c index 3546628c19..ff41ffd186 100644 --- a/third_party/coro/coro.c +++ b/third_party/coro/coro.c @@ -305,11 +305,7 @@ coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssiz # elif CORO_ASM - extern void * main_stack_frame; - ctx->sp = (void **)(ssize + (char *)sptr); - *--ctx->sp = (void *)main_stack_frame; - *--ctx->sp = (void *)main_stack_frame; *--ctx->sp = (void *)0xdeadbeef; /* needed for alignment only */ *--ctx->sp = (void *)coro_init; ctx->sp -= NUM_SAVED; -- GitLab