diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/Makefile | 4 | ||||
-rw-r--r-- | main/astobj2.c | 2 | ||||
-rw-r--r-- | main/logger.c | 152 | ||||
-rw-r--r-- | main/say.c | 2 | ||||
-rw-r--r-- | main/utils.c | 22 |
5 files changed, 178 insertions, 4 deletions
diff --git a/main/Makefile b/main/Makefile index af294dda6..64ad43fbb 100644 --- a/main/Makefile +++ b/main/Makefile @@ -46,6 +46,10 @@ else AST_LIBS+=$(EDITLINE_LIB) -lm endif +ifneq ($(findstring BETTER_BACKTRACES,$(MENUSELECT_CFLAGS)),) + AST_LIBS+=$(BFD_LIB) +endif + ifneq ($(findstring darwin,$(OSARCH)),) AST_LIBS+=-lresolv ASTLINK=-Xlinker -macosx_version_min -Xlinker 10.4 -Xlinker -undefined -Xlinker dynamic_lookup -force_flat_namespace diff --git a/main/astobj2.c b/main/astobj2.c index d0b438940..50886de2e 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -88,7 +88,7 @@ void ao2_bt(void) char **strings; c = backtrace(addresses, N1); - strings = backtrace_symbols(addresses,c); + strings = ast_bt_get_symbols(addresses,c); ast_verbose("backtrace returned: %d\n", c); for(i = 0; i < c; i++) { ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); diff --git a/main/logger.c b/main/logger.c index 25f252f31..23b9078b9 100644 --- a/main/logger.c +++ b/main/logger.c @@ -56,6 +56,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #ifdef HAVE_BKTR #include <execinfo.h> #define MAX_BACKTRACE_FRAMES 20 +# if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES) +# include <dlfcn.h> +# include <bfd.h> +# endif #endif #if defined(__linux__) && !defined(__NR_gettid) @@ -1222,6 +1226,150 @@ void *ast_bt_destroy(struct ast_bt *bt) return NULL; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **strings = NULL; +#if defined(BETTER_BACKTRACES) + int stackfr; + bfd *bfdobj; /* bfd.h */ + Dl_info dli; /* dlfcn.h */ + long allocsize; + asymbol **syms = NULL; /* bfd.h */ + bfd_vma offset; /* bfd.h */ + const char *lastslash; + asection *section; + const char *file, *func; + unsigned int line; + char address_str[128]; + char msg[1024]; + size_t strings_size; + size_t *eachlen; +#endif + +#if defined(BETTER_BACKTRACES) + strings_size = num_frames * sizeof(*strings); + eachlen = ast_calloc(num_frames, sizeof(*eachlen)); + + if (!(strings = ast_calloc(num_frames, sizeof(*strings)))) { + return NULL; + } + + for (stackfr = 0; stackfr < num_frames; stackfr++) { + int found = 0, symbolcount; + + msg[0] = '\0'; + + if (!dladdr(addresses[stackfr], &dli)) { + continue; + } + + if (strcmp(dli.dli_fname, "asterisk") == 0) { + char asteriskpath[256]; + if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) { + /* This will fail to find symbols */ + ast_log(LOG_DEBUG, "Failed to find asterisk binary for debug symbols.\n"); + dli.dli_fname = "asterisk"; + } + } + + lastslash = strrchr(dli.dli_fname, '/'); + if ( (bfdobj = bfd_openr(dli.dli_fname, NULL)) && + bfd_check_format(bfdobj, bfd_object) && + (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 && + (syms = ast_malloc(allocsize)) && + (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) { + + if (bfdobj->flags & DYNAMIC) { + offset = addresses[stackfr] - dli.dli_fbase; + } else { + offset = addresses[stackfr] - (void *) 0; + } + + for (section = bfdobj->sections; section; section = section->next) { + if ( !bfd_get_section_flags(bfdobj, section) & SEC_ALLOC || + section->vma > offset || + section->size + section->vma < offset) { + continue; + } + + if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) { + continue; + } + + /* Stack trace output */ + found++; + if ((lastslash = strrchr(file, '/'))) { + const char *prevslash; + for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--); + if (prevslash >= file) { + lastslash = prevslash; + } + } + if (dli.dli_saddr == NULL) { + address_str[0] = '\0'; + } else { + snprintf(address_str, sizeof(address_str), " (%p+%lX)", + dli.dli_saddr, + (unsigned long) (addresses[stackfr] - dli.dli_saddr)); + } + snprintf(msg, sizeof(msg), "%s:%u %s()%s", + lastslash ? lastslash + 1 : file, line, + S_OR(func, "???"), + address_str); + + break; /* out of section iteration */ + } + } + if (bfdobj) { + bfd_close(bfdobj); + if (syms) { + ast_free(syms); + } + } + + /* Default output, if we cannot find the information within BFD */ + if (!found) { + if (dli.dli_saddr == NULL) { + address_str[0] = '\0'; + } else { + snprintf(address_str, sizeof(address_str), " (%p+%lX)", + dli.dli_saddr, + (unsigned long) (addresses[stackfr] - dli.dli_saddr)); + } + snprintf(msg, sizeof(msg), "%s %s()%s", + lastslash ? lastslash + 1 : dli.dli_fname, + S_OR(dli.dli_sname, "<unknown>"), + address_str); + } + + if (!ast_strlen_zero(msg)) { + char **tmp; + eachlen[stackfr] = strlen(msg); + if (!(tmp = ast_realloc(strings, strings_size + eachlen[stackfr] + 1))) { + ast_free(strings); + strings = NULL; + break; /* out of stack frame iteration */ + } + strings = tmp; + strings[stackfr] = (char *) strings + strings_size; + ast_copy_string(strings[stackfr], msg, eachlen[stackfr] + 1); + strings_size += eachlen[stackfr] + 1; + } + } + + if (strings) { + /* Recalculate the offset pointers */ + strings[0] = (char *) strings + num_frames * sizeof(*strings); + for (stackfr = 1; stackfr < num_frames; stackfr++) { + strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1] + 1; + } + } +#else /* !defined(BETTER_BACKTRACES) */ + strings = backtrace_symbols(addresses, num_frames); +#endif /* defined(BETTER_BACKTRACES) */ + return strings; +} + #endif /* HAVE_BKTR */ void ast_backtrace(void) @@ -1236,7 +1384,7 @@ void ast_backtrace(void) return; } - if ((strings = backtrace_symbols(bt->addresses, bt->num_frames))) { + if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) { ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' '); for (i = 3; i < bt->num_frames - 2; i++) { ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]); @@ -1251,7 +1399,7 @@ void ast_backtrace(void) ast_bt_destroy(bt); #else ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n"); -#endif +#endif /* defined(HAVE_BKTR) */ } void __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap) diff --git a/main/say.c b/main/say.c index b57989ef3..be4b89987 100644 --- a/main/say.c +++ b/main/say.c @@ -3680,6 +3680,8 @@ int ast_say_date_with_format_en(struct ast_channel *chan, time_t t, const char * int res=0, offset, sndoffset; char sndfile[256], nextmsg[256]; + ast_backtrace(); + if (format == NULL) format = "ABdY 'digits/at' IMp"; diff --git a/main/utils.c b/main/utils.c index 6f2c884d0..268ab8eb5 100644 --- a/main/utils.c +++ b/main/utils.c @@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <ctype.h> #include <sys/stat.h> +#include <sys/stat.h> #ifdef HAVE_DEV_URANDOM #include <fcntl.h> @@ -739,7 +740,7 @@ static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt return; } - if ((symbols = backtrace_symbols(bt->addresses, bt->num_frames))) { + if ((symbols = ast_bt_get_symbols(bt->addresses, bt->num_frames))) { int frame_iterator; for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) { @@ -2081,3 +2082,22 @@ int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, co return res; } #endif + +char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size) +{ + const char *envPATH = getenv("PATH"); + char *tpath, *path; + struct stat unused; + if (!envPATH) { + return NULL; + } + tpath = ast_strdupa(envPATH); + while ((path = strsep(&tpath, ":"))) { + snprintf(fullpath, fullpath_size, "%s/%s", path, binary); + if (!stat(fullpath, &unused)) { + return fullpath; + } + } + return NULL; +} + |