Pyrogenesis
trunk
|
#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 char *fmt,...) PRINTF_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 char *tag) |
debug output is very useful, but "too much of a good thing can kill you". More... | |
LIB_API void | debug_filter_remove (const char *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 char *text) |
indicate if the given text would be printed. More... | |
LIB_API void | debug_puts_filtered (const char *text) |
call debug_puts if debug_filter_allows allows the string. More... | |
LIB_API Status | debug_WriteCrashlog (const char *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) ANALYZER_NORETURN |
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) ANALYZER_NORETURN |
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 char *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 |
a bool that is reasonably certain to be set atomically.
we cannot assume support for OpenMP (requires GCC 4.2) or C++0x, so we'll have to resort to intptr_t, cpu_CAS and COMPILER_FENCE.
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.
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 | ) |
context | must point to an instance of the platform-specific type (e.g. CONTEXT) or CACHE_ALIGNED storage of DEBUG_CONTEXT_SIZE bytes. |
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. |
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.
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 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.
LIB_API 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.
LIB_API void debug_filter_clear | ( | ) |
clear all filter state; equivalent to debug_filter_remove for each tag that was debug_filter_add-ed.
LIB_API void debug_filter_remove | ( | const char * | tag | ) |
in future, discard output with the given tag.
no effect if not currently added.
LIB_API void debug_FreeErrorMessage | ( | ErrorMessageMem * | emm | ) |
free memory from the error message.
emm | ErrorMessageMem* |
LIB_API 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 |
LIB_API bool debug_IsCodePointer | ( | void * | p | ) |
does the given pointer appear to point to code?
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 | ) |
does the given pointer appear to point to the stack?
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 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. |
LIB_API 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).
LIB_API void debug_puts_filtered | ( | const char * | text | ) |
call debug_puts if debug_filter_allows allows the string.
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 | ) |
inform the debugger of the current thread's name.
(threads are easier to keep apart when they are identified by name rather than TID.)
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 | ( | ) |
LIB_API 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 |
value for suppress flag once set by debug_DisplayError.
rationale: this value is fairly distinctive and helps when debugging the symbol engine. use 0 as the initial value to avoid allocating .rdata space.
|
static |
Maximum number of characters (including null terminator) written to user's buffers by debug_ResolveSymbol.