Debugger: Streamline LLDB input

All options are passed as python hash now.

Change-Id: I1caa049a0f5d49ece4b65e5f560b30a2443070a5
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
hjk
2013-05-07 10:45:53 +02:00
parent 5b99f0cb24
commit 3f0c873796
3 changed files with 243 additions and 166 deletions

View File

@@ -297,7 +297,7 @@ class Debugger(cmd.Cmd):
else: else:
self.report('state="inferiorsetupfailed",msg="%s",exe="%s"' % (error, fileName)) self.report('state="inferiorsetupfailed",msg="%s",exe="%s"' % (error, fileName))
def runEngine(self): def do_runEngine(self, args):
error = lldb.SBError() error = lldb.SBError()
#launchInfo = lldb.SBLaunchInfo(["-s"]) #launchInfo = lldb.SBLaunchInfo(["-s"])
#self.process = self.target.Launch(self.listener, None, None, #self.process = self.target.Launch(self.listener, None, None,
@@ -513,7 +513,7 @@ class Debugger(cmd.Cmd):
def describeBreakpoint(self, bp, modelId): def describeBreakpoint(self, bp, modelId):
cond = bp.GetCondition() cond = bp.GetCondition()
result = '{lldbid="%s"' % bp.GetID() result = 'lldbid="%s"' % bp.GetID()
result += ',modelid="%s"' % modelId result += ',modelid="%s"' % modelId
result += ',hitcount="%s"' % bp.GetHitCount() result += ',hitcount="%s"' % bp.GetHitCount()
result += ',threadid="%s"' % bp.GetThreadID() result += ',threadid="%s"' % bp.GetThreadID()
@@ -536,60 +536,60 @@ class Debugger(cmd.Cmd):
result += ',valid="%s"' % (1 if loc.IsValid() else 0) result += ',valid="%s"' % (1 if loc.IsValid() else 0)
result += ',ignorecount="%s"' % loc.GetIgnoreCount() result += ',ignorecount="%s"' % loc.GetIgnoreCount()
result += ',addr="%s"},' % loc.GetLoadAddress() result += ',addr="%s"},' % loc.GetLoadAddress()
result += ']},' result += '],'
return result return result
def handleBreakpoints(self, toAdd, toChange, toRemove): def do_handleBreakpoints(self, args):
result = "bkpts={added=[" options = eval(args)
result = 'bkpts=['
for bp in options['bkpts']:
operation = bp['operation']
for bp in toAdd: if operation == 'add':
bpType = bp["type"] bpType = bp["type"]
if bpType == BreakpointByFileAndLine: if bpType == BreakpointByFileAndLine:
bpNew = self.target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"])) bpNew = self.target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"]))
elif bpType == BreakpointByFunction: elif bpType == BreakpointByFunction:
bpNew = self.target.BreakpointCreateByName(bp["function"]) bpNew = self.target.BreakpointCreateByName(bp["function"])
elif bpType == BreakpointAtMain: elif bpType == BreakpointAtMain:
bpNew = self.target.BreakpointCreateByName("main", self.target.GetExecutable().GetFilename()) bpNew = self.target.BreakpointCreateByName("main", self.target.GetExecutable().GetFilename())
else: else:
warn("UNKNOWN TYPE") warn("UNKNOWN TYPE")
bpNew.SetIgnoreCount(int(bp["ignorecount"])) bpNew.SetIgnoreCount(int(bp["ignorecount"]))
bpNew.SetCondition(str(bp["condition"])) bpNew.SetCondition(str(bp["condition"]))
bpNew.SetEnabled(int(bp["enabled"])) bpNew.SetEnabled(int(bp["enabled"]))
try: try:
bpNew.SetOneShot(int(bp["oneshot"])) bpNew.SetOneShot(int(bp["oneshot"]))
except: except:
pass pass
#bpNew.SetCallback(breakpoint_function_wrapper, None) #bpNew.SetCallback(breakpoint_function_wrapper, None)
#bpNew.SetCallback(breakpoint_function_wrapper, None) #bpNew.SetCallback(breakpoint_function_wrapper, None)
#"breakpoint command add 1 -o \"import time; print time.asctime()\" #"breakpoint command add 1 -o \"import time; print time.asctime()\"
#cmd = "script print(11111111)" #cmd = "script print(11111111)"
#cmd = "continue" #cmd = "continue"
#self.debugger.HandleCommand( #self.debugger.HandleCommand(
# "breakpoint command add -o 'script onBreak()' %s" % bpNew.GetID()) # "breakpoint command add -o 'script onBreak()' %s" % bpNew.GetID())
result += self.describeBreakpoint(bpNew, bp["modelid"]) result += '{operation="added",%s}' % self.describeBreakpoint(bpNew, bp["modelid"])
result += "],changed=[" elif operation == 'change':
bpChange = self.target.FindBreakpointByID(int(bp["lldbid"]))
bpChange.SetIgnoreCount(int(bp["ignorecount"]))
bpChange.SetCondition(str(bp["condition"]))
bpChange.SetEnabled(int(bp["enabled"]))
try:
bpChange.SetOneShot(int(bp["oneshot"]))
except:
pass
result += '{operation="changed",%s' % self.describeBreakpoint(bpNew, bp["modelid"])
for bp in toChange: elif operation == 'remove':
bpChange = self.target.FindBreakpointByID(int(bp["lldbid"])) bpDead = self.target.BreakpointDelete(int(bp["lldbid"]))
bpChange.SetIgnoreCount(int(bp["ignorecount"])) result += '{operation="removed",modelid="%s"}' % bp["modelid"]
bpChange.SetCondition(str(bp["condition"]))
bpChange.SetEnabled(int(bp["enabled"]))
try:
bpChange.SetOneShot(int(bp["oneshot"]))
except:
pass
result += self.describeBreakpoint(bpChange, bp["modelid"])
result += "],removed=[" result += "]"
for bp in toRemove:
bpDead = self.target.BreakpointDelete(int(bp["lldbid"]))
result += '{modelid="%s"}' % bp["modelid"]
result += "]}"
self.report(result) self.report(result)
def listModules(self): def listModules(self):
result = 'modules=[' result = 'modules=['
for module in self.target.modules: for module in self.target.modules:
@@ -697,15 +697,8 @@ class Debugger(cmd.Cmd):
# Qt Creator internal # Qt Creator internal
def do_setupInferior(self, args): def do_setupInferior(self, args):
fileName = eval(args) options = eval(args)
self.setupInferior(fileName) self.setupInferior(options['executable'])
def do_handleBreakpoints(self, args):
toAdd, toChange, toRemove = eval(args)
self.handleBreakpoints(toAdd, toChange, toRemove)
def do_runEngine(self, args):
self.runEngine()
def do_interrupt(self, args): def do_interrupt(self, args):
self.interruptInferior() self.interruptInferior()
@@ -717,7 +710,7 @@ class Debugger(cmd.Cmd):
self.reportData() self.reportData()
# Convenience # Convenience
def do_bb(self, args): def do_updateData(self, args):
options = eval(args) options = eval(args)
self.expandedINames = set(options['expanded'].split(',')) self.expandedINames = set(options['expanded'].split(','))
self.reportData() self.reportData()
@@ -782,11 +775,15 @@ if __name__ == '__main__':
if rlist: if rlist:
line = sys.stdin.readline() line = sys.stdin.readline()
if line.startswith("db "): if line.startswith("db "):
(cmd, token, extra, cont) = eval(line[3:]) options = eval(line[3:])
db.onecmd("%s %s" % (cmd, extra)) cmd = options['cmd']
db.report('token="%s"' % token) db.onecmd("%s %s" % (cmd, line[3:]))
if len(cont): db.report('token="%s"' % options['token'])
try:
cont = options['continuation']
db.report('continuation="%s"' % cont) db.report('continuation="%s"' % cont)
except:
pass
else: else:
db.onecmd(line) db.onecmd(line)
else: else:

View File

@@ -103,15 +103,12 @@ void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguage
static int token = 1; static int token = 1;
void LldbEngine::runCommand(const QByteArray &functionName, void LldbEngine::runCommand(const Command &command)
const QByteArray &extraArgs, const QByteArray &continuation)
{ {
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
++token; ++token;
QByteArray cmd = "db ['" + functionName + "'," QByteArray cmd = "db {'cmd':'" + command.function + "',"
+ QByteArray::number(token) + "," + command.args + "'token':" + QByteArray::number(token) + "}\n";
+ "'" + extraArgs + "',"
+ "'" + continuation + "']\n";
showMessage(QString::number(token) + _(cmd), LogInput); showMessage(QString::number(token) + _(cmd), LogInput);
m_lldbProc.write(cmd); m_lldbProc.write(cmd);
} }
@@ -132,8 +129,8 @@ void LldbEngine::setupEngine()
{ {
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
m_lldb = startParameters().debuggerCommand; m_lldbBridge = startParameters().debuggerCommand;
showMessage(_("STARTING LLDB ") + m_lldb); showMessage(_("STARTING LLDB ") + m_lldbBridge);
connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)), connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)),
SLOT(handleLldbError(QProcess::ProcessError))); SLOT(handleLldbError(QProcess::ProcessError)));
@@ -148,11 +145,11 @@ void LldbEngine::setupEngine()
SLOT(handleResponse(QByteArray)), Qt::QueuedConnection); SLOT(handleResponse(QByteArray)), Qt::QueuedConnection);
//m_lldbProc.start(m_lldb); //m_lldbProc.start(m_lldb);
m_lldbProc.start(_("/usr/bin/python"), QStringList() << _("-i") << m_lldb); m_lldbProc.start(_("/usr/bin/python"), QStringList() << _("-i") << m_lldbBridge);
if (!m_lldbProc.waitForStarted()) { if (!m_lldbProc.waitForStarted()) {
const QString msg = tr("Unable to start lldb '%1': %2") const QString msg = tr("Unable to start lldb '%1': %2")
.arg(m_lldb, m_lldbProc.errorString()); .arg(m_lldbBridge, m_lldbProc.errorString());
notifyEngineSetupFailed(); notifyEngineSetupFailed();
showMessage(_("ADAPTER START FAILED")); showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty()) if (!msg.isEmpty())
@@ -162,20 +159,21 @@ void LldbEngine::setupEngine()
void LldbEngine::setupInferior() void LldbEngine::setupInferior()
{ {
QString fileName = QFileInfo(startParameters().executable).absoluteFilePath(); QString executable = QFileInfo(startParameters().executable).absoluteFilePath();
runCommand("setupInferior", '"' + fileName.toUtf8() + '"'); runCommand(Command("setupInferior").arg("executable", executable));
} }
void LldbEngine::runEngine() void LldbEngine::runEngine()
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
QByteArray command; Command cmd("handleBreakpoints");
bool done = attemptBreakpointSynchronizationHelper(&command); if (attemptBreakpointSynchronizationHelper(&cmd)) {
if (done)
runEngine2(); runEngine2();
else } else {
runCommand("handleBreakpoints", command, "runEngine2"); cmd.arg("continuation", "runEngine2");
runCommand(cmd);
}
} }
void LldbEngine::runEngine2() void LldbEngine::runEngine2()
@@ -276,23 +274,23 @@ void LldbEngine::executeRunToLine(const ContextData &data)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
runCommand("executeRunToLine", QByteArray::number(data.address) runCommand(Command("executeRunToLine")
+ ",'" + data.fileName.toUtf8() + "'"); .arg("file", data.fileName).arg("line", data.address));
} }
void LldbEngine::executeRunToFunction(const QString &functionName) void LldbEngine::executeRunToFunction(const QString &functionName)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
runCommand("executeRunToFunction", '"' + functionName.toUtf8() + '"'); runCommand(Command("executeRunToFunction").arg("function", functionName));
} }
void LldbEngine::executeJumpToLine(const ContextData &data) void LldbEngine::executeJumpToLine(const ContextData &data)
{ {
resetLocation(); resetLocation();
notifyInferiorRunRequested(); notifyInferiorRunRequested();
runCommand("executeJumpToLine", QByteArray::number(data.address) runCommand(Command("executeJumpToLine")
+ ',' + data.fileName.toUtf8()); .arg("file", data.fileName).arg("line", data.address));
} }
void LldbEngine::activateFrame(int frameIndex) void LldbEngine::activateFrame(int frameIndex)
@@ -301,12 +299,12 @@ void LldbEngine::activateFrame(int frameIndex)
if (state() != InferiorStopOk && state() != InferiorUnrunnable) if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return; return;
runCommand("activateFrame", QByteArray::number(frameIndex)); runCommand(Command("activateFrame").arg("index", frameIndex));
} }
void LldbEngine::selectThread(ThreadId threadId) void LldbEngine::selectThread(ThreadId threadId)
{ {
runCommand("selectThread", QByteArray::number(threadId.raw())); runCommand(Command("selectThread").arg("id", threadId.raw()));
} }
bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
@@ -315,7 +313,7 @@ bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
&& startParameters().startMode != AttachCore; && startParameters().startMode != AttachCore;
} }
bool LldbEngine::attemptBreakpointSynchronizationHelper(QByteArray *command) bool LldbEngine::attemptBreakpointSynchronizationHelper(Command *cmd)
{ {
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
@@ -331,11 +329,8 @@ bool LldbEngine::attemptBreakpointSynchronizationHelper(QByteArray *command)
} }
} }
QByteArray toAdd;
QByteArray toChange;
QByteArray toRemove;
bool done = true; bool done = true;
cmd->beginList("bkpts");
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) { foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
const BreakpointResponse &response = handler->response(id); const BreakpointResponse &response = handler->response(id);
switch (handler->state(id)) { switch (handler->state(id)) {
@@ -345,35 +340,44 @@ bool LldbEngine::attemptBreakpointSynchronizationHelper(QByteArray *command)
break; break;
case BreakpointInsertRequested: case BreakpointInsertRequested:
done = false; done = false;
toAdd += "{\"modelid\":" + id.toByteArray(); cmd->beginGroup()
toAdd += ",\"type\":" + QByteArray::number(handler->type(id)); .arg("operation", "add")
toAdd += ",\"ignorecount\":" + QByteArray::number(handler->ignoreCount(id)); .arg("modelid", id.toByteArray())
toAdd += ",\"condition\":\"" + handler->condition(id) + '"'; .arg("type", handler->type(id))
toAdd += ",\"function\":\"" + handler->functionName(id).toUtf8() + '"'; .arg("ignorecount", handler->ignoreCount(id))
toAdd += ",\"oneshot\":" + QByteArray::number(int(handler->isOneShot(id))); .arg("condition", handler->condition(id))
toAdd += ",\"enabled\":" + QByteArray::number(int(handler->isEnabled(id))); .arg("function", handler->functionName(id).toUtf8())
toAdd += ",\"file\":\"" + handler->fileName(id).toUtf8() + '"'; .arg("oneshot", handler->isOneShot(id))
toAdd += ",\"line\":" + QByteArray::number(handler->lineNumber(id)) + "},"; .arg("enabled", handler->isEnabled(id))
.arg("file", handler->fileName(id).toUtf8())
.arg("line", handler->lineNumber(id))
.endGroup();
handler->notifyBreakpointInsertProceeding(id); handler->notifyBreakpointInsertProceeding(id);
break; break;
case BreakpointChangeRequested: case BreakpointChangeRequested:
done = false; done = false;
toChange += "{\"modelid\":" + id.toByteArray(); cmd->beginGroup()
toChange += ",\"lldbid\":" + response.id.toByteArray(); .arg("operation", "change")
toChange += ",\"type\":" + QByteArray::number(handler->type(id)); .arg("modelid", id.toByteArray())
toChange += ",\"ignorecount\":" + QByteArray::number(handler->ignoreCount(id)); .arg("lldbid", response.id.toByteArray())
toChange += ",\"condition\":\"" + handler->condition(id) + '"'; .arg("type", handler->type(id))
toChange += ",\"function\":\"" + handler->functionName(id).toUtf8() + '"'; .arg("ignorecount", handler->ignoreCount(id))
toChange += ",\"oneshot\":" + QByteArray::number(int(handler->isOneShot(id))); .arg("condition", handler->condition(id))
toChange += ",\"enabled\":" + QByteArray::number(int(handler->isEnabled(id))); .arg("function", handler->functionName(id).toUtf8())
toChange += ",\"file\":\"" + handler->fileName(id).toUtf8() + '"'; .arg("oneshot", handler->isOneShot(id))
toChange += ",\"line\":" + QByteArray::number(handler->lineNumber(id)) + "},"; .arg("enabled", handler->isEnabled(id))
.arg("file", handler->fileName(id).toUtf8())
.arg("line", handler->lineNumber(id))
.endGroup();
handler->notifyBreakpointChangeProceeding(id); handler->notifyBreakpointChangeProceeding(id);
break; break;
case BreakpointRemoveRequested: case BreakpointRemoveRequested:
done = false; done = false;
toRemove += "{\"modelid\":" + id.toByteArray(); cmd->beginGroup()
toRemove += ",\"lldbid\":" + response.id.toByteArray() + "},"; .arg("operation", "remove")
.arg("modelid", id.toByteArray())
.arg("lldbid", response.id.toByteArray())
.endGroup();
handler->notifyBreakpointRemoveProceeding(id); handler->notifyBreakpointRemoveProceeding(id);
break; break;
case BreakpointChangeProceeding: case BreakpointChangeProceeding:
@@ -387,8 +391,7 @@ bool LldbEngine::attemptBreakpointSynchronizationHelper(QByteArray *command)
QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << id << state()); QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << id << state());
} }
} }
if (!done) cmd->endList();
*command = '[' + toAdd + "],[" + toChange + "],[" + toRemove + ']';
return done; return done;
} }
@@ -400,11 +403,10 @@ void LldbEngine::attemptBreakpointSynchronization()
return; return;
} }
QByteArray command; Command cmd("handleBreakpoints");
bool done = attemptBreakpointSynchronizationHelper(&command); if (!attemptBreakpointSynchronizationHelper(&cmd)) {
if (!done) {
showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED")); showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
runCommand("handleBreakpoints", command); runCommand(cmd);
} else { } else {
showMessage(_("BREAKPOINTS ARE SYNCHRONIZED")); showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
} }
@@ -491,23 +493,21 @@ void LldbEngine::refreshMemory(const GdbMi &data)
void LldbEngine::refreshBreakpoints(const GdbMi &bkpts) void LldbEngine::refreshBreakpoints(const GdbMi &bkpts)
{ {
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
GdbMi added = bkpts["added"]; foreach (const GdbMi &bkpt, bkpts.children()) {
GdbMi changed = bkpts["changed"]; QByteArray op = bkpt["operation"].data();
GdbMi removed = bkpts["removed"]; if (op == "added") {
foreach (const GdbMi &bkpt, added.children()) { BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); QTC_CHECK(handler->state(id) == BreakpointInsertProceeding);
QTC_CHECK(handler->state(id) == BreakpointInsertProceeding); updateBreakpointData(bkpt, true);
updateBreakpointData(bkpt, true); } else if (op == "changed") {
} BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
foreach (const GdbMi &bkpt, changed.children()) { QTC_CHECK(handler->state(id) == BreakpointChangeProceeding);
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); updateBreakpointData(bkpt, false);
QTC_CHECK(handler->state(id) == BreakpointChangeProceeding); } else if (op == "removed") {
updateBreakpointData(bkpt, false); BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
} QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding);
foreach (const GdbMi &bkpt, removed.children()) { handler->notifyBreakpointRemoveOk(id);
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); }
QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding);
handler->notifyBreakpointRemoveOk(id);
} }
} }
@@ -544,7 +544,7 @@ void LldbEngine::refreshModules(const GdbMi &modules)
void LldbEngine::requestModuleSymbols(const QString &moduleName) void LldbEngine::requestModuleSymbols(const QString &moduleName)
{ {
runCommand("requestModuleSymbols", '"' + moduleName.toUtf8() + '"'); runCommand(Command("requestModuleSymbols").arg("module", moduleName.toUtf8()));
} }
void LldbEngine::handleListSymbols(const QByteArray &response) void LldbEngine::handleListSymbols(const QByteArray &response)
@@ -672,7 +672,7 @@ void LldbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &
Q_UNUSED(data); Q_UNUSED(data);
Q_UNUSED(flags); Q_UNUSED(flags);
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
runCommand("bb", "{'expanded':'" + handler->expansionRequests() + "'}"); runCommand(Command("updateData").arg("expanded", handler->expansionRequests()));
} }
void LldbEngine::handleLldbError(QProcess::ProcessError error) void LldbEngine::handleLldbError(QProcess::ProcessError error)
@@ -702,7 +702,7 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const
return tr("The Lldb process failed to start. Either the " return tr("The Lldb process failed to start. Either the "
"invoked program '%1' is missing, or you may have insufficient " "invoked program '%1' is missing, or you may have insufficient "
"permissions to invoke the program.") "permissions to invoke the program.")
.arg(m_lldb); .arg(m_lldbBridge);
case QProcess::Crashed: case QProcess::Crashed:
return tr("The Lldb process crashed some time after starting " return tr("The Lldb process crashed some time after starting "
"successfully."); "successfully.");
@@ -742,8 +742,6 @@ void LldbEngine::readLldbStandardOutput()
{ {
QByteArray out = m_lldbProc.readAllStandardOutput(); QByteArray out = m_lldbProc.readAllStandardOutput();
showMessage(_("Lldb stdout: " + out)); showMessage(_("Lldb stdout: " + out));
//qDebug("\nLLDB RAW STDOUT: '%s'", quoteUnprintable(out).constData());
//qDebug("\nBUFFER FROM: '%s'", quoteUnprintable(m_inbuffer).constData());
m_inbuffer.append(out); m_inbuffer.append(out);
while (true) { while (true) {
int pos = m_inbuffer.indexOf("@\n"); int pos = m_inbuffer.indexOf("@\n");
@@ -751,11 +749,8 @@ void LldbEngine::readLldbStandardOutput()
break; break;
QByteArray response = m_inbuffer.left(pos).trimmed(); QByteArray response = m_inbuffer.left(pos).trimmed();
m_inbuffer = m_inbuffer.mid(pos + 2); m_inbuffer = m_inbuffer.mid(pos + 2);
//qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData());
//showMessage(_(response));
emit outputReady(response); emit outputReady(response);
} }
//qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData());
} }
QByteArray LldbEngine::currentOptions() const QByteArray LldbEngine::currentOptions() const
@@ -959,7 +954,7 @@ void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
id = ++m_lastAgentId; id = ++m_lastAgentId;
m_disassemblerAgents.insert(p, id); m_disassemblerAgents.insert(p, id);
} }
runCommand("disassemble", "{\"cookie\":" + QByteArray::number(id) + "}"); runCommand(Command("disassemble").arg("cookie", id));
} }
@@ -972,10 +967,10 @@ void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken,
m_memoryAgents.insert(agent, id); m_memoryAgents.insert(agent, id);
m_memoryAgentTokens.insert(id, editorToken); m_memoryAgentTokens.insert(id, editorToken);
} }
runCommand("readMemory", runCommand(Command("readMemory")
"{\"address\":" + QByteArray::number(addr) + .arg("address", addr)
",\"length\":" + QByteArray::number(length) + .arg("length", length)
",\"cookie\":" + QByteArray::number(id) + "}"); .arg("cookie", id));
} }
void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken, void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
@@ -987,16 +982,16 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
m_memoryAgents.insert(agent, id); m_memoryAgents.insert(agent, id);
m_memoryAgentTokens.insert(id, editorToken); m_memoryAgentTokens.insert(id, editorToken);
} }
runCommand("writeMemory", runCommand(Command("writeMemory")
"{\"address\":" + QByteArray::number(addr) + "" + .arg("address", addr)
",\"data\":\"" + data.toHex() + "\"" + .arg("data", data.toHex())
",\"cookie\":" + QByteArray::number(id) + "}"); .arg("cookie", id));
} }
void LldbEngine::setRegisterValue(int regnr, const QString &value) void LldbEngine::setRegisterValue(int regnr, const QString &value)
{ {
Register reg = registerHandler()->registers().at(regnr); Register reg = registerHandler()->registers().at(regnr);
runCommand("setRegister " + reg.name + ' ' + value.toLatin1()); runCommand(Command("setRegister").arg("name", reg.name).arg("value", value));
} }
@@ -1040,5 +1035,78 @@ DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters)
return new LldbEngine(startParameters); return new LldbEngine(startParameters);
} }
///////////////////////////////////////////////////////////////////////
//
// Command
//
///////////////////////////////////////////////////////////////////////
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, int value) const
{
args.append('\'');
args.append(name);
args.append("':");
args.append(QByteArray::number(value));
args.append(',');
return *this;
}
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QString &value) const
{
return arg(name, value.toUtf8().data());
}
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QByteArray &value) const
{
return arg(name, value.data());
}
const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const char *value) const
{
args.append('\'');
args.append(name);
args.append("':'");
args.append(value);
args.append("',");
return *this;
}
const LldbEngine::Command &LldbEngine::Command::beginList(const char *name) const
{
if (name) {
args += '\'';
args += name;
args += "':";
}
args += '[';
return *this;
}
void LldbEngine::Command::endList() const
{
if (args.endsWith(','))
args.chop(1);
args += "],";
}
const LldbEngine::Command &LldbEngine::Command::beginGroup(const char *name) const
{
if (name) {
args += '\'';
args += name;
args += "':";
}
args += '{';
return *this;
}
void LldbEngine::Command::endGroup() const
{
if (args.endsWith(','))
args.chop(1);
args += "},";
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -48,7 +48,8 @@ namespace Internal {
class WatchData; class WatchData;
class GdbMi; class GdbMi;
/* A debugger engine for using the lldb command line debugger. /* A debugger engine interfacing the LLDB debugger
* using its Python interface.
*/ */
class LldbEngine : public DebuggerEngine class LldbEngine : public DebuggerEngine
@@ -60,6 +61,25 @@ public:
~LldbEngine(); ~LldbEngine();
private: private:
// Convenience struct to build up backend commands.
struct Command
{
Command() {}
Command(const char *f) : function(f) {}
const Command &arg(const char *name, int value) const;
const Command &arg(const char *name, const QString &value) const;
const Command &arg(const char *name, const QByteArray &value) const;
const Command &arg(const char *name, const char *value) const;
const Command &beginList(const char *name = 0) const;
void endList() const;
const Command &beginGroup(const char *name = 0) const;
void endGroup() const;
QByteArray function;
mutable QByteArray args;
};
// DebuggerEngine implementation // DebuggerEngine implementation
void executeStep(); void executeStep();
void executeStepOut(); void executeStepOut();
@@ -88,7 +108,7 @@ private:
bool acceptsBreakpoint(BreakpointModelId id) const; bool acceptsBreakpoint(BreakpointModelId id) const;
void attemptBreakpointSynchronization(); void attemptBreakpointSynchronization();
bool attemptBreakpointSynchronizationHelper(QByteArray *command); bool attemptBreakpointSynchronizationHelper(Command *command);
void assignValueInDebugger(const WatchData *data, void assignValueInDebugger(const WatchData *data,
const QString &expr, const QVariant &value); const QString &expr, const QVariant &value);
@@ -142,13 +162,6 @@ private:
typedef void (LldbEngine::*LldbCommandContinuation)(); typedef void (LldbEngine::*LldbCommandContinuation)();
struct LldbCommand
{
LldbCommand() : token(0) {}
QByteArray command;
int token;
};
QByteArray currentOptions() const; QByteArray currentOptions() const;
void handleStop(const QByteArray &response); void handleStop(const QByteArray &response);
void handleListLocals(const QByteArray &response); void handleListLocals(const QByteArray &response);
@@ -161,14 +174,13 @@ private:
void handleChildren(const WatchData &data0, const GdbMi &item, void handleChildren(const WatchData &data0, const GdbMi &item,
QList<WatchData> *list); QList<WatchData> *list);
void runCommand(const QByteArray &function,
const QByteArray &extraArgs = QByteArray(), void runCommand(const Command &cmd);
const QByteArray &continuation = QByteArray());
QByteArray m_inbuffer; QByteArray m_inbuffer;
QString m_scriptFileName; QString m_scriptFileName;
QProcess m_lldbProc; QProcess m_lldbProc;
QString m_lldb; QString m_lldbBridge;
// FIXME: Make generic. // FIXME: Make generic.
int m_lastAgentId; int m_lastAgentId;