From 6596972385c5d23ac12901c08ff30e1a8f315a13 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 18 Jun 2008 13:17:15 -0300 Subject: Bug#37003 Tests sporadically crashes with embedded server The problem was that when a embedded linked version of mysqltest crashed there was no way to obtain a stack trace if no core file is available. Another problem is that the embedded version of libmysql was not behaving (crash) the same as the non-embedded with respect to sending commands to a explicitly closed connection. The solution is to generate a mysqltest's stack trace on crash and to enable "reconnect" if the connection handle was explicitly closed so the behavior matches the non-embedded one. client/CMakeLists.txt: Link mysys to mysqltest. client/Makefile.am: Link mysys to mysqltest. client/mysqltest.c: Add fatal signal handling with backtracing for Unix and Windows. configure.in: Add check for weak symbols support and remove a spurious word. include/Makefile.am: Add new header with prototype for stack tracing functions. include/my_stacktrace.h: Add new header with prototype for stack tracing functions. libmysqld/CMakeLists.txt: stack tracing is now part of mysys. libmysqld/Makefile.am: stack tracing is now part of mysys. libmysqld/lib_sql.cc: Re-connect if connection was explicitly closed. This is done to match the behavior of the non-embeded libmysql. mysql-test/t/sql_low_priority_updates_func.test: Test expects parallelism between queries that cannot be guaranteed under embedded. mysys/CMakeLists.txt: Add stacktrace to mysys. mysys/Makefile.am: Add stacktrace to mysys. mysys/stacktrace.c: Move stacktrace to mysys and add weak symbol for the C++ name de-mangling function so that it can later be overridden in C++ code. Also add my_ prefix to exported functions. sql/CMakeLists.txt: stacktrace was moved to mysys. sql/Makefile.am: stacktrace was moved to mysys. sql/mysqld.cc: Add my_ prefix to mysys functions. --- client/CMakeLists.txt | 8 +- client/Makefile.am | 12 +- client/mysqltest.c | 92 ++++ configure.in | 12 +- include/Makefile.am | 2 +- include/my_stacktrace.h | 61 +++ libmysqld/CMakeLists.txt | 3 +- libmysqld/Makefile.am | 2 +- libmysqld/lib_sql.cc | 9 + mysql-test/t/sql_low_priority_updates_func.test | 1 + mysys/CMakeLists.txt | 2 +- mysys/Makefile.am | 2 +- mysys/stacktrace.c | 582 ++++++++++++++++++++++++ sql/CMakeLists.txt | 2 +- sql/Makefile.am | 4 +- sql/mysqld.cc | 14 +- sql/stacktrace.c | 575 ----------------------- sql/stacktrace.h | 69 --- 18 files changed, 782 insertions(+), 670 deletions(-) create mode 100644 include/my_stacktrace.h create mode 100644 mysys/stacktrace.c delete mode 100644 sql/stacktrace.c delete mode 100644 sql/stacktrace.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a20db4134c2..cbd4a1f306b 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -15,7 +15,7 @@ INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") # We use the "mysqlclient_notls" library here just as safety, in case -# any of the clients here would go beond the client API and access the +# any of the clients here would go beyond the client API and access the # Thread Local Storage directly. SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") @@ -32,9 +32,9 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c) TARGET_LINK_LIBRARIES(mysql mysqlclient_notls wsock32) -ADD_EXECUTABLE(mysqltest mysqltest.c ../mysys/my_getsystime.c - ../mysys/my_copy.c ../mysys/my_mkdir.c) -TARGET_LINK_LIBRARIES(mysqltest mysqlclient_notls regex wsock32) +ADD_EXECUTABLE(mysqltest mysqltest.c) +SET_SOURCE_FILES_PROPERTIES(mysqltest.c PROPERTIES COMPILE_FLAGS "-DTHREADS") +TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug) ADD_EXECUTABLE(mysqlcheck mysqlcheck.c) TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient_notls wsock32) diff --git a/client/Makefile.am b/client/Makefile.am index c57a5673367..940766ac66c 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -86,11 +86,13 @@ mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ $(LIBMYSQLCLIENT_LA) \ $(top_builddir)/mysys/libmysys.a -mysqltest_SOURCES= mysqltest.c \ - $(top_srcdir)/mysys/my_getsystime.c \ - $(top_srcdir)/mysys/my_copy.c \ - $(top_srcdir)/mysys/my_mkdir.c -mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) +mysqltest_SOURCES= mysqltest.c +mysqltest_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK +mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ + @CLIENT_EXTRA_LDFLAGS@ \ + $(LIBMYSQLCLIENT_LA) \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/regex/libregex.a mysql_upgrade_SOURCES= mysql_upgrade.c \ $(top_srcdir)/mysys/my_getpagesize.c diff --git a/client/mysqltest.c b/client/mysqltest.c index bd7a84e2d6a..5cc0951cdf5 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -48,7 +48,14 @@ #ifdef __WIN__ #include #endif +#include +#ifdef __WIN__ +#include +#define SIGNAL_FMT "exception 0x%x" +#else +#define SIGNAL_FMT "signal %d" +#endif /* Use cygwin for --exec and --system before 5.0 */ #if MYSQL_VERSION_ID < 50000 @@ -214,6 +221,7 @@ struct st_connection /* Used when creating views and sp, to avoid implicit commit */ MYSQL* util_mysql; char *name; + size_t name_len; MYSQL_STMT* stmt; #ifdef EMBEDDED_LIBRARY @@ -4436,6 +4444,7 @@ void do_connect(struct st_command *command) ds_connection_name.str)); if (!(con_slot->name= my_strdup(ds_connection_name.str, MYF(MY_WME)))) die("Out of memory"); + con_slot->name_len= strlen(con_slot->name); cur_con= con_slot; if (con_slot == next_con) @@ -6839,6 +6848,87 @@ void mark_progress(struct st_command* command __attribute__((unused)), } +static sig_handler dump_backtrace(int sig) +{ + struct st_connection *conn= cur_con; + + fprintf(stderr, "mysqltest got " SIGNAL_FMT "\n", sig); + my_safe_print_str("read_command_buf", read_command_buf, + sizeof(read_command_buf)); + if (conn) + { + my_safe_print_str("conn->name", conn->name, conn->name_len); +#ifdef EMBEDDED_LIBRARY + my_safe_print_str("conn->cur_query", conn->cur_query, conn->cur_query_len); +#endif + } + fputs("Attempting backtrace...\n", stderr); + my_print_stacktrace(NULL, my_thread_stack_size); +} + +#ifdef __WIN__ + +LONG WINAPI exception_filter(EXCEPTION_POINTERS *exp) +{ + __try + { + my_set_exception_pointers(exp); + dump_backtrace(exp->ExceptionRecord->ExceptionCode); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + fputs("Got exception in exception handler!\n", stderr); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + + +static void init_signal_handling(void) +{ + UINT mode; + + /* Set output destination of messages to the standard error stream. */ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + /* Do not not display the a error message box. */ + mode= SetErrorMode(0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX; + SetErrorMode(mode); + + SetUnhandledExceptionFilter(exception_filter); +} + +#else /* __WIN__ */ + +static void init_signal_handling(void) +{ + struct sigaction sa; + DBUG_ENTER("init_signal_handling"); + + my_init_stacktrace(); + + sa.sa_flags = SA_RESETHAND | SA_NODEFER; + sigemptyset(&sa.sa_mask); + sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); + + sa.sa_handler= dump_backtrace; + + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); +#ifdef SIGBUS + sigaction(SIGBUS, &sa, NULL); +#endif + sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); +} + +#endif /* !__WIN__ */ + int main(int argc, char **argv) { struct st_command *command; @@ -6851,6 +6941,8 @@ int main(int argc, char **argv) save_file[0]= 0; TMPDIR[0]= 0; + init_signal_handling(); + /* Init expected errors */ memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); diff --git a/configure.in b/configure.in index af23b6035eb..033cabf1875 100644 --- a/configure.in +++ b/configure.in @@ -2341,10 +2341,20 @@ then fi AC_MSG_RESULT("$netinet_inc") +AC_CACHE_CHECK([support for weak symbols], mysql_cv_weak_symbol, +[AC_TRY_LINK([],[ + extern void __attribute__((weak)) foo(void); +], [mysql_cv_weak_symbol=yes], [mysql_cv_weak_symbol=no])]) + +if test "x$mysql_cv_weak_symbol" = xyes; then + AC_DEFINE(HAVE_WEAK_SYMBOL, 1, + [Define to 1 if compiler supports weak symbol attribute.]) +fi + AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_CHECK_HEADERS(cxxabi.h) -AC_CACHE_CHECK([checking for abi::__cxa_demangle], mysql_cv_cxa_demangle, +AC_CACHE_CHECK([for abi::__cxa_demangle], mysql_cv_cxa_demangle, [AC_TRY_LINK([#include ], [ char *foo= 0; int bar= 0; foo= abi::__cxa_demangle(foo, foo, 0, &bar); diff --git a/include/Makefile.am b/include/Makefile.am index 6f3e559cb23..f04afa06cb1 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -36,7 +36,7 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \ mysql_version.h.in my_handler.h my_time.h \ my_vle.h my_user.h my_atomic.h atomic/nolock.h \ atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \ - atomic/gcc_builtins.h my_libwrap.h + atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h # Remove built files and the symlinked directories CLEANFILES = $(BUILT_SOURCES) readline openssl diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h new file mode 100644 index 00000000000..3d51ba92ee1 --- /dev/null +++ b/include/my_stacktrace.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2000 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_stacktrace_h_ +#define _my_stacktrace_h_ + +#include + +#ifdef TARGET_OS_LINUX +#if defined (__x86_64__) || defined (__i386__) || \ + (defined(__alpha__) && defined(__GNUC__)) +#define HAVE_STACKTRACE 1 +#endif +#elif defined(__WIN__) +#define HAVE_STACKTRACE 1 +#endif + +#if !defined(__NETWARE__) +#define HAVE_WRITE_CORE +#endif + +#if HAVE_BACKTRACE && HAVE_BACKTRACE_SYMBOLS && \ + HAVE_CXXABI_H && HAVE_ABI_CXA_DEMANGLE && \ + HAVE_WEAK_SYMBOL +#define BACKTRACE_DEMANGLE 1 +#endif + +C_MODE_START + +#if defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE) +void my_init_stacktrace(); +void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack); +void my_safe_print_str(const char* name, const char* val, int max_len); +void my_write_core(int sig); +#if BACKTRACE_DEMANGLE +char *my_demangle(const char *mangled_name, int *status); +#endif +#ifdef __WIN__ +void my_set_exception_pointers(EXCEPTION_POINTERS *ep); +#endif +#endif + +#ifdef HAVE_WRITE_CORE +void my_write_core(int sig); +#endif + +C_MODE_END + +#endif /* _my_stacktrace_h_ */ diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 97c718627d1..1582f0898d8 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -185,8 +185,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc - ../sql/scheduler.cc ../sql/stacktrace.c - ../sql/event_parse_data.cc + ../sql/scheduler.cc ../sql/event_parse_data.cc ${GEN_SOURCES} ${LIB_SOURCES}) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 504980cbd07..ef2fab2da6d 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -69,7 +69,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ sql_select.cc sql_do.cc sql_show.cc set_var.cc \ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ - unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ + unireg.cc uniques.cc sql_union.cc hash_filo.cc \ spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \ diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 591b76f61ad..e1c8ab5abb4 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -79,6 +79,15 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, my_bool result= 1; THD *thd=(THD *) mysql->thd; NET *net= &mysql->net; + my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE; + + if (!thd) + { + /* Do "reconnect" if possible */ + if (mysql_reconnect(mysql) || stmt_skip) + return 1; + thd= (THD *) mysql->thd; + } #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.start_new_query(); diff --git a/mysql-test/t/sql_low_priority_updates_func.test b/mysql-test/t/sql_low_priority_updates_func.test index a427adf3ad3..6ff684af6cd 100644 --- a/mysql-test/t/sql_low_priority_updates_func.test +++ b/mysql-test/t/sql_low_priority_updates_func.test @@ -19,6 +19,7 @@ # # ############################################################################### +--source include/not_embedded.inc ################################################################ # sql_low_priority_updates was renamed to low_priority_updates # diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 60e75c96b75..545278485d1 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -39,7 +39,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c - my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c + my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c) diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 1c50160c3f4..3312c692c09 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -51,7 +51,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ charset.c charset-def.c my_bitmap.c my_bit.c md5.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ my_handler.c my_netware.c my_largepage.c \ - my_memmem.c \ + my_memmem.c stacktrace.c \ my_windac.c my_access.c base64.c my_libwrap.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ thr_mutex.c thr_rwlock.c \ diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c new file mode 100644 index 00000000000..7466dcb416e --- /dev/null +++ b/mysys/stacktrace.c @@ -0,0 +1,582 @@ +/* Copyright (C) 2000 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ +#define DONT_DEFINE_VOID 1 + +#include +#include + +#ifndef __WIN__ +#include +#include +#include +#ifdef HAVE_STACKTRACE +#include +#include + +#if HAVE_EXECINFO_H +#include +#endif + +#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) + +static char *heap_start; +extern char *__bss_start; + +void my_init_stacktrace() +{ + heap_start = (char*) &__bss_start; +} + +void my_safe_print_str(const char* name, const char* val, int max_len) +{ + char *heap_end= (char*) sbrk(0); + fprintf(stderr, "%s at %p ", name, val); + + if (!PTR_SANE(val)) + { + fprintf(stderr, "is an invalid pointer\n"); + return; + } + + fprintf(stderr, "= "); + for (; max_len && PTR_SANE(val) && *val; --max_len) + fputc(*val++, stderr); + fputc('\n', stderr); +} + +#ifdef TARGET_OS_LINUX + +#ifdef __i386__ +#define SIGRETURN_FRAME_OFFSET 17 +#endif + +#ifdef __x86_64__ +#define SIGRETURN_FRAME_OFFSET 23 +#endif + +#if defined(__alpha__) && defined(__GNUC__) +/* + The only way to backtrace without a symbol table on alpha + is to find stq fp,N(sp), and the first byte + of the instruction opcode will give us the value of N. From this + we can find where the old value of fp is stored +*/ + +#define MAX_INSTR_IN_FUNC 10000 + +inline uchar** find_prev_fp(uint32* pc, uchar** fp) +{ + int i; + for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + { + uchar* p = (uchar*)pc; + if (p[2] == 222 && p[3] == 35) + { + return (uchar**)((uchar*)fp - *(short int*)p); + } + } + return 0; +} + +inline uint32* find_prev_pc(uint32* pc, uchar** fp) +{ + int i; + for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + { + char* p = (char*)pc; + if (p[1] == 0 && p[2] == 94 && p[3] == -73) + { + uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp))); + return prev_pc; + } + } + return 0; +} +#endif /* defined(__alpha__) && defined(__GNUC__) */ + +#if BACKTRACE_DEMANGLE + +char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status) +{ + return NULL; +} + +static void my_demangle_symbols(char **addrs, int n) +{ + int status, i; + char *begin, *end, *demangled; + + for (i= 0; i < n; i++) + { + demangled= NULL; + begin= strchr(addrs[i], '('); + end= begin ? strchr(begin, '+') : NULL; + + if (begin && end) + { + *begin++= *end++= '\0'; + demangled= my_demangle(begin, &status); + if (!demangled || status) + { + demangled= NULL; + begin[-1]= '('; + end[-1]= '+'; + } + } + + if (demangled) + fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); + else + fprintf(stderr, "%s\n", addrs[i]); + } +} +#endif + + +#if HAVE_BACKTRACE +static void backtrace_current_thread(void) +{ + void *addrs[128]; + char **strings= NULL; + int n = backtrace(addrs, array_elements(addrs)); +#if BACKTRACE_DEMANGLE + if ((strings= backtrace_symbols(addrs, n))) + { + my_demangle_symbols(strings, n); + free(strings); + } +#endif +#if HAVE_BACKTRACE_SYMBOLS_FD + if (!strings) + { + backtrace_symbols_fd(addrs, n, fileno(stderr)); + } +#endif +} +#endif + + +void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) +{ +#if HAVE_BACKTRACE + backtrace_current_thread(); + return; +#endif + uchar** fp; + uint frame_count = 0, sigreturn_frame_count; +#if defined(__alpha__) && defined(__GNUC__) + uint32* pc; +#endif + LINT_INIT(fp); + + +#ifdef __i386__ + __asm __volatile__ ("movl %%ebp,%0" + :"=r"(fp) + :"r"(fp)); +#endif +#ifdef __x86_64__ + __asm __volatile__ ("movq %%rbp,%0" + :"=r"(fp) + :"r"(fp)); +#endif +#if defined(__alpha__) && defined(__GNUC__) + __asm __volatile__ ("mov $30,%0" + :"=r"(fp) + :"r"(fp)); +#endif + if (!fp) + { + fprintf(stderr, "frame pointer is NULL, did you compile with\n\ +-fomit-frame-pointer? Aborting backtrace!\n"); + return; + } + + if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp) + { + ulong tmp= min(0x10000,thread_stack); + /* Assume that the stack starts at the previous even 65K */ + stack_bottom= (uchar*) (((ulong) &fp + tmp) & + ~(ulong) 0xFFFF); + fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); + } + if (fp > (uchar**) stack_bottom || + fp < (uchar**) stack_bottom - thread_stack) + { + fprintf(stderr, "Bogus stack limit or frame pointer,\ + fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", + fp, stack_bottom, thread_stack); + return; + } + + fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); +#if defined(__alpha__) && defined(__GNUC__) + fprintf(stderr, "Warning: Alpha stacks are difficult -\ + will be taking some wild guesses, stack trace may be incorrect or \ + terminate abruptly\n"); + /* On Alpha, we need to get pc */ + __asm __volatile__ ("bsr %0, do_next; do_next: " + :"=r"(pc) + :"r"(pc)); +#endif /* __alpha__ */ + + /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */ + sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1; + + while (fp < (uchar**) stack_bottom) + { +#if defined(__i386__) || defined(__x86_64__) + uchar** new_fp = (uchar**)*fp; + fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? + *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); +#endif /* defined(__386__) || defined(__x86_64__) */ + +#if defined(__alpha__) && defined(__GNUC__) + uchar** new_fp = find_prev_fp(pc, fp); + if (frame_count == sigreturn_frame_count - 1) + { + new_fp += 90; + } + + if (fp && pc) + { + pc = find_prev_pc(pc, fp); + if (pc) + fprintf(stderr, "%p\n", pc); + else + { + fprintf(stderr, "Not smart enough to deal with the rest\ + of this stack\n"); + goto end; + } + } + else + { + fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); + goto end; + } +#endif /* defined(__alpha__) && defined(__GNUC__) */ + if (new_fp <= fp ) + { + fprintf(stderr, "New value of fp=%p failed sanity check,\ + terminating stack trace!\n", new_fp); + goto end; + } + fp = new_fp; + ++frame_count; + } + + fprintf(stderr, "Stack trace seems successful - bottom reached\n"); + +end: + fprintf(stderr, + "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" + "and follow instructions on how to resolve the stack trace.\n" + "Resolved stack trace is much more helpful in diagnosing the\n" + "problem, so please do resolve it\n"); +} +#endif /* TARGET_OS_LINUX */ +#endif /* HAVE_STACKTRACE */ + +/* Produce a core for the thread */ +void my_write_core(int sig) +{ + signal(sig, SIG_DFL); +#ifdef HAVE_gcov + /* + For GCOV build, crashing will prevent the writing of code coverage + information from this process, causing gcov output to be incomplete. + So we force the writing of coverage information here before terminating. + */ + extern void __gcov_flush(void); + __gcov_flush(); +#endif + pthread_kill(pthread_self(), sig); +#if defined(P_MYID) && !defined(SCO) + /* On Solaris, the above kill is not enough */ + sigsend(P_PID,P_MYID,sig); +#endif +} + +#else /* __WIN__*/ + +#include + +/* + Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll) + We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000) + is missing some important functions like functions StackWalk64 or MinidumpWriteDump. + Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress. +*/ + +typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions); +typedef BOOL (WINAPI *SymGetModuleInfo64_FctType) + (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ; +typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ; +typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64); +typedef BOOL (WINAPI *SymInitialize_FctType) + (HANDLE,PSTR,BOOL); +typedef BOOL (WINAPI *StackWalk64_FctType) + (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 , + PTRANSLATE_ADDRESS_ROUTINE64); +typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +static SymSetOptions_FctType pSymSetOptions; +static SymGetModuleInfo64_FctType pSymGetModuleInfo64; +static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64; +static SymInitialize_FctType pSymInitialize; +static StackWalk64_FctType pStackWalk64; +static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64; +static MiniDumpWriteDump_FctType pMiniDumpWriteDump; + +static EXCEPTION_POINTERS *exception_ptrs; + +#define MODULE64_SIZE_WINXP 576 +#define STACKWALK_MAX_FRAMES 64 + +void my_init_stacktrace() +{ +} + +/* + Dynamically load dbghelp functions +*/ +BOOL init_dbghelp_functions() +{ + static BOOL first_time= TRUE; + static BOOL rc; + HMODULE hDbghlp; + + if(first_time) + { + first_time= FALSE; + hDbghlp= LoadLibrary("dbghelp"); + if(!hDbghlp) + { + rc= FALSE; + return rc; + } + pSymSetOptions= (SymSetOptions_FctType) + GetProcAddress(hDbghlp,"SymSetOptions"); + pSymInitialize= (SymInitialize_FctType) + GetProcAddress(hDbghlp,"SymInitialize"); + pSymGetModuleInfo64= (SymGetModuleInfo64_FctType) + GetProcAddress(hDbghlp,"SymGetModuleInfo64"); + pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetLineFromAddr64"); + pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetSymFromAddr64"); + pStackWalk64= (StackWalk64_FctType) + GetProcAddress(hDbghlp,"StackWalk64"); + pMiniDumpWriteDump = (MiniDumpWriteDump_FctType) + GetProcAddress(hDbghlp,"MiniDumpWriteDump"); + + rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64 + && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64); + } + return rc; +} + +void my_set_exception_pointers(EXCEPTION_POINTERS *ep) +{ + exception_ptrs = ep; +} + +/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/ +#ifndef SYMOPT_NO_PROMPTS +#define SYMOPT_NO_PROMPTS 0 +#endif + +void my_print_stacktrace(uchar* unused1, ulong unused2) +{ + HANDLE hProcess= GetCurrentProcess(); + HANDLE hThread= GetCurrentThread(); + static IMAGEHLP_MODULE64 module= {sizeof(module)}; + static IMAGEHLP_SYMBOL64_PACKAGE package; + DWORD64 addr; + DWORD machine; + int i; + CONTEXT context; + STACKFRAME64 frame={0}; + + if(!exception_ptrs || !init_dbghelp_functions()) + return; + + /* Copy context, as stackwalking on original will unwind the stack */ + context = *(exception_ptrs->ContextRecord); + /*Initialize symbols.*/ + pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); + pSymInitialize(hProcess,NULL,TRUE); + + /*Prepare stackframe for the first StackWalk64 call*/ + frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat; +#if (defined _M_IX86) + machine= IMAGE_FILE_MACHINE_I386; + frame.AddrFrame.Offset= context.Ebp; + frame.AddrPC.Offset= context.Eip; + frame.AddrStack.Offset= context.Esp; +#elif (defined _M_X64) + machine = IMAGE_FILE_MACHINE_AMD64; + frame.AddrFrame.Offset= context.Rbp; + frame.AddrPC.Offset= context.Rip; + frame.AddrStack.Offset= context.Rsp; +#else + /*There is currently no need to support IA64*/ +#pragma error ("unsupported architecture") +#endif + + package.sym.SizeOfStruct= sizeof(package.sym); + package.sym.MaxNameLength= sizeof(package.name); + + /*Walk the stack, output useful information*/ + for(i= 0; i< STACKWALK_MAX_FRAMES;i++) + { + DWORD64 function_offset= 0; + DWORD line_offset= 0; + IMAGEHLP_LINE64 line= {sizeof(line)}; + BOOL have_module= FALSE; + BOOL have_symbol= FALSE; + BOOL have_source= FALSE; + + if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0)) + break; + addr= frame.AddrPC.Offset; + + have_module= pSymGetModuleInfo64(hProcess,addr,&module); +#ifdef _M_IX86 + if(!have_module) + { + /* + ModuleInfo structure has been "compatibly" extended in releases after XP, + and its size was increased. To make XP dbghelp.dll function + happy, pretend passing the old structure. + */ + module.SizeOfStruct= MODULE64_SIZE_WINXP; + have_module= pSymGetModuleInfo64(hProcess, addr, &module); + } +#endif + + have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset, + &(package.sym)); + have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); + + fprintf(stderr, "%p ", addr); + if(have_module) + { + char *base_image_name= strrchr(module.ImageName, '\\'); + if(base_image_name) + base_image_name++; + else + base_image_name= module.ImageName; + fprintf(stderr, "%s!", base_image_name); + } + if(have_symbol) + fprintf(stderr, "%s()", package.sym.Name); + else if(have_module) + fprintf(stderr, "???"); + + if(have_source) + { + char *base_file_name= strrchr(line.FileName, '\\'); + if(base_file_name) + base_file_name++; + else + base_file_name= line.FileName; + fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); + } + fprintf(stderr, "\n"); + } + fflush(stderr); +} + + +/* + Write dump. The dump is created in current directory, + file name is constructed from executable name plus + ".dmp" extension +*/ +void my_write_core(int unused) +{ + char path[MAX_PATH]; + char dump_fname[MAX_PATH]= "core.dmp"; + MINIDUMP_EXCEPTION_INFORMATION info; + HANDLE hFile; + + if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump) + return; + + info.ExceptionPointers= exception_ptrs; + info.ClientPointers= FALSE; + info.ThreadId= GetCurrentThreadId(); + + if(GetModuleFileName(NULL, path, sizeof(path))) + { + _splitpath(path, NULL, NULL,dump_fname,NULL); + strncat(dump_fname, ".dmp", sizeof(dump_fname)); + } + + hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + if(hFile) + { + /* Create minidump */ + if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hFile, MiniDumpNormal, &info, 0, 0)) + { + fprintf(stderr, "Minidump written to %s\n", + _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); + } + else + { + fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", + GetLastError()); + } + CloseHandle(hFile); + } + else + { + fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, + GetLastError()); + } + fflush(stderr); +} + + +void my_safe_print_str(const char *name, const char *val, int len) +{ + fprintf(stderr,"%s at %p", name, val); + __try + { + fprintf(stderr,"=%.*s\n", len, val); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + fprintf(stderr,"is an invalid string pointer\n"); + } +} +#endif /*__WIN__*/ diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 128fcbeddf0..5ab29aff69c 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN -DHAVE_EVENT_SCHEDULER) ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc - discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc + discover.cc ../libmysql/errmsg.c field.cc field_conv.cc filesort.cc gstream.cc ha_partition.cc handler.cc hash_filo.cc hash_filo.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 5b5f7aa1c5d..b9de9b279a3 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -66,7 +66,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_repl.h slave.h rpl_filter.h rpl_injector.h \ log_event.h rpl_record.h \ log_event_old.h rpl_record_old.h \ - stacktrace.h sql_sort.h sql_cache.h set_var.h \ + sql_sort.h sql_cache.h set_var.h \ spatial.h gstream.h client_settings.h tzfile.h \ tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ @@ -110,7 +110,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ rpl_reporting.cc \ sql_union.cc sql_derived.cc \ sql_client.cc \ - stacktrace.c repl_failsafe.h repl_failsafe.cc \ + repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ gstream.cc spatial.cc sql_help.cc sql_cursor.cc \ tztime.cc my_decimal.cc\ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e34356215e2..0bbd0abe9b9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -22,7 +22,7 @@ #include "sql_repl.h" #include "rpl_filter.h" #include "repl_failsafe.h" -#include "stacktrace.h" +#include #include "mysqld_suffix.h" #include "mysys_err.h" #include "events.h" @@ -2049,7 +2049,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) #endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ __try { - set_exception_pointers(ex_pointers); + my_set_exception_pointers(ex_pointers); handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); } __except(EXCEPTION_EXECUTE_HANDLER) @@ -2432,8 +2432,8 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", Attempting backtrace. You can use the following information to find out\n\ where mysqld died. If you see no messages after this, something went\n\ terribly wrong...\n"); - print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0, - my_thread_stack_size); + my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, + my_thread_stack_size); } if (thd) { @@ -2457,7 +2457,7 @@ terribly wrong...\n"); } fprintf(stderr, "Trying to get some variables.\n\ Some pointers may be invalid and cause the dump to abort...\n"); - safe_print_str("thd->query", thd->query, 1024); + my_safe_print_str("thd->query", thd->query, 1024); fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); fprintf(stderr, "thd->killed=%s\n", kreason); } @@ -2504,7 +2504,7 @@ bugs.\n"); { fprintf(stderr, "Writing a core file\n"); fflush(stderr); - write_core(sig); + my_write_core(sig); } #endif @@ -2538,7 +2538,7 @@ static void init_signals(void) sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); - init_stacktrace(); + my_init_stacktrace(); #if defined(__amiga__) sa.sa_handler=(void(*)())handle_segfault; #else diff --git a/sql/stacktrace.c b/sql/stacktrace.c deleted file mode 100644 index 5c3411aa8b1..00000000000 --- a/sql/stacktrace.c +++ /dev/null @@ -1,575 +0,0 @@ -/* Copyright (C) 2000 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ -#define DONT_DEFINE_VOID 1 - -#include -#include "stacktrace.h" - -#ifndef __WIN__ -#include -#include -#include -#ifdef HAVE_STACKTRACE -#include -#include - -#if HAVE_EXECINFO_H -#include -#endif - -#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) - -char *heap_start; - -void safe_print_str(const char* name, const char* val, int max_len) -{ - char *heap_end= (char*) sbrk(0); - fprintf(stderr, "%s at %p ", name, val); - - if (!PTR_SANE(val)) - { - fprintf(stderr, " is invalid pointer\n"); - return; - } - - fprintf(stderr, "= "); - for (; max_len && PTR_SANE(val) && *val; --max_len) - fputc(*val++, stderr); - fputc('\n', stderr); -} - -#ifdef TARGET_OS_LINUX - -#ifdef __i386__ -#define SIGRETURN_FRAME_OFFSET 17 -#endif - -#ifdef __x86_64__ -#define SIGRETURN_FRAME_OFFSET 23 -#endif - -#if defined(__alpha__) && defined(__GNUC__) -/* - The only way to backtrace without a symbol table on alpha - is to find stq fp,N(sp), and the first byte - of the instruction opcode will give us the value of N. From this - we can find where the old value of fp is stored -*/ - -#define MAX_INSTR_IN_FUNC 10000 - -inline uchar** find_prev_fp(uint32* pc, uchar** fp) -{ - int i; - for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) - { - uchar* p = (uchar*)pc; - if (p[2] == 222 && p[3] == 35) - { - return (uchar**)((uchar*)fp - *(short int*)p); - } - } - return 0; -} - -inline uint32* find_prev_pc(uint32* pc, uchar** fp) -{ - int i; - for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) - { - char* p = (char*)pc; - if (p[1] == 0 && p[2] == 94 && p[3] == -73) - { - uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp))); - return prev_pc; - } - } - return 0; -} -#endif /* defined(__alpha__) && defined(__GNUC__) */ - -#if BACKTRACE_DEMANGLE -static void my_demangle_symbols(char **addrs, int n) -{ - int status, i; - char *begin, *end, *demangled; - - for (i= 0; i < n; i++) - { - demangled= NULL; - begin= strchr(addrs[i], '('); - end= begin ? strchr(begin, '+') : NULL; - - if (begin && end) - { - *begin++= *end++= '\0'; - demangled= my_demangle(begin, &status); - if (!demangled || status) - { - demangled= NULL; - begin[-1]= '('; - end[-1]= '+'; - } - } - - if (demangled) - fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); - else - fprintf(stderr, "%s\n", addrs[i]); - } -} -#endif - - -#if HAVE_BACKTRACE -static void backtrace_current_thread(void) -{ - void *addrs[128]; - char **strings= NULL; - int n = backtrace(addrs, array_elements(addrs)); -#if BACKTRACE_DEMANGLE - if ((strings= backtrace_symbols(addrs, n))) - { - my_demangle_symbols(strings, n); - free(strings); - } -#endif -#if HAVE_BACKTRACE_SYMBOLS_FD - if (!strings) - { - backtrace_symbols_fd(addrs, n, fileno(stderr)); - } -#endif -} -#endif - - -void print_stacktrace(uchar* stack_bottom, ulong thread_stack) -{ -#if HAVE_BACKTRACE - backtrace_current_thread(); - return; -#endif - uchar** fp; - uint frame_count = 0, sigreturn_frame_count; -#if defined(__alpha__) && defined(__GNUC__) - uint32* pc; -#endif - LINT_INIT(fp); - - -#ifdef __i386__ - __asm __volatile__ ("movl %%ebp,%0" - :"=r"(fp) - :"r"(fp)); -#endif -#ifdef __x86_64__ - __asm __volatile__ ("movq %%rbp,%0" - :"=r"(fp) - :"r"(fp)); -#endif -#if defined(__alpha__) && defined(__GNUC__) - __asm __volatile__ ("mov $30,%0" - :"=r"(fp) - :"r"(fp)); -#endif - if (!fp) - { - fprintf(stderr, "frame pointer is NULL, did you compile with\n\ --fomit-frame-pointer? Aborting backtrace!\n"); - return; - } - - if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp) - { - ulong tmp= min(0x10000,thread_stack); - /* Assume that the stack starts at the previous even 65K */ - stack_bottom= (uchar*) (((ulong) &fp + tmp) & - ~(ulong) 0xFFFF); - fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); - } - if (fp > (uchar**) stack_bottom || - fp < (uchar**) stack_bottom - thread_stack) - { - fprintf(stderr, "Bogus stack limit or frame pointer,\ - fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", - fp, stack_bottom, thread_stack); - return; - } - - fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); -#if defined(__alpha__) && defined(__GNUC__) - fprintf(stderr, "Warning: Alpha stacks are difficult -\ - will be taking some wild guesses, stack trace may be incorrect or \ - terminate abruptly\n"); - /* On Alpha, we need to get pc */ - __asm __volatile__ ("bsr %0, do_next; do_next: " - :"=r"(pc) - :"r"(pc)); -#endif /* __alpha__ */ - - /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */ - sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1; - - while (fp < (uchar**) stack_bottom) - { -#if defined(__i386__) || defined(__x86_64__) - uchar** new_fp = (uchar**)*fp; - fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? - *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); -#endif /* defined(__386__) || defined(__x86_64__) */ - -#if defined(__alpha__) && defined(__GNUC__) - uchar** new_fp = find_prev_fp(pc, fp); - if (frame_count == sigreturn_frame_count - 1) - { - new_fp += 90; - } - - if (fp && pc) - { - pc = find_prev_pc(pc, fp); - if (pc) - fprintf(stderr, "%p\n", pc); - else - { - fprintf(stderr, "Not smart enough to deal with the rest\ - of this stack\n"); - goto end; - } - } - else - { - fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); - goto end; - } -#endif /* defined(__alpha__) && defined(__GNUC__) */ - if (new_fp <= fp ) - { - fprintf(stderr, "New value of fp=%p failed sanity check,\ - terminating stack trace!\n", new_fp); - goto end; - } - fp = new_fp; - ++frame_count; - } - - fprintf(stderr, "Stack trace seems successful - bottom reached\n"); - -end: - fprintf(stderr, - "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); -} -#endif /* TARGET_OS_LINUX */ -#endif /* HAVE_STACKTRACE */ - -/* Produce a core for the thread */ - -#ifdef NOT_USED /* HAVE_LINUXTHREADS */ -void write_core(int sig) -{ - signal(sig, SIG_DFL); - if (fork() != 0) exit(1); /* Abort main program */ - /* Core will be written at exit */ -} -#else -void write_core(int sig) -{ - signal(sig, SIG_DFL); -#ifdef HAVE_gcov - /* - For GCOV build, crashing will prevent the writing of code coverage - information from this process, causing gcov output to be incomplete. - So we force the writing of coverage information here before terminating. - */ - extern void __gcov_flush(void); - __gcov_flush(); -#endif - pthread_kill(pthread_self(), sig); -#if defined(P_MYID) && !defined(SCO) - /* On Solaris, the above kill is not enough */ - sigsend(P_PID,P_MYID,sig); -#endif -} -#endif -#else /* __WIN__*/ - -#include - -/* - Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll) - We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000) - is missing some important functions like functions StackWalk64 or MinidumpWriteDump. - Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress. -*/ - -typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions); -typedef BOOL (WINAPI *SymGetModuleInfo64_FctType) - (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ; -typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType) - (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ; -typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType) - (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64); -typedef BOOL (WINAPI *SymInitialize_FctType) - (HANDLE,PSTR,BOOL); -typedef BOOL (WINAPI *StackWalk64_FctType) - (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64, - PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 , - PTRANSLATE_ADDRESS_ROUTINE64); -typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)( - IN HANDLE hProcess, - IN DWORD ProcessId, - IN HANDLE hFile, - IN MINIDUMP_TYPE DumpType, - IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL - IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL - IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL - ); - -static SymSetOptions_FctType pSymSetOptions; -static SymGetModuleInfo64_FctType pSymGetModuleInfo64; -static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64; -static SymInitialize_FctType pSymInitialize; -static StackWalk64_FctType pStackWalk64; -static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64; -static MiniDumpWriteDump_FctType pMiniDumpWriteDump; - -static EXCEPTION_POINTERS *exception_ptrs; - -#define MODULE64_SIZE_WINXP 576 -#define STACKWALK_MAX_FRAMES 64 - -/* - Dynamically load dbghelp functions -*/ -BOOL init_dbghelp_functions() -{ - static BOOL first_time= TRUE; - static BOOL rc; - HMODULE hDbghlp; - - if(first_time) - { - first_time= FALSE; - hDbghlp= LoadLibrary("dbghelp"); - if(!hDbghlp) - { - rc= FALSE; - return rc; - } - pSymSetOptions= (SymSetOptions_FctType) - GetProcAddress(hDbghlp,"SymSetOptions"); - pSymInitialize= (SymInitialize_FctType) - GetProcAddress(hDbghlp,"SymInitialize"); - pSymGetModuleInfo64= (SymGetModuleInfo64_FctType) - GetProcAddress(hDbghlp,"SymGetModuleInfo64"); - pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType) - GetProcAddress(hDbghlp,"SymGetLineFromAddr64"); - pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType) - GetProcAddress(hDbghlp,"SymGetSymFromAddr64"); - pStackWalk64= (StackWalk64_FctType) - GetProcAddress(hDbghlp,"StackWalk64"); - pMiniDumpWriteDump = (MiniDumpWriteDump_FctType) - GetProcAddress(hDbghlp,"MiniDumpWriteDump"); - - rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64 - && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64); - } - return rc; -} - -void set_exception_pointers(EXCEPTION_POINTERS *ep) -{ - exception_ptrs = ep; -} - -/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/ -#ifndef SYMOPT_NO_PROMPTS -#define SYMOPT_NO_PROMPTS 0 -#endif - -void print_stacktrace(uchar* unused1, ulong unused2) -{ - HANDLE hProcess= GetCurrentProcess(); - HANDLE hThread= GetCurrentThread(); - static IMAGEHLP_MODULE64 module= {sizeof(module)}; - static IMAGEHLP_SYMBOL64_PACKAGE package; - DWORD64 addr; - DWORD machine; - int i; - CONTEXT context; - STACKFRAME64 frame={0}; - - if(!exception_ptrs || !init_dbghelp_functions()) - return; - - /* Copy context, as stackwalking on original will unwind the stack */ - context = *(exception_ptrs->ContextRecord); - /*Initialize symbols.*/ - pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); - pSymInitialize(hProcess,NULL,TRUE); - - /*Prepare stackframe for the first StackWalk64 call*/ - frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat; -#if (defined _M_IX86) - machine= IMAGE_FILE_MACHINE_I386; - frame.AddrFrame.Offset= context.Ebp; - frame.AddrPC.Offset= context.Eip; - frame.AddrStack.Offset= context.Esp; -#elif (defined _M_X64) - machine = IMAGE_FILE_MACHINE_AMD64; - frame.AddrFrame.Offset= context.Rbp; - frame.AddrPC.Offset= context.Rip; - frame.AddrStack.Offset= context.Rsp; -#else - /*There is currently no need to support IA64*/ -#pragma error ("unsupported architecture") -#endif - - package.sym.SizeOfStruct= sizeof(package.sym); - package.sym.MaxNameLength= sizeof(package.name); - - /*Walk the stack, output useful information*/ - for(i= 0; i< STACKWALK_MAX_FRAMES;i++) - { - DWORD64 function_offset= 0; - DWORD line_offset= 0; - IMAGEHLP_LINE64 line= {sizeof(line)}; - BOOL have_module= FALSE; - BOOL have_symbol= FALSE; - BOOL have_source= FALSE; - - if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0)) - break; - addr= frame.AddrPC.Offset; - - have_module= pSymGetModuleInfo64(hProcess,addr,&module); -#ifdef _M_IX86 - if(!have_module) - { - /* - ModuleInfo structure has been "compatibly" extended in releases after XP, - and its size was increased. To make XP dbghelp.dll function - happy, pretend passing the old structure. - */ - module.SizeOfStruct= MODULE64_SIZE_WINXP; - have_module= pSymGetModuleInfo64(hProcess, addr, &module); - } -#endif - - have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset, - &(package.sym)); - have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); - - fprintf(stderr, "%p ", addr); - if(have_module) - { - char *base_image_name= strrchr(module.ImageName, '\\'); - if(base_image_name) - base_image_name++; - else - base_image_name= module.ImageName; - fprintf(stderr, "%s!", base_image_name); - } - if(have_symbol) - fprintf(stderr, "%s()", package.sym.Name); - else if(have_module) - fprintf(stderr, "???"); - - if(have_source) - { - char *base_file_name= strrchr(line.FileName, '\\'); - if(base_file_name) - base_file_name++; - else - base_file_name= line.FileName; - fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); - } - fprintf(stderr, "\n"); - } - fflush(stderr); -} - - -/* - Write dump. The dump is created in current directory, - file name is constructed from executable name plus - ".dmp" extension -*/ -void write_core(int unused) -{ - char path[MAX_PATH]; - char dump_fname[MAX_PATH]= "core.dmp"; - MINIDUMP_EXCEPTION_INFORMATION info; - HANDLE hFile; - - if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump) - return; - - info.ExceptionPointers= exception_ptrs; - info.ClientPointers= FALSE; - info.ThreadId= GetCurrentThreadId(); - - if(GetModuleFileName(NULL, path, sizeof(path))) - { - _splitpath(path, NULL, NULL,dump_fname,NULL); - strncat(dump_fname, ".dmp", sizeof(dump_fname)); - } - - hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, 0); - if(hFile) - { - /* Create minidump */ - if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), - hFile, MiniDumpNormal, &info, 0, 0)) - { - fprintf(stderr, "Minidump written to %s\n", - _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); - } - else - { - fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", - GetLastError()); - } - CloseHandle(hFile); - } - else - { - fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, - GetLastError()); - } - fflush(stderr); -} - - -void safe_print_str(const char *name, const char *val, int len) -{ - fprintf(stderr,"%s at %p", name, val); - __try - { - fprintf(stderr,"=%.*s\n", len, val); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - fprintf(stderr,"is an invalid string pointer\n"); - } -} -#endif /*__WIN__*/ diff --git a/sql/stacktrace.h b/sql/stacktrace.h deleted file mode 100644 index 498f4f197fc..00000000000 --- a/sql/stacktrace.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 2000 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if HAVE_BACKTRACE && HAVE_BACKTRACE_SYMBOLS && HAVE_CXXABI_H && HAVE_ABI_CXA_DEMANGLE -#define BACKTRACE_DEMANGLE 1 -#endif - -#if BACKTRACE_DEMANGLE -char *my_demangle(const char *mangled_name, int *status); -#endif - -#ifdef TARGET_OS_LINUX -#if defined(HAVE_STACKTRACE) || (defined (__x86_64__) || defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) -#undef HAVE_STACKTRACE -#define HAVE_STACKTRACE - -extern char* __bss_start; -extern char* heap_start; - -#define init_stacktrace() do { \ - heap_start = (char*) &__bss_start; \ - } while(0); -void check_thread_lib(void); -#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ -#elif defined (__WIN__) -#define HAVE_STACKTRACE -extern void set_exception_pointers(EXCEPTION_POINTERS *ep); -#define init_stacktrace() {} -#endif - -#ifdef HAVE_STACKTRACE -void print_stacktrace(uchar* stack_bottom, ulong thread_stack); -void safe_print_str(const char* name, const char* val, int max_len); -#else -/* Define empty prototypes for functions that are not implemented */ -#define init_stacktrace() {} -#define print_stacktrace(A,B) {} -#define safe_print_str(A,B,C) {} -#endif /* HAVE_STACKTRACE */ - - -#if !defined(__NETWARE__) -#define HAVE_WRITE_CORE -#endif - -#ifdef HAVE_WRITE_CORE -void write_core(int sig); -#endif - - -#ifdef __cplusplus -} -#endif -- cgit v1.2.1