core/vul/vul_debug.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_debug.cxx
00002 
00003 //: \file
00004 //  \brief Get debug related information like core dumps, and stack traces
00005 //  \author Ian Scott
00006 
00007 #include "vul_debug.h"
00008 #include <vcl_iostream.h>
00009 #include <vxl_config.h>
00010 #include <vcl_new.h>
00011 #include <vcl_cstdlib.h>
00012 
00013 #ifdef _WIN32
00014 
00015 #if VXL_HAS_DBGHELP_H
00016 
00017 #define NOATOM
00018 #define NOGDI
00019 #define NOGDICAPMASKS
00020 #define NOMETAFILE
00021 #define NOMINMAX
00022 #define NOMSG
00023 #define NOOPENFILE
00024 #define NORASTEROPS
00025 #define NOSCROLL
00026 #define NOSOUND
00027 #define NOSYSMETRICS
00028 #define NOTEXTMETRIC
00029 #define NOWH
00030 #define NOCOMM
00031 #define NOKANJI
00032 #define NOCRYPT
00033 #define NOMCX
00034 #include <windows.h>
00035 #include <DbgHelp.h>
00036 #include <vcl_cstdio.h>
00037 #pragma comment (lib, "dbghelp")
00038 
00039 static void vul_debug_core_dump_in_windows_seh(const char * filename,
00040                                                EXCEPTION_POINTERS* pep)
00041 {
00042   static char buffer[2048];
00043   static int count = 0;
00044   vcl_snprintf(buffer, sizeof(buffer), filename, count++);
00045   buffer[sizeof(buffer)-1]=0; // Just in case it is too long
00046 
00047   HANDLE hFile = CreateFile( buffer, GENERIC_READ | GENERIC_WRITE,
00048                              0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
00049 
00050   if ( ( hFile == NULL ) || ( hFile == INVALID_HANDLE_VALUE ) )
00051   {
00052     vcl_cerr << "WARNING: vul_debug_core_dump: Unable to create core dump file: " << filename << vcl_endl;
00053     return;
00054   }
00055 
00056   MINIDUMP_EXCEPTION_INFORMATION mdei;
00057   mdei.ThreadId           = GetCurrentThreadId();
00058   mdei.ExceptionPointers  = pep;
00059   mdei.ClientPointers     = FALSE;
00060 
00061   if (! MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
00062     hFile, MiniDumpWithFullMemory, (pep != 0) ? &mdei : 0, 0, 0 ))
00063     vcl_cerr << "WARNING: vul_debug_core_dump: Unable to dump core: " << filename << vcl_endl;
00064 
00065   CloseHandle( hFile );
00066 }
00067 
00068 void vul_debug_core_dump_in_windows_seh(const char * filename,
00069                                         void* pep)
00070 {
00071   vul_debug_core_dump_in_windows_seh(filename, (EXCEPTION_POINTERS*)pep);
00072 }
00073 
00074 // Default builds don't set the correct compiler flags
00075 // but we don't want a warning.
00076 #pragma warning (disable: 4535)
00077 
00078 
00079 void vul_debug_core_dump(const char * filename)
00080 {
00081   _se_translator_function current = _set_se_translator(0);
00082 
00083   __try
00084   {
00085     RaiseException(0xe0000000,0,0,0);
00086   }
00087   __except(vul_debug_core_dump_in_windows_seh(filename, GetExceptionInformation()),1)
00088   {}
00089   _set_se_translator(current);
00090 }
00091 
00092 #if VCL_HAS_EXCEPTIONS
00093 //: Windows structured exception code.
00094 unsigned vul_debug_windows_structured_exception::code() const
00095 {
00096   return static_cast<EXCEPTION_POINTERS*>(ex_ptr_)->ExceptionRecord->ExceptionCode;
00097 }
00098 
00099 //: Related execution address.
00100 void *vul_debug_windows_structured_exception::address() const
00101 {
00102   return static_cast<EXCEPTION_POINTERS*>(ex_ptr_)->ExceptionRecord->ExceptionAddress;
00103 }
00104 
00105 const char *vul_debug_windows_structured_exception::what() const throw()
00106 {
00107   static char buf[100];
00108   vcl_sprintf(buf, "Caught Windows Structured Exception. Code %lx. Address %lx", code(), address());
00109   return buf;
00110 }
00111 #endif
00112 
00113 static const char* se_coredump_filename = 0;
00114 
00115 void vul_debug_set_coredump_and_throw_on_windows_se_handler(
00116   unsigned code, EXCEPTION_POINTERS * ex_ptr)
00117 {
00118   vul_debug_core_dump_in_windows_seh(se_coredump_filename, ex_ptr);
00119 #if VCL_HAS_EXCEPTIONS
00120   throw vul_debug_windows_structured_exception(ex_ptr);
00121 #else
00122   vcl_cerr << static_cast<char*>(ex_ptr) << '\n';
00123   vcl_abort();
00124 #endif
00125 }
00126 
00127 
00128 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
00129 // \throws vul_debug_windows_structured_exception.
00130 void vul_debug_set_coredump_and_throw_on_windows_se(const char * filename)
00131 {
00132   se_coredump_filename = filename;
00133   _set_se_translator(vul_debug_set_coredump_and_throw_on_windows_se_handler);
00134 }
00135 
00136 
00137 # else //VXL_HAS_DBGHELP_H
00138 
00139 void vul_debug_core_dump_in_windows_seh(const char *, void*)
00140 {
00141   vcl_cerr << "WARNING: vul_debug_core_dump_in_windows_seh: Unable to core dump\n";
00142 }
00143 
00144 void vul_debug_core_dump(const char *)
00145 {
00146   vcl_cerr << "WARNING: vul_debug_core_dump: Unable to core dump\n";
00147 }
00148 
00149 //: Windows structured exception code.
00150 unsigned vul_debug_windows_structured_exception::code() const
00151 {
00152   return 0;
00153 }
00154 
00155 //: Related execution address.
00156 void *vul_debug_windows_structured_exception::address() const
00157 {
00158   return 0;
00159 }
00160 
00161 const char *vul_debug_windows_structured_exception::what() const throw()
00162 {
00163   return "Caught Windows Exception on machine with old or no version of DbgHelp.";
00164 }
00165 
00166 
00167 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
00168 // \throws vul_debug_windows_structured_exception.
00169 void vul_debug_set_coredump_and_throw_on_windows_se(const char * )
00170 {
00171   vcl_cerr << "WARNING: No DbgHelp.h on this platform - can't set SE Handler.\n";
00172 }
00173 
00174 # endif // VXL_HAS_DBGHELP_H
00175 
00176 
00177 #else // _WIN32
00178 
00179 #include <vcl_string.h>
00180 #ifdef VXL_UNISTD_HAS_GETPID
00181 # include <unistd.h>
00182 #endif
00183 #include <vul/vul_sprintf.h>
00184 
00185 void vul_debug_core_dump(const char * filename)
00186 {
00187   static int count = 0;
00188 #ifdef VXL_UNISTD_HAS_GETPID
00189   vcl_string syscall = "gcore -o ";
00190   syscall += vul_sprintf(filename, count++);
00191   syscall += vul_sprintf(" %d", getpid());
00192   if (system(syscall.c_str())==0) return;
00193   syscall = "gcore -s -c ";
00194   syscall += filename;
00195   syscall += vul_sprintf(" %d", getpid());
00196   if (system(syscall.c_str())==0) return;
00197 #endif
00198   vcl_cerr << "WARNING: vul_debug_core_dump: Unable to core dump\n";
00199 }
00200 // For a more reliable way of dunping core try forking and sending a SIGSTOP to the child.
00201 // see http://kasperd.net/~kasperd/comp.os.linux.development.faq
00202 
00203 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
00204 // \throws vul_debug_windows_structured_exception.
00205 void vul_debug_set_coredump_and_throw_on_windows_se(const char * filename)
00206 {
00207 // Do nothing on non-windows box.
00208 }
00209 
00210 #endif // _WIN32
00211 
00212 
00213 static const char* out_out_memory_coredump_filename = 0;
00214 
00215 void
00216 #ifdef _WIN32
00217   __cdecl
00218 #endif
00219   vul_debug_set_coredump_and_throw_on_out_of_memory_handler()
00220 {
00221   vul_debug_core_dump(out_out_memory_coredump_filename);
00222 #if VCL_HAS_EXCEPTIONS
00223   throw vcl_bad_alloc();
00224 #else
00225   vcl_cerr << "Out of Memory.\n";
00226   vcl_abort();
00227 #endif
00228 }
00229 
00230 //: Setup the system to core dump and throw a C++ exception on detection of out of memory.
00231 // The system will throw vcl_bad_alloc.
00232 void vul_debug_set_coredump_and_throw_on_out_of_memory(const char * filename)
00233 {
00234   out_out_memory_coredump_filename = filename;
00235   vcl_set_new_handler(vul_debug_set_coredump_and_throw_on_out_of_memory_handler);
00236 }