forked from qt-creator/qt-creator
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:
@@ -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=['
|
||||||
|
@@ -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)
|
||||||
|
@@ -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)();
|
||||||
|
Reference in New Issue
Block a user