From 1d1695c2b40ffd9e0cbae56f117dce9768337a2c Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Mar 2014 19:06:24 +0100 Subject: [PATCH] Debugger: Move breakpoint markers with LLDB Task-number: QTCREATORBUG-11564 Change-Id: I98044c641ad68431176d8ef54e8e1ec1bef296bc Reviewed-by: Christian Stenger Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 73 ++++++++++------- src/plugins/debugger/lldb/lldbengine.cpp | 99 +++++++++++++----------- src/plugins/debugger/lldb/lldbengine.h | 4 +- 3 files changed, 100 insertions(+), 76 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 23c37dd88ce..dabd4587b89 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -316,6 +316,7 @@ class Dumper(DumperBase): self.isInterrupting_ = False self.dummyValue = None self.types_ = {} + self.breakpointsToCheck = set([]) def enterSubItem(self, item): if isinstance(item.name, lldb.SBValue): @@ -804,6 +805,14 @@ class Dumper(DumperBase): result += '],current-thread-id="%s"},' % self.currentThread().id self.report(result) + def reportChangedBreakpoints(self): + for i in xrange(0, self.target.GetNumBreakpoints()): + bp = self.target.GetBreakpointAtIndex(i) + if bp.GetID() in self.breakpointsToCheck: + if bp.GetNumLocations(): + self.breakpointsToCheck.remove(bp.GetID()) + self.report('breakpoint-changed={%s}' % self.describeBreakpoint(bp)) + def firstUsableFrame(self, thread): for i in xrange(10): frame = thread.GetFrameAtIndex(i) @@ -1283,6 +1292,7 @@ class Dumper(DumperBase): self.reportLocation() self.reportVariables() self.reportRegisters() + self.reportChangedBreakpoints() elif type == lldb.SBProcess.eBroadcastBitInterrupt: pass elif type == lldb.SBProcess.eBroadcastBitSTDOUT: @@ -1297,13 +1307,12 @@ class Dumper(DumperBase): elif type == lldb.SBProcess.eBroadcastBitProfileData: pass - def describeBreakpoint(self, bp, modelId): + def describeBreakpoint(self, bp): isWatch = isinstance(bp, lldb.SBWatchpoint) if isWatch: result = 'lldbid="%s"' % (qqWatchpointOffset + bp.GetID()) else: result = 'lldbid="%s"' % bp.GetID() - result += ',modelid="%s"' % modelId if not bp.IsValid(): return result += ',hitcount="%s"' % bp.GetHitCount() @@ -1318,18 +1327,25 @@ class Dumper(DumperBase): result += ',valid="%s"' % (1 if bp.IsValid() else 0) result += ',ignorecount="%s"' % bp.GetIgnoreCount() result += ',locations=[' + lineEntry = None if hasattr(bp, 'GetNumLocations'): for i in xrange(bp.GetNumLocations()): loc = bp.GetLocationAtIndex(i) addr = loc.GetAddress() + lineEntry = addr.GetLineEntry() result += '{locid="%s"' % loc.GetID() result += ',func="%s"' % addr.GetFunction().GetName() result += ',enabled="%s"' % (1 if loc.IsEnabled() else 0) result += ',resolved="%s"' % (1 if loc.IsResolved() else 0) result += ',valid="%s"' % (1 if loc.IsValid() else 0) result += ',ignorecount="%s"' % loc.GetIgnoreCount() + result += ',file="%s"' % lineEntry.GetFileSpec() + result += ',line="%s"' % lineEntry.GetLine() result += ',addr="%s"},' % loc.GetLoadAddress() - result += '],' + result += ']' + if lineEntry is not None: + result += ',file="%s"' % lineEntry.GetFileSpec() + result += ',line="%s"' % lineEntry.GetLine() return result def createBreakpointAtMain(self): @@ -1339,26 +1355,26 @@ class Dumper(DumperBase): def addBreakpoint(self, args): bpType = args["type"] if bpType == BreakpointByFileAndLine: - bpNew = self.target.BreakpointCreateByLocation( + bp = self.target.BreakpointCreateByLocation( str(args["file"]), int(args["line"])) elif bpType == BreakpointByFunction: - bpNew = self.target.BreakpointCreateByName(args["function"]) + bp = self.target.BreakpointCreateByName(args["function"]) elif bpType == BreakpointByAddress: - bpNew = self.target.BreakpointCreateByAddress(args["address"]) + bp = self.target.BreakpointCreateByAddress(args["address"]) elif bpType == BreakpointAtMain: - bpNew = self.createBreakpointAtMain() + bp = self.createBreakpointAtMain() elif bpType == BreakpointByFunction: - bpNew = self.target.BreakpointCreateByName(args["function"]) + bp = self.target.BreakpointCreateByName(args["function"]) elif bpType == BreakpointAtThrow: - bpNew = self.target.BreakpointCreateForException( + bp = self.target.BreakpointCreateForException( lldb.eLanguageTypeC_plus_plus, False, True) elif bpType == BreakpointAtCatch: - bpNew = self.target.BreakpointCreateForException( + bp = self.target.BreakpointCreateForException( lldb.eLanguageTypeC_plus_plus, True, False) elif bpType == WatchpointAtAddress: error = lldb.SBError() - bpNew = self.target.WatchAddress(args["address"], 4, False, True, error) - #warn("BPNEW: %s" % bpNew) + bp = self.target.WatchAddress(args["address"], 4, False, True, error) + #warn("BPNEW: %s" % bp) self.reportError(error) elif bpType == WatchpointAtExpression: # FIXME: Top level-only for now. @@ -1366,7 +1382,7 @@ class Dumper(DumperBase): frame = self.currentFrame() value = frame.FindVariable(args["expression"]) error = lldb.SBError() - bpNew = self.target.WatchAddress(value.GetLoadAddress(), + bp = self.target.WatchAddress(value.GetLoadAddress(), value.GetByteSize(), False, True, error) except: return self.target.BreakpointCreateByName(None) @@ -1374,13 +1390,14 @@ class Dumper(DumperBase): # This leaves the unhandled breakpoint in a (harmless) # "pending" state. return self.target.BreakpointCreateByName(None) - bpNew.SetIgnoreCount(int(args["ignorecount"])) - if hasattr(bpNew, 'SetCondition'): - bpNew.SetCondition(self.hexdecode(args["condition"])) - bpNew.SetEnabled(int(args["enabled"])) - if hasattr(bpNew, 'SetOneShot'): - bpNew.SetOneShot(int(args["oneshot"])) - return bpNew + 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 def changeBreakpoint(self, args): id = int(args["lldbid"]) @@ -1393,6 +1410,7 @@ class Dumper(DumperBase): bp.SetEnabled(int(args["enabled"])) if hasattr(bp, 'SetOneShot'): bp.SetOneShot(int(args["oneshot"])) + return bp def removeBreakpoint(self, args): id = int(args['lldbid']) @@ -1408,30 +1426,27 @@ class Dumper(DumperBase): if needStop: error = self.process.Stop() - result = 'bkpts=[' for bp in args['bkpts']: operation = bp['operation'] + modelId = bp['modelid'] if operation == 'add': bpNew = self.addBreakpoint(bp) - result += '{operation="added",%s}' \ - % self.describeBreakpoint(bpNew, bp["modelid"]) + self.report('breakpoint-added={%s,modelid="%s"}' + % (self.describeBreakpoint(bpNew), modelId)) elif operation == 'change': bpNew = self.changeBreakpoint(bp) - result += '{operation="changed",%s' \ - % self.describeBreakpoint(bpNew, bp["modelid"]) + self.report('breakpoint-changed={%s,modelid="%s"}' + % (self.describeBreakpoint(bpNew), modelId)) elif operation == 'remove': bpDead = self.removeBreakpoint(bp) - result += '{operation="removed",modelid="%s"}' % bp["modelid"] - - result += "]" + self.report('breakpoint-removed={modelid="%s"}' % modelId) if needStop: error = self.process.Continue() - self.report(result) def listModules(self, args): result = 'modules=[' diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index b3ffc938508..754958bf87e 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -415,8 +415,12 @@ void LldbEngine::handleResponse(const QByteArray &response) refreshModules(item); else if (name == "symbols") refreshSymbols(item); - else if (name == "bkpts") - refreshBreakpoints(item); + else if (name == "breakpoint-added") + refreshAddedBreakpoint(item); + else if (name == "breakpoint-changed") + refreshChangedBreakpoint(item); + else if (name == "breakpoint-removed") + refreshRemovedBreakpoint(item); else if (name == "output") refreshOutput(item); else if (name == "disassembly") @@ -605,9 +609,11 @@ void LldbEngine::attemptBreakpointSynchronization() void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) { BreakHandler *handler = breakHandler(); - BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - BreakpointResponse response = handler->response(id); BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data()); + BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); + if (!id.isValid()) + id = handler->findBreakpointByResponseId(rid); + BreakpointResponse response = handler->response(id); if (added) response.id = rid; QTC_CHECK(response.id == rid); @@ -616,35 +622,35 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) response.ignoreCount = bkpt["ignorecount"].toInt(); response.condition = QByteArray::fromHex(bkpt["condition"].data()); response.hitCount = bkpt["hitcount"].toInt(); + response.fileName = bkpt["file"].toUtf8(); + response.lineNumber = bkpt["line"].toInt(); - if (added) { - // Added. - GdbMi locations = bkpt["locations"]; - const int numChild = locations.children().size(); - if (numChild > 1) { - foreach (const GdbMi &location, locations.children()) { - const int locid = location["locid"].toInt(); - BreakpointResponse sub; - sub.id = BreakpointResponseId(rid.majorPart(), locid); - sub.type = response.type; - sub.address = location["addr"].toAddress(); - sub.functionName = location["func"].toUtf8(); - handler->insertSubBreakpoint(id, sub); - } - } else if (numChild == 1) { - const GdbMi location = locations.childAt(0); - response.address = location["addr"].toAddress(); - response.functionName = location["func"].toUtf8(); - } else { - QTC_CHECK(false); + GdbMi locations = bkpt["locations"]; + const int numChild = locations.children().size(); + if (numChild > 1) { + foreach (const GdbMi &location, locations.children()) { + const int locid = location["locid"].toInt(); + BreakpointResponse sub; + sub.id = BreakpointResponseId(rid.majorPart(), locid); + sub.type = response.type; + sub.address = location["addr"].toAddress(); + sub.functionName = location["func"].toUtf8(); + sub.fileName = location["file"].toUtf8(); + sub.lineNumber = location["line"].toInt(); + handler->insertSubBreakpoint(id, sub); } - handler->setResponse(id, response); - handler->notifyBreakpointInsertOk(id); + } else if (numChild == 1) { + const GdbMi location = locations.childAt(0); + response.address = location["addr"].toAddress(); + response.functionName = location["func"].toUtf8(); } else { - // Changed. - handler->setResponse(id, response); - handler->notifyBreakpointChangeOk(id); + QTC_CHECK(false); } + handler->setResponse(id, response); + if (added) + handler->notifyBreakpointInsertOk(id); + else + handler->notifyBreakpointChangeOk(id); } void LldbEngine::refreshDisassembly(const GdbMi &data) @@ -694,25 +700,26 @@ void LldbEngine::refreshOutput(const GdbMi &output) showMessage(QString::fromUtf8(data), ch); } -void LldbEngine::refreshBreakpoints(const GdbMi &bkpts) +void LldbEngine::refreshAddedBreakpoint(const GdbMi &bkpt) +{ + BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); + QTC_CHECK(breakHandler()->state(id) == BreakpointInsertProceeding); + updateBreakpointData(bkpt, true); +} + +void LldbEngine::refreshChangedBreakpoint(const GdbMi &bkpt) +{ + BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); + QTC_CHECK(!id.isValid() || breakHandler()->state(id) == BreakpointChangeProceeding); + updateBreakpointData(bkpt, false); +} + +void LldbEngine::refreshRemovedBreakpoint(const GdbMi &bkpt) { BreakHandler *handler = breakHandler(); - foreach (const GdbMi &bkpt, bkpts.children()) { - QByteArray op = bkpt["operation"].data(); - if (op == "added") { - BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(handler->state(id) == BreakpointInsertProceeding); - updateBreakpointData(bkpt, true); - } else if (op == "changed") { - BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(handler->state(id) == BreakpointChangeProceeding); - updateBreakpointData(bkpt, false); - } else if (op == "removed") { - BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding); - handler->notifyBreakpointRemoveOk(id); - } - } + BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); + QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding); + handler->notifyBreakpointRemoveOk(id); } void LldbEngine::loadSymbols(const QString &moduleName) diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 7b1d4aca943..571b55cf322 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -174,7 +174,9 @@ private: void refreshModules(const GdbMi &modules); void refreshSymbols(const GdbMi &symbols); void refreshOutput(const GdbMi &output); - void refreshBreakpoints(const GdbMi &bkpts); + void refreshAddedBreakpoint(const GdbMi &bkpts); + void refreshChangedBreakpoint(const GdbMi &bkpts); + void refreshRemovedBreakpoint(const GdbMi &bkpts); void runContinuation(const GdbMi &data); typedef void (LldbEngine::*LldbCommandContinuation)();