GDB support, continue

This commit is contained in:
Vadim Lopatin 2015-11-16 16:34:07 +03:00
parent 0ebd6c2394
commit be7717e108
5 changed files with 223 additions and 8 deletions

View File

@ -33,6 +33,7 @@
<String>USE_OPENGL</String>
<String>USE_SDL</String>
<String>USE_FREETYPE</String>
<String>USE_GDB_DEBUG</String>
<String>EmbedStandardResources</String>
</VersionIds>
</VersionIds>
@ -192,5 +193,9 @@
<Compile Include="src\dlangide\workspace\workspace.d" />
<Compile Include="src\ddebug\common\debugger.d" />
<Compile Include="src\ddebug\common\queue.d" />
<Compile Include="src\ddebug\gdb\gdbinterface.d" />
</ItemGroup>
<ItemGroup>
<Folder Include="src\ddebug\gdb\" />
</ItemGroup>
</Project>

View File

@ -2,26 +2,106 @@ module ddebug.common.debugger;
import core.thread;
import dlangui.core.logger;
import ddebug.common.queue;
enum ResponseCode : int {
/// Operation finished successfully
Ok = 0,
// more success codes here
/// General purpose failure code
Fail = 1000,
/// method is not implemented
NotImplemented,
/// error running debugger
CannotRunDebugger,
// more error codes here
}
alias Runnable = void delegate();
alias DebuggerResponse = void delegate(ResponseCode code, string msg);
interface Debugger {
/// start debugging
void startDebugging(string executable, string[] args, string workingDir);
void startDebugging(string debuggerExecutable, string executable, string[] args, string workingDir, DebuggerResponse response);
}
interface DebuggerCallback {
/// proxy for debugger interface implementing async calls
class DebuggerProxy : Debugger {
private DebuggerBase _debugger;
private void delegate(Runnable runnable) _callbackDelegate;
this(DebuggerBase debugger, void delegate(Runnable runnable) callbackDelegate) {
_debugger = debugger;
_callbackDelegate = callbackDelegate;
}
void startDebugging(string debuggerExecutable, string executable, string[] args, string workingDir, DebuggerResponse response) {
_debugger.postRequest(delegate() {
_debugger.startDebugging(debuggerExecutable, executable, args, workingDir,
delegate(ResponseCode code, string msg) {
_callbackDelegate( delegate() { response(code, msg); } );
}
);
});
}
}
class DebuggerBase : Thread {
class DebuggerBase : Thread, Debugger {
private bool _stopRequested;
private bool _finished;
protected string _debuggerExecutable;
protected BlockingQueue!Runnable _queue;
void postRequest(Runnable request) {
_queue.put(request);
}
this() {
super(&run);
_queue = new BlockingQueue!Runnable();
}
~this() {
stop();
destroy(_queue);
_queue = null;
}
void stop() {
Log.i("Debugger.stop()");
_stopRequested = true;
_queue.close();
}
protected void onDebuggerThreadStarted() {
}
protected void onDebuggerThreadFinished() {
}
/// thread func: execute all tasks from queue
private void run() {
onDebuggerThreadStarted();
Log.i("Debugger thread started");
while (!_stopRequested) {
Runnable task;
if (_queue.get(task, 0)) {
task();
}
}
Log.i("Debugger thread finished");
_finished = true;
onDebuggerThreadFinished();
}
void startDebugging(string debuggerExecutable, string executable, string[] args, string workingDir, DebuggerResponse response) {
response(ResponseCode.NotImplemented, "Not Implemented");
}
}

View File

@ -82,7 +82,6 @@ class BlockingQueue(T) {
foreach(ref item; items) {
append(item);
}
append(item);
_condition.notifyAll();
}
}
@ -99,7 +98,7 @@ class BlockingQueue(T) {
}
if (timeoutMillis <= 0)
_condition.wait(); // no timeout
else if (!_condition.wait(dur!msecs(timeoutMillis)))
else if (!_condition.wait(dur!"msecs"(timeoutMillis)))
return false; // timeout
if (_readPos < _writePos) {
value = _buffer[_readPos++];
@ -122,7 +121,7 @@ class BlockingQueue(T) {
return true;
if (timeoutMillis <= 0)
_condition.wait(); // no timeout
else if (!_condition.wait(dur!msecs(timeoutMillis)))
else if (!_condition.wait(dur!"msecs"(timeoutMillis)))
return false; // timeout
while (_readPos < _writePos)
values ~= _buffer[_readPos++];

View File

@ -0,0 +1,94 @@
module ddebug.gdb.gdbinterface;
public import ddebug.common.debugger;
import dlangui.core.logger;
import ddebug.common.queue;
import dlangide.builders.extprocess;
import std.utf;
class ConsoleDebuggerInterface : DebuggerBase, TextWriter {
protected ExternalProcess _debuggerProcess;
protected ExternalProcessState runDebuggerProcess(string executable, string[]args, string dir) {
_debuggerProcess = new ExternalProcess();
ExternalProcessState state = _debuggerProcess.run(executable, args, dir, this);
return state;
}
private string[] _stdoutLines;
private char[] _stdoutBuf;
/// return true to clear lines list
protected bool onDebuggerStdoutLines(string[] lines) {
return true;
}
private void onStdoutText(string text) {
_stdoutBuf ~= text;
// pass full lines
int startPos = 0;
bool fullLinesFound = false;
for (int i = 0; i < _stdoutBuf.length; i++) {
if (_stdoutBuf[i] == '\n' || _stdoutBuf[i] == '\r') {
if (i <= startPos)
_stdoutLines ~= "";
else
_stdoutLines ~= _stdoutBuf[startPos .. i].dup;
fullLinesFound = true;
if (i + 1 < _stdoutBuf.length) {
if ((_stdoutBuf[i] == '\n' && _stdoutBuf[i + 1] == '\r')
|| (_stdoutBuf[i] == '\r' && _stdoutBuf[i + 1] == '\n'))
i++;
}
startPos = i + 1;
}
}
if (fullLinesFound) {
for (int i = 0; i + startPos < _stdoutBuf.length; i++)
_stdoutBuf[i] = _stdoutBuf[i + startPos];
_stdoutBuf.length = _stdoutBuf.length - startPos;
if (onDebuggerStdoutLines(_stdoutLines)) {
_stdoutLines.length = 0;
}
}
}
/// log lines
override void writeText(dstring text) {
string text8 = toUTF8(text);
postRequest(delegate() {
onStdoutText(text8);
});
}
}
class GDBInterface : ConsoleDebuggerInterface {
override void startDebugging(string debuggerExecutable, string executable, string[] args, string workingDir, DebuggerResponse response) {
string[] debuggerArgs;
debuggerArgs ~= "--interpreter=mi";
debuggerArgs ~= "--silent";
debuggerArgs ~= "--args";
debuggerArgs ~= executable;
foreach(arg; args)
debuggerArgs ~= arg;
ExternalProcessState state = runDebuggerProcess(debuggerExecutable, debuggerArgs, workingDir);
Log.i("Debugger process state:");
if (state == ExternalProcessState.Running) {
response(ResponseCode.Ok, "Started");
} else {
response(ResponseCode.CannotRunDebugger, "Error while trying to run debugger process");
}
}
override void stop() {
if (_debuggerProcess !is null)
_debuggerProcess.kill();
super.stop();
}
/// return true to clear lines list
override protected bool onDebuggerStdoutLines(string[] lines) {
Log.d("onDebuggerStdout ", lines);
return true;
}
}

View File

@ -59,14 +59,17 @@ extern (C) int UIAppMain(string[] args) {
version(USE_WIN_DEBUG) {
debuggerTest();
}
version(USE_GDB_DEBUG) {
debuggerTest();
}
// create window
Window window = Platform.instance.createWindow("Dlang IDE", null, WindowFlag.Resizable, 800, 600);
// set window icon
window.windowIcon = drawableCache.getImage("dlangui-logo1");
Widget w = new Widget();
pragma(msg, w.click.return_t, "", w.click.params_t);
//Widget w = new Widget();
//pragma(msg, w.click.return_t, "", w.click.params_t);
IDEFrame frame = new IDEFrame(window);
@ -93,6 +96,40 @@ version(USE_WIN_DEBUG) {
}
}
version(USE_GDB_DEBUG) {
void debuggerTest() {
import ddebug.gdb.gdbinterface;
import core.thread;
Log.d("Testing GDB debugger");
DebuggerBase debugger = new DebuggerBase();
debugger.startDebugging("gdb", "test", [], "", delegate(ResponseCode code, string msg) {
Log.d("startDebugging result: ", code, " : ", msg);
//assert(code == ResponseCode.NotImplemented);
});
debugger.stop();
destroy(debugger);
// async
debugger = new GDBInterface();
DebuggerProxy proxy = new DebuggerProxy(debugger, delegate(Runnable runnable) {
runnable();
});
Log.d("calling debugger.start()");
debugger.start();
Log.d("calling proxy.startDebugging()");
proxy.startDebugging("gdb", "/home/lve/src/d/dlangide/test/gdbtest", ["param1", "param2"], "/home/lve/src/d/dlangide/test", delegate(ResponseCode code, string msg) {
Log.d("startDebugging result: ", code, " : ", msg);
//assert(code == ResponseCode.NotImplemented);
});
Thread.sleep(dur!"msecs"(2000));
debugger.stop();
Thread.sleep(dur!"msecs"(2000));
destroy(debugger);
Log.d("Testing of GDB debugger is finished");
}
}
unittest {
void jsonTest() {
import dlangui.core.settings;