Debugger: Simplify LLDB backend message passing

Change-Id: I3a95d6a21d1da1f0c3df743e6743d3d8e558e967
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
hjk
2013-04-11 17:06:17 +02:00
parent 7c6bb25248
commit 13090b21d1
4 changed files with 227 additions and 283 deletions

View File

@@ -68,11 +68,11 @@ if not cdbLoaded:
# LLDB # LLDB
if not gdbLoaded and not cdbLoaded: if not gdbLoaded and not cdbLoaded:
try: #try:
execfile(os.path.join(currentDir, "lbridge.py")) execfile(os.path.join(currentDir, "lbridge.py"))
lldbLoaded = True lldbLoaded = True
except: #except:
failReasons.append(traceback.format_exc()) # failReasons.append(traceback.format_exc())
# One is sufficient. # One is sufficient.

View File

@@ -1,4 +1,49 @@
import json
import inspect
import os
#import traceback
cdbLoaded = False
lldbLoaded = False
gdbLoaded = False
#######################################################################
#
# Helpers
#
#######################################################################
currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
#print "DIR: %s " % currentDir
def warn(message):
print "XXX: %s\n" % message.encode("latin1")
PointerCode = None
ArrayCode = None
StructCode = None
UnionCode = None
EnumCode = None
FlagsCode = None
FunctionCode = None
IntCode = None
FloatCode = None
VoidCode = None
SetCode = None
RangeCode = None
StringCode = None
BitStringCode = None
ErrorTypeCode = None
MethodCode = None
MethodPointerCode = None
MemberPointerCode = None
ReferenceCode = None
CharCode = None
BoolCode = None
ComplexCode = None
TypedefCode = None
NamespaceCode = None
SimpleValueCode = None # LLDB only
#warn("LOADING LLDB") #warn("LOADING LLDB")
@@ -26,9 +71,6 @@ BreakpointOnQmlSignalEmit = 13
BreakpointAtJavaScriptThrow = 14 BreakpointAtJavaScriptThrow = 14
def dumpJson(stuff):
warn("%s" % json.dumps(stuff, sort_keys=True, indent=4, separators=(',', ': ')))
def registerCommand(name, func): def registerCommand(name, func):
pass pass
@@ -135,9 +177,9 @@ def locationData(options):
return "location={file=\"%s\",line=\"%s\",addr=\"%s\"}," \ return "location={file=\"%s\",line=\"%s\",addr=\"%s\"}," \
% (frame.line_entry.file, frame.line_entry.line, frame.pc) % (frame.line_entry.file, frame.line_entry.line, frame.pc)
def stackData(options): def stackData(options, threadId):
try: try:
thread = lldb.process.GetThreadById(options["threadid"]) thread = lldb.process.GetThreadById(threadId)
except: except:
thread = lldb.process.GetThreadAtIndex(0) thread = lldb.process.GetThreadAtIndex(0)
result = "stack={frames=[" result = "stack={frames=["
@@ -156,29 +198,6 @@ def stackData(options):
result += "],hasmore=\"%s\"}, " % hasmore result += "],hasmore=\"%s\"}, " % hasmore
return result return result
def parseOptions(optionstring):
options = {}
for opt in optionstring.split(","):
try:
key, value = opt.split(":")
options[key] = value
except:
pass
return options
def updateData(parts, localsOptions, stackOptions, threadOptions):
result = "result={";
if parts & 1:
result += bb(localsOptions) + ","
if parts & 2:
result += stackData(parseOptions(stackOptions))
if parts & 4:
result += threadsData(parseOptions(threadOptions))
result += stateData({})
result += locationData({})
result += "}"
return result
def listModules(): def listModules():
result = "result={modules=[" result = "result={modules=["
for module in lldb.target.modules: for module in lldb.target.modules:
@@ -237,8 +256,8 @@ def onBreak():
result = "*stopped,frame={....}" result = "*stopped,frame={....}"
print result print result
def handleBreakpoints(stuff): def handleBreakpoints(opts, toAdd, toChange, toRemove):
todo = json.loads(stuff) #todo = json.loads(stuff)
#dumpJson(todo) #dumpJson(todo)
#target = lldb.debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) #target = lldb.debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)
target = lldb.debugger.GetTargetAtIndex(0) target = lldb.debugger.GetTargetAtIndex(0)
@@ -246,7 +265,7 @@ def handleBreakpoints(stuff):
result = "result={bkpts={added=[" result = "result={bkpts={added=["
for bp in todo["add"]: for bp in toAdd:
bpType = bp["type"] bpType = bp["type"]
if bpType == BreakpointByFileAndLine: if bpType == BreakpointByFileAndLine:
bpNew = target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"])) bpNew = target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"]))
@@ -270,7 +289,7 @@ def handleBreakpoints(stuff):
result += "],changed=[" result += "],changed=["
for bp in todo["change"]: for bp in toChange:
bpChange = target.FindBreakpointByID(int(bp["lldbid"])) bpChange = target.FindBreakpointByID(int(bp["lldbid"]))
bpChange.SetIgnoreCount(int(bp["ignorecount"])) bpChange.SetIgnoreCount(int(bp["ignorecount"]))
bpChange.SetCondition(str(bp["condition"])) bpChange.SetCondition(str(bp["condition"]))
@@ -280,7 +299,7 @@ def handleBreakpoints(stuff):
result += "],removed=[" result += "],removed=["
for bp in todo["remove"]: for bp in toRemove:
bpDead = target.BreakpointDelete(int(bp["lldbid"])) bpDead = target.BreakpointDelete(int(bp["lldbid"]))
result += "{modelid=\"%s\"}" % bp["modelid"] result += "{modelid=\"%s\"}" % bp["modelid"]
@@ -292,66 +311,70 @@ def doSync(func):
func() func()
lldb.debugger.SetAsync(True) lldb.debugger.SetAsync(True)
def createReport(): def createReport(options):
result = "result={" result = "result={"
result += stackData({'threadid': lldb.process.selected_thread.id}) result += bb(options["locals"])
result += stackData(options["stack"], lldb.process.selected_thread.id)
result += threadsData({}) result += threadsData({})
result += stateData({}) result += stateData({})
result += locationData({}) result += locationData({})
result += "token=\"%s\"" % options["token"]
result += "}" result += "}"
return result return result
def executeNext(): def executeNext(opts):
doSync(lldb.thread.StepOver) doSync(lldb.thread.StepOver)
return createReport() return createReport(opts)
def executeNextI(): def executeNextI(opts):
doSync(lldb.thread.StepOver) doSync(lldb.thread.StepOver)
return createReport() return createReport(opts)
def executeStep(): def executeStep(opts):
doSync(lldb.thread.Step) lldb.thread.Step()
return createReport() return createReport(opts)
def executeStepI(): def executeStepI(opts):
doSync(lldb.thread.StepInstOver) doSync(lldb.thread.StepInstOver)
return createReport() return createReport(opts)
def executeStepOut(): def executeStepOut(opts):
doSync(lldb.thread.StepOut) doSync(lldb.thread.StepOut)
return createReport() return createReport(opts)
def executeRunToLine(): def executeRunToLine(opts):
return "result={error={msg='Not implemented'}}" return "result={error={msg='Not implemented'}}"
def executeJumpToLine(): def executeJumpToLine(opts):
return "result={error={msg='Not implemented'}}" return "result={error={msg='Not implemented'}}"
def continueInferior(): def continueInferior(opts):
#lldb.debugger.HandleCommand("process continue") #lldb.debugger.HandleCommand("process continue")
lldb.process.Continue() lldb.process.Continue()
return "result={state='running'}" return "result={state='running'}"
def interruptInferior(): def interruptInferior(opts):
lldb.debugger.SetAsync(False) lldb.debugger.SetAsync(False)
lldb.process.Stop() lldb.process.Stop()
#lldb.process.SendAsyncInterrupt() #lldb.process.SendAsyncInterrupt()
lldb.debugger.SetAsync(True) lldb.debugger.SetAsync(True)
return createReport() return createReport()
def setupInferior(fileName): def setupInferior(opts, fileName):
lldb.debugger.HandleCommand("target create '%s'" % fileName) lldb.debugger.HandleCommand("target create '%s'" % fileName)
return "result={state=\"inferiorsetupok\"}"
def runEngine(): def runEngine(opts):
lldb.debugger.HandleCommand("process launch") lldb.debugger.HandleCommand("process launch")
return "result={state=\"enginerunok\"}"
def activateFrame(frame): def activateFrame(opts, frame):
lldb.debugger.HandleCommand("frame select " + frame) lldb.debugger.HandleCommand("frame select " + frame)
def selectThread(thread): def selectThread(opts, thread):
lldb.debugger.HandleCommand("thread select " + thread) lldb.debugger.HandleCommand("thread select " + thread)
def requestModuleSymbols(frame): def requestModuleSymbols(opts, frame):
lldb.debugger.HandleCommand("target module list " + frame) lldb.debugger.HandleCommand("target module list " + frame)
@@ -402,3 +425,12 @@ if False:
+ "stopreason='${thread.stop-reason}'" + "stopreason='${thread.stop-reason}'"
#+ "returnvalue='${thread.return-value}'" #+ "returnvalue='${thread.return-value}'"
+ "\},") + "\},")
lldbLoaded = True
execfile(os.path.join(currentDir, "dumper.py"))
execfile(os.path.join(currentDir, "qttypes.py"))
bbsetup()
print "result={state=\"enginesetupok\"}"

