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)
 {