#include "Debuggers.h" #ifdef PLATFORM_WIN32 #define LLOG(x) // LOG(x) void Pdb::PrettyTreeNode(int parent, Pdb::Val val, int64 from) { try { Pretty pp; if(val.ref || !PrettyVal(val, 0, 0, pp)) return; if(pp.kind == SINGLE_VALUE) { Pretty p; PrettyVal(val, 0, 1, p); if(p.text.part.GetCount()) { NamedVal nv; Visual result; nv.name = "$$"; for(const VisualPart& vp : p.text.part) result.Cat(vp.text, vp.ink); tree.Add(parent, Null, RawToValue(nv), RawPickToValue(pick(result)), false); } else if(p.data_type.GetCount() && p.data_ptr.GetCount()) PrettyTreeNode(parent, MakeVal(p.data_type[0], p.data_ptr[0]), from); } if(pp.kind == CONTAINER) { int chunk = pp.chunk; int n = int(min(pp.data_count, from + chunk) - from); Pretty p; PrettyVal(val, from, n, p); if(p.data_type.GetCount()) { Buffer item(p.data_type.GetCount()); for(int i = 0; i < p.data_type.GetCount(); i++) { (TypeInfo &)item[i] = GetTypeInfo(p.data_type[i]); item[i].context = val.context; } int ii = 0; int n = p.data_ptr.GetCount() / p.data_type.GetCount(); for(int i = 0; i < n; i++) { NamedVal nv; Visual result; nv.name << '[' << i + from << ']'; nv.val = val; nv.exp = true; result.Cat(nv.name + ' ', SGray); try { for(int j = 0; j < p.data_type.GetCount(); j++) { if(j) result.Cat(": "); item[j].address = p.data_ptr[p.separated_types ? j * n + i : ii++]; nv.val = item[j]; if(p.data_type.GetCount() > 1 && j == 0) nv.key = item[0]; Visualise(result, item[j], MEMBER); } } catch(LengthLimit) {} catch(CParser::Error e) { result.Cat("??"); } tree.Add(parent, Null, RawToValue(nv), RawPickToValue(pick(result)), nv.key.type != UNKNOWN || nv.val.type > 0); } if(pp.data_count > n && from == 0 && pp.data_count != INT64_MAX) { NamedVal nv; nv.name << ".."; nv.val = val; int64 ii = n; while(ii < pp.data_count) { nv.from = ii; nv.chunk = chunk; Visual v; v.Cat(String() << "[" << ii << ".." << min(pp.data_count - 1, ii + chunk - 1) << "]", SGray); tree.Add(parent, Null, RawToValue(nv), RawPickToValue(pick(v)), true); ii += chunk; } } } } } catch(LengthLimit) {} catch(CParser::Error e) {} } bool Pdb::TreeNode(int parent, const String& name, Pdb::Val val, int64 from, Color ink, bool exp) { PrettyTreeNode(parent, val); NamedVal nv; nv.name = name; nv.val = val; nv.from = from; nv.exp = exp; Visual v; bool r = true; try { v.Cat(name, ink); if(!from) { v.Cat("=", SGray); Visualise(v, val, 0); } } catch(LengthLimit) {} catch(CParser::Error e) { v.Cat(e, SColorDisabled); r = false; } tree.Add(parent, Null, RawToValue(nv), RawPickToValue(pick(v)), val.type >= 0 || val.ref > 0); return r; } bool Pdb::TreeNodeExp(int parent, const String& name, Val val, int64 from, Color ink) { return TreeNode(parent, name, val, from, ink, true); } void Pdb::TreeExpand(int node) { if(tree.GetChildCount(node)) return; try { Value v = tree.Get(node); if(!v.Is()) return; const NamedVal& nv = ValueTo(tree.Get(node)); Val val = nv.val; if(nv.key.type != UNKNOWN) { TreeNode(node, "key", nv.key); TreeNode(node, "value", val); SaveTree(); return; } if(nv.val.ref > 0) { Val val0 = val; val = DeRef(val); if(val.type < 0 || val.ref > 0) { int sz = SizeOfType(val.type); val.address += sz * nv.from; for(int i = 0; i < (nv.from ? nv.chunk : 40); i++) { if(!TreeNodeExp(node, String() << "[" << i + nv.from << "]" , val, 0, SLtMagenta())) { SaveTree(); return; } val.address += sz; } TreeNode(node, "[more]", val0, nv.from ? nv.from + nv.chunk : 40); SaveTree(); return; } } else if(nv.from > 0) { PrettyTreeNode(node, val, nv.from); SaveTree(); return; } if(val.type < 0) { SaveTree(); return; } PrettyTreeNode(node, val, 0); const Type& t = GetType(val.type); if(t.vtbl_typeindex == -2) { int count = GetSymInfo(t.modbase, type.GetKey(val.type), TI_GET_COUNT); Val prtti; prtti.ref = 1; prtti.type = UINT4; prtti.address = val.address - 4; Val rtti = GetRVal(prtti); FnInfo rtf = GetFnInfo(rtti.address); TreeNode(node, rtf.name, prtti); for(int i = 0; i < count; i++) { Val ventry; ventry.type = PFUNC; ventry.address = val.address + 4 * i; TreeNode(node, Format("[%d]", i), ventry); } SaveTree(); return; } if(t.vtbl_typeindex >= 0) { Val vtbl; vtbl.ref = 1; vtbl.address = val.address + t.vtbl_offset; vtbl.type = t.vtbl_typeindex; TreeNode(node, "virtual", vtbl); } for(int i = 0; i < t.base.GetCount(); i++) { Val r = t.base[i]; r.address += val.address; if(r.type >= 0) { const Type& bt = GetType(r.type); TreeNode(node, bt.name, r); } } for(int i = 0; i < t.member.GetCount(); i++) { Val r = t.member[i]; r.address += val.address; TreeNodeExp(node, t.member.GetKey(i), r); } for(int i = 0; i < t.static_member.GetCount(); i++) { Val r = t.static_member[i]; TreeNodeExp(node, t.static_member.GetKey(i), r); } SaveTree(); } catch(LengthLimit) {} catch(CParser::Error e) {} } void Pdb::StoreTree(StringBuffer& result, int parent) { int n = tree.GetChildCount(parent); for(int i = 0; i < n; i++) { int child = tree.GetChild(parent, i); bool first = true; if(tree.IsOpen(child)) { const NamedVal& nv = ValueTo(tree.Get(child)); if(!first) result << ";"; first = false; result << " " << AsCString(nv.name) << " {"; StoreTree(result, child); result << "}"; } } } void Pdb::SaveTree() { if(restoring_tree) return; Value v = tree.Get(0); if(!IsType(v)) return; const NamedVal& nv = ValueTo(v); if(nv.val.type < 0) return; StringBuffer w; Point p = tree.GetScroll(); w << p.x << ' ' << p.y << ' '; int id = tree.GetCursor(); Vector cursor; while(id >= 0) { const NamedVal& nv = ValueTo(tree.Get(id)); cursor.Add(AsCString(nv.name)); id = tree.GetParent(id); } Reverse(cursor); w << Join(cursor, ";") << ": "; StoreTree(w, 0); String r = w; treetype.GetAdd(GetType(nv.val.type).name) = r; LOG("SaveTree " << GetType(nv.val.type).name << ' ' << r); } int Pdb::FindChild(int parent, String id) { int n = tree.GetChildCount(parent); for(int i = 0; i < n; i++) { int child = tree.GetChild(parent, i); const NamedVal& nv = ValueTo(tree.Get(child)); if(nv.name == id) return child; } return -1; } void Pdb::ExpandTreeType(int parent, CParser& p) { while(p.IsString()) { int child = FindChild(parent, p.ReadString()); if(child >= 0) { tree.Open(child); p.Char('{'); ExpandTreeType(child, p); p.Char('}'); } } } void Pdb::SetTree(const String& exp) { tree_exp = exp; SaveTree(); tree.Clear(); NamedVal nv; try { CParser p(exp); nv.val = Exp(p); } catch(CParser::Error) { return; } if(nv.val.reference) { nv.val = DeRef(nv.val); nv.val.reference = false; } nv.name = exp; String n = exp; if(nv.val.type >= 0) n = GetType(nv.val.type).name; Visual v; try { v.Cat(n, SBlack); v.Cat("=", SGray); Visualise(v, nv.val, 0); } catch(LengthLimit) {} catch(CParser::Error e) { v.Cat(e, SColorDisabled); } tree.SetDisplay(visual_display); tree.SetRoot(Null, RawToValue(nv), RawPickToValue(pick(v))); if(nv.val.type >= 0) { String w = treetype.Get(n, Null); LOG("SetTree " << n << ' ' << w); tree.Open(0); CParser p(w); try { Point sc; sc.x = p.ReadInt(); sc.y = p.ReadInt(); Vector cursor; while(!p.Char(':')) { cursor.Add(p.ReadString()); p.Char(';'); } restoring_tree++; ExpandTreeType(0, p); restoring_tree--; tree.ScrollTo(sc); if(cursor.GetCount()) { int ii = 0; for(int i = 1; i < cursor.GetCount(); i++) { ii = FindChild(ii, cursor[i]); if(ii < 0) break; } if(ii >= 0) tree.SetCursor(ii); } } catch(CParser::Error) {} } SyncTreeDisas(); } void Pdb::SetTreeA(ArrayCtrl *array) { SetTree(array->Get(0)); } String Pdb::GetTreeText(int id) { return tree.GetValue(id).To().GetString(); } void Pdb::GetTreeText(String& r, int id, int depth) { int n = tree.GetChildCount(id); r << String('\t', depth) << GetTreeText(id) << "\n"; for(int i = 0; i < n; i++) GetTreeText(r, tree.GetChild(id, i), depth + 1); } void Pdb::TreeMenu(Bar& bar) { bar.Add(tree.IsCursor(), "Watch", [=] { TreeWatch(); }); bar.Add(tree.IsCursor(), "Copy", [=] { ClearClipboard(); AppendClipboardText(GetTreeText(tree.GetCursor())); }); bar.Add(tree.GetLineCount(), "Copy all", [=] { ClearClipboard(); String r; GetTreeText(r, 0, 0); AppendClipboardText(r); }); } void Pdb::TreeWatch() { int id = tree.GetCursor(); String exp; while(id >= 0) { Value v = tree.Get(id); if(!v.Is()) break; const NamedVal& nv = v.To(); if(nv.exp) { if(IsAlpha(*exp)) exp = '.' + exp; exp = nv.name + exp; } id = tree.GetParent(id); } AddWatch(tree_exp + "." + exp); } #endif