Debugger: Move breakpoint markers with LLDB

Task-number: QTCREATORBUG-11564
Change-Id: I98044c641ad68431176d8ef54e8e1ec1bef296bc
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
hjk
2014-03-05 19:06:24 +01:00
parent 11cc292da6
commit 1d1695c2b4
3 changed files with 100 additions and 76 deletions

View File

@@ -316,6 +316,7 @@ class Dumper(DumperBase):
self.isInterrupting_ = False self.isInterrupting_ = False
self.dummyValue = None self.dummyValue = None
self.types_ = {} self.types_ = {}
self.breakpointsToCheck = set([])
def enterSubItem(self, item): def enterSubItem(self, item):
if isinstance(item.name, lldb.SBValue): if isinstance(item.name, lldb.SBValue):
@@ -804,6 +805,14 @@ class Dumper(DumperBase):
result += '],current-thread-id="%s"},' % self.currentThread().id result += '],current-thread-id="%s"},' % self.currentThread().id
self.report(result) 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): def firstUsableFrame(self, thread):
for i in xrange(10): for i in xrange(10):
frame = thread.GetFrameAtIndex(i) frame = thread.GetFrameAtIndex(i)
@@ -1283,6 +1292,7 @@ class Dumper(DumperBase):
self.reportLocation() self.reportLocation()
self.reportVariables() self.reportVariables()
self.reportRegisters() self.reportRegisters()
self.reportChangedBreakpoints()
elif type == lldb.SBProcess.eBroadcastBitInterrupt: elif type == lldb.SBProcess.eBroadcastBitInterrupt:
pass pass
elif type == lldb.SBProcess.eBroadcastBitSTDOUT: elif type == lldb.SBProcess.eBroadcastBitSTDOUT:
@@ -1297,13 +1307,12 @@ class Dumper(DumperBase):
elif type == lldb.SBProcess.eBroadcastBitProfileData: elif type == lldb.SBProcess.eBroadcastBitProfileData:
pass pass
def describeBreakpoint(self, bp, modelId): def describeBreakpoint(self, bp):
isWatch = isinstance(bp, lldb.SBWatchpoint) isWatch = isinstance(bp, lldb.SBWatchpoint)
if isWatch: if isWatch:
result = 'lldbid="%s"' % (qqWatchpointOffset + bp.GetID()) result = 'lldbid="%s"' % (qqWatchpointOffset + bp.GetID())
else: else:
result = 'lldbid="%s"' % bp.GetID() result = 'lldbid="%s"' % bp.GetID()
result += ',modelid="%s"' % modelId
if not bp.IsValid(): if not bp.IsValid():
return return
result += ',hitcount="%s"' % bp.GetHitCount() result += ',hitcount="%s"' % bp.GetHitCount()
@@ -1318,18 +1327,25 @@ class Dumper(DumperBase):
result += ',valid="%s"' % (1 if bp.IsValid() else 0) result += ',valid="%s"' % (1 if bp.IsValid() else 0)
result += ',ignorecount="%s"' % bp.GetIgnoreCount() result += ',ignorecount="%s"' % bp.GetIgnoreCount()
result += ',locations=[' result += ',locations=['
lineEntry = None
if hasattr(bp, 'GetNumLocations'): if hasattr(bp, 'GetNumLocations'):
for i in xrange(bp.GetNumLocations()): for i in xrange(bp.GetNumLocations()):
loc = bp.GetLocationAtIndex(i) loc = bp.GetLocationAtIndex(i)
addr = loc.GetAddress() addr = loc.GetAddress()
lineEntry = addr.GetLineEntry()
result += '{locid="%s"' % loc.GetID() result += '{locid="%s"' % loc.GetID()
result += ',func="%s"' % addr.GetFunction().GetName() result += ',func="%s"' % addr.GetFunction().GetName()
result += ',enabled="%s"' % (1 if loc.IsEnabled() else 0) result += ',enabled="%s"' % (1 if loc.IsEnabled() else 0)
result += ',resolved="%s"' % (1 if loc.IsResolved() else 0) result += ',resolved="%s"' % (1 if loc.IsResolved() else 0)
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 += ',file="%s"' % lineEntry.GetFileSpec()
result += ',line="%s"' % lineEntry.GetLine()
result += ',addr="%s"},' % loc.GetLoadAddress() result += ',addr="%s"},' % loc.GetLoadAddress()
result += '],' result += ']'
if lineEntry is not None:
result += ',file="%s"' % lineEntry.GetFileSpec()
result += ',line="%s"' % lineEntry.GetLine()
return result return result
def createBreakpointAtMain(self): def createBreakpointAtMain(self):
@@ -1339,26 +1355,26 @@ class Dumper(DumperBase):
def addBreakpoint(self, args): def addBreakpoint(self, args):
bpType = args["type"] bpType = args["type"]
if bpType == BreakpointByFileAndLine: if bpType == BreakpointByFileAndLine:
bpNew = self.target.BreakpointCreateByLocation( bp = self.target.BreakpointCreateByLocation(
str(args["file"]), int(args["line"])) str(args["file"]), int(args["line"]))
elif bpType == BreakpointByFunction: elif bpType == BreakpointByFunction:
bpNew = self.target.BreakpointCreateByName(args["function"]) bp = self.target.BreakpointCreateByName(args["function"])
elif bpType == BreakpointByAddress: elif bpType == BreakpointByAddress:
bpNew = self.target.BreakpointCreateByAddress(args["address"]) bp = self.target.BreakpointCreateByAddress(args["address"])
elif bpType == BreakpointAtMain: elif bpType == BreakpointAtMain:
bpNew = self.createBreakpointAtMain() bp = self.createBreakpointAtMain()
elif bpType == BreakpointByFunction: elif bpType == BreakpointByFunction:
bpNew = self.target.BreakpointCreateByName(args["function"]) bp = self.target.BreakpointCreateByName(args["function"])
elif bpType == BreakpointAtThrow: elif bpType == BreakpointAtThrow:
bpNew = self.target.BreakpointCreateForException( bp = self.target.BreakpointCreateForException(
lldb.eLanguageTypeC_plus_plus, False, True) lldb.eLanguageTypeC_plus_plus, False, True)
elif bpType == BreakpointAtCatch: elif bpType == BreakpointAtCatch:
bpNew = self.target.BreakpointCreateForException( bp = self.target.BreakpointCreateForException(
lldb.eLanguageTypeC_plus_plus, True, False) lldb.eLanguageTypeC_plus_plus, True, False)
elif bpType == WatchpointAtAddress: elif bpType == WatchpointAtAddress:
error = lldb.SBError() error = lldb.SBError()
bpNew = self.target.WatchAddress(args["address"], 4, False, True, error) bp = self.target.WatchAddress(args["address"], 4, False, True, error)
#warn("BPNEW: %s" % bpNew) #warn("BPNEW: %s" % bp)
self.reportError(error) self.reportError(error)
elif bpType == WatchpointAtExpression: elif bpType == WatchpointAtExpression:
# FIXME: Top level-only for now. # FIXME: Top level-only for now.
@@ -1366,7 +1382,7 @@ class Dumper(DumperBase):
frame = self.currentFrame() frame = self.currentFrame()
value = frame.FindVariable(args["expression"]) value = frame.FindVariable(args["expression"])
error = lldb.SBError() error = lldb.SBError()
bpNew = self.target.WatchAddress(value.GetLoadAddress(), bp = self.target.WatchAddress(value.GetLoadAddress(),
value.GetByteSize(), False, True, error) value.GetByteSize(), False, True, error)
except: except:
return self.target.BreakpointCreateByName(None) return self.target.BreakpointCreateByName(None)
@@ -1374,13 +1390,14 @@ class Dumper(DumperBase):
# This leaves the unhandled breakpoint in a (harmless) # This leaves the unhandled breakpoint in a (harmless)
# "pending" state. # "pending" state.
return self.target.BreakpointCreateByName(None) return self.target.BreakpointCreateByName(None)
bpNew.SetIgnoreCount(int(args["ignorecount"])) bp.SetIgnoreCount(int(args["ignorecount"]))
if hasattr(bpNew, 'SetCondition'): if hasattr(bp, 'SetCondition'):
bpNew.SetCondition(self.hexdecode(args["condition"])) bp.SetCondition(self.hexdecode(args["condition"]))
bpNew.SetEnabled(int(args["enabled"])) bp.SetEnabled(int(args["enabled"]))
if hasattr(bpNew, 'SetOneShot'): if hasattr(bp, 'SetOneShot'):
bpNew.SetOneShot(int(args["oneshot"])) bp.SetOneShot(int(args["oneshot"]))
return bpNew self.breakpointsToCheck.add(bp.GetID())
return bp
def changeBreakpoint(self, args): def changeBreakpoint(self, args):
id = int(args["lldbid"]) id = int(args["lldbid"])
@@ -1393,6 +1410,7 @@ class Dumper(DumperBase):
bp.SetEnabled(int(args["enabled"])) bp.SetEnabled(int(args["enabled"]))
if hasattr(bp, 'SetOneShot'): if hasattr(bp, 'SetOneShot'):
bp.SetOneShot(int(args["oneshot"])) bp.SetOneShot(int(args["oneshot"]))
return bp
def removeBreakpoint(self, args): def removeBreakpoint(self, args):
id = int(args['lldbid']) id = int(args['lldbid'])
@@ -1408,30 +1426,27 @@ class Dumper(DumperBase):
if needStop: if needStop:
error = self.process.Stop() error = self.process.Stop()
result = 'bkpts=['
for bp in args['bkpts']: for bp in args['bkpts']:
operation = bp['operation'] operation = bp['operation']
modelId = bp['modelid']
if operation == 'add': if operation == 'add':
bpNew = self.addBreakpoint(bp) bpNew = self.addBreakpoint(bp)
result += '{operation="added",%s}' \ self.report('breakpoint-added={%s,modelid="%s"}'
% self.describeBreakpoint(bpNew, bp["modelid"]) % (self.describeBreakpoint(bpNew), modelId))
elif operation == 'change': elif operation == 'change':
bpNew = self.changeBreakpoint(bp) bpNew = self.changeBreakpoint(bp)
result += '{operation="changed",%s' \ self.report('breakpoint-changed={%s,modelid="%s"}'
% self.describeBreakpoint(bpNew, bp["modelid"]) % (self.describeBreakpoint(bpNew), modelId))
elif operation == 'remove': elif operation == 'remove':
bpDead = self.removeBreakpoint(bp) bpDead = self.removeBreakpoint(bp)
result += '{operation="removed",modelid="%s"}' % bp["modelid"] self.report('breakpoint-removed={modelid="%s"}' % modelId)
result += "]"
if needStop: if needStop:
error = self.process.Continue() error = self.process.Continue()
self.report(result)
def listModules(self, args): def listModules(self, args):
result = 'modules=[' result = 'modules=['

