Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
wdbg_sym.cpp File Reference
#include "precompiled.h"
#include "lib/sysdep/os/win/wdbg_sym.h"
#include <cstdlib>
#include <cstdio>
#include <set>
#include "lib/byte_order.h"
#include "lib/module_init.h"
#include "lib/debug_stl.h"
#include "lib/app_hooks.h"
#include "lib/external_libraries/dbghelp.h"
#include "lib/sysdep/os/win/wdbg.h"
#include "lib/sysdep/os/win/wutil.h"
#include <atomic>
Include dependency graph for wdbg_sym.cpp:

Classes

struct  SYMBOL_INFO_PACKAGEW2
 
struct  TI_FINDCHILDREN_PARAMS2
 
struct  DumpState
 

Macros

#define INDENT   STMT(for(size_t i__ = 0; i__ <= state.level; i__++) out(L" ");)
 
#define UNINDENT   STMT(out_erase((state.level+1)*4);)
 
#define SUPPRESS_HANDLE(name)   if(!wcscmp(type_name, L#name L"__")) return true;
 

Typedefs

typedef Status(* DumpFunc) (DWORD typeId, const u8 *p, DumpState &state)
 

Enumerations

enum  CV_HREG_e { CV_REG_EBP = 22 , CV_AMD64_RBP = 334 }
 

Functions

static Status InitDbghelp ()
 
static void sym_init ()
 
static STACKFRAME64 PopulateStackFrame (CONTEXT &context)
 
static IMAGEHLP_STACK_FRAME PopulateImageStackFrame (const STACKFRAME64 &sf)
 
static Status ResolveSymbol_lk (void *ptr_of_interest, wchar_t *sym_name, wchar_t *file, int *line)
 
Status debug_ResolveSymbol (void *ptr_of_interest, wchar_t *sym_name, wchar_t *file, int *line)
 read and return symbol information for the given address. More...
 
Status debug_CaptureContext (void *pcontext)
 
static Status CallStackWalk (STACKFRAME64 &sf, CONTEXT &context)
 
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. More...
 
void * debug_GetCaller (void *pcontext, const wchar_t *lastFuncToSkip)
 return the caller of a certain function on the call stack. More...
 
static void out_init (wchar_t *buf, size_t max_chars)
 
static void out (const wchar_t *fmt,...)
 
static void out_erase (size_t num_chars)
 
static void out_latch_pos ()
 
static Status out_check_limit ()
 
static bool is_string (const u8 *p, size_t stride)
 
static Status dump_sym (DWORD id, const u8 *p, DumpState &state)
 
static void dump_error (Status err)
 
static Status dump_string (const u8 *p, size_t el_size)
 
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 Status dump_sequence (DebugStlIterator el_iterator, void *internal, size_t el_count, DWORD el_type_id, size_t el_size, DumpState &state)
 
static const u8array_iterator (void *internal, size_t el_size)
 
static Status dump_array (const u8 *p, size_t el_count, DWORD el_type_id, size_t el_size, DumpState &state)
 
static Status CanHandleDataKind (DWORD dataKind)
 
static bool IsRelativeToFramePointer (DWORD flags, DWORD reg)
 
static bool IsUnretrievable (DWORD flags)
 
static Status DetermineSymbolAddress (DWORD id, const SYMBOL_INFOW *sym, const DumpState &state, const u8 **pp)
 
static Status dump_sym_array (DWORD type_id, const u8 *p, DumpState &state)
 
static void AppendCharacterIfPrintable (u64 data)
 
