2 * win32_crashrpt.c : provides information after a crash
4 * ====================================================================
5 * Copyright (c) 2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
20 #ifdef SVN_USE_WIN32_CRASHHANDLER
31 #include "svn_version.h"
33 #include "win32_crashrpt.h"
34 #include "win32_crashrpt_dll.h"
36 /*** Global variables ***/
37 HANDLE dbghelp_dll
= INVALID_HANDLE_VALUE
;
39 /* email address where the crash reports should be sent too. */
40 #define CRASHREPORT_EMAIL "svn-breakage@subversion.tigris.org"
42 #define DBGHELP_DLL "dbghelp.dll"
44 #define VERSION_DLL "version.dll"
46 #define LOGFILE_PREFIX "svn-crash-log"
50 /* Convert a wide-character string to utf-8. This function will create a buffer
51 * large enough to hold the result string, the caller should free this buffer.
52 * If the string can't be converted, NULL is returned.
55 convert_wbcs_to_utf8(const wchar_t *str
)
57 size_t len
= wcslen(str
);
58 char *utf8_str
= malloc(sizeof(wchar_t) * len
+ 1);
59 len
= wcstombs(utf8_str
, str
, len
);
69 /* Convert the exception code to a string */
71 exception_string(int exception
)
73 #define EXCEPTION(x) case EXCEPTION_##x: return (#x);
77 EXCEPTION(ACCESS_VIOLATION
)
78 EXCEPTION(DATATYPE_MISALIGNMENT
)
80 EXCEPTION(SINGLE_STEP
)
81 EXCEPTION(ARRAY_BOUNDS_EXCEEDED
)
82 EXCEPTION(FLT_DENORMAL_OPERAND
)
83 EXCEPTION(FLT_DIVIDE_BY_ZERO
)
84 EXCEPTION(FLT_INEXACT_RESULT
)
85 EXCEPTION(FLT_INVALID_OPERATION
)
86 EXCEPTION(FLT_OVERFLOW
)
87 EXCEPTION(FLT_STACK_CHECK
)
88 EXCEPTION(FLT_UNDERFLOW
)
89 EXCEPTION(INT_DIVIDE_BY_ZERO
)
90 EXCEPTION(INT_OVERFLOW
)
91 EXCEPTION(PRIV_INSTRUCTION
)
92 EXCEPTION(IN_PAGE_ERROR
)
93 EXCEPTION(ILLEGAL_INSTRUCTION
)
94 EXCEPTION(NONCONTINUABLE_EXCEPTION
)
95 EXCEPTION(STACK_OVERFLOW
)
96 EXCEPTION(INVALID_DISPOSITION
)
98 EXCEPTION(INVALID_HANDLE
)
101 return "UNKNOWN_ERROR";
106 /* Write the minidump to file. The callback function will at the same time
107 write the list of modules to the log file. */
109 write_minidump_file(const char *file
, PEXCEPTION_POINTERS ptrs
,
110 MINIDUMP_CALLBACK_ROUTINE module_callback
,
113 /* open minidump file */
114 HANDLE minidump_file
= CreateFile(file
, GENERIC_WRITE
, 0, NULL
,
116 FILE_ATTRIBUTE_NORMAL
,
119 if (minidump_file
!= INVALID_HANDLE_VALUE
)
121 MINIDUMP_EXCEPTION_INFORMATION expt_info
;
122 MINIDUMP_CALLBACK_INFORMATION dump_cb_info
;
124 expt_info
.ThreadId
= GetCurrentThreadId();
125 expt_info
.ExceptionPointers
= ptrs
;
126 expt_info
.ClientPointers
= FALSE
;
128 dump_cb_info
.CallbackRoutine
= module_callback
;
129 dump_cb_info
.CallbackParam
= data
;
131 MiniDumpWriteDump_(GetCurrentProcess(),
132 GetCurrentProcessId(),
135 ptrs
? &expt_info
: NULL
,
139 CloseHandle(minidump_file
);
146 /* Write module information to the log file */
148 write_module_info_callback(void *data
,
149 CONST PMINIDUMP_CALLBACK_INPUT callback_input
,
150 PMINIDUMP_CALLBACK_OUTPUT callback_output
)
153 callback_input
!= NULL
&&
154 callback_input
->CallbackType
== ModuleCallback
)
156 FILE *log_file
= (FILE *)data
;
157 MINIDUMP_MODULE_CALLBACK module
= callback_input
->Module
;
159 char *buf
= convert_wbcs_to_utf8(module
.FullPath
);
160 fprintf(log_file
, "0x%08x", module
.BaseOfImage
);
161 fprintf(log_file
, " %s", buf
);
164 fprintf(log_file
, " (%d.%d.%d.%d, %d bytes)\n",
165 HIWORD(module
.VersionInfo
.dwFileVersionMS
),
166 LOWORD(module
.VersionInfo
.dwFileVersionMS
),
167 HIWORD(module
.VersionInfo
.dwFileVersionLS
),
168 LOWORD(module
.VersionInfo
.dwFileVersionLS
),
175 /* Write details about the current process, platform and the exception */
177 write_process_info(EXCEPTION_RECORD
*exception
, CONTEXT
*context
,
181 const char *cmd_line
;
183 /* write the command line */
184 cmd_line
= GetCommandLine();
186 "Cmd line: %.65s\n", cmd_line
);
188 /* write the svn version number info. */
190 "Version: %s, compiled %s, %s\n",
191 SVN_VERSION
, __DATE__
, __TIME__
);
193 /* write information about the OS */
194 oi
.dwOSVersionInfoSize
= sizeof(oi
);
198 "Platform: Windows OS version %d.%d build %d %s\n\n",
199 oi
.dwMajorVersion
, oi
.dwMinorVersion
, oi
.dwBuildNumber
,
202 /* write the exception code */
205 exception_string(exception
->ExceptionCode
));
207 /* write the register info. */
212 "eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n",
213 context
->Eax
, context
->Ebx
, context
->Ecx
,
214 context
->Edx
, context
->Esi
, context
->Edi
);
216 "eip=%08x esp=%08x ebp=%08x efl=%08x\n",
217 context
->Eip
, context
->Esp
,
218 context
->Ebp
, context
->EFlags
);
220 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x\n",
221 context
->SegCs
, context
->SegSs
, context
->SegDs
,
222 context
->SegEs
, context
->SegFs
, context
->SegGs
);
223 #elif defined(_M_X64)
225 "Rax=%016I64x Rcx=%016I64x Rdx=%016I64x Rbx=%016I64x\n",
226 context
->Rax
, context
->Rcx
, context
->Rdx
, context
->Rbx
);
228 "Rsp=%016I64x Rbp=%016I64x Rsi=%016I64x Rdi=%016I64x\n",
229 context
->Rsp
, context
->Rbp
, context
->Rsi
, context
->Rdi
);
231 "R8= %016I64x R9= %016I64x R10= %016I64x R11=%016I64x\n",
232 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
234 "R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\n",
235 context
->R12
, context
->R13
, context
->R14
, context
->R15
);
238 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\n",
239 context
->SegCs
, context
->SegDs
, context
->SegEs
,
240 context
->SegFs
, context
->SegGs
, context
->SegSs
);
242 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
246 /* formats the value at address based on the specified basic type
247 * (char, int, long ...). */
249 format_basic_type(char *buf
, DWORD basic_type
, DWORD64 length
, void *address
)
254 sprintf(buf
, "%x", *(unsigned char *)address
);
257 sprintf(buf
, "%x", *(unsigned short *)address
);
264 if (!IsBadStringPtr(*(PSTR
*)address
, 32))
265 sprintf(buf
, "\"%.31s\"", *(unsigned long *)address
);
267 sprintf(buf
, "%x", *(unsigned long *)address
);
270 sprintf(buf
, "%d", *(int *)address
);
272 case 8: /* btFloat */
273 sprintf(buf
, "%f", *(float *)address
);
276 sprintf(buf
, "%x", *(unsigned long *)address
);
281 if (basic_type
== 8) /* btFloat */
282 sprintf(buf
, "%lf", *(double *)address
);
284 sprintf(buf
, "%I64X", *(unsigned __int64
*)address
);
289 /* formats the value at address based on the type (pointer, user defined,
292 format_value(char *value_str
, DWORD64 mod_base
, DWORD type
, void *value_addr
)
296 HANDLE proc
= GetCurrentProcess();
298 while (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_SYMTAG
, &tag
))
300 /* SymTagPointerType */
304 SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_TYPE
, &type
);
312 case 11: /* SymTagUDT */
314 WCHAR
*type_name_wbcs
;
315 if (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_SYMNAME
,
318 char *type_name
= convert_wbcs_to_utf8(type_name_wbcs
);
319 LocalFree(type_name_wbcs
);
322 sprintf(value_str
, "(%s) 0x%08x",
323 type_name
, (DWORD
*)value_addr
);
325 sprintf(value_str
, "(%s *) 0x%08x",
326 type_name
, *(DWORD
*)value_addr
);
328 sprintf(value_str
, "(%s **) 0x%08x",
329 type_name
, (DWORD
*)value_addr
);
335 case 16: /* SymTagBaseType */
339 SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_LENGTH
, &length
);
341 /* print a char * as a string */
342 if (ptr
== 1 && length
== 1)
344 sprintf(value_str
, "0x%08x \"%s\"",
345 *(DWORD
*)value_addr
, (char *)*(DWORD
*)value_addr
);
350 sprintf(value_str
, "0x%08x", *(DWORD
*)value_addr
);
353 if (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_BASETYPE
, &bt
))
355 format_basic_type(value_str
, bt
, length
, value_addr
);
360 case 12: /* SymTagEnum */
361 sprintf(value_str
, "%d", *(DWORD
*)value_addr
);
363 case 13: /* SymTagFunctionType */
364 sprintf(value_str
, "0x%08x", *(DWORD
*)value_addr
);
370 /* Internal structure used to pass some data to the enumerate symbols
373 STACKFRAME64
*stack_frame
;
379 /* write the details of one parameter or local variable to the log file */
381 write_var_values(PSYMBOL_INFO sym_info
, ULONG sym_size
, void *baton
)
383 static int last_nr_of_frame
= 0;
384 DWORD_PTR var_data
= 0; /* Will point to the variable's data in memory */
385 STACKFRAME64
*stack_frame
= ((symbols_baton_t
*)baton
)->stack_frame
;
386 FILE *log_file
= ((symbols_baton_t
*)baton
)->log_file
;
387 int nr_of_frame
= ((symbols_baton_t
*)baton
)->nr_of_frame
;
388 BOOL log_params
= ((symbols_baton_t
*)baton
)->log_params
;
389 char value_str
[256] = "";
391 /* get the variable's data */
392 if (sym_info
->Flags
& SYMFLAG_REGREL
)
394 var_data
= (DWORD_PTR
)stack_frame
->AddrFrame
.Offset
;
395 var_data
+= (DWORD_PTR
)sym_info
->Address
;
400 if (log_params
== TRUE
&& sym_info
->Flags
& SYMFLAG_PARAMETER
)
402 if (last_nr_of_frame
== nr_of_frame
)
403 fprintf(log_file
, ", ", 2);
405 last_nr_of_frame
= nr_of_frame
;
407 format_value(value_str
, sym_info
->ModBase
, sym_info
->TypeIndex
,
409 fprintf(log_file
, "%s=%s", sym_info
->Name
, value_str
);
411 if (log_params
== FALSE
&& sym_info
->Flags
& SYMFLAG_LOCAL
)
413 format_value(value_str
, sym_info
->ModBase
, sym_info
->TypeIndex
,
415 fprintf(log_file
, " %s = %s\n", sym_info
->Name
, value_str
);
421 /* write the details of one function to the log file */
423 write_function_detail(STACKFRAME64 stack_frame
, void *data
)
425 ULONG64 symbolBuffer
[(sizeof(SYMBOL_INFO
) +
427 sizeof(ULONG64
) - 1) /
429 PSYMBOL_INFO pIHS
= (PSYMBOL_INFO
)symbolBuffer
;
432 IMAGEHLP_STACK_FRAME ih_stack_frame
;
433 IMAGEHLP_LINE64 ih_line
;
436 HANDLE proc
= GetCurrentProcess();
437 FILE *log_file
= (FILE *)data
;
439 symbols_baton_t ensym
;
441 static int nr_of_frame
= 0;
445 /* log the function name */
446 pIHS
->SizeOfStruct
= sizeof(SYMBOL_INFO
);
447 pIHS
->MaxNameLen
= MAX_PATH
;
448 if (SymFromAddr_(proc
, stack_frame
.AddrPC
.Offset
, &func_disp
, pIHS
) == TRUE
)
451 "#%d 0x%08x in %.200s (",
452 nr_of_frame
, stack_frame
.AddrPC
.Offset
, pIHS
->Name
);
454 /* restrict symbol enumeration to this frame only */
455 ih_stack_frame
.InstructionOffset
= stack_frame
.AddrPC
.Offset
;
456 SymSetContext_(proc
, &ih_stack_frame
, 0);
458 ensym
.log_file
= log_file
;
459 ensym
.stack_frame
= &stack_frame
;
460 ensym
.nr_of_frame
= nr_of_frame
;
462 /* log all function parameters */
463 ensym
.log_params
= TRUE
;
464 SymEnumSymbols_(proc
, 0, 0, write_var_values
, &ensym
);
466 fprintf(log_file
, ")");
471 "#%d 0x%08x in (unknown function)",
472 nr_of_frame
, stack_frame
.AddrPC
.Offset
);
475 /* find the source line for this function. */
476 ih_line
.SizeOfStruct
= sizeof(IMAGEHLP_LINE
);
477 if (SymGetLineFromAddr64_(proc
, stack_frame
.AddrPC
.Offset
,
478 &line_disp
, &ih_line
) != 0)
481 " at %s:%d\n", ih_line
.FileName
, ih_line
.LineNumber
);
485 fprintf(log_file
, "\n");
488 /* log all function local variables */
489 ensym
.log_params
= FALSE
;
490 SymEnumSymbols_(proc
, 0, 0, write_var_values
, &ensym
);
493 /* walk over the stack and log all relevant information to the log file */
495 write_stacktrace(CONTEXT
*context
, FILE *log_file
)
497 #if defined (_M_IX86) || defined(_M_X64) || defined(_M_IA64)
498 HANDLE proc
= GetCurrentProcess();
499 STACKFRAME64 stack_frame
;
504 /* The thread information - if not supplied. */
507 /* If no context is supplied, skip 1 frame */
510 ctx
.ContextFlags
= CONTEXT_FULL
;
511 if (GetThreadContext(GetCurrentThread(), &ctx
))
518 /* Write the stack trace */
519 ZeroMemory(&stack_frame
, sizeof(STACKFRAME64
));
520 stack_frame
.AddrPC
.Mode
= AddrModeFlat
;
521 stack_frame
.AddrStack
.Mode
= AddrModeFlat
;
522 stack_frame
.AddrFrame
.Mode
= AddrModeFlat
;
525 machine
= IMAGE_FILE_MACHINE_I386
;
526 stack_frame
.AddrPC
.Offset
= context
->Eip
;
527 stack_frame
.AddrStack
.Offset
= context
->Esp
;
528 stack_frame
.AddrFrame
.Offset
= context
->Ebp
;
529 #elif defined(_M_X64)
530 machine
= IMAGE_FILE_MACHINE_AMD64
;
531 stack_frame
.AddrPC
.Offset
= context
->Rip
;
532 stack_frame
.AddrStack
.Offset
= context
->Rsp
;
533 stack_frame
.AddrFrame
.Offset
= context
->Rbp
;
534 #elif defined(_M_IA64)
535 machine
= IMAGE_FILE_MACHINE_IA64
;
536 stack_frame
.AddrPC
.Offset
= context
->StIIP
;
537 stack_frame
.AddrStack
.Offset
= context
->SP
;
538 stack_frame
.AddrBStore
.Mode
= AddrModeFlat
;
539 stack_frame
.AddrBStore
.Offset
= context
->RsBSP
;
541 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
546 if (! StackWalk64_(machine
, proc
, GetCurrentThread(),
547 &stack_frame
, context
, NULL
,
548 SymFunctionTableAccess64_
, SymGetModuleBase64_
, NULL
))
555 /* Try to include symbolic information.
556 Also check that the address is not zero. Sometimes StackWalk
557 returns TRUE with a frame of zero. */
558 if (stack_frame
.AddrPC
.Offset
!= 0)
560 write_function_detail(stack_frame
, (void *)log_file
);
566 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
570 /* Check if a debugger is attached to this process */
572 is_debugger_present()
574 HANDLE kernel32_dll
= LoadLibrary("kernel32.dll");
577 ISDEBUGGERPRESENT IsDebuggerPresent_
=
578 (ISDEBUGGERPRESENT
)GetProcAddress(kernel32_dll
, "IsDebuggerPresent");
580 if (IsDebuggerPresent_
&& IsDebuggerPresent_())
585 FreeLibrary(kernel32_dll
);
590 /* Match the version of dbghelp.dll with the minimum expected version */
592 check_dbghelp_version(WORD exp_major
, WORD exp_minor
, WORD exp_build
,
595 HANDLE version_dll
= LoadLibrary(VERSION_DLL
);
596 GETFILEVERSIONINFOSIZE GetFileVersionInfoSize_
=
597 (GETFILEVERSIONINFOSIZE
)GetProcAddress(version_dll
,
598 "GetFileVersionInfoSizeA");
599 GETFILEVERSIONINFO GetFileVersionInfo_
=
600 (GETFILEVERSIONINFO
)GetProcAddress(version_dll
,
601 "GetFileVersionInfoA");
602 VERQUERYVALUE VerQueryValue_
=
603 (VERQUERYVALUE
)GetProcAddress(version_dll
, "VerQueryValueA");
606 exp_version
= MAKELONG(MAKEWORD(exp_qfe
, exp_build
),
607 MAKEWORD(exp_minor
, exp_major
));
609 DWORD resource_size
= GetFileVersionInfoSize_(DBGHELP_DLL
, &h
);
613 void *resource_data
= malloc(resource_size
);
614 if (GetFileVersionInfo_(DBGHELP_DLL
, h
, resource_size
,
615 resource_data
) != FALSE
)
619 if (VerQueryValue_(resource_data
, "\\", &buf
, &len
))
621 VS_FIXEDFILEINFO
*info
= (VS_FIXEDFILEINFO
*)buf
;
622 version
= MAKELONG(MAKEWORD(LOWORD(info
->dwFileVersionLS
),
623 HIWORD(info
->dwFileVersionLS
)),
624 MAKEWORD(LOWORD(info
->dwFileVersionMS
),
625 HIWORD(info
->dwFileVersionMS
)));
631 FreeLibrary(version_dll
);
633 if (version
>= exp_version
)
639 /* Load the dbghelp.dll file, try to find a version that matches our
644 /* check version of the dll, should be at least 6.6.7.5 */
645 if (check_dbghelp_version(6, 6, 7, 5) == FALSE
)
648 dbghelp_dll
= LoadLibrary(DBGHELP_DLL
);
649 if (dbghelp_dll
!= INVALID_HANDLE_VALUE
)
653 /* load the functions */
655 (MINIDUMPWRITEDUMP
)GetProcAddress(dbghelp_dll
, "MiniDumpWriteDump");
657 (SYMINITIALIZE
)GetProcAddress(dbghelp_dll
, "SymInitialize");
659 (SYMSETOPTIONS
)GetProcAddress(dbghelp_dll
, "SymSetOptions");
661 (SYMGETOPTIONS
)GetProcAddress(dbghelp_dll
, "SymGetOptions");
663 (SYMCLEANUP
)GetProcAddress(dbghelp_dll
, "SymCleanup");
665 (SYMGETTYPEINFO
)GetProcAddress(dbghelp_dll
, "SymGetTypeInfo");
666 SymGetLineFromAddr64_
=
667 (SYMGETLINEFROMADDR64
)GetProcAddress(dbghelp_dll
,
668 "SymGetLineFromAddr64");
670 (SYMENUMSYMBOLS
)GetProcAddress(dbghelp_dll
, "SymEnumSymbols");
672 (SYMSETCONTEXT
)GetProcAddress(dbghelp_dll
, "SymSetContext");
673 SymFromAddr_
= (SYMFROMADDR
)GetProcAddress(dbghelp_dll
, "SymFromAddr");
674 StackWalk64_
= (STACKWALK64
)GetProcAddress(dbghelp_dll
, "StackWalk64");
675 SymFunctionTableAccess64_
=
676 (SYMFUNCTIONTABLEACCESS64
)GetProcAddress(dbghelp_dll
,
677 "SymFunctionTableAccess64");
678 SymGetModuleBase64_
=
679 (SYMGETMODULEBASE64
)GetProcAddress(dbghelp_dll
, "SymGetModuleBase64");
681 if (! (MiniDumpWriteDump_
&&
682 SymInitialize_
&& SymSetOptions_
&& SymGetOptions_
&&
683 SymCleanup_
&& SymGetTypeInfo_
&& SymGetLineFromAddr64_
&&
684 SymEnumSymbols_
&& SymSetContext_
&& SymFromAddr_
&&
685 SymGetModuleBase64_
&& StackWalk64_
&&
686 SymFunctionTableAccess64_
))
689 /* initialize the symbol loading code */
690 opts
= SymGetOptions_();
692 /* Set the 'load lines' option to retrieve line number information;
693 set the Deferred Loads option to map the debug info in memory only
695 SymSetOptions_(opts
| SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
);
697 /* Initialize the debughlp DLL with the default path and automatic
698 module enumeration (and loading of symbol tables) for this process.
700 SymInitialize_(GetCurrentProcess(), NULL
, TRUE
);
707 FreeLibrary(dbghelp_dll
);
712 /* Cleanup the dbghelp.dll library */
716 SymCleanup_(GetCurrentProcess());
718 FreeLibrary(dbghelp_dll
);
721 /* Create a filename based on a prefix, the timestamp and an extension.
722 check if the filename was already taken, retry 3 times. */
724 get_temp_filename(char *filename
, const char *prefix
, const char *ext
)
726 char temp_dir
[MAX_PATH
- 64];
729 if (! GetTempPath(MAX_PATH
- 64, temp_dir
))
732 for (i
= 0;i
< 3;i
++)
739 strftime(time_str
, 64, "%Y%m%d%H%M%S", localtime(&now
));
740 sprintf(filename
, "%s%s%s.%s", temp_dir
, prefix
, time_str
, ext
);
742 file
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
743 FILE_ATTRIBUTE_NORMAL
, NULL
);
744 if (file
!= INVALID_HANDLE_VALUE
)
755 /* unhandled exception callback set with SetUnhandledExceptionFilter() */
757 svn__unhandled_exception_filter(PEXCEPTION_POINTERS ptrs
)
759 char dmp_filename
[MAX_PATH
];
760 char log_filename
[MAX_PATH
];
763 /* Check if the crash handler was already loaded (crash while handling the
765 if (dbghelp_dll
!= INVALID_HANDLE_VALUE
)
766 return EXCEPTION_CONTINUE_SEARCH
;
768 /* don't log anything if we're running inside a debugger ... */
769 if (is_debugger_present() == TRUE
)
770 return EXCEPTION_CONTINUE_SEARCH
;
772 /* ... or if we can't create the log files ... */
773 if (get_temp_filename(dmp_filename
, LOGFILE_PREFIX
, "dmp") == FALSE
||
774 get_temp_filename(log_filename
, LOGFILE_PREFIX
, "log") == FALSE
)
775 return EXCEPTION_CONTINUE_SEARCH
;
777 /* If we can't load a recent version of the dbghelp.dll, pass on this
779 if (load_dbghelp_dll() == FALSE
)
780 return EXCEPTION_CONTINUE_SEARCH
;
783 log_file
= fopen(log_filename
, "w+");
785 /* write information about the process */
786 fprintf(log_file
, "\nProcess info:\n");
787 write_process_info(ptrs
? ptrs
->ExceptionRecord
: NULL
,
788 ptrs
? ptrs
->ContextRecord
: NULL
,
791 /* write the stacktrace, if available */
792 fprintf(log_file
, "\nStacktrace:\n");
793 write_stacktrace(ptrs
? ptrs
->ContextRecord
: NULL
, log_file
);
795 /* write the minidump file and use the callback to write the list of modules
797 fprintf(log_file
, "\n\nLoaded modules:\n");
798 write_minidump_file(dmp_filename
, ptrs
,
799 write_module_info_callback
, (void *)log_file
);
805 /* inform the user */
806 fprintf(stderr
, "This application has halted due to an unexpected error.\n"
807 "A crash report and minidump file were saved to disk, you"
808 " can find them here:\n"
810 "Please send the log file to %s to help us analyse\nand "
811 "solve this problem.\n\n"
812 "NOTE: The crash report and minidump files can contain some"
813 " sensitive information\n(filenames, partial file content, "
814 "usernames and passwords etc.)\n",
819 /* terminate the application */
820 return EXCEPTION_EXECUTE_HANDLER
;
822 #endif /* SVN_USE_WIN32_CRASHHANDLER */