Pyrogenesis
13997
|
#include "lib/lib_api.h"
#include "lib/types.h"
#include "lib/status.h"
#include "lib/alignment.h"
#include "lib/code_annotation.h"
#include "lib/code_generation.h"
Go to the source code of this file.
Classes | |
struct | ErrorMessageMem |
holds memory for an error message. More... | |
Namespaces | |
ERR | |
Introduction | |
INFO | |
Macros | |
#define | DEBUG_DISPLAY_ERROR(description) |
#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... | |
Typedefs | |
typedef volatile intptr_t | atomic_bool |
a bool that is reasonably certain to be set atomically. 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... | |
LIB_API void | debug_printf (const wchar_t *fmt,...) WPRINTF_ARGS(1) |
write a formatted string to the debug channel, subject to filtering (see below). More... | |
LIB_API void | debug_DisplayMessage (const wchar_t *caption, const wchar_t *msg) |
translates and displays the given strings in a dialog. More... | |
LIB_API 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. More... | |
LIB_API void | debug_filter_add (const wchar_t *tag) |
debug output is very useful, but "too much of a good thing can kill you". More... | |
LIB_API void | debug_filter_remove (const wchar_t *tag) |
in future, discard output with the given tag. More... | |
LIB_API void | debug_filter_clear () |
clear all filter state; equivalent to debug_filter_remove for each tag that was debug_filter_add-ed. More... | |
LIB_API bool | debug_filter_allows (const wchar_t *text) |
indicate if the given text would be printed. More... | |
LIB_API Status | debug_WriteCrashlog (const wchar_t *text) |
write an error description and all logs into crashlog.txt (in unicode format). More... | |
LIB_API 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. More... | |
LIB_API 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... | |
LIB_API void | debug_SkipErrors (Status err) |
suppress (prevent from showing) the error dialog from subsequent debug_OnError for the given Status. More... | |
LIB_API size_t | debug_StopSkippingErrors () |
LIB_API 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... | |
LIB_API Status | debug_CaptureContext (void *context) |
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. More... | |
LIB_API void | debug_puts (const wchar_t *text) |
[system-dependent] write a string to the debug channel. More... | |
LIB_API void * | debug_GetCaller (void *context, const wchar_t *lastFuncToSkip) |
return the caller of a certain function on the call stack. More... | |
LIB_API int | debug_IsPointerBogus (const void *p) |
check if a pointer appears to be totally invalid. More... | |
LIB_API bool | debug_IsCodePointer (void *p) |
does the given pointer appear to point to code? More... | |
LIB_API bool | debug_IsStackPointer (void *p) |
does the given pointer appear to point to the stack? More... | |
LIB_API void | debug_SetThreadName (const char *name) |
inform the debugger of the current thread's name. More... | |
LIB_API void | debug_FreeErrorMessage (ErrorMessageMem *emm) |
free memory from the error message. More... | |
LIB_API 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. More... | |
Variables | |
static const atomic_bool | DEBUG_SUPPRESS = 0xAB |
value for suppress flag once set by debug_DisplayError. More... | |
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 | ) |
#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").
typedef volatile intptr_t atomic_bool |
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 | ( | ) |
LIB_API 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.
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. |
emm | memory 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. |
LIB_API Status debug_CaptureContext | ( | void * | context | ) |
LIB_API 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.
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. values: see DEBUG_SUPPRESS above. |
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.
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. |
LIB_API void debug_filter_add | ( | const wchar_t * | 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.
LIB_API bool debug_filter_allows | ( | const wchar_t * | text | ) |
LIB_API void debug_filter_clear | ( | ) |
LIB_API void debug_filter_remove | ( | const wchar_t * | tag | ) |
LIB_API void debug_FreeErrorMessage | ( | ErrorMessageMem * | emm | ) |
LIB_API void* debug_GetCaller | ( | void * | context, |
const wchar_t * | lastFuncToSkip | ||
) |
LIB_API bool debug_IsCodePointer | ( | void * | p | ) |
LIB_API 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 |
LIB_API bool debug_IsStackPointer | ( | void * | p | ) |
LIB_API 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.
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 |
LIB_API 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.
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 |
LIB_API void debug_printf | ( | const wchar_t * | fmt, |
... | |||
) |
LIB_API void debug_puts | ( | const wchar_t * | text | ) |
LIB_API 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.
LIB_API void debug_SetThreadName | ( | const char * | name | ) |
LIB_API 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.
LIB_API size_t debug_StopSkippingErrors | ( | ) |
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 |