summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorDavi Arnaut <davi@mysql.com>2008-06-18 13:17:15 -0300
committerDavi Arnaut <davi@mysql.com>2008-06-18 13:17:15 -0300
commitfb8f32d0774876f79f7e3d9aa714c0ecb67adaca (patch)
treec6c8cd49b083e116e49ce10a1c7c3a63ac5eafa9 /mysys
parent5d237db6f6719e7a1132bdb664ac2206c7bb8a9b (diff)
downloadmariadb-git-fb8f32d0774876f79f7e3d9aa714c0ecb67adaca.tar.gz
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.
Diffstat (limited to 'mysys')
-rwxr-xr-xmysys/CMakeLists.txt2
-rw-r--r--mysys/Makefile.am2
-rw-r--r--mysys/stacktrace.c582
3 files changed, 584 insertions, 2 deletions
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 <my_global.h>
+#include <my_stacktrace.h>
+
+#ifndef __WIN__
+#include <signal.h>
+#include <my_pthread.h>
+#include <m_string.h>
+#ifdef HAVE_STACKTRACE
+#include <unistd.h>
+#include <strings.h>
+
+#if HAVE_EXECINFO_H
+#include <execinfo.h>
+#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 <dbghelp.h>
+
+/*
+ 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__*/