View File

@@ -68,15 +68,6 @@
#include <stdio.h> #include <stdio.h>
#define DEBUG_SCRIPT 1
#if DEBUG_SCRIPT
# define SDEBUG(s) qDebug() << s
#else
# define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
#define CB(callback) &LldbEngine::callback, STRINGIFY(callback) #define CB(callback) &LldbEngine::callback, STRINGIFY(callback)
namespace Debugger { namespace Debugger {
@@ -119,44 +110,34 @@ void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguage
if (!(languages & CppLanguage)) if (!(languages & CppLanguage))
return; return;
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
//XSDEBUG("LldbEngine::executeDebuggerCommand:" << command);
if (state() == DebuggerNotReady) { if (state() == DebuggerNotReady) {
showMessage(_("LLDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command); showMessage(_("LLDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return; return;
} }
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); runCommand("executeDebuggerCommand", '"' + command.toUtf8() + '"');
postCommand(command.toLatin1(), CB(handleExecuteDebuggerCommand));
} }
void LldbEngine::handleExecuteDebuggerCommand(const LldbResponse &response) static int token = 1;
void LldbEngine::runCommand(const QByteArray &functionName,
const QByteArray &extraArgs)
{ {
Q_UNUSED(response); runSimpleCommand("script " + functionName + "({"
+ currentOptions()
+ ",\"token\":" + QByteArray::number(token) + '}'
+ (extraArgs.isEmpty() ? "" : ',' + extraArgs) + ')');
} }
void LldbEngine::postDirectCommand(const QByteArray &command) void LldbEngine::runSimpleCommand(const QByteArray &command)
{ {
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
showMessage(_(command), LogInput);
m_lldbProc.write(command + '\n');
}
void LldbEngine::postCommand(const QByteArray &command,
LldbCommandCallback callback,
const char *callbackName,
const QVariant &cookie)
{
static int token = 0;
++token;
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
LldbCommand cmd; LldbCommand cmd;
cmd.command = command;
cmd.callback = callback;
cmd.callbackName = callbackName;
cmd.cookie = cookie;
cmd.token = token; cmd.token = token;
cmd.command = command;
m_commands.enqueue(cmd); m_commands.enqueue(cmd);
showMessage(QString::number(token) + _(cmd.command), LogInput); showMessage(QString::number(token) + _(command), LogInput);
m_lldbProc.write(cmd.command + '\n'); m_lldbProc.write(command + '\n');
++token;
} }
void LldbEngine::shutdownInferior() void LldbEngine::shutdownInferior()
@@ -188,12 +169,9 @@ void LldbEngine::setupEngine()
SLOT(readLldbStandardError())); SLOT(readLldbStandardError()));
connect(this, SIGNAL(outputReady(QByteArray)), connect(this, SIGNAL(outputReady(QByteArray)),
SLOT(handleOutput2(QByteArray)), Qt::QueuedConnection); SLOT(handleResponse(QByteArray)), Qt::QueuedConnection);
// We will stop immediately, so setup a proper callback. // We will stop immediately, so setup a proper callback.
LldbCommand cmd;
cmd.callback = &LldbEngine::handleFirstCommand;
m_commands.enqueue(cmd);
m_lldbProc.start(m_lldb); m_lldbProc.start(m_lldb);
@@ -210,28 +188,17 @@ void LldbEngine::setupEngine()
return; return;
} }
postCommand("script execfile('" + // Dummy callback for initial (lldb) prompt.
Core::ICore::resourcePath().toLocal8Bit() + "/dumper/bridge.py')", m_commands.enqueue(LldbCommand());
CB(handleSetupEngine));
}
void LldbEngine::handleSetupEngine(const LldbResponse &response) runSimpleCommand("script execfile(\"" + Core::ICore::resourcePath().toUtf8()
{ + "/dumper/lbridge.py\")");
Q_UNUSED(response);
notifyEngineSetupOk();
} }
void LldbEngine::setupInferior() void LldbEngine::setupInferior()
{ {
QString fileName = QFileInfo(startParameters().executable).absoluteFilePath(); QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
postCommand("script setupInferior('" + fileName.toUtf8() + "')", runCommand("setupInferior", '"' + fileName.toUtf8() + '"');
CB(handleInferiorSetup));
}
void LldbEngine::handleInferiorSetup(const LldbResponse &response)
{
Q_UNUSED(response);
notifyInferiorSetupOk();
} }
void LldbEngine::runEngine() void LldbEngine::runEngine()
@@ -244,73 +211,69 @@ void LldbEngine::runEngine()
void LldbEngine::runEngine2() void LldbEngine::runEngine2()
{ {
showStatusMessage(tr("Running requested..."), 5000); showStatusMessage(tr("Running requested..."), 5000);
postCommand("script runEngine()", CB(handleRunEngine)); runCommand("runEngine");
}
void LldbEngine::handleRunEngine(const LldbResponse &response)
{
Q_UNUSED(response);
notifyEngineRunAndInferiorRunOk();
} }
void LldbEngine::interruptInferior() void LldbEngine::interruptInferior()
{ {
showStatusMessage(tr("Interrupt requested..."), 5000); showStatusMessage(tr("Interrupt requested..."), 5000);
postCommand("script interruptInferior()", CB(handleInferiorInterrupt)); runCommand("interruptInferior");
} }
void LldbEngine::handleInferiorInterrupt(const LldbResponse &response) //void LldbEngine::handleInferiorInterrupt(const QByteArray &response)
{ //{
Q_UNUSED(response); // Q_UNUSED(response);
notifyInferiorStopOk(); // notifyInferiorStopOk();
} //}
void LldbEngine::executeStep() void LldbEngine::executeStep()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeStep()", CB(handleResponse)); runCommand("executeStep");
} }
void LldbEngine::executeStepI() void LldbEngine::executeStepI()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeStepI()", CB(handleResponse)); runCommand("executeStepI");
} }
void LldbEngine::executeStepOut() void LldbEngine::executeStepOut()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeStepOut()", CB(handleResponse)); runCommand("executeStepOut");
} }
void LldbEngine::executeNext() void LldbEngine::executeNext()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeNext()", CB(handleResponse)); runCommand("executeNext");
} }
void LldbEngine::executeNextI() void LldbEngine::executeNextI()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeStepNextI()", CB(handleResponse)); runCommand("executeStepNextI");
} }
void LldbEngine::continueInferior() void LldbEngine::continueInferior()
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script continueInferior()", CB(handleResponse)); runCommand("continueInferior");
} }
void LldbEngine::handleResponse(const LldbResponse &response) void LldbEngine::handleResponse(const QByteArray &response)
{ {
GdbMi all = parseResultFromString(response.data); GdbMi all = parseResultFromString(response);
int token = all.findChild("token").data().toInt();
Q_UNUSED(token);
refreshLocals(all.findChild("data")); refreshLocals(all.findChild("data"));
refreshStack(all.findChild("stack")); refreshStack(all.findChild("stack"));
refreshThreads(all.findChild("threads")); refreshThreads(all.findChild("threads"));
@@ -318,30 +281,32 @@ void LldbEngine::handleResponse(const LldbResponse &response)
refreshState(all.findChild("state")); refreshState(all.findChild("state"));
refreshLocation(all.findChild("location")); refreshLocation(all.findChild("location"));
refreshModules(all.findChild("modules")); refreshModules(all.findChild("modules"));
refreshBreakpoints(all.findChild("bkpts"));
performContinuation();
} }
void LldbEngine::executeRunToLine(const ContextData &data) void LldbEngine::executeRunToLine(const ContextData &data)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeRunToLine(" + QByteArray::number(data.address) runCommand("executeRunToLine", QByteArray::number(data.address)
+ ',' + data.fileName.toUtf8() + ')', CB(handleResponse)); + ",'" + data.fileName.toUtf8() + "'");
} }
void LldbEngine::executeRunToFunction(const QString &functionName) void LldbEngine::executeRunToFunction(const QString &functionName)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeRunToFuntion(" + functionName.toUtf8() + ')', runCommand("executeRunToFunction", '"' + functionName.toUtf8() + '"');
CB(handleResponse));
} }
void LldbEngine::executeJumpToLine(const ContextData &data) void LldbEngine::executeJumpToLine(const ContextData &data)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
postCommand("script executeJumpToLine(" + QByteArray::number(data.address) runCommand("executeJumpToLine", QByteArray::number(data.address)
+ ',' + data.fileName.toUtf8() + ')', CB(handleResponse)); + ',' + data.fileName.toUtf8());
} }
void LldbEngine::activateFrame(int frameIndex) void LldbEngine::activateFrame(int frameIndex)
@@ -350,14 +315,12 @@ void LldbEngine::activateFrame(int frameIndex)
if (state() != InferiorStopOk && state() != InferiorUnrunnable) if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return; return;
postCommand("script activateFrame(" + QByteArray::number(frameIndex) + ')', runCommand("activateFrame", QByteArray::number(frameIndex));
CB(handleResponse));
} }
void LldbEngine::selectThread(ThreadId threadId) void LldbEngine::selectThread(ThreadId threadId)
{ {
postCommand("script selectThread(" + QByteArray::number(threadId.raw()) + ')', runCommand("selectThread", QByteArray::number(threadId.raw()));
CB(handleResponse));
} }
bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
@@ -447,24 +410,10 @@ void LldbEngine::attemptBreakpointSynchronization()
if (!done) { if (!done) {
showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED")); showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
if (!toAdd.isEmpty()) runCommand("handleBreakpoints",
toAdd.chop(1); '[' + toAdd + "],[" + toChange + "],[" + toRemove + ']');
if (!toChange.isEmpty())
toChange.chop(1);
if (!toRemove.isEmpty())
toRemove.chop(1);
QByteArray cmd = "script handleBreakpoints('";
cmd += "{\"add\":[" + toAdd + "]";
cmd += ",\"change\":[" + toChange + "]";
cmd += ",\"remove\":[" + toRemove + "]}')";
postCommand(cmd, CB(handleBreakpointsSynchronized));
} else { } else {
showMessage(_("BREAKPOINTS ARE SYNCHRONIZED")); showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
// d->m_disassemblerAgent.updateBreakpointMarkers();
//LldbResponse dummy;
//handleBreakpointsSynchronized(dummy);
performContinuation();
} }
} }
@@ -521,33 +470,29 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
} }
} }
void LldbEngine::handleBreakpointsSynchronized(const LldbResponse &response) void LldbEngine::refreshBreakpoints(const GdbMi &bkpts)
{ {
BreakHandler *handler = breakHandler(); if (bkpts.isValid()) {
GdbMi all = parseResultFromString(response.data); BreakHandler *handler = breakHandler();
GdbMi bkpts = all.findChild("bkpts"); GdbMi added = bkpts.findChild("added");
GdbMi added = bkpts.findChild("added"); GdbMi changed = bkpts.findChild("changed");
GdbMi changed = bkpts.findChild("changed"); GdbMi removed = bkpts.findChild("removed");
GdbMi removed = bkpts.findChild("removed"); foreach (const GdbMi &bkpt, added.children()) {
foreach (const GdbMi &bkpt, added.children()) { BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data()); QTC_CHECK(handler->state(id) == BreakpointInsertRequested);
QTC_CHECK(handler->state(id) == BreakpointInsertRequested); updateBreakpointData(bkpt, true);
updateBreakpointData(bkpt, true); }
foreach (const GdbMi &bkpt, changed.children()) {
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
QTC_CHECK(handler->state(id) == BreakpointChangeRequested);
updateBreakpointData(bkpt, false);
}
foreach (const GdbMi &bkpt, removed.children()) {
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
QTC_CHECK(handler->state(id) == BreakpointRemoveRequested);
handler->notifyBreakpointRemoveOk(id);
}
} }
foreach (const GdbMi &bkpt, changed.children()) {
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
QTC_CHECK(handler->state(id) == BreakpointChangeRequested);
updateBreakpointData(bkpt, false);
}
foreach (const GdbMi &bkpt, removed.children()) {
BreakpointModelId id = BreakpointModelId(bkpt.findChild("modelid").data());
QTC_CHECK(handler->state(id) == BreakpointRemoveRequested);
handler->notifyBreakpointRemoveOk(id);
}
// Loop.
//attemptBreakpointSynchronization();
performContinuation();
} }
void LldbEngine::loadSymbols(const QString &moduleName) void LldbEngine::loadSymbols(const QString &moduleName)
@@ -561,7 +506,7 @@ void LldbEngine::loadAllSymbols()
void LldbEngine::reloadModules() void LldbEngine::reloadModules()
{ {
postCommand("script listModules()", CB(handleResponse)); runCommand("listModules");
} }
void LldbEngine::refreshModules(const GdbMi &modules) void LldbEngine::refreshModules(const GdbMi &modules)
@@ -583,22 +528,22 @@ void LldbEngine::refreshModules(const GdbMi &modules)
void LldbEngine::requestModuleSymbols(const QString &moduleName) void LldbEngine::requestModuleSymbols(const QString &moduleName)
{ {
postCommand("script requestModuleSymbols(" + moduleName.toUtf8() + ')', runCommand("requestModuleSymbols", '"' + moduleName.toUtf8() + '"');
CB(handleListSymbols), moduleName);
} }
void LldbEngine::handleListSymbols(const LldbResponse &response) void LldbEngine::handleListSymbols(const QByteArray &response)
{ {
GdbMi out; Q_UNUSED(response);
out.fromString(response.data.trimmed()); // GdbMi out;
Symbols symbols; // out.fromString(response.trimmed());
QString moduleName = response.cookie.toString(); // Symbols symbols;
foreach (const GdbMi &item, out.children()) { // QString moduleName = response.cookie.toString();
Symbol symbol; // foreach (const GdbMi &item, out.children()) {
symbol.name = _(item.findChild("name").data()); // Symbol symbol;
symbols.append(symbol); // symbol.name = _(item.findChild("name").data());
} // symbols.append(symbol);
debuggerCore()->showModuleSymbols(moduleName, symbols); // }
// debuggerCore()->showModuleSymbols(moduleName, symbols);
} }
@@ -615,8 +560,8 @@ static QHash<QString, WatchData> m_toolTipCache;
bool LldbEngine::setToolTipExpression(const QPoint &mousePos, bool LldbEngine::setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx) TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx)
{ {
Q_UNUSED(mousePos) Q_UNUSED(mousePos);
Q_UNUSED(editor) Q_UNUSED(editor);
if (state() != InferiorStopOk) { if (state() != InferiorStopOk) {
//SDEBUG("SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED"); //SDEBUG("SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED");
@@ -698,7 +643,7 @@ void LldbEngine::assignValueInDebugger(const Internal::WatchData *, const QStrin
{ {
Q_UNUSED(expression); Q_UNUSED(expression);
Q_UNUSED(value); Q_UNUSED(value);
SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value.toString())); //SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value.toString()));
#if 0 #if 0
m_scriptEngine->evaluate(expression + QLatin1Char('=') + value.toString()); m_scriptEngine->evaluate(expression + QLatin1Char('=') + value.toString());
updateLocals(); updateLocals();
@@ -815,17 +760,29 @@ void LldbEngine::readLldbStandardOutput()
m_inbuffer.append(out); m_inbuffer.append(out);
} }
qDebug("\nBUFFER FROM: '%s'", quoteUnprintable(m_inbuffer).constData()); //showMessage(_("Lldb stdout: " + out));
//qDebug("\nBUFFER FROM: '%s'", quoteUnprintable(m_inbuffer).constData());
while (true) { while (true) {
int pos = m_inbuffer.indexOf("(lldb) "); int pos = m_inbuffer.indexOf("(lldb) ");
if (pos == -1) if (pos == -1)
break; break;
QByteArray response = m_inbuffer.left(pos).trimmed(); QByteArray response = m_inbuffer.left(pos).trimmed();
m_inbuffer = m_inbuffer.mid(pos + 7); m_inbuffer = m_inbuffer.mid(pos + 7);
qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData()); //qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData());
showMessage(_(response));
if (m_commands.isEmpty()) {
QTC_ASSERT(false, qDebug() << "RESPONSE: " << response);
return;
}
LldbCommand cmd = m_commands.dequeue();
// FIXME: Find a way to tell LLDB to no echo input.
if (response.startsWith(cmd.command))
response = response.mid(cmd.command.size());
emit outputReady(response); emit outputReady(response);
} }
qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData()); //qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData());
if (m_inbuffer.isEmpty()) if (m_inbuffer.isEmpty())
return; return;
@@ -856,45 +813,13 @@ void LldbEngine::readLldbStandardOutput()
} }
} }
void LldbEngine::handleOutput2(const QByteArray &data) QByteArray LldbEngine::currentOptions() const
{
LldbResponse response;
response.data = data;
//showMessage(_(data));
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
LldbCommand cmd = m_commands.dequeue();
// FIXME: Find a way to tell LLDB to no echo input.
if (response.data.startsWith(cmd.command))
response.data = response.data.mid(cmd.command.size());
response.cookie = cmd.cookie;
qDebug("\nDEQUE: '%s' -> '%s'", cmd.command.constData(), cmd.callbackName);
if (cmd.callback) {
//qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
// << " RESPONSE: " << response.data;
(this->*cmd.callback)(response);
} else {
qDebug() << "NO CALLBACK FOR RESPONSE: " << response.data;
}
}
void LldbEngine::handleFirstCommand(const LldbResponse &response)
{
Q_UNUSED(response);
}
void LldbEngine::updateAll()
{
updateData(DataKind(LocalsData | StackData | ThreadData));
}
void LldbEngine::updateData(DataKind kind)
{ {
QByteArray localsOptions; QByteArray localsOptions;
QByteArray stackOptions; QByteArray stackOptions;
QByteArray threadsOptions; QByteArray threadsOptions;
if (kind & LocalsData) { {
QByteArray watchers; QByteArray watchers;
//if (!m_toolTipExpression.isEmpty()) //if (!m_toolTipExpression.isEmpty())
// watchers += m_toolTipExpression.toLatin1() // watchers += m_toolTipExpression.toLatin1()
@@ -927,18 +852,24 @@ void LldbEngine::updateData(DataKind kind)
+ "watcher:" + watchers.toHex(); + "watcher:" + watchers.toHex();
} }
if (kind & StackData) { {
int maxdepth = debuggerCore()->action(MaximalStackDepth)->value().toInt(); int maxdepth = debuggerCore()->action(MaximalStackDepth)->value().toInt();
ThreadId curthread = threadsHandler()->currentThread(); ThreadId curthread = threadsHandler()->currentThread();
stackOptions += "maxdepth:" + QByteArray::number(maxdepth); stackOptions += "maxdepth:" + QByteArray::number(maxdepth);
stackOptions += ",curthread:" + QByteArray::number(curthread.raw()); stackOptions += ",curthread:" + QByteArray::number(curthread.raw());
} }
postCommand("script updateData(" + QByteArray::number(kind) + ',' QByteArray result;
+ '\'' + localsOptions + "'," result += "\"locals\":\"" + localsOptions + '"';
+ '\'' + stackOptions + "'," result += ",\"stack\":\"" + stackOptions + '"';
+ '\'' + threadsOptions + "')", result += ",\"threads\":\"" + threadsOptions + '"';
CB(handleResponse));
return result;
}
void LldbEngine::updateAll()
{
runCommand("createReport");
} }
GdbMi LldbEngine::parseResultFromString(QByteArray out) GdbMi LldbEngine::parseResultFromString(QByteArray out)
@@ -1063,6 +994,12 @@ void LldbEngine::refreshState(const GdbMi &reportedState)
QByteArray newState = reportedState.data(); QByteArray newState = reportedState.data();
if (state() == InferiorRunRequested && newState == "running") if (state() == InferiorRunRequested && newState == "running")
notifyInferiorRunOk(); notifyInferiorRunOk();
else if (state() == EngineSetupRequested && newState == "enginesetupok")
notifyEngineSetupOk();
else if (state() == InferiorSetupRequested && newState == "inferiorsetupok")
notifyInferiorSetupOk();
else if (state() == EngineRunRequested && newState == "enginerunok")
notifyEngineRunAndInferiorRunOk();
else if (state() != InferiorStopOk && newState == "stopped") else if (state() != InferiorStopOk && newState == "stopped")
notifyInferiorSpontaneousStop(); notifyInferiorSpontaneousStop();
} }

