#include #include #include #include "cvconst.h" #include using namespace PdbKeys; struct Pdb : Debugger, ParentCtrl { virtual void Stop(); virtual bool IsFinished(); virtual bool Key(dword key, int count); virtual void DebugBar(Bar& bar); virtual bool SetBreakpoint(const String& filename, int line, const String& bp); virtual bool RunTo(); virtual void Run(); virtual bool Tip(const String& exp, CodeEditor::MouseTip& mt); virtual void Serialize(Stream& s); struct ModuleInfo : Moveable { adr_t base; dword size; String path; bool symbols; ModuleInfo() { base = size = 0; symbols = false; } }; struct FilePos { String path; int line; adr_t address; operator bool() const { return !IsNull(path); } FilePos() { line = 0; address = 0; } FilePos(const String& p, int l) : path(p), line(l) { address = 0; } }; enum CpuRegisterKind { REG_L, REG_H, REG_X, REG_E, REG_R }; struct CpuRegister : Moveable { int sym; // DbgHelp register symbol const char *name; // NULL: Do not list (e.g. al, as it is printed as EAX or RAX int kind; // CpuRegisterKind dword flags; // Unused }; struct MemPg : Moveable { char data[1024]; }; struct PdbHexView : HexView { Pdb *pdb; virtual int Byte(int64 addr) { return pdb ? pdb->Byte((adr_t)addr) : 0; } PdbHexView() { pdb = NULL; } } memory; struct FnInfo : Moveable { String name; adr_t address; dword size; dword pdbtype; FnInfo() { address = size = pdbtype = 0; } }; enum { UNKNOWN = -99, BOOL1, SINT1, UINT1, SINT2, UINT2, SINT4, UINT4, SINT8, UINT8, FLT, DBL, PFUNC }; struct Context { #ifdef CPU_64 union { CONTEXT context64; WOW64_CONTEXT context32; }; #else CONTEXT context32; #endif }; struct TypeInfo : Moveable { int type = UNKNOWN; int ref = 0; // this is pointer or reference bool reference = false; // this is reference }; struct Val : Moveable { bool array = false; bool rvalue = false; // data is loaded from debugee (if false, data pointed to by address) bool udt = false; // user defined type (e.g. struct..) byte bitpos = 0; byte bitcnt = 0; int reported_size = 0; // size of symbol, can be 0 - unknown, useful for C fixed size arrays union { adr_t address; int64 ival; double fval; }; Context *context = NULL; // needed to retrieve register variables #ifdef _DEBUG String ToString() const; #endif Val() { address = 0; } }; struct NamedVal : Moveable { String name; Val val; Val key; int64 from = 0; bool exp = false; }; struct Type : Moveable { Type() : size(-1), vtbl_typeindex(-1) {} adr_t modbase; String name; int size; int vtbl_typeindex; int vtbl_offset; Vector base; VectorMap member; VectorMap static_member; }; struct Frame : Moveable { adr_t pc, frame, stack; FnInfo fn; VectorMap param; VectorMap local; String text; }; struct VisualPart : Moveable { String text; Color ink; bool mark; Size GetSize() const; }; struct Visual { int length; Vector part; void Cat(const String& text, Color ink = SColorText); void Cat(const char *text, Color ink = SColorText); String GetString() const; void Clear() { part.Clear(); length = 0; } Size GetSize() const; Visual() { length = 0; } }; struct VisualDisplay : Display { Pdb *pdb; virtual Size GetStdSize(const Value& q) const; virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const; VisualDisplay(Pdb *pdb) : pdb(pdb) {} } visual_display; struct PrettyImage { Size size; adr_t pixels; }; struct Thread : Context { HANDLE hThread; adr_t sp; }; int lock; bool running; bool stop; HANDLE hProcess; HANDLE mainThread; DWORD processid; DWORD hProcessId; DWORD mainThreadId; ArrayMap threads; bool terminated; bool refreshmodules; Vector module; DEBUG_EVENT event; DWORD debug_threadid; HWND hWnd; VectorMap bp_set; // breakpoints active for single RunToException bool clang; // we are in clang toolchain bool win64; // debugee is 64-bit, always false in 32-bit exe Context context; Index invalidpage; VectorMap mempage; Index breakpoint; Vector breakpoint_cond; ArrayMap type; // maps pdb pSym->TypeIndex to type data VectorMap type_name; // maps the name of type to above 'type' index Index type_bases; // index of modbases for types (usually one) VectorMap type_index; // maps the name of type to TypeIndex, loaded by SymEnumTypes String disas_name; Array frame; Frame *current_frame; String autotext; VectorMap fninfo_cache; DbgDisas disas; EditString watchedit; enum { // Order in this enum has to be same as order of tab.Add TAB_AUTOS, TAB_LOCALS, TAB_THIS, TAB_WATCHES, TAB_CPU, TAB_MEMORY }; TabCtrl tab; DropList threadlist; DropList framelist; Button frame_up, frame_down; Label dlock; ArrayCtrl locals; ArrayCtrl self; ArrayCtrl watches; ArrayCtrl autos; ColumnList cpu; EditString expexp; Button exback, exfw; StaticRect explorer_pane; StaticRect pane, rpane; TreeCtrl tree; String tree_exp; bool first_exception = true; VectorMap treetype; int restoring_tree = 0; Vector exprev, exnext; Index noglobal; VectorMap global; adr_t current_modbase; // so that we do not need to pass it as parameter to GetTypeInfo VectorMap typeinfo_cache; enum { SINGLE_VALUE, TEXT, CONTAINER }; struct LengthLimit {}; struct Pretty { int kind; // VARIABLE, TEXT or CONTAINER int64 data_count = 0; // number of entries Vector data_type; // type of data items (usually type_param) Vector data_ptr; // pointer to items (data_count.GetCount() * data_type.GetCount() items) Visual text; void Text(const char *s, Color color = SRed) { text.Cat(s, color); } void Text(const String& s, Color color = SRed) { text.Cat(s, color); } void SetNull() { Text("Null", SCyan); } }; VectorMap&, int64, int, Pdb::Pretty&>>> pretty; bool break_running; // Needed for Wow64 BreakRunning to avoid ignoring breakpoint bool show_type = false; bool raw = false; int bc_lvl = 0; // For coloring { } in pretty container display void Error(const char *s = NULL); String Hex(adr_t); // CPU registers uint32 GetRegister32(const Context& ctx, int sym); uint64 GetRegister64(const Context& ctx, int sym); const VectorMap& GetRegisterList(); uint64 GetCpuRegister(const Context& ctx, int sym); // debug Context ReadContext(HANDLE hThread); void WriteContext(HANDLE hThread, Context& context); void LoadModuleInfo(); int FindModuleIndex(adr_t base); void UnloadModuleSymbols(); void AddThread(dword dwThreadId, HANDLE hThread); void RemoveThread(dword dwThreadId); void Lock(); void Unlock(); void ToForeground(); bool RunToException(); bool AddBp(adr_t address); bool RemoveBp(adr_t address); bool RemoveBp(); bool IsBpSet(adr_t address) const { return bp_set.Find(address) >= 0; } bool Continue(); bool SingleStep(); void BreakRunning(); bool ConditionalPass(); void SetBreakpoints(); void SaveForeground(); void RestoreForeground(); void SyncFrameButtons(); adr_t GetIP(); void WriteContext(); // mem int Byte(adr_t addr); bool Copy(adr_t addr, void *ptr, int count); String ReadString(adr_t addr, int maxlen, bool allowzero = false); WString ReadWString(adr_t addr, int maxlen, bool allowzero = false); // sym struct LocalsCtx; static BOOL CALLBACK EnumLocals(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext); static BOOL CALLBACK EnumGlobals(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext); void TypeVal(Pdb::Val& v, int typeId, adr_t modbase); String GetSymName(adr_t modbase, dword typeindex); dword GetSymInfo(adr_t modbase, dword typeindex, IMAGEHLP_SYMBOL_TYPE_INFO info); const Type& GetType(int ti); int GetTypeIndex(adr_t modbase, dword typeindex); Val GetGlobal(const String& name); adr_t GetAddress(FilePos p); FilePos GetFilePos(adr_t address); FnInfo GetFnInfo0(adr_t address); FnInfo GetFnInfo(adr_t address); void GetLocals(Frame& frame, Context& context, VectorMap& param, VectorMap& local); String TypeAsString(int ti, bool deep = true); int FindType(adr_t modbase, const String& name); String TypeInfoAsString(TypeInfo tf); TypeInfo GetTypeInfo(adr_t modbase, const String& name); TypeInfo GetTypeInfo(const String& name) { return GetTypeInfo(current_modbase, name); } // only in Pretty... static String FormatString(const String& x) { return AsCString(x, INT_MAX, NULL, CheckUtf8(x) ? 0 : ASCSTRING_OCTALHI); } // exp Val MakeVal(const String& type, adr_t address); void ThrowError(const char *s); int SizeOfType(int ti); int SizeOfType(const String& name); adr_t PeekPtr(adr_t address); byte PeekByte(adr_t address); word PeekWord(adr_t address); dword PeekDword(adr_t address); Val GetRVal(Val v); Val DeRef(Val v); Val Ref(Val v); int64 GetInt64(Val v); int GetInt(Val v) { return (int)GetInt64(v); } double GetFlt(Val v); void ZeroDiv(double x); Val Compute(Val v1, Val v2, int oper); Val RValue(int64 v); Val Field0(Pdb::Val v, const String& field); Val Field(Pdb::Val v, const String& field); Val Term(CParser& p); Val Post(CParser& p); Val Unary(CParser& p); Val Additive(CParser& p); Val Multiplicative(CParser& p); Val Compare(Val v, CParser& p, int r1, int r2); void GetBools(Val v1, Val v2, bool& a, bool& b); Val LogAnd(CParser& p); Val LogOr(CParser& p); Val Comparison(CParser& p); Val Exp0(CParser& p); Val Exp(CParser& p); bool HasAttr(Pdb::Val record, const String& id); Val GetAttr(Pdb::Val record, int i); Val GetAttr(Pdb::Val record, const String& id); int64 GetInt64Attr(Pdb::Val v, const char *a); int GetIntAttr(Pdb::Val v, const char *a) { return (int)GetInt64Attr(v, a); } byte GetByteAttr(Pdb::Val v, const char *a) { return (byte)GetInt64Attr(v, a); } Val At(Pdb::Val val, int i); Val At(Pdb::Val record, const char *id, int i); int IntAt(Pdb::Val record, const char *id, int i); void CatInt(Visual& result, int64 val, dword flags = 0); enum { MEMBER = 1, RAW = 2 }; void BaseFields(Visual& result, const Type& t, Pdb::Val val, dword flags, bool& cm, int depth); void Visualise(Visual& result, Pdb::Val val, dword flags); Visual Visualise(Val v, dword flags = 0); Visual Visualise(const String& rexp, dword flags = 0); bool VisualisePretty(Visual& result, Pdb::Val val, dword flags); bool PrettyVal(Pdb::Val val, int64 from, int count, Pretty& p); void PrettyString(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyWString(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyVector(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyArray(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyBiVector(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyBiArray(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyIndex(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyMap(Pretty& p, Pretty& key, Pretty& value); void PrettyVectorMap(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyArrayMap(Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyDate(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyTime(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyColor(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyRGBA(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyImageBuffer(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyImg(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyFont(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyValueArray_(adr_t a, Pdb::Pretty& p); void PrettyValueArray(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyValue(Pdb::Val val, const Vector& tparam, int64 from, int count, Pretty& p); void PrettyValueMap_(adr_t a, Pdb::Pretty& p, int64 from, int count); void PrettyValueMap(Pdb::Val val, const Vector&, int64 from, int count, Pdb::Pretty& p); void PrettyStdVector(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyStdString(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void TraverseTree(bool set, Val head, Val node, int64& from, int& count, Pdb::Pretty& p, int depth); void TraverseTreeClang(bool set, int nodet, Val node, int64& from, int& count, Pdb::Pretty& p, int depth); void PrettyStdTree(Pdb::Val val, bool set, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyStdListM(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p, bool map = false); void PrettyStdList(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyStdForwardList(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyStdDeque(Pdb::Val val, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); void PrettyStdUnordered(Pdb::Val val, bool set, const Vector& tparam, int64 from, int count, Pdb::Pretty& p); // code Thread& Current(); Array Backtrace(Thread& ctx, bool single_frame = false); int Disassemble(adr_t ip); bool IsValidFrame(adr_t eip); void Sync0(Thread& ctx); void Sync(); void SetThread(); void FrameUpDown(int dir); void SetFrame(); bool Step(bool over); void Trace(bool over); void StepOut(); void DoRunTo() { RunTo(); } adr_t CursorAdr(); void SetIp(); void Break(); // data static VectorMap DataMap(const ArrayCtrl& a); static Value Vis(const String& key, const VectorMap& prev, Visual&& vis, bool& ch); static void Vis(ArrayCtrl& a, const String& key, const VectorMap& prev, Visual&& vis); void DisasCursor() {} void DisasFocus() {} void Locals(); void Watches(); void TryAuto(const String& exp, const VectorMap& prev); void Autos(); void AddThis(const VectorMap& m, adr_t address, const VectorMap& prev); void AddThis(int type, adr_t address, const VectorMap& prev); void This(); void Data(); void ClearWatches(); void DropWatch(PasteClip& clip); void AddWatch(); void AddWatch(const String& s); void EditWatch(); void SetTab(int i); void SetTree(const String& exp); void SetTreeA(ArrayCtrl *data); void PrettyTreeNode(int parent, Pdb::Val val, int64 from = 0); bool TreeNode(int parent, const String& name, Val val, int64 from = 0, Color ink = SColorText(), bool exp = false); bool TreeNodeExp(int parent, const String& name, Val val, int64 from = 0, Color ink = SColorText()); void TreeExpand(int node); String GetTreeText(int id); void GetTreeText(String& r, int id, int depth); void TreeMenu(Bar& bar); void TreeWatch(); void StoreTree(StringBuffer& r, int parent); void SaveTree(); int FindChild(int parent, String id); void ExpandTreeType(int parent, CParser& p); void CopyStack(); void CopyStackAll(); void CopyDisas(); void MemoryGoto(const String& exp); void CopyMenu(ArrayCtrl& array, Bar& bar); void MemMenu(ArrayCtrl& array, Bar& bar, const String& exp); void DataMenu(ArrayCtrl& array, Bar& bar); void WatchMenu(Bar& bar, const String& exp); void WatchesMenu(Bar& bar); void SyncTreeDisas(); void Tab(); bool Create(One local, const String& exefile, const String& cmdline, bool clang_); void SerializeSession(Stream& s); typedef Pdb CLASSNAME; Pdb(); virtual ~Pdb(); void LoadGlobals(DWORD64 base); }; bool EditPDBExpression(const char *title, String& brk, Pdb *pdb);