vul_debug.cxx
Go to the documentation of this file.
1 // This is core/vul/vul_debug.cxx
2 #include <iostream>
3 #include <new>
4 #include <cstdlib>
5 #include <cstdio>
6 #include <string>
7 #include "vul_debug.h"
8 //: \file
9 // \brief Get debug related information like core dumps, and stack traces
10 // \author Ian Scott
11 
12 #include <vxl_config.h>
13 #ifdef _MSC_VER
14 # include <vcl_msvc_warnings.h>
15 #endif
16 
17 #ifdef _WIN32
18 
19 #if VXL_HAS_DBGHELP_H
20 
21 #define NOATOM
22 #define NOGDI
23 #define NOGDICAPMASKS
24 #define NOMETAFILE
25 #define NOMINMAX
26 #define NOMSG
27 #define NOOPENFILE
28 #define NORASTEROPS
29 #define NOSCROLL
30 #define NOSOUND
31 #define NOSYSMETRICS
32 #define NOTEXTMETRIC
33 #define NOWH
34 #define NOCOMM
35 #define NOKANJI
36 #define NOCRYPT
37 #define NOMCX
38 #include <windows.h>
39 #include <DbgHelp.h>
40 #pragma comment (lib, "dbghelp")
41 
42 static bool vul_debug_core_dump_in_windows_seh(const char * filename,
43  EXCEPTION_POINTERS* pep)
44 {
45  static char buffer[2048];
46  static int count = 0;
47  std::snprintf(buffer, sizeof(buffer), filename, count++);
48  buffer[sizeof(buffer)-1]=0; // Just in case it is too long
49 
50  HANDLE hFile = CreateFile( buffer, GENERIC_READ | GENERIC_WRITE,
51  0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
52 
53  if ( ( hFile == NULL ) || ( hFile == INVALID_HANDLE_VALUE ) )
54  {
55  std::cerr << "WARNING: vul_debug_core_dump: Unable to create core dump file: " << filename << std::endl;
56  return false;
57  }
58 
59  MINIDUMP_EXCEPTION_INFORMATION mdei;
60  mdei.ThreadId = GetCurrentThreadId();
61  mdei.ExceptionPointers = pep;
62  mdei.ClientPointers = FALSE;
63 
64  if (! MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
65  hFile, MiniDumpWithFullMemory, (pep != 0) ? &mdei : 0, 0, 0 ))
66  std::cerr << "WARNING: vul_debug_core_dump: Unable to dump core: " << filename << std::endl;
67 
68  CloseHandle( hFile );
69  return true;
70 }
71 
72 bool vul_debug_core_dump_in_windows_seh(const char * filename,
73  void* pep)
74 {
75  return vul_debug_core_dump_in_windows_seh(filename, (EXCEPTION_POINTERS*)pep);
76 }
77 
78 // Default builds don't set the correct compiler flags
79 // but we don't want a warning.
80 #pragma warning (disable: 4535)
81 
82 
83 bool vul_debug_core_dump(const char * filename)
84 {
85  _se_translator_function current = _set_se_translator(0);
86 
87  __try
88  {
89  RaiseException(0xe0000000,0,0,0);
90  }
91  __except(vul_debug_core_dump_in_windows_seh(filename, GetExceptionInformation()),1)
92  {}
93  _set_se_translator(current);
94  return true;
95 }
96 
97 //: Windows structured exception code.
99 {
100  return static_cast<EXCEPTION_POINTERS*>(ex_ptr_)->ExceptionRecord->ExceptionCode;
101 }
102 
103 //: Related execution address.
105 {
106  return static_cast<EXCEPTION_POINTERS*>(ex_ptr_)->ExceptionRecord->ExceptionAddress;
107 }
108 
109 const char *vul_debug_windows_structured_exception::what() const throw()
110 {
111  static char buf[100];
112  std::sprintf(buf, "Caught Windows Structured Exception. Code %lx. Address %lx", code(), address());
113  return buf;
114 }
115 
116 static const char* se_coredump_filename = 0;
117 
118 void vul_debug_set_coredump_and_throw_on_windows_se_handler(
119  unsigned code, EXCEPTION_POINTERS * ex_ptr)
120 {
121  vul_debug_core_dump_in_windows_seh(se_coredump_filename, ex_ptr);
123 }
124 
125 
126 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
127 // \throws vul_debug_windows_structured_exception.
128 void vul_debug_set_coredump_and_throw_on_windows_se(const char * filename)
129 {
130  se_coredump_filename = filename;
131  _set_se_translator(vul_debug_set_coredump_and_throw_on_windows_se_handler);
132 }
133 
134 
135 # else //VXL_HAS_DBGHELP_H
136 
137 bool vul_debug_core_dump_in_windows_seh(const char *, void*)
138 {
139  std::cerr << "WARNING: vul_debug_core_dump_in_windows_seh: Unable to core dump\n";
140  return false;
141 }
142 
143 bool vul_debug_core_dump(const char *)
144 {
145  std::cerr << "WARNING: vul_debug_core_dump: Unable to core dump\n";
146  return false;
147 }
148 
149 //: Windows structured exception code.
151 {
152  return 0;
153 }
154 
155 //: Related execution address.
157 {
158  return 0;
159 }
160 
161 const char *vul_debug_windows_structured_exception::what() const throw()
162 {
163  return "Caught Windows Exception on machine with old or no version of DbgHelp.";
164 }
165 
166 
167 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
168 // \throws vul_debug_windows_structured_exception.
170 {
171  std::cerr << "WARNING: No DbgHelp.h on this platform - can't set SE Handler.\n";
172 }
173 
174 # endif // VXL_HAS_DBGHELP_H
175 
176 
177 #else // _WIN32
178 
179 #ifdef VXL_UNISTD_HAS_GETPID
180 # include <unistd.h>
181 #endif
182 #include <vul/vul_sprintf.h>
183 
184 bool vul_debug_core_dump(const char * filename)
185 {
186  static int count = 0;
187 #ifdef VXL_UNISTD_HAS_GETPID
188  std::string syscall = "gcore -o ";
189  syscall += vul_sprintf(filename, count++);
190  syscall += vul_sprintf(" %d", getpid());
191  if (system(syscall.c_str())==0) return true;
192  syscall = "gcore -s -c ";
193  syscall += filename;
194  syscall += vul_sprintf(" %d", getpid());
195  if (system(syscall.c_str())==0) return true;
196 #endif
197  std::cerr << "WARNING: vul_debug_core_dump: Unable to core dump\n";
198  return false;
199 }
200 // For a more reliable way of dumping core try forking and sending a SIGSTOP to the child.
201 // see http://kasperd.net/~kasperd/comp.os.linux.development.faq
202 
203 //: Setup the system to core dump and throw a C++ exception on detection of a Structured Exception
204 // \throws vul_debug_windows_structured_exception.
205 void vul_debug_set_coredump_and_throw_on_windows_se(const char * /*filename*/)
206 {
207 // Do nothing on non-windows box.
208 }
209 
210 #endif // _WIN32
211 
212 
213 static const char* out_of_memory_coredump_filename = nullptr;
214 
215 void
216 #ifdef _WIN32
217  __cdecl
218 #endif
220 {
221  vul_debug_core_dump(out_of_memory_coredump_filename);
222  throw std::bad_alloc();
223 }
224 
225 //: Setup the system to core dump and throw a C++ exception on detection of out of memory.
226 // The system will throw std::bad_alloc.
228 {
229  out_of_memory_coredump_filename = filename;
231 }
A translated structured exception.
Definition: vul_debug.h:41
void vul_debug_set_coredump_and_throw_on_windows_se(const char *)
Setup the system to core dump and throw a C++ exception on detection of a Structured Exception.
Definition: vul_debug.cxx:205
void * address() const
Related execution address.
void vul_debug_set_coredump_and_throw_on_out_of_memory_handler()
Definition: vul_debug.cxx:219
const char * what() const override
bool vul_debug_core_dump(const char *filename)
Dump a core file.
Definition: vul_debug.cxx:184
unsigned code() const
Windows structured exception code.
C++ conforming replacement to the ANSI C functions sprintf and printf.
Definition: vul_sprintf.h:31
void vul_debug_set_coredump_and_throw_on_out_of_memory(const char *filename)
Setup the system to core dump and throw a C++ exception on detection of out of memory.
Definition: vul_debug.cxx:227
creates a formatted ANSI C++ string