mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Ide/Debuggers : fixed some bugs in Gdb_MI2 frontend -- removed Asynchronous break because of problems
git-svn-id: svn://ultimatepp.org/upp/trunk@5152 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
74466cf40d
commit
f7679cc1c8
4 changed files with 280 additions and 151 deletions
|
|
@ -40,7 +40,8 @@ void Gdb_MI2::DebugBar(Bar& bar)
|
||||||
{
|
{
|
||||||
bar.Add("Stop debugging", THISBACK(Stop)).Key(K_SHIFT_F5);
|
bar.Add("Stop debugging", THISBACK(Stop)).Key(K_SHIFT_F5);
|
||||||
bar.Separator();
|
bar.Separator();
|
||||||
bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk));
|
// see note on Run() function -- crashes X on my machine, so removed by now
|
||||||
|
// bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk));
|
||||||
bool b = !IdeIsDebugLock();
|
bool b = !IdeIsDebugLock();
|
||||||
bar.Add(b, "Step into", DbgImg::StepInto(), THISBACK1(Step, disas.HasFocus() ? "exec-step-instruction" : "exec-step")).Key(K_F11);
|
bar.Add(b, "Step into", DbgImg::StepInto(), THISBACK1(Step, disas.HasFocus() ? "exec-step-instruction" : "exec-step")).Key(K_F11);
|
||||||
bar.Add(b, "Step over", DbgImg::StepOver(), THISBACK1(Step, disas.HasFocus() ? "exec-next-instruction" : "exec-next")).Key(K_F10);
|
bar.Add(b, "Step over", DbgImg::StepOver(), THISBACK1(Step, disas.HasFocus() ? "exec-next-instruction" : "exec-next")).Key(K_F10);
|
||||||
|
|
@ -73,14 +74,18 @@ bool Gdb_MI2::SetBreakpoint(const String& filename, int line, const String& bp)
|
||||||
// and remove it
|
// and remove it
|
||||||
MIValue brk = bps.FindBreakpoint(file, line);
|
MIValue brk = bps.FindBreakpoint(file, line);
|
||||||
if(!brk.IsEmpty())
|
if(!brk.IsEmpty())
|
||||||
ASSERT(!MICmd(Format("break-delete %s", brk["number"].Get())).IsError());
|
if(!MICmd(Format("break-delete %s", brk["number"].Get())))
|
||||||
|
{
|
||||||
|
Exclamation(t_("Couldn't remove breakpoint"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(bp.IsEmpty())
|
if(bp.IsEmpty())
|
||||||
return true;
|
return true;
|
||||||
else if(bp[0] == 0xe)
|
else if(bp[0] == 0xe)
|
||||||
return !MICmd(Format("break-insert %s:%d", file, line)).IsError();
|
return MICmd(Format("break-insert %s:%d", file, line));
|
||||||
else
|
else
|
||||||
return !MICmd(Format("break-insert -c \"%s\" %s:%d", bp, file, line)).IsError();
|
return MICmd(Format("break-insert -c \"%s\" %s:%d", bp, file, line));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gdb_MI2::RunTo()
|
bool Gdb_MI2::RunTo()
|
||||||
|
|
@ -115,7 +120,15 @@ void Gdb_MI2::Run()
|
||||||
{
|
{
|
||||||
MIValue val;
|
MIValue val;
|
||||||
if(firstRun)
|
if(firstRun)
|
||||||
|
// GDB up to 7.1 has a bug that maps -exec-run ro run, not to run&
|
||||||
|
// making so async mode useless; we use the console run& command instead
|
||||||
|
// 2012-07-08 update : interrupting GDB in async mode without having
|
||||||
|
// 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("exec-run");
|
||||||
|
|
||||||
|
// val = MICmd("interpreter-exec console run&");
|
||||||
|
|
||||||
else
|
else
|
||||||
val = MICmd("exec-continue --all");
|
val = MICmd("exec-continue --all");
|
||||||
int i = 50;
|
int i = 50;
|
||||||
|
|
@ -139,17 +152,8 @@ void Gdb_MI2::Run()
|
||||||
}
|
}
|
||||||
Unlock();
|
Unlock();
|
||||||
if(stopped)
|
if(stopped)
|
||||||
{
|
|
||||||
CheckStopReason();
|
CheckStopReason();
|
||||||
|
|
||||||
// as we are in non-stop mode, to allow async break to work
|
|
||||||
// we shall stop ALL running threads here, otherwise we'll have
|
|
||||||
// problems when single stepping a gui MT app
|
|
||||||
// single step will be done so for a single thread, while other
|
|
||||||
// are idle. Maybe we could make this behaviour optional
|
|
||||||
MICmd("exec-interrupt --all");
|
|
||||||
}
|
|
||||||
|
|
||||||
started = stopped = false;
|
started = stopped = false;
|
||||||
firstRun = false;
|
firstRun = false;
|
||||||
IdeActivateBottom();
|
IdeActivateBottom();
|
||||||
|
|
@ -158,16 +162,18 @@ void Gdb_MI2::Run()
|
||||||
void Gdb_MI2::AsyncBrk()
|
void Gdb_MI2::AsyncBrk()
|
||||||
{
|
{
|
||||||
// send an interrupt command to all running threads
|
// send an interrupt command to all running threads
|
||||||
MICmd("exec-interrupt --all");
|
StopAllThreads();
|
||||||
|
|
||||||
// gdb usually returns to command prompt instantly, BEFORE
|
// gdb usually returns to command prompt instantly, BEFORE
|
||||||
// giving out stop reason, which we need. So, we wait some
|
// giving out stop reason, which we need. So, we wait some
|
||||||
// milliseconds and re-read (non blocking) GDB output to get it
|
// milliseconds and re-read (non blocking) GDB output to get it
|
||||||
|
/*
|
||||||
for(int i = 0; i < 20 && !stopped; i++)
|
for(int i = 0; i < 20 && !stopped; i++)
|
||||||
{
|
{
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
ReadGdb(false);
|
ReadGdb(false);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// if target is correctly stopped, 'stopped' flag should be already set
|
// if target is correctly stopped, 'stopped' flag should be already set
|
||||||
// so we don't care here. If not set, target can't be stopped.
|
// so we don't care here. If not set, target can't be stopped.
|
||||||
|
|
@ -378,8 +384,10 @@ void Gdb_MI2::Unlock()
|
||||||
MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
||||||
{
|
{
|
||||||
MIValue res;
|
MIValue res;
|
||||||
|
|
||||||
// parse result data
|
// parse result data
|
||||||
StringStream ss(output);
|
StringStream ss(output);
|
||||||
|
int iSubstr;
|
||||||
while(!ss.IsEof())
|
while(!ss.IsEof())
|
||||||
{
|
{
|
||||||
String s = TrimBoth(ss.GetLine());
|
String s = TrimBoth(ss.GetLine());
|
||||||
|
|
@ -391,6 +399,11 @@ MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
||||||
stopReason.Clear();
|
stopReason.Clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// 2012-07-08 -- In some cases, GDB output get mixed with app one
|
||||||
|
// so we shall look for 'stop' record in all string,
|
||||||
|
// not just at beginning as it was before
|
||||||
|
// not a wanderful way, as debugger could be tricked by some text...
|
||||||
|
/*
|
||||||
else if(s.StartsWith("*stopped"))
|
else if(s.StartsWith("*stopped"))
|
||||||
{
|
{
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
@ -398,6 +411,14 @@ MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
||||||
stopReason = MIValue(s);
|
stopReason = MIValue(s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
else if( (iSubstr = s.Find("*stopped,reason=")) >= 0)
|
||||||
|
{
|
||||||
|
stopped = true;
|
||||||
|
s = '{' + s.Mid(iSubstr + 9) + '}';
|
||||||
|
stopReason = MIValue(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// skip asynchronous responses
|
// skip asynchronous responses
|
||||||
// in future, we could be gather/use them
|
// in future, we could be gather/use them
|
||||||
|
|
@ -754,14 +775,61 @@ void Gdb_MI2::LogFrame(String const &msg, MIValue &frame)
|
||||||
PutConsole(Format(msg + " at %s, function '%s', file '%s', line %s", addr, function, file, line));
|
PutConsole(Format(msg + " at %s, function '%s', file '%s', line %s", addr, function, file, line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stop all running threads and re-select previous current thread
|
||||||
|
void Gdb_MI2::StopAllThreads(void)
|
||||||
|
{
|
||||||
|
// get thread info for all threads
|
||||||
|
MIValue tInfo = MICmd("thread-info");
|
||||||
|
MIValue &threads = tInfo["threads"];
|
||||||
|
bool someRunning = false;
|
||||||
|
for(int iThread = 0; iThread < threads.GetCount(); iThread++)
|
||||||
|
{
|
||||||
|
if(threads[iThread]["state"].Get() != "stopped")
|
||||||
|
{
|
||||||
|
someRunning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// don't issue any stop command if no threads running
|
||||||
|
// (brings problems....)
|
||||||
|
if(!someRunning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// stores current thread id
|
||||||
|
String current = tInfo("current-thread-id", "");
|
||||||
|
|
||||||
|
// stops all threads
|
||||||
|
MICmd("exec-interrupt --all");
|
||||||
|
|
||||||
|
// just to be sure, reads out GDB output
|
||||||
|
ReadGdb(false);
|
||||||
|
|
||||||
|
// reselect current thread as it was before stopping all others
|
||||||
|
if(current != "")
|
||||||
|
MICmd("thread-select " + current);
|
||||||
|
}
|
||||||
|
|
||||||
// check for stop reason
|
// check for stop reason
|
||||||
void Gdb_MI2::CheckStopReason(void)
|
void Gdb_MI2::CheckStopReason(void)
|
||||||
{
|
{
|
||||||
|
// we need to store stop reason BEFORE interrupting all other
|
||||||
|
// threads, otherwise it'll be lost
|
||||||
|
MIValue stReason = stopReason;
|
||||||
|
|
||||||
|
// get the reason string
|
||||||
String reason;
|
String reason;
|
||||||
if(stopReason.IsEmpty())
|
if(stReason.IsEmpty())
|
||||||
reason = "unknown reason";
|
reason = "unknown reason";
|
||||||
else
|
else
|
||||||
reason = stopReason["reason"];
|
reason = stReason["reason"];
|
||||||
|
|
||||||
|
// as we are in non-stop mode, to allow async break to work
|
||||||
|
// we shall stop ALL running threads here, otherwise we'll have
|
||||||
|
// problems when single stepping a gui MT app
|
||||||
|
// single step will be done so for a single thread, while other
|
||||||
|
// are idle. Maybe we could make this behaviour optional
|
||||||
|
StopAllThreads();
|
||||||
|
|
||||||
if(reason == "exited-normally")
|
if(reason == "exited-normally")
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
@ -774,21 +842,27 @@ void Gdb_MI2::CheckStopReason(void)
|
||||||
}
|
}
|
||||||
else if(reason == "breakpoint-hit")
|
else if(reason == "breakpoint-hit")
|
||||||
{
|
{
|
||||||
LogFrame("Hit breakpoint", stopReason["frame"]);
|
LogFrame("Hit breakpoint", stReason["frame"]);
|
||||||
|
SyncIde();
|
||||||
|
}
|
||||||
|
else if(reason == "end-stepping-range")
|
||||||
|
{
|
||||||
|
LogFrame("End stepping range", stReason["frame"]);
|
||||||
SyncIde();
|
SyncIde();
|
||||||
}
|
}
|
||||||
else if(reason == "unknown reason")
|
else if(reason == "unknown reason")
|
||||||
{
|
{
|
||||||
PutConsole("Stopped by unknown reason");
|
PutConsole("Stopped by unknown reason");
|
||||||
|
SyncIde();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// weird stop reasons (i.e., signals, segfaults... may not have a frame
|
// weird stop reasons (i.e., signals, segfaults... may not have a frame
|
||||||
// data inside
|
// data inside
|
||||||
if(stopReason.Find("frame") < 0)
|
if(stReason.Find("frame") < 0)
|
||||||
PutConsole(Format("Stopped, reason '%s'", reason));
|
PutConsole(Format("Stopped, reason '%s'", reason));
|
||||||
else
|
else
|
||||||
LogFrame(Format("Stopped, reason '%s'", reason), stopReason["frame"]);
|
LogFrame(Format("Stopped, reason '%s'", reason), stReason["frame"]);
|
||||||
SyncIde();
|
SyncIde();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -808,7 +882,8 @@ void Gdb_MI2::Step(const char *cmd)
|
||||||
}
|
}
|
||||||
if(!started)
|
if(!started)
|
||||||
{
|
{
|
||||||
Exclamation(t_("Failed to start application"));
|
Stop();
|
||||||
|
Exclamation(t_("Step failed - terminating debugger"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,7 +941,11 @@ void Gdb_MI2::DisasFocus()
|
||||||
// create a string representation of frame given its info and args
|
// create a string representation of frame given its info and args
|
||||||
String Gdb_MI2::FormatFrame(MIValue &fInfo, MIValue &fArgs)
|
String Gdb_MI2::FormatFrame(MIValue &fInfo, MIValue &fArgs)
|
||||||
{
|
{
|
||||||
int idx = atoi(fInfo["level"].Get());
|
int idx = atoi(fInfo("level", "-1"));
|
||||||
|
if(idx < 0)
|
||||||
|
return t_("invalid frame info");
|
||||||
|
if(!fArgs.IsArray())
|
||||||
|
return t_("invalid frame args");
|
||||||
String func = fInfo("func", "<unknown>");
|
String func = fInfo("func", "<unknown>");
|
||||||
String file = fInfo("file", "<unknown>");
|
String file = fInfo("file", "<unknown>");
|
||||||
String line = fInfo("line", "<unknown>");
|
String line = fInfo("line", "<unknown>");
|
||||||
|
|
@ -874,7 +953,7 @@ String Gdb_MI2::FormatFrame(MIValue &fInfo, MIValue &fArgs)
|
||||||
String argLine;
|
String argLine;
|
||||||
for(int iArg = 0; iArg < nArgs; iArg++)
|
for(int iArg = 0; iArg < nArgs; iArg++)
|
||||||
{
|
{
|
||||||
argLine += fArgs[iArg]["name"];
|
argLine += fArgs[iArg]["name"].Get();
|
||||||
if(fArgs[iArg].Find("value") >= 0)
|
if(fArgs[iArg].Find("value") >= 0)
|
||||||
argLine << "=" << fArgs[iArg]["value"];
|
argLine << "=" << fArgs[iArg]["value"];
|
||||||
argLine << ',';
|
argLine << ',';
|
||||||
|
|
@ -892,11 +971,19 @@ void Gdb_MI2::DropFrames()
|
||||||
|
|
||||||
// get a list of frames
|
// get a list of frames
|
||||||
MIValue frameList = MICmd("stack-list-frames")["stack"];
|
MIValue frameList = MICmd("stack-list-frames")["stack"];
|
||||||
frameList.AssertArray();
|
if(frameList.IsError() || !frameList.IsArray())
|
||||||
|
{
|
||||||
|
Exclamation("Couldn't get stack frame list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// get the arguments for all frames, values just for simple types
|
// get the arguments for all frames, values just for simple types
|
||||||
MIValue frameArgs = MICmd("stack-list-arguments 1")["stack-args"];
|
MIValue frameArgs = MICmd("stack-list-arguments 1")["stack-args"];
|
||||||
frameArgs.AssertArray();
|
if(frameArgs.IsError() || !frameArgs.IsArray())
|
||||||
|
{
|
||||||
|
Exclamation("Couldn't get stack arguments list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// fill the droplist
|
// fill the droplist
|
||||||
for(int iFrame = 0; iFrame < frameArgs.GetCount(); iFrame++)
|
for(int iFrame = 0; iFrame < frameArgs.GetCount(); iFrame++)
|
||||||
|
|
@ -912,7 +999,11 @@ void Gdb_MI2::DropFrames()
|
||||||
void Gdb_MI2::ShowFrame()
|
void Gdb_MI2::ShowFrame()
|
||||||
{
|
{
|
||||||
int i = (int)~frame;
|
int i = (int)~frame;
|
||||||
MICmd(Format("stack-select-frame %d", i));
|
if(!MICmd(Format("stack-select-frame %d", i)))
|
||||||
|
{
|
||||||
|
Exclamation(Format(t_("Couldn't select frame #%d"), i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
SyncIde(i);
|
SyncIde(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,6 +1016,11 @@ void Gdb_MI2::dropThreads()
|
||||||
// get a list of all available threads
|
// get a list of all available threads
|
||||||
MIValue tInfo = MICmd("thread-info");
|
MIValue tInfo = MICmd("thread-info");
|
||||||
MIValue &threads = tInfo["threads"];
|
MIValue &threads = tInfo["threads"];
|
||||||
|
if(!tInfo.IsTuple() || !threads.IsArray())
|
||||||
|
{
|
||||||
|
Exclamation(t_("couldn't get thread info"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
int currentId = atoi(tInfo["current-thread-id"].Get());
|
int currentId = atoi(tInfo["current-thread-id"].Get());
|
||||||
for(int iThread = 0; iThread < threads.GetCount(); iThread++)
|
for(int iThread = 0; iThread < threads.GetCount(); iThread++)
|
||||||
{
|
{
|
||||||
|
|
@ -987,9 +1083,11 @@ void Gdb_MI2::UpdateLocalVars(void)
|
||||||
// re-reading as a whole is too time expensive.
|
// re-reading as a whole is too time expensive.
|
||||||
// So, at first we build a list of local variable NAMES only
|
// So, at first we build a list of local variable NAMES only
|
||||||
MIValue iLoc = MICmd("stack-list-variables 0");
|
MIValue iLoc = MICmd("stack-list-variables 0");
|
||||||
if(iLoc.IsEmpty() || iLoc.IsError())
|
if(!iLoc || iLoc.IsEmpty())
|
||||||
return;
|
return;
|
||||||
MIValue &loc = iLoc["variables"];
|
MIValue &loc = iLoc["variables"];
|
||||||
|
if(!loc.IsArray())
|
||||||
|
return;
|
||||||
Index<String>locIdx;
|
Index<String>locIdx;
|
||||||
for(int iLoc = 0; iLoc < loc.GetCount(); iLoc++)
|
for(int iLoc = 0; iLoc < loc.GetCount(); iLoc++)
|
||||||
locIdx.Add(loc[iLoc]["name"]);
|
locIdx.Add(loc[iLoc]["name"]);
|
||||||
|
|
@ -1076,7 +1174,7 @@ void Gdb_MI2::UpdateWatches(void)
|
||||||
|
|
||||||
// sometimes it has problem creating vars... maybe because they're
|
// sometimes it has problem creating vars... maybe because they're
|
||||||
// still not active; we just skip them
|
// still not active; we just skip them
|
||||||
if(var.IsError() || var.IsEmpty())
|
if(!var || var.IsEmpty() || !var.IsTuple())
|
||||||
continue;
|
continue;
|
||||||
watchesNames.Add(var["name"]);
|
watchesNames.Add(var["name"]);
|
||||||
watchesExpressions.Add(exprs[i]);
|
watchesExpressions.Add(exprs[i]);
|
||||||
|
|
@ -1120,7 +1218,7 @@ void Gdb_MI2::UpdateAutos(void)
|
||||||
|
|
||||||
// sometimes it has problem creating vars... maybe because they're
|
// sometimes it has problem creating vars... maybe because they're
|
||||||
// still not active; we just skip them
|
// still not active; we just skip them
|
||||||
if(var.IsError() || var.IsEmpty())
|
if(!var || var.IsEmpty() || !var.IsTuple())
|
||||||
continue;
|
continue;
|
||||||
autosNames.Add(var["name"]);
|
autosNames.Add(var["name"]);
|
||||||
autosExpressions.Add(exprs[i]);
|
autosExpressions.Add(exprs[i]);
|
||||||
|
|
@ -1281,14 +1379,21 @@ String Gdb_MI2::FormatWatchLine(String exp, String const &val, int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deep watch current quickwatch variable
|
// deep watch current quickwatch variable
|
||||||
void Gdb_MI2::WatchDeep(String parentExp, String const &var, int level)
|
void Gdb_MI2::WatchDeep0(String parentExp, String const &var, int level, int &maxRemaining)
|
||||||
{
|
{
|
||||||
|
// avoid endless recursion for circularly linked vars
|
||||||
|
if(--maxRemaining <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
MIValue childInfo = MICmd("var-list-children 1 \"" + var + "\" 0 100");
|
MIValue childInfo = MICmd("var-list-children 1 \"" + var + "\" 0 100");
|
||||||
int nChilds = min(atoi(childInfo["numchild"].Get()), 100);
|
if(!childInfo || !childInfo.IsTuple())
|
||||||
if(nChilds)
|
return;
|
||||||
{
|
int nChilds = min(atoi(childInfo("numchild", "-1")), 100);
|
||||||
|
if(nChilds <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
MIValue &childs = childInfo["children"];
|
MIValue &childs = childInfo["children"];
|
||||||
for(int i = 0; i < childs.GetCount(); i++)
|
for(int i = 0; i < childs.GetCount() && maxRemaining > 0; i++)
|
||||||
{
|
{
|
||||||
MIValue child = childs[i];
|
MIValue child = childs[i];
|
||||||
String exp = child["exp"];
|
String exp = child["exp"];
|
||||||
|
|
@ -1319,11 +1424,19 @@ void Gdb_MI2::WatchDeep(String parentExp, String const &var, int level)
|
||||||
quickwatch.value <<= (String)~quickwatch.value + "\n" + FormatWatchLine(parentExp + exp, type + value, level);
|
quickwatch.value <<= (String)~quickwatch.value + "\n" + FormatWatchLine(parentExp + exp, type + value, level);
|
||||||
|
|
||||||
// recursive deep watch
|
// recursive deep watch
|
||||||
WatchDeep(exp, child["name"], level + 1);
|
WatchDeep0(exp, child["name"], level + 1, maxRemaining);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Gdb_MI2::WatchDeep(String parentExp, String const &name)
|
||||||
|
{
|
||||||
|
// this is to avoid circular endless recursion
|
||||||
|
// we limit the total watched (sub)variables to this count
|
||||||
|
int maxRemaining = 300;
|
||||||
|
|
||||||
|
WatchDeep0(parentExp, name, 1, maxRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
// opens quick watch dialog
|
// opens quick watch dialog
|
||||||
void Gdb_MI2::QuickWatch()
|
void Gdb_MI2::QuickWatch()
|
||||||
{
|
{
|
||||||
|
|
@ -1375,7 +1488,7 @@ void Gdb_MI2::QuickWatch()
|
||||||
quickwatch.value <<= FormatWatchLine(exp, type + value, 0);
|
quickwatch.value <<= FormatWatchLine(exp, type + value, 0);
|
||||||
quickwatch.expression.AddHistory();
|
quickwatch.expression.AddHistory();
|
||||||
String name = v["name"];
|
String name = v["name"];
|
||||||
WatchDeep(exp, name, 1);
|
WatchDeep(exp, name);
|
||||||
MICmd("var-delete " + name);
|
MICmd("var-delete " + name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1612,9 +1725,15 @@ bool Gdb_MI2::Create(One<Host> _host, const String& exefile, const String& cmdli
|
||||||
tab <<= THISBACK(SyncData);
|
tab <<= THISBACK(SyncData);
|
||||||
|
|
||||||
// this one will allow asynchronous break of running app
|
// this one will allow asynchronous break of running app
|
||||||
MICmd("gdb-set target-async 1");
|
// 2012-07-08 -- DISABLED because of GDB bugs...
|
||||||
|
// MICmd("gdb-set target-async 1");
|
||||||
MICmd("gdb-set pagination off");
|
MICmd("gdb-set pagination off");
|
||||||
MICmd("gdb-set non-stop on");
|
|
||||||
|
// Don't enable this one -- brings every sort of bugs with
|
||||||
|
// It was useful to issue Asynchronous break, but too many bugs
|
||||||
|
// to be useable
|
||||||
|
// MICmd("gdb-set non-stop on");
|
||||||
|
|
||||||
// MICmd("gdb-set interactive-mode off");
|
// MICmd("gdb-set interactive-mode off");
|
||||||
|
|
||||||
MICmd("gdb-set disassembly-flavor intel");
|
MICmd("gdb-set disassembly-flavor intel");
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,9 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
||||||
// check for stop reason
|
// check for stop reason
|
||||||
void CheckStopReason(void);
|
void CheckStopReason(void);
|
||||||
|
|
||||||
|
// stop all running threads and re-select previous current thread
|
||||||
|
void StopAllThreads(void);
|
||||||
|
|
||||||
// single step command handler
|
// single step command handler
|
||||||
void Step(const char *cmd);
|
void Step(const char *cmd);
|
||||||
|
|
||||||
|
|
@ -197,7 +200,8 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
||||||
String FormatWatchLine(String exp, String const &val, int level);
|
String FormatWatchLine(String exp, String const &val, int level);
|
||||||
|
|
||||||
// deep watch current quickwatch variable
|
// deep watch current quickwatch variable
|
||||||
void WatchDeep(String parentExp, String const &name, int level = 0);
|
void WatchDeep0(String parentExp, String const &name, int level, int &maxRemaining);
|
||||||
|
void WatchDeep(String parentExp, String const &name);
|
||||||
|
|
||||||
// copy stack frame list to clipboard
|
// copy stack frame list to clipboard
|
||||||
void CopyStack(void);
|
void CopyStack(void);
|
||||||
|
|
|
||||||
|
|
@ -247,13 +247,13 @@ MIValue &MIValue::SetError(String const &msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if value contains an error
|
// check if value contains an error
|
||||||
bool MIValue::IsError(void)
|
bool MIValue::IsError(void) const
|
||||||
{
|
{
|
||||||
return type == MIString && string.StartsWith("error:");
|
return type == MIString && string.StartsWith("error:");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for emptyness
|
// check for emptyness
|
||||||
bool MIValue::IsEmpty(void)
|
bool MIValue::IsEmpty(void) const
|
||||||
{
|
{
|
||||||
return type == MIString && string == "";
|
return type == MIString && string == "";
|
||||||
}
|
}
|
||||||
|
|
@ -261,6 +261,8 @@ bool MIValue::IsEmpty(void)
|
||||||
// simple accessors
|
// simple accessors
|
||||||
int MIValue::GetCount(void) const
|
int MIValue::GetCount(void) const
|
||||||
{
|
{
|
||||||
|
if(IsError())
|
||||||
|
return 0;
|
||||||
if(type == MIArray)
|
if(type == MIArray)
|
||||||
return array.GetCount();
|
return array.GetCount();
|
||||||
else if(type == MITuple)
|
else if(type == MITuple)
|
||||||
|
|
@ -278,6 +280,8 @@ int MIValue::Find(const char *key) const
|
||||||
|
|
||||||
MIValue &MIValue::Get(int i)
|
MIValue &MIValue::Get(int i)
|
||||||
{
|
{
|
||||||
|
if(IsError())
|
||||||
|
return *this;
|
||||||
if(type != MIArray)
|
if(type != MIArray)
|
||||||
return ErrorMIValue("Not an Array value type");
|
return ErrorMIValue("Not an Array value type");
|
||||||
return array[i];
|
return array[i];
|
||||||
|
|
@ -308,7 +312,7 @@ String const &MIValue::Get(void) const
|
||||||
String MIValue::Get(const char *key, const char *def) const
|
String MIValue::Get(const char *key, const char *def) const
|
||||||
{
|
{
|
||||||
if(type != MITuple)
|
if(type != MITuple)
|
||||||
return def;
|
return ErrorMIValue("Not a Tuple value type");
|
||||||
int i = tuple.Find(key);
|
int i = tuple.Find(key);
|
||||||
if(i >= 0)
|
if(i >= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -321,7 +325,7 @@ String MIValue::Get(const char *key, const char *def) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// data dump
|
// data dump
|
||||||
String MIValue::Dump(int level)
|
String MIValue::Dump(int level) const
|
||||||
{
|
{
|
||||||
String spacer(' ', level);
|
String spacer(' ', level);
|
||||||
switch(type)
|
switch(type)
|
||||||
|
|
@ -338,7 +342,7 @@ String MIValue::Dump(int level)
|
||||||
{
|
{
|
||||||
String s1 = spacer + tuple.GetKey(i) + "=";
|
String s1 = spacer + tuple.GetKey(i) + "=";
|
||||||
s += s1;
|
s += s1;
|
||||||
MIValue &val = tuple[i];
|
MIValue const &val = tuple[i];
|
||||||
if(val.type == MIString)
|
if(val.type == MIString)
|
||||||
s += val.Dump();
|
s += val.Dump();
|
||||||
else
|
else
|
||||||
|
|
@ -362,7 +366,7 @@ String MIValue::Dump(int level)
|
||||||
level += 4;
|
level += 4;
|
||||||
for(int i = 0; i < array.GetCount(); i++)
|
for(int i = 0; i < array.GetCount(); i++)
|
||||||
{
|
{
|
||||||
MIValue &val = array[i];
|
MIValue const &val = array[i];
|
||||||
s += val.Dump(level);
|
s += val.Dump(level);
|
||||||
if(val.type != MIString)
|
if(val.type != MIString)
|
||||||
s = s.Left(s.GetCount()-1);
|
s = s.Left(s.GetCount()-1);
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ class MIValue : public Moveable<MIValue>
|
||||||
MIValue &SetError(String const &msg);
|
MIValue &SetError(String const &msg);
|
||||||
|
|
||||||
// check if value contains an error
|
// check if value contains an error
|
||||||
bool IsError(void);
|
bool IsError(void) const;
|
||||||
|
bool operator!(void) const { return IsError(); }
|
||||||
|
operator bool() { return !IsError(); }
|
||||||
|
|
||||||
// check for emptyness
|
// check for emptyness
|
||||||
bool IsEmpty(void);
|
bool IsEmpty(void) const;
|
||||||
|
|
||||||
MIValue &operator=(pick_ MIValue &v);
|
MIValue &operator=(pick_ MIValue &v);
|
||||||
MIValue &operator=(String const &s);
|
MIValue &operator=(String const &s);
|
||||||
|
|
@ -59,15 +61,15 @@ class MIValue : public Moveable<MIValue>
|
||||||
String operator()(const char *key, const char *def) const { return Get(key, def); }
|
String operator()(const char *key, const char *def) const { return Get(key, def); }
|
||||||
|
|
||||||
// some type checking
|
// some type checking
|
||||||
bool IsArray(void) { return type == MIArray; }
|
bool IsArray(void) const { return type == MIArray; }
|
||||||
void AssertArray(void) { ASSERT(type == MIArray); }
|
void AssertArray(void) const { ASSERT(type == MIArray); }
|
||||||
bool IsTuple(void) { return type == MITuple; }
|
bool IsTuple(void) const { return type == MITuple; }
|
||||||
void AssertTuple(void) { ASSERT(type == MITuple); }
|
void AssertTuple(void) const { ASSERT(type == MITuple); }
|
||||||
bool IsString(void) { return type == MIString; }
|
bool IsString(void) const { return type == MIString; }
|
||||||
void AssertString(void) { ASSERT(type == MIString); }
|
void AssertString(void) const { ASSERT(type == MIString); }
|
||||||
|
|
||||||
// data dump
|
// data dump
|
||||||
String Dump(int level = 0);
|
String Dump(int level = 0) const;
|
||||||
|
|
||||||
// finds breakpoint data given file and line
|
// finds breakpoint data given file and line
|
||||||
MIValue &FindBreakpoint(String const &file, int line);
|
MIValue &FindBreakpoint(String const &file, int line);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue