mirror of https://github.com/buggins/dlangide.git
debugger enhancements; compatibility fixes for lldbmi2
This commit is contained in:
parent
3d14caa41f
commit
97a9cd90c8
2
dub.json
2
dub.json
|
@ -12,7 +12,7 @@
|
||||||
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
|
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dlangui": "==0.8.28",
|
"dlangui": "==0.8.29",
|
||||||
"dcd": "~>0.8.0"
|
"dcd": "~>0.8.0"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,9 @@ abstract class ConsoleDebuggerInterface : DebuggerBase, TextWriter {
|
||||||
|
|
||||||
interface TextCommandTarget {
|
interface TextCommandTarget {
|
||||||
/// send command as a text string
|
/// send command as a text string
|
||||||
int sendCommand(string text);
|
int sendCommand(string text, int commandId = 0);
|
||||||
|
/// reserve next command id
|
||||||
|
int reserveCommandId();
|
||||||
}
|
}
|
||||||
|
|
||||||
import std.process;
|
import std.process;
|
||||||
|
@ -90,19 +92,26 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
_requests.setTarget(this);
|
_requests.setTarget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int commandId;
|
// last command id
|
||||||
|
private int _commandId;
|
||||||
|
|
||||||
int sendCommand(string text) {
|
int reserveCommandId() {
|
||||||
|
_commandId++;
|
||||||
|
return _commandId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sendCommand(string text, int id = 0) {
|
||||||
ExternalProcessState state = _debuggerProcess.poll();
|
ExternalProcessState state = _debuggerProcess.poll();
|
||||||
if (state != ExternalProcessState.Running) {
|
if (state != ExternalProcessState.Running) {
|
||||||
_stopRequested = true;
|
_stopRequested = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
commandId++;
|
if (!id)
|
||||||
string cmd = to!string(commandId) ~ text;
|
id = reserveCommandId();
|
||||||
Log.d("GDB command[", commandId, "]> ", text);
|
string cmd = to!string(id) ~ text;
|
||||||
|
Log.d("GDB command[", id, "]> ", text);
|
||||||
sendLine(cmd);
|
sendLine(cmd);
|
||||||
return commandId;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pid terminalPid;
|
Pid terminalPid;
|
||||||
|
@ -212,23 +221,37 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
}
|
}
|
||||||
debuggerArgs ~= "--interpreter=mi";
|
debuggerArgs ~= "--interpreter=mi";
|
||||||
debuggerArgs ~= "--silent";
|
debuggerArgs ~= "--silent";
|
||||||
debuggerArgs ~= "--args";
|
if (!USE_INIT_SEQUENCE) {
|
||||||
debuggerArgs ~= _executableFile;
|
debuggerArgs ~= "--args";
|
||||||
foreach(arg; _executableArgs)
|
debuggerArgs ~= _executableFile;
|
||||||
debuggerArgs ~= arg;
|
foreach(arg; _executableArgs)
|
||||||
|
debuggerArgs ~= arg;
|
||||||
|
}
|
||||||
ExternalProcessState state = runDebuggerProcess(_debuggerExecutable, debuggerArgs, _executableWorkingDir);
|
ExternalProcessState state = runDebuggerProcess(_debuggerExecutable, debuggerArgs, _executableWorkingDir);
|
||||||
Log.i("Debugger process state:");
|
Log.i("Debugger process state:", state);
|
||||||
if (state == ExternalProcessState.Running) {
|
if (USE_INIT_SEQUENCE) {
|
||||||
Thread.sleep(dur!"seconds"(1));
|
if (state == ExternalProcessState.Running) {
|
||||||
_callback.onProgramLoaded(true, true);
|
submitInitRequests();
|
||||||
//sendCommand("-break-insert main");
|
} else {
|
||||||
|
_status = ExecutionStatus.Error;
|
||||||
|
_stopRequested = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_status = ExecutionStatus.Error;
|
if (state == ExternalProcessState.Running) {
|
||||||
_stopRequested = true;
|
Thread.sleep(dur!"seconds"(1));
|
||||||
return;
|
_callback.onProgramLoaded(true, true);
|
||||||
|
//sendCommand("-break-insert main");
|
||||||
|
} else {
|
||||||
|
_status = ExecutionStatus.Error;
|
||||||
|
_stopRequested = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
immutable bool USE_INIT_SEQUENCE = true;
|
||||||
|
|
||||||
override protected void onDebuggerThreadFinished() {
|
override protected void onDebuggerThreadFinished() {
|
||||||
Log.d("Debugger thread finished");
|
Log.d("Debugger thread finished");
|
||||||
if (_debuggerProcess !is null) {
|
if (_debuggerProcess !is null) {
|
||||||
|
@ -273,46 +296,46 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
/// start program execution, can be called after program is loaded
|
/// start program execution, can be called after program is loaded
|
||||||
int _startRequestId;
|
int _startRequestId;
|
||||||
void execStart() {
|
void execStart() {
|
||||||
sendCommand("handle SIGUSR1 nostop noprint");
|
submitRequest("handle SIGUSR1 nostop noprint");
|
||||||
sendCommand("handle SIGUSR2 nostop noprint");
|
submitRequest("handle SIGUSR2 nostop noprint");
|
||||||
_startRequestId = sendCommand("-exec-run");
|
_startRequestId = submitRequest("-exec-run");
|
||||||
}
|
}
|
||||||
|
|
||||||
void execAbort() {
|
void execAbort() {
|
||||||
_startRequestId = sendCommand("-exec-abort");
|
_startRequestId = submitRequest("-exec-abort");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// start program execution, can be called after program is loaded
|
/// start program execution, can be called after program is loaded
|
||||||
int _continueRequestId;
|
int _continueRequestId;
|
||||||
void execContinue() {
|
void execContinue() {
|
||||||
_continueRequestId = sendCommand("-exec-continue");
|
_continueRequestId = submitRequest("-exec-continue");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stop program execution
|
/// stop program execution
|
||||||
int _stopRequestId;
|
int _stopRequestId;
|
||||||
void execStop() {
|
void execStop() {
|
||||||
_continueRequestId = sendCommand("-gdb-exit");
|
_continueRequestId = submitRequest("-gdb-exit");
|
||||||
}
|
}
|
||||||
/// interrupt execution
|
/// interrupt execution
|
||||||
int _pauseRequestId;
|
int _pauseRequestId;
|
||||||
void execPause() {
|
void execPause() {
|
||||||
_pauseRequestId = sendCommand("-exec-interrupt");
|
_pauseRequestId = submitRequest("-exec-interrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step over
|
/// step over
|
||||||
int _stepOverRequestId;
|
int _stepOverRequestId;
|
||||||
void execStepOver(ulong threadId) {
|
void execStepOver(ulong threadId) {
|
||||||
_stepOverRequestId = sendCommand("-exec-next".appendThreadParam(threadId));
|
_stepOverRequestId = submitRequest("-exec-next".appendThreadParam(threadId));
|
||||||
}
|
}
|
||||||
/// step in
|
/// step in
|
||||||
int _stepInRequestId;
|
int _stepInRequestId;
|
||||||
void execStepIn(ulong threadId) {
|
void execStepIn(ulong threadId) {
|
||||||
_stepInRequestId = sendCommand("-exec-step".appendThreadParam(threadId));
|
_stepInRequestId = submitRequest("-exec-step".appendThreadParam(threadId));
|
||||||
}
|
}
|
||||||
/// step out
|
/// step out
|
||||||
int _stepOutRequestId;
|
int _stepOutRequestId;
|
||||||
void execStepOut(ulong threadId) {
|
void execStepOut(ulong threadId) {
|
||||||
_stepOutRequestId = sendCommand("-exec-finish".appendThreadParam(threadId));
|
_stepOutRequestId = submitRequest("-exec-finish".appendThreadParam(threadId));
|
||||||
}
|
}
|
||||||
/// restart
|
/// restart
|
||||||
int _restartRequestId;
|
int _restartRequestId;
|
||||||
|
@ -440,15 +463,15 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
}
|
}
|
||||||
if (breakpointsToDelete.length) {
|
if (breakpointsToDelete.length) {
|
||||||
Log.d("Deleting breakpoints: " ~ breakpointsToDelete);
|
Log.d("Deleting breakpoints: " ~ breakpointsToDelete);
|
||||||
sendCommand(("-break-delete " ~ breakpointsToDelete).dup);
|
submitRequest(("-break-delete " ~ breakpointsToDelete).dup);
|
||||||
}
|
}
|
||||||
if (breakpointsToEnable.length) {
|
if (breakpointsToEnable.length) {
|
||||||
Log.d("Enabling breakpoints: " ~ breakpointsToEnable);
|
Log.d("Enabling breakpoints: " ~ breakpointsToEnable);
|
||||||
sendCommand(("-break-enable " ~ breakpointsToEnable).dup);
|
submitRequest(("-break-enable " ~ breakpointsToEnable).dup);
|
||||||
}
|
}
|
||||||
if (breakpointsToDisable.length) {
|
if (breakpointsToDisable.length) {
|
||||||
Log.d("Disabling breakpoints: " ~ breakpointsToDisable);
|
Log.d("Disabling breakpoints: " ~ breakpointsToDisable);
|
||||||
sendCommand(("-break-disable " ~ breakpointsToDisable).dup);
|
submitRequest(("-break-disable " ~ breakpointsToDisable).dup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,12 +601,118 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
_requests.submit(requests[0]);
|
_requests.submit(requests[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// submit simple text command request
|
||||||
|
int submitRequest(string text) {
|
||||||
|
auto request = new GDBRequest(text);
|
||||||
|
_requests.submit(request);
|
||||||
|
return request.id;
|
||||||
|
}
|
||||||
|
|
||||||
/// request stack trace and local vars for thread and frame
|
/// request stack trace and local vars for thread and frame
|
||||||
void requestDebugContextInfo(ulong threadId, int frame) {
|
void requestDebugContextInfo(ulong threadId, int frame) {
|
||||||
Log.d("requestDebugContextInfo threadId=", threadId, " frame=", frame);
|
Log.d("requestDebugContextInfo threadId=", threadId, " frame=", frame);
|
||||||
submitRequest(new StackListFramesRequest(threadId, frame));
|
submitRequest(new StackListFramesRequest(threadId, frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int initRequestsSuccessful = 0;
|
||||||
|
private int initRequestsError = 0;
|
||||||
|
private int initRequestsWarnings = 0;
|
||||||
|
private int totalInitRequests = 0;
|
||||||
|
private int finishedInitRequests = 0;
|
||||||
|
class GDBInitRequest : GDBRequest {
|
||||||
|
bool _mandatory;
|
||||||
|
this(string cmd, bool mandatory) {
|
||||||
|
command = cmd;
|
||||||
|
_mandatory = mandatory;
|
||||||
|
totalInitRequests++;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void onOtherResult() {
|
||||||
|
initRequestsSuccessful++;
|
||||||
|
finishedInitRequests++;
|
||||||
|
checkFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
override void onResult() {
|
||||||
|
initRequestsSuccessful++;
|
||||||
|
finishedInitRequests++;
|
||||||
|
checkFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// called if resultClass is error
|
||||||
|
override void onError() {
|
||||||
|
if (_mandatory)
|
||||||
|
initRequestsError++;
|
||||||
|
else
|
||||||
|
initRequestsWarnings++;
|
||||||
|
finishedInitRequests++;
|
||||||
|
checkFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkFinished() {
|
||||||
|
if (initRequestsError)
|
||||||
|
initRequestsCompleted(false);
|
||||||
|
else if (finishedInitRequests == totalInitRequests)
|
||||||
|
initRequestsCompleted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initRequestsCompleted(bool successful = true) {
|
||||||
|
Log.d("Init sequence complection result: ", successful);
|
||||||
|
if (successful) {
|
||||||
|
// ok
|
||||||
|
_callback.onProgramLoaded(true, true);
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
_requests.cancelPendingRequests();
|
||||||
|
_status = ExecutionStatus.Error;
|
||||||
|
_stopRequested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void submitInitRequests() {
|
||||||
|
initRequestsSuccessful = 0;
|
||||||
|
initRequestsError = 0;
|
||||||
|
totalInitRequests = 0;
|
||||||
|
initRequestsWarnings = 0;
|
||||||
|
finishedInitRequests = 0;
|
||||||
|
submitRequest(new GDBInitRequest("-environment-cd " ~ quotePathIfNeeded(_executableWorkingDir), true));
|
||||||
|
if (terminalTty)
|
||||||
|
submitRequest(new GDBInitRequest("-inferior-tty-set " ~ terminalTty, true));
|
||||||
|
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set breakpoint pending on", false));
|
||||||
|
submitRequest(new GDBInitRequest("-enable-pretty-printing", false));
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set print object on", false));
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set print sevenbit-strings on", false));
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set host-charset UTF-8", false));
|
||||||
|
//11-gdb-set target-charset WINDOWS-1252
|
||||||
|
//12-gdb-set target-wide-charset UTF-16
|
||||||
|
//13source .gdbinit
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set target-async off", false));
|
||||||
|
submitRequest(new GDBInitRequest("-gdb-set auto-solib-add on", false));
|
||||||
|
if (_executableArgs.length) {
|
||||||
|
char[] buf;
|
||||||
|
for(uint i = 0; i < _executableArgs.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
buf ~= " ";
|
||||||
|
buf ~= quotePathIfNeeded(_executableArgs[i]);
|
||||||
|
}
|
||||||
|
submitRequest(new GDBInitRequest(("-exec-arguments " ~ buf).dup, true));
|
||||||
|
}
|
||||||
|
submitRequest(new GDBInitRequest("-file-exec-and-symbols " ~ quotePathIfNeeded(_executableFile), true));
|
||||||
|
|
||||||
|
//debuggerArgs ~= _executableFile;
|
||||||
|
//foreach(arg; _executableArgs)
|
||||||
|
// debuggerArgs ~= arg;
|
||||||
|
//ExternalProcessState state = runDebuggerProcess(_debuggerExecutable, debuggerArgs, _executableWorkingDir);
|
||||||
|
//17-gdb-show language
|
||||||
|
//18-gdb-set language c
|
||||||
|
//19-interpreter-exec console "p/x (char)-1"
|
||||||
|
//20-data-evaluate-expression "sizeof (void*)"
|
||||||
|
//21-gdb-set language auto
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class ThreadInfoRequest : GDBRequest {
|
class ThreadInfoRequest : GDBRequest {
|
||||||
this() { command = "-thread-info"; }
|
this() { command = "-thread-info"; }
|
||||||
override void onResult() {
|
override void onResult() {
|
||||||
|
@ -655,6 +784,7 @@ class GDBInterface : ConsoleDebuggerInterface, TextCommandTarget {
|
||||||
// (gdb)
|
// (gdb)
|
||||||
void onDebuggerIdle() {
|
void onDebuggerIdle() {
|
||||||
Log.d("GDB idle");
|
Log.d("GDB idle");
|
||||||
|
_requests.targetIsReady();
|
||||||
if (_firstIdle) {
|
if (_firstIdle) {
|
||||||
_firstIdle = false;
|
_firstIdle = false;
|
||||||
return;
|
return;
|
||||||
|
@ -718,6 +848,13 @@ class GDBRequest {
|
||||||
MIValue params;
|
MIValue params;
|
||||||
GDBRequest next;
|
GDBRequest next;
|
||||||
|
|
||||||
|
this() {
|
||||||
|
}
|
||||||
|
|
||||||
|
this(string cmdtext) {
|
||||||
|
command = cmdtext;
|
||||||
|
}
|
||||||
|
|
||||||
/// called if resultClass is done
|
/// called if resultClass is done
|
||||||
void onResult() {
|
void onResult() {
|
||||||
}
|
}
|
||||||
|
@ -737,19 +874,62 @@ class GDBRequest {
|
||||||
|
|
||||||
struct GDBRequestList {
|
struct GDBRequestList {
|
||||||
|
|
||||||
|
private bool _synchronousMode = false;
|
||||||
|
|
||||||
|
void setSynchronousMode(bool flg) {
|
||||||
|
_synchronousMode = flg;
|
||||||
|
_ready = _ready | _synchronousMode;
|
||||||
|
}
|
||||||
|
|
||||||
private TextCommandTarget _target;
|
private TextCommandTarget _target;
|
||||||
private GDBRequest[int] _activeRequests;
|
private GDBRequest[int] _activeRequests;
|
||||||
|
private GDBRequest[] _pendingRequests;
|
||||||
|
|
||||||
|
private bool _ready = false;
|
||||||
|
|
||||||
void setTarget(TextCommandTarget target) {
|
void setTarget(TextCommandTarget target) {
|
||||||
_target = target;
|
_target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void submit(GDBRequest request) {
|
private void executeRequest(GDBRequest request) {
|
||||||
request.id = _target.sendCommand(request.command);
|
request.id = _target.sendCommand(request.command, request.id);
|
||||||
if (request.id)
|
if (request.id)
|
||||||
_activeRequests[request.id] = request;
|
_activeRequests[request.id] = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int submit(GDBRequest request) {
|
||||||
|
if (!request.id)
|
||||||
|
request.id = _target.reserveCommandId();
|
||||||
|
if (Log.traceEnabled)
|
||||||
|
Log.v("submitting request " ~ to!string(request.id) ~ " " ~ request.command);
|
||||||
|
if (_ready || _synchronousMode) {
|
||||||
|
_ready = _synchronousMode;
|
||||||
|
executeRequest(request);
|
||||||
|
} else
|
||||||
|
_pendingRequests ~= request;
|
||||||
|
return request.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (gdb) prompt received
|
||||||
|
void targetIsReady() {
|
||||||
|
_ready = true;
|
||||||
|
if (_pendingRequests.length) {
|
||||||
|
// execute next pending request
|
||||||
|
GDBRequest next = _pendingRequests[0];
|
||||||
|
for (uint i = 0; i + 1 < _pendingRequests.length; i++)
|
||||||
|
_pendingRequests[i] = _pendingRequests[i + 1];
|
||||||
|
_pendingRequests[$ - 1] = null;
|
||||||
|
_pendingRequests.length = _pendingRequests.length - 1;
|
||||||
|
executeRequest(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelPendingRequests() {
|
||||||
|
foreach(ref r; _pendingRequests)
|
||||||
|
r = null; // just to help GC
|
||||||
|
_pendingRequests.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool handleResult(int token, ResultClass resultClass, MIValue params) {
|
bool handleResult(int token, ResultClass resultClass, MIValue params) {
|
||||||
if (token in _activeRequests) {
|
if (token in _activeRequests) {
|
||||||
GDBRequest r = _activeRequests[token];
|
GDBRequest r = _activeRequests[token];
|
||||||
|
|
|
@ -73,8 +73,11 @@ class DebuggerUIHandler : DebuggerCallback, StackFrameSelectedHandler {
|
||||||
_ide.logPanel.logLine("Program is loaded");
|
_ide.logPanel.logLine("Program is loaded");
|
||||||
switchToDebugPerspective();
|
switchToDebugPerspective();
|
||||||
// TODO: check succes status and debug info
|
// TODO: check succes status and debug info
|
||||||
if (_breakpoints.length)
|
if (_breakpoints.length) {
|
||||||
|
Log.v("Setting breakpoints");
|
||||||
_debugger.setBreakpoints(_breakpoints);
|
_debugger.setBreakpoints(_breakpoints);
|
||||||
|
}
|
||||||
|
Log.v("Starting execution");
|
||||||
_debugger.execStart();
|
_debugger.execStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue