2 * win32_crashrpt.c : provides information after a crash
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 /* prevent "empty compilation unit" warning on e.g. UNIX */
25 typedef int win32_crashrpt__dummy
;
28 #ifdef SVN_USE_WIN32_CRASHHANDLER
38 #include "svn_version.h"
42 #include "win32_crashrpt.h"
43 #include "win32_crashrpt_dll.h"
45 /*** Global variables ***/
46 static HANDLE dbghelp_dll
= INVALID_HANDLE_VALUE
;
48 #define DBGHELP_DLL "dbghelp.dll"
50 #define LOGFILE_PREFIX "svn-crash-log"
53 #define FORMAT_PTR "0x%08Ix"
55 #define FORMAT_PTR "0x%016Ix"
60 /* Convert a wide-character string to the current windows locale, suitable
61 * for directly using stdio. This function will create a buffer large
62 * enough to hold the result string, the caller should free this buffer.
63 * If the string can't be converted, NULL is returned.
66 convert_wbcs_to_ansi(const wchar_t *str
)
68 size_t len
= wcslen(str
);
69 char *utf8_str
= malloc(sizeof(wchar_t) * len
+ 1);
70 len
= wcstombs(utf8_str
, str
, len
);
80 /* Convert the exception code to a string */
82 exception_string(int exception
)
84 #define EXCEPTION(x) case x: return (#x);
88 EXCEPTION(EXCEPTION_ACCESS_VIOLATION
)
89 EXCEPTION(EXCEPTION_DATATYPE_MISALIGNMENT
)
90 EXCEPTION(EXCEPTION_BREAKPOINT
)
91 EXCEPTION(EXCEPTION_SINGLE_STEP
)
92 EXCEPTION(EXCEPTION_ARRAY_BOUNDS_EXCEEDED
)
93 EXCEPTION(EXCEPTION_FLT_DENORMAL_OPERAND
)
94 EXCEPTION(EXCEPTION_FLT_DIVIDE_BY_ZERO
)
95 EXCEPTION(EXCEPTION_FLT_INEXACT_RESULT
)
96 EXCEPTION(EXCEPTION_FLT_INVALID_OPERATION
)
97 EXCEPTION(EXCEPTION_FLT_OVERFLOW
)
98 EXCEPTION(EXCEPTION_FLT_STACK_CHECK
)
99 EXCEPTION(EXCEPTION_FLT_UNDERFLOW
)
100 EXCEPTION(EXCEPTION_INT_DIVIDE_BY_ZERO
)
101 EXCEPTION(EXCEPTION_INT_OVERFLOW
)
102 EXCEPTION(EXCEPTION_PRIV_INSTRUCTION
)
103 EXCEPTION(EXCEPTION_IN_PAGE_ERROR
)
104 EXCEPTION(EXCEPTION_ILLEGAL_INSTRUCTION
)
105 EXCEPTION(EXCEPTION_NONCONTINUABLE_EXCEPTION
)
106 EXCEPTION(EXCEPTION_STACK_OVERFLOW
)
107 EXCEPTION(EXCEPTION_INVALID_DISPOSITION
)
108 EXCEPTION(EXCEPTION_GUARD_PAGE
)
109 EXCEPTION(EXCEPTION_INVALID_HANDLE
)
110 EXCEPTION(STATUS_NO_MEMORY
)
113 return "UNKNOWN_ERROR";
118 /* Write the minidump to file. The callback function will at the same time
119 write the list of modules to the log file. */
121 write_minidump_file(const char *file
, PEXCEPTION_POINTERS ptrs
,
122 MINIDUMP_CALLBACK_ROUTINE module_callback
,
125 /* open minidump file */
126 HANDLE minidump_file
= CreateFile(file
, GENERIC_WRITE
, 0, NULL
,
128 FILE_ATTRIBUTE_NORMAL
,
131 if (minidump_file
!= INVALID_HANDLE_VALUE
)
133 MINIDUMP_EXCEPTION_INFORMATION expt_info
;
134 MINIDUMP_CALLBACK_INFORMATION dump_cb_info
;
136 expt_info
.ThreadId
= GetCurrentThreadId();
137 expt_info
.ExceptionPointers
= ptrs
;
138 expt_info
.ClientPointers
= FALSE
;
140 dump_cb_info
.CallbackRoutine
= module_callback
;
141 dump_cb_info
.CallbackParam
= data
;
143 MiniDumpWriteDump_(GetCurrentProcess(),
144 GetCurrentProcessId(),
147 ptrs
? &expt_info
: NULL
,
151 CloseHandle(minidump_file
);
158 /* Write module information to the log file */
160 write_module_info_callback(void *data
,
161 CONST PMINIDUMP_CALLBACK_INPUT callback_input
,
162 PMINIDUMP_CALLBACK_OUTPUT callback_output
)
165 callback_input
!= NULL
&&
166 callback_input
->CallbackType
== ModuleCallback
)
168 FILE *log_file
= (FILE *)data
;
169 MINIDUMP_MODULE_CALLBACK module
= callback_input
->Module
;
171 char *buf
= convert_wbcs_to_ansi(module
.FullPath
);
172 fprintf(log_file
, FORMAT_PTR
, (UINT_PTR
)module
.BaseOfImage
);
173 fprintf(log_file
, " %s", buf
);
176 fprintf(log_file
, " (%d.%d.%d.%d, %d bytes)\n",
177 HIWORD(module
.VersionInfo
.dwFileVersionMS
),
178 LOWORD(module
.VersionInfo
.dwFileVersionMS
),
179 HIWORD(module
.VersionInfo
.dwFileVersionLS
),
180 LOWORD(module
.VersionInfo
.dwFileVersionLS
),
187 /* Write details about the current process, platform and the exception */
189 write_process_info(EXCEPTION_RECORD
*exception
, CONTEXT
*context
,
193 const char *cmd_line
;
194 char workingdir
[8192];
196 /* write the command line */
197 cmd_line
= GetCommandLine();
199 "Cmd line: %s\n", cmd_line
);
201 _getcwd(workingdir
, sizeof(workingdir
));
203 "Working Dir: %s\n", workingdir
);
205 /* write the svn version number info. */
207 "Version: %s, compiled %s, %s\n",
208 SVN_VERSION
, __DATE__
, __TIME__
);
210 /* write information about the OS */
211 if (svn_sysinfo___fill_windows_version(&oi
))
213 "Platform: Windows OS version %d.%d build %d %S\n\n",
214 oi
.dwMajorVersion
, oi
.dwMinorVersion
, oi
.dwBuildNumber
,
217 /* write the exception code */
220 exception_string(exception
->ExceptionCode
));
222 /* write the register info. */
227 "eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n",
228 context
->Eax
, context
->Ebx
, context
->Ecx
,
229 context
->Edx
, context
->Esi
, context
->Edi
);
231 "eip=%08x esp=%08x ebp=%08x efl=%08x\n",
232 context
->Eip
, context
->Esp
,
233 context
->Ebp
, context
->EFlags
);
235 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x\n",
236 context
->SegCs
, context
->SegSs
, context
->SegDs
,
237 context
->SegEs
, context
->SegFs
, context
->SegGs
);
238 #elif defined(_M_X64)
240 "Rax=%016I64x Rcx=%016I64x Rdx=%016I64x Rbx=%016I64x\n",
241 context
->Rax
, context
->Rcx
, context
->Rdx
, context
->Rbx
);
243 "Rsp=%016I64x Rbp=%016I64x Rsi=%016I64x Rdi=%016I64x\n",
244 context
->Rsp
, context
->Rbp
, context
->Rsi
, context
->Rdi
);
246 "R8= %016I64x R9= %016I64x R10=%016I64x R11=%016I64x\n",
247 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
249 "R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\n",
250 context
->R12
, context
->R13
, context
->R14
, context
->R15
);
253 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x\n",
254 context
->SegCs
, context
->SegSs
, context
->SegDs
,
255 context
->SegEs
, context
->SegFs
, context
->SegGs
);
257 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
261 /* Writes the value at address based on the specified basic type
262 * (char, int, long ...) to LOG_FILE. */
264 write_basic_type(FILE *log_file
, DWORD basic_type
, DWORD64 length
,
270 fprintf(log_file
, "0x%02x", (int)*(unsigned char *)address
);
273 fprintf(log_file
, "0x%04x", (int)*(unsigned short *)address
);
280 if (!IsBadStringPtr(*(PSTR
*)address
, 32))
281 fprintf(log_file
, "\"%.31s\"", *(const char **)address
);
283 fprintf(log_file
, FORMAT_PTR
, *(DWORD_PTR
*)address
);
286 fprintf(log_file
, "%d", *(int *)address
);
288 case 8: /* btFloat */
289 fprintf(log_file
, "%f", *(float *)address
);
292 fprintf(log_file
, FORMAT_PTR
, *(DWORD_PTR
*)address
);
297 if (basic_type
== 8) /* btFloat */
298 fprintf(log_file
, "%lf", *(double *)address
);
300 fprintf(log_file
, "0x%016I64X", *(unsigned __int64
*)address
);
303 fprintf(log_file
, "[unhandled type 0x%08x of length " FORMAT_PTR
"]",
304 basic_type
, (UINT_PTR
)length
);
309 /* Writes the value at address based on the type (pointer, user defined,
310 * basic type) to LOG_FILE. */
312 write_value(FILE *log_file
, DWORD64 mod_base
, DWORD type
, void *value_addr
)
316 HANDLE proc
= GetCurrentProcess();
318 while (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_SYMTAG
, &tag
))
320 /* SymTagPointerType */
324 SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_TYPE
, &type
);
332 case 11: /* SymTagUDT */
334 WCHAR
*type_name_wbcs
;
335 if (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_SYMNAME
,
338 char *type_name
= convert_wbcs_to_ansi(type_name_wbcs
);
339 LocalFree(type_name_wbcs
);
342 fprintf(log_file
, "(%s) " FORMAT_PTR
,
343 type_name
, (UINT_PTR
)(DWORD_PTR
*)value_addr
);
345 fprintf(log_file
, "(%s *) " FORMAT_PTR
,
346 type_name
, *(DWORD_PTR
*)value_addr
);
348 fprintf(log_file
, "(%s **) " FORMAT_PTR
,
349 type_name
, *(DWORD_PTR
*)value_addr
);
354 fprintf(log_file
, "[no symbol tag]");
357 case 16: /* SymTagBaseType */
361 SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_LENGTH
, &length
);
363 /* print a char * as a string */
364 if (ptr
== 1 && length
== 1)
366 fprintf(log_file
, FORMAT_PTR
" \"%s\"",
367 *(DWORD_PTR
*)value_addr
, *(const char **)value_addr
);
371 fprintf(log_file
, FORMAT_PTR
, *(DWORD_PTR
*)value_addr
);
373 else if (SymGetTypeInfo_(proc
, mod_base
, type
, TI_GET_BASETYPE
, &bt
))
375 write_basic_type(log_file
, bt
, length
, value_addr
);
379 case 12: /* SymTagEnum */
380 fprintf(log_file
, "%Id", *(DWORD_PTR
*)value_addr
);
382 case 13: /* SymTagFunctionType */
383 fprintf(log_file
, FORMAT_PTR
, *(DWORD_PTR
*)value_addr
);
386 fprintf(log_file
, "[unhandled tag: %d]", tag
);
391 /* Internal structure used to pass some data to the enumerate symbols
393 typedef struct symbols_baton_t
{
394 STACKFRAME64
*stack_frame
;
400 /* Write the details of one parameter or local variable to the log file */
402 write_var_values(PSYMBOL_INFO sym_info
, ULONG sym_size
, void *baton
)
404 static int last_nr_of_frame
= 0;
405 DWORD_PTR var_data
= 0; /* Will point to the variable's data in memory */
406 STACKFRAME64
*stack_frame
= ((symbols_baton_t
*)baton
)->stack_frame
;
407 FILE *log_file
= ((symbols_baton_t
*)baton
)->log_file
;
408 int nr_of_frame
= ((symbols_baton_t
*)baton
)->nr_of_frame
;
409 BOOL log_params
= ((symbols_baton_t
*)baton
)->log_params
;
411 /* get the variable's data */
412 if (sym_info
->Flags
& SYMFLAG_REGREL
)
414 var_data
= (DWORD_PTR
)stack_frame
->AddrFrame
.Offset
;
415 var_data
+= (DWORD_PTR
)sym_info
->Address
;
420 if (log_params
&& sym_info
->Flags
& SYMFLAG_PARAMETER
)
422 if (last_nr_of_frame
== nr_of_frame
)
423 fprintf(log_file
, ", ");
425 last_nr_of_frame
= nr_of_frame
;
427 fprintf(log_file
, "%.*s=", (int)sym_info
->NameLen
, sym_info
->Name
);
428 write_value(log_file
, sym_info
->ModBase
, sym_info
->TypeIndex
,
431 if (!log_params
&& sym_info
->Flags
& SYMFLAG_LOCAL
)
433 fprintf(log_file
, " %.*s = ", (int)sym_info
->NameLen
,
435 write_value(log_file
, sym_info
->ModBase
, sym_info
->TypeIndex
,
437 fprintf(log_file
, "\n");
443 /* Write the details of one function to the log file */
445 write_function_detail(STACKFRAME64 stack_frame
, int nr_of_frame
, FILE *log_file
)
447 ULONG64 symbolBuffer
[(sizeof(SYMBOL_INFO
) +
449 sizeof(ULONG64
) - 1) /
451 PSYMBOL_INFO pIHS
= (PSYMBOL_INFO
)symbolBuffer
;
454 IMAGEHLP_STACK_FRAME ih_stack_frame
;
455 IMAGEHLP_LINE64 ih_line
;
458 HANDLE proc
= GetCurrentProcess();
460 symbols_baton_t ensym
;
462 nr_of_frame
++; /* We need a 1 based index here */
464 /* log the function name */
465 pIHS
->SizeOfStruct
= sizeof(SYMBOL_INFO
);
466 pIHS
->MaxNameLen
= MAX_SYM_NAME
;
467 if (SymFromAddr_(proc
, stack_frame
.AddrPC
.Offset
, &func_disp
, pIHS
))
470 "#%d 0x%08I64x in %.*s(",
471 nr_of_frame
, stack_frame
.AddrPC
.Offset
,
472 pIHS
->NameLen
> 200 ? 200 : (int)pIHS
->NameLen
,
475 /* restrict symbol enumeration to this frame only */
476 ih_stack_frame
.InstructionOffset
= stack_frame
.AddrPC
.Offset
;
477 SymSetContext_(proc
, &ih_stack_frame
, 0);
479 ensym
.log_file
= log_file
;
480 ensym
.stack_frame
= &stack_frame
;
481 ensym
.nr_of_frame
= nr_of_frame
;
483 /* log all function parameters */
484 ensym
.log_params
= TRUE
;
485 SymEnumSymbols_(proc
, 0, 0, write_var_values
, &ensym
);
487 fprintf(log_file
, ")");
492 "#%d 0x%08I64x in (unknown function)",
493 nr_of_frame
, stack_frame
.AddrPC
.Offset
);
496 /* find the source line for this function. */
497 ih_line
.SizeOfStruct
= sizeof(IMAGEHLP_LINE
);
498 if (SymGetLineFromAddr64_(proc
, stack_frame
.AddrPC
.Offset
,
499 &line_disp
, &ih_line
) != 0)
502 " at %s:%d\n", ih_line
.FileName
, ih_line
.LineNumber
);
506 fprintf(log_file
, "\n");
509 /* log all function local variables */
510 ensym
.log_params
= FALSE
;
511 SymEnumSymbols_(proc
, 0, 0, write_var_values
, &ensym
);
514 /* Walk over the stack and log all relevant information to the log file */
516 write_stacktrace(CONTEXT
*context
, FILE *log_file
)
518 #if defined (_M_IX86) || defined(_M_X64) || defined(_M_IA64)
519 HANDLE proc
= GetCurrentProcess();
520 STACKFRAME64 stack_frame
;
525 /* The thread information - if not supplied. */
528 /* If no context is supplied, skip 1 frame */
531 ctx
.ContextFlags
= CONTEXT_FULL
;
532 if (!GetThreadContext(GetCurrentThread(), &ctx
))
543 /* Write the stack trace */
544 ZeroMemory(&stack_frame
, sizeof(STACKFRAME64
));
545 stack_frame
.AddrPC
.Mode
= AddrModeFlat
;
546 stack_frame
.AddrStack
.Mode
= AddrModeFlat
;
547 stack_frame
.AddrFrame
.Mode
= AddrModeFlat
;
550 machine
= IMAGE_FILE_MACHINE_I386
;
551 stack_frame
.AddrPC
.Offset
= context
->Eip
;
552 stack_frame
.AddrStack
.Offset
= context
->Esp
;
553 stack_frame
.AddrFrame
.Offset
= context
->Ebp
;
554 #elif defined(_M_X64)
555 machine
= IMAGE_FILE_MACHINE_AMD64
;
556 stack_frame
.AddrPC
.Offset
= context
->Rip
;
557 stack_frame
.AddrStack
.Offset
= context
->Rsp
;
558 stack_frame
.AddrFrame
.Offset
= context
->Rbp
;
559 #elif defined(_M_IA64)
560 machine
= IMAGE_FILE_MACHINE_IA64
;
561 stack_frame
.AddrPC
.Offset
= context
->StIIP
;
562 stack_frame
.AddrStack
.Offset
= context
->SP
;
563 stack_frame
.AddrBStore
.Mode
= AddrModeFlat
;
564 stack_frame
.AddrBStore
.Offset
= context
->RsBSP
;
566 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
571 if (! StackWalk64_(machine
, proc
, GetCurrentThread(),
572 &stack_frame
, &ctx
, NULL
,
573 SymFunctionTableAccess64_
, SymGetModuleBase64_
, NULL
))
580 /* Try to include symbolic information.
581 Also check that the address is not zero. Sometimes StackWalk
582 returns TRUE with a frame of zero. */
583 if (stack_frame
.AddrPC
.Offset
!= 0)
585 write_function_detail(stack_frame
, i
, log_file
);
591 #error Unknown processortype, please disable SVN_USE_WIN32_CRASHHANDLER
595 /* Check if a debugger is attached to this process */
597 is_debugger_present()
599 return IsDebuggerPresent();
602 /* Load the dbghelp.dll file, try to find a version that matches our
607 dbghelp_dll
= LoadLibrary(DBGHELP_DLL
);
608 if (dbghelp_dll
!= NULL
)
612 /* load the functions */
614 (MINIDUMPWRITEDUMP
)GetProcAddress(dbghelp_dll
, "MiniDumpWriteDump");
616 (SYMINITIALIZE
)GetProcAddress(dbghelp_dll
, "SymInitialize");
618 (SYMSETOPTIONS
)GetProcAddress(dbghelp_dll
, "SymSetOptions");
620 (SYMGETOPTIONS
)GetProcAddress(dbghelp_dll
, "SymGetOptions");
622 (SYMCLEANUP
)GetProcAddress(dbghelp_dll
, "SymCleanup");
624 (SYMGETTYPEINFO
)GetProcAddress(dbghelp_dll
, "SymGetTypeInfo");
625 SymGetLineFromAddr64_
=
626 (SYMGETLINEFROMADDR64
)GetProcAddress(dbghelp_dll
,
627 "SymGetLineFromAddr64");
629 (SYMENUMSYMBOLS
)GetProcAddress(dbghelp_dll
, "SymEnumSymbols");
631 (SYMSETCONTEXT
)GetProcAddress(dbghelp_dll
, "SymSetContext");
632 SymFromAddr_
= (SYMFROMADDR
)GetProcAddress(dbghelp_dll
, "SymFromAddr");
633 StackWalk64_
= (STACKWALK64
)GetProcAddress(dbghelp_dll
, "StackWalk64");
634 SymFunctionTableAccess64_
=
635 (SYMFUNCTIONTABLEACCESS64
)GetProcAddress(dbghelp_dll
,
636 "SymFunctionTableAccess64");
637 SymGetModuleBase64_
=
638 (SYMGETMODULEBASE64
)GetProcAddress(dbghelp_dll
, "SymGetModuleBase64");
640 if (! (MiniDumpWriteDump_
&&
641 SymInitialize_
&& SymSetOptions_
&& SymGetOptions_
&&
642 SymCleanup_
&& SymGetTypeInfo_
&& SymGetLineFromAddr64_
&&
643 SymEnumSymbols_
&& SymSetContext_
&& SymFromAddr_
&&
644 SymGetModuleBase64_
&& StackWalk64_
&&
645 SymFunctionTableAccess64_
))
648 /* initialize the symbol loading code */
649 opts
= SymGetOptions_();
651 /* Set the 'load lines' option to retrieve line number information;
652 set the Deferred Loads option to map the debug info in memory only
654 SymSetOptions_(opts
| SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
);
656 /* Initialize the debughlp DLL with the default path and automatic
657 module enumeration (and loading of symbol tables) for this process.
659 SymInitialize_(GetCurrentProcess(), NULL
, TRUE
);
666 FreeLibrary(dbghelp_dll
);
671 /* Cleanup the dbghelp.dll library */
675 SymCleanup_(GetCurrentProcess());
677 FreeLibrary(dbghelp_dll
);
680 /* Create a filename based on a prefix, the timestamp and an extension.
681 check if the filename was already taken, retry 3 times. */
683 get_temp_filename(char *filename
, const char *prefix
, const char *ext
)
685 char temp_dir
[MAX_PATH
- 64];
688 if (! GetTempPath(MAX_PATH
- 64, temp_dir
))
691 for (i
= 0;i
< 3;i
++)
698 strftime(time_str
, 64, "%Y%m%d%H%M%S", localtime(&now
));
699 sprintf(filename
, "%s%s%s.%s", temp_dir
, prefix
, time_str
, ext
);
701 file
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
702 FILE_ATTRIBUTE_NORMAL
, NULL
);
703 if (file
!= INVALID_HANDLE_VALUE
)
714 /* Unhandled exception callback set with SetUnhandledExceptionFilter() */
716 svn__unhandled_exception_filter(PEXCEPTION_POINTERS ptrs
)
718 char dmp_filename
[MAX_PATH
];
719 char log_filename
[MAX_PATH
];
722 /* Check if the crash handler was already loaded (crash while handling the
724 if (dbghelp_dll
!= INVALID_HANDLE_VALUE
)
725 return EXCEPTION_CONTINUE_SEARCH
;
727 /* don't log anything if we're running inside a debugger ... */
728 if (is_debugger_present())
729 return EXCEPTION_CONTINUE_SEARCH
;
731 /* ... or if we can't create the log files ... */
732 if (!get_temp_filename(dmp_filename
, LOGFILE_PREFIX
, "dmp") ||
733 !get_temp_filename(log_filename
, LOGFILE_PREFIX
, "log"))
734 return EXCEPTION_CONTINUE_SEARCH
;
736 /* If we can't load a recent version of the dbghelp.dll, pass on this
738 if (!load_dbghelp_dll())
739 return EXCEPTION_CONTINUE_SEARCH
;
742 log_file
= fopen(log_filename
, "w+");
744 /* write information about the process */
745 fprintf(log_file
, "\nProcess info:\n");
746 write_process_info(ptrs
? ptrs
->ExceptionRecord
: NULL
,
747 ptrs
? ptrs
->ContextRecord
: NULL
,
750 /* write the stacktrace, if available */
751 fprintf(log_file
, "\nStacktrace:\n");
752 write_stacktrace(ptrs
? ptrs
->ContextRecord
: NULL
, log_file
);
754 /* write the minidump file and use the callback to write the list of modules
756 fprintf(log_file
, "\n\nLoaded modules:\n");
757 write_minidump_file(dmp_filename
, ptrs
,
758 write_module_info_callback
, (void *)log_file
);
762 /* inform the user */
763 fprintf(stderr
, "This application has halted due to an unexpected error.\n"
764 "A crash report and minidump file were saved to disk, you"
765 " can find them here:\n"
767 "Please send the log file to %s to help us analyze\nand "
768 "solve this problem.\n\n"
769 "NOTE: The crash report and minidump files can contain some"
770 " sensitive information\n(filenames, partial file content, "
771 "usernames and passwords etc.)\n",
774 SVN_WIN32_CRASHREPORT_EMAIL
);
776 if (getenv("SVN_DBG_STACKTRACES_TO_STDERR") != NULL
)
778 fprintf(stderr
, "\nProcess info:\n");
779 write_process_info(ptrs
? ptrs
->ExceptionRecord
: NULL
,
780 ptrs
? ptrs
->ContextRecord
: NULL
,
782 fprintf(stderr
, "\nStacktrace:\n");
783 write_stacktrace(ptrs
? ptrs
->ContextRecord
: NULL
, stderr
);
791 /* terminate the application */
792 return EXCEPTION_EXECUTE_HANDLER
;
794 #endif /* SVN_USE_WIN32_CRASHHANDLER */
797 /* Silence OSX ranlib warnings about object files with no symbols. */
799 extern const apr_uint32_t svn__fake__win32_crashrpt
;
800 const apr_uint32_t svn__fake__win32_crashrpt
= 0xdeadbeef;