mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
404 lines
9.5 KiB
C++
404 lines
9.5 KiB
C++
#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<Val> 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<NamedVal>())
|
|
return;
|
|
const NamedVal& nv = ValueTo<NamedVal>(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<NamedVal>(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<NamedVal>(v))
|
|
return;
|
|
const NamedVal& nv = ValueTo<NamedVal>(v);
|
|
if(nv.val.type < 0)
|
|
return;
|
|
StringBuffer w;
|
|
Point p = tree.GetScroll();
|
|
w << p.x << ' ' << p.y << ' ';
|
|
int id = tree.GetCursor();
|
|
Vector<String> cursor;
|
|
while(id >= 0) {
|
|
const NamedVal& nv = ValueTo<NamedVal>(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<NamedVal>(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<String> 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<Visual>().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<NamedVal>())
|
|
break;
|
|
const NamedVal& nv = v.To<NamedVal>();
|
|
if(nv.exp) {
|
|
if(IsAlpha(*exp))
|
|
exp = '.' + exp;
|
|
exp = nv.name + exp;
|
|
}
|
|
id = tree.GetParent(id);
|
|
}
|
|
AddWatch(tree_exp + "." + exp);
|
|
}
|
|
|
|
#endif
|