diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 7d480af10b2..a1a8f569340 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -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=[' diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 4a2c5981c8a..8d3b65b740e 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -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::stateAcceptsBreakpointChanges() const +{ + switch (state()) { + case InferiorSetupRequested: + case InferiorRunRequested: + case InferiorRunOk: + case InferiorStopRequested: + case InferiorStopOk: + return true; + default: + return false; + } +} + bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const { - return bp.parameters().isCppBreakpoint() && startParameters().startMode != AttachCore; + if (startParameters().startMode == AttachCore) + return false; + // We handle QML breakpoint unless specifically disabled. + if (isNativeMixedEnabled() && !(startParameters().languages & QmlLanguage)) + return true; + return bp.parameters().isCppBreakpoint(); } -bool LldbEngine::attemptBreakpointSynchronizationHelper(DebuggerCommand *cmd) +void LldbEngine::insertBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - - 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())); - } - } - - 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; + DebuggerCommand cmd("insertBreakpoint"); + insertBreakpointHelper(&cmd, bp); + runCommand(cmd); } -void LldbEngine::attemptBreakpointSynchronization() +void LldbEngine::insertBreakpointHelper(DebuggerCommand *cmd, Breakpoint bp) const { - showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION")); - if (!stateAcceptsBreakpointChanges()) { - showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE")); - return; - } + 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(); +} - DebuggerCommand cmd("handleBreakpoints"); - if (!attemptBreakpointSynchronizationHelper(&cmd)) { - showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED")); - runCommand(cmd); - } else { - showMessage(_("BREAKPOINTS ARE SYNCHRONIZED")); - } +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::removeBreakpoint(Breakpoint bp) +{ + 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) diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 479fdbb0323..0f5996629e0 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -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);