Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
|
#include "lib/alignment.h"
#include "lib/code_annotation.h"
#include "lib/code_generation.h"
#include "lib/status.h"
#include "lib/types.h"
#include <atomic>
Go to the source code of this file.
Namespaces | |
namespace | ERR |
namespace | INFO |
Macros | |
#define | DEBUG_DISPLAY_ERROR_IMPL(description, flags) |
#define | DEBUG_DISPLAY_ERROR(description) DEBUG_DISPLAY_ERROR_IMPL(description, 0) |
#define | DEBUG_DISPLAY_FATAL_ERROR(description) DEBUG_DISPLAY_ERROR_IMPL(description, DE_NO_CONTINUE) |
#define | ENSURE(expr) |
ensure the expression <expr> evaluates to non-zero. More... | |
#define | ASSERT(expr) ENSURE(expr) |
same as ENSURE in debug mode, does nothing in release mode. More... | |
#define | debug_warn(expr) ENSURE(0 && (expr)) |
display the error dialog with the given text. More... | |
#define | DEBUG_WARN_ERR(status) |
display the error dialog with text corresponding to the given error code. More... | |
Enumerations | |
enum | DebugDisplayErrorFlags { DE_NO_CONTINUE = 1 , DE_ALLOW_SUPPRESS = 2 , DE_MANUAL_BREAK = 4 , DE_NO_DEBUG_INFO = 8 } |
flags to customize debug_DisplayError behavior More... | |
enum | ErrorReaction { ER_CONTINUE = 1 , ER_BREAK } |
choices offered by the error dialog that are returned by debug_DisplayError. More... | |
enum | ErrorReactionInternal { ERI_CONTINUE = ER_CONTINUE , ERI_BREAK = ER_BREAK , ERI_SUPPRESS , ERI_EXIT , ERI_NOT_IMPLEMENTED } |
all choices offered by the error dialog. More... | |
Functions | |
void | debug_break () |
trigger a breakpoint when reached/"called". More... | |
void | debug_printf (const char *fmt,...) PRINTF_ARGS(1) |
write a formatted string to the debug channel, subject to filtering (see below). More... | |
void | debug_DisplayMessage (const wchar_t *caption, const wchar_t *msg) |
translates and displays the given strings in a dialog. More... | |
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, std::atomic< bool > *suppress) |
display an error dialog with a message and stack trace. More... | |
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_puts_filtered (const char *text) |
call debug_puts if debug_filter_allows allows the string. More... | |
Status | debug_WriteCrashlog (const char *text) |
write an error description and all logs into crashlog.txt (in unicode format). More... | |
ErrorReaction | debug_OnAssertionFailure (const wchar_t *assert_expr, std::atomic< bool > *suppress, const wchar_t *file, int line, const char *func) ANALYZER_NORETURN |
called when a ENSURE/ASSERT fails; notifies the user via debug_DisplayError. More... | |
ErrorReaction | debug_OnError (Status err, std::atomic< bool > *suppress, const wchar_t *file, int line, const char *func) ANALYZER_NORETURN |
called when a DEBUG_WARN_ERR indicates an error occurred; notifies the user via debug_DisplayError. 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 () |
Status | debug_ResolveSymbol (void *ptr_of_interest, wchar_t *sym_name, wchar_t *file, int *line) |
read and return symbol information for the given address. More... | |
Status | debug_CaptureContext (void *context) |
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. More... | |
void | debug_puts (const char *text) |
[system-dependent] write a string to the debug channel. More... | |
void * | debug_GetCaller (void *context, const wchar_t *lastFuncToSkip) |
return the caller of a certain function on the call stack. More... | |
int | debug_IsPointerBogus (const void *p) |
check if a pointer appears to be totally invalid. More... | |
bool | debug_IsCodePointer (void *p) |
does the given pointer appear to point to code? More... | |
bool | debug_IsStackPointer (void *p) |
does the given pointer appear to point to the stack? More... | |
void | debug_SetThreadName (const char *name) |
inform the debugger of the current thread's name. More... | |
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) |
build a string describing the given error. More... | |
Variables | |
const Status | ERR::SYM_NO_STACK_FRAMES_FOUND = -100400 |
const Status | ERR::SYM_UNRETRIEVABLE_STATIC = -100401 |
const Status | ERR::SYM_UNRETRIEVABLE = -100402 |
const Status | ERR::SYM_TYPE_INFO_UNAVAILABLE = -100403 |
const Status | ERR::SYM_INTERNAL_ERROR = -100404 |
const Status | ERR::SYM_UNSUPPORTED = -100405 |
const Status | ERR::SYM_CHILD_NOT_FOUND = -100406 |
const Status | ERR::SYM_NESTING_LIMIT = -100407 |
const Status | ERR::SYM_SINGLE_SYMBOL_LIMIT = -100408 |
const Status | INFO::SYM_SUPPRESS_OUTPUT = +100409 |
static const size_t | DEBUG_SYMBOL_CHARS = 1000 |
Maximum number of characters (including null terminator) written to user's buffers by debug_ResolveSymbol. More... | |
static const size_t | DEBUG_FILE_CHARS = 100 |
static const size_t | DEBUG_CONTEXT_SIZE = 2048 |
#define ASSERT | ( | expr | ) | ENSURE(expr) |
same as ENSURE in debug mode, does nothing in release mode.
(we don't override the ‘assert’ macro because users may inadvertently include <assert.h> afterwards) (we do not provide an MFC-style VERIFY macro because the distinction between ENSURE and VERIFY is unclear. to always run code but only check for success in debug builds without raising unused-variable warnings, use ASSERT + UNUSED2.)
#define DEBUG_DISPLAY_ERROR | ( | description | ) | DEBUG_DISPLAY_ERROR_IMPL(description, 0) |
#define DEBUG_DISPLAY_ERROR_IMPL | ( | description, | |
flags | |||
) |
#define DEBUG_DISPLAY_FATAL_ERROR | ( | description | ) | DEBUG_DISPLAY_ERROR_IMPL(description, DE_NO_CONTINUE) |
#define debug_warn | ( | expr | ) | ENSURE(0 && (expr)) |
display the error dialog with the given text.
this is less error-prone than ENSURE(0 && "text"). note that "conditional expression is constant" warnings are disabled anyway.
if being able to suppress the warning is desirable (e.g. for self-tests), then use DEBUG_WARN_ERR instead.
#define DEBUG_WARN_ERR | ( | status | ) |
display the error dialog with text corresponding to the given error code.
used by WARN_RETURN_STATUS_IF_ERR et al., which wrap function calls and automatically raise warnings and return to the caller.
#define ENSURE | ( | expr | ) |
ensure the expression <expr> evaluates to non-zero.
used to validate invariants in the program during development and thus gives a very helpful warning if something isn't going as expected. sprinkle these liberally throughout your code!
to pass more information to users at runtime, you can write ENSURE(expression && "descriptive string").
flags to customize debug_DisplayError behavior
enum ErrorReaction |
choices offered by the error dialog that are returned by debug_DisplayError.
all choices offered by the error dialog.
those not defined in ErrorReaction are acted upon by debug_DisplayError and never returned to callers. (this separation avoids enumerator-not-handled warnings)
void debug_break | ( | ) |
trigger a breakpoint when reached/"called".
if defined as a macro, the debugger can break directly into the target function instead of one frame below it as with a conventional call-based implementation.
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 | ||
) |
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.
description | general description of the problem. |
fn_only | filename (no path) of source file that triggered the error. |
line,func | exact position of the error. |
context,lastFuncToSkip | see debug_DumpStack. |
Status debug_CaptureContext | ( | void * | context | ) |
context | must point to an instance of the platform-specific type (e.g. CONTEXT) or CACHE_ALIGNED storage of DEBUG_CONTEXT_SIZE bytes. |
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, | ||
std::atomic< bool > * | suppress | ||
) |
display an error dialog with a message and stack trace.
description | text to show. |
flags | see DebugDisplayErrorFlags. |
context,lastFuncToSkip | see debug_DumpStack. |
file,line,func | location of the error (typically passed as WIDEN(FILE), LINE, func from a macro) |
suppress | pointer 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. |
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.
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.
buf | Target buffer. |
maxChars | Max chars of buffer (should be several thousand). |
context | Platform-specific representation of execution state (e.g. Win32 CONTEXT). either specify an SEH exception's context record or use debug_CaptureContext to retrieve the current state. Rationale: intermediates such as debug_DisplayError change the context, so it should be captured as soon as possible. |
lastFuncToSkip | Is used for omitting error-reporting functions like debug_OnAssertionFailure from the stack trace. It is either 0 (skip nothing) or a substring of a function's name (this allows platform-independent matching of stdcall-decorated names). Rationale: this is safer than specifying a fixed number of frames, which can be incorrect due to inlining. |
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:
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_GetCaller | ( | void * | context, |
const wchar_t * | lastFuncToSkip | ||
) |
return the caller of a certain function on the call stack.
this function is useful for recording (partial) stack traces for memory allocation tracking, etc.
context,lastFuncToSkip | - see debug_DumpStack |
bool debug_IsCodePointer | ( | void * | p | ) |
does the given pointer appear to point to code?
int debug_IsPointerBogus | ( | const void * | p | ) |
check if a pointer appears to be totally invalid.
this check is not authoritative (the pointer may be "valid" but incorrect) but can be used to filter out obviously wrong values in a portable manner.
p | pointer |
bool debug_IsStackPointer | ( | void * | p | ) |
does the given pointer appear to point to the stack?
ErrorReaction debug_OnAssertionFailure | ( | const wchar_t * | assert_expr, |
std::atomic< bool > * | suppress, | ||
const wchar_t * | file, | ||
int | line, | ||
const char * | func | ||
) |
called when a ENSURE/ASSERT fails; notifies the user via debug_DisplayError.
assert_expr | the expression that failed; typically passed as #expr in the assert macro. |
suppress | see debug_DisplayError. |
file,line | source file name and line number of the spot that failed |
func | name of the function containing it |
ErrorReaction debug_OnError | ( | Status | err, |
std::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.
err | Status value indicating the error that occurred |
suppress | see debug_DisplayError. |
file,line | source file name and line number of the spot that failed |
func | name of the function containing it |
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.
fmt | Format string and varargs; see printf. |
void debug_puts | ( | const char * | text | ) |
[system-dependent] write a string to the debug channel.
this can be quite slow (~1 ms)! On Windows, it uses OutputDebugString (entails context switch), otherwise stdout+fflush (waits for IO).
void debug_puts_filtered | ( | const char * | text | ) |
call debug_puts if debug_filter_allows allows the string.
Status debug_ResolveSymbol | ( | void * | ptr_of_interest, |
wchar_t * | sym_name, | ||
wchar_t * | file, | ||
int * | line | ||
) |
read and return symbol information for the given address.
NOTE: the PDB implementation is rather slow (~500 us).
ptr_of_interest | address of symbol (e.g. function, variable) |
sym_name | optional out; holds at least DEBUG_SYMBOL_CHARS; receives symbol name returned via debug info. |
file | optional out; holds at least DEBUG_FILE_CHARS; receives base name only (no path; see rationale in wdbg_sym) of source file containing the symbol. |
line | optional out; receives source file line number of symbol. |
note: all of the output parameters are optional; we pass back as much information as is available and desired.
void debug_SetThreadName | ( | const char * | name | ) |
inform the debugger of the current thread's name.
(threads are easier to keep apart when they are identified by name rather than TID.)
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.
err | the Status to skip. |
note: only one concurrent skip request is allowed; call debug_StopSkippingErrors before the next debug_SkipErrors.
size_t debug_StopSkippingErrors | ( | ) |
Status debug_WriteCrashlog | ( | const char * | text | ) |
write an error description and all logs into crashlog.txt (in unicode format).
text | description of the error (including stack trace); typically generated by debug_BuildErrorMessage. |
|
static |
|
static |
|
static |
Maximum number of characters (including null terminator) written to user's buffers by debug_ResolveSymbol.