forked from mirrors/0ad
fixes to stack trace code under x64 (from work):
- displaying symbol values requires stack pointer, not frame pointer - update debug_IsPointerBogus - skip-n-frames code changed to skip-all-frames-up-to-func (more reliable in the face of inlining) debug.cpp: cleanup This was SVN commit r6410.
This commit is contained in:
@@ -32,7 +32,7 @@ static LibError validate_da(DynArray* da)
|
||||
const int prot = da->prot;
|
||||
|
||||
// note: this happens if max_size == 0
|
||||
// if(debug_is_pointer_bogus(base))
|
||||
// if(debug_IsPointerBogus(base))
|
||||
// WARN_RETURN(ERR::_1);
|
||||
// note: don't check if base is page-aligned -
|
||||
// might not be true for 'wrapped' mem regions.
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
u8 buf[4];
|
||||
TS_ASSERT_OK(da_read(&da, buf, 4));
|
||||
TS_ASSERT_EQUALS(read_le32(buf), 0x78563412); // read correct value
|
||||
debug_skip_next_err(ERR::FAIL);
|
||||
debug_SkipNextError(ERR::FAIL);
|
||||
TS_ASSERT(da_read(&da, buf, 1) < 0); // no more data left
|
||||
TS_ASSERT_OK(da_free(&da));
|
||||
}
|
||||
|
||||
+102
-109
@@ -47,24 +47,24 @@ wchar_t* debug_log_pos = debug_log;
|
||||
// write to memory buffer (fast)
|
||||
void debug_wprintf_mem(const wchar_t* fmt, ...)
|
||||
{
|
||||
const ssize_t chars_left = (ssize_t)LOG_CHARS - (debug_log_pos-debug_log);
|
||||
debug_assert(chars_left >= 0);
|
||||
const ssize_t charsLeft = (ssize_t)LOG_CHARS - (debug_log_pos-debug_log);
|
||||
debug_assert(charsLeft >= 0);
|
||||
|
||||
// potentially not enough room for the new string; throw away the
|
||||
// older half of the log. we still protect against overflow below.
|
||||
if(chars_left < 512)
|
||||
if(charsLeft < 512)
|
||||
{
|
||||
const size_t copy_size = sizeof(wchar_t) * LOG_CHARS/2;
|
||||
const size_t copySize = sizeof(wchar_t) * LOG_CHARS/2;
|
||||
wchar_t* const middle = &debug_log[LOG_CHARS/2];
|
||||
cpu_memcpy(debug_log, middle, copy_size);
|
||||
memset(middle, 0, copy_size);
|
||||
cpu_memcpy(debug_log, middle, copySize);
|
||||
memset(middle, 0, copySize);
|
||||
debug_log_pos -= LOG_CHARS/2; // don't assign middle (may leave gap)
|
||||
}
|
||||
|
||||
// write into buffer (in-place)
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = vswprintf(debug_log_pos, chars_left-2, fmt, args);
|
||||
int len = vswprintf(debug_log_pos, charsLeft-2, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
debug_log_pos += len+2;
|
||||
@@ -194,22 +194,22 @@ void debug_printf(const wchar_t* fmt, ...)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LibError debug_write_crashlog(const wchar_t* text)
|
||||
LibError debug_WriteCrashlog(const wchar_t* text)
|
||||
{
|
||||
// avoid potential infinite loop if an error occurs here.
|
||||
static uintptr_t in_progress;
|
||||
if(!cpu_CAS(&in_progress, 0, 1))
|
||||
static uintptr_t isBusy;
|
||||
if(!cpu_CAS(&isBusy, 0, 1))
|
||||
return ERR::REENTERED; // NOWARN
|
||||
|
||||
OsPath path = OsPath(ah_get_log_dir())/"crashlog.txt";
|
||||
FILE* f = fopen(path.string().c_str(), "w");
|
||||
if(!f)
|
||||
{
|
||||
in_progress = 0;
|
||||
isBusy = 0;
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
}
|
||||
|
||||
fputwc(0xfeff, f); // BOM
|
||||
fputwc(0xFEFF, f); // BOM
|
||||
fwprintf(f, L"%ls\n", text);
|
||||
fwprintf(f, L"\n\n====================================\n\n");
|
||||
|
||||
@@ -219,7 +219,7 @@ LibError debug_write_crashlog(const wchar_t* text)
|
||||
fwprintf(f, L"Last known activity:\n\n %ls\n", debug_log);
|
||||
|
||||
fclose(f);
|
||||
in_progress = 0;
|
||||
isBusy = 0;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@@ -229,10 +229,10 @@ LibError debug_write_crashlog(const wchar_t* text)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// translates and displays the given strings in a dialog.
|
||||
// this is typically only used when debug_display_error has failed or
|
||||
// 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_display_msgw(const wchar_t* caption, const wchar_t* msg)
|
||||
void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg)
|
||||
{
|
||||
sys_display_msg(ah_translate(caption), ah_translate(msg));
|
||||
}
|
||||
@@ -242,11 +242,11 @@ void debug_display_msgw(const wchar_t* caption, const wchar_t* msg)
|
||||
// errors (e.g. caused by atexit handlers) to come up, possibly causing an
|
||||
// infinite loop. it sucks to hide errors, but we assume that whoever clicked
|
||||
// exit really doesn't want to see any more errors.
|
||||
static bool exit_requested;
|
||||
static bool isExiting;
|
||||
|
||||
// this logic is applicable to any type of error. special cases such as
|
||||
// suppressing certain expected WARN_ERRs are done there.
|
||||
static bool should_suppress_error(u8* suppress)
|
||||
static bool ShouldSuppressError(u8* suppress)
|
||||
{
|
||||
if(!suppress)
|
||||
return false;
|
||||
@@ -254,7 +254,7 @@ static bool should_suppress_error(u8* suppress)
|
||||
if(*suppress == DEBUG_SUPPRESS)
|
||||
return true;
|
||||
|
||||
if(exit_requested)
|
||||
if(isExiting)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -263,68 +263,67 @@ static bool should_suppress_error(u8* suppress)
|
||||
|
||||
// (NB: this may appear obscene, but deep stack traces have been
|
||||
// observed to take up > 256 KiB)
|
||||
static const size_t message_size_bytes = 512*KiB;
|
||||
static const size_t messageSize = 512*KiB;
|
||||
|
||||
void debug_error_message_free(ErrorMessageMem* emm)
|
||||
void debug_FreeErrorMessage(ErrorMessageMem* emm)
|
||||
{
|
||||
page_aligned_free(emm->pa_mem, message_size_bytes);
|
||||
page_aligned_free(emm->pa_mem, messageSize);
|
||||
}
|
||||
|
||||
// split out of debug_display_error because it's used by the self-test.
|
||||
const wchar_t* debug_error_message_build(
|
||||
|
||||
// split out of debug_DisplayError because it's used by the self-test.
|
||||
const wchar_t* debug_BuildErrorMessage(
|
||||
const wchar_t* description,
|
||||
const char* fn_only, int line, const char* func,
|
||||
size_t skip, void* context,
|
||||
const char* filename, int line, const char* func,
|
||||
void* context, const char* lastFuncToSkip,
|
||||
ErrorMessageMem* emm)
|
||||
{
|
||||
// rationale: see ErrorMessageMem
|
||||
emm->pa_mem = page_aligned_alloc(message_size_bytes);
|
||||
emm->pa_mem = page_aligned_alloc(messageSize);
|
||||
if(!emm->pa_mem)
|
||||
return L"(insufficient memory to generate error message)";
|
||||
wchar_t* const buf = (wchar_t*)emm->pa_mem;
|
||||
const size_t max_chars = message_size_bytes / sizeof(wchar_t);
|
||||
wchar_t* pos = buf; size_t chars_left = max_chars; int len;
|
||||
const size_t maxChars = messageSize / sizeof(wchar_t);
|
||||
wchar_t* pos = buf; size_t charsLeft = maxChars; int len;
|
||||
|
||||
// header
|
||||
len = swprintf(pos, chars_left,
|
||||
len = swprintf(pos, charsLeft,
|
||||
L"%ls\r\n"
|
||||
L"Location: %hs:%d (%hs)\r\n"
|
||||
L"\r\n"
|
||||
L"Call stack:\r\n"
|
||||
L"\r\n",
|
||||
description, fn_only, line, func);
|
||||
description, filename, line, func);
|
||||
if(len < 0)
|
||||
{
|
||||
fail:
|
||||
return L"(error while formatting error message)";
|
||||
}
|
||||
pos += len; chars_left -= len;
|
||||
pos += len; charsLeft -= len;
|
||||
|
||||
// append stack trace
|
||||
if(!context)
|
||||
skip += 2; // skip debug_error_message_build and debug_display_error
|
||||
LibError ret = debug_dump_stack(pos, chars_left, skip, context);
|
||||
LibError ret = debug_DumpStack(pos, charsLeft, context, lastFuncToSkip);
|
||||
if(ret == ERR::REENTERED)
|
||||
{
|
||||
len = swprintf(pos, chars_left,
|
||||
len = swprintf(pos, charsLeft,
|
||||
L"(cannot start a nested stack trace; what probably happened is that "
|
||||
L"an debug_assert/debug_warn/CHECK_ERR fired during the current trace.)"
|
||||
);
|
||||
if(len < 0) goto fail; pos += len; chars_left -= len;
|
||||
if(len < 0) goto fail; pos += len; charsLeft -= len;
|
||||
}
|
||||
else if(ret != INFO::OK)
|
||||
{
|
||||
char description_buf[100] = {'?'};
|
||||
len = swprintf(pos, chars_left,
|
||||
len = swprintf(pos, charsLeft,
|
||||
L"(error while dumping stack: %hs)",
|
||||
error_description_r(ret, description_buf, ARRAY_SIZE(description_buf))
|
||||
);
|
||||
if(len < 0) goto fail; pos += len; chars_left -= len;
|
||||
if(len < 0) goto fail; pos += len; charsLeft -= len;
|
||||
}
|
||||
else // success
|
||||
{
|
||||
len = (int)wcslen(buf);
|
||||
pos = buf+len; chars_left = max_chars-len;
|
||||
pos = buf+len; charsLeft = maxChars-len;
|
||||
}
|
||||
|
||||
// append OS error (just in case it happens to be relevant -
|
||||
@@ -335,18 +334,18 @@ fail:
|
||||
error_description_r(errno_equiv, description_buf, ARRAY_SIZE(description_buf));
|
||||
char os_error[100] = "?";
|
||||
sys_error_description_r(0, os_error, ARRAY_SIZE(os_error));
|
||||
len = swprintf(pos, chars_left,
|
||||
len = swprintf(pos, charsLeft,
|
||||
L"\r\n"
|
||||
L"errno = %d (%hs)\r\n"
|
||||
L"OS error = %hs\r\n",
|
||||
errno, description_buf, os_error
|
||||
);
|
||||
if(len < 0) goto fail; pos += len; chars_left -= len;
|
||||
if(len < 0) goto fail; pos += len; charsLeft -= len;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static ErrorReaction call_display_error(const wchar_t* text, size_t flags)
|
||||
static ErrorReaction CallDisplayError(const wchar_t* text, size_t flags)
|
||||
{
|
||||
// first try app hook implementation
|
||||
ErrorReaction er = ah_display_error(text, flags);
|
||||
@@ -357,16 +356,16 @@ static ErrorReaction call_display_error(const wchar_t* text, size_t flags)
|
||||
return er;
|
||||
}
|
||||
|
||||
static ErrorReaction carry_out_ErrorReaction(ErrorReaction er, size_t flags, u8* suppress)
|
||||
static ErrorReaction PerformErrorReaction(ErrorReaction er, size_t flags, u8* suppress)
|
||||
{
|
||||
const bool manual_break = (flags & DE_MANUAL_BREAK) != 0;
|
||||
const bool shouldHandleBreak = (flags & DE_MANUAL_BREAK) == 0;
|
||||
|
||||
switch(er)
|
||||
{
|
||||
case ER_BREAK:
|
||||
// handle "break" request unless the caller wants to (doing so here
|
||||
// instead of within the dlgproc yields a correct call stack)
|
||||
if(!manual_break)
|
||||
if(shouldHandleBreak)
|
||||
{
|
||||
debug_break();
|
||||
er = ER_CONTINUE;
|
||||
@@ -379,7 +378,7 @@ static ErrorReaction carry_out_ErrorReaction(ErrorReaction er, size_t flags, u8*
|
||||
break;
|
||||
|
||||
case ER_EXIT:
|
||||
exit_requested = true; // see declaration
|
||||
isExiting = true; // see declaration
|
||||
|
||||
#if OS_WIN
|
||||
// prevent (slow) heap reporting since we're exiting abnormally and
|
||||
@@ -393,13 +392,13 @@ static ErrorReaction carry_out_ErrorReaction(ErrorReaction er, size_t flags, u8*
|
||||
return er;
|
||||
}
|
||||
|
||||
ErrorReaction debug_display_error(const wchar_t* description,
|
||||
size_t flags, size_t skip, void* context,
|
||||
const char* file, int line, const char* func,
|
||||
ErrorReaction debug_DisplayError(const wchar_t* description,
|
||||
size_t flags, void* context, const char* lastFuncToSkip,
|
||||
const char* pathname, int line, const char* func,
|
||||
u8* suppress)
|
||||
{
|
||||
// "suppressing" this error means doing nothing and returning ER_CONTINUE.
|
||||
if(should_suppress_error(suppress))
|
||||
if(ShouldSuppressError(suppress))
|
||||
return ER_CONTINUE;
|
||||
|
||||
// fix up params
|
||||
@@ -410,105 +409,99 @@ ErrorReaction debug_display_error(const wchar_t* description,
|
||||
if(suppress)
|
||||
flags |= DE_ALLOW_SUPPRESS;
|
||||
// .. deal with incomplete file/line info
|
||||
if(!file || file[0] == '\0')
|
||||
file = "unknown";
|
||||
if(!pathname || pathname[0] == '\0')
|
||||
pathname = "unknown";
|
||||
if(line <= 0)
|
||||
line = 0;
|
||||
if(!func || func[0] == '\0')
|
||||
func = "?";
|
||||
// .. _FILE__ evaluates to the full path (albeit without drive letter)
|
||||
// which is rather long. we only display the base name for clarity.
|
||||
const char* fn_only = path_name_only(file);
|
||||
const char* filename = path_name_only(pathname);
|
||||
|
||||
// display in output window; double-click will navigate to error location.
|
||||
debug_printf("%s(%d): %ls\n", fn_only, line, description);
|
||||
|
||||
debug_printf("%s(%d): %ls\n", filename, line, description);
|
||||
|
||||
ErrorMessageMem emm;
|
||||
const wchar_t* text = debug_error_message_build(description,
|
||||
fn_only, line, func, skip, context, &emm);
|
||||
const wchar_t* text = debug_BuildErrorMessage(description, filename, line, func, context, lastFuncToSkip, &emm);
|
||||
|
||||
debug_write_crashlog(text);
|
||||
ErrorReaction er = call_display_error(text, flags);
|
||||
debug_WriteCrashlog(text);
|
||||
ErrorReaction er = CallDisplayError(text, flags);
|
||||
|
||||
// note: debug_break-ing here to make sure the app doesn't continue
|
||||
// running is no longer necessary. debug_display_error now determines our
|
||||
// running is no longer necessary. debug_DisplayError now determines our
|
||||
// window handle and is modal.
|
||||
|
||||
// must happen before carry_out_ErrorReaction because that may exit.
|
||||
debug_error_message_free(&emm);
|
||||
// must happen before PerformErrorReaction because that may exit.
|
||||
debug_FreeErrorMessage(&emm);
|
||||
|
||||
return carry_out_ErrorReaction(er, flags, suppress);
|
||||
return PerformErrorReaction(er, flags, suppress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// strobe indicating expected_err is valid and the next error should be
|
||||
// strobe indicating expectedError is valid and the next error should be
|
||||
// compared against that / skipped if equal to it.
|
||||
// set/reset via cpu_CAS for thread-safety (hence uintptr_t).
|
||||
static uintptr_t expected_err_valid;
|
||||
static LibError expected_err;
|
||||
static uintptr_t isExpectedErrorValid;
|
||||
static LibError expectedError;
|
||||
|
||||
void debug_skip_next_err(LibError err)
|
||||
void debug_SkipNextError(LibError err)
|
||||
{
|
||||
if(cpu_CAS(&expected_err_valid, 0, 1))
|
||||
expected_err = err;
|
||||
if(cpu_CAS(&isExpectedErrorValid, 0, 1))
|
||||
expectedError = err;
|
||||
else
|
||||
debug_assert(0); // internal error: concurrent attempt to skip assert/error
|
||||
|
||||
}
|
||||
|
||||
static bool should_skip_this_error(LibError err)
|
||||
static bool ShouldSkipThisError(LibError err)
|
||||
{
|
||||
// (compare before resetting strobe - expected_err may change afterwards)
|
||||
bool was_expected_err = (expected_err == err);
|
||||
// (compare before resetting strobe - expectedError may change afterwards)
|
||||
bool isExpected = (expectedError == err);
|
||||
// (use cpu_CAS to ensure only one error is skipped)
|
||||
if(cpu_CAS(&expected_err_valid, 1, 0))
|
||||
if(cpu_CAS(&isExpectedErrorValid, 1, 0))
|
||||
{
|
||||
debug_assert(was_expected_err);
|
||||
return was_expected_err;
|
||||
debug_assert(isExpected);
|
||||
return isExpected;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// to share code between assert and error skip mechanism, we treat the former as
|
||||
// an error. choose the code such that no one would want to warn of it.
|
||||
static const LibError assert_err = INFO::OK;
|
||||
|
||||
void debug_skip_next_assert()
|
||||
ErrorReaction debug_OnError(LibError err, u8* suppress, const char* file, int line, const char* func)
|
||||
{
|
||||
debug_skip_next_err(assert_err);
|
||||
}
|
||||
|
||||
static bool should_skip_this_assert()
|
||||
{
|
||||
return should_skip_this_error(assert_err);
|
||||
}
|
||||
|
||||
|
||||
ErrorReaction debug_assert_failed(const char* expr, u8* suppress,
|
||||
const char* file, int line, const char* func)
|
||||
{
|
||||
if(should_skip_this_assert())
|
||||
return ER_CONTINUE;
|
||||
size_t skip = 1; void* context = 0;
|
||||
wchar_t buf[400];
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"Assertion failed: \"%hs\"", expr);
|
||||
return debug_display_error(buf, DE_MANUAL_BREAK, skip,context, file,line,func, suppress);
|
||||
}
|
||||
|
||||
|
||||
ErrorReaction debug_warn_err(LibError err, u8* suppress,
|
||||
const char* file, int line, const char* func)
|
||||
{
|
||||
if(should_skip_this_error(err))
|
||||
if(ShouldSkipThisError(err))
|
||||
return ER_CONTINUE;
|
||||
|
||||
size_t skip = 1; void* context = 0;
|
||||
void* context = 0; const char* lastFuncToSkip = __func__;
|
||||
wchar_t buf[400];
|
||||
char err_buf[200]; error_description_r(err, err_buf, ARRAY_SIZE(err_buf));
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"Function call failed: return value was %d (%hs)", err, err_buf);
|
||||
return debug_display_error(buf, DE_MANUAL_BREAK, skip,context, file,line,func, suppress);
|
||||
return debug_DisplayError(buf, DE_MANUAL_BREAK, context, lastFuncToSkip, file,line,func, suppress);
|
||||
}
|
||||
|
||||
|
||||
void debug_SkipNextAssertion()
|
||||
{
|
||||
// to share code between assert and error skip mechanism, we treat the
|
||||
// former as an error.
|
||||
debug_SkipNextError(ERR::ASSERTION_FAILED);
|
||||
}
|
||||
|
||||
|
||||
static bool ShouldSkipThisAssertion()
|
||||
{
|
||||
return ShouldSkipThisError(ERR::ASSERTION_FAILED);
|
||||
}
|
||||
|
||||
ErrorReaction debug_OnAssertionFailure(const char* expr, u8* suppress, const char* file, int line, const char* func)
|
||||
{
|
||||
if(ShouldSkipThisAssertion())
|
||||
return ER_CONTINUE;
|
||||
void* context = 0; const char* lastFuncToSkip = __func__;
|
||||
wchar_t buf[400];
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"Assertion failed: \"%hs\"", expr);
|
||||
return debug_DisplayError(buf, DE_MANUAL_BREAK, context, lastFuncToSkip, file,line,func, suppress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+52
-65
@@ -50,22 +50,22 @@ LIB_API void debug_printf(const wchar_t* fmt, ...);
|
||||
|
||||
/**
|
||||
* translates and displays the given strings in a dialog.
|
||||
* this is typically only used when debug_display_error has failed or
|
||||
* 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 void debug_display_msgw(const wchar_t* caption, const wchar_t* msg);
|
||||
LIB_API void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg);
|
||||
|
||||
/// flags to customize debug_display_error behavior
|
||||
/// flags to customize debug_DisplayError behavior
|
||||
enum DebugDisplayErrorFlags
|
||||
{
|
||||
/**
|
||||
* disallow the Continue button. used e.g. if an exception is fatal.
|
||||
**/
|
||||
DE_NO_CONTINUE = 1,
|
||||
DE_NO_CONTINUE = 1,
|
||||
|
||||
/**
|
||||
* enable the Suppress button. set automatically by debug_display_error if
|
||||
* enable the Suppress button. set automatically by debug_DisplayError if
|
||||
* it receives a non-NULL suppress pointer. a flag is necessary because
|
||||
* the sys_display_error interface doesn't get that pointer.
|
||||
* rationale for automatic setting: this may prevent someone from
|
||||
@@ -75,15 +75,15 @@ enum DebugDisplayErrorFlags
|
||||
DE_ALLOW_SUPPRESS = 2,
|
||||
|
||||
/**
|
||||
* do not trigger a breakpoint inside debug_display_error; caller
|
||||
* do not trigger a breakpoint inside debug_DisplayError; caller
|
||||
* will take care of this if ER_BREAK is returned. this is so that the
|
||||
* debugger can jump directly into the offending function.
|
||||
**/
|
||||
DE_MANUAL_BREAK = 4
|
||||
DE_MANUAL_BREAK = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* value for suppress flag once set by debug_display_error.
|
||||
* value for suppress flag once set by debug_DisplayError.
|
||||
* rationale: this value is fairly distinctive and helps when
|
||||
* debugging the symbol engine.
|
||||
* initial value is 0 rather that another constant; this avoids
|
||||
@@ -106,20 +106,20 @@ enum ErrorReaction
|
||||
/**
|
||||
* trigger breakpoint, i.e. enter debugger.
|
||||
* only returned if DE_MANUAL_BREAK was passed; otherwise,
|
||||
* debug_display_error will trigger a breakpoint itself.
|
||||
* debug_DisplayError will trigger a breakpoint itself.
|
||||
**/
|
||||
ER_BREAK,
|
||||
|
||||
/**
|
||||
* ignore and do not report again.
|
||||
* note: non-persistent; only applicable during this program run.
|
||||
* acted on by debug_display_error; never returned to caller.
|
||||
* acted on by debug_DisplayError; never returned to caller.
|
||||
**/
|
||||
ER_SUPPRESS,
|
||||
|
||||
/**
|
||||
* exit the program immediately.
|
||||
* acted on by debug_display_error; never returned to caller.
|
||||
* acted on by debug_DisplayError; never returned to caller.
|
||||
**/
|
||||
ER_EXIT,
|
||||
|
||||
@@ -127,7 +127,7 @@ enum ErrorReaction
|
||||
* special return value for the display_error app hook stub to indicate
|
||||
* that it has done nothing and that the normal sys_display_error
|
||||
* implementation should be called instead.
|
||||
* acted on by debug_display_error; never returned to caller.
|
||||
* acted on by debug_DisplayError; never returned to caller.
|
||||
**/
|
||||
ER_NOT_IMPLEMENTED
|
||||
};
|
||||
@@ -137,7 +137,7 @@ enum ErrorReaction
|
||||
*
|
||||
* @param description text to show.
|
||||
* @param flags: see DebugDisplayErrorFlags.
|
||||
* @param context, skip: see debug_dump_stack.
|
||||
* @param context, lastFuncToSkip: see debug_DumpStack.
|
||||
* @param file, line, func: location of the error (typically passed as
|
||||
* __FILE__, __LINE__, __func__ from a macro)
|
||||
* @param suppress pointer to a caller-allocated flag that can be used to
|
||||
@@ -147,16 +147,13 @@ enum ErrorReaction
|
||||
* provides the storage. values: see DEBUG_SUPPRESS above.
|
||||
* @return ErrorReaction (user's choice: continue running or stop?)
|
||||
**/
|
||||
LIB_API ErrorReaction debug_display_error(const wchar_t* description,
|
||||
size_t flags, size_t skip, void* context,
|
||||
const char* file, int line, const char* func,
|
||||
u8* suppress);
|
||||
LIB_API ErrorReaction debug_DisplayError(const wchar_t* description, size_t flags, void* context, const char* lastFuncToSkip, const char* file, int line, const char* func, u8* suppress);
|
||||
|
||||
/**
|
||||
* convenience version, in case the advanced parameters aren't needed.
|
||||
* macro instead of providing overload/default values for C compatibility.
|
||||
**/
|
||||
#define DEBUG_DISPLAY_ERROR(text) debug_display_error(text, 0, 0,0, __FILE__,__LINE__,__func__, 0)
|
||||
#define DEBUG_DISPLAY_ERROR(text) debug_DisplayError(text, 0, 0, "debug_DisplayError", __FILE__,__LINE__,__func__, 0)
|
||||
|
||||
|
||||
//
|
||||
@@ -221,12 +218,12 @@ LIB_API void debug_wprintf_mem(const wchar_t* fmt, ...);
|
||||
* (in unicode format).
|
||||
*
|
||||
* @param text description of the error (including stack trace);
|
||||
* typically generated by debug_error_message_build.
|
||||
* typically generated by debug_BuildErrorMessage.
|
||||
*
|
||||
* @return LibError; ERR::REENTERED if reentered via recursion or
|
||||
* multithreading (not allowed since an infinite loop may result).
|
||||
**/
|
||||
LIB_API LibError debug_write_crashlog(const wchar_t* text);
|
||||
LIB_API LibError debug_WriteCrashlog(const wchar_t* text);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -256,7 +253,7 @@ STMT(\
|
||||
static u8 suppress__;\
|
||||
if(!(expr))\
|
||||
{\
|
||||
switch(debug_assert_failed(#expr, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
switch(debug_OnAssertionFailure(#expr, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
{\
|
||||
case ER_BREAK:\
|
||||
debug_break();\
|
||||
@@ -280,7 +277,7 @@ STMT(\
|
||||
#define debug_warn(expr) \
|
||||
STMT(\
|
||||
static u8 suppress__;\
|
||||
switch(debug_assert_failed(expr, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
switch(debug_OnAssertionFailure(expr, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
{\
|
||||
case ER_BREAK:\
|
||||
debug_break();\
|
||||
@@ -299,7 +296,7 @@ STMT(\
|
||||
#define DEBUG_WARN_ERR(err)\
|
||||
STMT(\
|
||||
static u8 suppress__;\
|
||||
switch(debug_warn_err(err, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
switch(debug_OnError(err, &suppress__, __FILE__, __LINE__, __func__))\
|
||||
{\
|
||||
case ER_BREAK:\
|
||||
debug_break();\
|
||||
@@ -312,32 +309,28 @@ STMT(\
|
||||
|
||||
/**
|
||||
* called when a debug_assert fails;
|
||||
* notifies the user via debug_display_error.
|
||||
* notifies the user via debug_DisplayError.
|
||||
*
|
||||
* @param assert_expr the expression that failed; typically passed as
|
||||
* #expr in the assert macro.
|
||||
* @param suppress see debug_display_error.
|
||||
* @param suppress see debug_DisplayError.
|
||||
* @param file, line source file name and line number of the spot that failed
|
||||
* @param func name of the function containing it
|
||||
* @return ErrorReaction (user's choice: continue running or stop?)
|
||||
**/
|
||||
LIB_API ErrorReaction debug_assert_failed(const char* assert_expr,
|
||||
u8* suppress,
|
||||
const char* file, int line, const char* func);
|
||||
LIB_API ErrorReaction debug_OnAssertionFailure(const char* assert_expr, u8* suppress, const char* file, int line, const char* func);
|
||||
|
||||
/**
|
||||
* called when a DEBUG_WARN_ERR indicates an error occurred;
|
||||
* notifies the user via debug_display_error.
|
||||
* notifies the user via debug_DisplayError.
|
||||
*
|
||||
* @param err LibError value indicating the error that occurred
|
||||
* @param suppress see debug_display_error.
|
||||
* @param suppress see debug_DisplayError.
|
||||
* @param file, line source file name and line number of the spot that failed
|
||||
* @param func name of the function containing it
|
||||
* @return ErrorReaction (user's choice: continue running or stop?)
|
||||
**/
|
||||
LIB_API ErrorReaction debug_warn_err(LibError err,
|
||||
u8* suppress,
|
||||
const char* file, int line, const char* func);
|
||||
LIB_API ErrorReaction debug_OnError(LibError err, u8* suppress, const char* file, int line, const char* func);
|
||||
|
||||
|
||||
/**
|
||||
@@ -356,14 +349,14 @@ LIB_API ErrorReaction debug_warn_err(LibError err,
|
||||
* note: this is thread-safe, but to prevent confusion, only one
|
||||
* concurrent skip request is allowed.
|
||||
*/
|
||||
LIB_API void debug_skip_next_err(LibError err);
|
||||
LIB_API void debug_SkipNextError(LibError err);
|
||||
|
||||
/**
|
||||
* same as debug_skip_next_err, but for asserts.
|
||||
* same as debug_SkipNextError, but for asserts.
|
||||
* note that this is implemented in terms of it, so only one assert or
|
||||
* error skip request may be active at a time.
|
||||
*/
|
||||
LIB_API void debug_skip_assert();
|
||||
LIB_API void debug_SkipNextAssertion();
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -397,7 +390,7 @@ namespace INFO
|
||||
|
||||
/**
|
||||
* maximum number of characters (including trailing \0) written to
|
||||
* user's buffers by debug_resolve_symbol.
|
||||
* user's buffers by debug_ResolveSymbol.
|
||||
**/
|
||||
const size_t DBG_SYMBOL_LEN = 1000;
|
||||
const size_t DBG_FILE_LEN = 100;
|
||||
@@ -420,7 +413,7 @@ const size_t DBG_FILE_LEN = 100;
|
||||
* @return LibError; INFO::OK iff any information was successfully
|
||||
* retrieved and stored.
|
||||
**/
|
||||
LIB_API LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
|
||||
LIB_API LibError debug_ResolveSymbol(void* ptr_of_interest, char* sym_name, char* file, int* line);
|
||||
|
||||
/**
|
||||
* write a complete stack trace (including values of local variables) into
|
||||
@@ -428,16 +421,19 @@ LIB_API LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, cha
|
||||
*
|
||||
* @param buf target buffer
|
||||
* @param max_chars of buffer (should be several thousand)
|
||||
* @param skip number of stack frames (i.e. functions on call stack) to skip.
|
||||
* this prevents error-reporting functions like debug_assert_failed from
|
||||
* cluttering up the trace.
|
||||
* @param context platform-specific representation of execution state
|
||||
* (e.g. Win32 CONTEXT). if not NULL, tracing starts there; this is useful
|
||||
* for exceptions. otherwise, tracing starts from the current call stack.
|
||||
* @param 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.
|
||||
* @return LibError; ERR::REENTERED if reentered via recursion or
|
||||
* multithreading (not allowed since static data is used).
|
||||
**/
|
||||
LIB_API LibError debug_dump_stack(wchar_t* buf, size_t max_chars, size_t skip, void* context);
|
||||
LIB_API LibError debug_DumpStack(wchar_t* buf, size_t maxChars, void* context, const char* lastFuncToSkip);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -452,17 +448,12 @@ LIB_API LibError debug_dump_stack(wchar_t* buf, size_t max_chars, size_t skip, v
|
||||
LIB_API void debug_puts(const char* text);
|
||||
|
||||
/**
|
||||
* return address of the Nth function on the call stack.
|
||||
* return the caller of a certain function on the call stack.
|
||||
*
|
||||
* @param skip number of stack frames (i.e. functions on call stack) to skip.
|
||||
* @param context platform-specific representation of execution state
|
||||
* (e.g. Win32 CONTEXT). if not NULL, tracing starts there; this is useful
|
||||
* for exceptions. otherwise, tracing starts from the current call stack.
|
||||
* @return address of Nth function
|
||||
*
|
||||
* note: this does not access debug symbols and is therefore quite fast.
|
||||
* @param context, lastFuncToSkip - see debug_DumpStack
|
||||
* @return address of the caller
|
||||
**/
|
||||
LIB_API void* debug_get_nth_caller(size_t skip, void* context);
|
||||
LIB_API void* debug_GetCaller(void* context, const char* lastFuncToSkip);
|
||||
|
||||
/**
|
||||
* check if a pointer appears to be totally invalid.
|
||||
@@ -473,13 +464,13 @@ LIB_API void* debug_get_nth_caller(size_t skip, void* context);
|
||||
* @param p pointer
|
||||
* @return 1 if totally bogus, otherwise 0.
|
||||
**/
|
||||
LIB_API int debug_is_pointer_bogus(const void* p);
|
||||
LIB_API int debug_IsPointerBogus(const void* p);
|
||||
|
||||
/// does the given pointer appear to point to code?
|
||||
LIB_API bool debug_is_code_ptr(void* p);
|
||||
LIB_API bool debug_IsCodePointer(void* p);
|
||||
|
||||
/// does the given pointer appear to point to the stack?
|
||||
LIB_API bool debug_is_stack_ptr(void* p);
|
||||
LIB_API bool debug_IsStackPointer(void* p);
|
||||
|
||||
|
||||
/**
|
||||
@@ -488,7 +479,7 @@ LIB_API bool debug_is_stack_ptr(void* p);
|
||||
* (threads are easier to keep apart when they are identified by
|
||||
* name rather than TID.)
|
||||
**/
|
||||
LIB_API void debug_set_thread_name(const char* name);
|
||||
LIB_API void debug_SetThreadName(const char* name);
|
||||
|
||||
|
||||
/**
|
||||
@@ -498,7 +489,7 @@ struct ErrorMessageMem
|
||||
{
|
||||
// rationale:
|
||||
// - error messages with stack traces require a good deal of memory
|
||||
// (dozens of KB). static buffers of that size are undesirable.
|
||||
// (hundreds of KB). static buffers of that size are undesirable.
|
||||
// - the heap may be corrupted, so don't use malloc. allocator.h's
|
||||
// page_aligned_malloc (implemented via mmap) should be safe.
|
||||
// - alloca is a bit iffy (the stack may be maxed out), non-portable and
|
||||
@@ -513,27 +504,23 @@ struct ErrorMessageMem
|
||||
*
|
||||
* @param ErrorMessageMem*
|
||||
**/
|
||||
LIB_API void debug_error_message_free(ErrorMessageMem* emm);
|
||||
LIB_API void debug_FreeErrorMessage(ErrorMessageMem* emm);
|
||||
|
||||
/**
|
||||
* build a string describing the given error.
|
||||
*
|
||||
* this is a helper function used by debug_dump_stack and is made available
|
||||
* 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.
|
||||
*
|
||||
* @param description: general description of the problem.
|
||||
* @param fn_only filename (no path) of source file that triggered the error.
|
||||
* @param line, func: exact position of the error.
|
||||
* @param skip, context: see debug_dump_stack.
|
||||
* @param context, lastFuncToSkip: see debug_DumpStack.
|
||||
* @param 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_error_message_free when no longer needed.
|
||||
* debug_FreeErrorMessage when no longer needed.
|
||||
**/
|
||||
LIB_API const wchar_t* debug_error_message_build(
|
||||
const wchar_t* description,
|
||||
const char* fn_only, int line, const char* func,
|
||||
size_t skip, void* context,
|
||||
ErrorMessageMem* emm);
|
||||
LIB_API const wchar_t* debug_BuildErrorMessage(const wchar_t* description, const char* fn_only, int line, const char* func, void* context, const char* lastFuncToSkip, ErrorMessageMem* emm);
|
||||
|
||||
#endif // #ifndef INCLUDED_DEBUG
|
||||
|
||||
@@ -538,7 +538,7 @@ static bool IsContainerValid(const T& t, size_t el_count)
|
||||
{
|
||||
// valid pointer
|
||||
const u8* front = (const u8*)&*t.begin(); // (note: map doesn't have front)
|
||||
if(debug_is_pointer_bogus(front))
|
||||
if(debug_IsPointerBogus(front))
|
||||
return false;
|
||||
|
||||
// note: don't test back() because that depends on el_size and
|
||||
|
||||
@@ -140,6 +140,7 @@ ERROR_ASSOCIATE(ERR::LOGIC, "Logic error in code", -1);
|
||||
ERROR_ASSOCIATE(ERR::TIMED_OUT, "Timed out", -1);
|
||||
ERROR_ASSOCIATE(ERR::REENTERED, "Single-call function was reentered", -1);
|
||||
ERROR_ASSOCIATE(ERR::CORRUPTED, "File/memory data is corrupted", -1);
|
||||
ERROR_ASSOCIATE(ERR::ASSERTION_FAILED, "Assertion failed", -1);
|
||||
|
||||
ERROR_ASSOCIATE(ERR::INVALID_PARAM, "Invalid function argument", EINVAL);
|
||||
ERROR_ASSOCIATE(ERR::INVALID_HANDLE, "Invalid Handle (argument)", -1);
|
||||
|
||||
@@ -384,6 +384,7 @@ const LibError LOGIC = -100010;
|
||||
const LibError TIMED_OUT = -100011;
|
||||
const LibError REENTERED = -100012;
|
||||
const LibError CORRUPTED = -100013;
|
||||
const LibError ASSERTION_FAILED = -100014;
|
||||
|
||||
// function arguments
|
||||
const LibError INVALID_PARAM = -100020;
|
||||
|
||||
@@ -167,7 +167,7 @@ static LibError UniFont_validate(const UniFont* f)
|
||||
{
|
||||
if(f->ht < 0)
|
||||
WARN_RETURN(ERR::_1);
|
||||
if(debug_is_pointer_bogus(f->glyphs_id) || debug_is_pointer_bogus(f->glyphs_size))
|
||||
if(debug_IsPointerBogus(f->glyphs_id) || debug_IsPointerBogus(f->glyphs_size))
|
||||
WARN_RETURN(ERR::_2);
|
||||
// <LineSpacing> and <Height> are read directly from font file.
|
||||
// negative values don't make sense, but that's all we can check.
|
||||
|
||||
@@ -178,7 +178,7 @@ called automatically when the Handle is dereferenced or freed.
|
||||
static LibError Type_validate(const Res1* r);
|
||||
{
|
||||
const int permissible_flags = 0x01;
|
||||
if(debug_is_pointer_bogus(r->data))
|
||||
if(debug_IsPointerBogus(r->data))
|
||||
WARN_RETURN(ERR::_1);
|
||||
if(r->flags & ~permissible_flags)
|
||||
WARN_RETURN(ERR::_2);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "self_test.h"
|
||||
#include "timer.h"
|
||||
|
||||
// checked by debug_assert_failed; disables asserts if true (see above).
|
||||
// checked by debug_OnAssertionFailure; disables asserts if true (see above).
|
||||
// set/cleared by self_test_run.
|
||||
bool self_test_active = false;
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ For further details, see below.
|
||||
// macro magic (stringize+prepend L) and we already display file+line.
|
||||
#define TEST(condition) STMT(\
|
||||
if(!(condition))\
|
||||
debug_display_error(L"Self-test failed");\
|
||||
debug_DisplayError(L"Self-test failed");\
|
||||
)
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ extern int self_test_run(void(*func)());
|
||||
|
||||
extern int self_test_register(SelfTestRecord* r);
|
||||
|
||||
// checked by debug_assert_failed; disables asserts if true (see above).
|
||||
// checked by debug_OnAssertionFailure; disables asserts if true (see above).
|
||||
// set/cleared by run_self_test.
|
||||
extern bool self_test_active;
|
||||
|
||||
|
||||
@@ -49,4 +49,6 @@
|
||||
# define ARCH_MIPS 0
|
||||
#endif
|
||||
|
||||
#define ARCH_X86_X64 (ARCH_IA32|ARCH_AMD64)
|
||||
|
||||
#endif // #ifndef INCLUDED_ARCH
|
||||
|
||||
@@ -59,20 +59,19 @@ struct symbol_lookup_context
|
||||
bool found;
|
||||
};
|
||||
|
||||
void* debug_get_nth_caller(size_t n, void *UNUSED(context))
|
||||
void* debug_GetCaller(void* UNUSED(context), const char* UNUSED(lastFuncToSkip))
|
||||
{
|
||||
// bt[0] == debug_get_nth_caller
|
||||
// bt[1] == caller of get_nth_caller
|
||||
// bt[2] == 1:st caller (n==1)
|
||||
void *bt[n+2];
|
||||
int bt_size;
|
||||
|
||||
bt_size=backtrace(bt, n+2);
|
||||
assert(bt_size >= (int)(n+2) && "Need at least n+2 frames in get_nth_caller");
|
||||
return bt[n+1]; // n==1 => bt[2], and so forth
|
||||
// bt[0] == this function
|
||||
// bt[1] == our caller
|
||||
// bt[2] == the first caller they are interested in
|
||||
// HACK: we currently don't support lastFuncToSkip (would require debug information),
|
||||
// instead just returning the caller of the function calling us
|
||||
void *bt[3];
|
||||
int bt_size = backtrace(bt, 3);
|
||||
return bt[2];
|
||||
}
|
||||
|
||||
LibError debug_dump_stack(wchar_t* buf, size_t max_chars, size_t skip, void* UNUSED(context))
|
||||
LibError debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context), const char* UNUSED(lastFuncToSkip))
|
||||
{
|
||||
++skip; // Skip ourselves too
|
||||
|
||||
@@ -86,19 +85,19 @@ LibError debug_dump_stack(wchar_t* buf, size_t max_chars, size_t skip, void* UNU
|
||||
|
||||
bt_size=backtrace(bt, ARRAY_SIZE(bt));
|
||||
// did we get enough backtraced frames?
|
||||
assert((bt_size >= (int)skip) && "Need at least <skip> frames in the backtrace");
|
||||
//assert((bt_size >= (int)skip) && "Need at least <skip> frames in the backtrace");
|
||||
|
||||
// Assumed max length of a single print-out
|
||||
static const size_t MAX_OUT_CHARS=1024;
|
||||
|
||||
for (size_t i=skip;(int)i<bt_size && bufpos+MAX_OUT_CHARS < bufend;i++)
|
||||
for (size_t i=0;(int)i<bt_size && bufpos+MAX_OUT_CHARS < bufend;i++)
|
||||
{
|
||||
char file[DBG_FILE_LEN];
|
||||
char symbol[DBG_SYMBOL_LEN];
|
||||
int line;
|
||||
int len;
|
||||
|
||||
if (debug_resolve_symbol(bt[i], symbol, file, &line) == 0)
|
||||
if (debug_ResolveSymbol(bt[i], symbol, file, &line) == 0)
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(0x%08x) %hs:%d %hs\n", bt[i], file, line, symbol);
|
||||
else
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(0x%08x)\n", bt[i]);
|
||||
@@ -217,11 +216,11 @@ void udbg_bfd_init(void)
|
||||
char symbol[DBG_SYMBOL_LEN];
|
||||
char file[DBG_FILE_LEN];
|
||||
int line;
|
||||
debug_resolve_symbol(debug_get_nth_caller(3), symbol, file, &line);
|
||||
debug_ResolveSymbol(debug_get_nth_caller(3), symbol, file, &line);
|
||||
printf("%s (%s:%d)\n", symbol, file, line);
|
||||
for (int i=0;i<1000000;i++)
|
||||
{
|
||||
debug_resolve_symbol(debug_get_nth_caller(1), symbol, file, &line);
|
||||
debug_ResolveSymbol(debug_get_nth_caller(1), symbol, file, &line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -309,7 +308,7 @@ static LibError debug_resolve_symbol_dladdr(void *ptr, char* sym_name, char* fil
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line)
|
||||
LibError debug_ResolveSymbol(void* ptr_of_interest, char* sym_name, char* file, int* line)
|
||||
{
|
||||
ONCE(udbg_bfd_init());
|
||||
|
||||
@@ -374,7 +373,7 @@ LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file,
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void debug_set_thread_name(char const* UNUSED(name))
|
||||
void debug_SetThreadName(char const* UNUSED(name))
|
||||
{
|
||||
// Currently unimplemented
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/debug.h"
|
||||
|
||||
void* debug_get_nth_caller(size_t UNUSED(n), void *UNUSED(context))
|
||||
void* debug_GetCaller(void* UNUSED(context), const char* UNUSED(lastFuncToSkip))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LibError debug_dump_stack(wchar_t* UNUSED(buf), size_t UNUSED(max_chars), size_t UNUSED(skip), void* UNUSED(context))
|
||||
LibError debug_DumpStack(wchar_t* UNUSED(buf), size_t UNUSED(max_chars), size_t UNUSED(skip), void* UNUSED(context))
|
||||
{
|
||||
return ERR::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LibError debug_resolve_symbol(void* UNUSED(ptr_of_interest), char* UNUSED(sym_name), char* UNUSED(file), int* UNUSED(line))
|
||||
LibError debug_ResolveSymbol(void* UNUSED(ptr_of_interest), char* UNUSED(sym_name), char* UNUSED(file), int* UNUSED(line))
|
||||
{
|
||||
return ERR::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void debug_set_thread_name(char const* UNUSED(name))
|
||||
void debug_SetThreadName(char const* UNUSED(name))
|
||||
{
|
||||
// Currently unimplemented
|
||||
}
|
||||
|
||||
@@ -82,13 +82,13 @@ void debug_puts(const char* text)
|
||||
// TODO: Do these properly. (I don't know what I'm doing; I just
|
||||
// know that these functions are required in order to compile...)
|
||||
|
||||
int debug_write_crashlog(const char* UNUSED(file), wchar_t* UNUSED(header),
|
||||
int debug_WriteCrashlog(const char* UNUSED(file), wchar_t* UNUSED(header),
|
||||
void* UNUSED(context))
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
int debug_is_pointer_bogus(const void* UNUSED(p))
|
||||
int debug_IsPointerBogus(const void* UNUSED(p))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -54,15 +54,15 @@ class TestWdbgSym : public CxxTest::TestSuite
|
||||
// this test now always runs. therefore, just make sure a decent
|
||||
// amount of text (not just "(failed)" error messages) was produced.
|
||||
//
|
||||
// however, we can't call debug_dump_stack directly because
|
||||
// however, we can't call debug_DumpStack directly because
|
||||
// it'd be reentered if an actual error comes up.
|
||||
// therefore, use debug_display_error with DE_HIDE_DIALOG.
|
||||
// therefore, use debug_DisplayError with DE_HIDE_DIALOG.
|
||||
// unfortunately this means we can no longer get at the error text.
|
||||
// a sanity check of the text length has been added to debug_display_error
|
||||
// a sanity check of the text length has been added to debug_DisplayError
|
||||
ErrorMessageMem emm = {0};
|
||||
const wchar_t* text = debug_error_message_build(L"dummy", 0,0,0, 0,0, &emm);
|
||||
const wchar_t* text = debug_BuildErrorMessage(L"dummy", 0,0,0, 0,0, &emm);
|
||||
TS_ASSERT(wcslen(text) > 500);
|
||||
debug_error_message_free(&emm);
|
||||
debug_FreeErrorMessage(&emm);
|
||||
}
|
||||
|
||||
// also used by test_stl as an element type
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
// return 1 if the pointer appears to be totally bogus, otherwise 0.
|
||||
// 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.
|
||||
int debug_is_pointer_bogus(const void* p)
|
||||
int debug_IsPointerBogus(const void* p)
|
||||
{
|
||||
#if ARCH_IA32
|
||||
if(p < (void*)0x10000)
|
||||
return true;
|
||||
if(p >= (void*)(uintptr_t)0x80000000)
|
||||
#if ARCH_AMD64
|
||||
if(p == (const void*)0xCCCCCCCCCCCCCCCCull)
|
||||
return true;
|
||||
#elif ARCH_IA32
|
||||
if(p == (const void*)0xCCCCCCCCul)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -40,11 +43,11 @@ int debug_is_pointer_bogus(const void* p)
|
||||
}
|
||||
|
||||
|
||||
bool debug_is_code_ptr(void* p)
|
||||
bool debug_IsCodePointer(void* p)
|
||||
{
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
// totally invalid pointer
|
||||
if(debug_is_pointer_bogus(p))
|
||||
if(debug_IsPointerBogus(p))
|
||||
return false;
|
||||
// comes before load address
|
||||
static const HMODULE base = GetModuleHandle(0);
|
||||
@@ -55,11 +58,11 @@ bool debug_is_code_ptr(void* p)
|
||||
}
|
||||
|
||||
|
||||
bool debug_is_stack_ptr(void* p)
|
||||
bool debug_IsStackPointer(void* p)
|
||||
{
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
// totally invalid pointer
|
||||
if(debug_is_pointer_bogus(p))
|
||||
if(debug_IsPointerBogus(p))
|
||||
return false;
|
||||
// not aligned
|
||||
if(addr % sizeof(void*))
|
||||
@@ -95,7 +98,7 @@ void wdbg_printf(const char* fmt, ...)
|
||||
// displays instead of just the thread handle.
|
||||
//
|
||||
// see "Setting a Thread Name (Unmanaged)": http://msdn2.microsoft.com/en-us/library/xcb2z8hs(vs.71).aspx
|
||||
void debug_set_thread_name(const char* name)
|
||||
void debug_SetThreadName(const char* name)
|
||||
{
|
||||
// we pass information to the debugger via a special exception it
|
||||
// swallows. if not running under one, bail now to avoid
|
||||
|
||||
@@ -825,7 +825,7 @@ static void PrintCallStack(const uintptr_t* callers, size_t numCallers)
|
||||
for(size_t i = 0; i < numCallers; i++)
|
||||
{
|
||||
char name[DBG_SYMBOL_LEN] = {'\0'}; char file[DBG_FILE_LEN] = {'\0'}; int line = -1;
|
||||
LibError err = debug_resolve_symbol((void*)callers[i], name, file, &line);
|
||||
LibError err = debug_ResolveSymbol((void*)callers[i], name, file, &line);
|
||||
wdbg_printf(" ");
|
||||
if(err != INFO::OK)
|
||||
wdbg_printf("(error %d resolving PC=%p) ", err, callers[i]);
|
||||
@@ -920,7 +920,7 @@ static LibError wdbg_heap_Init()
|
||||
|
||||
// load symbol information now (fails if it happens during shutdown)
|
||||
char name[DBG_SYMBOL_LEN]; char file[DBG_FILE_LEN]; int line;
|
||||
(void)debug_resolve_symbol(wdbg_heap_Init, name, file, &line);
|
||||
(void)debug_ResolveSymbol(wdbg_heap_Init, name, file, &line);
|
||||
|
||||
int ret = _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, ReportHook);
|
||||
if(ret == -1)
|
||||
|
||||
@@ -24,7 +24,7 @@ LIB_API void wdbg_heap_Enable(bool);
|
||||
|
||||
/**
|
||||
* check heap integrity.
|
||||
* errors are reported by the CRT or via debug_display_error.
|
||||
* errors are reported by the CRT or via debug_DisplayError.
|
||||
* no effect if called between wdbg_heap_Enable(false) and the next
|
||||
* wdbg_heap_Enable(true).
|
||||
**/
|
||||
|
||||
@@ -180,7 +180,7 @@ static LibError debug_resolve_symbol_lk(void* ptr_of_interest, char* sym_name, c
|
||||
// sym_name and file must hold at least the number of chars above;
|
||||
// file is the base name only, not path (see rationale in wdbg_sym).
|
||||
// the PDB implementation is rather slow (~500µs).
|
||||
LibError debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int* line)
|
||||
LibError debug_ResolveSymbol(void* ptr_of_interest, char* sym_name, char* file, int* line)
|
||||
{
|
||||
WinScopedLock lock(WDBG_SYM_CS);
|
||||
return debug_resolve_symbol_lk(ptr_of_interest, sym_name, file, line);
|
||||
@@ -246,11 +246,11 @@ static LibError ia32_walk_stack(_tagSTACKFRAME64* sf)
|
||||
void* prev_fp = (void*)(uintptr_t)sf->AddrFrame .Offset;
|
||||
void* prev_ip = (void*)(uintptr_t)sf->AddrPC .Offset;
|
||||
void* prev_ret = (void*)(uintptr_t)sf->AddrReturn.Offset;
|
||||
if(!debug_is_stack_ptr(prev_fp))
|
||||
if(!debug_IsStackPointer(prev_fp))
|
||||
WARN_RETURN(ERR::_11);
|
||||
if(prev_ip && !debug_is_code_ptr(prev_ip))
|
||||
if(prev_ip && !debug_IsCodePointer(prev_ip))
|
||||
WARN_RETURN(ERR::_12);
|
||||
if(prev_ret && !debug_is_code_ptr(prev_ret))
|
||||
if(prev_ret && !debug_IsCodePointer(prev_ret))
|
||||
WARN_RETURN(ERR::_13);
|
||||
|
||||
// read stack frame
|
||||
@@ -258,9 +258,9 @@ static LibError ia32_walk_stack(_tagSTACKFRAME64* sf)
|
||||
void* ret_addr = ((void**)prev_fp)[1];
|
||||
if(!fp)
|
||||
return INFO::ALL_COMPLETE;
|
||||
if(!debug_is_stack_ptr(fp))
|
||||
if(!debug_IsStackPointer(fp))
|
||||
WARN_RETURN(ERR::_14);
|
||||
if(!debug_is_code_ptr(ret_addr))
|
||||
if(!debug_IsCodePointer(ret_addr))
|
||||
return ERR::FAIL; // NOWARN (invalid address)
|
||||
|
||||
void* target;
|
||||
@@ -268,7 +268,7 @@ static LibError ia32_walk_stack(_tagSTACKFRAME64* sf)
|
||||
RETURN_ERR(err);
|
||||
if(target) // were able to determine it from the call instruction
|
||||
{
|
||||
if(!debug_is_code_ptr(target))
|
||||
if(!debug_IsCodePointer(target))
|
||||
return ERR::FAIL; // NOWARN (invalid address)
|
||||
}
|
||||
|
||||
@@ -282,17 +282,10 @@ static LibError ia32_walk_stack(_tagSTACKFRAME64* sf)
|
||||
#endif
|
||||
|
||||
|
||||
static void skip_this_frame(size_t& skip, void* context)
|
||||
{
|
||||
if(!context)
|
||||
skip++;
|
||||
}
|
||||
|
||||
|
||||
typedef VOID (WINAPI *PRtlCaptureContext)(PCONTEXT);
|
||||
static PRtlCaptureContext s_RtlCaptureContext;
|
||||
|
||||
LibError wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, size_t skip, const CONTEXT* pcontext)
|
||||
LibError wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, const CONTEXT* pcontext, const char* lastFuncToSkip)
|
||||
{
|
||||
// to function properly, StackWalk64 requires a CONTEXT on
|
||||
// non-x86 systems (documented) or when in release mode (observed).
|
||||
@@ -306,8 +299,6 @@ LibError wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, size_t skip
|
||||
// .. need to determine context ourselves.
|
||||
else
|
||||
{
|
||||
skip_this_frame(skip, (void*)pcontext);
|
||||
|
||||
// there are 4 ways to do so, in order of preference:
|
||||
// - asm (easy to use but currently only implemented on IA32)
|
||||
// - RtlCaptureContext (only available on WinXP or above)
|
||||
@@ -389,14 +380,21 @@ LibError wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, size_t skip
|
||||
|
||||
// no more frames found - abort. note: also test FP because
|
||||
// StackWalk64 sometimes erroneously reports success.
|
||||
void* fp = (void*)(uintptr_t)sf.AddrFrame.Offset;
|
||||
void* const fp = (void*)(uintptr_t)sf.AddrFrame.Offset;
|
||||
if(err != INFO::OK || !fp)
|
||||
return ret;
|
||||
|
||||
if(skip)
|
||||
if(lastFuncToSkip)
|
||||
{
|
||||
skip--;
|
||||
continue;
|
||||
void* const pc = (void*)(uintptr_t)sf.AddrPC.Offset;
|
||||
char func[DBG_SYMBOL_LEN];
|
||||
err = debug_ResolveSymbol(pc, func, 0, 0);
|
||||
if(err == INFO::OK)
|
||||
{
|
||||
if(strstr(func, lastFuncToSkip))
|
||||
lastFuncToSkip = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret = cb(&sf, cbData);
|
||||
@@ -428,11 +426,10 @@ static LibError nth_caller_cb(const _tagSTACKFRAME64* sf, uintptr_t cbData)
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void* debug_get_nth_caller(size_t skip, void* pcontext)
|
||||
void* debug_GetCaller(void* pcontext, const char* lastFuncToSkip)
|
||||
{
|
||||
void* func;
|
||||
skip_this_frame(skip, pcontext);
|
||||
LibError ret = wdbg_sym_WalkStack(nth_caller_cb, (uintptr_t)&func, skip, (const CONTEXT*)pcontext);
|
||||
LibError ret = wdbg_sym_WalkStack(nth_caller_cb, (uintptr_t)&func, (const CONTEXT*)pcontext, lastFuncToSkip);
|
||||
return (ret == INFO::OK)? func : 0;
|
||||
}
|
||||
|
||||
@@ -626,48 +623,10 @@ static LibError dump_sym(DWORD id, const u8* p, DumpState state);
|
||||
// all we can do is display FP-relative variables.
|
||||
enum CV_HREG_e
|
||||
{
|
||||
CV_REG_EAX = 17,
|
||||
CV_REG_ECX = 18,
|
||||
CV_REG_EDX = 19,
|
||||
CV_REG_EBX = 20,
|
||||
CV_REG_ESP = 21,
|
||||
CV_REG_EBP = 22,
|
||||
CV_REG_ESI = 23,
|
||||
CV_REG_EDI = 24
|
||||
CV_AMD64_RSP = 335
|
||||
};
|
||||
|
||||
#if 0
|
||||
// (no longer needed - reg was always 0 (unknown), so there's no point in
|
||||
// cluttering the stack trace with register strings)
|
||||
static const wchar_t* string_for_register(CV_HREG_e reg)
|
||||
{
|
||||
switch(reg)
|
||||
{
|
||||
case CV_REG_EAX:
|
||||
return L"eax";
|
||||
case CV_REG_ECX:
|
||||
return L"ecx";
|
||||
case CV_REG_EDX:
|
||||
return L"edx";
|
||||
case CV_REG_EBX:
|
||||
return L"ebx";
|
||||
case CV_REG_ESP:
|
||||
return L"esp";
|
||||
case CV_REG_EBP:
|
||||
return L"ebp";
|
||||
case CV_REG_ESI:
|
||||
return L"esi";
|
||||
case CV_REG_EDI:
|
||||
return L"edi";
|
||||
default:
|
||||
{
|
||||
static wchar_t buf[19];
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"0x%x", reg);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dump_error(LibError err)
|
||||
{
|
||||
@@ -876,7 +835,9 @@ static bool IsRelativeToFramePointer(DWORD flags, DWORD reg)
|
||||
{
|
||||
if(flags & SYMFLAG_FRAMEREL) // note: this is apparently obsolete
|
||||
return true;
|
||||
if(flags & SYMFLAG_REGREL && reg == CV_REG_EBP)
|
||||
if((flags & SYMFLAG_REGREL) == 0)
|
||||
return false;
|
||||
if(reg == CV_REG_EBP || reg == CV_AMD64_RSP)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -918,9 +879,11 @@ static LibError DetermineSymbolAddress(DWORD id, const SYMBOL_INFOW* sym, const
|
||||
uintptr_t addr = sym->Address;
|
||||
if(IsRelativeToFramePointer(sym->Flags, sym->Register))
|
||||
{
|
||||
#if ARCH_AMD64
|
||||
addr += sf->AddrStack.Offset;
|
||||
#else
|
||||
addr += sf->AddrFrame.Offset;
|
||||
|
||||
#ifdef NDEBUG
|
||||
# if defined(NDEBUG)
|
||||
// NB: the addresses of register-relative symbols are apparently
|
||||
// incorrect [VC8, 32-bit Wow64]. the problem occurs regardless of
|
||||
// IA32_STACK_WALK_ENABLED and with both ia32_asm_GetCurrentContext
|
||||
@@ -931,6 +894,7 @@ static LibError DetermineSymbolAddress(DWORD id, const SYMBOL_INFOW* sym, const
|
||||
addr += sizeof(void*);
|
||||
else
|
||||
addr += sizeof(void*) * 2;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
else if(IsUnretrievable(sym->Flags))
|
||||
@@ -1289,7 +1253,7 @@ static bool ptr_already_visited(const u8* p)
|
||||
else
|
||||
{
|
||||
// warn user - but only once (we can't use the regular
|
||||
// debug_display_error and wdbg_assert doesn't have a
|
||||
// debug_DisplayError and wdbg_assert doesn't have a
|
||||
// suppress mechanism)
|
||||
static bool haveComplained;
|
||||
if(!haveComplained)
|
||||
@@ -1317,7 +1281,7 @@ static LibError dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
|
||||
|
||||
// bail if it's obvious the pointer is bogus
|
||||
// (=> can't display what it's pointing to)
|
||||
if(debug_is_pointer_bogus(p))
|
||||
if(debug_IsPointerBogus(p))
|
||||
return INFO::OK;
|
||||
|
||||
// avoid duplicates and circular references
|
||||
@@ -1578,7 +1542,11 @@ static LibError udt_dump_normal(const wchar_t* type_name, const u8* p, size_t si
|
||||
DWORD ofs = 0;
|
||||
if(!SymGetTypeInfo(hProcess, mod_base, child_id, TI_GET_OFFSET, &ofs))
|
||||
continue;
|
||||
debug_assert(ofs < size);
|
||||
if(ofs >= size)
|
||||
{
|
||||
debug_printf("INVALID_UDT %ws %d %d\n", type_name, ofs, size);
|
||||
}
|
||||
//debug_assert(ofs < size);
|
||||
|
||||
if(!fits_on_one_line)
|
||||
INDENT;
|
||||
@@ -1834,17 +1802,16 @@ static LibError dump_frame_cb(const _tagSTACKFRAME64* sf, uintptr_t UNUSED(cbDat
|
||||
}
|
||||
|
||||
|
||||
LibError debug_dump_stack(wchar_t* buf, size_t max_chars, size_t skip, void* pcontext)
|
||||
LibError debug_DumpStack(wchar_t* buf, size_t maxChars, void* pcontext, const char* lastFuncToSkip)
|
||||
{
|
||||
static uintptr_t already_in_progress;
|
||||
if(!cpu_CAS(&already_in_progress, 0, 1))
|
||||
return ERR::REENTERED; // NOWARN
|
||||
|
||||
out_init(buf, max_chars);
|
||||
out_init(buf, maxChars);
|
||||
ptr_reset_visited();
|
||||
|
||||
skip_this_frame(skip, pcontext);
|
||||
LibError ret = wdbg_sym_WalkStack(dump_frame_cb, 0, skip, (const CONTEXT*)pcontext);
|
||||
LibError ret = wdbg_sym_WalkStack(dump_frame_cb, 0, (const CONTEXT*)pcontext, lastFuncToSkip);
|
||||
|
||||
already_in_progress = 0;
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ static HANDLE hUpdateThread;
|
||||
|
||||
static unsigned __stdcall UpdateThread(void* UNUSED(data))
|
||||
{
|
||||
debug_set_thread_name("whrt_UpdateThread");
|
||||
debug_SetThreadName("whrt_UpdateThread");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
// defined by winsock2 and also Linux (with different values)
|
||||
// (values derived from winsock2 WSA* constants minus WSABASEERR)
|
||||
// update: disabled on newer Boost versions because filesystem drags in boost/cerrno.hpp
|
||||
#if BOOST_VERSION <= 103401
|
||||
#if !defined(BOOST_VERSION) || BOOST_VERSION <= 103401
|
||||
#define EWOULDBLOCK 35
|
||||
#define EINPROGRESS 36
|
||||
#define EALREADY 37
|
||||
|
||||
@@ -90,7 +90,7 @@ static sem_t exit_flag;
|
||||
|
||||
static void* prof_thread_func(void* UNUSED(data))
|
||||
{
|
||||
debug_set_thread_name("eip_sampler");
|
||||
debug_SetThreadName("eip_sampler");
|
||||
|
||||
const long _1e6 = 1000000;
|
||||
const long _1e9 = 1000000000;
|
||||
|
||||
@@ -195,17 +195,17 @@ static const wchar_t* GetExceptionDescription(const EXCEPTION_POINTERS* ep,
|
||||
|
||||
|
||||
// return location at which the exception <er> occurred.
|
||||
// params: see debug_resolve_symbol.
|
||||
// params: see debug_ResolveSymbol.
|
||||
static void GetExceptionLocus(const EXCEPTION_POINTERS* ep,
|
||||
char* file, int* line, char* func)
|
||||
{
|
||||
// HACK: <ep> provides no useful information - ExceptionAddress always
|
||||
// points to kernel32!RaiseException. we use debug_get_nth_caller to
|
||||
// points to kernel32!RaiseException. we use debug_GetCaller to
|
||||
// determine the real location.
|
||||
|
||||
const size_t skip = 1; // skip RaiseException
|
||||
void* func_addr = debug_get_nth_caller(skip, ep->ContextRecord);
|
||||
(void)debug_resolve_symbol(func_addr, func, file, line);
|
||||
const char* const lastFuncToSkip = "RaiseException";
|
||||
void* func_addr = debug_GetCaller(ep->ContextRecord, lastFuncToSkip);
|
||||
(void)debug_ResolveSymbol(func_addr, func, file, line);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,8 @@ long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep)
|
||||
size_t flags = 0;
|
||||
if(ep->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
|
||||
flags = DE_NO_CONTINUE;
|
||||
ErrorReaction er = debug_display_error(message, flags, 1,ep->ContextRecord, file,line,func, 0);
|
||||
const char* const lastFuncToSkip = STRINGIZE(DECORATED_NAME(wseh_ExceptionFilter));
|
||||
ErrorReaction er = debug_DisplayError(message, flags, ep->ContextRecord, lastFuncToSkip, file,line,func, 0);
|
||||
debug_assert(er == ER_CONTINUE); // nothing else possible
|
||||
|
||||
// invoke the Win32 default handler - it calls ExitProcess for
|
||||
|
||||
@@ -259,7 +259,7 @@ ErrorReaction sys_display_error(const wchar_t* text, size_t flags)
|
||||
// failed; warn user and make sure we return an ErrorReaction.
|
||||
if(ret == 0 || ret == -1)
|
||||
{
|
||||
debug_display_msgw(L"Error", L"Unable to display detailed error dialog.");
|
||||
debug_DisplayMessage(L"Error", L"Unable to display detailed error dialog.");
|
||||
return ER_CONTINUE;
|
||||
}
|
||||
return (ErrorReaction)ret;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* @param msg message contents
|
||||
*
|
||||
* implemented as a MessageBox on Win32 and printf on Unix.
|
||||
* called from debug_display_msgw.
|
||||
* called from debug_DisplayMessage.
|
||||
**/
|
||||
extern void sys_display_msg(const wchar_t* caption, const wchar_t* msg);
|
||||
|
||||
@@ -38,7 +38,7 @@ extern void sys_display_msg(const wchar_t* caption, const wchar_t* msg);
|
||||
* @param flags: see DebugDisplayErrorFlags.
|
||||
* @return ErrorReaction (except ER_EXIT, which is acted on immediately)
|
||||
*
|
||||
* called from debug_display_error unless overridden by means of
|
||||
* called from debug_DisplayError unless overridden by means of
|
||||
* ah_display_error.
|
||||
**/
|
||||
extern ErrorReaction sys_display_error(const wchar_t* text, size_t flags);
|
||||
|
||||
@@ -109,7 +109,7 @@ class TestMultithread : public CxxTest::TestSuite
|
||||
|
||||
static void* thread_func(void* arg)
|
||||
{
|
||||
debug_set_thread_name("LF_test");
|
||||
debug_SetThreadName("LF_test");
|
||||
|
||||
ThreadFuncParam* param = (ThreadFuncParam*)arg;
|
||||
TestMultithread* this_ = param->this_;
|
||||
|
||||
@@ -8,9 +8,9 @@ public:
|
||||
// complain if huge interval or min > max
|
||||
void TestParam()
|
||||
{
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TS_ASSERT_EQUALS(rand(1, 0), size_t(0));
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TS_ASSERT_EQUALS(rand(2, ~0u), size_t(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -107,64 +107,64 @@ public:
|
||||
void test_param_validation()
|
||||
{
|
||||
#if EMULATE_SECURE_CRT
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CPY(0 ,0,0 , EINVAL,""); // all invalid
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CPY(0 ,0,s1, EINVAL,""); // dst = 0, max = 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CPY(0 ,1,s1, EINVAL,""); // dst = 0, max > 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CPY(d1,1,0 , EINVAL,""); // src = 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CPY(d1,0,s1, ERANGE,""); // max_dst_chars = 0
|
||||
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CPY2(d1,1, s1, ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CPY2(d1,1, s5, ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CPY2(d5,5, s5, ERANGE,"");
|
||||
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCPY(d1,1 ,s1,1, ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCPY(d1,1 ,s5,1, ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCPY(d5,5 ,s5,5, ERANGE,"");
|
||||
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CAT(0 ,0,0 , EINVAL,""); // all invalid
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CAT(0 ,0,s1, EINVAL,""); // dst = 0, max = 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CAT(0 ,1,s1, EINVAL,""); // dst = 0, max > 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CAT(d1,1,0 , EINVAL,""); // src = 0
|
||||
debug_skip_next_err(ERR::INVALID_PARAM);
|
||||
debug_SkipNextError(ERR::INVALID_PARAM);
|
||||
TEST_CAT(d1,0,s1, ERANGE,""); // max_dst_chars = 0
|
||||
debug_skip_next_err(ERR::STRING_NOT_TERMINATED);
|
||||
debug_SkipNextError(ERR::STRING_NOT_TERMINATED);
|
||||
TEST_CAT(no_null,5,s1, ERANGE,""); // dst not terminated
|
||||
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CAT2(d1,1, s1, "",ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CAT2(d1,1, s5, "",ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CAT2(d10,10, s10, "",ERANGE,""); // empty, total overflow
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CAT2(d10,10, s5, "12345",ERANGE,""); // not empty, overflow
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_CAT2(d10,10, s10, "12345",ERANGE,""); // not empty, total overflow
|
||||
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCAT(d1,1, s1,1, "",ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCAT(d1,1, s5,5, "",ERANGE,"");
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCAT(d10,10, s10,10, "",ERANGE,""); // empty, total overflow
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCAT(d10,10, s5,5, "12345",ERANGE,""); // not empty, overflow
|
||||
debug_skip_next_err(ERR::BUF_SIZE);
|
||||
debug_SkipNextError(ERR::BUF_SIZE);
|
||||
TEST_NCAT(d10,10, s10,10, "12345",ERANGE,""); // not empty, total overflow
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ ScopeTimer::~ScopeTimer()
|
||||
// note that overflow isn't an issue either way (63 bit cycle counts
|
||||
// at 10 GHz cover intervals of 29 years).
|
||||
|
||||
#if ARCH_IA32 && CONFIG2_TIMER_ALLOW_RDTSC
|
||||
#if ARCH_X86_X64 && CONFIG2_TIMER_ALLOW_RDTSC
|
||||
|
||||
void TimerUnit::SetToZero()
|
||||
{
|
||||
|
||||
@@ -221,7 +221,7 @@ void CSocketBase::Shutdown()
|
||||
|
||||
void *WaitLoopThreadMain(void *)
|
||||
{
|
||||
debug_set_thread_name("net_wait");
|
||||
debug_SetThreadName("net_wait");
|
||||
|
||||
GLOBAL_LOCK();
|
||||
CSocketBase::RunWaitLoop();
|
||||
|
||||
@@ -18,7 +18,7 @@ CStreamSocket::~CStreamSocket()
|
||||
|
||||
void *CStreamSocket_ConnectThread(void *data)
|
||||
{
|
||||
debug_set_thread_name("net_connect");
|
||||
debug_SetThreadName("net_connect");
|
||||
|
||||
CStreamSocket *pSock=(CStreamSocket *)data;
|
||||
PS_RESULT res=PS_OK;
|
||||
|
||||
@@ -839,7 +839,7 @@ void EarlyInit()
|
||||
// If you ever want to catch a particular allocation:
|
||||
//_CrtSetBreakAlloc(321);
|
||||
|
||||
debug_set_thread_name("main");
|
||||
debug_SetThreadName("main");
|
||||
// add all debug_printf "tags" that we are interested in:
|
||||
debug_filter_add("TIMER");
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ GameLoopState* g_GameLoop = &state;
|
||||
static void* LaunchWindow(void* data)
|
||||
{
|
||||
const wchar_t* windowName = reinterpret_cast<const wchar_t*>(data);
|
||||
debug_set_thread_name("atlas_window");
|
||||
debug_SetThreadName("atlas_window");
|
||||
Atlas_StartWindow(windowName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user