27 #include "precompiled.h"
67 hProcess = GetCurrentProcess();
76 DWORD opts = pSymGetOptions();
78 opts |= SYMOPT_DEFERRED_LOADS;
79 opts |= SYMOPT_LOAD_LINES;
80 opts |= SYMOPT_UNDNAME;
85 const BOOL fInvadeProcess = TRUE;
88 const PWSTR UserSearchPath = 0;
90 const BOOL ok = pSymInitializeW(hProcess, UserSearchPath, fInvadeProcess);
93 HMODULE hModule = GetModuleHandle(0);
94 IMAGE_NT_HEADERS*
const header = pImageNtHeader(hModule);
95 machine = header->FileHeader.Machine;
117 memset(&sf, 0,
sizeof(sf));
118 sf.AddrPC.Mode = AddrModeFlat;
119 sf.AddrFrame.Mode = AddrModeFlat;
120 sf.AddrStack.Mode = AddrModeFlat;
122 sf.AddrPC.Offset = context.Rip;
123 sf.AddrFrame.Offset = context.Rbp;
124 sf.AddrStack.Offset = context.Rsp;
126 sf.AddrPC.Offset = context.Eip;
127 sf.AddrFrame.Offset = context.Ebp;
128 sf.AddrStack.Offset = context.Esp;
136 IMAGEHLP_STACK_FRAME isf;
137 memset(&isf, 0,
sizeof(isf));
140 isf.InstructionOffset = sf.AddrPC.Offset;
141 isf.ReturnOffset = sf.AddrReturn.Offset;
142 isf.FrameOffset = sf.AddrFrame.Offset;
143 isf.StackOffset = sf.AddrStack.Offset;
144 isf.BackingStoreOffset = sf.AddrBStore.Offset;
145 isf.FuncTableEntry = (ULONG64)sf.FuncTableEntry;
147 for(
int i = 0; i < 4; i++)
148 isf.Params[i] = sf.Params[i];
150 isf.Virtual = sf.Virtual;
160 si.SizeOfStruct =
sizeof(si);
161 si.MaxNameLen = MAX_SYM_NAME;
165 #pragma pack(push, 1)
178 TI_FINDCHILDREN_PARAMS
p;
191 const DWORD64 addr = (DWORD64)ptr_of_interest;
192 size_t successes = 0;
202 SYMBOL_INFOW* sym = &sp.si;
203 if(pSymFromAddrW(hProcess, addr, 0, sym))
216 IMAGEHLP_LINEW64 line_info = {
sizeof(IMAGEHLP_LINEW64) };
218 if(pSymGetLineFromAddrW64(hProcess, addr, &displacement, &line_info))
233 *line = line_info.LineNumber;
239 if(addr == 0 && GetLastError() == ERROR_MOD_NOT_FOUND)
241 if(GetLastError() == ERROR_INVALID_ADDRESS)
272 if(!pRtlCaptureContext)
275 CONTEXT* context = (CONTEXT*)pcontext;
277 memset(context, 0,
sizeof(CONTEXT));
278 context->ContextFlags = CONTEXT_FULL;
279 pRtlCaptureContext(context);
289 const HANDLE hThread = GetCurrentThread();
290 if(!pStackWalk64(machine, hProcess, hThread, &sf, &context, 0, pSymFunctionTableAccess64, pSymGetModuleBase64, 0))
294 if(sf.AddrFrame.Offset == 0)
302 sf.AddrFrame.Offset = context.Rbp;
327 void*
const pc = (
void*)(uintptr_t)sf.AddrPC.Offset;
330 if(wcsstr(func, lastFuncToSkip))
336 ret = cb(&sf, cbData);
346 static Status Func(
const STACKFRAME64* sf, uintptr_t cbData)
348 const uintptr_t funcAddress = sf->AddrPC.Offset;
351 memcpy((
void*)cbData, &funcAddress,
sizeof(funcAddress));
410 static void out_init(
wchar_t* buf,
size_t max_chars)
413 out_chars_left = max_chars;
414 out_have_warned_of_overflow =
false;
415 out_have_warned_of_limit =
false;
419 static void out(
const wchar_t* fmt, ...)
425 int len = vswprintf(out_pos, out_chars_left, fmt, args);
433 if((
size_t)len > out_chars_left)
436 len = (int)out_chars_left;
438 out_chars_left -= len;
450 if(!out_have_warned_of_overflow)
452 out_have_warned_of_overflow =
true;
458 const wchar_t text[] = L
"(no more room in buffer)";
469 if(out_have_warned_of_overflow)
472 out_chars_left += (
ssize_t)num_chars;
473 out_pos -= num_chars;
482 out_have_warned_of_limit =
false;
490 if(out_have_warned_of_limit)
492 if(out_pos - out_latched_pos > 3000)
494 out_have_warned_of_limit =
true;
504 #define INDENT STMT(for(size_t i__ = 0; i__ <= state.level; i__++) out(L" ");)
505 #define UNINDENT STMT(out_erase((state.level+1)*4);)
520 const int c = *p & 0xff;
568 out(L
"(too much output; skipping to next top-level symbol)");
571 out(L
"(unavailable - located in another module)");
574 out(L
"(unavailable)");
577 out(L
"(unavailable - type info request failed (GLE=%d))", GetLastError());
580 out(L
"(unavailable - internal error)\r\n");
586 out(L
"(unavailable - unspecified error 0x%X (%d))", err, err);
596 if(el_size !=
sizeof(
char) && el_size !=
sizeof(
wchar_t))
603 if(el_size ==
sizeof(
wchar_t))
605 wcsncpy(buf, (
const wchar_t*)p,
ARRAY_SIZE(buf));
621 out(L
"\"%ls\"", buf);
629 if(el_size ==
sizeof(
char))
631 *fits_on_one_line = el_count <= 16;
632 *num_elements_to_show = std::min((
size_t)16u, el_count);
634 else if(el_size <=
sizeof(
int))
636 *fits_on_one_line = el_count <= 8;
637 *num_elements_to_show = std::min((
size_t)12u, el_count);
641 *fits_on_one_line =
false;
642 *num_elements_to_show = std::min((
size_t)8u, el_count);
648 *fits_on_one_line =
true;
661 el_p = el_iterator(
internal, el_size);
669 bool fits_on_one_line;
670 size_t num_elements_to_show;
673 out(L
"[%d] ", el_count);
675 out(fits_on_one_line? L
"{ " : L
"\r\n");
677 for(
size_t i = 0; i < num_elements_to_show; i++)
679 if(!fits_on_one_line)
683 el_p = el_iterator(
internal, el_size);
689 if(!fits_on_one_line)
697 if(i != num_elements_to_show-1)
698 out(fits_on_one_line? L
", " : L
"\r\n");
705 if(el_count != num_elements_to_show)
717 const u8*& pos = *(
const u8**)
internal;
718 const u8* cur_pos = pos;
726 const u8* iterator_internal_pos = p;
728 el_count, el_type_id, el_size, state);
766 if(flags & SYMFLAG_FRAMEREL)
768 if((flags & SYMFLAG_REGREL) == 0)
780 if(flags & SYMFLAG_REGISTER)
787 if(flags & SYMFLAG_REGREL)
796 if(!pSymGetTypeInfo(hProcess, state.
moduleBase,
id, TI_GET_DATAKIND, &dataKind))
807 uintptr_t addr = (uintptr_t)sym->Address;
809 addr += (uintptr_t)state.
stackFrame->AddrFrame.Offset;
813 *pp = (
const u8*)(uintptr_t)addr;
815 debug_printf(L
"SYM| %ls at %p flags=%X dk=%d sym->addr=%I64X fp=%I64x\n", sym->Name, *pp, sym->Flags, dataKind, sym->Address, state.
stackFrame->AddrFrame.Offset);
832 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_LENGTH, &size64))
834 const size_t size = (size_t)size64;
837 DWORD el_type_id = 0;
838 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_TYPEID, &el_type_id))
843 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, el_type_id, TI_GET_LENGTH, &el_size_))
845 const size_t el_size = (size_t)el_size_;
847 const size_t num_elements = size/el_size;
848 ENSURE(num_elements != 0);
850 return dump_array(p, num_elements, el_type_id, el_size, state);
873 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_BASETYPE, &base_type))
876 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_LENGTH, &size64))
878 const size_t size = (size_t)size64;
883 const wchar_t* fmt = L
"";
889 for(
size_t i = 0; i < size; i++)
895 out(L
"(uninitialized)");
904 if(size ==
sizeof(
float))
910 memcpy(&value, p,
sizeof(value));
911 out(L
"%f (0x%08I64X)", value, data);
913 else if(size ==
sizeof(
double))
914 out(L
"%g (0x%016I64X)", data, data);
921 ENSURE(size ==
sizeof(
bool));
922 if(data == 0 || data == 1)
923 out(L
"%ls", data? L
"true " : L
"false");
925 out(L
"(bool)0x%02I64X", data);
942 return dump_array(p, 8, type_id, size, state);
944 fmt = L
"%I64d (0x%02I64X)";
947 fmt = L
"%I64d (0x%04I64X)";
949 fmt = L
"%I64d (0x%08I64X)";
951 fmt = L
"%I64d (0x%016I64X)";
954 out(fmt, data, data);
960 ENSURE(size ==
sizeof(
char) || size ==
sizeof(
wchar_t));
965 return dump_array(p, 8, type_id, size, state);
1008 DWORD base_class_type_id;
1009 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_TYPEID, &base_class_type_id))
1016 if(pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_VIRTUALBASEPOINTEROFFSET, &vptr_ofs))
1019 return dump_sym(base_class_type_id, p, state);
1028 SYMBOL_INFOW* sym = &sp.si;
1029 if(!pSymFromIndexW(hProcess, state.
moduleBase,
id, sym))
1032 out(L
"%ls = ", sym->Name);
1038 return dump_sym(sym->TypeIndex, p, state);
1040 __except(EXCEPTION_EXECUTE_HANDLER)
1052 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_LENGTH, &size64))
1054 const size_t size = (size_t)size64;
1060 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_CHILDRENCOUNT, &numChildren))
1063 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_FINDCHILDREN, &fcp))
1065 numChildren = fcp.
p.Count;
1066 const DWORD* children = fcp.
p.ChildId;
1069 for(
size_t i = 0; i < numChildren; i++)
1071 DWORD child_data_id = children[i];
1079 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, child_data_id, TI_GET_VALUE, &v))
1081 if(VariantChangeType(&v, &v, 0, VT_I8) != S_OK)
1085 if(enum_value == v.llVal)
1087 const wchar_t* name;
1088 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, child_data_id, TI_GET_SYMNAME, &name))
1091 LocalFree((HLOCAL)name);
1100 out(L
"%I64d", enum_value);
1127 out(L
"(%ls)", name);
1159 if(numVisited < maxVisited)
1170 static bool haveComplained;
1173 debug_printf(L
"WARNING: ptr_already_visited: capacity exceeded, increase maxVisited\n");
1175 haveComplained =
true;
1186 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_LENGTH, &size64))
1188 const size_t size = (size_t)size64;
1202 out(L
" (see above)");
1212 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_TYPEID, &type_id))
1219 return dump_sym(type_id, p, state);
1228 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_TYPEID, &type_id))
1230 return dump_sym(type_id, p, state);
1242 const DWORD lastError = GetLastError();
1247 for(ULONG i = 0; i < numChildren; i++)
1249 const DWORD child_id = children[i];
1252 SYMBOL_INFOW* sym = &sp.si;
1253 if(!pSymFromIndexW(hProcess, state.
moduleBase, child_id, sym))
1256 ENSURE(GetLastError() == ERROR_NOT_FOUND);
1259 if(!wcscmp(sym->Name, child_name))
1261 *el_type_id = sym->TypeIndex;
1262 *el_size = (size_t)sym->Size;
1267 SetLastError(lastError);
1279 if(wcsncmp(type_name, L
"std::", 5) != 0)
1285 if(!wcsncmp(type_name, L
"std::pair", 9) ||
1286 !wcsncmp(type_name, L
"std::tr1::", 10))
1293 err =
udt_get_child_type(L
"value_type", numChildren, children, state, &el_type_id, &el_size);
1295 goto not_valid_container;
1302 goto not_valid_container;
1303 return dump_sequence(el_iterator, it_mem, el_count, el_type_id, el_size, state);
1304 not_valid_container:
1308 const wchar_t* text;
1319 text = L
"unsupported ";
1322 text = L
"uninitialized/invalid ";
1326 wchar_t description[200];
1350 if(type_name[0] !=
'H')
1352 #define SUPPRESS_HANDLE(name) if(!wcscmp(type_name, L#name L"__")) return true;
1416 if(!wcscmp(type_name, L
"CStr") || !wcscmp(type_name, L
"CStr8") || !wcscmp(type_name, L
"CStrW"))
1424 if(child_count == 0)
1428 if(!wcsncmp(type_name, L
"std::pair", 9))
1431 const size_t avg_size = total_size / child_count;
1436 if(child_count <= 3 && avg_size <=
sizeof(
int))
1448 if(!wcsncmp(type_name, L
"boost::unordered", 16))
1454 if(state.
level >= maxLevel)
1458 out(fits_on_one_line? L
"{ " : L
"\r\n");
1460 bool displayed_anything =
false;
1461 for(ULONG i = 0; i < numChildren; i++)
1463 const DWORD child_id = children[i];
1468 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, child_id, TI_GET_OFFSET, &ofs))
1472 debug_printf(L
"INVALID_UDT %ls %d %d\n", type_name, ofs, size);
1476 if(!fits_on_one_line)
1479 const u8* el_p = p+ofs;
1486 if(!fits_on_one_line)
1491 displayed_anything =
true;
1493 out(fits_on_one_line? L
", " : L
"\r\n");
1501 if(!displayed_anything)
1504 out(L
"(%ls)", type_name);
1511 if(fits_on_one_line)
1524 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_LENGTH, &size64))
1526 const size_t size = (size_t)size64;
1530 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_CHILDRENCOUNT, &numChildren))
1533 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_FINDCHILDREN, &fcp))
1535 numChildren = fcp.
p.Count;
1536 const DWORD* children = fcp.
p.ChildId;
1538 const wchar_t* type_name;
1539 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_SYMNAME, &type_name))
1546 ret =
udt_dump_std (type_name, p, size, state, numChildren, children);
1554 ret =
udt_dump_normal (type_name, p, size, state, numChildren, children);
1559 LocalFree((HLOCAL)type_name);
1581 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_SYMTAG, &type_tag))
1585 out(L
"(unknown symbol type)");
1598 case SymTagArrayType:
1600 case SymTagBaseType:
1602 case SymTagBaseClass:
1608 case SymTagFunction:
1610 case SymTagFunctionType:
1612 case SymTagPointerType:
1633 if(!pSymGetTypeInfo(hProcess, state.
moduleBase, type_id, TI_GET_SYMTAG, &typeTag))
1636 return dumpFunc(type_id, p, state);
1646 if(!wcscmp(name, L
"suppress__"))
1648 if(!wcscmp(name, L
"__profile"))
1661 const u8* p = (
const u8*)(uintptr_t)sym->Address;
1662 DumpState state((uintptr_t)sym->ModBase, (LPSTACKFRAME64)userContext);
1678 void* func = (
void*)(uintptr_t)sf->AddrPC.Offset;
1691 if(!wcsncmp(func_name, L
"_BaseProcessStart", 17) ||
1692 !wcscmp(func_name, L
"BaseThreadInitThunk"))
1696 if(!wcscmp(func_name, L
"__tmainCRTStartup"))
1698 if(!wcscmp(func_name, L
"mainCRTStartup"))
1701 out(L
"%ls (%ls:%d)\r\n", func_name, file, line);
1704 out(L
"%p\r\n", func);
1714 const PIMAGEHLP_CONTEXT ic = 0;
1717 (void)pSymSetContext(hProcess, &isf, ic);
1719 const ULONG64 base = 0;
const wchar_t*
const mask = 0;
1720 pSymEnumSymbolsW(hProcess, base, mask,
dump_sym_cb, (PVOID)sf);
1722 if(GetLastError() == ERROR_NOT_SUPPORTED)
1732 static intptr_t busy;
1762 HANDLE hFile = CreateFileW(
OsString(path).c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
1763 if(hFile == INVALID_HANDLE_VALUE)
1769 MINIDUMP_EXCEPTION_INFORMATION mei;
1770 mei.ThreadId = GetCurrentThreadId();
1771 mei.ExceptionPointers = exception_pointers;
1772 mei.ClientPointers = FALSE;
1779 HANDLE hProcess = GetCurrentProcess();
1780 DWORD pid = GetCurrentProcessId();
1781 if(!pMiniDumpWriteDump || !pMiniDumpWriteDump(hProcess, pid, hFile, MiniDumpNormal, &mei, 0, 0))
#define RETURN_STATUS_FROM_CALLBACK(expression)
const Status STL_CNT_UNSUPPORTED
static Status dump_sequence(DebugStlIterator el_iterator, void *internal, size_t el_count, DWORD el_type_id, size_t el_size, DumpState &state)
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
static WUTIL_FUNC(pRtlCaptureContext, VOID,(PCONTEXT))
static Status CanHandleDataKind(DWORD dataKind)
Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, CONTEXT &context, const wchar_t *lastFuncToSkip)
Iterate over a call stack, invoking a callback for each frame encountered.
static bool out_have_warned_of_overflow
static Status udt_dump_suppressed(const wchar_t *type_name, const u8 *p, size_t size, DumpState state, ULONG numChildren, const DWORD *children)
#define COMPILER_FENCE
prevent the compiler from reordering loads or stores across this point.
const Status SYM_UNSUPPORTED
static const size_t DEBUG_SYMBOL_CHARS
Maximum number of characters (including null terminator) written to user's buffers by debug_ResolveSy...
static Status dump_frame_cb(const STACKFRAME64 *sf, uintptr_t userContext)
static bool udt_should_suppress(const wchar_t *type_name)
some WinAPI functions SetLastError(0) on success, which is bad because it can hide previous errors...
const Status SYM_SUPPRESS_OUTPUT
static void out_erase(size_t num_chars)
static BOOL CALLBACK dump_sym_cb(SYMBOL_INFOW *sym, ULONG size, PVOID userContext)
#define SUPPRESS_HANDLE(name)
void wdbg_sym_WriteMinidump(EXCEPTION_POINTERS *exception_pointers)
static DumpFunc DumpFuncFromTypeTag(DWORD typeTag)
static Status dump_sym_unknown(DWORD type_id, const u8 *p, DumpState &state)
static void out(const wchar_t *fmt,...)
const Status STL_CNT_INVALID
static Status dump_sym_array(DWORD type_id, const u8 *p, DumpState &state)
static Status udt_get_child_type(const wchar_t *child_name, ULONG numChildren, const DWORD *children, const DumpState &state, DWORD *el_type_id, size_t *el_size)
static const size_t maxLevel
static bool out_have_warned_of_limit
static Status udt_dump_std(const wchar_t *type_name, const u8 *p, size_t size, DumpState &state, ULONG numChildren, const DWORD *children)
static const size_t maxIndirection
static Status ResolveSymbol_lk(void *ptr_of_interest, wchar_t *sym_name, wchar_t *file, int *line)
static void out_latch_pos()
static Status udt_dump_normal(const wchar_t *type_name, const u8 *p, size_t size, DumpState state, ULONG numChildren, const DWORD *children)
void dbghelp_ImportFunctions()
DumpState(uintptr_t moduleBase, LPSTACKFRAME64 stackFrame)
static wchar_t * out_latched_pos
const Status SYM_CHILD_NOT_FOUND
static ModuleInitState initState
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
static Status DetermineSymbolAddress(DWORD id, const SYMBOL_INFOW *sym, const DumpState &state, const u8 **pp)
const Status CANNOT_HANDLE
wchar_t * debug_stl_simplify_name(wchar_t *name)
reduce complicated STL symbol names to human-readable form.
static Status dump_sym_base_type(DWORD type_id, const u8 *p, DumpState &state)
i64 movsx_le64(const u8 *p, size_t size_bytes)
sign-extend <size> (truncated to 8) bytes of little-endian data to i64, starting at address <p> (need...
static Status wdbg_sym_Init()
static void seq_determine_formatting(size_t el_size, size_t el_count, bool *fits_on_one_line, size_t *num_elements_to_show)
static bool ShouldSkipSymbol(const wchar_t *name)
static Status dump_sym_function_type(DWORD type_id, const u8 *p, DumpState &state)
int wcscpy_s(wchar_t *dst, size_t max_dst_chars, const wchar_t *src)
const Status SYM_UNRETRIEVABLE_STATIC
Status(* StackFrameCallback)(const _tagSTACKFRAME64 *frame, uintptr_t cbData)
called for each stack frame found by wdbg_sym_WalkStack.
const Status NOT_SUPPORTED
static bool IsRelativeToFramePointer(DWORD flags, DWORD reg)
LIB_API Status debug_CaptureContext(void *context)
const Status SYM_UNRETRIEVABLE
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Status debug_stl_get_container_info(const wchar_t *type_name, const u8 *p, size_t size, size_t el_size, size_t *el_count, DebugStlIterator *el_iterator, void *it_mem)
prepare to enumerate the elements of arbitrarily typed STL containers.
intptr_t ModuleInitState
initialization state of a module (class, source file, etc.) must be initialized to zero (e...
static bool udt_fits_on_one_line(const wchar_t *type_name, size_t child_count, size_t total_size)
static Status dump_sym_base_class(DWORD type_id, const u8 *p, DumpState &state)
LIB_API int debug_IsPointerBogus(const void *p)
check if a pointer appears to be totally invalid.
const Status SYM_NO_STACK_FRAMES_FOUND
#define WINIT_REGISTER_CRITICAL_INIT(func)
static Status dump_sym_typedef(DWORD type_id, const u8 *p, DumpState &state)
static Status dump_string(const u8 *p, size_t el_size)
static Status dump_sym_pointer(DWORD type_id, const u8 *p, DumpState &state)
static const DWORD maxChildren
static void ptr_reset_visited()
static Status dump_array(const u8 *p, size_t el_count, DWORD el_type_id, size_t el_size, DumpState &state)
static IMAGEHLP_STACK_FRAME PopulateImageStackFrame(const STACKFRAME64 &sf)
static const size_t DEBUG_FILE_CHARS
Status(* DumpFunc)(DWORD typeId, const u8 *p, DumpState &state)
static bool ptr_already_visited(const u8 *p)
const Status SYM_TYPE_INFO_UNAVAILABLE
LIB_API void * debug_GetCaller(void *context, const wchar_t *lastFuncToSkip)
return the caller of a certain function on the call stack.
static const u8 * visited[maxVisited]
i64 Status
Error handling system.
void debug_break()
trigger a breakpoint when reached/"called".
static Status dump_sym_vtable(DWORD type_id, const u8 *p, DumpState &state)
static Status dump_sym_udt(DWORD type_id, const u8 *p, DumpState &state)
static void AppendCharacterIfPrintable(u64 data)
const size_t DEBUG_STL_MAX_ITERATOR_SIZE
no STL iterator is larger than this; see below.
static const u8 * array_iterator(void *internal, size_t el_size)
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
DWORD childrenStorage[maxChildren-1]
static void dump_error(Status err)
static Status dump_sym_enum(DWORD type_id, const u8 *p, DumpState &state)
static void out_init(wchar_t *buf, size_t max_chars)
static const size_t maxVisited
const u8 *(* DebugStlIterator)(void *internal, size_t el_size)
abstraction of all STL iterators used by debug_stl.
const Status SYM_INTERNAL_ERROR
bool cpu_CAS(volatile intptr_t *location, intptr_t expected, intptr_t newValue)
atomic "compare and swap".
wchar_t * StatusDescription(Status status, wchar_t *buf, size_t max_chars)
generate textual description of a Status.
#define WARN_IF_FALSE(expression)
const Status STL_CNT_UNKNOWN
static Status dump_sym(DWORD id, const u8 *p, DumpState &state)
static Status dump_sym_data(DWORD id, const u8 *p, DumpState &state)
LPSTACKFRAME64 stackFrame
static Status dump_sym_function(DWORD type_id, const u8 *p, DumpState &state)
const wchar_t * path_name_only(const wchar_t *path)
Get the path component of a path.
static Status CallStackWalk(STACKFRAME64 &sf, CONTEXT &context)
#define DEBUG_DISPLAY_ERROR(description)
#define WARN_RETURN(status)
static const size_t DEBUG_CONTEXT_SIZE
static Status out_check_limit()
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.
const OsPath & ah_get_log_dir()
return path to directory into which crash dumps should be written.
const Status SYM_NESTING_LIMIT
static bool IsUnretrievable(DWORD flags)
#define cassert(expr)
Compile-time assertion.
TI_FINDCHILDREN_PARAMS2(DWORD numChildren)
const Status SYM_SINGLE_SYMBOL_LIMIT
#define wdbg_assert(expr)
similar to ENSURE but safe to use during critical init or while under the heap or dbghelp locks...
static bool is_string(const u8 *p, size_t stride)
Status ModuleInit(volatile ModuleInitState *initState, Status(*init)())
calls a user-defined init function if initState is zero.
static STACKFRAME64 PopulateStackFrame(CONTEXT &context)
static size_t out_chars_left
static Status InitDbghelp()
#define WUTIL_IMPORT_KERNEL32(procName, varName)
u64 movzx_le64(const u8 *p, size_t size_bytes)
see write_be16
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
static std::string OsString(const OsPath &path)
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...
#define RETURN_STATUS_IF_ERR(expression)