diff --git a/build_tools/cflags-devmode.xml b/build_tools/cflags-devmode.xml index 37f7a4d4f40be1cb352a6f8977793a7f6fd315d1..85d7bc8ce2d60c11da1705b9a45cacfc72c06030 100644 --- a/build_tools/cflags-devmode.xml +++ b/build_tools/cflags-devmode.xml @@ -22,5 +22,9 @@ </member> <member name="TEST_FRAMEWORK" displayname="Enable Test Framework API"> </member> - + <member name="BETTER_BACKTRACES" displayname="Use libbfd to generate better inline backtraces"> + <depend>BFD</depend> + <depend>DLADDR</depend> + <defaultenabled>no</defaultenabled> + </member> </category> diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index 2a5bcd74b2d727850057e18f1b7ddb1adf642e8d..35573c3bf17b5af945f22814ab0034212c741bfc 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -1,9 +1,11 @@ ALSA=@PBX_ALSA@ BLUETOOTH=@PBX_BLUETOOTH@ CRYPTO=@PBX_CRYPTO@ +BFD=@PBX_BFD@ BISON=@PBX_BISON@ CURL=@PBX_CURL@ DAHDI=@PBX_DAHDI@ +DLADDR=@PBX_DLADDR@ FLEX=@PBX_FLEX@ FREETDS=@PBX_FREETDS@ GENERIC_ODBC=@PBX_GENERIC_ODBC@ diff --git a/configure b/configure index 82465dbd827cdbe84e616f3bca582217fb5346ab..76e68d70eab80869ce3ed2854d43d52e2f4136e2 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac Revision: 298137 . +# From configure.ac Revision: 298819 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for asterisk trunk. # @@ -650,6 +650,7 @@ CONFIG_LIBXML2 GSM_INTERNAL PBX_DAHDI_HALF_FULL PKGCONFIG +PBX_DLADDR PBX_IP_MTU_DISCOVER PBX_GLOB_BRACE PBX_GLOB_NOMAGIC @@ -977,10 +978,10 @@ PBX_GSM GSM_DIR GSM_INCLUDE GSM_LIB -PBX_BKTR -BKTR_DIR -BKTR_INCLUDE -BKTR_LIB +PBX_FFMPEG +FFMPEG_DIR +FFMPEG_INCLUDE +FFMPEG_LIB PBX_DAHDI DAHDI_DIR DAHDI_INCLUDE @@ -1001,10 +1002,14 @@ PBX_BLUETOOTH BLUETOOTH_DIR BLUETOOTH_INCLUDE BLUETOOTH_LIB -PBX_FFMPEG -FFMPEG_DIR -FFMPEG_INCLUDE -FFMPEG_LIB +PBX_BKTR +BKTR_DIR +BKTR_INCLUDE +BKTR_LIB +PBX_BFD +BFD_DIR +BFD_INCLUDE +BFD_LIB PBX_ALSA ALSA_DIR ALSA_INCLUDE @@ -1149,13 +1154,14 @@ with_gnu_ld enable_dev_mode enable_coverage with_asound -with_avcodec +with_bfd +with_execinfo with_bluetooth with_cap with_curses with_crypto with_dahdi -with_execinfo +with_avcodec with_gsm with_gtk2 with_gmime @@ -1860,13 +1866,14 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-asound=PATH use Advanced Linux Sound Architecture files in PATH - --with-avcodec=PATH use Ffmpeg and avcodec files in PATH + --with-bfd=PATH use Debug symbol decoding files in PATH + --with-execinfo=PATH use Stack Backtrace files in PATH --with-bluetooth=PATH use Bluetooth files in PATH --with-cap=PATH use POSIX 1.e capabilities files in PATH --with-curses=PATH use curses files in PATH --with-crypto=PATH use OpenSSL Cryptography files in PATH --with-dahdi=PATH use DAHDI files in PATH - --with-execinfo=PATH use Stack Backtrace files in PATH + --with-avcodec=PATH use Ffmpeg and avcodec files in PATH --with-gsm=PATH use External GSM files in PATH, use 'internal' GSM otherwise --with-gtk2=PATH use gtk2 files in PATH @@ -8706,26 +8713,61 @@ fi - FFMPEG_DESCRIP="Ffmpeg and avcodec" - FFMPEG_OPTION="avcodec" - PBX_FFMPEG=0 + BFD_DESCRIP="Debug symbol decoding" + BFD_OPTION="bfd" + PBX_BFD=0 -# Check whether --with-avcodec was given. -if test "${with_avcodec+set}" = set; then : - withval=$with_avcodec; +# Check whether --with-bfd was given. +if test "${with_bfd+set}" = set; then : + withval=$with_bfd; case ${withval} in n|no) - USE_FFMPEG=no + USE_BFD=no # -1 is a magic value used by menuselect to know that the package # was disabled, other than 'not found' - PBX_FFMPEG=-1 + PBX_BFD=-1 ;; y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} FFMPEG" + ac_mandatory_list="${ac_mandatory_list} BFD" ;; *) - FFMPEG_DIR="${withval}" - ac_mandatory_list="${ac_mandatory_list} FFMPEG" + BFD_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} BFD" + ;; + esac + +fi + + + + + + + + +# BKTR is used for backtrace support on platforms that do not +# have it natively. + + BKTR_DESCRIP="Stack Backtrace" + BKTR_OPTION="execinfo" + PBX_BKTR=0 + +# Check whether --with-execinfo was given. +if test "${with_execinfo+set}" = set; then : + withval=$with_execinfo; + case ${withval} in + n|no) + USE_BKTR=no + # -1 is a magic value used by menuselect to know that the package + # was disabled, other than 'not found' + PBX_BKTR=-1 + ;; + y|ye|yes) + ac_mandatory_list="${ac_mandatory_list} BKTR" + ;; + *) + BKTR_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} BKTR" ;; esac @@ -8898,29 +8940,26 @@ fi -# BKTR is used for backtrace support on platforms that do not -# have it natively. - - BKTR_DESCRIP="Stack Backtrace" - BKTR_OPTION="execinfo" - PBX_BKTR=0 + FFMPEG_DESCRIP="Ffmpeg and avcodec" + FFMPEG_OPTION="avcodec" + PBX_FFMPEG=0 -# Check whether --with-execinfo was given. -if test "${with_execinfo+set}" = set; then : - withval=$with_execinfo; +# Check whether --with-avcodec was given. +if test "${with_avcodec+set}" = set; then : + withval=$with_avcodec; case ${withval} in n|no) - USE_BKTR=no + USE_FFMPEG=no # -1 is a magic value used by menuselect to know that the package # was disabled, other than 'not found' - PBX_BKTR=-1 + PBX_FFMPEG=-1 ;; y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} BKTR" + ac_mandatory_list="${ac_mandatory_list} FFMPEG" ;; *) - BKTR_DIR="${withval}" - ac_mandatory_list="${ac_mandatory_list} BKTR" + FFMPEG_DIR="${withval}" + ac_mandatory_list="${ac_mandatory_list} FFMPEG" ;; esac @@ -16677,6 +16716,41 @@ $as_echo "#define TYPEOF_FD_SET_FDS_BITS long long" >>confdefs.h fi ; fi ; fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dladdr in dlfcn.h" >&5 +$as_echo_n "checking for dladdr in dlfcn.h... " >&6; } +PBX_DLADDR=0 +old_LIBS=${LIBS} +LIBS="${LIBS} -ldl" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE 1 +#include <dlfcn.h> +int +main () +{ +dladdr((void *)0, (void *)0) + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PBX_DLADDR=1 + + +$as_echo "#define HAVE_DLADDR 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=${old_LIBS} + # PKGCONFIG is used in later tests if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. @@ -16881,6 +16955,112 @@ fi +if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then + pbxlibdir="" + # if --with-BFD=DIR has been specified, use it. + if test "x${BFD_DIR}" != "x"; then + if test -d ${BFD_DIR}/lib; then + pbxlibdir="-L${BFD_DIR}/lib" + else + pbxlibdir="-L${BFD_DIR}" + fi + fi + pbxfuncname="bfd_openr" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_BFD_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_bfd_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbfd" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lbfd... " >&6; } +if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbfd ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +eval as_val=\$$as_ac_Lib + if test "x$as_val" = x""yes; then : + AST_BFD_FOUND=yes +else + AST_BFD_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_BFD_FOUND}" = "yes"; then + BFD_LIB="${pbxlibdir} -lbfd " + # if --with-BFD=DIR has been specified, use it. + if test "x${BFD_DIR}" != "x"; then + BFD_INCLUDE="-I${BFD_DIR}/include" + fi + BFD_INCLUDE="${BFD_INCLUDE} " + if test "xbfd.h" = "x" ; then # no header, assume found + BFD_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${BFD_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "bfd.h" "ac_cv_header_bfd_h" "$ac_includes_default" +if test "x$ac_cv_header_bfd_h" = x""yes; then : + BFD_HEADER_FOUND=1 +else + BFD_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${BFD_HEADER_FOUND}" = "x0" ; then + BFD_LIB="" + BFD_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + BFD_LIB="" + fi + PBX_BFD=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_BFD 1 +_ACEOF + + fi + fi +fi + + + + if test "x${PBX_CURSES}" != "x1" -a "${USE_CURSES}" != "no"; then pbxlibdir="" # if --with-CURSES=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index 8bc894d043a49a642ac01c39094b0ce1aea985c2..593b5c74761a5d419f4b60e0986cc4bf5d4fb435 100644 --- a/configure.ac +++ b/configure.ac @@ -364,16 +364,17 @@ AC_SUBST(AST_CODE_COVERAGE) # to make things easier for the users. AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound]) -AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec], [avcodec]) +AST_EXT_LIB_SETUP([BFD], [Debug symbol decoding], [bfd]) + +# BKTR is used for backtrace support on platforms that do not +# have it natively. +AST_EXT_LIB_SETUP([BKTR], [Stack Backtrace], [execinfo]) AST_EXT_LIB_SETUP([BLUETOOTH], [Bluetooth], [bluetooth]) AST_EXT_LIB_SETUP([CAP], [POSIX 1.e capabilities], [cap]) AST_EXT_LIB_SETUP([CURSES], [curses], [curses]) AST_EXT_LIB_SETUP([CRYPTO], [OpenSSL Cryptography], [crypto]) AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi]) - -# BKTR is used for backtrace support on platforms that do not -# have it natively. -AST_EXT_LIB_SETUP([BKTR], [Stack Backtrace], [execinfo]) +AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec], [avcodec]) AST_EXT_LIB_SETUP([GSM], [External GSM], [gsm], [, use 'internal' GSM otherwise]) AST_EXT_LIB_SETUP([GTK2], [gtk2], [gtk2]) AST_EXT_LIB_SETUP([GMIME], [GMime], [gmime]) @@ -1012,6 +1013,23 @@ else if test $ac_cv_sizeof_long_long = $ac_cv_sizeof_fd_set_fds_bits; then AC_DEFINE([TYPEOF_FD_SET_FDS_BITS], [long long], [Define to a type of the same size as fd_set.fds_bits[[0]]]) fi ; fi ; fi +AC_MSG_CHECKING(for dladdr in dlfcn.h) +PBX_DLADDR=0 +old_LIBS=${LIBS} +LIBS="${LIBS} -ldl" +AC_LINK_IFELSE( + AC_LANG_PROGRAM([#define _GNU_SOURCE 1 +#include <dlfcn.h>], + [dladdr((void *)0, (void *)0)] + ), + AC_MSG_RESULT(yes) + PBX_DLADDR=1 + AC_SUBST([PBX_DLADDR]) + AC_DEFINE([HAVE_DLADDR], 1, [Define to 1 if your system has the dladdr() GNU extension]), + AC_MSG_RESULT(no) +) +LIBS=${old_LIBS} + # PKGCONFIG is used in later tests AC_CHECK_TOOL(PKGCONFIG, pkg-config, No) @@ -1020,6 +1038,8 @@ AC_CHECK_TOOL(PKGCONFIG, pkg-config, No) AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl]) +AST_EXT_LIB_CHECK([BFD], [bfd], [bfd_openr], [bfd.h]) + AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h]) if test "x${OSARCH}" = "xlinux-gnu" ; then diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 5ef3dc15ec2da36d190c73f14c33da65b0557c5d..d59eef27711d0dcafb821e963a1edacfdbd09c4e 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -107,6 +107,9 @@ /* Define to 1 if your GCC C compiler supports the 'weakref' attribute. */ #undef HAVE_ATTRIBUTE_weakref +/* Define to 1 if you have the Debug symbol decoding library. */ +#undef HAVE_BFD + /* Define to 1 if you have the Stack Backtrace library. */ #undef HAVE_BKTR @@ -168,6 +171,9 @@ */ #undef HAVE_DIRENT_H +/* Define to 1 if your system has the dladdr() GNU extension */ +#undef HAVE_DLADDR + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 886c43ce02bdc2c4a628cb18900c20a7ab5edd9b..91824d70440fe705007f17736b7cfc483fcbff9e 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -296,6 +296,16 @@ int ast_bt_get_addresses(struct ast_bt *bt); */ void *ast_bt_destroy(struct ast_bt *bt); +/* \brief Retrieve symbols for a set of backtrace addresses + * + * \param addresses A list of addresses, such as the ->addresses structure element of struct ast_bt. + * \param num_frames Number of addresses in the addresses list + * \retval NULL Unable to allocate memory + * \return List of strings + * \since 1.6.2.16 + */ +char **ast_bt_get_symbols(void **addresses, size_t num_frames); + #endif /* HAVE_BKTR */ #endif /* _LOGGER_BACKTRACE_H */ diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 97f32bf67b4adbdc716f97e2f47a7326d927d1dd..3d3f18f0816c4534fe1d3be2e60eeed30273bce2 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -765,4 +765,13 @@ int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2); */ int ast_get_tid(void); +/*!\brief Resolve a binary to a full pathname + * \param binary Name of the executable to resolve + * \param fullpath Buffer to hold the complete pathname + * \param fullpath_size Size of \a fullpath + * \retval NULL \a binary was not found or the environment variable PATH is not set + * \return \a fullpath + */ +char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/Makefile b/main/Makefile index 0bb7c97c0c6730ba99dce149fcbcc7f830772379..ad4d39c036b18524d115136f517ade47242e5db1 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 d0b438940f728d87451d727069b25331977aaaad..50886de2ecbf09a0cd2ceee688268449c09ec1e2 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 430f01f581f4f2d95235e572e64d83a5623fb3dd..12f835f999e593abbff007e5300d3473509c24e2 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 static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */ @@ -1213,6 +1217,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) @@ -1227,7 +1375,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]); @@ -1242,7 +1390,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/utils.c b/main/utils.c index 7ac62bd39f07e89b83ca844f8f0bee6fc687c93f..f8ec82f259f3b9f39c470f1ab5234b76bd92482e 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> @@ -746,7 +747,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) { @@ -2106,3 +2107,22 @@ int ast_get_tid(void) #endif return ret; } + +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; +} + diff --git a/makeopts.in b/makeopts.in index 5e9ef8c7aa8c3cb72c552a01241be1ac9f757bff..3cde8141d43811c980b30b3bb72e9ff7b36ea393 100644 --- a/makeopts.in +++ b/makeopts.in @@ -104,6 +104,9 @@ AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@ ALSA_INCLUDE=@ALSA_INCLUDE@ ALSA_LIB=@ALSA_LIB@ +BFD_INCLUDE=@BFD_INCLUDE@ +BFD_LIB=@BFD_LIB@ + BLUETOOTH_INCLUDE=@BLUETOOTH_INCLUDE@ BLUETOOTH_LIB=@BLUETOOTH_LIB@ diff --git a/utils/ael_main.c b/utils/ael_main.c index 8b28d31d3b1da7b8fac2d4f38c0d760026f13e92..e5a7346edb2977c4f55a1a68eebe8cb7a140aa19 100644 --- a/utils/ael_main.c +++ b/utils/ael_main.c @@ -591,6 +591,17 @@ int ast_bt_get_addresses(struct ast_bt *bt) return 0; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} #else void ast_remove_lock_info(void *lock_addr) { diff --git a/utils/check_expr.c b/utils/check_expr.c index a8d2e6525baaa06db3db973711490e6f751a1403..b904b482464672a896089f7e8f2ff6f0c91f7f0d 100644 --- a/utils/check_expr.c +++ b/utils/check_expr.c @@ -73,6 +73,18 @@ int ast_bt_get_addresses(struct ast_bt *bt) /* Suck it, you stupid utils directory! */ return 0; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames); +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} #else void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr); diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 48a18392c363532ac3e101ac6f9c97c8b0ad1c34..538818b2509bb4e9dbafd23eeaf34f9529989e6a 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -724,6 +724,18 @@ int ast_bt_get_addresses(struct ast_bt *bt) return 0; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} + #else void ast_remove_lock_info(void *lock_addr) { diff --git a/utils/hashtest.c b/utils/hashtest.c index 16c5e1d9b18caa2d023b02525c8c56faa06ed9bb..9ec597f4e7ecf5388e9fb06b4e8fbca718e5df3a 100644 --- a/utils/hashtest.c +++ b/utils/hashtest.c @@ -385,6 +385,19 @@ int ast_bt_get_addresses(struct ast_bt *bt) return 0; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames); +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} + void *ast_bt_destroy(struct ast_bt *bt); void *ast_bt_destroy(struct ast_bt *bt) { diff --git a/utils/hashtest2.c b/utils/hashtest2.c index a9fdf661b6b68f784d5da76fdef095e4a7a41a48..7953decf6613f047409a3a397331cb5e88583992 100644 --- a/utils/hashtest2.c +++ b/utils/hashtest2.c @@ -395,6 +395,18 @@ int ast_bt_get_addresses(struct ast_bt *bt) return -1; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} + void *ast_bt_destroy(struct ast_bt *bt) { return NULL; diff --git a/utils/refcounter.c b/utils/refcounter.c index d71ebf1d8a32d5cdcbbeda5016195192bc05b412..1c679e8221460bd868eeace48d8f05e84b72da0b 100644 --- a/utils/refcounter.c +++ b/utils/refcounter.c @@ -287,6 +287,19 @@ int ast_bt_get_addresses(struct ast_bt *bt) return 0; } +char **ast_bt_get_symbols(void **addresses, size_t num_frames); +char **ast_bt_get_symbols(void **addresses, size_t num_frames) +{ + char **foo = calloc(num_frames, sizeof(char *) + 1); + if (foo) { + int i; + for (i = 0; i < num_frames; i++) { + foo[i] = (char *) foo + sizeof(char *) * num_frames; + } + } + return foo; +} + void *ast_bt_destroy(struct ast_bt *bt); void *ast_bt_destroy(struct ast_bt *bt) {