mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-09-10 03:54:54 -06:00
Ide: GDB_MI2 removed from TheIDE.
git-svn-id: svn://ultimatepp.org/upp/trunk@12119 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
1e0574c5d3
commit
0581d4b38f
19 changed files with 7 additions and 4795 deletions
|
|
@ -174,7 +174,7 @@ void Sentinel(Stream& s, const char *txt)
|
|||
|
||||
void Ide::Serialize(Stream& s)
|
||||
{
|
||||
int version = 13;
|
||||
int version = 14;
|
||||
Sentinel(s, "before 12341234");
|
||||
s.Magic(0x12341234);
|
||||
Sentinel(s, "after magic");
|
||||
|
|
@ -261,7 +261,10 @@ void Ide::Serialize(Stream& s)
|
|||
s % hydra1_threads;
|
||||
if(s.IsLoading())
|
||||
console.SetSlots(hydra1_threads);
|
||||
s % gdbSelector;
|
||||
if(version < 14) {
|
||||
int dummy_gdb_selector;
|
||||
s % dummy_gdb_selector;
|
||||
}
|
||||
s % doc;
|
||||
s % chstyle;
|
||||
s % astyle_BracketIndent;
|
||||
|
|
|
|||
|
|
@ -297,10 +297,7 @@ void Ide::BuildAndDebug(bool runto)
|
|||
bool console = ShouldHaveConsole();
|
||||
|
||||
if(findarg(builder, "GCC", "CLANG") >= 0) {
|
||||
if(gdbSelector)
|
||||
debugger = Gdb_MI2Create(pick(host), target, runarg, console);
|
||||
else
|
||||
debugger = GdbCreate(pick(host), target, runarg, console);
|
||||
debugger = GdbCreate(pick(host), target, runarg, console);
|
||||
}
|
||||
#ifdef PLATFORM_WIN32
|
||||
else
|
||||
|
|
|
|||
|
|
@ -240,8 +240,6 @@ private:
|
|||
One<IGdbUtils> gdb_utils;
|
||||
};
|
||||
|
||||
#include "Gdb_MI2.h"
|
||||
|
||||
#define KEYGROUPNAME "Debugger"
|
||||
#define KEYNAMESPACE PdbKeys
|
||||
#define KEYFILE <ide/Debuggers/Pdb.key>
|
||||
|
|
@ -251,6 +249,4 @@ private:
|
|||
#include "Pdb.h"
|
||||
#endif
|
||||
|
||||
INITIALIZE(UppSimplifiers)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,19 +20,6 @@ file
|
|||
Gdb.cpp,
|
||||
GdbUtils.h,
|
||||
GdbUtils.cpp,
|
||||
GDB_MI2 readonly separator,
|
||||
MIValue.h,
|
||||
MIValue.cpp,
|
||||
VarItem.h,
|
||||
VarItem.cpp,
|
||||
TypeSimplify.h,
|
||||
TypeSimplify.cpp,
|
||||
Gdb_MI2.lay,
|
||||
Gdb_MI2.h,
|
||||
Gdb_MI2Explore.cpp,
|
||||
Gdb_MI2Gdb.cpp,
|
||||
Gdb_MI2.cpp,
|
||||
UppSimplifiers.cpp,
|
||||
PDB readonly separator,
|
||||
Pdb.h,
|
||||
cvconst.h,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,329 +0,0 @@
|
|||
#ifndef _ide_Debuggers_Gdb_MI2_h_
|
||||
#define _ide_Debuggers_Gdb_MI2_h_
|
||||
|
||||
#include "MIValue.h"
|
||||
#include "VarItem.h"
|
||||
|
||||
class WatchEdit : public LineEdit
|
||||
{
|
||||
virtual void HighlightLine(int line, Vector<Highlight>& h, int pos);
|
||||
};
|
||||
|
||||
#define LAYOUTFILE <ide/Debuggers/Gdb_MI2.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
// abort command exception - used to stop non-main threads
|
||||
struct BreakExc : public Exc
|
||||
{
|
||||
BreakExc() : Exc("break") {}
|
||||
|
||||
};
|
||||
|
||||
class Gdb_MI2 : public Debugger, public ParentCtrl
|
||||
{
|
||||
friend class VarItem;
|
||||
private:
|
||||
|
||||
// list of processes (and connected thread groups)
|
||||
// used to stop them
|
||||
VectorMap<String, int> processes;
|
||||
|
||||
// list of debug variables created and thread-safe functions to
|
||||
// manage them -- used to clean up
|
||||
Vector<String>debugVariables;
|
||||
#ifdef flagMT
|
||||
Vector<String>prevDebugVariables;
|
||||
#endif
|
||||
Mutex varMutex;
|
||||
void StoreVariable(String const &name);
|
||||
void CleanupVariables(void);
|
||||
|
||||
// multithread support
|
||||
#ifdef flagMT
|
||||
// numbr of running debug threads
|
||||
int threadRunning;
|
||||
|
||||
// flag to signal threads to stop
|
||||
bool stopThread;
|
||||
|
||||
// mutex and thead object
|
||||
Mutex mutex;
|
||||
Thread debugThread;
|
||||
|
||||
// mutex-protected functions
|
||||
bool IsThreadRunning(void);
|
||||
void IncThreadRunning();
|
||||
void DecThreadRunning();
|
||||
|
||||
public:
|
||||
bool IsStopThread(void);
|
||||
private:
|
||||
void SetStopThread(bool b);
|
||||
|
||||
// shut down threads and wait till done
|
||||
void ShutDownThreads(void);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
// debug break support -- ONLY POSIX, by now
|
||||
bool InterruptDebugger(void);
|
||||
#endif
|
||||
|
||||
// current command break support -- ONLY POSIX, by now
|
||||
// used to speed up operations in MT mode
|
||||
bool InterruptCommand(void);
|
||||
|
||||
// used to post and kill timed callbacks
|
||||
TimeCallback timeCallback;
|
||||
TimeCallback exploreCallback;
|
||||
|
||||
One<Host> host;
|
||||
One<AProcess> dbg;
|
||||
|
||||
bool firstRun;
|
||||
|
||||
// the disassembler window
|
||||
DbgDisas disas;
|
||||
|
||||
// the registers pane
|
||||
#ifdef CPU_64
|
||||
FrameBottom<WithGdb_MI2Registers64Layout<StaticRect> > regs;
|
||||
#define RPREFIX "r"
|
||||
#else
|
||||
FrameBottom<WithGdb_MI2RegistersLayout<StaticRect> > regs;
|
||||
#define RPREFIX "e"
|
||||
#endif
|
||||
|
||||
// the quick watch dialog
|
||||
WithGdb_MI2QuickwatchLayout<TopWindow> quickwatch;
|
||||
|
||||
EditString watchedit;
|
||||
DropList frame;
|
||||
DropList threadSelector;
|
||||
TabCtrl tab;
|
||||
|
||||
ArrayCtrl autos;
|
||||
ArrayCtrl locals;
|
||||
ArrayCtrl members;
|
||||
ArrayCtrl watches;
|
||||
ArrayCtrl explorer;
|
||||
|
||||
// explorer stuffs -- just starting
|
||||
EditString explorerExprEdit;
|
||||
Button explorerBackBtn, explorerForwardBtn;
|
||||
StaticRect explorerPane;
|
||||
void onExploreExpr(ArrayCtrl *what = NULL);
|
||||
void onExplorerChild();
|
||||
void onExplorerBack();
|
||||
void onExplorerForward();
|
||||
void ExplorerMenu(Bar& bar);
|
||||
|
||||
void doExplore(String const &expr, bool appendHistory);
|
||||
|
||||
// explorer expressions and values
|
||||
Index<String>explorerExpressions;
|
||||
Vector<String>explorerValues;
|
||||
Index<String> explorerHistoryExpressions;
|
||||
int explorerHistoryPos;
|
||||
|
||||
Label dlock;
|
||||
|
||||
Vector<String> regname;
|
||||
Vector<Label *> reglbl;
|
||||
void AddReg(const char *reg, Label *lbl) { regname.Add(reg); reglbl.Add(lbl); }
|
||||
|
||||
// find free space at right of tabs (we should probably add something to TabCtrl for that..)
|
||||
int FindTabsRight(void);
|
||||
|
||||
// running flags -- setup by ReadGdb function when async input is catched
|
||||
bool started;
|
||||
bool stopped;
|
||||
MIValue stopReason;
|
||||
|
||||
// read debugger output analyzing command responses
|
||||
// and async output
|
||||
MIValue ParseGdb(String const &s, bool wait = true);
|
||||
MIValue ReadGdb(bool wait = true);
|
||||
|
||||
// format breakpoint line from ide file and line
|
||||
String BreakPos(String const &file, int line);
|
||||
|
||||
// get breakpoints info
|
||||
MIValue GetBreakpoints(void);
|
||||
MIValue GetBreakpoint(int id);
|
||||
MIValue GetBreakPoint(const char *file, int line);
|
||||
|
||||
// try to set a breakpoint - returns false if no code there
|
||||
bool TryBreak(adr_t addr, bool temp);
|
||||
bool TryBreak(String const &file, int line, bool temp);
|
||||
|
||||
// set breakpoint
|
||||
MIValue InsertBreakpoint(const char *file, int line);
|
||||
|
||||
// stored local variable expressions, and values
|
||||
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
|
||||
Index<String>thisExpressions;
|
||||
Vector<String>thisValues;
|
||||
Vector<int>thisHints;
|
||||
Index<String>thisShortExpressions;
|
||||
|
||||
// stored autos expressions, values and types
|
||||
String autoLine;
|
||||
|
||||
// logs frame data on console
|
||||
void LogFrame(String const &msg, MIValue &frame);
|
||||
|
||||
// check for stop reason
|
||||
void CheckStopReason(void);
|
||||
|
||||
// stop all running threads and re-select previous current thread
|
||||
void StopAllThreads(void);
|
||||
|
||||
// single step command handler
|
||||
void Step(const char *cmd);
|
||||
|
||||
// run to command for menu -- just removes return value
|
||||
void doRunTo(void) { RunTo(); }
|
||||
|
||||
// setup ide cursor based on disassembler one
|
||||
void DisasCursor();
|
||||
|
||||
// reset ide default cursor image when disassembler loose focus
|
||||
void DisasFocus();
|
||||
|
||||
// sync disassembler pane
|
||||
void SyncDisas(MIValue &fInfo, bool fr);
|
||||
|
||||
// sync auto vars treectrl
|
||||
void SyncAutos();
|
||||
|
||||
#ifdef flagMT
|
||||
// sync local variables pane
|
||||
void SyncLocals(void);
|
||||
|
||||
// Sync 'this' inspector data
|
||||
void SyncThis(void);
|
||||
|
||||
// sync watches treectrl
|
||||
void SyncWatches(void);
|
||||
|
||||
// sync explorer pane
|
||||
void SyncExplorer();
|
||||
#else
|
||||
// sync local variables pane
|
||||
void SyncLocals(const Vector<VarItem>& localVars = Vector<VarItem>());
|
||||
|
||||
// Sync 'this' inspector data
|
||||
void SyncThis(const Vector<VarItem>& children = Vector<VarItem>());
|
||||
|
||||
// sync watches treectrl
|
||||
void SyncWatches(const Vector<VarItem>& children = Vector<VarItem>());
|
||||
|
||||
// sync explorer pane
|
||||
void SyncExplorer(const Vector<VarItem>& children = Vector<VarItem>());
|
||||
#endif
|
||||
|
||||
// sync data tabs, depending on which tab is shown
|
||||
bool localSynced;
|
||||
bool thisSynced;
|
||||
bool watchesSynced;
|
||||
bool explorerSynced;
|
||||
void SyncData();
|
||||
|
||||
// sync ide display with breakpoint position
|
||||
void SyncIde(bool frame = false);
|
||||
|
||||
// watches arrayctrl key handling
|
||||
bool Key(dword key, int count);
|
||||
|
||||
// create a string representation of frame given its info and args
|
||||
String FormatFrame(MIValue &fInfo, MIValue &fArgs);
|
||||
|
||||
// re-fills frame's droplist when dropping it
|
||||
bool FillDropFrames(int min, int max, bool val);
|
||||
void DropFrames();
|
||||
|
||||
// shows selected stack frame in editor
|
||||
void ShowFrame();
|
||||
|
||||
// re-fills thread selector droplist on drop
|
||||
void dropThreads();
|
||||
|
||||
// selects current thread
|
||||
void showThread(void);
|
||||
|
||||
// opens quick watch dialog
|
||||
void QuickWatch(void);
|
||||
|
||||
// format watch line
|
||||
String FormatWatchLine(String exp, String const &val, int level);
|
||||
|
||||
// deep watch current quickwatch variable
|
||||
void WatchDeep0(String parentExp, String const &name, int level, int &maxRemaining);
|
||||
void WatchDeep(String parentExp, String const &name);
|
||||
|
||||
// copy stack frame list to clipboard
|
||||
void CopyStack(void);
|
||||
|
||||
// copy disassembly listing to clipboard
|
||||
void CopyDisas(void);
|
||||
|
||||
// lock/unlock debugger controls
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
// Period check for killed console
|
||||
TimeCallback periodic;
|
||||
void Periodic();
|
||||
|
||||
String GetHostPath(const String& path) { return host->GetHostPath(path); }
|
||||
String GetLocalPath(const String& path) { return host->GetLocalPath(path); }
|
||||
|
||||
// fill a pane with data from a couple of arrays without erasing it first
|
||||
// (avoid re-painting and resetting scroll if not needed)
|
||||
void FillPane(ArrayCtrl &pane, Index<String> const &nam, Vector<String> const &val);
|
||||
|
||||
void Setup(ArrayCtrl& a, int x = 1);
|
||||
void SyncWidth(ArrayCtrl& a);
|
||||
|
||||
protected:
|
||||
|
||||
public :
|
||||
|
||||
typedef Gdb_MI2 CLASSNAME;
|
||||
|
||||
// debugger IDE inteface
|
||||
virtual void DebugBar(Bar& bar);
|
||||
virtual bool SetBreakpoint(const String& filename, int line, const String& bp);
|
||||
virtual void AsyncBrk();
|
||||
virtual bool RunTo();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
virtual bool IsFinished();
|
||||
virtual bool Tip(const String& exp, CodeEditor::MouseTip& mt);
|
||||
|
||||
// create GDB process and initializes it
|
||||
bool Create(One<Host>&& _host, const String& exefile, const String& cmdline, bool console);
|
||||
|
||||
Gdb_MI2();
|
||||
virtual ~Gdb_MI2();
|
||||
|
||||
// sends an MI command and get answer back
|
||||
MIValue MICmd(const char *cmdLine);
|
||||
|
||||
// quick exit from service thread when called and 'stopThread' is set
|
||||
// throws a BreakExc exception
|
||||
void RaiseIfStop(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
#include "Debuggers.h"
|
||||
|
||||
// sync explorer pane
|
||||
#ifdef flagMT
|
||||
void Gdb_MI2::SyncExplorer()
|
||||
{
|
||||
// re-enter if called from main thread
|
||||
if(IsMainThread())
|
||||
{
|
||||
debugThread.Start(THISBACK(SyncExplorer));
|
||||
return;
|
||||
}
|
||||
|
||||
INTERLOCKED {
|
||||
IncThreadRunning();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
VectorMap<String, String> prev = DataMap(explorer);
|
||||
|
||||
// get expression from editfield
|
||||
String expr;
|
||||
{
|
||||
GuiLock __;
|
||||
expr = ~explorerExprEdit;
|
||||
}
|
||||
|
||||
// create a vari object and evaluate '*this' expression
|
||||
VarItem vItem(this);
|
||||
vItem.Evaluate(expr);
|
||||
|
||||
RaiseIfStop();
|
||||
|
||||
// get children if complex variable
|
||||
Vector<VarItem> children;
|
||||
if(vItem.kind == VarItem::COMPLEX)
|
||||
children = vItem.GetChildren();
|
||||
else
|
||||
children.Add(vItem);
|
||||
|
||||
RaiseIfStop();
|
||||
|
||||
// fill explorer memners expressions, short expressions and values
|
||||
explorerExpressions.Clear();
|
||||
explorerValues.Clear();
|
||||
for(int iVar = 0; iVar < children.GetCount(); iVar++)
|
||||
{
|
||||
VarItem &v = children[iVar];
|
||||
explorerExpressions << v.shortExpression;
|
||||
explorerValues << v.value;
|
||||
}
|
||||
|
||||
RaiseIfStop();
|
||||
|
||||
// update 'this' pane
|
||||
FillPane(explorer, explorerExpressions, explorerValues);
|
||||
|
||||
// simplify batch
|
||||
for(int iVar = 0; iVar < children.GetCount(); iVar++)
|
||||
{
|
||||
RaiseIfStop();
|
||||
while(children[iVar].Simplify())
|
||||
RaiseIfStop();
|
||||
|
||||
VarItem &v = children[iVar];
|
||||
|
||||
explorerValues[iVar] = v.value;
|
||||
{
|
||||
GuiLock __;
|
||||
explorer.Set(iVar, 1, v.value);
|
||||
}
|
||||
}
|
||||
|
||||
// when finished, mark changed values
|
||||
MarkChanged(prev, explorer);
|
||||
|
||||
explorerSynced = true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
explorerSynced = false;
|
||||
}
|
||||
|
||||
DecThreadRunning();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void Gdb_MI2::SyncExplorer(const Vector<VarItem>& children_)
|
||||
{
|
||||
static VectorMap<String, String> prev;
|
||||
Vector<VarItem> children = clone(children_);
|
||||
if(children.IsEmpty())
|
||||
{
|
||||
prev = DataMap(explorer);
|
||||
|
||||
// get expression from editfield
|
||||
String expr = explorerExprEdit;
|
||||
if(expr.IsEmpty())
|
||||
{
|
||||
explorerSynced = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// create a vari object and evaluate the expression
|
||||
VarItem vItem(this, expr);
|
||||
|
||||
// get children if complex variable
|
||||
if(vItem.kind == VarItem::COMPLEX)
|
||||
children = clone(vItem.GetChildren());
|
||||
else
|
||||
children.Add(vItem);
|
||||
|
||||
// fill explorer memners expressions, short expressions and values
|
||||
explorerExpressions.Clear();
|
||||
explorerValues.Clear();
|
||||
for(int iVar = 0; iVar < children.GetCount(); iVar++)
|
||||
{
|
||||
VarItem &v = children[iVar];
|
||||
explorerExpressions << v.shortExpression;
|
||||
explorerValues << v.value;
|
||||
}
|
||||
|
||||
// update 'this' pane
|
||||
FillPane(explorer, explorerExpressions, explorerValues);
|
||||
|
||||
exploreEvent<> .Set(500, THISBACK1(SyncExplorer, DeepClone(children)));
|
||||
return;
|
||||
}
|
||||
|
||||
// simplify batch
|
||||
for(int iVar = 0; iVar < children.GetCount(); iVar++)
|
||||
{
|
||||
if(children[iVar].Simplify())
|
||||
{
|
||||
VarItem &v = children[iVar];
|
||||
explorer.Set(iVar, 1, v.value);
|
||||
explorerValues[iVar] = v.value;
|
||||
exploreEvent<> .Set(100, THISBACK1(SyncExplorer, DeepClone(children)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(int iVar = 0; iVar < children.GetCount(); iVar++)
|
||||
explorer.Set(iVar, 1, children[iVar].value);
|
||||
|
||||
// when finished, mark changed values
|
||||
MarkChanged(prev, explorer);
|
||||
explorerSynced = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Gdb_MI2::doExplore(String const &expr, bool appendHistory)
|
||||
{
|
||||
// set the expression inside expression editor
|
||||
explorerExprEdit <<= expr;
|
||||
|
||||
// update the history : trim it from past current position
|
||||
// and append it at end
|
||||
if(appendHistory)
|
||||
{
|
||||
if(explorerHistoryPos >= 0)
|
||||
{
|
||||
explorerHistoryPos++;
|
||||
explorerHistoryExpressions.Trim(explorerHistoryPos);
|
||||
}
|
||||
else
|
||||
explorerHistoryPos = 0;
|
||||
explorerHistoryExpressions.Add(expr);
|
||||
}
|
||||
|
||||
explorerSynced = false;
|
||||
SyncExplorer();
|
||||
|
||||
// update history buttons visibility
|
||||
explorerBackBtn.Enable(explorerHistoryPos > 0);
|
||||
explorerForwardBtn.Enable(explorerHistoryPos < explorerHistoryExpressions.GetCount() - 1);
|
||||
}
|
||||
|
||||
void Gdb_MI2::onExploreExpr(ArrayCtrl *what)
|
||||
{
|
||||
String expr;
|
||||
if(!what)
|
||||
{
|
||||
// if expression don't come from another ArrayCtrl
|
||||
// we use the expression editbox
|
||||
expr = ~explorerExprEdit;
|
||||
}
|
||||
else if(what == &members)
|
||||
{
|
||||
int line = what->GetCursor();
|
||||
if(line >= 0)
|
||||
expr = thisExpressions[line];
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, we use the expression from sending ArrayCtrl
|
||||
int line = what->GetCursor();
|
||||
int col = what->GetClickColumn();
|
||||
if(line >= 0 && (what != &watches || col != 0))
|
||||
expr = what->Get(line, 0);
|
||||
}
|
||||
// nothing to do on empty expression
|
||||
if(expr == "")
|
||||
return;
|
||||
|
||||
doExplore(expr, true);
|
||||
|
||||
// activate explorer tab
|
||||
tab.Set(4);
|
||||
}
|
||||
|
||||
void Gdb_MI2::onExplorerChild()
|
||||
{
|
||||
// click on first line (value line) does nothing
|
||||
int line = explorer.GetCursor();
|
||||
if(line < 0)
|
||||
return;
|
||||
if(line < explorerExpressions.GetCount())
|
||||
doExplore(explorerExpressions[line], true);
|
||||
}
|
||||
|
||||
void Gdb_MI2::onExplorerBack()
|
||||
{
|
||||
if(explorerHistoryPos < 1)
|
||||
return;
|
||||
explorerHistoryPos--;
|
||||
String expr = explorerHistoryExpressions[explorerHistoryPos];
|
||||
doExplore(expr, false);
|
||||
}
|
||||
|
||||
void Gdb_MI2::onExplorerForward()
|
||||
{
|
||||
if(explorerHistoryPos >= explorerHistoryExpressions.GetCount() - 1)
|
||||
return;
|
||||
explorerHistoryPos++;
|
||||
String expr = explorerHistoryExpressions[explorerHistoryPos];
|
||||
doExplore(expr, false);
|
||||
}
|
||||
|
||||
void Gdb_MI2::ExplorerMenu(Bar& bar)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,357 +0,0 @@
|
|||
#include "Debuggers.h"
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
// sends a ctrl-c to debugger, returns true on success, false otherwise
|
||||
bool Gdb_MI2::InterruptDebugger(void)
|
||||
{
|
||||
int killed = 0;
|
||||
for(int iProc = 0; iProc < processes.GetCount(); iProc++)
|
||||
if(kill(processes[iProc], SIGINT) == 0)
|
||||
killed++;
|
||||
return killed;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
// current command break support -- ONLY POSIX, by now
|
||||
// used to speed up operations in MT mode
|
||||
bool Gdb_MI2::InterruptCommand(void)
|
||||
{
|
||||
try
|
||||
{
|
||||
LocalProcess &proc = dynamic_cast<LocalProcess &>(*dbg);
|
||||
pid_t pid = proc.GetPid();
|
||||
bool res = (kill(pid, SIGINT) == 0);
|
||||
return res;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
bool Gdb_MI2::InterruptCommand(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// read debugger output analyzing command responses and async output
|
||||
// things are quite tricky because debugger output seems to be
|
||||
// slow and we have almost no terminator to stop on -- (gdb) is not
|
||||
// so reliable as it can happen (strangely) in middle of nothing
|
||||
MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
||||
{
|
||||
MIValue res;
|
||||
|
||||
// parse result data
|
||||
StringStream ss(output);
|
||||
while(!ss.IsEof())
|
||||
{
|
||||
String s;
|
||||
String str = ss.GetLine();
|
||||
s = str;
|
||||
while(str.GetCount() == 1024 && !ss.IsEof())
|
||||
{
|
||||
str = ss.GetLine();
|
||||
s << str;
|
||||
}
|
||||
|
||||
s = TrimBoth(s);
|
||||
|
||||
// check 'running' and 'stopped' async output
|
||||
if(s.StartsWith("*running"))
|
||||
{
|
||||
started = true;
|
||||
stopReason.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
else if(s.StartsWith("*stopped"))
|
||||
{
|
||||
stopped = true;
|
||||
s = '{' + s.Mid(9) + '}';
|
||||
stopReason = MIValue(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// catch process start/stop and store/remove pids
|
||||
else if(s.StartsWith("=thread-group-started,id="))
|
||||
{
|
||||
String id, pid;
|
||||
int i = s.Find("id=");
|
||||
if(i < 0)
|
||||
continue;
|
||||
i += 4;
|
||||
while(s[i] && s[i] != '"')
|
||||
id.Cat(s[i++]);
|
||||
i = s.Find("pid=");
|
||||
if(i < 0)
|
||||
continue;
|
||||
i += 5;
|
||||
while(s[i] && s[i] != '"')
|
||||
pid.Cat(s[i++]);
|
||||
|
||||
processes.Add(id, atoi(pid));
|
||||
continue;
|
||||
}
|
||||
|
||||
else if(s.StartsWith("=thread-group-exited,id="))
|
||||
{
|
||||
String id;
|
||||
int i = s.Find("id=");
|
||||
if(i < 0)
|
||||
continue;
|
||||
i += 4;
|
||||
while(s[i] && s[i] != '"')
|
||||
id.Cat(s[i++]);
|
||||
i = processes.Find(id);
|
||||
if(i >= 0)
|
||||
processes.Remove(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip asynchronous responses
|
||||
// in future, we could be gather/use them
|
||||
if(s[0] == '*'|| s[0] == '=')
|
||||
continue;
|
||||
|
||||
// here handling of command responses
|
||||
// we're not interested either, as we use MI interface
|
||||
if(s[0] == '~')
|
||||
continue;
|
||||
|
||||
// here handling of target output
|
||||
// well, for now discard this one too, but it should go on console output
|
||||
if(s[0] == '~')
|
||||
continue;
|
||||
|
||||
// here handling of gdb log/debug message
|
||||
// not interesting here
|
||||
if(s[0] == '&')
|
||||
continue;
|
||||
|
||||
// now we SHALL have something starting with any of
|
||||
// // "^done", "^running", "^connected", "^error" or "^exit" records
|
||||
if(s.StartsWith("^done") || s.StartsWith("^running"))
|
||||
{
|
||||
// here we've got succesful command output in list form, if any
|
||||
// shall skip the comma; following can be a serie of pairs,
|
||||
// or directly an array of maps in form of :
|
||||
// [{key="value",key="value",...},{key="value"...}...]
|
||||
|
||||
int i = 5; // just skip shortest, ^done
|
||||
while(s[i] && s[i] != ',')
|
||||
i++;
|
||||
if(!s[i])
|
||||
continue;
|
||||
i++;
|
||||
if(!s[i])
|
||||
continue;
|
||||
res = MIValue(s.Mid(i));
|
||||
continue;
|
||||
}
|
||||
else if(s.StartsWith("^error"))
|
||||
{
|
||||
// first array element is reserved for command result status
|
||||
s = s.Right(12); // '^error,msg=\"'
|
||||
s = s.Left(s.GetCount() - 1);
|
||||
res.SetError(s);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
MIValue Gdb_MI2::ReadGdb(bool wait)
|
||||
{
|
||||
String output, s;
|
||||
MIValue res;
|
||||
|
||||
// blocking path
|
||||
// waits for 2 minutes max, then return empty value
|
||||
// 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)
|
||||
bool stop = false;
|
||||
int retries = 120 * 50;
|
||||
while(dbg && --retries && !stop)
|
||||
{
|
||||
dbg->Read(s);
|
||||
StringStream ss(s);
|
||||
while(!ss.IsEof())
|
||||
{
|
||||
String s2 = ss.GetLine();
|
||||
output << s2 << "\n";
|
||||
|
||||
// wait till (gdb) end marker appears
|
||||
s2 = TrimBoth(s2);
|
||||
if(s2 == "(gdb)" || s2 == "&\"quit\\n\"")
|
||||
{
|
||||
stop = true;
|
||||
#ifdef flagMT
|
||||
// exit if in service threa and thread is stoppint
|
||||
if(!IsMainThread() && IsStopThread())
|
||||
throw BreakExc();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// non-blocking quick exit
|
||||
if(!wait)
|
||||
break;
|
||||
|
||||
Sleep(20);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(output.IsEmpty())
|
||||
return res;
|
||||
|
||||
return ParseGdb(output);
|
||||
}
|
||||
|
||||
// new-way commands using GDB MI interface
|
||||
// on input : MI interface command line
|
||||
// on output : an MIValue containing GDB output
|
||||
// STREAM OUTPUT
|
||||
// ~ command response
|
||||
// @ target output
|
||||
// & gdb log/debug messages
|
||||
//
|
||||
// RESULT RECORDS
|
||||
// "^done" [ "," results ]
|
||||
// "^running" same as "^done"
|
||||
// "^connected" gdb has connected to a remote target.
|
||||
// "^error" "," c-string The operation failed. The c-string contains the corresponding error message.
|
||||
// "^exit" gdb has terminate
|
||||
//
|
||||
// ASYNCHRONOUS RECORDS
|
||||
// *running,thread-id="thread"
|
||||
// *stopped,reason="reason",thread-id="id",stopped-threads="stopped",core="core"
|
||||
// =thread-group-added,id="id"
|
||||
// =thread-group-removed,id="id"
|
||||
// =thread-group-started,id="id",pid="pid"
|
||||
// =thread-group-exited,id="id"[,exit-code="code"]
|
||||
// =thread-created,id="id",group-id="gid"
|
||||
// =thread-exited,id="id",group-id="gid"
|
||||
// =thread-selected,id="id"
|
||||
// =library-loaded,...
|
||||
// =library-unloaded,...
|
||||
// =breakpoint-created,bkpt={...}
|
||||
// =breakpoint-modified,bkpt={...}
|
||||
// =breakpoint-deleted,bkpt={...}
|
||||
//
|
||||
// FRAME INFO INSIDE RESPONSES
|
||||
// level The level of the stack frame. The innermost frame has the level of zero. This field is always present.
|
||||
// func The name of the function corresponding to the frame. This field may be absent if gdb is unable to determine the function name.
|
||||
// addr The code address for the frame. This field is always present.
|
||||
// file The name of the source files that correspond to the frame's code address. This field may be absent.
|
||||
// line The source line corresponding to the frames' code address. This field may be absent.
|
||||
// from The name of the binary file (either executable or shared library) the corresponds to the frame's code address. This field may be absent.
|
||||
|
||||
// THREAD INFO INSIDE RESPONSES
|
||||
// id The numeric id assigned to the thread by gdb. This field is always present.
|
||||
// target-id Target-specific string identifying the thread. This field is always present.
|
||||
// details Additional information about the thread provided by the target. It is supposed to be human-readable and not interpreted by the frontend. This field is optional.
|
||||
// state Either `stopped' or `running', depending on whether the thread is presently running. This field is always present.
|
||||
// core The value of this field is an integer number of the processor core the thread was last seen on. This field is optional.
|
||||
//
|
||||
// REMARKS : by now, we just handle synchronous output and check asynchronous one just to detect
|
||||
// debugger run/stop status -- all remaining asynchrnonous output is discarded
|
||||
MIValue Gdb_MI2::MICmd(const char *cmdLine)
|
||||
{
|
||||
MIValue res;
|
||||
|
||||
#ifdef flagMT
|
||||
// on MT, we interrupt all non-main threads
|
||||
// issued GDB commands (which normally can lag several seconds...)
|
||||
// before issuing the command
|
||||
if(IsMainThread() && IsThreadRunning())
|
||||
ShutDownThreads();
|
||||
|
||||
// quick exit for service thread
|
||||
if(!IsMainThread() && IsStopThread())
|
||||
throw BreakExc();
|
||||
|
||||
// lock other thread's access
|
||||
INTERLOCKED {
|
||||
#endif
|
||||
|
||||
// sends command to debugger and get result data
|
||||
// should handle dbg unexpected termination ?
|
||||
if(!dbg || !dbg->IsRunning() /* || IdeIsDebugLock() */)
|
||||
return MIValue();
|
||||
|
||||
// consume previous output from gdb... don't know why sometimes
|
||||
// is there and gives problems to MI interface. We shall maybe
|
||||
// parse and store it somewhere
|
||||
ReadGdb(false);
|
||||
|
||||
dbg->Write(String("-") + cmdLine + "\n");
|
||||
res = ReadGdb();
|
||||
#ifdef flagMT
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// support for debugger variables cleanup
|
||||
void Gdb_MI2::StoreVariable(String const &name)
|
||||
{
|
||||
INTERLOCKED_(varMutex) {
|
||||
debugVariables.Add(name);
|
||||
}
|
||||
}
|
||||
|
||||
void Gdb_MI2::CleanupVariables(void)
|
||||
{
|
||||
#ifdef flagMT
|
||||
// restart if called from main thread
|
||||
if(IsMainThread())
|
||||
{
|
||||
INTERLOCKED_(varMutex) {
|
||||
prevDebugVariables.Append(debugVariables);
|
||||
debugVariables.Clear();
|
||||
}
|
||||
debugThread.Start(THISBACK(CleanupVariables));
|
||||
return;
|
||||
}
|
||||
|
||||
IncThreadRunning();
|
||||
|
||||
String name;
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
name = "";
|
||||
INTERLOCKED_(varMutex) {
|
||||
if(!prevDebugVariables.IsEmpty())
|
||||
{
|
||||
name = prevDebugVariables.Top();
|
||||
MICmd("var-delete " + name);
|
||||
prevDebugVariables.Pop();
|
||||
}
|
||||
}
|
||||
Sleep(50);
|
||||
}
|
||||
while(!IsStopThread() && name != "");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
|
||||
DecThreadRunning();
|
||||
|
||||
#else
|
||||
if(!debugVariables.IsEmpty())
|
||||
{
|
||||
String name = debugVariables.Pop();
|
||||
MICmd("var-delete " + name);
|
||||
timeEvent<> .Set(50, THISBACK(CleanupVariables));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,806 +0,0 @@
|
|||
#include "MIValue.h"
|
||||
|
||||
//#define MITUPLE_DUMP_MARKERS
|
||||
|
||||
static MIValue &NullMIValue(void)
|
||||
{
|
||||
static MIValue v;
|
||||
return v;
|
||||
}
|
||||
|
||||
static MIValue &ErrorMIValue(String const &msg)
|
||||
{
|
||||
static MIValue v;
|
||||
v.SetError(msg);
|
||||
return v;
|
||||
}
|
||||
|
||||
bool MIValue::expect(String const &where, char exp, int i, String const &s)
|
||||
{
|
||||
if(s[i] == exp)
|
||||
return true;
|
||||
int start = i - 30;
|
||||
if(start < 0)
|
||||
start = 0;
|
||||
if(!s[i])
|
||||
SetError(Format(where + " : Expected '%c', got end of string at pos %d around '%s'", exp, i, s.Mid(start, 60)));
|
||||
else
|
||||
SetError(Format(where + " : Expected '%c', got '%c' at pos %d in '%s'", exp, s[i], i, s.Mid(start, 60)));
|
||||
return false;
|
||||
}
|
||||
|
||||
static char backslash(String const &s, int &i)
|
||||
{
|
||||
i++;
|
||||
if(IsDigit(s[i]))
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MIValue::ParsePair(String &name, MIValue &val, String const &s, int i)
|
||||
{
|
||||
name.Clear();
|
||||
val.Clear();
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
if(!s[i])
|
||||
{
|
||||
SetError("ParsePair:Unexpected end of string");
|
||||
return i;
|
||||
}
|
||||
|
||||
// is starting wirh '[' or '{' take it as a value with empty name
|
||||
if(s[i] == '{' || s[i] == '[')
|
||||
{
|
||||
name = "<UNNAMED>";
|
||||
return val.ParseTuple(s, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int aCount = 0;
|
||||
while(s[i] && ((s[i] != '=' && s[i] != '}' && s[i] != ']' && s[i] != ',') || aCount))
|
||||
{
|
||||
if(s[i] == '<')
|
||||
aCount++;
|
||||
else if(s[i] == '>')
|
||||
aCount--;
|
||||
if(s[i] == '\\')
|
||||
name.Cat(backslash(s, i));
|
||||
else
|
||||
name.Cat(s[i]);
|
||||
i++;
|
||||
|
||||
// skip blanks if not inside <>
|
||||
/*
|
||||
if(!aCount)
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
*/
|
||||
}
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
|
||||
if(s[i] != '=')
|
||||
{
|
||||
// we take the data without = as the value part
|
||||
// of keyless tuple...
|
||||
val.Set(name);
|
||||
name = "<UNNAMED>";
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
}
|
||||
|
||||
// skip address part before a tuple start, if any... it's useless and confuses the parser
|
||||
if(s[i] == '@')
|
||||
{
|
||||
int j = i;
|
||||
while(s[j] && s[j] != ':')
|
||||
j++;
|
||||
if(s[j] == ':')
|
||||
j++;
|
||||
while(s[j] && IsSpace(s[j]))
|
||||
j++;
|
||||
if(s[j] == '{')
|
||||
i = j;
|
||||
}
|
||||
|
||||
switch(s[i])
|
||||
{
|
||||
case '"':
|
||||
i = val.ParseString(s, i);
|
||||
break;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
i = val.ParseArray(s, i);
|
||||
break;
|
||||
|
||||
case '{':
|
||||
i = val.ParseTuple(s, i);
|
||||
break;
|
||||
|
||||
default:
|
||||
i = val.ParseUnquotedString(s, i);
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int MIValue::ParseTuple(String const &s, int i)
|
||||
{
|
||||
Clear();
|
||||
type = MITuple;
|
||||
|
||||
// drop opening delimiter
|
||||
if(!expect("ParseTuple", '{', i, s))
|
||||
return s.GetCount();
|
||||
i++;
|
||||
while(s[i] && s[i] != '}')
|
||||
{
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
String name;
|
||||
MIValue val;
|
||||
i = ParsePair(name, val, s, i);
|
||||
tuple.AddPick(name, pick(val));
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
if(s[i] == '}')
|
||||
break;
|
||||
if(!expect("ParseTuple", ',', i, s))
|
||||
return s.GetCount();
|
||||
i++;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
int MIValue::ParseArray(String const &s, int i)
|
||||
{
|
||||
Clear();
|
||||
type = MIArray;
|
||||
|
||||
// drop opening delimiter
|
||||
if(!expect("ParseArray", '[', i, s))
|
||||
return s.GetCount();
|
||||
i++;
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
while(s[i] && s[i] != ']')
|
||||
{
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
String name;
|
||||
MIValue val;
|
||||
if(s[i] == '[')
|
||||
i = val.ParseArray(s, i);
|
||||
else if(s[i] == '{')
|
||||
i = val.ParseTuple(s, i);
|
||||
else if(s[i] == '"')
|
||||
i = val.ParseString(s, i);
|
||||
else if(s[i] == '<')
|
||||
i = val.ParseAngle(s, i);
|
||||
else
|
||||
i = ParsePair(name, val, s, i);
|
||||
array.Add() = pick(val);
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
if(s[i] == ']')
|
||||
break;
|
||||
if(!expect("ParseArray", ',', i, s))
|
||||
return s.GetCount();
|
||||
i++;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
int MIValue::ParseString(String const &s, int i)
|
||||
{
|
||||
Clear();
|
||||
type = MIString;
|
||||
|
||||
if(!expect("ParseString", '"', i, s))
|
||||
return s.GetCount();
|
||||
i++;
|
||||
while(s[i])
|
||||
{
|
||||
// verbatim if escaped
|
||||
if(s[i] == '\\')
|
||||
string.Cat(backslash(s, i));
|
||||
else if(s[i] == '"')
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
string.Cat(s[i]);
|
||||
i++;
|
||||
}
|
||||
if(!expect("ParseString", '"', i-1, s))
|
||||
return s.GetCount();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int MIValue::ParseAngle(String const &s, int i)
|
||||
{
|
||||
Clear();
|
||||
type = MIString;
|
||||
int aCount = 0;
|
||||
|
||||
if(!expect("ParseAngle", '<', i, s))
|
||||
return s.GetCount();
|
||||
string = "<";
|
||||
aCount++;
|
||||
i++;
|
||||
while(s[i])
|
||||
{
|
||||
// verbatim if escaped
|
||||
if(s[i] == '\\')
|
||||
string.Cat(backslash(s, i));
|
||||
else if(s[i] == '>' && !--aCount)
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Cat(s[i]);
|
||||
if(s[i] == '<')
|
||||
aCount++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(!expect("ParseAngle", '>', i-1, s))
|
||||
return s.GetCount();
|
||||
string.Cat('>');
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// sigh
|
||||
static bool comma(String const &s, int i)
|
||||
{
|
||||
if(s[i] != ',')
|
||||
return false;
|
||||
if(!i)
|
||||
return true;
|
||||
if(IsDigit(s[i-1]) && IsDigit(s[i+1]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// we can hava a non-quoted string... so we read up
|
||||
// to terminator, which can be '}', ']' or ','
|
||||
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]);
|
||||
if(s[i] == '\\')
|
||||
{
|
||||
i++;
|
||||
if(s[i])
|
||||
valStr.Cat(s[i++]);
|
||||
continue;
|
||||
}
|
||||
if(s[i] == '<' && !inQuote)
|
||||
aCount++;
|
||||
else if(s[i] == '>' && !inQuote)
|
||||
aCount--;
|
||||
else if(s[i] == '"' && !aCount)
|
||||
inQuote = !inQuote;
|
||||
i++;
|
||||
}
|
||||
type = MIString;
|
||||
string = valStr;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int MIValue::Parse(String const &s, int i)
|
||||
{
|
||||
// if starts with '"', it's a string
|
||||
// if starts with '[', it's an array
|
||||
// if starts with '{', it's a tuple
|
||||
// otherwise, it can be a sequence of pair name="value" which is stored like a tuple
|
||||
// latter case is an example o bad design of MI interface....
|
||||
Clear();
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
if(s[i] == '"')
|
||||
return ParseString(s, i);
|
||||
else if(s[i] == '<')
|
||||
return ParseAngle(s, i);
|
||||
else if(s[i] == '[')
|
||||
return ParseArray(s, i);
|
||||
else if(s[i] == '{')
|
||||
return ParseTuple(s, i);
|
||||
else
|
||||
{
|
||||
String name;
|
||||
MIValue val;
|
||||
type = MITuple;
|
||||
while(s[i])
|
||||
{
|
||||
i = ParsePair(name, val, s, i);
|
||||
tuple.AddPick(name, pick(val));
|
||||
while(s[i] && isspace(s[i]))
|
||||
i++;
|
||||
if(s[i] != ',')
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
MIValue &MIValue::operator=(MIValue&& v)
|
||||
{
|
||||
Clear();
|
||||
type = pick(v.type);
|
||||
switch(type)
|
||||
{
|
||||
case MIString:
|
||||
string = v.string;
|
||||
break;
|
||||
case MIArray:
|
||||
array = pick(v.array);
|
||||
break;
|
||||
case MITuple:
|
||||
tuple = pick(v.tuple);
|
||||
break;
|
||||
default:
|
||||
SetError("Unknown MIValue type");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MIValue::MIValue()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
MIValue::MIValue(MIValue&& v)
|
||||
{
|
||||
Clear();
|
||||
type = v.type;
|
||||
switch(type)
|
||||
{
|
||||
case MIString:
|
||||
string = v.string;
|
||||
break;
|
||||
case MIArray:
|
||||
array = pick(v.array);
|
||||
break;
|
||||
case MITuple:
|
||||
tuple = pick(v.tuple);
|
||||
break;
|
||||
default:
|
||||
SetError("Unknown MIValue type");
|
||||
}
|
||||
}
|
||||
|
||||
MIValue::MIValue(String const &s)
|
||||
{
|
||||
Parse(s);
|
||||
|
||||
// tuple with 1 element and unnamed key is a string
|
||||
if(IsTuple() && tuple.GetCount() == 1 && tuple.GetKey(0) == "<UNNAMED>")
|
||||
{
|
||||
type = MIString;
|
||||
string = tuple[0];
|
||||
tuple.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
MIValue &MIValue::operator=(String const &s)
|
||||
{
|
||||
Parse(s);
|
||||
// tuple with 1 element and unnamed key is a string
|
||||
if(IsTuple() && tuple.GetCount() == 1 && tuple.GetKey(0) == "<UNNAMED>")
|
||||
{
|
||||
type = MIString;
|
||||
string = tuple[0];
|
||||
tuple.Clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MIValue::Clear()
|
||||
{
|
||||
type = MIString;
|
||||
string = "";
|
||||
array.Clear();
|
||||
tuple.Clear();
|
||||
}
|
||||
|
||||
// sets value to an error condition
|
||||
MIValue &MIValue::SetError(String const &msg)
|
||||
{
|
||||
type = MIString;
|
||||
string = "error:" + msg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// check if value contains an error
|
||||
bool MIValue::IsError(void) const
|
||||
{
|
||||
return type == MIString && string.StartsWith("error:");
|
||||
}
|
||||
|
||||
// check for emptyness
|
||||
bool MIValue::IsEmpty(void) const
|
||||
{
|
||||
return type == MIString && string == "";
|
||||
}
|
||||
|
||||
// simple accessors
|
||||
int MIValue::GetCount(void) const
|
||||
{
|
||||
if(IsError())
|
||||
return 0;
|
||||
if(type == MIArray)
|
||||
return array.GetCount();
|
||||
else if(type == MITuple)
|
||||
return tuple.GetCount();
|
||||
else
|
||||
return string.GetCount();
|
||||
}
|
||||
|
||||
int MIValue::Find(const char *key) const
|
||||
{
|
||||
if(type != MITuple)
|
||||
return -1;
|
||||
return tuple.Find(key);
|
||||
}
|
||||
|
||||
MIValue &MIValue::Get(int i)
|
||||
{
|
||||
if(IsError())
|
||||
return *this;
|
||||
if(type == MIArray)
|
||||
return array[i];
|
||||
if(type == MITuple)
|
||||
return tuple[i];
|
||||
return ErrorMIValue("Not an Array value type");
|
||||
}
|
||||
|
||||
MIValue const &MIValue::Get(int i) const
|
||||
{
|
||||
if(IsError())
|
||||
return *this;
|
||||
if(type == MIArray)
|
||||
return array[i];
|
||||
if(type == MITuple)
|
||||
return tuple[i];
|
||||
return ErrorMIValue("Not an Array value type");
|
||||
}
|
||||
|
||||
MIValue &MIValue::Get(const char *key)
|
||||
{
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
if(tuple.Find(key) < 0)
|
||||
return ErrorMIValue(String("key '") + key + "' not found");
|
||||
return tuple.Get(key);
|
||||
}
|
||||
|
||||
MIValue const &MIValue::Get(const char *key) const
|
||||
{
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
if(tuple.Find(key) < 0)
|
||||
return ErrorMIValue(String("key '") + key + "' not found");
|
||||
return tuple.Get(key);
|
||||
}
|
||||
|
||||
String &MIValue::Get(void)
|
||||
{
|
||||
if(type != MIString)
|
||||
return ErrorMIValue("Not a String value type");
|
||||
return string;
|
||||
}
|
||||
|
||||
String const &MIValue::Get(void) const
|
||||
{
|
||||
if(type != MIString)
|
||||
return ErrorMIValue("Not a String value type");
|
||||
return string;
|
||||
}
|
||||
|
||||
// tuple string member accessor with default value if not found
|
||||
String MIValue::Get(const char *key, const char *def) const
|
||||
{
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
int i = tuple.Find(key);
|
||||
if(i >= 0)
|
||||
{
|
||||
if(tuple[i].type != MIString)
|
||||
return def;
|
||||
return tuple[i].Get();
|
||||
}
|
||||
else
|
||||
return def;
|
||||
}
|
||||
|
||||
// gets key by index for tuple values
|
||||
String MIValue::GetKey(int idx) const
|
||||
{
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
return tuple.GetKey(idx);
|
||||
}
|
||||
|
||||
void MIValue::Set(String const &s)
|
||||
{
|
||||
Clear();
|
||||
type = MIString;
|
||||
string = s;
|
||||
}
|
||||
|
||||
// data dump
|
||||
#ifdef MITUPLE_DUMP_MARKERS
|
||||
#define MARK_STRING "<STRING>"
|
||||
#define MARK_ARRAY "<ARRAY>"
|
||||
#define MARK_TUPLE "<TUPLE>"
|
||||
#else
|
||||
#define MARK_STRING ""
|
||||
#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 + Dump(string);
|
||||
|
||||
case MITuple:
|
||||
{
|
||||
String s = spacer + MARK_TUPLE + "{\n";
|
||||
level += 4;
|
||||
spacer = String(' ', level);
|
||||
for(int i = 0; i < tuple.GetCount(); i++)
|
||||
{
|
||||
String s1 = spacer + tuple.GetKey(i) + "=";
|
||||
s += s1;
|
||||
MIValue const &val = tuple[i];
|
||||
if(val.type == MIString)
|
||||
s += val.Dump();
|
||||
else
|
||||
{
|
||||
s += '\n' + val.Dump(level + 4);
|
||||
s = s.Left(s.GetCount()-1);
|
||||
}
|
||||
if(i < tuple.GetCount() - 1)
|
||||
s += ',';
|
||||
s += '\n';
|
||||
}
|
||||
level -= 4;
|
||||
spacer = String(' ', level);
|
||||
s += spacer + "}\n";
|
||||
return s;
|
||||
}
|
||||
|
||||
case MIArray:
|
||||
{
|
||||
String s = spacer + MARK_ARRAY + "[ \n";
|
||||
level += 4;
|
||||
for(int i = 0; i < array.GetCount(); i++)
|
||||
{
|
||||
MIValue const &val = array[i];
|
||||
s += val.Dump(level);
|
||||
if(val.type != MIString)
|
||||
s = s.Left(s.GetCount()-1);
|
||||
if(i < array.GetCount() - 1)
|
||||
s += ',';
|
||||
s += '\n';
|
||||
}
|
||||
s += spacer + "]\n";
|
||||
return s;
|
||||
}
|
||||
|
||||
default:
|
||||
return spacer + "*UNKNOWN MIVALUE TYPE*";
|
||||
}
|
||||
}
|
||||
|
||||
// finds breakpoint data given file and line
|
||||
MIValue &MIValue::FindBreakpoint(String const &file, int line)
|
||||
{
|
||||
MIValue &body = Get("body");
|
||||
if(body.IsError() || !body.IsArray())
|
||||
return NullMIValue();
|
||||
for(int i = 0; i < body.GetCount(); i++)
|
||||
{
|
||||
MIValue &bp = body[i];
|
||||
if(bp.IsError() || !bp.IsTuple())
|
||||
return NullMIValue();
|
||||
if(bp["file"] == file && atoi(bp["line"].Get()) == line)
|
||||
return bp;
|
||||
}
|
||||
return NullMIValue();
|
||||
}
|
||||
|
||||
static String PackName(String const &name)
|
||||
{
|
||||
String res;
|
||||
const char *c = ~name;
|
||||
while(*c)
|
||||
{
|
||||
if(!IsSpace(*c))
|
||||
res.Cat(*c);
|
||||
c++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// packs names inside tuples -- to make type recognition easy
|
||||
void MIValue::PackNames(void)
|
||||
{
|
||||
if(type == MITuple)
|
||||
{
|
||||
for(int i = 0; i < tuple.GetCount(); i++)
|
||||
{
|
||||
tuple.SetKey(i, PackName(tuple.GetKey(i)));
|
||||
tuple[i].PackNames();
|
||||
}
|
||||
}
|
||||
else if(type == MIArray)
|
||||
{
|
||||
for(int i = 0; i < array.GetCount(); i++)
|
||||
array[i].PackNames();
|
||||
}
|
||||
}
|
||||
|
||||
// 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() = pick(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&& v)
|
||||
{
|
||||
if(IsEmpty())
|
||||
{
|
||||
Clear();
|
||||
type = MITuple;
|
||||
}
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
tuple.AddPick(key, pick(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MIValue &MIValue::Add(String const &key, String const &data)
|
||||
{
|
||||
MIValue v;
|
||||
v.Set(data);
|
||||
return Add(key, pick(v));
|
||||
}
|
||||
|
||||
MIValue &MIValue::FindAdd(String const &key, String const &data)
|
||||
{
|
||||
if(IsEmpty())
|
||||
{
|
||||
Clear();
|
||||
type = MITuple;
|
||||
}
|
||||
if(type != MITuple)
|
||||
return ErrorMIValue("Not a Tuple value type");
|
||||
int idx = tuple.Find(key);
|
||||
MIValue v;
|
||||
v.Set(data);
|
||||
if(idx >= 0)
|
||||
tuple[idx] = pick(v);
|
||||
else
|
||||
tuple.AddPick(key, pick(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// add an item to an array
|
||||
MIValue &MIValue::Add(MIValue&& v)
|
||||
{
|
||||
if(IsEmpty())
|
||||
{
|
||||
Clear();
|
||||
type = MIArray;
|
||||
}
|
||||
if(type != MIArray)
|
||||
return ErrorMIValue("Not a Array value type");
|
||||
array.AddPick(pick(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MIValue &MIValue::Add(String const &data)
|
||||
{
|
||||
MIValue v;
|
||||
v.Set(data);
|
||||
return Add(pick(v));
|
||||
}
|
||||
|
||||
// remove a tuple key
|
||||
MIValue &MIValue::Remove(String const &key)
|
||||
{
|
||||
if(type != MITuple)
|
||||
return *this;
|
||||
tuple.RemoveKey(key);
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
#ifndef _ide_Debuggers_MIValue_h_
|
||||
#define _ide_Debuggers_MIValue_h_
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
// this struct contains values returned by GDB MI interface
|
||||
typedef enum { MIString, MIArray, MITuple } MIValueType;
|
||||
class MIValue : public Moveable<MIValue>
|
||||
{
|
||||
private:
|
||||
bool expect(String const &where, char exp, int i, String const &s);
|
||||
|
||||
int ParsePair(String &name, MIValue &val, String const &s, int i = 0);
|
||||
int ParseTuple(String const &s, int i = 0);
|
||||
int ParseArray(String const &s, int i = 0);
|
||||
int ParseString(String const &s, int i = 0);
|
||||
int ParseAngle(String const &s, int i = 0);
|
||||
int ParseUnquotedString(String const &s, int i = 0);
|
||||
int ParseValue(String const &s, int i = 0);
|
||||
int Parse(String const &s, int i = 0);
|
||||
|
||||
MIValueType type;
|
||||
String string;
|
||||
Vector<MIValue> array;
|
||||
VectorMap<String, MIValue> tuple;
|
||||
|
||||
public:
|
||||
// sets value to an error condition
|
||||
MIValue &SetError(String const &msg);
|
||||
|
||||
// check if value contains an error
|
||||
bool IsError(void) const;
|
||||
bool operator!(void) const { return IsError(); }
|
||||
operator bool() { return !IsError(); }
|
||||
|
||||
// check for emptyness
|
||||
bool IsEmpty(void) const;
|
||||
|
||||
MIValue &operator=(MIValue&& v);
|
||||
MIValue &operator=(String const &s);
|
||||
MIValue();
|
||||
MIValue(MIValue&& v);
|
||||
MIValue(String const &s);
|
||||
|
||||
void Clear(void);
|
||||
|
||||
// simple accessors
|
||||
int GetCount(void) const;
|
||||
int Find(const char *key) const;
|
||||
|
||||
MIValue &Get(int i);
|
||||
MIValue const &Get(int i) const;
|
||||
|
||||
MIValue &operator[](int i) { return Get(i); }
|
||||
MIValue const &operator[](int i) const { return Get(i); }
|
||||
|
||||
MIValue &Get(const char *s);
|
||||
MIValue const &Get(const char *s) const;
|
||||
|
||||
MIValue &operator[](const char *key) { return Get(key); }
|
||||
MIValue const &operator[](const char *key) const { return Get(key); }
|
||||
|
||||
String &Get(void);
|
||||
String const &Get(void) const;
|
||||
|
||||
// gets key by index for tuple values
|
||||
String GetKey(int idx) const;
|
||||
|
||||
operator String&() { return Get(); }
|
||||
operator const String &() const { return Get(); }
|
||||
String &ToString(void) { return Get(); }
|
||||
String const &ToString(void) const { return Get(); }
|
||||
|
||||
// tuple string member accessor with default value if not found
|
||||
String Get(const char *key, const char *def) const;
|
||||
String operator()(const char *key, const char *def) const { return Get(key, def); }
|
||||
|
||||
// setter for string (operator= starts parser...)
|
||||
void Set(String const &s);
|
||||
|
||||
// some type checking
|
||||
bool IsArray(void) const { return type == MIArray; }
|
||||
void AssertArray(void) const { ASSERT(type == MIArray); }
|
||||
bool IsTuple(void) const { return type == MITuple; }
|
||||
void AssertTuple(void) const { ASSERT(type == MITuple); }
|
||||
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;
|
||||
|
||||
// finds breakpoint data given file and line
|
||||
MIValue &FindBreakpoint(String const &file, int line);
|
||||
|
||||
// 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
|
||||
MIValue &Add(String const &key, MIValue&& v);
|
||||
MIValue &Add(String const &key, String const &data);
|
||||
MIValue &FindAdd(String const &key, String const &data);
|
||||
|
||||
// add an item to an array
|
||||
MIValue &Add(MIValue&& v);
|
||||
MIValue &Add(String const &data);
|
||||
|
||||
// remove a tuple key
|
||||
MIValue &Remove(String const &key);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#include "TypeSimplify.h"
|
||||
|
||||
static VectorMap<String, TYPE_SIMPLIFIER_HANDLER> &GetSimplifierMap(void)
|
||||
{
|
||||
static VectorMap<String, TYPE_SIMPLIFIER_HANDLER> map;
|
||||
return map;
|
||||
}
|
||||
|
||||
void RegisterSimplifier(const char *pattern, TYPE_SIMPLIFIER_HANDLER handler)
|
||||
{
|
||||
GetSimplifierMap().Add(pattern, handler);
|
||||
}
|
||||
|
||||
TYPE_SIMPLIFIER_HANDLER GetSimplifier(String const &pattern)
|
||||
{
|
||||
VectorMap<String, TYPE_SIMPLIFIER_HANDLER> &map = GetSimplifierMap();
|
||||
for(int i = 0; i < map.GetCount(); i++)
|
||||
{
|
||||
if(pattern.StartsWith(map.GetKey(i)))
|
||||
return map[i];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#ifndef _ide_Debuggers_TypeSimplify_h_
|
||||
#define _ide_Debuggers_TypeSimplify_h_
|
||||
|
||||
#include "Debuggers.h"
|
||||
#include "VarItem.h"
|
||||
|
||||
#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>"
|
||||
|
||||
// Simplifier handler
|
||||
// step is the simplifying step, used for arrays and maps
|
||||
// step 0 -- base simplify, no deep evaluation of containers
|
||||
// step i -- deep evaluation of element 'i' of container
|
||||
// returns number of needed steps to complete optimization
|
||||
// all this stuff is needed to allow gui to have priority on data display
|
||||
typedef int (*TYPE_SIMPLIFIER_HANDLER)(VarItem &varItem, int step);
|
||||
|
||||
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); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,669 +0,0 @@
|
|||
#include "TypeSimplify.h"
|
||||
|
||||
#define EVALDEEP
|
||||
#define EVALDEEP_VECTOR 5
|
||||
#define EVALDEEP_ARRAY 5
|
||||
#define EVALDEEP_VECTORMAP 5
|
||||
#define EVALDEEP_ARRAYMAP 5
|
||||
#define EVALDEEP_INDEX 5
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SIMPLIFIERS MUST BE CODED AS STATE MACHINES -- THEY'LL BE CALLED MANY TIMES, WITH A 'step' PARAMETER
|
||||
// STEP = 0 MEANS BASE SIMPLIFY AND CHECK IF MORE STEPS ARE NEEDED
|
||||
// RETURN NEXT STEP, OR 0 IF NONE
|
||||
// STEP = N MEANS A SIMPLIFY STEP
|
||||
// RETURN NEXT STEP, OR 0 IF NONE
|
||||
// THEY MUST CHANGE 'value' MEMBER OF PASSED VarItem object ON EACH STEP
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppStringSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
enum { SMALL = 0, MEDIUM = 31 }; // SMALL has to be 0 because of GetSpecial and because is it ending zero
|
||||
enum { KIND = 14, SLEN = 15, LLEN = 2, SPECIAL = 13 };
|
||||
union
|
||||
{
|
||||
char chr[16];
|
||||
char *ptr;
|
||||
dword *wptr;
|
||||
qword *qptr;
|
||||
word v[8];
|
||||
dword w[4];
|
||||
qword q[2];
|
||||
} u;
|
||||
|
||||
// see Upp::String code for how it works....
|
||||
MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ")." + "chr");
|
||||
if(!val.IsString())
|
||||
return 0;
|
||||
String chrs = val.ToString();
|
||||
memcpy(u.chr, ~chrs, 16);
|
||||
|
||||
bool isSmall = (u.chr[14] == 0);
|
||||
String s;
|
||||
if(isSmall)
|
||||
{
|
||||
byte len = u.chr[SLEN];
|
||||
s = chrs.Left(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
dword len = u.w[LLEN];
|
||||
MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ").ptr[0]@" + FormatInt(len));
|
||||
if(!val.IsString())
|
||||
return 0;
|
||||
s = val.ToString();
|
||||
}
|
||||
varItem.value = "\"" + s + "\"";
|
||||
varItem.kind = VarItem::SIMPLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppVectorSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::ARRAY;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// just getting items count...
|
||||
if(step == 1)
|
||||
{
|
||||
// initialize default value
|
||||
varItem.value = "<can't evaluate>";
|
||||
|
||||
// get items count
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".items");
|
||||
if(val.IsError() || !val.IsString())
|
||||
return 0;
|
||||
varItem.items = atoi(val.ToString());
|
||||
|
||||
// update value
|
||||
varItem.value = Format("Upp::Vector with %d elements", varItem.items, "");
|
||||
|
||||
// if no elements, just quit
|
||||
if(!varItem.items)
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int count = min(EVALDEEP_VECTOR, varItem.items);
|
||||
|
||||
// start from item 0
|
||||
step -= 2;
|
||||
|
||||
// fetch elements, check on first if they're SIMPLE, so displayable
|
||||
VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".vector[%d]", step));
|
||||
if(!vItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
if(vItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = [...]";
|
||||
return 0;
|
||||
}
|
||||
vItem.Simplify();
|
||||
|
||||
if(!step)
|
||||
varItem.value << " = [ ]";
|
||||
|
||||
const char *sep = step ? " , " : "";
|
||||
varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + vItem.value + " ]";
|
||||
if(++step >= count)
|
||||
return 0;
|
||||
else
|
||||
return step + 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppVectorMapSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::MAP;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// just getting items count...
|
||||
if(step == 1)
|
||||
{
|
||||
// initialize default value
|
||||
varItem.value = "<can't evaluate>";
|
||||
|
||||
// get items count
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".key.key.items");
|
||||
if(val.IsError() || !val.IsString())
|
||||
return 0;
|
||||
varItem.items = atoi(val.ToString());
|
||||
|
||||
// update value
|
||||
varItem.value = Format("Upp::VectorMap with %d elements", varItem.items, "");
|
||||
|
||||
// if no elements, just quit
|
||||
if(!varItem.items)
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int count = min(EVALDEEP_VECTORMAP, varItem.items);
|
||||
|
||||
// start from item 0
|
||||
step -= 2;
|
||||
|
||||
// fetch elements, check on first if they're SIMPLE, so displayable
|
||||
VarItem kItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".key.key.vector[%d]", step));
|
||||
if(!kItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
// for complex types, just return placeholder
|
||||
if(kItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = {...}";
|
||||
return 0;
|
||||
}
|
||||
kItem.Simplify();
|
||||
|
||||
VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".value.vector[%d]", step));
|
||||
if(!vItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
// for complex types, just return placeholder
|
||||
if(vItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = {...}";
|
||||
return 0;
|
||||
}
|
||||
vItem.Simplify();
|
||||
|
||||
if(!step)
|
||||
varItem.value << " = { }";
|
||||
|
||||
const char *sep = step ? " , " : "";
|
||||
varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + "(" + kItem.value + " , " + vItem.value + ") }";
|
||||
if(++step >= count)
|
||||
return 0;
|
||||
else
|
||||
return step + 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppArraySimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::ARRAY;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// just getting items count...
|
||||
if(step == 1)
|
||||
{
|
||||
// initialize default value
|
||||
varItem.value = "<can't evaluate>";
|
||||
|
||||
// get items count
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".vector.items");
|
||||
|
||||
if(val.IsError() || !val.IsString())
|
||||
return 0;
|
||||
varItem.items = atoi(val.ToString());
|
||||
|
||||
// update value
|
||||
varItem.value = Format("Upp::Array with %d elements", varItem.items, "");
|
||||
|
||||
// if no elements, just quit
|
||||
if(!varItem.items)
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int count = min(EVALDEEP_ARRAY, varItem.items);
|
||||
|
||||
// start from item 0
|
||||
step -= 2;
|
||||
|
||||
// fetch elements, check on first if they're SIMPLE, so displayable
|
||||
VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".vector.vector[%d][0]", step));
|
||||
if(!vItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
if(vItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = [...]";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!step)
|
||||
varItem.value << " = [ ]";
|
||||
|
||||
vItem.Simplify();
|
||||
const char *sep = step ? " , " : "";
|
||||
varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + vItem.value + " ]";
|
||||
|
||||
if(++step >= count)
|
||||
return 0;
|
||||
else
|
||||
return step + 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppArrayMapSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::MAP;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// just getting items count...
|
||||
if(step == 1)
|
||||
{
|
||||
// initialize default value
|
||||
varItem.value = "<can't evaluate>";
|
||||
|
||||
// get items count
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".key.key.items");
|
||||
if(val.IsError() || !val.IsString())
|
||||
return 0;
|
||||
varItem.items = atoi(val.ToString());
|
||||
|
||||
// update value
|
||||
varItem.value = Format("Upp::ArrayMap with %d elements", varItem.items, "");
|
||||
|
||||
// if no elements, just quit
|
||||
if(!varItem.items)
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int count = min(EVALDEEP_VECTORMAP, varItem.items);
|
||||
|
||||
// start from item 0
|
||||
step -= 2;
|
||||
|
||||
// fetch elements, check on first if they're SIMPLE, so displayable
|
||||
VarItem kItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".key.key.vector[%d]", step));
|
||||
if(!kItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
// for complex types, just return placeholder
|
||||
if(kItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = {...}";
|
||||
return 0;
|
||||
}
|
||||
kItem.Simplify();
|
||||
|
||||
VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".value.vector.vector[%d][0]", step));
|
||||
if(!vItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
// for complex types, just return placeholder
|
||||
if(vItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = {...}";
|
||||
return 0;
|
||||
}
|
||||
vItem.Simplify();
|
||||
|
||||
if(!step)
|
||||
varItem.value << " = { }";
|
||||
|
||||
const char *sep = step ? " , " : "";
|
||||
varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + "(" + kItem.value + " , " + vItem.value + ") }";
|
||||
if(++step >= count)
|
||||
return 0;
|
||||
else
|
||||
return step + 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppIndexSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::ARRAY;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// just getting items count...
|
||||
if(step == 1)
|
||||
{
|
||||
// initialize default value
|
||||
varItem.value = "<can't evaluate>";
|
||||
|
||||
// get items count
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".key.items");
|
||||
if(val.IsError() || !val.IsString())
|
||||
return 0;
|
||||
varItem.items = atoi(val.ToString());
|
||||
|
||||
// update value
|
||||
varItem.value = Format("Upp::Index with %d elements", varItem.items, "");
|
||||
|
||||
// if no elements, just quit
|
||||
if(!varItem.items)
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int count = min(EVALDEEP_VECTOR, varItem.items);
|
||||
|
||||
// start from item 0
|
||||
step -= 2;
|
||||
|
||||
// fetch elements, check on first if they're SIMPLE, so displayable
|
||||
VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".key.vector[%d]", step));
|
||||
if(!vItem)
|
||||
{
|
||||
varItem.value << " <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
if(vItem.kind != VarItem::SIMPLE)
|
||||
{
|
||||
varItem.value << " = [...]";
|
||||
return 0;
|
||||
}
|
||||
vItem.Simplify();
|
||||
|
||||
if(!step)
|
||||
varItem.value << " = [ ]";
|
||||
|
||||
const char *sep = step ? " , " : "";
|
||||
varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + vItem.value + " ]";
|
||||
if(++step >= count)
|
||||
return 0;
|
||||
else
|
||||
return step + 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppOneSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
// setup item type
|
||||
varItem.kind = VarItem::COMPLEX;
|
||||
|
||||
// if we're just doing first scan phase, signal that we need further evaluation later
|
||||
#ifdef EVALDEEP
|
||||
if(!step)
|
||||
// next step is 1
|
||||
return 1;
|
||||
#else
|
||||
varItem.value = placeHolder;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
// de-reference and forward simplify
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + "." + "ptr");
|
||||
if(val.IsError() || !val.IsString())
|
||||
{
|
||||
varItem.value = "Upp::One<> = <can't evaluate contents>";
|
||||
return 0;
|
||||
}
|
||||
String ptr = val.ToString();
|
||||
if(ptr == "0x0")
|
||||
{
|
||||
varItem.value = "Upp::One<> = <EMPTY>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// replace variable with de-referenced one
|
||||
VarItem vItem(&varItem.Debugger(), "*" + varItem.evaluableExpression + "." + "ptr");
|
||||
varItem = vItem;
|
||||
return varItem.GetSimplifyStep();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppTimeSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression);
|
||||
val.PackNames();
|
||||
int day = atoi(val[0]["day"].ToString());
|
||||
int month = atoi(val[0]["month"].ToString());
|
||||
int year = atoi(val[0]["year"].ToString());
|
||||
int hour = atoi(val["hour"].ToString());
|
||||
int minute = atoi(val["minute"].ToString());
|
||||
int second = atoi(val["second"].ToString());
|
||||
varItem.value = Format("Upp::Time = %02d/%02d/%04d - %02d:%02d:%02d", day, month, year, hour, minute, second);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppDateSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression);
|
||||
val.PackNames();
|
||||
int day = atoi(val["day"].ToString());
|
||||
int month = atoi(val["month"].ToString());
|
||||
int year = atoi(val["year"].ToString());
|
||||
varItem.value = Format("Upp::Date = %02d/%02d/%04d", day, month, year);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int UppValueSimplify(VarItem &varItem, int step)
|
||||
{
|
||||
enum { SMALL = 0, MEDIUM = 31 }; // SMALL has to be 0 because of GetSpecial and because is it ending zero
|
||||
enum { KIND = 14, SLEN = 15, LLEN = 2, SPECIAL = 13 };
|
||||
enum { STRING = 0, REF = 255, VOIDV = 3 };
|
||||
|
||||
// get the embedded 'data' string 'chr' member
|
||||
// it contains info about value type
|
||||
union
|
||||
{
|
||||
char chr[16];
|
||||
char *ptr;
|
||||
dword *wptr;
|
||||
qword *qptr;
|
||||
word v[8];
|
||||
dword w[4];
|
||||
qword q[2];
|
||||
|
||||
int iData;
|
||||
int64 i64Data;
|
||||
double dData;
|
||||
bool bData;
|
||||
struct
|
||||
{
|
||||
byte day;
|
||||
byte month;
|
||||
int16 year;
|
||||
byte hour;
|
||||
byte minute;
|
||||
byte second;
|
||||
};
|
||||
} u;
|
||||
|
||||
// see Upp::String code for how it works....
|
||||
MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ").data.chr");
|
||||
if(!val.IsString())
|
||||
return 0;
|
||||
String chrs = val.ToString();
|
||||
memcpy(u.chr, ~chrs, 16);
|
||||
|
||||
// get value type, among the fixed ones
|
||||
// we could try later to decode registered types....
|
||||
dword type;
|
||||
bool isSpecial = !u.v[7] && u.v[6];
|
||||
if(!isSpecial)
|
||||
type = STRING_V;
|
||||
else
|
||||
{
|
||||
byte st = u.chr[SPECIAL];
|
||||
if(st == REF)
|
||||
{
|
||||
// ptr()->GetType()
|
||||
// by now, just mark as ref...
|
||||
type = REF;
|
||||
}
|
||||
else if(st == VOIDV)
|
||||
type = VOID_V;
|
||||
else
|
||||
type = st;
|
||||
}
|
||||
|
||||
// by now, treat all types beyond VALUEMAP_V as unknown
|
||||
if(type > VALUEMAP_V)
|
||||
type = UNKNOWN_V;
|
||||
|
||||
// now, based on type, we can decode it
|
||||
varItem.kind = VarItem::SIMPLE;
|
||||
switch(type)
|
||||
{
|
||||
case VOID_V:
|
||||
{
|
||||
varItem.value = "<VOID>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case INT_V:
|
||||
{
|
||||
varItem.value = FormatInt(u.iData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case DOUBLE_V:
|
||||
{
|
||||
varItem.value = FormatDouble(u.dData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case STRING_V:
|
||||
{
|
||||
// we simply replace the VarItem with the string
|
||||
VarItem vItem(&varItem.Debugger(), "(" + varItem.evaluableExpression + ").data");
|
||||
vItem.evaluableExpression = varItem.evaluableExpression;
|
||||
vItem.shortExpression = varItem.shortExpression;
|
||||
varItem = vItem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case DATE_V:
|
||||
{
|
||||
varItem.value = Format("Upp::Date = %02d/%02d/%04d", u.day, u.month, u.year);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case TIME_V:
|
||||
{
|
||||
varItem.value = Format("Upp::Time = %02d/%02d/%04d - %02d:%02d:%02d", u.day, u.month, u.year, u.hour, u.minute, u.second);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERROR_V:
|
||||
{
|
||||
varItem.value = "<ERROR_V>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VALUE_V:
|
||||
{
|
||||
varItem.value = "<VALUE_V>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WSTRING_V:
|
||||
{
|
||||
varItem.value = "<WSTRING_V>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VALUEARRAY_V:
|
||||
{
|
||||
varItem.value = "<VALUEARRAY_V>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case INT64_V:
|
||||
{
|
||||
varItem.value = FormatInt64(u.i64Data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BOOL_V:
|
||||
{
|
||||
varItem.value = (u.bData ? "TRUE" : "FALSE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VALUEMAP_V:
|
||||
{
|
||||
varItem.value = "<VALUEMAP_V>";
|
||||
return 0;
|
||||
}
|
||||
|
||||
case UNKNOWN_V:
|
||||
default:
|
||||
{
|
||||
varItem.value = "<UNKNOWN_V>";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
INITIALIZER(UppSimplifiers) {}
|
||||
|
||||
// Register the simplifiers
|
||||
REGISTERSIMPLIFIER("Upp::String" , UppStringSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Vector<" , UppVectorSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::VectorMap<" , UppVectorMapSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Array<" , UppArraySimplify);
|
||||
REGISTERSIMPLIFIER("Upp::ArrayMap<" , UppArrayMapSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Index<" , UppIndexSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::One<" , UppOneSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Time" , UppTimeSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Date" , UppDateSimplify);
|
||||
REGISTERSIMPLIFIER("Upp::Value" , UppValueSimplify);
|
||||
|
|
@ -1,238 +0,0 @@
|
|||
#include "VarItem.h"
|
||||
#include "TypeSimplify.h"
|
||||
|
||||
// constructor
|
||||
VarItem::VarItem(Gdb_MI2 *deb)
|
||||
{
|
||||
debugger = deb;
|
||||
Clear();
|
||||
}
|
||||
|
||||
VarItem::VarItem(Gdb_MI2 *deb, String const &expr)
|
||||
{
|
||||
debugger = deb;
|
||||
Evaluate(expr);
|
||||
}
|
||||
|
||||
// copy
|
||||
VarItem::VarItem(const VarItem &v)
|
||||
{
|
||||
debugger = v.debugger;
|
||||
empty = v.empty;
|
||||
simplifyStep = v.simplifyStep;
|
||||
|
||||
varName = v.varName;
|
||||
|
||||
shortExpression = v.shortExpression;
|
||||
evaluableExpression = v.evaluableExpression;
|
||||
type = v.type;
|
||||
kind = v.kind;
|
||||
value = v.value;
|
||||
numChildren = v.numChildren;
|
||||
items = v.items;
|
||||
}
|
||||
|
||||
// destructor
|
||||
VarItem::~VarItem()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
VarItem const &VarItem::operator=(const VarItem &v)
|
||||
{
|
||||
debugger = v.debugger;
|
||||
empty = v.empty;
|
||||
simplifyStep = v.simplifyStep;
|
||||
|
||||
varName = v.varName;
|
||||
|
||||
shortExpression = v.shortExpression;
|
||||
evaluableExpression = v.evaluableExpression;
|
||||
type = v.type;
|
||||
kind = v.kind;
|
||||
value = v.value;
|
||||
numChildren = v.numChildren;
|
||||
items = v.items;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// clears contents
|
||||
void VarItem::Clear(void)
|
||||
{
|
||||
empty = true;
|
||||
simplifyStep = -1;
|
||||
varName.Clear();
|
||||
shortExpression.Clear();
|
||||
evaluableExpression.Clear();
|
||||
type.Clear();
|
||||
value.Clear();
|
||||
numChildren = 0;
|
||||
items = 0;
|
||||
kind = SIMPLE;
|
||||
}
|
||||
|
||||
bool VarItem::Simplify(void)
|
||||
{
|
||||
// if already simplified, return false
|
||||
if(!simplifyStep)
|
||||
return false;
|
||||
|
||||
// lookup for simplifier
|
||||
TYPE_SIMPLIFIER_HANDLER simplifier = GetSimplifier(type);
|
||||
if(!simplifier)
|
||||
{
|
||||
// none found, mark as already simplifie and leave
|
||||
simplifyStep = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// simplifier found
|
||||
if(simplifyStep == -1)
|
||||
{
|
||||
// fast, non-deep simplification
|
||||
// set simplified to false if need deep one
|
||||
simplifyStep = simplifier(*this, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// slow, deep simplification
|
||||
simplifyStep = simplifier(*this, simplifyStep);
|
||||
}
|
||||
return (simplifyStep != 0);
|
||||
}
|
||||
|
||||
// evaluate an expression usign gdb variables
|
||||
bool VarItem::Evaluate(String const &expr)
|
||||
{
|
||||
Clear();
|
||||
|
||||
// create the variable
|
||||
MIValue var = debugger->MICmd("var-create - * " + expr);
|
||||
if(var.IsError())
|
||||
return false;
|
||||
empty = false;
|
||||
|
||||
// store its name
|
||||
varName = var["name"];
|
||||
|
||||
// store variable name for later cleanup
|
||||
debugger->StoreVariable(varName);
|
||||
|
||||
// store its value
|
||||
value = var["value"];
|
||||
|
||||
// store type
|
||||
type = var["type"];
|
||||
|
||||
// store number of children (temporary number...)
|
||||
// and set temporary object kind
|
||||
numChildren = atoi(var.Get("numchild", "0"));
|
||||
kind = numChildren ? COMPLEX : SIMPLE;
|
||||
|
||||
// get and store expression
|
||||
evaluableExpression = expr;
|
||||
shortExpression = expr;
|
||||
|
||||
// fast simplify known types
|
||||
Simplify();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// fetch variable children
|
||||
Vector<VarItem> VarItem::GetChildren0(MIValue const &val, String const &prePath)
|
||||
{
|
||||
Vector<VarItem> res;
|
||||
|
||||
MIValue const &children = val["children"];
|
||||
if(!children.IsArray())
|
||||
return res;
|
||||
|
||||
for(int iChild = 0; iChild < children.GetCount(); iChild++)
|
||||
{
|
||||
MIValue const &child = children[iChild];
|
||||
|
||||
// for private, protected, public and inherited fake childs, just go deeper
|
||||
String exp = child["exp"];
|
||||
String typ = child.Get("type", "");
|
||||
String nam = child.Get("name");
|
||||
if(exp == "private" || exp == "protected" || exp == "public" || exp == typ)
|
||||
{
|
||||
MIValue val2 = debugger->MICmd("var-list-children 1 " + nam);
|
||||
if(!val2.IsTuple())
|
||||
continue;
|
||||
res.Append(GetChildren0(val2, prePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
VarItem &v = res.Add(VarItem(debugger));
|
||||
v.empty = false;
|
||||
v.varName = nam;
|
||||
v.shortExpression = prePath + "." + exp;
|
||||
v.type = typ;
|
||||
|
||||
v.value = child["value"];
|
||||
v.numChildren = atoi(child.Get("numchild", "0"));
|
||||
v.kind = v.numChildren ? COMPLEX : SIMPLE;
|
||||
|
||||
MIValue vExp = debugger->MICmd("var-info-path-expression " + nam);
|
||||
v.evaluableExpression = vExp.Get("path_expr", "");
|
||||
|
||||
// fast simplify known types
|
||||
Simplify();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// fetch variable children
|
||||
Vector<VarItem> VarItem::GetChildren(void)
|
||||
{
|
||||
Vector<VarItem> res;
|
||||
|
||||
// do not enumerate children for non-complex types
|
||||
// (for arrays and maps just use GetArray and GetMap functions)
|
||||
if(kind != COMPLEX)
|
||||
return res;
|
||||
|
||||
// if no variable name, just return empty array
|
||||
if(varName.IsEmpty())
|
||||
return res;
|
||||
|
||||
// get children of current variable
|
||||
MIValue val = debugger->MICmd("var-list-children 1 " + varName);
|
||||
if(!val.IsTuple())
|
||||
return res;
|
||||
|
||||
res = GetChildren0(val, evaluableExpression);
|
||||
return res;
|
||||
}
|
||||
|
||||
// fetch array elements
|
||||
Vector<VarItem> VarItem::GetArray(int start, int count)
|
||||
{
|
||||
Vector<VarItem> res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// fetch map elements
|
||||
VectorMap<VarItem, VarItem> VarItem::GetMap(int start, int count)
|
||||
{
|
||||
VectorMap<VarItem, VarItem> res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
MIValue VarItem::EvaluateExpression(String const &exp) const
|
||||
{
|
||||
MIValue val = debugger->MICmd("data-evaluate-expression " + exp);
|
||||
if(!val.IsTuple())
|
||||
return MIValue();
|
||||
const MIValue& v = val["value"];
|
||||
if(v.IsError() || !v.IsString())
|
||||
return MIValue();
|
||||
String s = v.ToString();
|
||||
return MIValue(s);
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
#ifndef _ide_Debuggers_VarItem_h_
|
||||
#define _ide_Debuggers_VarItem_h_
|
||||
|
||||
#include <Core/Core.h>
|
||||
using namespace Upp;
|
||||
|
||||
#include "MIValue.h"
|
||||
|
||||
// item for a GDB variable
|
||||
class Gdb_MI2;
|
||||
|
||||
class VarItem : Moveable<VarItem>
|
||||
{
|
||||
private:
|
||||
|
||||
// connected debugger object
|
||||
Gdb_MI2 *debugger;
|
||||
|
||||
// error/empty state
|
||||
bool empty;
|
||||
|
||||
// next simplify step, 0 if completed
|
||||
int simplifyStep;
|
||||
|
||||
// gdb internal variable name
|
||||
String varName;
|
||||
|
||||
// fetch variable children
|
||||
Vector<VarItem> GetChildren0(MIValue const &children, String const &prePath);
|
||||
|
||||
public:
|
||||
typedef enum { SIMPLE, COMPLEX, ARRAY, MAP } VarKind;
|
||||
|
||||
// short name
|
||||
String shortExpression;
|
||||
|
||||
// evaluable expression
|
||||
String evaluableExpression;
|
||||
|
||||
// type
|
||||
String type;
|
||||
|
||||
// kind
|
||||
int kind;
|
||||
|
||||
// value of expression for non-sequence types
|
||||
String value;
|
||||
|
||||
// children
|
||||
int numChildren;
|
||||
|
||||
// number of items for array and maps
|
||||
int items;
|
||||
|
||||
// check if value contains an error
|
||||
bool IsEmpty(void) const { return empty; }
|
||||
bool operator!(void) const { return IsEmpty(); }
|
||||
operator bool() { return !IsEmpty(); }
|
||||
|
||||
// check if value is simplified
|
||||
bool IsSimplified(void) { return simplifyStep == 0; }
|
||||
|
||||
// clears contents
|
||||
void Clear(void);
|
||||
|
||||
// evaluate expression
|
||||
bool Evaluate(String const &expr);
|
||||
|
||||
// deep simplify known types
|
||||
bool Simplify(void);
|
||||
|
||||
// get next simplify step
|
||||
int GetSimplifyStep(void) { return simplifyStep; }
|
||||
|
||||
// constructors
|
||||
VarItem(Gdb_MI2 *dbg);
|
||||
VarItem(Gdb_MI2 *dbg, String const &expr);
|
||||
|
||||
// destructor
|
||||
~VarItem();
|
||||
|
||||
// copy
|
||||
VarItem(const VarItem &v);
|
||||
VarItem const &operator=(const VarItem &v);
|
||||
|
||||
// get children
|
||||
Vector<VarItem>GetChildren(void);
|
||||
|
||||
// fetch array elements
|
||||
Vector<VarItem> GetArray(int start = 0, int count = -1);
|
||||
|
||||
// fetch map elements
|
||||
VectorMap<VarItem, VarItem> GetMap(int start = 0, int count = -1);
|
||||
|
||||
// helpers for simplifiers
|
||||
Gdb_MI2 &Debugger() { return *debugger; }
|
||||
MIValue EvaluateExpression(String const &exp) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -483,7 +483,6 @@ void Ide::SetupFormat() {
|
|||
(ide.mute_sounds, mute_sounds)
|
||||
(ide.wrap_console_text, wrap_console_text)
|
||||
(ide.hydra1_threads, hydra1_threads)
|
||||
(ide.gdbSelector, gdbSelector)
|
||||
(ide.chstyle, chstyle)
|
||||
(ide.console, LinuxHostConsole)
|
||||
(ide.output_per_assembly, output_per_assembly)
|
||||
|
|
|
|||
|
|
@ -430,8 +430,6 @@ public:
|
|||
int debuglock;
|
||||
int hydra1_threads;
|
||||
|
||||
int gdbSelector;
|
||||
|
||||
int chstyle;
|
||||
|
||||
One<IdeDesigner> designer;
|
||||
|
|
|
|||
|
|
@ -589,9 +589,7 @@ LAYOUT(SetupIdeLayout, 512, 264)
|
|||
ITEM(Label, dv___16, SetLabel(t_("HYDRA threads")).LeftPosZ(212, 80).TopPosZ(4, 19))
|
||||
ITEM(EditIntSpin, hydra1_threads, Max(64).Min(1).LeftPosZ(344, 48).TopPosZ(4, 19))
|
||||
ITEM(Option, output_per_assembly, SetLabel(t_("Use unique output directory per assembly (append assembly name to output directory)")).HSizePosZ(4, 4).TopPosZ(224, 16))
|
||||
ITEM(Switch, gdbSelector, SetLabel(t_("Standard\nGDB_MI2 (experimental)")).LeftPosZ(344, 176).TopPosZ(28, 36))
|
||||
ITEM(Label, dv___20, SetLabel(t_("GDB Debugger interface")).LeftPosZ(212, 188).TopPosZ(24, 20))
|
||||
ITEM(Label, dv___21, SetLabel(t_("In editor mode, path for .usc files")).LeftPosZ(4, 192).TopPosZ(244, 20))
|
||||
ITEM(Label, dv___19, SetLabel(t_("In editor mode, path for .usc files")).LeftPosZ(4, 192).TopPosZ(244, 20))
|
||||
ITEM(EditString, uscpath, LeftPosZ(172, 336).TopPosZ(244, 19))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
|
|||
|
|
@ -386,8 +386,6 @@ Ide::Ide()
|
|||
build_start_time = Null;
|
||||
hydra1_threads = CPU_Cores();
|
||||
|
||||
gdbSelector = 0;
|
||||
|
||||
chstyle = 0;
|
||||
|
||||
Sizeable().Zoomable();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue