Commit 3a9b34f2 authored by hjk's avatar hjk

Debugger: Re-use base infrastructure for LLDB breakpoint handling

Change-Id: If32b1f421e45dc4ee446e193e03c959d7c700948
Reviewed-by: default avatarhjk <hjk@theqtcompany.com>
parent d9af2e05
......@@ -643,7 +643,8 @@ class Dumper(DumperBase):
self.target = self.debugger.CreateTarget(None, None, None, True, error)
if self.target.IsValid():
self.handleBreakpoints(args)
for bp in args['bkpts']:
self.insertBreakpoint(bp)
state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
......@@ -1309,7 +1310,9 @@ class Dumper(DumperBase):
return self.target.BreakpointCreateByName(
"main", self.target.GetExecutable().GetFilename())
def addBreakpoint(self, args):
def insertBreakpoint(self, args):
more = True
modelId = args['modelid']
bpType = args["type"]
if bpType == BreakpointByFileAndLine:
bp = self.target.BreakpointCreateByLocation(
......@@ -1342,68 +1345,45 @@ class Dumper(DumperBase):
bp = self.target.WatchAddress(value.GetLoadAddress(),
value.GetByteSize(), False, True, error)
except:
return self.target.BreakpointCreateByName(None)
bp = self.target.BreakpointCreateByName(None)
else:
# This leaves the unhandled breakpoint in a (harmless)
# "pending" state.
return self.target.BreakpointCreateByName(None)
bp.SetIgnoreCount(int(args["ignorecount"]))
if hasattr(bp, 'SetCondition'):
bp.SetCondition(self.hexdecode(args["condition"]))
bp.SetEnabled(int(args["enabled"]))
if hasattr(bp, 'SetOneShot'):
bp.SetOneShot(int(args["oneshot"]))
self.breakpointsToCheck.add(bp.GetID())
return bp
bp = self.target.BreakpointCreateByName(None)
more = False
if more:
bp.SetIgnoreCount(int(args["ignorecount"]))
if hasattr(bp, 'SetCondition'):
bp.SetCondition(self.hexdecode(args["condition"]))
bp.SetEnabled(int(args["enabled"]))
if hasattr(bp, 'SetOneShot'):
bp.SetOneShot(int(args["oneshot"]))
self.breakpointsToCheck.add(bp.GetID())
self.report('breakpoint-added={%s,modelid="%s"}' % (self.describeBreakpoint(bp), modelId))
def changeBreakpoint(self, args):
id = int(args["lldbid"])
if id > qqWatchpointOffset:
bp = self.target.FindWatchpointByID(id)
lldbId = int(args["lldbid"])
modelId = args['modelid']
if lldbId > qqWatchpointOffset:
bp = self.target.FindWatchpointByID(lldbId)
else:
bp = self.target.FindBreakpointByID(id)
bp = self.target.FindBreakpointByID(lldbId)
bp.SetIgnoreCount(int(args["ignorecount"]))
bp.SetCondition(self.hexdecode(args["condition"]))
bp.SetEnabled(int(args["enabled"]))
if hasattr(bp, 'SetOneShot'):
bp.SetOneShot(int(args["oneshot"]))
return bp
self.report('breakpoint-changed={%s,modelid="%s"}'
% (self.describeBreakpoint(bp), modelId))
def removeBreakpoint(self, args):
id = int(args['lldbid'])
if id > qqWatchpointOffset:
return self.target.DeleteWatchpoint(id - qqWatchpointOffset)
return self.target.BreakpointDelete(id)
def handleBreakpoints(self, args):
# This seems to be only needed on Linux.
needStop = False
if self.process and platform.system() == "Linux":
needStop = self.process.GetState() != lldb.eStateStopped
if needStop:
error = self.process.Stop()
for bp in args['bkpts']:
operation = bp['operation']
modelId = bp['modelid']
if operation == 'add':
bpNew = self.addBreakpoint(bp)
self.report('breakpoint-added={%s,modelid="%s"}'
% (self.describeBreakpoint(bpNew), modelId))
elif operation == 'change':
bpNew = self.changeBreakpoint(bp)
self.report('breakpoint-changed={%s,modelid="%s"}'
% (self.describeBreakpoint(bpNew), modelId))
elif operation == 'remove':
bpDead = self.removeBreakpoint(bp)
self.report('breakpoint-removed={modelid="%s"}' % modelId)
if needStop:
error = self.process.Continue()
lldbId = int(args['lldbid'])
modelId = args['modelid']
if lldbId > qqWatchpointOffset:
res = self.target.DeleteWatchpoint(lldbId - qqWatchpointOffset)
res = self.target.BreakpointDelete(lldbId)
self.report('breakpoint-removed={modelid="%s"}' % modelId)
def listModules(self, args):
result = 'modules=['
......
......@@ -309,7 +309,21 @@ void LldbEngine::setupInferior()
cmd.arg("useTerminal", sp.useTerminal);
cmd.arg("startMode", sp.startMode);
attemptBreakpointSynchronizationHelper(&cmd);
cmd.beginList("bkpts");
foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) {
if (acceptsBreakpoint(bp)) {
showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
.arg(bp.id().toString()).arg(bp.state()));
bp.setEngine(this);
cmd.beginGroup();
insertBreakpointHelper(&cmd, bp);
cmd.endGroup();
} else {
showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
.arg(bp.id().toString()).arg(bp.state()));
}
}
cmd.endList();
cmd.beginList("processArgs");
foreach (const QString &arg, args.toUnixArgs())
......@@ -520,113 +534,81 @@ void LldbEngine::selectThread(ThreadId threadId)
runCommand(DebuggerCommand("selectThread").arg("id", threadId.raw()));
}
bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
bool LldbEngine::stateAcceptsBreakpointChanges() const
{
return bp.parameters().isCppBreakpoint() && startParameters().startMode != AttachCore;
switch (state()) {
case InferiorSetupRequested:
case InferiorRunRequested:
case InferiorRunOk:
case InferiorStopRequested:
case InferiorStopOk:
return true;
default:
return false;
}
}
bool LldbEngine::attemptBreakpointSynchronizationHelper(DebuggerCommand *cmd)
bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
{
BreakHandler *handler = breakHandler();
if (startParameters().startMode == AttachCore)
return false;
// We handle QML breakpoint unless specifically disabled.
if (isNativeMixedEnabled() && !(startParameters().languages & QmlLanguage))
return true;
return bp.parameters().isCppBreakpoint();
}
foreach (Breakpoint bp, handler->unclaimedBreakpoints()) {
// Take ownership of the breakpoint. Requests insertion.
if (acceptsBreakpoint(bp)) {
showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
.arg(bp.id().toString()).arg(bp.state()));
bp.setEngine(this);
} else {
showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
.arg(bp.id().toString()).arg(bp.state()));
}
}
void LldbEngine::insertBreakpoint(Breakpoint bp)
{
DebuggerCommand cmd("insertBreakpoint");
insertBreakpointHelper(&cmd, bp);
runCommand(cmd);
}
bool done = true;
cmd->beginList("bkpts");
foreach (Breakpoint bp, handler->engineBreakpoints(this)) {
const BreakpointResponse &response = bp.response();
const BreakpointState bpState = bp.state();
switch (bpState) {
case BreakpointNew:
// Should not happen once claimed.
QTC_CHECK(false);
break;
case BreakpointInsertRequested:
done = false;
cmd->beginGroup()
.arg("operation", "add")
.arg("modelid", bp.id().toByteArray())
.arg("type", bp.type())
.arg("ignorecount", bp.ignoreCount())
.arg("condition", bp.condition().toHex())
.arg("function", bp.functionName().toUtf8())
.arg("oneshot", bp.isOneShot())
.arg("enabled", bp.isEnabled())
.arg("file", bp.fileName().toUtf8())
.arg("line", bp.lineNumber())
.arg("address", bp.address())
.arg("expression", bp.expression())
.endGroup();
bp.notifyBreakpointInsertProceeding();
break;
case BreakpointChangeRequested:
done = false;
cmd->beginGroup()
.arg("operation", "change")
.arg("modelid", bp.id().toByteArray())
.arg("lldbid", response.id.toByteArray())
.arg("type", bp.type())
.arg("ignorecount", bp.ignoreCount())
.arg("condition", bp.condition().toHex())
.arg("function", bp.functionName().toUtf8())
.arg("oneshot", bp.isOneShot())
.arg("enabled", bp.isEnabled())
.arg("file", bp.fileName().toUtf8())
.arg("line", bp.lineNumber())
.arg("address", bp.address())
.arg("expression", bp.expression())
.endGroup();
bp.notifyBreakpointChangeProceeding();
break;
case BreakpointRemoveRequested:
done = false;
cmd->beginGroup()
.arg("operation", "remove")
.arg("modelid", bp.id().toByteArray())
.arg("lldbid", response.id.toByteArray())
.endGroup();
bp.notifyBreakpointRemoveProceeding();
break;
case BreakpointChangeProceeding:
case BreakpointInsertProceeding:
case BreakpointRemoveProceeding:
case BreakpointInserted:
case BreakpointDead:
QTC_ASSERT(false, qDebug() << "UNEXPECTED STATE" << bpState << "FOR BP " << bp.id());
break;
default:
QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bpState << "FOR BP" << bp.id());
}
}
cmd->endList();
return done;
void LldbEngine::insertBreakpointHelper(DebuggerCommand *cmd, Breakpoint bp) const
{
cmd->arg("modelid", bp.id().toByteArray());
cmd->arg("type", bp.type());
cmd->arg("ignorecount", bp.ignoreCount());
cmd->arg("condition", bp.condition().toHex());
cmd->arg("function", bp.functionName().toUtf8());
cmd->arg("oneshot", bp.isOneShot());
cmd->arg("enabled", bp.isEnabled());
cmd->arg("file", bp.fileName().toUtf8());
cmd->arg("line", bp.lineNumber());
cmd->arg("address", bp.address());
cmd->arg("expression", bp.expression());
bp.notifyBreakpointInsertProceeding();
}
void LldbEngine::changeBreakpoint(Breakpoint bp)
{
const BreakpointResponse &response = bp.response();
DebuggerCommand cmd("changeBreakpoint");
cmd.arg("modelid", bp.id().toByteArray());
cmd.arg("lldbid", response.id.toByteArray());
cmd.arg("type", bp.type());
cmd.arg("ignorecount", bp.ignoreCount());
cmd.arg("condition", bp.condition().toHex());
cmd.arg("function", bp.functionName().toUtf8());
cmd.arg("oneshot", bp.isOneShot());
cmd.arg("enabled", bp.isEnabled());
cmd.arg("file", bp.fileName().toUtf8());
cmd.arg("line", bp.lineNumber());
cmd.arg("address", bp.address());
cmd.arg("expression", bp.expression());
bp.notifyBreakpointChangeProceeding();
runCommand(cmd);
}
void LldbEngine::attemptBreakpointSynchronization()
void LldbEngine::removeBreakpoint(Breakpoint bp)
{
showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION"));
if (!stateAcceptsBreakpointChanges()) {
showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE"));
return;
}
DebuggerCommand cmd("handleBreakpoints");
if (!attemptBreakpointSynchronizationHelper(&cmd)) {
showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
runCommand(cmd);
} else {
showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
}
const BreakpointResponse &response = bp.response();
DebuggerCommand cmd("removeBreakpoint");
cmd.arg("modelid", bp.id().toByteArray());
cmd.arg("lldbid", response.id.toByteArray());
bp.notifyBreakpointRemoveProceeding();
runCommand(cmd);
}
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
......
......@@ -95,9 +95,13 @@ private:
void activateFrame(int index);
void selectThread(ThreadId threadId);
// This should be always the last call in a function.
bool stateAcceptsBreakpointChanges() const;
bool acceptsBreakpoint(Breakpoint bp) const;
void attemptBreakpointSynchronization();
bool attemptBreakpointSynchronizationHelper(DebuggerCommand *command);
void insertBreakpoint(Breakpoint bp);
void insertBreakpointHelper(DebuggerCommand *cmd, Breakpoint bp) const;
void removeBreakpoint(Breakpoint bp);
void changeBreakpoint(Breakpoint bp);
void assignValueInDebugger(const WatchData *data,
const QString &expr, const QVariant &value);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment