summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/qtcreator/debugger/dumper.py5
-rw-r--r--share/qtcreator/debugger/gdbbridge.py5
-rw-r--r--share/qtcreator/debugger/lldbbridge.py332
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp2
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp586
-rw-r--r--src/plugins/debugger/lldb/lldbengine.h55
6 files changed, 403 insertions, 582 deletions
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 418b28ac19..b7667a5c29 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -1702,10 +1702,7 @@ class DumperBase:
formats = (',formats=\"%s\"' % str(value)[1:-1]) if len(value) else ''
msg += '{type="%s"%s%s},' % (key, editable, formats)
msg += ']'
- self.reportDumpers(msg)
-
- def reportDumpers(self, msg):
- raise NotImplementedError
+ return msg
def reloadDumpers(self, args):
for mod in self.dumpermodules:
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index fb45f2ce86..123d2f5957 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -1665,10 +1665,7 @@ class Dumper(DumperBase):
gdb.execute("quit")
def loadDumpers(self, args):
- self.setupDumpers()
-
- def reportDumpers(self, msg):
- print(msg)
+ print(self.setupDumpers())
def profile1(self, args):
"""Internal profiling"""
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index 3f18e6f20f..8a4da00499 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -547,10 +547,9 @@ class Dumper(DumperBase):
self.report('output="%s"' % result.GetOutput())
else:
self.report('error="%s"' % result.GetError())
- self.reportData()
def put(self, stuff):
- sys.stdout.write(stuff)
+ self.out += stuff
def isMovableType(self, type):
if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
@@ -656,7 +655,6 @@ class Dumper(DumperBase):
return None
def setupInferior(self, args):
- self.reportToken(args)
error = lldb.SBError()
self.executable_ = args['executable']
@@ -697,12 +695,8 @@ class Dumper(DumperBase):
else:
self.target = self.debugger.CreateTarget(None, None, None, True, error)
- if self.target.IsValid():
- 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_))
+ state = 1 if self.target.IsValid() else 0
+ self.reportResult('success="%s",msg="%s",exe="%s"' % (state, error, self.executable_), args)
def runEngine(self, args):
self.prepare(args)
@@ -710,7 +704,6 @@ class Dumper(DumperBase):
s.start()
def prepare(self, args):
- self.reportToken(args)
error = lldb.SBError()
listener = self.debugger.GetListener()
@@ -730,7 +723,7 @@ class Dumper(DumperBase):
self.debugger.GetListener(),
self.remoteChannel_, None, error)
if not error.Success():
- self.reportError(error)
+ self.report(self.describeError(error))
self.reportState("enginerunfailed")
return
# Even if it stops it seems that LLDB assumes it is running
@@ -741,7 +734,6 @@ class Dumper(DumperBase):
coreFile = args.get('coreFile', '');
self.process = self.target.LoadCore(coreFile)
self.reportState("enginerunokandinferiorunrunnable")
- #self.reportContinuation(args)
else:
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
launchInfo.SetWorkingDirectory(os.getcwd())
@@ -751,7 +743,7 @@ class Dumper(DumperBase):
self.createBreakpointAtMain()
self.process = self.target.Launch(launchInfo, error)
if not error.Success():
- self.reportError(error)
+ self.report(self.describeError(error))
self.reportState("enginerunfailed")
return
self.report('pid="%s"' % self.process.GetProcessID())
@@ -769,15 +761,23 @@ class Dumper(DumperBase):
def describeError(self, error):
desc = lldb.SBStream()
error.GetDescription(desc)
- result = 'error={type="%s"' % error.GetType()
+ result = 'success="%s",' % int(error.Success())
+ result += 'error={type="%s"' % error.GetType()
+ if error.GetType():
+ result += ',status="%s"' % error.GetCString()
result += ',code="%s"' % error.GetError()
result += ',desc="%s"}' % desc.GetData()
return result
- def reportError(self, error):
- self.report(self.describeError(error))
- if error.GetType():
- self.reportStatus(error.GetCString())
+ def describeStatus(self, status):
+ return 'status="%s",' % status
+
+ def describeLocation(self, frame):
+ if int(frame.pc) == 0xffffffffffffffff:
+ return ''
+ file = fileName(frame.line_entry.file)
+ line = frame.line_entry.line
+ return 'location={file="%s",line="%s",addr="%s"}' % (file, line, frame.pc)
def currentThread(self):
return None if self.process is None else self.process.GetSelectedThread()
@@ -786,13 +786,6 @@ class Dumper(DumperBase):
thread = self.currentThread()
return None if thread is None else thread.GetSelectedFrame()
- def reportLocation(self, frame):
- if int(frame.pc) != 0xffffffffffffffff:
- file = fileName(frame.line_entry.file)
- line = frame.line_entry.line
- self.report('location={file="%s",line="%s",addr="%s"}'
- % (file, line, frame.pc))
-
def firstStoppedThread(self):
for i in xrange(0, self.process.GetNumThreads()):
thread = self.process.GetThreadAtIndex(i)
@@ -805,9 +798,8 @@ class Dumper(DumperBase):
return thread
return None
- def reportThreads(self, args):
- self.reportToken(args)
- result = 'threads={threads=['
+ def fetchThreads(self, args):
+ result = 'threads=['
for i in xrange(0, self.process.GetNumThreads()):
thread = self.process.GetThreadAtIndex(i)
if thread.is_stopped:
@@ -834,12 +826,8 @@ class Dumper(DumperBase):
result += ',file="%s"' % fileName(frame.line_entry.file)
result += '}},'
- result += ']},'
- self.report(result)
-
- def reportCurrentThread(self, args):
- self.reportToken(args)
- self.report('current-thread={id="%s"}' % self.currentThread().id)
+ result += '],current-thread-id="%s"' % self.currentThread().id
+ self.reportResult(result, args)
def firstUsableFrame(self, thread):
for i in xrange(10):
@@ -850,17 +838,16 @@ class Dumper(DumperBase):
return i
return None
- def reportStack(self, args):
- self.reportToken(args)
+ def fetchStack(self, args):
if not self.process:
- self.report('msg="No process"')
+ self.reportResult('msg="No process"', args)
return
thread = self.currentThread()
if not thread:
- self.report('msg="No thread"')
+ self.reportResult('msg="No thread"', args)
return
- self.reportLocation(thread.GetFrameAtIndex(0)) # FIXME
+ self.report(self.describeLocation(thread.GetFrameAtIndex(0))) # FIXME
isNativeMixed = int(args.get('nativeMixed', 0))
@@ -919,8 +906,10 @@ class Dumper(DumperBase):
result += ',hasmore="%d"' % isLimited
result += ',limit="%d"' % limit
result += '}'
- self.report(result)
- self.reportContinuation(args)
+ self.reportResult(result, args)
+
+ def reportResult(self, result, args):
+ self.report('result={token="%s",%s}' % (args.get("token", 0), result))
def reportToken(self, args):
if "token" in args:
@@ -928,10 +917,6 @@ class Dumper(DumperBase):
# logview pane feature.
self.report('token(\"%s\")' % args["token"])
- def reportContinuation(self, args):
- if not self.isShuttingDown_ and "continuation" in args:
- self.report('continuation=\"%s\"' % args["continuation"])
-
def extractBlob(self, base, size):
if size == 0:
return Blob("")
@@ -1171,11 +1156,10 @@ class Dumper(DumperBase):
with SubItem(self, child):
self.putItem(child)
- def reportVariables(self, args = {}):
- with self.outputLock:
- sys.stdout.write("@\n")
- self.reportVariablesHelper(args)
- sys.stdout.write("@\n")
+ def reportVariables(self, args):
+ self.out = ""
+ self.reportVariablesHelper(args)
+ self.reportResult(self.out, args)
def reportVariablesHelper(self, args = {}):
frame = self.currentFrame()
@@ -1186,7 +1170,7 @@ class Dumper(DumperBase):
isPartial = len(partialVariable) > 0
self.currentIName = 'local'
- self.put('all={data=[')
+ self.put('data=[')
self.anonNumber = 0
shadowed = {}
ids = {} # Filter out duplicates entries at the same address.
@@ -1248,19 +1232,11 @@ class Dumper(DumperBase):
self.handleWatches(args)
- self.put('],partial="%d"}' % isPartial)
+ self.put('],partial="%d"' % isPartial)
- def reportData(self, _ = None):
+ def fetchRegisters(self, args = None):
if self.process is None:
- self.report('process="none"')
- else:
- state = self.process.GetState()
- if state == lldb.eStateStopped:
- self.reportVariables()
-
- def reportRegisters(self, _ = None):
- if self.process is None:
- self.report('process="none"')
+ result = 'process="none"'
else:
frame = self.currentFrame()
if frame:
@@ -1273,10 +1249,9 @@ class Dumper(DumperBase):
result += ',size="%s"' % reg.GetByteSize()
result += ',type="%s"},' % reg.GetType()
result += ']'
- self.report(result)
+ self.reportResult(result, args)
def setRegister(self, args):
- self.reportToken(args)
name = args["name"]
value = args["value"]
result = lldb.SBCommandReturnObject()
@@ -1284,55 +1259,50 @@ class Dumper(DumperBase):
interp.HandleCommand("register write %s %s" % (name, value), result)
success = result.Succeeded()
if success:
- self.report('output="%s"' % result.GetOutput())
+ self.reportResult('output="%s"' % result.GetOutput(), args)
return
# Try again with register write xmm0 "{0x00 ... 0x02}" syntax:
vec = ' '.join(["0x" + value[i:i+2] for i in range(2, len(value), 2)])
success = interp.HandleCommand('register write %s "{%s}"' % (name, vec), result)
if success:
- self.report('output="%s"' % result.GetOutput())
- return
- self.report('error="%s"' % result.GetError())
+ self.reportResult('output="%s"' % result.GetOutput(), args)
+ else:
+ self.reportResult('error="%s"' % result.GetError(), args)
def report(self, stuff):
with self.outputLock:
sys.stdout.write("@\n" + stuff + "@\n")
- def reportStatus(self, msg):
- self.report('statusmessage="%s"' % msg)
+ def reportState(self, state):
+ self.report('state="%s"' % state)
- def interruptInferior(self, _ = None):
- self.reportToken(args)
+ def interruptInferior(self, args):
if self.process is None:
- self.reportStatus("No process to interrupt.")
- return
- self.isInterrupting_ = True
- error = self.process.Stop()
- self.reportError(error)
+ self.reportResult('status="No process to interrupt",success="0"', args)
+ else:
+ self.isInterrupting_ = True
+ error = self.process.Stop()
+ self.reportResult(describeError(error), args)
- def detachInferior(self, _ = None):
- self.reportToken(args)
+ def detachInferior(self, args):
if self.process is None:
- self.reportStatus("No process to detach from.")
+ self.reportResult('status="No process to detach from."', args)
else:
error = self.process.Detach()
- self.reportError(error)
- self.reportData()
+ self.reportResult(self.describeError(error), args)
- def continueInferior(self, _ = None):
- self.reportToken(args)
+ def continueInferior(self, args):
if self.process is None:
- self.reportStatus("No process to continue.")
+ self.reportResult('status="No process to continue."', args)
else:
+ # Can fail when attaching to GDBserver.
error = self.process.Continue()
- self.reportError(error)
- # Happens when attaching to GDBserver.
- if not error.Success():
- self.reportState("inferiorill")
+ self.reportResult(self.describeError(error), args)
- def quitDebugger(self, _ = None):
+ def quitDebugger(self, args):
self.reportState("inferiorshutdownrequested")
self.process.Kill()
+ self.reportResult('', args)
def handleEvent(self, event):
out = lldb.SBStream()
@@ -1407,9 +1377,6 @@ class Dumper(DumperBase):
elif eventType == lldb.SBProcess.eBroadcastBitProfileData:
pass
- def reportState(self, state):
- self.report('state="%s"' % state)
-
def describeBreakpoint(self, bp):
isWatch = isinstance(bp, lldb.SBWatchpoint)
if isWatch:
@@ -1419,32 +1386,28 @@ class Dumper(DumperBase):
if not bp.IsValid():
return
result += ',hitcount="%s"' % bp.GetHitCount()
- if hasattr(bp, 'GetThreadID'):
- result += ',threadid="%s"' % bp.GetThreadID()
- if hasattr(bp, 'IsOneShot'):
- result += ',oneshot="%s"' % (1 if bp.IsOneShot() else 0)
- if hasattr(bp, 'GetCondition'):
- cond = bp.GetCondition()
- result += ',condition="%s"' % self.hexencode("" if cond is None else cond)
+ result += ',threadid="%s"' % bp.GetThreadID()
+ result += ',oneshot="%s"' % (1 if bp.IsOneShot() else 0)
+ cond = bp.GetCondition()
+ result += ',condition="%s"' % self.hexencode("" if cond is None else cond)
result += ',enabled="%s"' % (1 if bp.IsEnabled() else 0)
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"},' % addr.GetFileAddress()
+ 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"},' % addr.GetFileAddress()
result += ']'
if lineEntry is not None:
result += ',file="%s"' % lineEntry.GetFileSpec()
@@ -1463,8 +1426,8 @@ class Dumper(DumperBase):
self.insertQmlBreakpoint(args)
return
+ extra = ''
more = True
- modelId = args['modelid']
if bpType == BreakpointByFileAndLine:
bp = self.target.BreakpointCreateByLocation(
str(args["fileName"]), int(args["lineNumber"]))
@@ -1484,7 +1447,7 @@ class Dumper(DumperBase):
error = lldb.SBError()
bp = self.target.WatchAddress(args["address"], 4, False, True, error)
#warn("BPNEW: %s" % bp)
- self.reportError(error)
+ extra = self.describeError(error)
elif bpType == WatchpointAtExpression:
# FIXME: Top level-only for now.
try:
@@ -1503,17 +1466,13 @@ class Dumper(DumperBase):
if more:
bp.SetIgnoreCount(int(args["ignorecount"]))
- if hasattr(bp, 'SetCondition'):
- bp.SetCondition(self.hexdecode(args["condition"]))
+ bp.SetCondition(self.hexdecode(args["condition"]))
bp.SetEnabled(bool(args["enabled"]))
- if hasattr(bp, 'SetOneShot'):
- bp.SetOneShot(bool(args["oneshot"]))
- self.report('breakpoint-added={%s,modelid="%s"}' % (self.describeBreakpoint(bp), modelId))
+ bp.SetOneShot(bool(args["oneshot"]))
+ self.reportResult(self.describeBreakpoint(bp) + extra, args)
def changeBreakpoint(self, args):
- self.reportToken(args)
lldbId = int(args["lldbid"])
- modelId = args['modelid']
if lldbId > qqWatchpointOffset:
bp = self.target.FindWatchpointByID(lldbId)
else:
@@ -1521,21 +1480,17 @@ class Dumper(DumperBase):
bp.SetIgnoreCount(int(args["ignorecount"]))
bp.SetCondition(self.hexdecode(args["condition"]))
bp.SetEnabled(bool(args["enabled"]))
- if hasattr(bp, 'SetOneShot'):
- bp.SetOneShot(bool(args["oneshot"]))
- self.report('breakpoint-changed={%s,modelid="%s"}'
- % (self.describeBreakpoint(bp), modelId))
+ bp.SetOneShot(bool(args["oneshot"]))
+ self.reportResult(self.describeBreakpoint(bp), args)
def removeBreakpoint(self, args):
- self.reportToken(args)
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)
+ self.reportResult('success="%s"' % int(res), args)
- def listModules(self, args):
+ def fetchModules(self, args):
result = 'modules=['
for i in xrange(self.target.GetNumModules()):
module = self.target.GetModuleAtIndex(i)
@@ -1551,10 +1506,9 @@ class Dumper(DumperBase):
#result += '}'
result += '},'
result += ']'
- self.report(result)
+ self.reportResult(result, args)
- def listSymbols(self, args):
- self.reportToken(args)
+ def fetchSymbols(self, args):
moduleName = args['module']
#file = lldb.SBFileSpec(moduleName)
#module = self.target.FindModule(file)
@@ -1562,8 +1516,7 @@ class Dumper(DumperBase):
module = self.target.GetModuleAtIndex(i)
if module.file.fullpath == moduleName:
break
- result = 'symbols={module="%s"' % moduleName
- result += ',valid="%s"' % module.IsValid()
+ result = 'symbols={valid="%s"' % module.IsValid()
result += ',sections="%s"' % module.GetNumSections()
result += ',symbols=['
for symbol in module.symbols:
@@ -1576,22 +1529,21 @@ class Dumper(DumperBase):
result += ',size="%s"' % (endAddress - startAddress)
result += '},'
result += ']}'
- self.report(result)
+ self.reportResult(result, args)
- def executeNext(self, _ = None):
- self.reportToken(args)
+ def executeNext(self, args):
self.currentThread().StepOver()
+ self.reportResult('', args)
- def executeNextI(self, _ = None):
- self.reportToken(args)
+ def executeNextI(self, args):
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
+ self.reportResult('', args)
- def executeStep(self, _ = None):
- self.reportToken(args)
+ def executeStep(self, args):
self.currentThread().StepInto()
+ self.reportResult('', args)
- def shutdownInferior(self, _ = None):
- self.reportToken(args)
+ def shutdownInferior(self, args):
self.isShuttingDown_ = True
if self.process is None:
self.reportState("inferiorshutdownok")
@@ -1600,19 +1552,20 @@ class Dumper(DumperBase):
if state == lldb.eStateStopped:
self.process.Kill()
self.reportState("inferiorshutdownok")
+ self.reportResult('', args)
- def quit(self, args = {}):
- self.reportToken(args)
+ def quit(self, args):
self.reportState("engineshutdownok")
self.process.Kill()
+ self.reportResult('', args)
- def executeStepI(self, args = {}):
- self.reportToken(args)
+ def executeStepI(self, args):
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
+ self.reportResult('', args)
def executeStepOut(self, args = {}):
- self.reportToken(args)
self.currentThread().StepOut()
+ self.reportResult('', args)
def executeRunToLocation(self, args):
self.reportToken(args)
@@ -1623,28 +1576,26 @@ class Dumper(DumperBase):
bp = self.target.BreakpointCreateByAddress(addr)
if bp.GetNumLocations() == 0:
self.target.BreakpointDelete(bp.GetID())
- self.reportStatus("No target location found.")
- self.reportLocation(frame)
+ self.reportResult(self.describeStatus("No target location found.")
+ + self.describeLocation(frame), args)
return
bp.SetOneShot(True)
+ self.reportResult('', args)
self.process.Continue()
else:
frame = self.currentFrame()
file = args['file']
line = int(args['line'])
error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line)
- if error.GetType():
- self.reportState("running")
- self.reportState("stopped")
- self.reportError(error)
- else:
- self.reportData()
+ self.reportResult(self.describeError(error), args)
+ self.reportState("running")
+ self.reportState("stopped")
def executeJumpToLocation(self, args):
self.reportToken(args)
frame = self.currentFrame()
if not frame:
- self.reportStatus("No frame available.")
+ self.reportResult(self.describeStatus("No frame available."), args)
return
addr = args.get('address', 0)
if addr:
@@ -1654,16 +1605,13 @@ class Dumper(DumperBase):
str(args['file']), int(args['line']))
if bp.GetNumLocations() == 0:
self.target.BreakpointDelete(bp.GetID())
- self.reportStatus("No target location found.")
- self.reportLocation(frame)
- return
- loc = bp.GetLocationAtIndex(0)
- self.target.BreakpointDelete(bp.GetID())
- if frame.SetPC(loc.GetLoadAddress()):
- self.report("Jumped.")
+ status = "No target location found."
else:
- self.report("Cannot jump.")
- self.reportLocation(frame)
+ loc = bp.GetLocationAtIndex(0)
+ self.target.BreakpointDelete(bp.GetID())
+ res = frame.SetPC(loc.GetLoadAddress())
+ status = "Jumped." if res else "Cannot jump."
+ self.reportResult(self.describeStatus(status) + self.describeLocation(frame), args)
def breakList(self):
result = lldb.SBCommandReturnObject()
@@ -1675,22 +1623,18 @@ class Dumper(DumperBase):
self.reportToken(args)
thread = args['thread']
self.currentThread().SetSelectedFrame(args['index'])
- self.reportContinuation(args)
+ self.reportResult('', args)
def selectThread(self, args):
self.reportToken(args)
self.process.SetSelectedThreadByID(args['id'])
+ self.reportResult('', args)
- def requestModuleSymbols(self, frame):
- self.reportToken(args)
- self.handleCommand("target module list " + frame)
-
- def createFullBacktrace(self, _ = None):
- self.reportToken(args)
+ def fetchFullBacktrace(self, _ = None):
command = "thread backtrace all"
result = lldb.SBCommandReturnObject()
self.debugger.GetCommandInterpreter().HandleCommand(command, result)
- self.report('full-backtrace="%s"' % self.hexencode(result.GetOutput()))
+ self.reportResult(self.hexencode(result.GetOutput()), {})
def executeDebuggerCommand(self, args):
self.reportToken(args)
@@ -1702,8 +1646,8 @@ class Dumper(DumperBase):
error = str(result.GetError())
self.report('success="%d",output="%s",error="%s"' % (success, output, error))
- def updateData(self, args):
- self.reportToken(args)
+ def fetchLocals(self, args):
+ self.output = ''
self.expandedINames = set(args.get('expanded', []))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.sortStructMembers = bool(args.get("sortStructMembers", True));
@@ -1715,8 +1659,7 @@ class Dumper(DumperBase):
self.formats = args.get("formats", {})
self.reportVariables(args)
- def disassemble(self, args):
- self.reportToken(args)
+ def fetchDisassembler(self, args):
functionName = args.get('function', '')
flavor = args.get('flavor', '')
function = None
@@ -1739,8 +1682,7 @@ class Dumper(DumperBase):
currentLine = None
hunks = dict()
sources = dict()
- result = 'disassembly={cookie="%s",' % args['cookie']
- result += ',lines=['
+ result = 'lines=['
for insn in instructions:
comment = insn.GetComment(self.target)
addr = insn.GetAddress()
@@ -1774,26 +1716,21 @@ class Dumper(DumperBase):
if comment:
result += ',comment="%s"' % comment
result += ',offset="%s"}' % (loadAddr - base)
- self.report(result + ']')
+ self.reportResult(result + ']', args)
def loadDumpers(self, args):
- self.reportToken(args)
- self.setupDumpers()
-
- def reportDumpers(self, msg):
- self.report(msg)
+ msg = self.setupDumpers()
+ self.reportResult(msg, args)
def fetchMemory(self, args):
- self.reportToken(args)
address = args['address']
length = args['length']
error = lldb.SBError()
contents = self.process.ReadMemory(address, length, error)
- result = 'memory={cookie="%s",' % args['cookie']
- result += ',address="%s",' % address
+ result = 'address="%s",' % address
result += self.describeError(error)
- result += ',contents="%s"}' % self.hexencode(contents)
- self.report(result)
+ result += ',contents="%s"' % self.hexencode(contents)
+ self.reportResult(result, args)
def findValueByExpression(self, exp):
# FIXME: Top level-only for now.
@@ -1808,8 +1745,7 @@ class Dumper(DumperBase):
value = self.hexdecode(args['value'])
lhs = self.findValueByExpression(exp)
lhs.SetValueFromCString(value, error)
- self.reportError(error)
- self.reportVariables()
+ self.reportResult(describeError(error), args)
def createResolvePendingBreakpointsHookBreakpoint(self, args):
if self.qmlTriggeredBreakpoint is None:
@@ -1832,7 +1768,7 @@ class Tester(Dumper):
self.passExceptions = True
self.sortStructMembers = True
- self.loadDumpers({})
+ self.loadDumpers({'token': 1})
error = lldb.SBError()
self.target = self.debugger.CreateTarget(binary, None, None, True, error)
@@ -1890,8 +1826,8 @@ class Tester(Dumper):
if line != 0:
self.report = savedReport
self.process.SetSelectedThread(stoppedThread)
- self.reportVariables()
- #self.reportLocation(frame)
+ self.reportVariables({'token':2})
+ #self.describeLocation(frame)
self.report("@NS@%s@" % self.qtNamespace())
#self.report("ENV=%s" % os.environ.items())
#self.report("DUMPER=%s" % self.qqDumpers)
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 0e26fdcb18..21eec10980 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -4719,7 +4719,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters &params)
cmd.arg("partialVariable", params.partialVariable);
cmd.arg("sortStructMembers", boolSetting(SortStructMembers));
cmd.flags = Discardable | InUpdateLocals;
- cmd.callback = [this](const DebuggerResponse &r) { handleStackFrame(r); };
+ cmd.callback = CB(handleStackFrame);
runCommand(cmd);
cmd.arg("passExceptions", true);
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index 6500b766bd..ceb135f313 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -107,7 +107,7 @@ LldbEngine::LldbEngine(const DebuggerRunParameters &startParameters)
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
this, &LldbEngine::updateLocals);
connect(action(CreateFullBacktrace), &QAction::triggered,
- this, &LldbEngine::createFullBacktrace);
+ this, &LldbEngine::fetchFullBacktrace);
connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
this, &LldbEngine::updateLocals);
connect(action(UseDynamicType), &SavedAction::valueChanged,
@@ -138,6 +138,7 @@ void LldbEngine::runCommand(const DebuggerCommand &command_)
QByteArray token = QByteArray::number(tok);
QByteArray cmd = command.function + "({" + command.args + "})";
showMessage(_(token + cmd + '\n'), LogInput);
+ m_commandForToken[currentToken()] = command;
m_lldbProc.write("script theDumper." + cmd + "\n");
}
@@ -316,12 +317,11 @@ void LldbEngine::setupInferior()
}
DebuggerCommand cmd1("loadDumpers");
+ cmd1.callback = [this](const DebuggerResponse &response) {
+ watchHandler()->addDumpers(response.data);
+ };
runCommand(cmd1);
-}
-// FIXME: splitting of setupInferior() necessary to support LLDB <= 310 - revert asap
-void LldbEngine::setupInferiorStage2()
-{
const DebuggerRunParameters &rp = runParameters();
QString executable;
@@ -329,33 +329,16 @@ void LldbEngine::setupInferiorStage2()
QtcProcess::prepareCommand(QFileInfo(rp.executable).absoluteFilePath(),
rp.processArgs, &executable, &args);
- DebuggerCommand cmd("setupInferior");
- cmd.arg("executable", executable);
- cmd.arg("breakOnMain", rp.breakOnMain);
- cmd.arg("useTerminal", rp.useTerminal);
- cmd.arg("startMode", rp.startMode);
-
- 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);
- bp.notifyBreakpointInsertProceeding();
- cmd.beginGroup();
- bp.addToCommand(&cmd);
- cmd.endGroup();
- } else {
- showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
- .arg(bp.id().toString()).arg(bp.state()));
- }
- }
- cmd.endList();
+ DebuggerCommand cmd2("setupInferior");
+ cmd2.arg("executable", executable);
+ cmd2.arg("breakOnMain", rp.breakOnMain);
+ cmd2.arg("useTerminal", rp.useTerminal);
+ cmd2.arg("startMode", rp.startMode);
- cmd.beginList("processArgs");
+ cmd2.beginList("processArgs");
foreach (const QString &arg, args.toUnixArgs())
- cmd.arg(arg.toUtf8().toHex());
- cmd.endList();
+ cmd2.arg(arg.toUtf8().toHex());
+ cmd2.endList();
if (rp.useTerminal) {
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
@@ -365,28 +348,45 @@ void LldbEngine::setupInferiorStage2()
? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
: QString::fromLatin1("Attaching to %1").arg(attachedPID);
showMessage(msg, LogMisc);
- cmd.arg("attachPid", attachedPID);
+ cmd2.arg("attachPid", attachedPID);
} else {
- cmd.arg("startMode", rp.startMode);
+ cmd2.arg("startMode", rp.startMode);
// it is better not to check the start mode on the python sid (as we would have to duplicate the
// enum values), and thus we assume that if the rp.attachPID is valid we really have to attach
QTC_CHECK(rp.attachPID <= 0 || (rp.startMode == AttachCrashedExternal
|| rp.startMode == AttachExternal));
- cmd.arg("attachPid", rp.attachPID);
- cmd.arg("sysRoot", rp.deviceSymbolsRoot.isEmpty() ? rp.sysRoot : rp.deviceSymbolsRoot);
- cmd.arg("remoteChannel", ((rp.startMode == AttachToRemoteProcess
+ cmd2.arg("attachPid", rp.attachPID);
+ cmd2.arg("sysRoot", rp.deviceSymbolsRoot.isEmpty() ? rp.sysRoot : rp.deviceSymbolsRoot);
+ cmd2.arg("remoteChannel", ((rp.startMode == AttachToRemoteProcess
|| rp.startMode == AttachToRemoteServer)
? rp.remoteChannel : QString()));
- cmd.arg("platform", rp.platform);
+ cmd2.arg("platform", rp.platform);
QTC_CHECK(!rp.continueAfterAttach || (rp.startMode == AttachToRemoteProcess
|| rp.startMode == AttachExternal
|| rp.startMode == AttachToRemoteServer));
m_continueAtNextSpontaneousStop = false;
}
- runCommand(cmd);
+ cmd2.callback = [this](const DebuggerResponse &response) {
+ bool success = response.data["success"].toInt();
+ if (success) {
+ foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) {
+ if (acceptsBreakpoint(bp)) {
+ bp.setEngine(this);
+ insertBreakpoint(bp);
+ } else {
+ showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
+ .arg(bp.id().toString()).arg(bp.state()));
+ }
+ }
+ notifyInferiorSetupOk();
+ } else {
+ notifyInferiorSetupFailed();
+ }
+ };
+ runCommand(cmd2);
}
void LldbEngine::runEngine()
@@ -395,10 +395,8 @@ void LldbEngine::runEngine()
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return);
showStatusMessage(tr("Running requested..."), 5000);
DebuggerCommand cmd("runEngine");
- if (rp.startMode == AttachCore) {
+ if (rp.startMode == AttachCore)
cmd.arg("coreFile", rp.coreFile);
- cmd.arg("continuation", "updateAll");
- }
runCommand(cmd);
}
@@ -447,7 +445,12 @@ void LldbEngine::continueInferior()
{
resetLocation();
notifyInferiorRunRequested();
- runCommand("continueInferior");
+ DebuggerCommand cmd("continueInferior");
+ cmd.callback = [this](const DebuggerResponse &response) {
+ if (response.resultClass == ResultError)
+ notifyEngineIll();
+ };
+ runCommand(cmd);
}
void LldbEngine::handleResponse(const QByteArray &response)
@@ -457,72 +460,31 @@ void LldbEngine::handleResponse(const QByteArray &response)
foreach (const GdbMi &item, all.children()) {
const QByteArray name = item.name();
- if (name == "all") {
- updateLocalsView(item);
- watchHandler()->notifyUpdateFinished();
- } else if (name == "dumpers") {
- watchHandler()->addDumpers(item);
- setupInferiorStage2();
- } else if (name == "stack")
- refreshStack(item);
- else if (name == "registers")
- refreshRegisters(item);
- else if (name == "threads")
- refreshThreads(item);
- else if (name == "current-thread")
- refreshCurrentThread(item);
- else if (name == "typeinfo")
- refreshTypeInfo(item);
- else if (name == "state")
- refreshState(item);
- else if (name == "location")
- refreshLocation(item);
- else if (name == "modules")
- refreshModules(item);
- else if (name == "symbols")
- refreshSymbols(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")
- refreshDisassembly(item);
- else if (name == "memory")
- refreshMemory(item);
- else if (name == "full-backtrace")
- showFullBacktrace(item);
- else if (name == "continuation")
- handleContinuation(item);
- else if (name == "statusmessage") {
- QString msg = QString::fromUtf8(item.data());
+ if (name == "result") {
+ QString msg = item["status"].toUtf8();
if (msg.size())
msg[0] = msg.at(0).toUpper();
showStatusMessage(msg);
- }
- }
-}
-void LldbEngine::handleContinuation(const GdbMi &data)
-{
- if (data.data() == "updateLocals") {
- updateLocals();
- } else if (data.data() == "updateAll") {
- updateAll();
- } else {
- QTC_ASSERT(false, qDebug() << "Unknown continuation: " << data.data());
+ int token = item["token"].toInt();
+ showMessage(QString::fromLatin1("%1^").arg(token), LogOutput);
+ if (m_commandForToken.contains(token)) {
+ DebuggerCommand cmd = m_commandForToken.take(token);
+ DebuggerResponse response;
+ response.token = token;
+ response.data = item;
+ if (cmd.callback)
+ cmd.callback(response);
+ }
+ } else if (name == "state")
+ handleStateNotification(item);
+ else if (name == "location")
+ handleLocationNotification(item);
+ else if (name == "output")
+ handleOutputNotification(item);
}
}
-void LldbEngine::showFullBacktrace(const GdbMi &data)
-{
- Internal::openTextEditor(_("Backtrace $"),
- QString::fromUtf8(QByteArray::fromHex(data.data())));
-}
-
void LldbEngine::executeRunToLine(const ContextData &data)
{
resetLocation();
@@ -559,13 +521,8 @@ void LldbEngine::activateFrame(int frameIndex)
return;
StackHandler *handler = stackHandler();
-
- const int n = handler->stackSize();
- if (frameIndex == n) {
- DebuggerCommand cmd("reportStack");
- cmd.arg("nativeMixed", isNativeMixedActive());
- cmd.arg("stacklimit", n * 10 + 3);
- runCommand(cmd);
+ if (frameIndex == handler->stackSize()) {
+ fetchStack(handler->stackSize() * 10 + 3);
return;
}
@@ -576,20 +533,23 @@ void LldbEngine::activateFrame(int frameIndex)
DebuggerCommand cmd("activateFrame");
cmd.arg("index", frameIndex);
cmd.arg("thread", threadsHandler()->currentThread().raw());
- cmd.arg("continuation", "updateLocals");
runCommand(cmd);
+
+ updateLocals();
+ reloadRegisters();
}
void LldbEngine::selectThread(ThreadId threadId)
{
- DebuggerCommand cmd1("selectThread");
- cmd1.arg("id", threadId.raw());
- runCommand(cmd1);
-
- DebuggerCommand cmd("reportStack");
- cmd.arg("nativeMixed", isNativeMixedActive());
- cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt());
- cmd.arg("continuation", "updateLocals");
+ DebuggerCommand cmd("selectThread");
+ cmd.arg("id", threadId.raw());
+ cmd.callback = [this](const DebuggerResponse &) {
+ DebuggerCommand cmd("fetchStack");
+ cmd.arg("nativeMixed", isNativeMixedActive());
+ cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt());
+ runCommand(cmd);
+ updateLocals();
+ };
runCommand(cmd);
}
@@ -620,6 +580,10 @@ bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
void LldbEngine::insertBreakpoint(Breakpoint bp)
{
DebuggerCommand cmd("insertBreakpoint");
+ cmd.callback = [this, bp](const DebuggerResponse &response) {
+ QTC_CHECK(bp.state() == BreakpointInsertProceeding);
+ updateBreakpointData(bp, response.data, true);
+ };
bp.addToCommand(&cmd);
bp.notifyBreakpointInsertProceeding();
runCommand(cmd);
@@ -630,6 +594,10 @@ void LldbEngine::changeBreakpoint(Breakpoint bp)
const BreakpointResponse &response = bp.response();
DebuggerCommand cmd("changeBreakpoint");
cmd.arg("lldbid", response.id.toByteArray());
+ cmd.callback = [this, bp](const DebuggerResponse &response) {
+ QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
+ updateBreakpointData(bp, response.data, false);
+ };
bp.addToCommand(&cmd);
bp.notifyBreakpointChangeProceeding();
runCommand(cmd);
@@ -638,19 +606,23 @@ void LldbEngine::changeBreakpoint(Breakpoint bp)
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);
+ if (response.id.isValid()) {
+ DebuggerCommand cmd("removeBreakpoint");
+ cmd.arg("lldbid", response.id.toByteArray());
+ cmd.callback = [this, bp](const DebuggerResponse &) {
+ QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
+ Breakpoint bp0 = bp;
+ bp0.notifyBreakpointRemoveOk();
+ };
+ bp.notifyBreakpointRemoveProceeding();
+ runCommand(cmd);
+ }
}
-void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
+void LldbEngine::updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added)
{
BreakHandler *handler = breakHandler();
BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
- BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
- Breakpoint bp = handler->breakpointById(id);
if (!bp.isValid())
bp = handler->findBreakpointByResponseId(rid);
BreakpointResponse response = bp.response();
@@ -694,50 +666,7 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
bp.notifyBreakpointChangeOk();
}
-void LldbEngine::refreshDisassembly(const GdbMi &data)
-{
- DisassemblerLines result;
-
- int cookie = data["cookie"].toInt();
- QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(cookie);
- if (!agent.isNull()) {
- foreach (const GdbMi &line, data["lines"].children()) {
- DisassemblerLine dl;
- dl.address = line["address"].toAddress();
- //dl.data = line["data"].toUtf8();
- //dl.rawData = line["rawdata"].data();
- dl.data = line["rawdata"].toUtf8();
- if (!dl.data.isEmpty())
- dl.data += QString(30 - dl.data.size(), QLatin1Char(' '));
- dl.data += line["data"].toUtf8();
- dl.offset = line["offset"].toInt();
- dl.lineNumber = line["line"].toInt();
- dl.fileName = line["file"].toUtf8();
- dl.function = line["function"].toUtf8();
- dl.hunk = line["hunk"].toInt();
- QByteArray comment = line["comment"].data();
- if (!comment.isEmpty())
- dl.data += QString::fromUtf8(" # " + comment);
- result.appendLine(dl);
- }
- agent->setContents(result);
- }
-}
-
-void LldbEngine::refreshMemory(const GdbMi &data)
-{
- int cookie = data["cookie"].toInt();
- qulonglong addr = data["address"].toAddress();
- QPointer<MemoryAgent> agent = m_memoryAgents.key(cookie);
- if (!agent.isNull()) {
- QPointer<QObject> token = m_memoryAgentTokens.value(cookie);
- QTC_ASSERT(!token.isNull(), return);
- QByteArray ba = QByteArray::fromHex(data["contents"].data());
- agent->addLazyData(token.data(), addr, ba);
- }
-}
-
-void LldbEngine::refreshOutput(const GdbMi &output)
+void LldbEngine::handleOutputNotification(const GdbMi &output)
{
QByteArray channel = output["channel"].data();
QByteArray data = QByteArray::fromHex(output["data"].data());
@@ -749,30 +678,6 @@ void LldbEngine::refreshOutput(const GdbMi &output)
showMessage(QString::fromUtf8(data), ch);
}
-void LldbEngine::refreshAddedBreakpoint(const GdbMi &bkpt)
-{
- BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
- Breakpoint bp = breakHandler()->breakpointById(id);
- QTC_CHECK(bp.state() == BreakpointInsertProceeding);
- updateBreakpointData(bkpt, true);
-}
-
-void LldbEngine::refreshChangedBreakpoint(const GdbMi &bkpt)
-{
- BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
- Breakpoint bp = breakHandler()->breakpointById(id);
- QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
- updateBreakpointData(bkpt, false);
-}
-
-void LldbEngine::refreshRemovedBreakpoint(const GdbMi &bkpt)
-{
- BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
- Breakpoint bp = breakHandler()->breakpointById(id);
- QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
- bp.notifyBreakpointRemoveOk();
-}
-
void LldbEngine::loadSymbols(const QString &moduleName)
{
Q_UNUSED(moduleName)
@@ -784,48 +689,47 @@ void LldbEngine::loadAllSymbols()
void LldbEngine::reloadModules()
{
- runCommand("listModules");
-}
-
-void LldbEngine::refreshModules(const GdbMi &modules)
-{
- ModulesHandler *handler = modulesHandler();
- handler->beginUpdateAll();
- foreach (const GdbMi &item, modules.children()) {
- Module module;
- module.modulePath = item["file"].toUtf8();
- module.moduleName = item["name"].toUtf8();
- module.symbolsRead = Module::UnknownReadState;
- module.startAddress = item["loaded_addr"].toAddress();
- module.endAddress = 0; // FIXME: End address not easily available.
- handler->updateModule(module);
- }
- handler->endUpdateAll();
+ DebuggerCommand cmd("fetchModules");
+ cmd.callback = [this](const DebuggerResponse &response) {
+ const GdbMi &modules = response.data["modules"];
+ ModulesHandler *handler = modulesHandler();
+ handler->beginUpdateAll();
+ foreach (const GdbMi &item, modules.children()) {
+ Module module;
+ module.modulePath = item["file"].toUtf8();
+ module.moduleName = item["name"].toUtf8();
+ module.symbolsRead = Module::UnknownReadState;
+ module.startAddress = item["loaded_addr"].toAddress();
+ module.endAddress = 0; // FIXME: End address not easily available.
+ handler->updateModule(module);
+ }
+ handler->endUpdateAll();
+ };
+ runCommand(cmd);
}
void LldbEngine::requestModuleSymbols(const QString &moduleName)
{
- DebuggerCommand cmd("listSymbols");
+ DebuggerCommand cmd("fetchSymbols");
cmd.arg("module", moduleName);
+ cmd.callback = [this, moduleName](const DebuggerResponse &response) {
+ const GdbMi &symbols = response.data["symbols"];
+ QString moduleName = response.data["module"].toUtf8();
+ Symbols syms;
+ foreach (const GdbMi &item, symbols.children()) {
+ Symbol symbol;
+ symbol.address = item["address"].toUtf8();
+ symbol.name = item["name"].toUtf8();
+ symbol.state = item["state"].toUtf8();
+ symbol.section = item["section"].toUtf8();
+ symbol.demangled = item["demangled"].toUtf8();
+ syms.append(symbol);
+ }
+ Internal::showModuleSymbols(moduleName, syms);
+ };
runCommand(cmd);
}
-void LldbEngine::refreshSymbols(const GdbMi &symbols)
-{
- QString moduleName = symbols["module"].toUtf8();
- Symbols syms;
- foreach (const GdbMi &item, symbols["symbols"].children()) {
- Symbol symbol;
- symbol.address = item["address"].toUtf8();
- symbol.name = item["name"].toUtf8();
- symbol.state = item["state"].toUtf8();
- symbol.section = item["section"].toUtf8();
- symbol.demangled = item["demangled"].toUtf8();
- syms.append(symbol);
- }
- Internal::showModuleSymbols(moduleName, syms);
-}
-
//////////////////////////////////////////////////////////////////////
//
@@ -840,27 +744,60 @@ bool LldbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
void LldbEngine::updateAll()
{
- DebuggerCommand cmd1("reportThreads");
- runCommand(cmd1);
-
- DebuggerCommand cmd2("reportCurrentThread");
- runCommand(cmd2);
-
- DebuggerCommand cmd("reportStack");
- cmd.arg("nativeMixed", isNativeMixedActive());
- cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt());
- cmd.arg("continuation", "updateLocals");
+ DebuggerCommand cmd("fetchThreads");
+ cmd.callback = [this](const DebuggerResponse &response) {
+ threadsHandler()->updateThreads(response.data);
+ fetchStack(action(MaximalStackDepth)->value().toInt());
+ reloadRegisters();
+ };
runCommand(cmd);
}
void LldbEngine::reloadFullStack()
{
- DebuggerCommand cmd("reportStack");
+ fetchStack(-1);
+}
+
+void LldbEngine::fetchStack(int limit)
+{
+ DebuggerCommand cmd("fetchStack");
cmd.arg("nativeMixed", isNativeMixedActive());
- cmd.arg("stacklimit", -1);
+ cmd.arg("stacklimit", limit);
+ cmd.callback = [this](const DebuggerResponse &response) {
+ const GdbMi &stack = response.data["stack"];
+ StackHandler *handler = stackHandler();
+ StackFrames frames;
+ foreach (const GdbMi &item, stack["frames"].children()) {
+ StackFrame frame;
+ frame.level = item["level"].toInt();
+ frame.file = item["file"].toUtf8();
+ frame.function = item["func"].toUtf8();
+ frame.from = item["func"].toUtf8();
+ frame.line = item["line"].toInt();
+ frame.address = item["addr"].toAddress();
+ GdbMi usable = item["usable"];
+ if (usable.isValid())
+ frame.usable = usable.data().toInt();
+ else
+ frame.usable = QFileInfo(frame.file).isReadable();
+ if (item["language"].data() == "js"
+ || frame.file.endsWith(QLatin1String(".js"))
+ || frame.file.endsWith(QLatin1String(".qml"))) {
+ frame.language = QmlLanguage;
+ frame.fixQmlFrame(runParameters());
+ }
+ frames.append(frame);
+ }
+ bool canExpand = stack["hasmore"].toInt();
+ action(ExpandStack)->setEnabled(canExpand);
+ handler->setFrames(frames, canExpand);
+
+ updateLocals();
+ };
runCommand(cmd);
}
+
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
@@ -873,6 +810,7 @@ void LldbEngine::assignValueInDebugger(WatchItem *,
DebuggerCommand cmd("assignValue");
cmd.arg("exp", expression.toLatin1().toHex());
cmd.arg("value", value.toString().toLatin1().toHex());
+ cmd.callback = [this](const DebuggerResponse &) { updateLocals(); };
runCommand(cmd);
}
@@ -885,7 +823,7 @@ void LldbEngine::doUpdateLocals(const UpdateParameters &params)
watchHandler()->notifyUpdateStarted(params.partialVariables());
- DebuggerCommand cmd("updateData");
+ DebuggerCommand cmd("fetchLocals");
cmd.arg("nativeMixed", isNativeMixedActive());
watchHandler()->appendFormatRequests(&cmd);
@@ -925,9 +863,12 @@ void LldbEngine::doUpdateLocals(const UpdateParameters &params)
m_lastDebuggableCommand = cmd;
m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
- runCommand(cmd);
+ cmd.callback = [this](const DebuggerResponse &response) {
+ updateLocalsView(response.data);
+ watchHandler()->notifyUpdateFinished();
+ };
- reloadRegisters();
+ runCommand(cmd);
}
void LldbEngine::handleLldbError(QProcess::ProcessError error)
@@ -991,7 +932,7 @@ void LldbEngine::readLldbStandardOutput()
{
QByteArray out = m_lldbProc.readAllStandardOutput();
out.replace("\r\n", "\n");
- showMessage(_(out));
+ showMessage(_(out), LogOutput);
m_inbuffer.append(out);
while (true) {
int pos = m_inbuffer.indexOf("@\n");
@@ -1006,86 +947,7 @@ void LldbEngine::readLldbStandardOutput()
}
}
-void LldbEngine::refreshStack(const GdbMi &stack)
-{
- StackHandler *handler = stackHandler();
- StackFrames frames;
- foreach (const GdbMi &item, stack["frames"].children()) {
- StackFrame frame;
- frame.level = item["level"].toInt();
- frame.file = item["file"].toUtf8();
- frame.function = item["func"].toUtf8();
- frame.from = item["func"].toUtf8();
- frame.line = item["line"].toInt();
- frame.address = item["addr"].toAddress();
- GdbMi usable = item["usable"];
- if (usable.isValid())
- frame.usable = usable.data().toInt();
- else
- frame.usable = QFileInfo(frame.file).isReadable();
- if (item["language"].data() == "js"
- || frame.file.endsWith(QLatin1String(".js"))
- || frame.file.endsWith(QLatin1String(".qml"))) {
- frame.language = QmlLanguage;
- frame.fixQmlFrame(runParameters());
- }
- frames.append(frame);
- }
- bool canExpand = stack["hasmore"].toInt();
- action(ExpandStack)->setEnabled(canExpand);
- handler->setFrames(frames, canExpand);
-}
-
-void LldbEngine::refreshRegisters(const GdbMi &registers)
-{
- RegisterHandler *handler = registerHandler();
- foreach (const GdbMi &item, registers.children()) {
- Register reg;
- reg.name = item["name"].data();
- reg.value.fromByteArray(item["value"].data(), HexadecimalFormat);
- reg.size = item["size"].data().toInt();
- reg.reportedType = item["type"].data();
- if (reg.reportedType.startsWith("unsigned"))
- reg.kind = IntegerRegister;
- handler->updateRegister(reg);
- }
- handler->commitUpdates();
-}
-
-void LldbEngine::refreshThreads(const GdbMi &threads)
-{
- ThreadsHandler *handler = threadsHandler();
- handler->updateThreads(threads);
- updateViews(); // Adjust Threads combobox.
-}
-
-void LldbEngine::refreshCurrentThread(const GdbMi &data)
-{
- ThreadsHandler *handler = threadsHandler();
- ThreadId id(data["id"].toInt());
- handler->setCurrentThread(id);
- updateViews(); // Adjust Threads combobox.
-}
-
-void LldbEngine::refreshTypeInfo(const GdbMi &typeInfo)
-{
- if (typeInfo.type() == GdbMi::List) {
-// foreach (const GdbMi &s, typeInfo.children()) {
-// const GdbMi name = s["name"];
-// const GdbMi size = s["size"];
-// if (name.isValid() && size.isValid())
-// m_typeInfoCache.insert(QByteArray::fromBase64(name.data()),
-// TypeInfo(size.data().toUInt()));
-// }
- }
-// for (int i = 0; i != list.size(); ++i) {
-// const TypeInfo ti = m_typeInfoCache.value(list.at(i).type);
-// if (ti.size)
-// list[i].size = ti.size;
-// }
-}
-
-void LldbEngine::refreshState(const GdbMi &reportedState)
+void LldbEngine::handleStateNotification(const GdbMi &reportedState)
{
QByteArray newState = reportedState.data();
if (newState == "running")
@@ -1113,10 +975,6 @@ void LldbEngine::refreshState(const GdbMi &reportedState)
notifyEngineSetupFailed();
else if (newState == "enginerunfailed")
notifyEngineRunFailed();
- else if (newState == "inferiorsetupok")
- notifyInferiorSetupOk();
- else if (newState == "inferiorsetupfailed")
- notifyInferiorSetupFailed();
else if (newState == "enginerunandinferiorrunok") {
if (runParameters().continueAfterAttach)
m_continueAtNextSpontaneousStop = true;
@@ -1137,7 +995,7 @@ void LldbEngine::refreshState(const GdbMi &reportedState)
notifyInferiorExited();
}
-void LldbEngine::refreshLocation(const GdbMi &reportedLocation)
+void LldbEngine::handleLocationNotification(const GdbMi &reportedLocation)
{
qulonglong addr = reportedLocation["addr"].toAddress();
QString file = reportedLocation["file"].toUtf8();
@@ -1153,8 +1011,26 @@ void LldbEngine::refreshLocation(const GdbMi &reportedLocation)
void LldbEngine::reloadRegisters()
{
- if (Internal::isDockVisible(QLatin1String(DOCKWIDGET_REGISTER)))
- runCommand("reportRegisters");
+ if (!Internal::isDockVisible(QLatin1String(DOCKWIDGET_REGISTER)))
+ return;
+
+ DebuggerCommand cmd("fetchRegisters");
+ cmd.callback = [this](const DebuggerResponse &response) {
+ RegisterHandler *handler = registerHandler();
+ GdbMi regs = response.data["registers"];
+ foreach (const GdbMi &item, regs.children()) {
+ Register reg;
+ reg.name = item["name"].data();
+ reg.value.fromByteArray(item["value"].data(), HexadecimalFormat);
+ reg.size = item["size"].data().toInt();
+ reg.reportedType = item["type"].data();
+ if (reg.reportedType.startsWith("unsigned"))
+ reg.kind = IntegerRegister;
+ handler->updateRegister(reg);
+ }
+ handler->commitUpdates();
+ };
+ runCommand(cmd);
}
void LldbEngine::reloadDebuggingHelpers()
@@ -1172,17 +1048,47 @@ void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
m_disassemblerAgents.insert(p, id);
}
const Location &loc = agent->location();
- DebuggerCommand cmd("disassemble");
- cmd.arg("cookie", id);
+ DebuggerCommand cmd("fetchDisassembler");
cmd.arg("address", loc.address());
cmd.arg("function", loc.functionName());
cmd.arg("flavor", boolSetting(IntelFlavor) ? "intel" : "att");
+ cmd.callback = [this, id](const DebuggerResponse &response) {
+ DisassemblerLines result;
+ QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(id);
+ if (!agent.isNull()) {
+ foreach (const GdbMi &line, response.data["lines"].children()) {
+ DisassemblerLine dl;
+ dl.address = line["address"].toAddress();
+ //dl.data = line["data"].toUtf8();
+ //dl.rawData = line["rawdata"].data();
+ dl.data = line["rawdata"].toUtf8();
+ if (!dl.data.isEmpty())
+ dl.data += QString(30 - dl.data.size(), QLatin1Char(' '));
+ dl.data += line["data"].toUtf8();
+ dl.offset = line["offset"].toInt();
+ dl.lineNumber = line["line"].toInt();
+ dl.fileName = line["file"].toUtf8();
+ dl.function = line["function"].toUtf8();
+ dl.hunk = line["hunk"].toInt();
+ QByteArray comment = line["comment"].data();
+ if (!comment.isEmpty())
+ dl.data += QString::fromUtf8(" # " + comment);
+ result.appendLine(dl);
+ }
+ agent->setContents(result);
+ }
+ };
runCommand(cmd);
}
-void LldbEngine::createFullBacktrace()
+void LldbEngine::fetchFullBacktrace()
{
- runCommand("createFullBacktrace");
+ DebuggerCommand cmd("fetchFullBacktrace");
+ cmd.callback = [](const DebuggerResponse &response) {
+ Internal::openTextEditor(_("Backtrace $"),
+ QString::fromUtf8(QByteArray::fromHex(response.data.data())));
+ };
+ runCommand("fetchFullBacktrace");
}
void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken,
@@ -1194,10 +1100,20 @@ void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken,
m_memoryAgents.insert(agent, id);
}
m_memoryAgentTokens.insert(id, editorToken);
+
DebuggerCommand cmd("fetchMemory");
cmd.arg("address", addr);
cmd.arg("length", length);
- cmd.arg("cookie", id);
+ cmd.callback = [this, id](const DebuggerResponse &response) {
+ qulonglong addr = response.data["address"].toAddress();
+ QPointer<MemoryAgent> agent = m_memoryAgents.key(id);
+ if (!agent.isNull()) {
+ QPointer<QObject> token = m_memoryAgentTokens.value(id);
+ QTC_ASSERT(!token.isNull(), return);
+ QByteArray ba = QByteArray::fromHex(response.data["contents"].data());
+ agent->addLazyData(token.data(), addr, ba);
+ }
+ };
runCommand(cmd);
}
@@ -1213,7 +1129,7 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
DebuggerCommand cmd("writeMemory");
cmd.arg("address", addr);
cmd.arg("data", data.toHex());
- cmd.arg("cookie", id);
+ cmd.callback = [this, id](const DebuggerResponse &response) { Q_UNUSED(response); };
runCommand(cmd);
}
diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h
index b924c1af9d..02c195aa8b 100644
--- a/src/plugins/debugger/lldb/lldbengine.h
+++ b/src/plugins/debugger/lldb/lldbengine.h
@@ -67,8 +67,10 @@ public:
explicit LldbEngine(const DebuggerRunParameters &runParameters);
~LldbEngine();
+signals:
+ void outputReady(const QByteArray &data);
+
private:
- // DebuggerEngine implementation
DebuggerEngine *cppEngine() { return this; }
void executeStep();
@@ -81,7 +83,6 @@ private:
void startLldb();
void startLldbStage2();
void setupInferior();
- void setupInferiorStage2();
void runEngine();
void shutdownInferior();
void shutdownEngine();
@@ -98,6 +99,7 @@ private:
void activateFrame(int index);
void selectThread(ThreadId threadId);
+ void fetchFullBacktrace();
// This should be always the last call in a function.
bool stateAcceptsBreakpointChanges() const;
@@ -118,20 +120,13 @@ private:
void reloadFullStack();
void reloadDebuggingHelpers();
void fetchDisassembler(Internal::DisassemblerAgent *);
- void refreshDisassembly(const GdbMi &data);
- bool supportsThreads() const { return true; }
bool isSynchronous() const { return true; }
void setRegisterValue(const QByteArray &name, const QString &value);
void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length);
void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data);
- void refreshMemory(const GdbMi &data);
-signals:
- void outputReady(const QByteArray &data);
-
-private:
QString errorMessage(QProcess::ProcessError error) const;
bool hasCapability(unsigned cap) const;
@@ -139,45 +134,23 @@ private:
void handleLldbError(QProcess::ProcessError error);
void readLldbStandardOutput();
void readLldbStandardError();
+
+ void handleStateNotification(const GdbMi &state);
+ void handleLocationNotification(const GdbMi &location);
+ void handleOutputNotification(const GdbMi &output);
+
void handleResponse(const QByteArray &data);
void updateAll();
- void createFullBacktrace();
void doUpdateLocals(const UpdateParameters &params);
- void handleContinuation(const GdbMi &data);
-
- void refreshAll(const GdbMi &all);
- void refreshThreads(const GdbMi &threads);
- void refreshCurrentThread(const GdbMi &data);
- void refreshStack(const GdbMi &stack);
- void refreshRegisters(const GdbMi &registers);
- void refreshTypeInfo(const GdbMi &typeInfo);
- void refreshState(const GdbMi &state);
- void refreshLocation(const GdbMi &location);
- void refreshModules(const GdbMi &modules);
- void refreshSymbols(const GdbMi &symbols);
- void refreshOutput(const GdbMi &output);
- void refreshAddedBreakpoint(const GdbMi &bkpts);
- void refreshChangedBreakpoint(const GdbMi &bkpts);
- void refreshRemovedBreakpoint(const GdbMi &bkpts);
- void showFullBacktrace(const GdbMi &data);
-
- typedef void (LldbEngine::*LldbCommandContinuation)();
-
- void handleListLocals(const QByteArray &response);
- void handleListModules(const QByteArray &response);
- void handleListSymbols(const QByteArray &response);
- void handleBreakpointsSynchronized(const QByteArray &response);
- void updateBreakpointData(const GdbMi &bkpt, bool added);
- void handleUpdateStack(const QByteArray &response);
- void handleUpdateThreads(const QByteArray &response);
+ void updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added);
+ void fetchStack(int limit);
void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result);
- void handleChildren(const WatchData &data0, const GdbMi &item,
- QList<WatchData> *list);
-
void runCommand(const DebuggerCommand &cmd);
void debugLastCommand();
+
+private:
DebuggerCommand m_lastDebuggableCommand;
QByteArray m_inbuffer;
@@ -192,6 +165,8 @@ private:
QMap<QPointer<MemoryAgent>, int> m_memoryAgents;
QHash<int, QPointer<QObject> > m_memoryAgentTokens;
+ QHash<int, DebuggerCommand> m_commandForToken;
+
// Console handling.
Q_SLOT void stubError(const QString &msg);
Q_SLOT void stubExited();