Commit 37c81d81 authored by Sergei Golubchik's avatar Sergei Golubchik

another backtrace resolver that prints source file name and line number

parent c753bedc
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#cmakedefine HAVE_CRYPT_H 1 #cmakedefine HAVE_CRYPT_H 1
#cmakedefine HAVE_CURSES_H 1 #cmakedefine HAVE_CURSES_H 1
#cmakedefine HAVE_CXXABI_H 1 #cmakedefine HAVE_CXXABI_H 1
#cmakedefine HAVE_BFD_H 1
#cmakedefine HAVE_NCURSES_H 1 #cmakedefine HAVE_NCURSES_H 1
#cmakedefine HAVE_NDIR_H 1 #cmakedefine HAVE_NDIR_H 1
#cmakedefine HAVE_DIRENT_H 1 #cmakedefine HAVE_DIRENT_H 1
......
...@@ -186,6 +186,7 @@ CHECK_INCLUDE_FILES (aio.h HAVE_AIO_H) ...@@ -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 (arpa/inet.h HAVE_ARPA_INET_H)
CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H) CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H)
CHECK_INCLUDE_FILES (cxxabi.h HAVE_CXXABI_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 (dirent.h HAVE_DIRENT_H)
CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H) CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H)
CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H) CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H)
......
...@@ -55,6 +55,24 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep); ...@@ -55,6 +55,24 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep);
#endif #endif
#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 #ifdef HAVE_WRITE_CORE
void my_write_core(int sig); void my_write_core(int sig);
#endif #endif
......
...@@ -4660,7 +4660,7 @@ sub extract_warning_lines ($$) { ...@@ -4660,7 +4660,7 @@ sub extract_warning_lines ($$) {
$Ferr = undef; # Close error log file $Ferr = undef; # Close error log file
# mysql_client_test.test sends a COM_DEBUG packet to the server # 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" # between "Begin/end safemalloc memory dump"
if ( grep(/Begin safemalloc memory dump:/, @lines) > 0) if ( grep(/Begin safemalloc memory dump:/, @lines) > 0)
{ {
......
...@@ -33,6 +33,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c ...@@ -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 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 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 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_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_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
my_rdtsc.c) my_rdtsc.c)
...@@ -70,6 +71,10 @@ TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY} ...@@ -70,6 +71,10 @@ TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY}
${LIBNSL} ${LIBM} ${LIBRT}) ${LIBNSL} ${LIBM} ${LIBRT})
DTRACE_INSTRUMENT(mysys) DTRACE_INSTRUMENT(mysys)
IF(HAVE_BFD_H)
TARGET_LINK_LIBRARIES(mysys bfd)
ENDIF(HAVE_BFD_H)
IF (WIN32) IF (WIN32)
TARGET_LINK_LIBRARIES(mysys IPHLPAPI) TARGET_LINK_LIBRARIES(mysys IPHLPAPI)
ENDIF(WIN32) ENDIF(WIN32)
......
/* 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
...@@ -210,25 +210,52 @@ static void my_demangle_symbols(char **addrs, int n) ...@@ -210,25 +210,52 @@ static void my_demangle_symbols(char **addrs, int n)
#endif /* BACKTRACE_DEMANGLE */ #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 my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{ {
void *addrs[128]; void *addrs[128];
char **strings= NULL; char **strings __attribute__((unused)) = NULL;
int n = backtrace(addrs, array_elements(addrs)); int n = backtrace(addrs, array_elements(addrs));
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n", fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack); stack_bottom, thread_stack);
#if HAVE_MY_ADDR_RESOLVE
if (print_with_addr_resolve(addrs, n))
return;
#endif
#if BACKTRACE_DEMANGLE #if BACKTRACE_DEMANGLE
if ((strings= backtrace_symbols(addrs, n))) if ((strings= backtrace_symbols(addrs, n)))
{ {
my_demangle_symbols(strings, n); my_demangle_symbols(strings, n);
free(strings); free(strings);
return;
} }
#endif #endif
#if HAVE_BACKTRACE_SYMBOLS_FD #if HAVE_BACKTRACE_SYMBOLS_FD
if (!strings) backtrace_symbols_fd(addrs, n, fileno(stderr));
{
backtrace_symbols_fd(addrs, n, fileno(stderr));
}
#endif #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment