Pyrogenesis  trunk
Classes | Enumerations | Functions | Variables
debug.cpp File Reference
#include "precompiled.h"
#include "lib/debug.h"
#include <cstdarg>
#include <cstring>
#include <cstdio>
#include "lib/alignment.h"
#include "lib/app_hooks.h"
#include "lib/fnv_hash.h"
#include "lib/sysdep/vm.h"
#include "lib/sysdep/cpu.h"
#include "lib/sysdep/sysdep.h"
Include dependency graph for debug.cpp:

Classes

class  PrintfWriter
 

Enumerations

enum  SkipStatus { INVALID, VALID, BUSY }
 

Functions

 STATUS_ADD_DEFINITIONS (debugStatusDefinitions)
 
void debug_filter_add (const char *tag)
 debug output is very useful, but "too much of a good thing can kill you". More...
 
void debug_filter_remove (const char *tag)
 in future, discard output with the given tag. More...
 
void debug_filter_clear ()
 clear all filter state; equivalent to debug_filter_remove for each tag that was debug_filter_add-ed. More...
 
bool debug_filter_allows (const char *text)
 indicate if the given text would be printed. More...
 
void debug_printf (const char *fmt,...)
 write a formatted string to the debug channel, subject to filtering (see below). More...
 
void debug_puts_filtered (const char *text)
 call debug_puts if debug_filter_allows allows the string. More...
 
Status debug_WriteCrashlog (const wchar_t *text)
 
void debug_FreeErrorMessage (ErrorMessageMem *emm)
 free memory from the error message. More...
 
const wchar_tdebug_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. More...
 
void debug_DisplayMessage (const wchar_t *caption, const wchar_t *msg)
 translates and displays the given strings in a dialog. More...
 
static bool ShouldSuppressError (atomic_bool *suppress)
 
static ErrorReactionInternal CallDisplayError (const wchar_t *text, size_t flags)
 
static ErrorReaction PerformErrorReaction (ErrorReactionInternal er, size_t flags, atomic_bool *suppress)
 
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. More...
 
void debug_SkipErrors (Status err)
 suppress (prevent from showing) the error dialog from subsequent debug_OnError for the given Status. More...
 
size_t debug_StopSkippingErrors ()
 
static bool ShouldSkipError (Status err)
 
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. More...
 
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. More...
 

Variables

static const StatusDefinition debugStatusDefinitions []
 
static const size_t MAX_TAGS = 20
 
static u32 tags [MAX_TAGS]
 
static size_t num_tags
 
static const size_t messageSize = 512*KiB
 
static atomic_bool isExiting
 
static intptr_t skipStatus = INVALID
 
static Status errorToSkip
 
static size_t numSkipped
 

Enumeration Type Documentation

enum SkipStatus
Enumerator
INVALID 
VALID 
BUSY 

Function Documentation

static ErrorReactionInternal CallDisplayError ( const wchar_t text,
size_t  flags 
)
static
const wchar_t* debug_BuildErrorMessage ( const wchar_t description,
const wchar_t fn_only,
int  line,
const char *  func,
void *  context,
const wchar_t lastFuncToSkip,
ErrorMessageMem emm 
)

build a string describing the given error.

this is a helper function used by debug_DumpStack and is made available so that the self-test doesn't have to display the error dialog.

Parameters
descriptiongeneral description of the problem.
fn_onlyfilename (no path) of source file that triggered the error.
line,funcexact position of the error.
context,lastFuncToSkipsee debug_DumpStack.
emmmemory for the error message. caller should allocate stack memory and set alloc_buf*; if not, there will be no fallback in case heap alloc fails. should be freed via debug_FreeErrorMessage when no longer needed.
ErrorReaction debug_DisplayError ( const wchar_t description,
size_t  flags,
void *  context,
const wchar_t lastFuncToSkip,
const wchar_t file,
int  line,
const char *  func,
atomic_bool suppress 
)

display an error dialog with a message and stack trace.

