summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h.cmake1
-rw-r--r--configure.cmake1
-rw-r--r--include/my_stacktrace.h18
-rwxr-xr-xmysql-test/mysql-test-run.pl2
-rw-r--r--mysys/CMakeLists.txt5
-rw-r--r--mysys/my_addr_resolve.c131
-rw-r--r--mysys/stacktrace.c37
7 files changed, 189 insertions, 6 deletions
diff --git a/config.h.cmake b/config.h.cmake
index 65f5d93f4d8..eae3a4ba886 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -28,6 +28,7 @@
#cmakedefine HAVE_CRYPT_H 1
#cmakedefine HAVE_CURSES_H 1
#cmakedefine HAVE_CXXABI_H 1
+#cmakedefine HAVE_BFD_H 1
#cmakedefine HAVE_NCURSES_H 1
#cmakedefine HAVE_NDIR_H 1
#cmakedefine HAVE_DIRENT_H 1
diff --git a/configure.cmake b/configure.cmake
index 6363a616b41..fd4e22de447 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -186,6 +186,7 @@ CHECK_INCLUDE_FILES (aio.h HAVE_AIO_H)
CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H)
CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H)
CHECK_INCLUDE_FILES (cxxabi.h HAVE_CXXABI_H)
+CHECK_INCLUDE_FILES (bfd.h HAVE_BFD_H)
CHECK_INCLUDE_FILES (dirent.h HAVE_DIRENT_H)
CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H)
CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H)
diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h
index df5741fa3d8..f5229a4b0af 100644
--- a/include/my_stacktrace.h
+++ b/include/my_stacktrace.h
@@ -55,6 +55,24 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep);
#endif
#endif
+#ifndef SAFEMALLOC
+#undef HAVE_BFD_H
+#endif
+
+#ifdef HAVE_BFD_H
+#define HAVE_MY_ADDR_RESOLVE 1
+#endif
+
+#ifdef HAVE_MY_ADDR_RESOLVE
+typedef struct {
+ const char *file;
+ const char *func;
+ uint line;
+} my_addr_loc;
+int my_addr_resolve(void *ptr, my_addr_loc *loc);
+const char *my_addr_resolve_init();
+#endif
+
#ifdef HAVE_WRITE_CORE
void my_write_core(int sig);
#endif
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 25427b81eff..e3f5cb65507 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -4660,7 +4660,7 @@ sub extract_warning_lines ($$) {
$Ferr = undef; # Close error log file
# mysql_client_test.test sends a COM_DEBUG packet to the server
- # to provoke a SAFEMALLOC leak report, ignore any warnings
+ # to provoke a safemalloc leak report, ignore any warnings
# between "Begin/end safemalloc memory dump"
if ( grep(/Begin safemalloc memory dump:/, @lines) > 0)
{
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 5b611601955..f258fd7bb7f 100644
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -33,6 +33,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
rijndael.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c
lf_alloc-pin.c lf_dynarray.c lf_hash.c
+ my_addr_resolve.c
my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c
my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
my_rdtsc.c)
@@ -70,6 +71,10 @@ TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY}
${LIBNSL} ${LIBM} ${LIBRT})
DTRACE_INSTRUMENT(mysys)
+IF(HAVE_BFD_H)
+ TARGET_LINK_LIBRARIES(mysys bfd)
+ENDIF(HAVE_BFD_H)
+
IF (WIN32)
TARGET_LINK_LIBRARIES(mysys IPHLPAPI)
ENDIF(WIN32)
diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c
new file mode 100644
index 00000000000..c9c9212eb7d
--- /dev/null
+++ b/mysys/my_addr_resolve.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 2011 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_sys.h>
+#include <my_stacktrace.h>
+
+/**
+ strip the path, leave the file name and the last dirname
+*/
+static const char *strip_path(const char *s)
+{
+ const char *prev, *last;
+ for(prev= last= s; *s; s++)
+ if (*s == '/' || *s == '\\')
+ {
+ prev= last;
+ last= s + 1;
+ }
+ return prev;
+}
+
+/*
+ The following is very much single-threaded code and it's only supposed
+ to be used on shutdown or for a crash report
+ Or the caller should take care and use mutexes.
+
+ Also it does not free any its memory. For the same reason -
+ it's only used for crash reports or on shutdown when we already
+ have a memory leak.
+*/
+
+#ifdef HAVE_BFD_H
+#include <bfd.h>
+static bfd *bfdh= 0;
+static asymbol **symtable= 0;
+
+/**
+ finds a file name, a line number, and a function name corresponding to addr.
+
+ the function name is demangled.
+ the file name is stripped of its path, only the two last components are kept
+ the resolving logic is mostly based on addr2line of binutils-2.17
+
+ @return 0 on success, 1 on failure
+*/
+int my_addr_resolve(void *ptr, my_addr_loc *loc)
+{
+ bfd_vma addr= (intptr)ptr;
+ asection *sec;
+
+ for (sec= bfdh->sections; sec; sec= sec->next)
+ {
+ bfd_vma start;
+
+ if ((bfd_get_section_flags(bfdh, sec) & SEC_ALLOC) == 0)
+ continue;
+
+ start = bfd_get_section_vma(bfdh, sec);
+ if (addr < start || addr >= start + bfd_get_section_size(sec))
+ continue;
+
+ if (bfd_find_nearest_line(bfdh, sec, symtable, addr - start,
+ &loc->file, &loc->func, &loc->line))
+ {
+ if (loc->file)
+ loc->file= strip_path(loc->file);
+ else
+ loc->file= "";
+
+ if (loc->func)
+ {
+ const char *str= bfd_demangle(bfdh, loc->func, 3);
+ if (str)
+ loc->func= str;
+ }
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+const char *my_addr_resolve_init()
+{
+ if (!bfdh)
+ {
+ uint unused;
+ char **matching;
+
+ bfdh= bfd_openr(my_progname, NULL);
+ if (!bfdh)
+ goto err;
+
+ if (bfd_check_format(bfdh, bfd_archive))
+ goto err;
+ if (!bfd_check_format_matches (bfdh, bfd_object, &matching))
+ goto err;
+
+ if (bfd_read_minisymbols(bfdh, FALSE, (void *)&symtable, &unused) < 0)
+ goto err;
+ }
+ return 0;
+
+err:
+ return bfd_errmsg(bfd_get_error());
+}
+#elif defined(HAVE_LIBELF_H)
+/*
+ another possible implementation.
+*/
+#elif defined(MY_ADDR_RESOLVE_FORK)
+/*
+ yet another - just execute addr2line or eu-addr2line, whatever available,
+ pipe the addresses to it, and parse the output
+*/
+#endif
diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c
index d0897fabb52..a7b71a0bca6 100644
--- a/mysys/stacktrace.c
+++ b/mysys/stacktrace.c
@@ -210,25 +210,52 @@ static void my_demangle_symbols(char **addrs, int n)
#endif /* BACKTRACE_DEMANGLE */
+#if HAVE_MY_ADDR_RESOLVE
+static int print_with_addr_resolve(void **addrs, int n)
+{
+ int i;
+ const char *err;
+
+ if ((err= my_addr_resolve_init()))
+ {
+ fprintf(stderr, "(my_addr_resolve failure: %s)\n", err);
+ return 0;
+ }
+
+ for (i= 0; i < n; i++)
+ {
+ my_addr_loc loc;
+ if (my_addr_resolve(addrs[i], &loc))
+ backtrace_symbols_fd(addrs+i, 1, fileno(stderr));
+ else
+ fprintf(stderr, "%s:%u(%s)[%p]\n",
+ loc.file, loc.line, loc.func, addrs[i]);
+ }
+ return 1;
+}
+#endif
+
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
void *addrs[128];
- char **strings= NULL;
+ char **strings __attribute__((unused)) = NULL;
int n = backtrace(addrs, array_elements(addrs));
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack);
+#if HAVE_MY_ADDR_RESOLVE
+ if (print_with_addr_resolve(addrs, n))
+ return;
+#endif
#if BACKTRACE_DEMANGLE
if ((strings= backtrace_symbols(addrs, n)))
{
my_demangle_symbols(strings, n);
free(strings);
+ return;
}
#endif
#if HAVE_BACKTRACE_SYMBOLS_FD
- if (!strings)
- {
- backtrace_symbols_fd(addrs, n, fileno(stderr));
- }
+ backtrace_symbols_fd(addrs, n, fileno(stderr));
#endif
}