backtrace.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2013, Digium, Inc.
00005  *
00006  * Matt Jordan <mjordan@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief Asterisk backtrace generation
00021  *
00022  * This file provides backtrace generation utilities
00023  */
00024 
00025 /*** MODULEINFO
00026    <support_level>core</support_level>
00027  ***/
00028 
00029 #include "asterisk.h"
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397570 $");
00031 
00032 #include "asterisk/backtrace.h"
00033 #include "asterisk/utils.h"
00034 #include "asterisk/strings.h"
00035 
00036 #ifdef HAVE_BKTR
00037 #include <execinfo.h>
00038 #if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00039 #include <dlfcn.h>
00040 #include <bfd.h>
00041 #endif
00042 
00043 struct ast_bt *__ast_bt_create(void)
00044 {
00045    struct ast_bt *bt = ast_std_calloc(1, sizeof(*bt));
00046 
00047    if (!bt) {
00048       return NULL;
00049    }
00050    bt->alloced = 1;
00051 
00052    ast_bt_get_addresses(bt);
00053 
00054    return bt;
00055 }
00056 
00057 int __ast_bt_get_addresses(struct ast_bt *bt)
00058 {
00059    bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
00060    return 0;
00061 }
00062 
00063 void *__ast_bt_destroy(struct ast_bt *bt)
00064 {
00065    if (bt && bt->alloced) {
00066       ast_std_free(bt);
00067    }
00068    return NULL;
00069 }
00070 
00071 char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
00072 {
00073    char **strings;
00074 #if defined(BETTER_BACKTRACES)
00075    int stackfr;
00076    bfd *bfdobj;           /* bfd.h */
00077    Dl_info dli;           /* dlfcn.h */
00078    long allocsize;
00079    asymbol **syms = NULL; /* bfd.h */
00080    bfd_vma offset;        /* bfd.h */
00081    const char *lastslash;
00082    asection *section;
00083    const char *file, *func;
00084    unsigned int line;
00085    char address_str[128];
00086    char msg[1024];
00087    size_t strings_size;
00088    size_t *eachlen;
00089 #endif
00090 
00091 #if defined(BETTER_BACKTRACES)
00092    strings_size = num_frames * sizeof(*strings);
00093 
00094    eachlen = ast_std_calloc(num_frames, sizeof(*eachlen));
00095    strings = ast_std_calloc(num_frames, sizeof(*strings));
00096    if (!eachlen || !strings) {
00097       ast_std_free(eachlen);
00098       ast_std_free(strings);
00099       return NULL;
00100    }
00101 
00102    for (stackfr = 0; stackfr < num_frames; stackfr++) {
00103       int found = 0, symbolcount;
00104 
00105       msg[0] = '\0';
00106 
00107       if (!dladdr(addresses[stackfr], &dli)) {
00108          continue;
00109       }
00110 
00111       if (strcmp(dli.dli_fname, "asterisk") == 0) {
00112          char asteriskpath[256];
00113 
00114          if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
00115             /* This will fail to find symbols */
00116             dli.dli_fname = "asterisk";
00117          }
00118       }
00119 
00120       lastslash = strrchr(dli.dli_fname, '/');
00121       if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
00122          bfd_check_format(bfdobj, bfd_object) &&
00123          (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
00124          (syms = ast_std_malloc(allocsize)) &&
00125          (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
00126 
00127          if (bfdobj->flags & DYNAMIC) {
00128             offset = addresses[stackfr] - dli.dli_fbase;
00129          } else {
00130             offset = addresses[stackfr] - (void *) 0;
00131          }
00132 
00133          for (section = bfdobj->sections; section; section = section->next) {
00134             if (!bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
00135                section->vma > offset ||
00136                section->size + section->vma < offset) {
00137                continue;
00138             }
00139 
00140             if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
00141                continue;
00142             }
00143 
00144             /* file can possibly be null even with a success result from bfd_find_nearest_line */
00145             file = file ? file : "";
00146 
00147             /* Stack trace output */
00148             found++;
00149             if ((lastslash = strrchr(file, '/'))) {
00150                const char *prevslash;
00151 
00152                for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) {
00153                }
00154                if (prevslash >= file) {
00155                   lastslash = prevslash;
00156                }
00157             }
00158             if (dli.dli_saddr == NULL) {
00159                address_str[0] = '\0';
00160             } else {
00161                snprintf(address_str, sizeof(address_str), " (%p+%lX)",
00162                   dli.dli_saddr,
00163                   (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00164             }
00165             snprintf(msg, sizeof(msg), "%s:%u %s()%s",
00166                lastslash ? lastslash + 1 : file, line,
00167                S_OR(func, "???"),
00168                address_str);
00169 
00170             break; /* out of section iteration */
00171          }
00172       }
00173       if (bfdobj) {
00174          bfd_close(bfdobj);
00175          ast_std_free(syms);
00176       }
00177 
00178       /* Default output, if we cannot find the information within BFD */
00179       if (!found) {
00180          if (dli.dli_saddr == NULL) {
00181             address_str[0] = '\0';
00182          } else {
00183             snprintf(address_str, sizeof(address_str), " (%p+%lX)",
00184                dli.dli_saddr,
00185                (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00186          }
00187          snprintf(msg, sizeof(msg), "%s %s()%s",
00188             lastslash ? lastslash + 1 : dli.dli_fname,
00189             S_OR(dli.dli_sname, "<unknown>"),
00190             address_str);
00191       }
00192 
00193       if (!ast_strlen_zero(msg)) {
00194          char **tmp;
00195 
00196          eachlen[stackfr] = strlen(msg) + 1;
00197          if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) {
00198             ast_std_free(strings);
00199             strings = NULL;
00200             break; /* out of stack frame iteration */
00201          }
00202          strings = tmp;
00203          strings[stackfr] = (char *) strings + strings_size;
00204          strcpy(strings[stackfr], msg);/* Safe since we just allocated the room. */
00205          strings_size += eachlen[stackfr];
00206       }
00207    }
00208 
00209    if (strings) {
00210       /* Recalculate the offset pointers because of the reallocs. */
00211       strings[0] = (char *) strings + num_frames * sizeof(*strings);
00212       for (stackfr = 1; stackfr < num_frames; stackfr++) {
00213          strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1];
00214       }
00215    }
00216    ast_std_free(eachlen);
00217 
00218 #else /* !defined(BETTER_BACKTRACES) */
00219 
00220    strings = backtrace_symbols(addresses, num_frames);
00221 #endif /* defined(BETTER_BACKTRACES) */
00222    return strings;
00223 }
00224 
00225 #endif /* HAVE_BKTR */

Generated on Thu Apr 16 06:27:15 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6