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