aboutsummaryrefslogtreecommitdiffstats
path: root/share/qtcreator/debugger/lldbbridge.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/qtcreator/debugger/lldbbridge.py')
-rw-r--r--share/qtcreator/debugger/lldbbridge.py139
1 files changed, 85 insertions, 54 deletions
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index 3350318fbd..41d2ebf7f8 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -32,7 +32,7 @@ import threading
import time
import lldb
import utils
-from utils import DebuggerStartMode, BreakpointType, TypeCode
+from utils import DebuggerStartMode, BreakpointType, TypeCode, LogChannel
from contextlib import contextmanager
@@ -40,6 +40,11 @@ sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.curre
# Simplify development of this module by reloading deps
if 'dumper' in sys.modules:
+ if sys.version_info[0] >= 3:
+ if sys.version_info[1] > 3:
+ from importlib import reload
+ else:
+ def reload(m): print('Unsupported Python version - not reloading %s' % str(m))
reload(sys.modules['dumper'])
from dumper import DumperBase, SubItem, Children, TopLevelItem
@@ -108,7 +113,6 @@ class Dumper(DumperBase):
self.process = None
self.target = None
self.eventState = lldb.eStateInvalid
- self.runEngineAttempted = False
self.executable_ = None
self.symbolFile_ = None
@@ -123,8 +127,15 @@ class Dumper(DumperBase):
self.isInterrupting_ = False
self.interpreterBreakpointResolvers = []
+ DumperBase.warn = Dumper.warn_impl
self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
- self.reportState('enginesetupok')
+
+ @staticmethod
+ def warn_impl(message):
+ if message[-1:] == '\n':
+ message += '\n'
+ print('@\nbridgemessage={msg="%s",channel="%s"}\n@'
+ % (message.replace('"', '$'), LogChannel.AppError))
def fromNativeFrameValue(self, nativeValue):
return self.fromNativeValue(nativeValue)
@@ -843,6 +854,8 @@ class Dumper(DumperBase):
return None
def setupInferior(self, args):
+ """ Set up SBTarget instance """
+
error = lldb.SBError()
self.executable_ = args['executable']
@@ -880,6 +893,12 @@ class Dumper(DumperBase):
if self.sysRoot_:
self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
+ # There seems to be some kind of unexpected behavior, or bug in LLDB
+ # such that target.Attach(attachInfo, error) below does not create
+ # a valid process if this symbolFile here is valid.
+ if self.startMode_ == DebuggerStartMode.AttachExternal:
+ self.symbolFile_ = ''
+
self.target = self.debugger.CreateTarget(
self.symbolFile_, None, self.platform_, True, error)
@@ -888,18 +907,6 @@ class Dumper(DumperBase):
self.reportState('enginerunfailed')
return
- if (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
- or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
- if self.platform_ != 'remote-ios':
- # lldb-server expected on remote
- remote_channel = 'connect://' + self.remoteChannel_
- connect_options = lldb.SBPlatformConnectOptions(remote_channel)
-
- res = self.target.GetPlatform().ConnectRemote(connect_options)
- DumperBase.warn("CONNECT: %s %s %s" % (res,
- self.target.GetPlatform().GetName(),
- self.target.GetPlatform().IsConnected()))
-
broadcaster = self.target.GetBroadcaster()
listener = self.debugger.GetListener()
broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
@@ -917,47 +924,59 @@ class Dumper(DumperBase):
% (state, error, self.executable_), args)
def runEngine(self, args):
- if self.runEngineAttempted:
- return
- self.runEngineAttempted = True
- self.prepare(args)
- s = threading.Thread(target=self.loop, args=[])
- s.start()
+ """ Set up SBProcess instance """
- def prepare(self, args):
error = lldb.SBError()
- if self.attachPid_ > 0:
- attachInfo = lldb.SBAttachInfo(self.attachPid_)
- self.process = self.target.Attach(attachInfo, error)
+ if self.startMode_ == DebuggerStartMode.AttachExternal:
+ attach_info = lldb.SBAttachInfo(self.attachPid_)
+ self.process = self.target.Attach(attach_info, error)
if not error.Success():
- self.reportState('inferiorrunfailed')
- return
- self.report('pid="%s"' % self.process.GetProcessID())
- # Even if it stops it seems that LLDB assumes it is running
- # and later detects that it did stop after all, so it is be
- # better to mirror that and wait for the spontaneous stop
- if self.process and self.process.GetState() == lldb.eStateStopped:
- # lldb stops the process after attaching. This happens before the
- # eventloop starts. Relay the correct state back.
+ self.reportState('enginerunfailed')
+ else:
+ self.report('pid="%s"' % self.process.GetProcessID())
self.reportState('enginerunandinferiorstopok')
+
+ elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
+ and self.platform_ == 'remote-android'):
+
+ connect_options = lldb.SBPlatformConnectOptions(self.remoteChannel_)
+ res = self.target.GetPlatform().ConnectRemote(connect_options)
+
+ DumperBase.warn("CONNECT: %s %s platform: %s %s" % (res,
+ self.remoteChannel_,
+ self.target.GetPlatform().GetName(),
+ self.target.GetPlatform().IsConnected()))
+ if not res.Success():
+ self.report(self.describeError(error))
+ self.reportState('enginerunfailed')
+ return
+
+ attach_info = lldb.SBAttachInfo(self.attachPid_)
+ self.process = self.target.Attach(attach_info, error)
+ if not error.Success():
+ self.report(self.describeError(error))
+ self.reportState('enginerunfailed')
else:
- self.reportState('enginerunandinferiorrunok')
+ self.report('pid="%s"' % self.process.GetProcessID())
+ self.reportState('enginerunandinferiorstopok')
+
elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
-
if self.platform_ == 'remote-ios':
self.process = self.target.ConnectRemote(
self.debugger.GetListener(),
self.remoteChannel_, None, error)
else:
- # lldb-server expected
f = lldb.SBFileSpec()
f.SetFilename(self.executable_)
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
#launchInfo.SetWorkingDirectory(self.workingDirectory_)
launchInfo.SetWorkingDirectory('/tmp')
+ if self.platform_ == 'remote-android':
+ launchInfo.SetWorkingDirectory('/data/local/tmp')
+ launchInfo.SetEnvironmentEntries(self.environment_, False)
launchInfo.SetExecutableFile(f, True)
DumperBase.warn("TARGET: %s" % self.target)
@@ -995,6 +1014,9 @@ class Dumper(DumperBase):
self.report('pid="%s"' % self.process.GetProcessID())
self.reportState('enginerunandinferiorrunok')
+ s = threading.Thread(target=self.loop, args=[])
+ s.start()
+
def loop(self):
event = lldb.SBEvent()
#broadcaster = self.target.GetBroadcaster()
@@ -1215,7 +1237,7 @@ class Dumper(DumperBase):
with SubItem(self, '[statics]'):
self.put('iname="%s",' % self.currentIName)
self.putEmptyValue()
- self.putNumChild(1)
+ self.putExpandable()
if self.isExpanded():
with Children(self):
statics = frame.GetVariables(False, False, True, False)
@@ -1232,7 +1254,6 @@ class Dumper(DumperBase):
else:
with SubItem(self, "None"):
self.putEmptyValue()
- self.putNumChild(0)
# FIXME: Implement shortcut for partial updates.
#if isPartial:
@@ -1262,23 +1283,29 @@ class Dumper(DumperBase):
self.put('],partial="%d"' % isPartial)
self.reportResult(self.output, args)
+
def fetchRegisters(self, args=None):
- if self.process is None:
- result = 'process="none"'
- else:
- frame = self.currentFrame()
- if frame:
- result = 'registers=['
- for group in frame.GetRegisters():
- for reg in group:
- value = ''.join(["%02x" % x for x in reg.GetData().uint8s])
- result += '{name="%s"' % reg.GetName()
- result += ',value="0x%s"' % value
- result += ',size="%s"' % reg.GetByteSize()
- result += ',type="%s"},' % reg.GetType()
- result += ']'
+ if not self.process:
+ self.reportResult('process="none",registers=[]', args)
+ return
+
+ frame = self.currentFrame()
+ if not frame or not frame.IsValid():
+ self.reportResult('frame="none",registers=[]', args)
+ return
+
+ result = 'registers=['
+ for group in frame.GetRegisters():
+ for reg in group:
+ value = ''.join(["%02x" % x for x in reg.GetData().uint8s])
+ result += '{name="%s"' % reg.GetName()
+ result += ',value="0x%s"' % value
+ result += ',size="%s"' % reg.GetByteSize()
+ result += ',type="%s"},' % reg.GetType()
+ result += ']'
self.reportResult(result, args)
+
def setRegister(self, args):
name = args["name"]
value = args["value"]
@@ -1703,7 +1730,8 @@ class Dumper(DumperBase):
def activateFrame(self, args):
self.reportToken(args)
- self.currentThread().SetSelectedFrame(args['index'])
+ frame = max(0, int(args['index'])) # Can be -1 in all-asm stacks
+ self.currentThread().SetSelectedFrame(frame)
self.reportResult('', args)
def selectThread(self, args):
@@ -1727,6 +1755,9 @@ class Dumper(DumperBase):
error = str(result.GetError())
self.report('success="%d",output="%s",error="%s"' % (success, output, error))
+ def executeRoundtrip(self, args):
+ self.reportResult('', args)
+
def fetchDisassembler(self, args):
functionName = args.get('function', '')
flavor = args.get('flavor', '')