View File

@@ -415,8 +415,12 @@ void LldbEngine::handleResponse(const QByteArray &response)
refreshModules(item); refreshModules(item);
else if (name == "symbols") else if (name == "symbols")
refreshSymbols(item); refreshSymbols(item);
else if (name == "bkpts") else if (name == "breakpoint-added")
refreshBreakpoints(item); refreshAddedBreakpoint(item);
else if (name == "breakpoint-changed")
refreshChangedBreakpoint(item);
else if (name == "breakpoint-removed")
refreshRemovedBreakpoint(item);
else if (name == "output") else if (name == "output")
refreshOutput(item); refreshOutput(item);
else if (name == "disassembly") else if (name == "disassembly")
@@ -605,9 +609,11 @@ void LldbEngine::attemptBreakpointSynchronization()
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
{ {
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
BreakpointResponse response = handler->response(id);
BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data()); 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) if (added)
response.id = rid; response.id = rid;
QTC_CHECK(response.id == rid); QTC_CHECK(response.id == rid);
@@ -616,9 +622,9 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
response.ignoreCount = bkpt["ignorecount"].toInt(); response.ignoreCount = bkpt["ignorecount"].toInt();
response.condition = QByteArray::fromHex(bkpt["condition"].data()); response.condition = QByteArray::fromHex(bkpt["condition"].data());
response.hitCount = bkpt["hitcount"].toInt(); response.hitCount = bkpt["hitcount"].toInt();
response.fileName = bkpt["file"].toUtf8();
response.lineNumber = bkpt["line"].toInt();
if (added) {
// Added.
GdbMi locations = bkpt["locations"]; GdbMi locations = bkpt["locations"];
const int numChild = locations.children().size(); const int numChild = locations.children().size();
if (numChild > 1) { if (numChild > 1) {
@@ -629,6 +635,8 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
sub.type = response.type; sub.type = response.type;
sub.address = location["addr"].toAddress(); sub.address = location["addr"].toAddress();
sub.functionName = location["func"].toUtf8(); sub.functionName = location["func"].toUtf8();
sub.fileName = location["file"].toUtf8();
sub.lineNumber = location["line"].toInt();
handler->insertSubBreakpoint(id, sub); handler->insertSubBreakpoint(id, sub);
} }
} else if (numChild == 1) { } else if (numChild == 1) {
@@ -639,12 +647,10 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
QTC_CHECK(false); QTC_CHECK(false);
} }
handler->setResponse(id, response); handler->setResponse(id, response);
if (added)
handler->notifyBreakpointInsertOk(id); handler->notifyBreakpointInsertOk(id);
} else { else
// Changed.
handler->setResponse(id, response);
handler->notifyBreakpointChangeOk(id); handler->notifyBreakpointChangeOk(id);
}
} }
void LldbEngine::refreshDisassembly(const GdbMi &data) void LldbEngine::refreshDisassembly(const GdbMi &data)
@@ -694,25 +700,26 @@ void LldbEngine::refreshOutput(const GdbMi &output)
showMessage(QString::fromUtf8(data), ch); 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(); 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()); BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding); QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding);
handler->notifyBreakpointRemoveOk(id); handler->notifyBreakpointRemoveOk(id);
}
}
} }
void LldbEngine::loadSymbols(const QString &moduleName) void LldbEngine::loadSymbols(const QString &moduleName)

View File

@@ -174,7 +174,9 @@ private:
void refreshModules(const GdbMi &modules); void refreshModules(const GdbMi &modules);
void refreshSymbols(const GdbMi &symbols); void refreshSymbols(const GdbMi &symbols);
void refreshOutput(const GdbMi &output); 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); void runContinuation(const GdbMi &data);
typedef void (LldbEngine::*LldbCommandContinuation)(); typedef void (LldbEngine::*LldbCommandContinuation)();