Parameters
descriptiontext to show.
flagssee DebugDisplayErrorFlags.
context,lastFuncToSkipsee debug_DumpStack.
file,line,funclocation of the error (typically passed as WIDEN(FILE), LINE, func from a macro)
suppresspointer to a caller-allocated flag that can be used to suppress this error. if NULL, this functionality is skipped and the "Suppress" dialog button will be disabled. note: this flag is read and written exclusively here; caller only provides the storage. values: see DEBUG_SUPPRESS above.
Returns
ErrorReaction (user's choice: continue running or stop?)
void debug_DisplayMessage ( const wchar_t caption,
const wchar_t msg 
)

translates and displays the given strings in a dialog.

this is typically only used when debug_DisplayError has failed or is unavailable because that function is much more capable. implemented via sys_display_msg; see documentation there.

void debug_filter_add ( const char *  tag)

debug output is very useful, but "too much of a good thing can kill you".

we don't want to require different LOGn() macros that are enabled depending on "debug level", because changing that entails lengthy compiles and it's too coarse-grained. instead, we require all strings to start with "tag_string|" (exact case and no quotes; the alphanumeric-only <tag_string> identifies output type). they are then subject to filtering: only if the tag has been "added" via debug_filter_add is the appendant string displayed.

this approach is easiest to implement and is fine because we control all logging code. LIMODS falls from consideration since it's not portable and too complex.

notes:

  • filter changes only affect subsequent debug_*printf calls; output that didn't pass the filter is permanently discarded.
  • strings not starting with a tag are always displayed.
  • debug_filter_* can be called at any time and from the debugger, but are not reentrant.

in future, allow output with the given tag to proceed. no effect if already added.

bool debug_filter_allows ( const char *  text)

indicate if the given text would be printed.

useful for a series of debug_printfs - avoids needing to add a tag to each of their format strings.

void debug_filter_clear ( )

clear all filter state; equivalent to debug_filter_remove for each tag that was debug_filter_add-ed.

void debug_filter_remove ( const char *  tag)

in future, discard output with the given tag.

no effect if not currently added.

void debug_FreeErrorMessage ( ErrorMessageMem emm)

free memory from the error message.

Parameters
emmErrorMessageMem*
ErrorReaction debug_OnAssertionFailure ( const wchar_t assert_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.

Parameters
assert_exprthe expression that failed; typically passed as #expr in the assert macro.
suppresssee debug_DisplayError.
file,linesource file name and line number of the spot that failed
funcname of the function containing it
Returns
ErrorReaction (user's choice: continue running or stop?)
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.

Parameters
errStatus value indicating the error that occurred
suppresssee debug_DisplayError.
file,linesource file name and line number of the spot that failed
funcname of the function containing it
Returns
ErrorReaction (user's choice: continue running or stop?)
void debug_printf ( const char *  fmt,
  ... 
)

write a formatted string to the debug channel, subject to filtering (see below).

implemented via debug_puts - see performance note there.

Parameters
fmtFormat string and varargs; see printf.
void debug_puts_filtered ( const char *  text)

call debug_puts if debug_filter_allows allows the string.

void debug_SkipErrors ( Status  err)

suppress (prevent from showing) the error dialog from subsequent debug_OnError for the given Status.

rationale: for edge cases in some functions, warnings are raised in addition to returning an error code. self-tests deliberately trigger these cases and check for the latter but shouldn't cause the former. we therefore need to squelch them.

Parameters
errthe Status to skip.

note: only one concurrent skip request is allowed; call debug_StopSkippingErrors before the next debug_SkipErrors.

size_t debug_StopSkippingErrors ( )
Returns
how many errors were skipped since the call to debug_SkipErrors()
Status debug_WriteCrashlog ( const wchar_t text)
static ErrorReaction PerformErrorReaction ( ErrorReactionInternal  er,
size_t  flags,
atomic_bool suppress 
)
static
static bool ShouldSkipError ( Status  err)
static
static bool ShouldSuppressError ( atomic_bool suppress)
static
STATUS_ADD_DEFINITIONS ( debugStatusDefinitions  )

Variable Documentation

const StatusDefinition debugStatusDefinitions[]
static
Initial value:
= {
{ ERR::SYM_NO_STACK_FRAMES_FOUND, L"No stack frames found" },
{ ERR::SYM_UNRETRIEVABLE_STATIC, L"Value unretrievable (stored in external module)" },
{ ERR::SYM_UNRETRIEVABLE, L"Value unretrievable" },
{ ERR::SYM_TYPE_INFO_UNAVAILABLE, L"Error getting type_info" },
{ ERR::SYM_INTERNAL_ERROR, L"Exception raised while processing a symbol" },
{ ERR::SYM_UNSUPPORTED, L"Symbol type not (fully) supported" },
{ ERR::SYM_CHILD_NOT_FOUND, L"Symbol does not have the given child" },
{ ERR::SYM_NESTING_LIMIT, L"Symbol nesting too deep or infinite recursion" },
{ ERR::SYM_SINGLE_SYMBOL_LIMIT, L"Symbol has produced too much output" },
{ INFO::SYM_SUPPRESS_OUTPUT, L"Symbol was suppressed" }
}
const Status SYM_UNSUPPORTED
Definition: debug.h:411
const Status SYM_SUPPRESS_OUTPUT
Definition: debug.h:425
const Status SYM_CHILD_NOT_FOUND
Definition: debug.h:412
const Status SYM_UNRETRIEVABLE_STATIC
Definition: debug.h:407
const Status SYM_UNRETRIEVABLE
Definition: debug.h:408
const Status SYM_NO_STACK_FRAMES_FOUND
Definition: debug.h:406
const Status SYM_TYPE_INFO_UNAVAILABLE
Definition: debug.h:409
const Status SYM_INTERNAL_ERROR
Definition: debug.h:410
const Status SYM_NESTING_LIMIT
Definition: debug.h:414
const Status SYM_SINGLE_SYMBOL_LIMIT
Definition: debug.h:417
Status errorToSkip
static
atomic_bool isExiting
static
const size_t MAX_TAGS = 20
static
const size_t messageSize = 512*KiB
static
size_t num_tags
static
size_t numSkipped
static
intptr_t skipStatus = INVALID
static
u32 tags[MAX_TAGS]
static