aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-12-17 23:30:55 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2010-12-17 23:30:55 +0000
commite81ed3fc262e65b8e5f2a3d207c1b435ca2e669d (patch)
tree74460e8cd1b5b2149afa0f07b856a96ad8bac972
parent1c923ad9517ce0ce50806f1348fc861089285b01 (diff)
Merged revisions 298905 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r298905 | tilghman | 2010-12-17 15:40:56 -0600 (Fri, 17 Dec 2010) | 6 lines Let Asterisk find better backtrace information with libbfd. The menuselect option BETTER_BACKTRACES, if enabled, will use libbfd to search for better symbol information within both the Asterisk binary, as well as loaded modules, to assist when using inline backtraces to track down problems. ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.2@298957 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--build_tools/cflags-devmode.xml5
-rw-r--r--build_tools/menuselect-deps.in2
-rwxr-xr-xconfigure256
-rw-r--r--configure.ac30
-rw-r--r--include/asterisk/autoconfig.h.in6
-rw-r--r--include/asterisk/logger.h10
-rw-r--r--include/asterisk/utils.h9
-rw-r--r--main/Makefile4
-rw-r--r--main/astobj2.c2
-rw-r--r--main/logger.c156
-rw-r--r--main/say.c2
-rw-r--r--main/utils.c22
-rw-r--r--makeopts.in3
-rw-r--r--utils/ael_main.c11
-rw-r--r--utils/check_expr.c12
-rw-r--r--utils/conf2ael.c12
-rw-r--r--utils/hashtest.c13
-rw-r--r--utils/hashtest2.c12
-rw-r--r--utils/refcounter.c13
19 files changed, 531 insertions, 49 deletions
diff --git a/build_tools/cflags-devmode.xml b/build_tools/cflags-devmode.xml
index e47e7160b..85d7bc8ce 100644
--- a/build_tools/cflags-devmode.xml
+++ b/build_tools/cflags-devmode.xml
@@ -22,4 +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 5f399fcdf..dba1b8f42 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -1,8 +1,10 @@
ALSA=@PBX_ALSA@
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 83e8d1934..3d3c4379c 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 298050 .
+# From configure.ac Revision: 298817 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.65 for asterisk 1.6.2.
#
@@ -632,6 +632,7 @@ CONFIG_LIBXML2
GSM_INTERNAL
PBX_DAHDI_HALF_FULL
PKGCONFIG
+PBX_DLADDR
PBX_IP_MTU_DISCOVER
AST_SHADOW_WARNINGS
AST_NO_STRICT_OVERFLOW
@@ -879,10 +880,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
@@ -899,10 +900,14 @@ PBX_CAP
CAP_DIR
CAP_INCLUDE
CAP_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
@@ -1029,12 +1034,13 @@ enable_option_checking
with_gnu_ld
enable_dev_mode
with_asound
-with_avcodec
+with_bfd
+with_execinfo
with_cap
with_curses
with_crypto
with_dahdi
-with_execinfo
+with_avcodec
with_gsm
with_gtk
with_gtk2
@@ -1733,12 +1739,13 @@ 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-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-gtk=PATH use gtk files in PATH
@@ -8365,26 +8372,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
@@ -8525,29 +8567,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
@@ -15341,6 +15380,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.
@@ -15545,6 +15619,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 5a8924e50..99beb3232 100644
--- a/configure.ac
+++ b/configure.ac
@@ -295,15 +295,16 @@ AC_SUBST(AST_DEVMODE)
# 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([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])
+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([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])
+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([GTK], [gtk], [gtk])
AST_EXT_LIB_SETUP([GTK2], [gtk2], [gtk2])
@@ -820,6 +821,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)
@@ -828,6 +846,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 ae5f9d136..327a44ee0 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -110,6 +110,9 @@
/* Define to 1 if your GCC C compiler supports the 'weak_import' attribute. */
#undef HAVE_ATTRIBUTE_weak_import
+/* 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
@@ -165,6 +168,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 65448cfe4..214738a25 100644
--- a/include/asterisk/logger.h
+++ b/include/asterisk/logger.h
@@ -276,6 +276,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 91de914b5..c940f4d51 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -726,4 +726,13 @@ int ast_str_to_eid(struct ast_eid *eid, const char *s);
*/
int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2);
+/*!\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 6e618087c..9ba16fe2d 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -56,6 +56,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
ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
diff --git a/main/astobj2.c b/main/astobj2.c
index 784dfb0a9..6cada222e 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 6425183b3..9849a595c 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -46,8 +46,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_BKTR
-#include <execinfo.h>
-#define MAX_BACKTRACE_FRAMES 20
+# 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
#define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
@@ -1214,6 +1218,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)
@@ -1228,7 +1376,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 = 0; i < bt->num_frames; i++) {
ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i, bt->addresses[i], strings[i]);
@@ -1240,7 +1388,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 3108c335e..fd24f28b3 100644
--- a/main/say.c
+++ b/main/say.c
@@ -3493,6 +3493,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 10b9a4d8d..4fe4984b2 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>
@@ -736,7 +737,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) {
@@ -1826,3 +1827,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;
+}
+
diff --git a/makeopts.in b/makeopts.in
index 5df805ef1..83ae26b84 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -81,6 +81,9 @@ AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
ALSA_INCLUDE=@ALSA_INCLUDE@
ALSA_LIB=@ALSA_LIB@
+BFD_INCLUDE=@BFD_INCLUDE@
+BFD_LIB=@BFD_LIB@
+
CURL_INCLUDE=@CURL_INCLUDE@
CURL_LIB=@CURL_LIB@
diff --git a/utils/ael_main.c b/utils/ael_main.c
index 8b28d31d3..e5a7346ed 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 a8d2e6525..b904b4824 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 3b15336c3..cffd1bb67 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 16c5e1d9b..9ec597f4e 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 a9fdf661b..7953decf6 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 d71ebf1d8..1c679e822 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)
{