Ide/Debuggers/Gdb_MI2 : refactoring

git-svn-id: svn://ultimatepp.org/upp/trunk@6928 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
micio 2014-02-19 10:33:22 +00:00
parent fa9b75e082
commit 5034466cda
8 changed files with 840 additions and 302 deletions

View file

@ -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");

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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); \

View file

@ -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);