static Status dump_sym_base_type (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_base_class (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_data (DWORD id, const u8 *p, DumpState &state)
 
static Status dump_sym_enum (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_function (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_function_type (DWORD type_id, const u8 *p, DumpState &state)
 
static void ptr_reset_visited ()
 
static bool ptr_already_visited (const u8 *p)
 
static Status dump_sym_pointer (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_typedef (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 Status udt_dump_std (const wchar_t *type_name, const u8 *p, size_t size, DumpState &state, ULONG numChildren, const DWORD *children)
 
static bool udt_should_suppress (const wchar_t *type_name)
 
static Status udt_dump_suppressed (const wchar_t *type_name, const u8 *p, size_t size, DumpState state, ULONG numChildren, const DWORD *children)
 
static bool udt_fits_on_one_line (const wchar_t *type_name, size_t child_count, size_t total_size)
 
static Status udt_dump_normal (const wchar_t *type_name, const u8 *p, size_t size, DumpState state, ULONG numChildren, const DWORD *children)
 
static Status dump_sym_udt (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_vtable (DWORD type_id, const u8 *p, DumpState &state)
 
static Status dump_sym_unknown (DWORD type_id, const u8 *p, DumpState &state)
 
static DumpFunc DumpFuncFromTypeTag (DWORD typeTag)
 
static bool ShouldSkipSymbol (const wchar_t *name)
 
static BOOL CALLBACK dump_sym_cb (SYMBOL_INFOW *sym, ULONG size, PVOID userContext)
 
static Status dump_frame_cb (const STACKFRAME64 *sf, uintptr_t userContext)
 
Status debug_DumpStack (wchar_t *buf, size_t maxChars, void *pcontext, const wchar_t *lastFuncToSkip)
 write a complete stack trace (including values of local variables) into the specified buffer. More...
 
void wdbg_sym_WriteMinidump (EXCEPTION_POINTERS *exception_pointers)
 

Variables

static HANDLE hProcess
 
static WORD machine
 
static const size_t maxIndirection = 255
 
static const size_t maxLevel = 255
 
static size_t out_chars_left
 
static wchar_t * out_pos
 
static bool out_have_warned_of_overflow
 
static wchar_t * out_latched_pos
 
static bool out_have_warned_of_limit
 
static const size_t maxVisited = 1000
 
static const u8visited [maxVisited]
 
static size_t numVisited
 

Macro Definition Documentation

◆ INDENT

#define INDENT   STMT(for(size_t i__ = 0; i__ <= state.level; i__++) out(L" ");)

◆ SUPPRESS_HANDLE

#define SUPPRESS_HANDLE (   name)    if(!wcscmp(type_name, L#name L"__")) return true;

◆ UNINDENT

#define UNINDENT   STMT(out_erase((state.level+1)*4);)

Typedef Documentation

◆ DumpFunc

typedef Status(* DumpFunc) (DWORD typeId, const u8 *p, DumpState &state)

Enumeration Type Documentation

◆ CV_HREG_e

enum CV_HREG_e
Enumerator
CV_REG_EBP 
CV_AMD64_RBP 

Function Documentation

◆ AppendCharacterIfPrintable()

static void AppendCharacterIfPrintable ( u64  data)
static

◆ array_iterator()

static const u8 * array_iterator ( void *  internal,
size_t  el_size 
)
static

◆ CallStackWalk()

static Status CallStackWalk ( STACKFRAME64 &  sf,
CONTEXT &  context 
)
static

◆ CanHandleDataKind()

static Status CanHandleDataKind ( DWORD  dataKind)
static

◆ debug_CaptureContext()

Status debug_CaptureContext ( void *  context)
Parameters
contextmust point to an instance of the platform-specific type (e.g. CONTEXT) or CACHE_ALIGNED storage of DEBUG_CONTEXT_SIZE bytes.

◆ debug_DumpStack()

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.

Parameters
bufTarget buffer.
maxCharsMax chars of buffer (should be several thousand).
contextPlatform-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.
lastFuncToSkipIs 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.
Returns
Status; ERR::REENTERED if reentered via recursion or multithreading (not allowed since static data is used).

◆ debug_GetCaller()

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.

Parameters
context,lastFuncToSkip- see debug_DumpStack
Returns
address of the caller

◆ debug_ResolveSymbol()

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).

Parameters
ptr_of_interestaddress of symbol (e.g. function, variable)
sym_nameoptional out; holds at least DEBUG_SYMBOL_CHARS; receives symbol name returned via debug info.
fileoptional out; holds at least DEBUG_FILE_CHARS; receives base name only (no path; see rationale in wdbg_sym) of source file containing the symbol.
lineoptional 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.

Returns
Status; INFO::OK iff any information was successfully retrieved and stored.

◆ DetermineSymbolAddress()

static Status DetermineSymbolAddress ( DWORD  id,
const SYMBOL_INFOW *  sym,
const DumpState state,
const u8 **  pp 
)
static

◆ dump_array()

static Status dump_array ( const u8 p,
size_t  el_count,
DWORD  el_type_id,
size_t  el_size,
DumpState state 
)
static

◆ dump_error()

static void dump_error ( Status  err)
static

◆ dump_frame_cb()

static Status dump_frame_cb ( const STACKFRAME64 *  sf,
uintptr_t  userContext 
)
static

◆ dump_sequence()

static Status dump_sequence ( DebugStlIterator  el_iterator,
void *  internal,
size_t  el_count,
DWORD  el_type_id,
size_t  el_size,
DumpState state 
)
static

◆ dump_string()

static Status dump_string ( const u8 p,
size_t  el_size 
)
static

◆ dump_sym()

static Status dump_sym ( DWORD  id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_array()

static Status dump_sym_array ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_base_class()

static Status dump_sym_base_class ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_base_type()

static Status dump_sym_base_type ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_cb()

static BOOL CALLBACK dump_sym_cb ( SYMBOL_INFOW *  sym,
ULONG  size,
PVOID  userContext 
)
static

◆ dump_sym_data()

static Status dump_sym_data ( DWORD  id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_enum()

static Status dump_sym_enum ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_function()

static Status dump_sym_function ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_function_type()

static Status dump_sym_function_type ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_pointer()

static Status dump_sym_pointer ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_typedef()

static Status dump_sym_typedef ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_udt()

static Status dump_sym_udt ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_unknown()

static Status dump_sym_unknown ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ dump_sym_vtable()

static Status dump_sym_vtable ( DWORD  type_id,
const u8 p,
DumpState state 
)
static

◆ DumpFuncFromTypeTag()

static DumpFunc DumpFuncFromTypeTag ( DWORD  typeTag)
static

◆ InitDbghelp()

static Status InitDbghelp ( )
static

◆ is_string()

static bool is_string ( const u8 p,
size_t  stride 
)
static

◆ IsRelativeToFramePointer()

static bool IsRelativeToFramePointer ( DWORD  flags,
DWORD  reg 
)
static

◆ IsUnretrievable()

static bool IsUnretrievable ( DWORD  flags)
static

◆ out()

static void out ( const wchar_t *  fmt,
  ... 
)
static

◆ out_check_limit()

static Status out_check_limit ( )
static

◆ out_erase()

static void out_erase ( size_t  num_chars)
static

◆ out_init()

static void out_init ( wchar_t *  buf,
size_t  max_chars 
)
static

◆ out_latch_pos()

static void out_latch_pos ( )
static

◆ PopulateImageStackFrame()

static IMAGEHLP_STACK_FRAME PopulateImageStackFrame ( const STACKFRAME64 &  sf)
static

◆ PopulateStackFrame()

static STACKFRAME64 PopulateStackFrame ( CONTEXT &  context)
static

◆ ptr_already_visited()

static bool ptr_already_visited ( const u8 p)
static

◆ ptr_reset_visited()

static void ptr_reset_visited ( )
static

◆ ResolveSymbol_lk()

static Status ResolveSymbol_lk ( void *  ptr_of_interest,
wchar_t *  sym_name,
wchar_t *  file,
int *  line 
)
static

◆ seq_determine_formatting()

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

◆ ShouldSkipSymbol()

static bool ShouldSkipSymbol ( const wchar_t *  name)
static

◆ sym_init()

static void sym_init ( )
static

◆ udt_dump_normal()

static Status udt_dump_normal ( const wchar_t *  type_name,
const u8 p,
size_t  size,
DumpState  state,
ULONG  numChildren,
const DWORD *  children 
)
static

◆ udt_dump_std()

static Status udt_dump_std ( const wchar_t *  type_name,
const u8 p,
size_t  size,
DumpState state,
ULONG  numChildren,
const DWORD *  children 
)
static

◆ udt_dump_suppressed()

static Status udt_dump_suppressed ( const wchar_t *  type_name,
const u8 p,
size_t  size,
DumpState  state,
ULONG  numChildren,
const DWORD *  children 
)
static

◆ udt_fits_on_one_line()

static bool udt_fits_on_one_line ( const wchar_t *  type_name,
size_t  child_count,
size_t  total_size 
)
static

◆ udt_get_child_type()

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

◆ udt_should_suppress()

static bool udt_should_suppress ( const wchar_t *  type_name)
static

◆ wdbg_sym_WalkStack()

Status wdbg_sym_WalkStack ( StackFrameCallback  cb,
uintptr_t  cbData,
CONTEXT &  context,
const wchar_t *  lastFuncToSkip = 0 
)

Iterate over a call stack, invoking a callback for each frame encountered.

Parameters
cb
cbData
contextProcessor context from which to start (taken from an exception record or debug_CaptureContext).
lastFuncToSkip
Note
It is safe to use ENSURE/debug_warn/WARN_RETURN_STATUS_IF_ERR even during a stack trace (which is triggered by ENSURE et al. in app code) because nested stack traces are ignored and only the error is displayed.

◆ wdbg_sym_WriteMinidump()

void wdbg_sym_WriteMinidump ( EXCEPTION_POINTERS *  exception_pointers)

Variable Documentation

◆ hProcess

HANDLE hProcess
static

◆ machine

WORD machine
static

◆ maxIndirection

const size_t maxIndirection = 255
static

◆ maxLevel

const size_t maxLevel = 255
static

◆ maxVisited

const size_t maxVisited = 1000
static

◆ numVisited

size_t numVisited
static

◆ out_chars_left

size_t out_chars_left
static

◆ out_have_warned_of_limit

bool out_have_warned_of_limit
static

◆ out_have_warned_of_overflow

bool out_have_warned_of_overflow
static

◆ out_latched_pos

wchar_t* out_latched_pos
static

◆ out_pos

wchar_t* out_pos
static

◆ visited

const u8* visited[maxVisited]
static