View File

@@ -47,13 +47,6 @@ class GdbMi;
/* A debugger engine for using the lldb command line debugger. /* A debugger engine for using the lldb command line debugger.
*/ */
class LldbResponse
{
public:
QByteArray data;
QVariant cookie;
};
class LldbEngine : public DebuggerEngine class LldbEngine : public DebuggerEngine
{ {
Q_OBJECT Q_OBJECT
@@ -110,7 +103,6 @@ private:
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
void performContinuation(); void performContinuation();
void handleResponse(const LldbResponse &response);
signals: signals:
void outputReady(const QByteArray &data); void outputReady(const QByteArray &data);
@@ -123,9 +115,7 @@ private:
Q_SLOT void handleLldbError(QProcess::ProcessError error); Q_SLOT void handleLldbError(QProcess::ProcessError error);
Q_SLOT void readLldbStandardOutput(); Q_SLOT void readLldbStandardOutput();
Q_SLOT void readLldbStandardError(); Q_SLOT void readLldbStandardError();
Q_SLOT void handleOutput2(const QByteArray &data); Q_SLOT void handleResponse(const QByteArray &data);
void handleSetupEngine(const LldbResponse &response);
void handleResponse(const QByteArray &ba);
void refreshAll(const GdbMi &all); void refreshAll(const GdbMi &all);
void refreshThreads(const GdbMi &threads); void refreshThreads(const GdbMi &threads);
void refreshStack(const GdbMi &stack); void refreshStack(const GdbMi &stack);
@@ -134,49 +124,34 @@ private:
void refreshState(const GdbMi &state); void refreshState(const GdbMi &state);
void refreshLocation(const GdbMi &location); void refreshLocation(const GdbMi &location);
void refreshModules(const GdbMi &modules); void refreshModules(const GdbMi &modules);
void refreshBreakpoints(const GdbMi &bkpts);
enum DataKind { LocalsData = 1, StackData = 2, ThreadData = 4 };
void updateAll(); void updateAll();
void updateData(DataKind kind);
void handleUpdateData(const LldbResponse &response);
void handleFirstCommand(const LldbResponse &response);
void handleExecuteDebuggerCommand(const LldbResponse &response);
void handleInferiorSetup(const LldbResponse &response);
void handleRunEngine(const LldbResponse &response);
void handleInferiorInterrupt(const LldbResponse &response);
typedef void (LldbEngine::*LldbCommandCallback)
(const LldbResponse &response);
typedef void (LldbEngine::*LldbCommandContinuation)(); typedef void (LldbEngine::*LldbCommandContinuation)();
struct LldbCommand struct LldbCommand
{ {
LldbCommand() : callback(0), callbackName(0), token(0) {} LldbCommand() : token(0) {}
LldbCommandCallback callback;
const char *callbackName;
QByteArray command; QByteArray command;
QVariant cookie;
int token; int token;
}; };
void handleStop(const LldbResponse &response); QByteArray currentOptions() const;
void handleListLocals(const LldbResponse &response); void handleStop(const QByteArray &response);
void handleListModules(const LldbResponse &response); void handleListLocals(const QByteArray &response);
void handleListSymbols(const LldbResponse &response); void handleListModules(const QByteArray &response);
void handleBreakpointsSynchronized(const LldbResponse &response); void handleListSymbols(const QByteArray &response);
void handleBreakpointsSynchronized(const QByteArray &response);
void updateBreakpointData(const GdbMi &bkpt, bool added); void updateBreakpointData(const GdbMi &bkpt, bool added);
void handleUpdateStack(const LldbResponse &response); void handleUpdateStack(const QByteArray &response);
void handleUpdateThreads(const LldbResponse &response); void handleUpdateThreads(const QByteArray &response);
void handleChildren(const WatchData &data0, const GdbMi &item, void handleChildren(const WatchData &data0, const GdbMi &item,
QList<WatchData> *list); QList<WatchData> *list);
void postCommand(const QByteArray &command, void runSimpleCommand(const QByteArray &command);
LldbCommandCallback callback = 0, void runCommand(const QByteArray &function,
const char *callbackName = 0, const QByteArray &extraArgs = QByteArray());
const QVariant &cookie = QVariant());
void postDirectCommand(const QByteArray &command);
GdbMi parseResultFromString(QByteArray out); GdbMi parseResultFromString(QByteArray out);
QQueue<LldbCommand> m_commands; QQueue<LldbCommand> m_commands;