mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Ide/Debuggers/Gdb_MI2 : refactoring
git-svn-id: svn://ultimatepp.org/upp/trunk@6928 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
faa74e6cba
commit
392dbb89b4
8 changed files with 840 additions and 302 deletions
|
|
@ -1,6 +1,7 @@
|
|||
#include "Debuggers.h"
|
||||
#include <ide/ide.h>
|
||||
|
||||
#include "TypeSimplify.h"
|
||||
#include "PrettyPrinters.brc"
|
||||
|
||||
#define LDUMP(x) // DDUMP(x)
|
||||
|
|
@ -35,6 +36,24 @@ void WatchEdit::HighlightLine(int line, Vector<Highlight>& h, int pos)
|
|||
h[i].paper = (line % 2 ? cOdd : cEven);
|
||||
}
|
||||
|
||||
// fill a pane with data from a couple of arrays without erasing it first
|
||||
// (avoid re-painting and resetting scroll if not needed)
|
||||
static void FillPane(ArrayCtrl &pane, Index<String> const &nam, Vector<String> const &val)
|
||||
{
|
||||
int oldCount = pane.GetCount();
|
||||
int newCount = nam.GetCount();
|
||||
if(newCount < oldCount)
|
||||
for(int i = oldCount - 1; i >= newCount; i--)
|
||||
pane.Remove(i);
|
||||
for(int i = 0; i < min(oldCount, newCount); i++)
|
||||
{
|
||||
pane.Set(i, 0, nam[i]);
|
||||
pane.Set(i, 1, val[i]);
|
||||
}
|
||||
for(int i = oldCount; i < newCount; i++)
|
||||
pane.Add(nam[i], val[i]);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC IDE INTERFACE
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -130,11 +149,10 @@ void Gdb_MI2::Run()
|
|||
// non-stop mode enabled crashes X...don't know if it's a GDB bug or Theide one.
|
||||
// anyways, by now we give up with async mode and remove 'Asynchronous break' function
|
||||
val = MICmd("exec-run");
|
||||
|
||||
// val = MICmd("interpreter-exec console run&");
|
||||
|
||||
else
|
||||
val = MICmd("exec-continue --all");
|
||||
|
||||
int i = 50;
|
||||
while(!started && --i)
|
||||
{
|
||||
|
|
@ -200,33 +218,31 @@ bool Gdb_MI2::IsFinished()
|
|||
|
||||
bool Gdb_MI2::Tip(const String& exp, CodeEditor::MouseTip& mt)
|
||||
{
|
||||
/*
|
||||
// quick exit
|
||||
if(exp.IsEmpty() || !dbg)
|
||||
return false;
|
||||
|
||||
int idx = localVarNames.Find(exp);
|
||||
String nam, val;
|
||||
if(idx < 0)
|
||||
{
|
||||
idx = thisNames.Find(exp);
|
||||
if(idx < 0)
|
||||
return false;
|
||||
nam = thisFullNames[idx];
|
||||
val = thisValues[idx];
|
||||
}
|
||||
int iVal;
|
||||
String val;
|
||||
|
||||
// first look into locals....
|
||||
iVal = localExpressions.Find(exp);
|
||||
if(iVal >= 0)
|
||||
val = localValues[iVal];
|
||||
// if not fount, look into 'this'
|
||||
else
|
||||
{
|
||||
nam = exp;
|
||||
val = localVarValues[idx];
|
||||
iVal = thisShortExpressions.Find(exp);
|
||||
if(iVal >= 0)
|
||||
val = thisValues[iVal];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
mt.display = &StdDisplay();
|
||||
mt.value = nam + "=" + val;
|
||||
mt.value = exp + "=" + val;
|
||||
mt.sz = mt.display->GetStdSize(String(mt.value) + "X");
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -293,6 +309,7 @@ Gdb_MI2::Gdb_MI2()
|
|||
watches.WhenLeftDouble = THISBACK1(onExploreExpr, &watches);
|
||||
watches.EvenRowColor();
|
||||
watches.OddRowColor();
|
||||
watches.WhenUpdateRow = THISBACK1(SyncWatches, MIValue());
|
||||
|
||||
int c = EditField::GetStdHeight();
|
||||
explorer.AddColumn("", 1);
|
||||
|
|
@ -530,7 +547,7 @@ MIValue Gdb_MI2::ReadGdb(bool wait)
|
|||
// some commands (in particular if they return python exceptions)
|
||||
// have a delay between returned exception text and command result
|
||||
// so we shall wait up to the final (gdb)
|
||||
int retries = 3 * 50;
|
||||
int retries = 13 * 50;
|
||||
while(dbg && retries--)
|
||||
{
|
||||
dbg->Read(s);
|
||||
|
|
@ -543,7 +560,6 @@ MIValue Gdb_MI2::ReadGdb(bool wait)
|
|||
}
|
||||
else if(dbg)
|
||||
dbg->Read(output);
|
||||
|
||||
if(output.IsEmpty())
|
||||
return res;
|
||||
return ParseGdb(output);
|
||||
|
|
@ -610,8 +626,8 @@ MIValue Gdb_MI2::MICmd(const char *cmdLine)
|
|||
// is there and gives problems to MI interface. We shall maybe
|
||||
// parse and store it somewhere
|
||||
ReadGdb(false);
|
||||
dbg->Write(String("-") + cmdLine + "\n");
|
||||
|
||||
dbg->Write(String("-") + cmdLine + "\n");
|
||||
return ReadGdb();
|
||||
}
|
||||
|
||||
|
|
@ -743,7 +759,7 @@ void Gdb_MI2::SyncIde(bool fr)
|
|||
{
|
||||
// kill pending update callbacks
|
||||
timeCallback.Kill();
|
||||
|
||||
|
||||
// get current frame info and level
|
||||
MIValue fInfo = MICmd("stack-info-frame")["frame"];
|
||||
int level = atoi(fInfo["level"].Get());
|
||||
|
|
@ -763,22 +779,24 @@ void Gdb_MI2::SyncIde(bool fr)
|
|||
}
|
||||
|
||||
// setup threads droplist
|
||||
threadSelector.Clear();
|
||||
MIValue tInfo = MICmd("thread-info");
|
||||
if(!tInfo.IsError() && !tInfo.IsEmpty())
|
||||
{
|
||||
int curThread = atoi(tInfo["current-thread-id"].Get());
|
||||
MIValue &threads = tInfo["threads"];
|
||||
for(int iThread = 0; iThread < threads.GetCount(); iThread++)
|
||||
threadSelector.Clear();
|
||||
MIValue tInfo = MICmd("thread-info");
|
||||
if(!tInfo.IsError() && !tInfo.IsEmpty())
|
||||
{
|
||||
int id = atoi(threads[iThread]["id"].Get());
|
||||
if(id == curThread)
|
||||
int curThread = atoi(tInfo["current-thread-id"].Get());
|
||||
MIValue &threads = tInfo["threads"];
|
||||
for(int iThread = 0; iThread < threads.GetCount(); iThread++)
|
||||
{
|
||||
threadSelector.Add(id, Format("#%03x(*)", id));
|
||||
break;
|
||||
int id = atoi(threads[iThread]["id"].Get());
|
||||
if(id == curThread)
|
||||
{
|
||||
threadSelector.Add(id, Format("#%03x(*)", id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
threadSelector <<= curThread;
|
||||
}
|
||||
threadSelector <<= curThread;
|
||||
}
|
||||
|
||||
// get the arguments for current frame
|
||||
|
|
@ -791,11 +809,11 @@ void Gdb_MI2::SyncIde(bool fr)
|
|||
frame <<= 0;
|
||||
}
|
||||
|
||||
// update vars and disasm only on idle times
|
||||
timeCallback.Set(500, THISBACK(SyncData));
|
||||
//SyncData();
|
||||
|
||||
// sync disassembly
|
||||
SyncDisas(fInfo, fr);
|
||||
|
||||
// update vars only on idle times
|
||||
timeCallback.Set(500, THISBACK(SyncData));
|
||||
}
|
||||
|
||||
// logs frame data on console
|
||||
|
|
@ -841,9 +859,8 @@ void Gdb_MI2::StopAllThreads(void)
|
|||
// reselect current thread as it was before stopping all others
|
||||
if(current != "")
|
||||
MICmd("thread-select " + current);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// check for stop reason
|
||||
void Gdb_MI2::CheckStopReason(void)
|
||||
{
|
||||
|
|
@ -1085,34 +1102,111 @@ struct CapitalLess
|
|||
};
|
||||
|
||||
// update local variables on demand
|
||||
void Gdb_MI2::UpdateLocalVars(void)
|
||||
void Gdb_MI2::SyncLocals(MIValue val)
|
||||
{
|
||||
localVarNames.Clear();
|
||||
localVarValues.Clear();
|
||||
|
||||
MIValue iLoc = MICmd("stack-list-variables 1");
|
||||
if(!iLoc || iLoc.IsEmpty())
|
||||
return;
|
||||
MIValue &loc = iLoc["variables"];
|
||||
if(!loc.IsArray())
|
||||
return;
|
||||
|
||||
for(int iLoc = 0; iLoc < loc.GetCount(); iLoc++)
|
||||
bool firstCall = false;
|
||||
static VectorMap<String, String> prev;
|
||||
|
||||
// if not done, start first evaluation step
|
||||
if(val.IsEmpty())
|
||||
{
|
||||
MIValue &curLoc = loc[iLoc];
|
||||
if(curLoc["value"].IsString())
|
||||
prev = DataMap2(locals);
|
||||
|
||||
// get local vars names
|
||||
MIValue locs = MICmd("stack-list-variables 1");
|
||||
if(!locs.IsTuple() || locs.Find("variables") < 0)
|
||||
return;
|
||||
|
||||
// variables are returned as a tuple, named "variables"
|
||||
// containing a array of variables
|
||||
MIValue lLocs = locs["variables"];
|
||||
if(!lLocs.IsArray())
|
||||
return;
|
||||
|
||||
// as values are in string format we must parse them
|
||||
// so we simply build a big string with all variables
|
||||
// and feed into MIValue parser
|
||||
String s = "{";
|
||||
for(int iLoc = 0; iLoc < lLocs.GetCount(); iLoc++)
|
||||
{
|
||||
localVarNames.Add(curLoc["name"].ToString());
|
||||
localVarValues.Add(curLoc["value"].ToString());
|
||||
MIValue &lLoc = lLocs[iLoc];
|
||||
String name = lLoc["name"];
|
||||
|
||||
// skip 'this', we've a page for it
|
||||
if(name == "this")
|
||||
continue;
|
||||
s << name << "=" << lLoc["value"] << ",";
|
||||
}
|
||||
}
|
||||
if(s.EndsWith(","))
|
||||
s = s.Left(s.GetCount()-1);
|
||||
s << "}";
|
||||
val = s;
|
||||
|
||||
val.PackNames();
|
||||
AddAttribs("", val);
|
||||
val.FixArrays();
|
||||
|
||||
TypeSimplify(val, false);
|
||||
|
||||
firstCall = true;
|
||||
}
|
||||
|
||||
bool more = TypeSimplify(val, true);
|
||||
|
||||
// collect variables names and values
|
||||
CollectVariables(val, localExpressions, localValues, localHints);
|
||||
|
||||
// update locals pane
|
||||
FillPane(locals, localExpressions, localValues);
|
||||
|
||||
if(more)
|
||||
// more evaluations are needed, respawn the function with a delay
|
||||
// big delay on first respawn to allow quick stepping without lag
|
||||
timeCallback.Set(firstCall ? 2000 : 200, THISBACK1(SyncLocals, val));
|
||||
else
|
||||
// when finished, mark changed values
|
||||
MarkChanged2(prev, locals);
|
||||
}
|
||||
|
||||
// update 'this' inspector data
|
||||
void Gdb_MI2::UpdateThis(void)
|
||||
void Gdb_MI2::SyncThis(MIValue val)
|
||||
{
|
||||
MIValue val = Evaluate("*this");
|
||||
bool firstCall = false;
|
||||
static VectorMap<String, String> prev;
|
||||
|
||||
// if not done, start first evaluation step
|
||||
if(val.IsEmpty())
|
||||
{
|
||||
val = Evaluate("*this", false);
|
||||
prev = DataMap2(members);
|
||||
|
||||
// this is the first evaluation step
|
||||
// just simple types -- lag some seconds to full evaluation
|
||||
// which is quite slow
|
||||
firstCall = true;
|
||||
}
|
||||
|
||||
// deep evaluation step
|
||||
bool more = TypeSimplify(val, true);
|
||||
|
||||
// collect variables names and values
|
||||
CollectVariables(val, thisExpressions, thisValues, thisHints);
|
||||
|
||||
// strip the (*this) from variables names
|
||||
thisShortExpressions.Clear();
|
||||
for(int iExpr = 0; iExpr < thisExpressions.GetCount(); iExpr++)
|
||||
thisShortExpressions.Add(thisExpressions[iExpr].Mid(8));
|
||||
|
||||
// update 'this' pane
|
||||
FillPane(members, thisShortExpressions, thisValues);
|
||||
|
||||
if(more)
|
||||
// more evaluations are needed, respawn the function with a delay
|
||||
// big delay on first respawn to allow quick stepping without lag
|
||||
timeCallback.Set(firstCall ? 2000 : 200, THISBACK1(SyncThis, val));
|
||||
else
|
||||
// when finished, mark changed values
|
||||
MarkChanged2(prev, members);
|
||||
}
|
||||
|
||||
// sync auto vars treectrl
|
||||
|
|
@ -1139,9 +1233,9 @@ void Gdb_MI2::SyncAutos()
|
|||
break;
|
||||
exp << p.ReadId();
|
||||
}
|
||||
int idx = localVarNames.Find(exp);
|
||||
int idx = localExpressions.Find(exp);
|
||||
if(idx >= 0)
|
||||
autos.Add(exp, localVarValues[idx]);
|
||||
autos.Add(exp, localValues[idx]);
|
||||
}
|
||||
p.SkipTerm();
|
||||
}
|
||||
|
|
@ -1150,40 +1244,72 @@ void Gdb_MI2::SyncAutos()
|
|||
}
|
||||
|
||||
// sync watches treectrl
|
||||
void Gdb_MI2::SyncLocals()
|
||||
void Gdb_MI2::SyncWatches(MIValue val)
|
||||
{
|
||||
VectorMap<String, String> prev = DataMap2(locals);
|
||||
locals.Clear();
|
||||
|
||||
for(int iLoc = 0; iLoc < localVarNames.GetCount(); iLoc++)
|
||||
locals.Add(localVarNames[iLoc], localVarValues[iLoc]);
|
||||
MarkChanged2(prev, locals);
|
||||
}
|
||||
|
||||
void Gdb_MI2::SyncMembers(void)
|
||||
{
|
||||
VectorMap<String, String> prev = DataMap2(members);
|
||||
members.Clear();
|
||||
|
||||
for(int iMem = 0; iMem < thisExpressions.GetCount(); iMem++)
|
||||
members.Add(thisExpressions[iMem].Mid(7), thisValues[iMem]);
|
||||
MarkChanged2(prev, members);
|
||||
}
|
||||
|
||||
// sync watches treectrl
|
||||
void Gdb_MI2::SyncWatches()
|
||||
{
|
||||
// re-fill the control
|
||||
VectorMap<String, String> prev = DataMap2(watches);
|
||||
for(int i = 0; i < watches.GetCount(); i++)
|
||||
static VectorMap<String, String> prev;
|
||||
bool firstCall = false;
|
||||
|
||||
// on first cycle, we fast evaluate all expressions
|
||||
// without going deep, and put all results into an array
|
||||
if(val.IsEmpty())
|
||||
{
|
||||
MIValue res = MICmd("data-evaluate-expression \"" + watches.Get(i, 0).ToString() + "\"");
|
||||
if(res.IsError() || res.IsEmpty())
|
||||
watches.Set(i, 2, t_("<can't evaluate expression>"));
|
||||
else
|
||||
watches.Set(i, 2, res["value"].ToString());
|
||||
prev = DataMap2(watches);
|
||||
|
||||
for(int i = 0; i < watches.GetCount(); i++)
|
||||
{
|
||||
String expr = watches.Get(i,0);
|
||||
MIValue res;
|
||||
res.Set("<can't evaluate>");
|
||||
MIValue valExpr = MICmd("data-evaluate-expression " + expr);
|
||||
|
||||
if(valExpr.IsTuple() && valExpr.Find("value") >= 0)
|
||||
{
|
||||
MIValue const &tup = valExpr.Get("value");
|
||||
if(tup.IsString())
|
||||
{
|
||||
String s = tup.ToString();
|
||||
res = s;
|
||||
}
|
||||
}
|
||||
res.PackNames();
|
||||
AddAttribs("", res);
|
||||
res.FixArrays();
|
||||
|
||||
val.Add(res);
|
||||
}
|
||||
firstCall = true;
|
||||
}
|
||||
MarkChanged2(prev, watches);
|
||||
RLOG(val.Dump());
|
||||
bool more = false;
|
||||
|
||||
// simplify loop, returns when at least one simplify step happens
|
||||
for(int iVal = 0; iVal < val.GetCount(); iVal++)
|
||||
{
|
||||
MIValue &v = val[iVal];
|
||||
more |= TypeSimplify(v, true);
|
||||
if(more)
|
||||
break;
|
||||
}
|
||||
// collects all results
|
||||
watchesValues.Clear();
|
||||
for(int iVal = 0; iVal < val.GetCount(); iVal++)
|
||||
watchesValues << CollectVariablesShort(val[iVal]);
|
||||
|
||||
// fill expressions with ctrl expr contents
|
||||
watchesExpressions.Clear();
|
||||
for(int iVal = 0; iVal < watchesValues.GetCount(); iVal++)
|
||||
watchesExpressions << watches.Get(iVal, 0);
|
||||
|
||||
// update locals pane
|
||||
FillPane(watches, watchesExpressions, watchesValues);
|
||||
|
||||
if(more)
|
||||
// more evaluations are needed, respawn the function with a delay
|
||||
// big delay on first respawn to allow quick stepping without lag
|
||||
timeCallback.Set(firstCall ? 2000 : 200, THISBACK1(SyncWatches, val));
|
||||
else
|
||||
// when finished, mark changed values
|
||||
MarkChanged2(prev, watches);
|
||||
}
|
||||
|
||||
// sync data tabs, depending on which tab is shown
|
||||
|
|
@ -1192,17 +1318,15 @@ void Gdb_MI2::SyncData()
|
|||
if(dataSynced)
|
||||
return;
|
||||
|
||||
// updates stored local variables
|
||||
// those are needed for Autos, Locals and Tooltips
|
||||
UpdateLocalVars();
|
||||
|
||||
// update stored 'this' member data
|
||||
// also used for tooltips and 'this' pane page
|
||||
UpdateThis();
|
||||
SyncThis();
|
||||
|
||||
SyncAutos();
|
||||
// updated locals variables
|
||||
SyncLocals();
|
||||
SyncMembers();
|
||||
|
||||
SyncAutos();
|
||||
|
||||
SyncWatches();
|
||||
|
||||
dataSynced = true;
|
||||
|
|
@ -1515,7 +1639,8 @@ void Gdb_MI2::onExploreExpr(ArrayCtrl *what)
|
|||
{
|
||||
// otherwise, we use the expression from sending ArrayCtrl
|
||||
int line = what->GetCursor();
|
||||
if(line >= 0)
|
||||
int col = what->GetClickColumn();
|
||||
if(line >= 0 && (what != &watches || col != 0))
|
||||
expr = what->Get(line, 0);
|
||||
}
|
||||
// nothing to do on empty expression
|
||||
|
|
@ -1620,6 +1745,24 @@ bool Gdb_MI2::Create(One<Host> _host, const String& exefile, const String& cmdli
|
|||
MICmd("gdb-set confirm off");
|
||||
MICmd("gdb-set print asm-demangle");
|
||||
|
||||
// limit array printing to 200 elements
|
||||
MICmd("gdb-set print elements 200");
|
||||
|
||||
// do NOT print repeated counts -- they confuse the parser
|
||||
MICmd("gdb-set print repeat 0");
|
||||
|
||||
// we wanna addresses, we skip them in parser if useless
|
||||
// MICmd("gdb-set print address off");
|
||||
|
||||
// print true objects having their pointers (if have vtbls)
|
||||
MICmd("gdb-set print object on");
|
||||
|
||||
// print symbolic addresses, if found
|
||||
MICmd("gdb-set print symbol on");
|
||||
|
||||
// do not search of symbolic address near current one
|
||||
MICmd("gdb-set print max-symbolic-offset 1");
|
||||
|
||||
// avoids debugger crash if caught inside ungrabbing function
|
||||
// (don't solves all cases, but helps...)
|
||||
MICmd("gdb-set unwindonsignal on");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class WatchEdit : public LineEdit
|
|||
class Gdb_MI2 : public Debugger, public ParentCtrl
|
||||
{
|
||||
private:
|
||||
|
||||
|
||||
// item for a GDB variable
|
||||
struct VarItem : Moveable<VarItem>
|
||||
{
|
||||
|
|
@ -139,9 +139,6 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
MIValue ParseGdb(String const &s, bool wait = true);
|
||||
MIValue ReadGdb(bool wait = true);
|
||||
|
||||
// sends an MI command and get answer back
|
||||
MIValue MICmd(const char *cmdLine);
|
||||
|
||||
// format breakpoint line from ide file and line
|
||||
String BreakPos(String const &file, int line);
|
||||
|
||||
|
|
@ -158,27 +155,24 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
MIValue InsertBreakpoint(const char *file, int line);
|
||||
|
||||
// stored local variable expressions, and values
|
||||
Index<String>localVarNames;
|
||||
Vector<String>localVarValues;
|
||||
Index<String>localExpressions;
|
||||
Vector<String>localValues;
|
||||
Vector<int>localHints;
|
||||
|
||||
// stored watches expressions and values
|
||||
Index<String>watchesExpressions;
|
||||
Vector<String>watchesValues;
|
||||
Vector<int>watchesHints;
|
||||
|
||||
// 'this' variable inspection data
|
||||
Vector<String>thisExpressions;
|
||||
Index<String>thisExpressions;
|
||||
Vector<String>thisValues;
|
||||
Vector<int>thisHints;
|
||||
Index<String>thisShortExpressions;
|
||||
|
||||
// stored autos expressions, values and types
|
||||
String autoLine;
|
||||
|
||||
// update local variables on demand
|
||||
void UpdateLocalVars(void);
|
||||
|
||||
// update 'this' inspector data
|
||||
void UpdateThis(void);
|
||||
|
||||
// logs frame data on console
|
||||
void LogFrame(String const &msg, MIValue &frame);
|
||||
|
||||
|
|
@ -207,13 +201,13 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
void SyncAutos();
|
||||
|
||||
// sync local variables pane
|
||||
void SyncLocals(void);
|
||||
void SyncLocals(MIValue val = MIValue());
|
||||
|
||||
// sync 'this' members pane
|
||||
void SyncMembers(void);
|
||||
// Sync 'this' inspector data
|
||||
void SyncThis(MIValue val = MIValue());
|
||||
|
||||
// sync watches treectrl
|
||||
void SyncWatches();
|
||||
void SyncWatches(MIValue val = MIValue());
|
||||
|
||||
// sync data tabs, depending on which tab is shown
|
||||
bool dataSynced;
|
||||
|
|
@ -270,15 +264,26 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
String GetHostPath(const String& path) { return host->GetHostPath(path); }
|
||||
String GetLocalPath(const String& path) { return host->GetLocalPath(path); }
|
||||
|
||||
// known types simplifier
|
||||
// takes a MIValue from '-data-evaluate-expression' command and try
|
||||
// do simplify diplay of known types
|
||||
void TypeSimplify(MIValue &val);
|
||||
// now we scan the result and add some info
|
||||
// so, for example, if we find tuple like this one:
|
||||
// data = simplevalue
|
||||
// this will be modified as
|
||||
// data = { value = simplevalue, expr = evaluable_expression }
|
||||
// and for a complex value
|
||||
// data = { some=complex, not_simple=val }
|
||||
// woll be modified as
|
||||
// data = { <!value> = { some=complex, not_simple=val }, <!expr> = evaluable_expression }
|
||||
// More attributes will be added by type simplifier phase
|
||||
void AddAttribs(String const &expr, MIValue &valExpr);
|
||||
|
||||
// collects evaluated variables got with Evaluate
|
||||
// hints are used to choose the visualizer when deep-inspecting members
|
||||
// 0 for simple values, 1 for arrays, 2 for map
|
||||
void CollectVariables(MIValue &val, Vector<String> &exprs, Vector<String> &vals, Vector<int> &hints);
|
||||
void CollectVariables(MIValue &val, Index<String> &exprs, Vector<String> &vals, Vector<int> &hints);
|
||||
|
||||
// collect evaluated variables got with Evaluate
|
||||
// into a single-line string for short display
|
||||
String CollectVariablesShort(MIValue &val);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -301,13 +306,24 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
|
||||
Gdb_MI2();
|
||||
virtual ~Gdb_MI2();
|
||||
|
||||
|
||||
// sends an MI command and get answer back
|
||||
MIValue MICmd(const char *cmdLine);
|
||||
|
||||
// known types simplifier
|
||||
// takes a MIValue from '-data-evaluate-expression' command and try
|
||||
// do simplify diplay of known types
|
||||
// with deep = false it does just type simplification, no deep evaluation of containers
|
||||
// with deep = true it does ONE deep evaluation step
|
||||
// returns true if more deep evaluation steps are needed, false otherwise
|
||||
bool TypeSimplify(MIValue &val, bool deep);
|
||||
|
||||
// variable inspection support
|
||||
// returns a MIValue with inspected data and some info fields added
|
||||
// and known types simplified and cathegorized
|
||||
// unknown and simple types are left as they are
|
||||
MIValue Evaluate(String expr);
|
||||
// deep is true if we shall have a complete sub-elements evaluation
|
||||
MIValue Evaluate(String expr, bool deep = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
// woll be modified as
|
||||
// data = { <!value> = { some=complex, not_simple=val }, <!expr> = evaluable_expression }
|
||||
// More attributes will be added by type simplifier phase
|
||||
static void AddAttribs(String const &expr, MIValue &valExpr)
|
||||
void Gdb_MI2::AddAttribs(String const &expr, MIValue &valExpr)
|
||||
{
|
||||
if(valExpr.IsTuple())
|
||||
{
|
||||
|
|
@ -22,7 +22,12 @@ static void AddAttribs(String const &expr, MIValue &valExpr)
|
|||
String nam = valExpr.GetKey(i);
|
||||
String nExpr;
|
||||
if(!nam.StartsWith("<"))
|
||||
nExpr = expr + "." + nam;
|
||||
{
|
||||
if(expr != "")
|
||||
nExpr = expr + "." + nam;
|
||||
else
|
||||
nExpr = nam;
|
||||
}
|
||||
else
|
||||
nExpr = expr;
|
||||
MIValue v = valExpr[i];
|
||||
|
|
@ -34,11 +39,14 @@ static void AddAttribs(String const &expr, MIValue &valExpr)
|
|||
}
|
||||
else if(valExpr.IsArray())
|
||||
{
|
||||
for(int i = 0; i < valExpr.GetCount(); i++)
|
||||
AddAttribs(expr, valExpr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Gdb_MI2::TypeSimplify(MIValue &val)
|
||||
bool Gdb_MI2::TypeSimplify(MIValue &val, bool deep)
|
||||
{
|
||||
bool needMore = false;
|
||||
if(val.IsTuple())
|
||||
{
|
||||
for(int i = 0; i < val.GetCount(); i++)
|
||||
|
|
@ -58,24 +66,56 @@ void Gdb_MI2::TypeSimplify(MIValue &val)
|
|||
{
|
||||
TYPE_SIMPLIFIER_HANDLER handler = GetSimplifier(v.GetKey(0));
|
||||
if(handler)
|
||||
handler(*this, vRoot);
|
||||
{
|
||||
needMore |= handler(*this, vRoot, deep);
|
||||
if(deep)
|
||||
{
|
||||
if(needMore)
|
||||
{
|
||||
// we shall remove the temporary value now...
|
||||
vRoot.Remove(SIMPLIFY_TEMPVAL);
|
||||
return needMore;
|
||||
}
|
||||
}
|
||||
else if(needMore)
|
||||
vRoot.FindAdd(SIMPLIFY_TEMPVAL, "<evaluating...>");
|
||||
}
|
||||
else
|
||||
TypeSimplify(v);
|
||||
needMore |= TypeSimplify(v, deep);
|
||||
}
|
||||
else
|
||||
TypeSimplify(v);
|
||||
needMore |= TypeSimplify(v, deep);
|
||||
}
|
||||
else
|
||||
TypeSimplify(v);
|
||||
needMore |= TypeSimplify(v, deep);
|
||||
}
|
||||
}
|
||||
else if(val.IsArray())
|
||||
{
|
||||
for(int i = 0; i < val.GetCount(); i++)
|
||||
{
|
||||
// encapsulate each element inside a tuple
|
||||
MIValue tuple;
|
||||
tuple.Add("<!DUMMY>", val[i]);
|
||||
|
||||
// simplify
|
||||
needMore |= TypeSimplify(tuple, deep);
|
||||
|
||||
// de-encapsulate the element
|
||||
val[i] = tuple[0];
|
||||
if(deep && needMore)
|
||||
return needMore;
|
||||
}
|
||||
}
|
||||
return needMore;
|
||||
}
|
||||
|
||||
// variable inspection support
|
||||
// returns a MIValue with inspected data and some info fields added
|
||||
// and known types simplified and cathegorized
|
||||
// unknown and simple types are left as they are
|
||||
MIValue Gdb_MI2::Evaluate(String expr)
|
||||
// if deep is true, partial evaluation of containers is done
|
||||
MIValue Gdb_MI2::Evaluate(String expr, bool deep)
|
||||
{
|
||||
// add parhentesis around expression... gdb is dumb
|
||||
expr = "(" + expr + ")";
|
||||
|
|
@ -83,7 +123,7 @@ MIValue Gdb_MI2::Evaluate(String expr)
|
|||
// ask gdb to evaluate expression
|
||||
// and gather result in a tuple
|
||||
MIValue valExpr = MICmd("data-evaluate-expression " + expr);
|
||||
|
||||
|
||||
// return empty value on error
|
||||
if(!valExpr.IsTuple())
|
||||
return MIValue();
|
||||
|
|
@ -97,25 +137,24 @@ MIValue Gdb_MI2::Evaluate(String expr)
|
|||
String s = tup.ToString();
|
||||
MIValue parsed(s);
|
||||
|
||||
// enclose it in a dummy container
|
||||
MIValue enclosed;
|
||||
enclosed.Add("<DUMMY>", parsed);
|
||||
// pack tuple names--remove spaces
|
||||
parsed.PackNames();
|
||||
|
||||
// remove spaces from names
|
||||
enclosed.PackNames();
|
||||
|
||||
// Add attributes to expression data
|
||||
AddAttribs(expr, enclosed);
|
||||
|
||||
//RLOG(parsed.Dump());
|
||||
AddAttribs(expr, parsed);
|
||||
|
||||
// fix arrays
|
||||
parsed.FixArrays();
|
||||
|
||||
//RLOG(parsed.Dump());
|
||||
// now we go through the type simplifier, which try to give simple representation
|
||||
// for known types
|
||||
TypeSimplify(enclosed);
|
||||
|
||||
//RLOG(enclosed.Dump());
|
||||
|
||||
// now we can de-enclose it...
|
||||
parsed = enclosed["<DUMMY>"][SIMPLIFY_VALUE];
|
||||
// for known types -- first step, just type simplification and NOT deep evaluation
|
||||
bool needMore = TypeSimplify(parsed, false);
|
||||
|
||||
// deep container evaluation on request
|
||||
if(deep)
|
||||
while(needMore)
|
||||
needMore = TypeSimplify(parsed, true);
|
||||
//RLOG(parsed.Dump());
|
||||
|
||||
// and finally return the cleaned evaluated data
|
||||
|
|
@ -137,7 +176,7 @@ RLOG("WEIRD STUFF HERE....");
|
|||
// collects evaluated variables got with Evaluate
|
||||
// hints are used to choose the visualizer when deep-inspecting members
|
||||
// 0 for simple values, 1 for arrays, 2 for map
|
||||
static void Collect0(MIValue &val, Vector<String> &exprs, Vector<String> &vals, Vector<int> &hints)
|
||||
static void Collect0(MIValue &val, Index<String> &exprs, Vector<String> &vals, Vector<int> &hints)
|
||||
{
|
||||
if(!val.IsTuple())
|
||||
return;
|
||||
|
|
@ -145,33 +184,44 @@ static void Collect0(MIValue &val, Vector<String> &exprs, Vector<String> &vals,
|
|||
for(int i = 0; i < val.GetCount(); i++)
|
||||
{
|
||||
MIValue &v = val[i];
|
||||
MIValue &data = v[SIMPLIFY_VALUE];
|
||||
if(data.IsError())
|
||||
continue;
|
||||
if(data.IsString())
|
||||
|
||||
// variables still to be evaluated...
|
||||
if(v.Find(SIMPLIFY_TEMPVAL) >= 0)
|
||||
{
|
||||
String d = data.ToString();
|
||||
if(!d.StartsWith("<"))
|
||||
{
|
||||
vals.Add(data.ToString()),
|
||||
exprs.Add(v[SIMPLIFY_EXPR]);
|
||||
String hint = v.Get(SIMPLIFY_HINT, SIMPLIFY_SIMPLE);
|
||||
if(hint == SIMPLIFY_SIMPLE)
|
||||
hints << 0;
|
||||
else if(hint == SIMPLIFY_ARRAY)
|
||||
hints << 1;
|
||||
else if(hint == SIMPLIFY_MAP)
|
||||
hints << 2;
|
||||
else
|
||||
hints << 0;
|
||||
}
|
||||
vals.Add(v[SIMPLIFY_TEMPVAL].ToString());
|
||||
exprs.Add(v[SIMPLIFY_EXPR].ToString());
|
||||
hints << 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MIValue &data = v[SIMPLIFY_VALUE];
|
||||
if(data.IsError())
|
||||
continue;
|
||||
if(data.IsString())
|
||||
{
|
||||
String d = data.ToString();
|
||||
if(!d.StartsWith("<"))
|
||||
{
|
||||
vals.Add(data.ToString()),
|
||||
exprs.Add(v[SIMPLIFY_EXPR].ToString());
|
||||
String hint = v.Get(SIMPLIFY_HINT, SIMPLIFY_SIMPLE);
|
||||
if(hint == SIMPLIFY_SIMPLE)
|
||||
hints << 0;
|
||||
else if(hint == SIMPLIFY_ARRAY)
|
||||
hints << 1;
|
||||
else if(hint == SIMPLIFY_MAP)
|
||||
hints << 2;
|
||||
else
|
||||
hints << 0;
|
||||
}
|
||||
}
|
||||
else if(data.IsTuple())
|
||||
Collect0(data, exprs, vals, hints);
|
||||
}
|
||||
else if(data.IsTuple())
|
||||
Collect0(data, exprs, vals, hints);
|
||||
}
|
||||
}
|
||||
|
||||
void Gdb_MI2::CollectVariables(MIValue &val, Vector<String> &exprs, Vector<String> &vals, Vector<int> &hints)
|
||||
void Gdb_MI2::CollectVariables(MIValue &val, Index<String> &exprs, Vector<String> &vals, Vector<int> &hints)
|
||||
{
|
||||
exprs.Clear();
|
||||
vals.Clear();
|
||||
|
|
@ -180,3 +230,74 @@ void Gdb_MI2::CollectVariables(MIValue &val, Vector<String> &exprs, Vector<Strin
|
|||
Collect0(val, exprs, vals, hints);
|
||||
}
|
||||
|
||||
static void CollectShort0(MIValue &val, String &s)
|
||||
{
|
||||
if(val.IsTuple())
|
||||
{
|
||||
for(int i = 0; i < val.GetCount(); i++)
|
||||
{
|
||||
MIValue &v = val[i];
|
||||
String expr = v[SIMPLIFY_EXPR].ToString();
|
||||
|
||||
// variables still to be evaluated...
|
||||
if(v.Find(SIMPLIFY_TEMPVAL) >= 0)
|
||||
s << expr << "=" << v[SIMPLIFY_TEMPVAL].ToString() << " , ";
|
||||
else
|
||||
{
|
||||
MIValue &data = v[SIMPLIFY_VALUE];
|
||||
if(data.IsError())
|
||||
return;
|
||||
if(data.IsString())
|
||||
{
|
||||
// skip vtbls... quite useless
|
||||
if(expr.StartsWith("_vptr."))
|
||||
return;
|
||||
|
||||
String d = data.ToString();
|
||||
if(!d.StartsWith("<"))
|
||||
s << v[SIMPLIFY_EXPR].ToString() << "=" << d << " , ";
|
||||
}
|
||||
else if(data.IsTuple())
|
||||
CollectShort0(data, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(val.IsArray())
|
||||
{
|
||||
for(int i = 0; i < val.GetCount(); i++)
|
||||
{
|
||||
MIValue &v = val[i];
|
||||
|
||||
if(v.Find(SIMPLIFY_TEMPVAL) >= 0)
|
||||
s << v[SIMPLIFY_TEMPVAL].ToString() << " , ";
|
||||
else
|
||||
{
|
||||
MIValue &data = v[SIMPLIFY_VALUE];
|
||||
if(data.IsError())
|
||||
return;
|
||||
if(data.IsString())
|
||||
{
|
||||
String d = data.ToString();
|
||||
if(!d.StartsWith("<"))
|
||||
s << d << " , ";
|
||||
}
|
||||
else if(data.IsTuple())
|
||||
CollectShort0(data, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collect evaluated variables got with Evaluate
|
||||
// into a vector of single-line string for short display
|
||||
String Gdb_MI2::CollectVariablesShort(MIValue &val)
|
||||
{
|
||||
String s;
|
||||
|
||||
CollectShort0(val, s);
|
||||
if(s == "")
|
||||
s = "<can't evaluate>";
|
||||
else if(s.EndsWith(" , "))
|
||||
s = s.Left(s.GetCount()-3);
|
||||
return s;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,33 @@ bool MIValue::expect(String const &where, char exp, int i, String const &s)
|
|||
static char backslash(String const &s, int &i)
|
||||
{
|
||||
i++;
|
||||
char c;
|
||||
if(IsDigit(s[i]))
|
||||
{
|
||||
c = (s[i]-'0')*64 + (s[i+1]-'0')*8 + s[i+2]-'0';
|
||||
char c = (s[i]-'0')*64 + (s[i+1]-'0')*8 + s[i+2]-'0';
|
||||
i += 2;
|
||||
return c;
|
||||
}
|
||||
|
||||
// control chars and octals
|
||||
switch(s[i])
|
||||
{
|
||||
case 'a' :
|
||||
return '\a';
|
||||
case 'b' :
|
||||
return '\b';
|
||||
case 'f' :
|
||||
return '\f';
|
||||
case 'n' :
|
||||
return '\n';
|
||||
case 'r' :
|
||||
return '\r';
|
||||
case 't' :
|
||||
return '\t';
|
||||
case 'v' :
|
||||
return '\v';
|
||||
default:
|
||||
return s[i];
|
||||
}
|
||||
else
|
||||
c = s[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -58,11 +76,18 @@ int MIValue::ParsePair(String &name, MIValue &val, String const &s, int i)
|
|||
|
||||
// is starting wirh '[' or '{' take it as a value with empty name
|
||||
if(s[i] == '{' || s[i] == '[')
|
||||
{
|
||||
/*
|
||||
RLOG("STICAZZI....");
|
||||
RLOG("i = " << i << " s = " << s);
|
||||
*/
|
||||
name = "<UNNAMED>";
|
||||
return val.ParseTuple(s, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int aCount = 0;
|
||||
while(s[i] && ((s[i] != '=' && s[i] != '}' && s[i] != ']') || aCount))
|
||||
while(s[i] && ((s[i] != '=' && s[i] != '}' && s[i] != ']' && s[i] != ',') || aCount))
|
||||
{
|
||||
if(s[i] == '<')
|
||||
aCount++;
|
||||
|
|
@ -97,6 +122,18 @@ int MIValue::ParsePair(String &name, MIValue &val, String const &s, int i)
|
|||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
}
|
||||
|
||||
// skip address part, if any... it's useless and confuses the parser
|
||||
if(s[i] == '@')
|
||||
{
|
||||
while(s[i] && s[i] != ':')
|
||||
i++;
|
||||
if(s[i] == ':')
|
||||
i++;
|
||||
while(s[i] && IsSpace(s[i]))
|
||||
i++;
|
||||
}
|
||||
|
||||
switch(s[i])
|
||||
{
|
||||
case '"':
|
||||
|
|
@ -271,6 +308,7 @@ int MIValue::ParseUnquotedString(String const &s, int i)
|
|||
String valStr;
|
||||
int aCount = 0;
|
||||
bool inQuote = false;
|
||||
|
||||
while(s[i] && ((s[i] != '=' && s[i] != '}' && s[i] != ']' && !comma(s, i)) || inQuote || aCount))
|
||||
{
|
||||
valStr.Cat(s[i]);
|
||||
|
|
@ -533,13 +571,28 @@ void MIValue::Set(String const &s)
|
|||
#define MARK_ARRAY ""
|
||||
#define MARK_TUPLE ""
|
||||
#endif
|
||||
|
||||
// dumps a string with special chars inside
|
||||
String MIValue::Dump(String const &s)
|
||||
{
|
||||
String res;
|
||||
for(int i = 0; i < s.GetCharCount(); i++)
|
||||
{
|
||||
byte c = s[i];
|
||||
if(isprint(c))
|
||||
res << c;
|
||||
else
|
||||
res += Format("\\%03o", c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
String MIValue::Dump(int level) const
|
||||
{
|
||||
String spacer(' ', level);
|
||||
switch(type)
|
||||
{
|
||||
case MIString:
|
||||
return spacer + MARK_STRING + string;
|
||||
return spacer + MARK_STRING + Dump(string);
|
||||
|
||||
case MITuple:
|
||||
{
|
||||
|
|
@ -639,6 +692,35 @@ void MIValue::PackNames(void)
|
|||
}
|
||||
}
|
||||
|
||||
// fix arrays -- i.e. replace a tuple containing ALL unnamed elements
|
||||
// with the corresponding array
|
||||
// ( gdb evaluator array data is returned as tuple with {} instead []=
|
||||
void MIValue::FixArrays(void)
|
||||
{
|
||||
|
||||
bool named = false;
|
||||
if(IsTuple())
|
||||
{
|
||||
for(int iVal = 0; iVal < tuple.GetCount(); iVal++)
|
||||
if(tuple.GetKey(iVal) != "<UNNAMED>")
|
||||
{
|
||||
named = true;
|
||||
break;
|
||||
}
|
||||
if(!named)
|
||||
{
|
||||
array.Clear();
|
||||
for(int iVal = 0; iVal < tuple.GetCount(); iVal++)
|
||||
array.Add(tuple[iVal]);
|
||||
tuple.Clear();
|
||||
type = MIArray;
|
||||
}
|
||||
}
|
||||
if(IsTuple() || IsArray())
|
||||
for(int i = 0; i < GetCount(); i++)
|
||||
Get(i).FixArrays();
|
||||
}
|
||||
|
||||
// add an item to a tuple
|
||||
MIValue &MIValue::Add(String const &key, MIValue pick_ &v)
|
||||
{
|
||||
|
|
@ -699,3 +781,12 @@ MIValue &MIValue::Add(String const &data)
|
|||
v.Set(data);
|
||||
return Add(v);
|
||||
}
|
||||
|
||||
// remove a tuple key
|
||||
MIValue &MIValue::Remove(String const &key)
|
||||
{
|
||||
if(type != MITuple)
|
||||
return *this;
|
||||
tuple.RemoveKey(key);
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ class MIValue : public Moveable<MIValue>
|
|||
bool IsString(void) const { return type == MIString; }
|
||||
void AssertString(void) const { ASSERT(type == MIString); }
|
||||
|
||||
// dumps a string with special chars inside
|
||||
static String Dump(String const &s);
|
||||
|
||||
// data dump
|
||||
String Dump(int level = 0) const;
|
||||
|
||||
|
|
@ -97,6 +100,10 @@ class MIValue : public Moveable<MIValue>
|
|||
// packs names inside tuples -- to make type recognition easy
|
||||
void PackNames(void);
|
||||
|
||||
// fix arrays -- i.e. replace a tuple containing ALL unnamed elements
|
||||
// with the corresponding array
|
||||
void FixArrays(void);
|
||||
|
||||
// add some data to a value
|
||||
|
||||
// add an item to a tuple
|
||||
|
|
@ -107,6 +114,9 @@ class MIValue : public Moveable<MIValue>
|
|||
// add an item to an array
|
||||
MIValue &Add(MIValue pick_ &v);
|
||||
MIValue &Add(String const &data);
|
||||
|
||||
// remove a tuple key
|
||||
MIValue &Remove(String const &key);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,3 +21,25 @@ TYPE_SIMPLIFIER_HANDLER GetSimplifier(String const &pattern)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// next index when stepping through containers values
|
||||
int SIMPLIFIER_NEXT_INDEX(MIValue &val, int total)
|
||||
{
|
||||
int step;
|
||||
|
||||
int idx = val.Find(SIMPLIFY_STEP);
|
||||
if(idx < 0)
|
||||
{
|
||||
step = 0;
|
||||
val.Add(SIMPLIFY_STEP, "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
step = atoi(val[SIMPLIFY_STEP].ToString()) + 1;
|
||||
if(step >= total)
|
||||
val.Remove(SIMPLIFY_STEP);
|
||||
else
|
||||
val[SIMPLIFY_STEP].Set(FormatInt(step));
|
||||
}
|
||||
return step;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@
|
|||
|
||||
#define SIMPLIFY_EXPR "<!EXPR>"
|
||||
#define SIMPLIFY_VALUE "<!VALUE>"
|
||||
#define SIMPLIFY_TEMPVAL "<!TEMPVAL>"
|
||||
#define SIMPLIFY_HINT "<!HINT>"
|
||||
#define SIMPLIFY_START "<!START>"
|
||||
#define SIMPLIFY_COUNT "<!COUNT>"
|
||||
|
||||
#define SIMPLIFY_STEP "<!STEP>"
|
||||
#define SIMPLIFY_STEPVAL "<!STEPVAL>"
|
||||
|
||||
|
||||
#define SIMPLIFY_SIMPLE "<!SIMPLE>"
|
||||
#define SIMPLIFY_ARRAY "<!ARRAY>"
|
||||
#define SIMPLIFY_MAP "<!MAP>"
|
||||
|
|
@ -18,12 +23,15 @@
|
|||
// parameters:
|
||||
// gdb handler to debugger object -- used mostly to inspect deeper
|
||||
// expRoot gdb evaluable expression of 'val' expression root. The one used to get the 'val'.
|
||||
typedef bool (*TYPE_SIMPLIFIER_HANDLER)(Gdb_MI2 &gdb, MIValue &val);
|
||||
typedef bool (*TYPE_SIMPLIFIER_HANDLER)(Gdb_MI2 &gdb, MIValue &val, bool deep);
|
||||
|
||||
void RegisterSimplifier(const char *pattern, TYPE_SIMPLIFIER_HANDLER handler);
|
||||
|
||||
TYPE_SIMPLIFIER_HANDLER GetSimplifier(String const &pattern);
|
||||
|
||||
// next index when stepping through containers values
|
||||
int SIMPLIFIER_NEXT_INDEX(MIValue &val, int total);
|
||||
|
||||
#define REGISTERSIMPLIFIER(pattern, handler) \
|
||||
INITBLOCK { \
|
||||
RegisterSimplifier(pattern, handler); \
|
||||
|
|
|
|||
|
|
@ -1,7 +1,26 @@
|
|||
#include "TypeSimplify.h"
|
||||
|
||||
static bool UppStringSimplify(Gdb_MI2 &gdb, MIValue &val)
|
||||
#define EVALDEEP
|
||||
#define EVALDEEP_VECTOR 5
|
||||
#define EVALDEEP_ARRAY 5
|
||||
#define EVALDEEP_VECTORMAP 5
|
||||
#define EVALDEEP_ARRAYMAP 5
|
||||
#define EVALDEEP_INDEX 5
|
||||
|
||||
#define SLEN 15
|
||||
#define LLEN 2
|
||||
static bool UppStringSimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
union
|
||||
{
|
||||
char chr[16];
|
||||
char *ptr;
|
||||
dword *wptr;
|
||||
qword *qptr;
|
||||
word v[8];
|
||||
dword w[4];
|
||||
qword q[2];
|
||||
} u;
|
||||
|
||||
// strings are "easy", in debug mode 's' and 'len' members are provided
|
||||
// so we shall just look at them in tuple
|
||||
|
|
@ -13,20 +32,25 @@ static bool UppStringSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
|
||||
if(!v.IsTuple() || !unn.IsTuple())
|
||||
return false;
|
||||
|
||||
if(unn.Find("chr") < 0)
|
||||
return false;
|
||||
String chr = unn["chr"][SIMPLIFY_VALUE];
|
||||
bool isSmall = (chr[14] == 0);
|
||||
String chrs = unn["chr"][SIMPLIFY_VALUE];
|
||||
memcpy(u.chr, ~chrs, 16);
|
||||
|
||||
bool isSmall = (u.chr[14] == 0);
|
||||
String s;
|
||||
if(isSmall)
|
||||
s = chr;
|
||||
{
|
||||
byte len = u.chr[SLEN];
|
||||
s = chrs.Left(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(unn.Find("ptr") < 0)
|
||||
return false;
|
||||
s = unn["ptr"][SIMPLIFY_VALUE];
|
||||
|
||||
dword len = u.w[LLEN];
|
||||
s = unn["ptr"][SIMPLIFY_VALUE].ToString();
|
||||
|
||||
// strip address...
|
||||
int i = s.Find('"');
|
||||
if(i >= 0)
|
||||
|
|
@ -34,10 +58,13 @@ static bool UppStringSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
s = s.Mid(i+1);
|
||||
s = s.Left(s.GetCount()-1);
|
||||
}
|
||||
s = s.Left(len);
|
||||
}
|
||||
val[SIMPLIFY_VALUE].Set("\"" + s + "\"");
|
||||
val.FindAdd(SIMPLIFY_HINT, SIMPLIFY_SIMPLE);
|
||||
return true;
|
||||
|
||||
// no need for further evaluation on this object
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
@ -45,9 +72,13 @@ static bool UppStringSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
}
|
||||
}
|
||||
|
||||
static bool UppVectorSimplify(Gdb_MI2 &gdb, MIValue &val)
|
||||
static bool UppVectorSimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
//RLOG(val.Dump());
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!deep)
|
||||
return true;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
MIValue &v = val[SIMPLIFY_VALUE];
|
||||
|
|
@ -61,31 +92,40 @@ static bool UppVectorSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
// display max 5 elements of array, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// otherwise display {...} string
|
||||
// to do this, we shall ask gdb to evaluate the undelying vector
|
||||
int count = min(5, items);
|
||||
String vals = "";
|
||||
for(int i = 0; i < count; i++)
|
||||
String vals;
|
||||
int count = min(EVALDEEP_VECTOR, items);
|
||||
//RLOG("COUNT : " << count);
|
||||
#ifdef EVALDEEP
|
||||
if(count)
|
||||
{
|
||||
MIValue vi = gdb.Evaluate(vectorExpr + Format("[%d]", i));
|
||||
if(vi.IsError())
|
||||
vals = ": [ ... ]";
|
||||
String expr = vectorExpr + Format("[0]@%d", count);
|
||||
MIValue vi = gdb.Evaluate(expr);
|
||||
//RLOG(vi.Dump());
|
||||
if(vi.IsArray() && vi.GetCount() && vi[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
vals = "can't evaluate";
|
||||
break;
|
||||
vals = ": [ ";
|
||||
for(int i = 0; i < vi.GetCount(); i++)
|
||||
vals = vals + vi[i][SIMPLIFY_VALUE].ToString() + " , ";
|
||||
if(count < items)
|
||||
vals << "... ]";
|
||||
else
|
||||
vals = vals.Left(vals.GetCount() - 2) + "]";
|
||||
}
|
||||
if(!vi.IsString())
|
||||
{
|
||||
vals = "{...}";
|
||||
break;
|
||||
}
|
||||
vals = vals + ", " + vi.ToString();
|
||||
}
|
||||
if(vals.StartsWith(", "))
|
||||
vals = vals.Mid(2);
|
||||
vals = Format("Upp::Vector with %d elements : %s", items, vals);
|
||||
//RLOG("VALS = " << vals);
|
||||
#else
|
||||
if(count)
|
||||
vals = ": [ ... ]";
|
||||
#endif
|
||||
vals = Format("Upp::Vector with %d elements %s", items, vals);
|
||||
val[SIMPLIFY_VALUE].Set(vals);
|
||||
|
||||
//RLOG(v.Dump());
|
||||
// signal we've done a deep evaluation
|
||||
#ifdef EVALDEEP
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
@ -93,9 +133,14 @@ static bool UppVectorSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
}
|
||||
}
|
||||
|
||||
static bool UppVectorMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
||||
static bool UppVectorMapSimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
//RLOG(val.Dump());
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!deep)
|
||||
return true;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
MIValue &v = val[SIMPLIFY_VALUE];
|
||||
|
|
@ -112,51 +157,47 @@ static bool UppVectorMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
val.FindAdd(SIMPLIFY_COUNT, FormatInt(items));
|
||||
|
||||
|
||||
// display max 3 elements of map, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// display max 5 elements of map, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// otherwise display {...} string
|
||||
// to do this, we shall ask gdb to evaluate the undelying vector
|
||||
int count = min(3, items);
|
||||
String vals = "";
|
||||
bool err = false;
|
||||
bool complex = false;
|
||||
for(int i = 0; i < count; i++)
|
||||
String vals;
|
||||
int count = min(EVALDEEP_VECTORMAP, items);
|
||||
#ifdef EVALDEEP
|
||||
if(count)
|
||||
{
|
||||
MIValue vk = gdb.Evaluate(keyExpr + Format("[%d]", i));
|
||||
if(vk.IsError())
|
||||
vals = ": { ... }";
|
||||
String kExpr = keyExpr + Format("[0]@%d", count);
|
||||
MIValue viKey = gdb.Evaluate(kExpr);
|
||||
if(viKey.IsArray() && viKey[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
err = true;
|
||||
break;
|
||||
String vExpr = valExpr + Format("[0]@%d", count);
|
||||
MIValue viVal = gdb.Evaluate(vExpr);
|
||||
if(viVal.IsArray() && viVal[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
vals = ": { ";
|
||||
for(int i = 0; i < viKey.GetCount(); i++)
|
||||
vals << "( " << viKey[i][SIMPLIFY_VALUE].ToString() << " , " << viVal[i][SIMPLIFY_VALUE].ToString() << " ) , ";
|
||||
if(count < items)
|
||||
vals << "... }";
|
||||
else
|
||||
vals = vals.Left(vals.GetCount() - 2) + "}";
|
||||
}
|
||||
//RLOG(vals);
|
||||
}
|
||||
if(!vk.IsString())
|
||||
{
|
||||
complex = true;
|
||||
break;
|
||||
}
|
||||
MIValue vv = gdb.Evaluate(valExpr + Format("[%d]", i));
|
||||
if(vv.IsError())
|
||||
{
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
if(!vv.IsString())
|
||||
{
|
||||
complex = true;
|
||||
break;
|
||||
}
|
||||
vals = vals + ", (" + vk.ToString() + "," + vv.ToString() + ")";
|
||||
}
|
||||
|
||||
if(complex)
|
||||
vals = "{...}";
|
||||
else if(err)
|
||||
vals = "can't evaluate";
|
||||
if(vals.StartsWith(", "))
|
||||
vals = vals.Mid(2);
|
||||
vals = Format("Upp::VectorMap with %d elements : %s", items, vals);
|
||||
//RLOG("VALS = " << vals);
|
||||
#else
|
||||
if(count)
|
||||
vals = ": { ... }";
|
||||
#endif
|
||||
vals = Format("Upp::VectorMap with %d elements %s", items, vals);
|
||||
val[SIMPLIFY_VALUE].Set(vals);
|
||||
return true;
|
||||
|
||||
// signal we've done a deep evaluation
|
||||
#ifdef EVALDEEP
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
@ -165,9 +206,14 @@ static bool UppVectorMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
}
|
||||
|
||||
|
||||
static bool UppArraySimplify(Gdb_MI2 &gdb, MIValue &val)
|
||||
static bool UppArraySimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
//RLOG(val.Dump());
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!deep)
|
||||
return true;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
MIValue &v = val[SIMPLIFY_VALUE]["vector"][SIMPLIFY_VALUE];
|
||||
|
|
@ -182,31 +228,46 @@ static bool UppArraySimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
// display max 5 elements of array, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// otherwise display {...} string
|
||||
// to do this, we shall ask gdb to evaluate the undelying vector
|
||||
int count = min(5, items);
|
||||
String vals = "";
|
||||
for(int i = 0; i < count; i++)
|
||||
String vals;
|
||||
int count = min(EVALDEEP_ARRAY, items);
|
||||
#ifdef EVALDEEP
|
||||
if(count)
|
||||
{
|
||||
MIValue vi = gdb.Evaluate(vectorExpr + Format("[%d][0]", i));
|
||||
if(vi.IsError())
|
||||
// pre-fetch main array variable to speedup element request
|
||||
gdb.MICmd("gdb-set variable $thearray=" + vectorExpr);
|
||||
|
||||
// get array elements
|
||||
vals = ": [ ... ]";
|
||||
String expr = "{";
|
||||
for(int i = 0; i < count; i++)
|
||||
expr << Format("$thearray[%d][0]", i) << ",";
|
||||
expr = expr.Left(expr.GetCount()-1) + "}";
|
||||
MIValue vi = gdb.Evaluate(expr);
|
||||
|
||||
if(vi.IsArray() && vi.GetCount() && vi[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
vals = "can't evaluate";
|
||||
break;
|
||||
vals = ": [ ";
|
||||
for(int i = 0; i < vi.GetCount(); i++)
|
||||
vals = vals + vi[i][SIMPLIFY_VALUE].ToString() + " , ";
|
||||
if(count < items)
|
||||
vals << "... ]";
|
||||
else
|
||||
vals = vals.Left(vals.GetCount() - 2) + "]";
|
||||
}
|
||||
if(!vi.IsString())
|
||||
{
|
||||
vals = "{...}";
|
||||
break;
|
||||
}
|
||||
vals = vals + ", " + vi.ToString();
|
||||
}
|
||||
if(vals.StartsWith(", "))
|
||||
vals = vals.Mid(2);
|
||||
vals = Format("Upp::Array with %d elements : %s", items, vals);
|
||||
//RLOG("VALS = " << vals);
|
||||
#else
|
||||
if(count)
|
||||
vals = ": [ ... ]";
|
||||
#endif
|
||||
vals = Format("Upp::Array with %d elements %s", items, vals);
|
||||
val[SIMPLIFY_VALUE].Set(vals);
|
||||
|
||||
//RLOG(v.Dump());
|
||||
// signal we've done a deep evaluation
|
||||
#ifdef EVALDEEP
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
@ -214,9 +275,14 @@ static bool UppArraySimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
}
|
||||
}
|
||||
|
||||
static bool UppArrayMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
||||
static bool UppArrayMapSimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
//RLOG(val.Dump());
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!deep)
|
||||
return true;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
MIValue &v = val[SIMPLIFY_VALUE];
|
||||
|
|
@ -236,49 +302,51 @@ static bool UppArrayMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
// display max 3 elements of map, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// otherwise display {...} string
|
||||
// to do this, we shall ask gdb to evaluate the undelying vector
|
||||
int count = min(3, items);
|
||||
String vals = "";
|
||||
bool err = false;
|
||||
bool complex = false;
|
||||
for(int i = 0; i < count; i++)
|
||||
String vals;
|
||||
int count = min(EVALDEEP_ARRAYMAP, items);
|
||||
#ifdef EVALDEEP
|
||||
if(count)
|
||||
{
|
||||
MIValue vk = gdb.Evaluate(keyExpr + Format("[%d]", i));
|
||||
if(vk.IsError())
|
||||
// pre-fetch main array variable to speedup element request
|
||||
gdb.MICmd("gdb-set variable $thearray=" + valExpr);
|
||||
|
||||
vals = ": { ... }";
|
||||
String kExpr = keyExpr + Format("[0]@%d", count);
|
||||
MIValue viKey = gdb.Evaluate(kExpr);
|
||||
if(viKey.IsArray() && viKey[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
err = true;
|
||||
break;
|
||||
String vExpr = "{";
|
||||
for(int i = 0; i < count; i++)
|
||||
vExpr << Format("$thearray[%d][0]", i) << ",";
|
||||
vExpr = vExpr.Left(vExpr.GetCount()-1) + "}";
|
||||
MIValue viVal = gdb.Evaluate(vExpr);
|
||||
|
||||
if(viVal.IsArray() && viVal[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
vals = ": { ";
|
||||
for(int i = 0; i < viKey.GetCount(); i++)
|
||||
vals << "( " << viKey[i][SIMPLIFY_VALUE].ToString() << " , " << viVal[i][SIMPLIFY_VALUE].ToString() << " ) , ";
|
||||
if(count < items)
|
||||
vals << "... }";
|
||||
else
|
||||
vals = vals.Left(vals.GetCount() - 2) + "}";
|
||||
}
|
||||
//RLOG(vals);
|
||||
}
|
||||
if(!vk.IsString())
|
||||
{
|
||||
complex = true;
|
||||
break;
|
||||
}
|
||||
MIValue vv = gdb.Evaluate(valExpr + Format("[%d][0]", i));
|
||||
if(vv.IsError())
|
||||
{
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
if(!vv.IsString())
|
||||
{
|
||||
complex = true;
|
||||
break;
|
||||
}
|
||||
vals = vals + ", (" + vk.ToString() + "," + vv.ToString() + ")";
|
||||
}
|
||||
|
||||
if(complex)
|
||||
vals = "{...}";
|
||||
else if(err)
|
||||
vals = "can't evaluate";
|
||||
if(vals.StartsWith(", "))
|
||||
vals = vals.Mid(2);
|
||||
vals = Format("Upp::ArrayMap with %d elements : %s", items, vals);
|
||||
//RLOG("VALS = " << vals);
|
||||
#else
|
||||
if(count)
|
||||
vals = ": { ... }";
|
||||
#endif
|
||||
vals = Format("Upp::ArrayMap with %d elements %s", items, vals);
|
||||
val[SIMPLIFY_VALUE].Set(vals);
|
||||
|
||||
// signal we've done a deep evaluation
|
||||
#ifdef EVALDEEP
|
||||
return true;
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
@ -286,6 +354,65 @@ static bool UppArrayMapSimplify(Gdb_MI2 &gdb, MIValue &val)
|
|||
}
|
||||
}
|
||||
|
||||
static bool UppIndexSimplify(Gdb_MI2 &gdb, MIValue &val, bool deep)
|
||||
{
|
||||
//RLOG(val.Dump());
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!deep)
|
||||
return true;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
MIValue &keyExpr = val[SIMPLIFY_VALUE][1][SIMPLIFY_VALUE]["key"][SIMPLIFY_VALUE];
|
||||
String vectorExpr = keyExpr["vector"][SIMPLIFY_EXPR];
|
||||
int items = atoi(keyExpr["items"][SIMPLIFY_VALUE].ToString());
|
||||
|
||||
val.FindAdd(SIMPLIFY_HINT, SIMPLIFY_ARRAY);
|
||||
val.FindAdd(SIMPLIFY_START, "0");
|
||||
val.FindAdd(SIMPLIFY_COUNT, FormatInt(items));
|
||||
|
||||
// display max 5 elements of array, starting from 0 and ONLY if elements evaluate to a simple type
|
||||
// otherwise display {...} string
|
||||
// to do this, we shall ask gdb to evaluate the undelying vector
|
||||
String vals;
|
||||
int count = min(EVALDEEP_INDEX, items);
|
||||
#ifdef EVALDEEP
|
||||
if(count)
|
||||
{
|
||||
vals = ": [ ... ]";
|
||||
String expr = vectorExpr << Format("[0]@%d", count);
|
||||
MIValue vi = gdb.Evaluate(expr);
|
||||
if(vi.IsArray() && vi.GetCount() && vi[0][SIMPLIFY_VALUE].IsString())
|
||||
{
|
||||
vals = ": [ ";
|
||||
for(int i = 0; i < vi.GetCount(); i++)
|
||||
vals = vals + vi[i][SIMPLIFY_VALUE].ToString() + " , ";
|
||||
if(count < items)
|
||||
vals << "... ]";
|
||||
else
|
||||
vals = vals.Left(vals.GetCount() - 2) + "]";
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(count)
|
||||
vals = ": [ ... ]";
|
||||
#endif
|
||||
vals = Format("Upp::Index with %d elements %s", items, vals);
|
||||
val[SIMPLIFY_VALUE].Set(vals);
|
||||
|
||||
// signal we've done a deep evaluation
|
||||
#ifdef EVALDEEP
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Register the simplifiers
|
||||
REGISTERSIMPLIFIER("<Upp::Moveable<Upp::String,Upp::AString<Upp::String0>>>" , UppStringSimplify);
|
||||
|
|
@ -293,5 +420,5 @@ REGISTERSIMPLIFIER("<Upp::MoveableAndDeepCopyOption<Upp::Vector<" , UppVecto
|
|||
REGISTERSIMPLIFIER("<Upp::MoveableAndDeepCopyOption<Upp::VectorMap<" , UppVectorMapSimplify);
|
||||
REGISTERSIMPLIFIER("<Upp::MoveableAndDeepCopyOption<Upp::Array<" , UppArraySimplify);
|
||||
REGISTERSIMPLIFIER("<Upp::MoveableAndDeepCopyOption<Upp::ArrayMap<" , UppArrayMapSimplify);
|
||||
|
||||
REGISTERSIMPLIFIER("<Upp::MoveableAndDeepCopyOption<Upp::Index<" , UppIndexSimplify);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue