Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
debug.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * platform-independent debug support code.
25  */
26 
27 #include "precompiled.h"
28 #include "lib/debug.h"
29 
30 #include <cstdarg>
31 #include <cstring>
32 #include <cstdio>
33 
34 #include "lib/alignment.h"
35 #include "lib/app_hooks.h"
36 #include "lib/fnv_hash.h"
37 #include "lib/sysdep/vm.h"
38 #include "lib/sysdep/cpu.h" // cpu_CAS
39 #include "lib/sysdep/sysdep.h"
40 
41 #if OS_WIN
43 #endif
44 
46  { ERR::SYM_NO_STACK_FRAMES_FOUND, L"No stack frames found" },
47  { ERR::SYM_UNRETRIEVABLE_STATIC, L"Value unretrievable (stored in external module)" },
48  { ERR::SYM_UNRETRIEVABLE, L"Value unretrievable" },
49  { ERR::SYM_TYPE_INFO_UNAVAILABLE, L"Error getting type_info" },
50  { ERR::SYM_INTERNAL_ERROR, L"Exception raised while processing a symbol" },
51  { ERR::SYM_UNSUPPORTED, L"Symbol type not (fully) supported" },
52  { ERR::SYM_CHILD_NOT_FOUND, L"Symbol does not have the given child" },
53  { ERR::SYM_NESTING_LIMIT, L"Symbol nesting too deep or infinite recursion" },
54  { ERR::SYM_SINGLE_SYMBOL_LIMIT, L"Symbol has produced too much output" },
55  { INFO::SYM_SUPPRESS_OUTPUT, L"Symbol was suppressed" }
56 };
57 STATUS_ADD_DEFINITIONS(debugStatusDefinitions);
58 
59 
60 // need to shoehorn printf-style variable params into
61 // the OutputDebugString call.
62 // - don't want to split into multiple calls - would add newlines to output.
63 // - fixing Win32 _vsnprintf to return # characters that would be written,
64 // as required by C99, looks difficult and unnecessary. if any other code
65 // needs that, implement GNU vasprintf.
66 // - fixed size buffers aren't nice, but much simpler than vasprintf-style
67 // allocate+expand_until_it_fits. these calls are for quick debug output,
68 // not loads of data, anyway.
69 
70 // rationale: static data instead of std::set to allow setting at any time.
71 // we store FNV hash of tag strings for fast comparison; collisions are
72 // extremely unlikely and can only result in displaying more/less text.
73 static const size_t MAX_TAGS = 20;
74 static u32 tags[MAX_TAGS];
75 static size_t num_tags;
76 
77 void debug_filter_add(const wchar_t* tag)
78 {
79  const u32 hash = fnv_hash(tag, wcslen(tag)*sizeof(tag[0]));
80 
81  // make sure it isn't already in the list
82  for(size_t i = 0; i < MAX_TAGS; i++)
83  if(tags[i] == hash)
84  return;
85 
86  // too many already?
87  if(num_tags == MAX_TAGS)
88  {
89  DEBUG_WARN_ERR(ERR::LOGIC); // increase MAX_TAGS
90  return;
91  }
92 
93  tags[num_tags++] = hash;
94 }
95 
96 void debug_filter_remove(const wchar_t* tag)
97 {
98  const u32 hash = fnv_hash(tag, wcslen(tag)*sizeof(tag[0]));
99 
100  for(size_t i = 0; i < MAX_TAGS; i++)
101  {
102  if(tags[i] == hash) // found it
103  {
104  // replace with last element (avoid holes)
105  tags[i] = tags[MAX_TAGS-1];
106  num_tags--;
107 
108  // can only happen once, so we're done.
109  return;
110  }
111  }
112 }
113 
115 {
116  std::fill(tags, tags+MAX_TAGS, 0);
117 }
118 
119 bool debug_filter_allows(const wchar_t* text)
120 {
121  size_t i;
122  for(i = 0; ; i++)
123  {
124  // no | found => no tag => should always be displayed
125  if(text[i] == ' ' || text[i] == '\0')
126  return true;
127  if(text[i] == '|' && i != 0)
128  break;
129  }
130 
131  const u32 hash = fnv_hash(text, i*sizeof(text[0]));
132 
133  // check if entry allowing this tag is found
134  for(i = 0; i < MAX_TAGS; i++)
135  if(tags[i] == hash)
136  return true;
137 
138  return false;
139 }
140 
141 #undef debug_printf // allowing #defining it out
142 void debug_printf(const wchar_t* fmt, ...)
143 {
144  wchar_t buf[16384];
145 
146  va_list ap;
147  va_start(ap, fmt);
148  const int numChars = vswprintf_s(buf, ARRAY_SIZE(buf), fmt, ap);
149  if(numChars < 0)
150  debug_break(); // poor man's assert - avoid infinite loop because ENSURE also uses debug_printf
151  va_end(ap);
152 
153  if(debug_filter_allows(buf))
154  debug_puts(buf);
155 }
156 
157 
158 //-----------------------------------------------------------------------------
159 
160 Status debug_WriteCrashlog(const wchar_t* text)
161 {
162  // (avoid infinite recursion and/or reentering this function if it
163  // fails/reports an error)
164  enum State
165  {
166  IDLE,
167  BUSY,
168  FAILED
169  };
170  // note: the initial state is IDLE. we rely on zero-init because
171  // initializing local static objects from constants may happen when
172  // this is first called, which isn't thread-safe. (see C++ 6.7.4)
173  cassert(IDLE == 0);
174  static volatile intptr_t state;
175 
176  if(!cpu_CAS(&state, IDLE, BUSY))
177  return ERR::REENTERED; // NOWARN
178 
179  OsPath pathname = ah_get_log_dir()/"crashlog.txt";
180  FILE* f = sys_OpenFile(pathname, "w");
181  if(!f)
182  {
183  state = FAILED; // must come before DEBUG_DISPLAY_ERROR
184  DEBUG_DISPLAY_ERROR(L"Unable to open crashlog.txt for writing (please ensure the log directory is writable)");
185  return ERR::FAIL; // NOWARN (the above text is more helpful than a generic error code)
186  }
187 
188  fputwc(0xFEFF, f); // BOM
189  fwprintf(f, L"%ls\n", text);
190  fwprintf(f, L"\n\n====================================\n\n");
191 
192  // allow user to bundle whatever information they want
193  ah_bundle_logs(f);
194 
195  fclose(f);
196  state = IDLE;
197  return INFO::OK;
198 }
199 
200 
201 //-----------------------------------------------------------------------------
202 // error message
203 //-----------------------------------------------------------------------------
204 
205 // (NB: this may appear obscene, but deep stack traces have been
206 // observed to take up > 256 KiB)
207 static const size_t messageSize = 512*KiB;
208 
210 {
211  vm::Free(emm->pa_mem, messageSize);
212 }
213 
214 
215 // a stream with printf-style varargs and the possibility of
216 // writing directly to the output buffer.
218 {
219 public:
220  PrintfWriter(wchar_t* buf, size_t maxChars)
221  : m_pos(buf), m_charsLeft(maxChars)
222  {
223  }
224 
225  bool operator()(const wchar_t* fmt, ...) WPRINTF_ARGS(2)
226  {
227  va_list ap;
228  va_start(ap, fmt);
229  const int len = vswprintf(m_pos, m_charsLeft, fmt, ap);
230  va_end(ap);
231  if(len < 0)
232  return false;
233  m_pos += len;
234  m_charsLeft -= len;
235  return true;
236  }
237 
238  wchar_t* Position() const
239  {
240  return m_pos;
241  }
242 
243  size_t CharsLeft() const
244  {
245  return m_charsLeft;
246  }
247 
249  {
250  const size_t len = wcslen(m_pos);
251  m_pos += len;
252  m_charsLeft -= len;
253  }
254 
255 private:
256  wchar_t* m_pos;
257  size_t m_charsLeft;
258 };
259 
260 
261 // split out of debug_DisplayError because it's used by the self-test.
262 const wchar_t* debug_BuildErrorMessage(
263  const wchar_t* description,
264  const wchar_t* filename, int line, const char* func,
265  void* context, const wchar_t* lastFuncToSkip,
266  ErrorMessageMem* emm)
267 {
268  // retrieve errno (might be relevant) before doing anything else
269  // that might overwrite it.
270  wchar_t description_buf[100] = L"?";
271  wchar_t os_error[100] = L"?";
272  Status errno_equiv = StatusFromErrno(); // NOWARN
273  if(errno_equiv != ERR::FAIL) // meaningful translation
274  StatusDescription(errno_equiv, description_buf, ARRAY_SIZE(description_buf));
275  sys_StatusDescription(0, os_error, ARRAY_SIZE(os_error));
276 
277  // rationale: see ErrorMessageMem
279  wchar_t* const buf = (wchar_t*)emm->pa_mem;
280  if(!buf)
281  return L"(insufficient memory to generate error message)";
282  PrintfWriter writer(buf, messageSize / sizeof(wchar_t));
283 
284  // header
285  if(!writer(
286  L"%ls\r\n"
287  L"Location: %ls:%d (%hs)\r\n"
288  L"\r\n"
289  L"Call stack:\r\n"
290  L"\r\n",
291  description, filename, line, func
292  ))
293  {
294 fail:
295  return L"(error while formatting error message)";
296  }
297 
298  // append stack trace
299  Status ret = debug_DumpStack(writer.Position(), writer.CharsLeft(), context, lastFuncToSkip);
300  if(ret == ERR::REENTERED)
301  {
302  if(!writer(
303  L"While generating an error report, we encountered a second "
304  L"problem. Please be sure to report both this and the subsequent "
305  L"error messages."
306  ))
307  goto fail;
308  }
309  else if(ret != INFO::OK)
310  {
311  wchar_t error_buf[100] = {'?'};
312  if(!writer(
313  L"(error while dumping stack: %ls)",
314  StatusDescription(ret, error_buf, ARRAY_SIZE(error_buf))
315  ))
316  goto fail;
317  }
318  else // success
319  {
320  writer.CountAddedChars();
321  }
322 
323  // append errno
324  if(!writer(
325  L"\r\n"
326  L"errno = %d (%ls)\r\n"
327  L"OS error = %ls\r\n",
328  errno, description_buf, os_error
329  ))
330  goto fail;
331 
332  return buf;
333 }
334 
335 
336 //-----------------------------------------------------------------------------
337 // display error messages
338 //-----------------------------------------------------------------------------
339 
340 // translates and displays the given strings in a dialog.
341 // this is typically only used when debug_DisplayError has failed or
342 // is unavailable because that function is much more capable.
343 // implemented via sys_display_msg; see documentation there.
344 void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg)
345 {
346  sys_display_msg(ah_translate(caption), ah_translate(msg));
347 }
348 
349 
350 // when an error has come up and user clicks Exit, we don't want any further
351 // errors (e.g. caused by atexit handlers) to come up, possibly causing an
352 // infinite loop. hiding errors isn't good, but we assume that whoever clicked
353 // exit really doesn't want to see any more messages.
355 
356 // this logic is applicable to any type of error. special cases such as
357 // suppressing certain expected WARN_ERRs are done there.
358 static bool ShouldSuppressError(atomic_bool* suppress)
359 {
360  if(isExiting)
361  return true;
362 
363  if(!suppress)
364  return false;
365 
366  if(*suppress == DEBUG_SUPPRESS)
367  return true;
368 
369  return false;
370 }
371 
372 static ErrorReactionInternal CallDisplayError(const wchar_t* text, size_t flags)
373 {
374  // first try app hook implementation
375  ErrorReactionInternal er = ah_display_error(text, flags);
376  // .. it's only a stub: default to normal implementation
377  if(er == ERI_NOT_IMPLEMENTED)
378  er = sys_display_error(text, flags);
379 
380  return er;
381 }
382 
384 {
385  const bool shouldHandleBreak = (flags & DE_MANUAL_BREAK) == 0;
386 
387  switch(er)
388  {
389  case ERI_CONTINUE:
390  return ER_CONTINUE;
391 
392  case ERI_BREAK:
393  // handle "break" request unless the caller wants to (doing so here
394  // instead of within the dlgproc yields a correct call stack)
395  if(shouldHandleBreak)
396  {
397  debug_break();
398  return ER_CONTINUE;
399  }
400  else
401  return ER_BREAK;
402 
403  case ERI_SUPPRESS:
404  (void)cpu_CAS(suppress, 0, DEBUG_SUPPRESS);
405  return ER_CONTINUE;
406 
407  case ERI_EXIT:
408  isExiting = 1; // see declaration
410 
411 #if OS_WIN
412  // prevent (slow) heap reporting since we're exiting abnormally and
413  // thus probably leaking like a sieve.
414  wdbg_heap_Enable(false);
415 #endif
416 
417  exit(EXIT_FAILURE);
418 
419  case ERI_NOT_IMPLEMENTED:
420  default:
421  debug_break(); // not expected to be reached
422  return ER_CONTINUE;
423  }
424 }
425 
426 ErrorReaction debug_DisplayError(const wchar_t* description,
427  size_t flags, void* context, const wchar_t* lastFuncToSkip,
428  const wchar_t* pathname, int line, const char* func,
429  atomic_bool* suppress)
430 {
431  // "suppressing" this error means doing nothing and returning ER_CONTINUE.
432  if(ShouldSuppressError(suppress))
433  return ER_CONTINUE;
434 
435  // fix up params
436  // .. translate
437  description = ah_translate(description);
438  // .. caller supports a suppress flag; set the corresponding flag so that
439  // the error display implementation enables the Suppress option.
440  if(suppress)
441  flags |= DE_ALLOW_SUPPRESS;
442 
443  if(flags & DE_NO_DEBUG_INFO)
444  {
445  // in non-debug-info mode, simply display the given description
446  // and then return immediately
447  ErrorReactionInternal er = CallDisplayError(description, flags);
448  return PerformErrorReaction(er, flags, suppress);
449  }
450 
451  // .. deal with incomplete file/line info
452  if(!pathname || pathname[0] == '\0')
453  pathname = L"unknown";
454  if(line <= 0)
455  line = 0;
456  if(!func || func[0] == '\0')
457  func = "?";
458  // .. _FILE__ evaluates to the full path (albeit without drive letter)
459  // which is rather long. we only display the base name for clarity.
460  const wchar_t* filename = path_name_only(pathname);
461 
462  // display in output window; double-click will navigate to error location.
463  debug_printf(L"%ls(%d): %ls\n", filename, line, description);
464 
465  ErrorMessageMem emm;
466  const wchar_t* text = debug_BuildErrorMessage(description, filename, line, func, context, lastFuncToSkip, &emm);
467 
468  (void)debug_WriteCrashlog(text);
469  ErrorReactionInternal er = CallDisplayError(text, flags);
470 
471  // note: debug_break-ing here to make sure the app doesn't continue
472  // running is no longer necessary. debug_DisplayError now determines our
473  // window handle and is modal.
474 
475  // must happen before PerformErrorReaction because that may exit.
477 
478  return PerformErrorReaction(er, flags, suppress);
479 }
480 
481 
482 // is errorToSkip valid? (also guarantees mutual exclusion)
484 {
486 };
487 static intptr_t skipStatus = INVALID;
489 static size_t numSkipped;
490 
492 {
494  {
495  errorToSkip = err;
496  numSkipped = 0;
498  skipStatus = VALID; // linearization point
499  }
500  else
502 }
503 
505 {
506  if(cpu_CAS(&skipStatus, VALID, BUSY))
507  {
508  const size_t ret = numSkipped;
510  skipStatus = INVALID; // linearization point
511  return ret;
512  }
513  else
514  {
516  return 0;
517  }
518 }
519 
520 static bool ShouldSkipError(Status err)
521 {
522  if(cpu_CAS(&skipStatus, VALID, BUSY))
523  {
524  numSkipped++;
525  const bool ret = (err == errorToSkip);
527  skipStatus = VALID;
528  return ret;
529  }
530  return false;
531 }
532 
533 
534 ErrorReaction debug_OnError(Status err, atomic_bool* suppress, const wchar_t* file, int line, const char* func)
535 {
537  (void)debug_CaptureContext(context);
538 
539  if(ShouldSkipError(err))
540  return ER_CONTINUE;
541 
542  const wchar_t* lastFuncToSkip = L"debug_OnError";
543  wchar_t buf[400];
544  wchar_t err_buf[200]; StatusDescription(err, err_buf, ARRAY_SIZE(err_buf));
545  swprintf_s(buf, ARRAY_SIZE(buf), L"Function call failed: return value was %lld (%ls)", (long long)err, err_buf);
546  return debug_DisplayError(buf, DE_MANUAL_BREAK, context, lastFuncToSkip, file,line,func, suppress);
547 }
548 
549 
550 ErrorReaction debug_OnAssertionFailure(const wchar_t* expr, atomic_bool* suppress, const wchar_t* file, int line, const char* func)
551 {
553  (void)debug_CaptureContext(context);
554 
555  const std::wstring lastFuncToSkip = L"debug_OnAssertionFailure";
556  wchar_t buf[400];
557  swprintf_s(buf, ARRAY_SIZE(buf), L"Assertion failed: \"%ls\"", expr);
558  return debug_DisplayError(buf, DE_MANUAL_BREAK, context, lastFuncToSkip.c_str(), file,line,func, suppress);
559 }
void CountAddedChars()
Definition: debug.cpp:248
static intptr_t skipStatus
Definition: debug.cpp:487
LIB_API void debug_puts(const wchar_t *text)
[system-dependent] write a string to the debug channel.
Definition: udbg.cpp:106
#define u8
Definition: types.h:39
const Status LOGIC
Definition: status.h:409
static size_t num_tags
Definition: debug.cpp:75
Definition: debug.cpp:485
static ErrorReactionInternal CallDisplayError(const wchar_t *text, size_t flags)
Definition: debug.cpp:372
static const size_t messageSize
Definition: debug.cpp:207
const wchar_t * debug_BuildErrorMessage(const wchar_t *description, const wchar_t *filename, int line, const char *func, void *context, const wchar_t *lastFuncToSkip, ErrorMessageMem *emm)
build a string describing the given error.
Definition: debug.cpp:262
#define COMPILER_FENCE
prevent the compiler from reordering loads or stores across this point.
const Status SYM_UNSUPPORTED
Definition: debug.h:406
static const size_t MAX_TAGS
Definition: debug.cpp:73
const Status OK
Definition: status.h:386
const Status SYM_SUPPRESS_OUTPUT
Definition: debug.h:420
ErrorReaction debug_DisplayError(const wchar_t *description, size_t flags, void *context, const wchar_t *lastFuncToSkip, const wchar_t *pathname, int line, const char *func, atomic_bool *suppress)
display an error dialog with a message and stack trace.
Definition: debug.cpp:426
wchar_t * Position() const
Definition: debug.cpp:238
enable the Suppress button.
Definition: debug.h:96
special return value for the display_error app hook stub to indicate that it has done nothing and tha...
Definition: debug.h:175
ErrorReactionInternal sys_display_error(const wchar_t *text, size_t flags)
show the error dialog.
Definition: unix.cpp:202
ErrorReaction
choices offered by the error dialog that are returned by debug_DisplayError.
Definition: debug.h:131
size_t CharsLeft() const
Definition: debug.cpp:243
const Status SYM_CHILD_NOT_FOUND
Definition: debug.h:407
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
wchar_t * m_pos
Definition: debug.cpp:256
trigger breakpoint, i.e.
Definition: debug.h:145
Status debug_WriteCrashlog(const wchar_t *text)
write an error description and all logs into crashlog.txt (in unicode format).
Definition: debug.cpp:160
#define ARRAY_SIZE(name)
const Status SYM_UNRETRIEVABLE_STATIC
Definition: debug.h:402
FILE * sys_OpenFile(const OsPath &pathname, const char *mode)
open a file like with fopen (but taking an OsPath argument).
Definition: unix.cpp:373
Definition: Loader.cpp:51
LIB_API Status debug_CaptureContext(void *context)
Definition: udbg.cpp:42
const Status SYM_UNRETRIEVABLE
Definition: debug.h:403
exit the program immediately.
Definition: debug.h:168
Status sys_StatusDescription(int err, wchar_t *buf, size_t max_chars)
describe the current OS error state.
Definition: unix.cpp:271
volatile intptr_t atomic_bool
a bool that is reasonably certain to be set atomically.
Definition: debug.h:117
void wdbg_heap_Enable(bool enable)
enable or disable manual and automatic heap validity checking.
Definition: wdbg_heap.cpp:41
size_t m_charsLeft
Definition: debug.cpp:257
const Status SYM_NO_STACK_FRAMES_FOUND
Definition: debug.h:401
display just the given message; do not add any information about the call stack, do not write crashlo...
Definition: debug.h:109
static const atomic_bool DEBUG_SUPPRESS
value for suppress flag once set by debug_DisplayError.
Definition: debug.h:125
Definition: path.h:75
bool debug_filter_allows(const wchar_t *text)
indicate if the given text would be printed.
Definition: debug.cpp:119
void debug_filter_clear()
clear all filter state; equivalent to debug_filter_remove for each tag that was debug_filter_add-ed.
Definition: debug.cpp:114
const Status REENTERED
Definition: status.h:412
void sys_display_msg(const wchar_t *caption, const wchar_t *msg)
display a message.
Definition: unix.cpp:60
SkipStatus
Definition: debug.cpp:483
void debug_DisplayMessage(const wchar_t *caption, const wchar_t *msg)
translates and displays the given strings in a dialog.
Definition: debug.cpp:344
static const size_t KiB
Definition: alignment.h:71
ErrorReactionInternal ah_display_error(const wchar_t *text, size_t flags)
display an error dialog, thus overriding sys_display_error.
Definition: app_hooks.cpp:176
void debug_filter_add(const wchar_t *tag)
debug output is very useful, but &quot;too much of a good thing can kill you&quot;.
Definition: debug.cpp:77
const Status SYM_TYPE_INFO_UNAVAILABLE
Definition: debug.h:404
i64 Status
Error handling system.
Definition: status.h:171
void debug_break()
trigger a breakpoint when reached/&quot;called&quot;.
Definition: udbg.cpp:48
static size_t numSkipped
Definition: debug.cpp:489
PrintfWriter(wchar_t *buf, size_t maxChars)
Definition: debug.cpp:220
#define STATUS_ADD_DEFINITIONS(definitions)
add a module&#39;s array of StatusDefinition to the list.
Definition: status.h:216
do not trigger a breakpoint inside debug_DisplayError; caller will take care of this if ER_BREAK is r...
Definition: debug.h:103
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
Definition: debug.cpp:485
Status StatusFromErrno()
Definition: status.cpp:105
u32 fnv_hash(const void *buf, size_t len)
rationale: this algorithm was chosen because it delivers &#39;good&#39; results for string data and is relati...
Definition: fnv_hash.cpp:33
#define WPRINTF_ARGS(fmtpos)
static Status errorToSkip
Definition: debug.cpp:488
ignore and do not report again.
Definition: debug.h:163
static ErrorReaction PerformErrorReaction(ErrorReactionInternal er, size_t flags, atomic_bool *suppress)
Definition: debug.cpp:383
#define u32
Definition: types.h:41
void debug_FreeErrorMessage(ErrorMessageMem *emm)
free memory from the error message.
Definition: debug.cpp:209
ErrorReaction debug_OnError(Status err, atomic_bool *suppress, const wchar_t *file, int line, const char *func)
called when a DEBUG_WARN_ERR indicates an error occurred; notifies the user via debug_DisplayError.
Definition: debug.cpp:534
void * pa_mem
Definition: debug.h:546
const Status SYM_INTERNAL_ERROR
Definition: debug.h:405
bool cpu_CAS(volatile intptr_t *location, intptr_t expected, intptr_t newValue)
atomic &quot;compare and swap&quot;.
Definition: arm.cpp:36
static bool ShouldSuppressError(atomic_bool *suppress)
Definition: debug.cpp:358
wchar_t * StatusDescription(Status status, wchar_t *buf, size_t max_chars)
generate textual description of a Status.
Definition: status.cpp:79
holds memory for an error message.
Definition: debug.h:535
const wchar_t * path_name_only(const wchar_t *path)
Get the path component of a path.
Definition: path.cpp:85
size_t debug_StopSkippingErrors()
Definition: debug.cpp:504
bool operator()(const wchar_t *fmt,...) WPRINTF_ARGS(2)
Definition: debug.cpp:225
#define DEBUG_DISPLAY_ERROR(description)
Definition: debug.h:197
void * Allocate(size_t size, PageType pageType, int prot)
reserve address space and commit memory.
Definition: uvm.cpp:98
static const size_t DEBUG_CONTEXT_SIZE
Definition: debug.h:451
void debug_filter_remove(const wchar_t *tag)
in future, discard output with the given tag.
Definition: debug.cpp:96
const Status FAIL
Definition: status.h:406
const OsPath & ah_get_log_dir()
return path to directory into which crash dumps should be written.
Definition: app_hooks.cpp:151
const Status SYM_NESTING_LIMIT
Definition: debug.h:409
static const StatusDefinition debugStatusDefinitions[]
Definition: debug.cpp:45
#define CACHE_ALIGNED(type)
Definition: alignment.h:52
#define cassert(expr)
Compile-time assertion.
const Status SYM_SINGLE_SYMBOL_LIMIT
Definition: debug.h:412
static u32 tags[MAX_TAGS]
Definition: debug.cpp:74
ErrorReaction debug_OnAssertionFailure(const wchar_t *expr, atomic_bool *suppress, const wchar_t *file, int line, const char *func)
called when a ENSURE/ASSERT fails; notifies the user via debug_DisplayError.
Definition: debug.cpp:550
static bool ShouldSkipError(Status err)
Definition: debug.cpp:520
void Free(void *p, size_t size)
decommit memory and release address space.
Definition: uvm.cpp:113
int vswprintf_s(wchar_t *dst, size_t max_dst_chars, const wchar_t *fmt, va_list ap) VWPRINTF_ARGS(3)
static atomic_bool isExiting
Definition: debug.cpp:354
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
Definition: debug.cpp:142
ignore, continue as if nothing happened.
Definition: debug.h:138
static enum @41 state
LIB_API Status debug_DumpStack(wchar_t *buf, size_t maxChars, void *context, const wchar_t *lastFuncToSkip)
write a complete stack trace (including values of local variables) into the specified buffer...
Definition: bdbg.cpp:52
const wchar_t * ah_translate(const wchar_t *text)
translate text to the current locale.
Definition: app_hooks.cpp:161
ErrorReactionInternal
all choices offered by the error dialog.
Definition: debug.h:154
void ah_bundle_logs(FILE *f)
gather all app-related logs/information and write it to file.
Definition: app_hooks.cpp:156
void debug_SkipErrors(Status err)
suppress (prevent from showing) the error dialog from subsequent debug_OnError for the given Status...
Definition: debug.cpp:491