mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Ide/Debuggers/Gdb_MI2 : added asynchronous break command - only posix by now
git-svn-id: svn://ultimatepp.org/upp/trunk@6939 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
d907ce7c3b
commit
bf1b0a4bb8
2 changed files with 99 additions and 18 deletions
|
|
@ -40,8 +40,9 @@ void Gdb_MI2::DebugBar(Bar& bar)
|
|||
{
|
||||
bar.Add("Stop debugging", DbgImg::StopDebug(), THISBACK(Stop)).Key(K_SHIFT_F5);
|
||||
bar.Separator();
|
||||
// see note on Run() function -- crashes X on my machine, so removed by now
|
||||
// bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk));
|
||||
#ifdef PLATFORM_POSIX
|
||||
bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk));
|
||||
#endif
|
||||
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 over", DbgImg::StepOver(), THISBACK1(Step, disas.HasFocus() ? "exec-next-instruction" : "exec-next")).Key(K_F10);
|
||||
|
|
@ -160,27 +161,39 @@ void Gdb_MI2::Run()
|
|||
IdeActivateBottom();
|
||||
}
|
||||
|
||||
#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
|
||||
void Gdb_MI2::AsyncBrk()
|
||||
{
|
||||
// send an interrupt command to all running threads
|
||||
StopAllThreads();
|
||||
|
||||
// data must be refreshed
|
||||
dataSynced = false;
|
||||
|
||||
// gdb usually returns to command prompt instantly, BEFORE
|
||||
// giving out stop reason, which we need. So, we wait some
|
||||
// milliseconds and re-read (non blocking) GDB output to get it
|
||||
/*
|
||||
for(int i = 0; i < 20 && !stopped; i++)
|
||||
{
|
||||
Sleep(100);
|
||||
ReadGdb(false);
|
||||
}
|
||||
*/
|
||||
|
||||
// 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.
|
||||
// send interrupt command to debugger
|
||||
if(!InterruptDebugger())
|
||||
return;
|
||||
|
||||
// if successful, wait for some time for 'stopped' flag to become true
|
||||
for(int iMsec = 0; iMsec < 1000; iMsec += 20)
|
||||
{
|
||||
ReadGdb(false);
|
||||
Sleep(20);
|
||||
Ctrl::ProcessEvents();
|
||||
if(stopped)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Gdb_MI2::Stop()
|
||||
{
|
||||
|
|
@ -343,6 +356,13 @@ Gdb_MI2::Gdb_MI2()
|
|||
|
||||
periodic.Set(-50, THISBACK(Periodic));
|
||||
dataSynced = false;
|
||||
|
||||
#ifdef flagMT
|
||||
// no running debug threads
|
||||
runningThreads = 0;
|
||||
stopThreads = false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Gdb_MI2::~Gdb_MI2()
|
||||
|
|
@ -460,6 +480,40 @@ MIValue Gdb_MI2::ParseGdb(String const &output, bool wait)
|
|||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// skip asynchronous responses
|
||||
// in future, we could be gather/use them
|
||||
if(s[0] == '*'|| s[0] == '=')
|
||||
|
|
@ -805,6 +859,7 @@ void Gdb_MI2::LogFrame(String const &msg, MIValue &frame)
|
|||
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)
|
||||
{
|
||||
|
|
@ -838,6 +893,7 @@ void Gdb_MI2::StopAllThreads(void)
|
|||
if(current != "")
|
||||
MICmd("thread-select " + current);
|
||||
}
|
||||
*/
|
||||
|
||||
// check for stop reason
|
||||
void Gdb_MI2::CheckStopReason(void)
|
||||
|
|
@ -856,12 +912,14 @@ void Gdb_MI2::CheckStopReason(void)
|
|||
else
|
||||
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")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,29 @@ class Gdb_MI2 : public Debugger, public ParentCtrl
|
|||
{
|
||||
private:
|
||||
|
||||
// list of processes (and connected thread groups)
|
||||
// used to stop them
|
||||
VectorMap<String, int> processes;
|
||||
|
||||
// multithread support
|
||||
#ifdef flagMT
|
||||
// numbr of running debug threads
|
||||
int runningThreads;
|
||||
|
||||
// flag to signal threads to stop
|
||||
bool stopThreads;
|
||||
|
||||
// mutex and thead object
|
||||
Mutex mutex;
|
||||
Thread debugThread;
|
||||
|
||||
#endif
|
||||
|
||||
// debug break support -- ONLY POSIX, by now
|
||||
#ifdef PLATFORM_POSIX
|
||||
bool InterruptDebugger(void);
|
||||
#endif
|
||||
|
||||
// used to post and kill timed callbacks
|
||||
TimeCallback timeCallback;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue