2013-09-11 21:35:39 +02:00
|
|
|
############################################################################
|
|
|
|
#
|
2016-01-15 14:53:55 +01:00
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
# Contact: https://www.qt.io/licensing/
|
2013-09-11 21:35:39 +02:00
|
|
|
#
|
|
|
|
# This file is part of Qt Creator.
|
|
|
|
#
|
|
|
|
# Commercial License Usage
|
|
|
|
# Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
# accordance with the commercial license agreement provided with the
|
|
|
|
# Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:53:55 +01:00
|
|
|
# a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
# and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
# information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
#
|
|
|
|
# GNU General Public License Usage
|
|
|
|
# Alternatively, this file may be used under the terms of the GNU
|
|
|
|
# General Public License version 3 as published by the Free Software
|
|
|
|
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
# included in the packaging of this file. Please review the following
|
|
|
|
# information to ensure the GNU General Public License requirements will
|
|
|
|
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-09-11 21:35:39 +02:00
|
|
|
#
|
2016-01-15 14:53:55 +01:00
|
|
|
############################################################################
|
2013-04-11 17:06:17 +02:00
|
|
|
|
|
|
|
import inspect
|
|
|
|
import os
|
2014-02-10 17:38:58 +01:00
|
|
|
import platform
|
2013-10-21 12:02:57 +02:00
|
|
|
import re
|
2013-05-13 16:04:00 +02:00
|
|
|
import sys
|
2013-10-21 12:02:57 +02:00
|
|
|
import threading
|
2015-01-30 12:36:04 +01:00
|
|
|
import lldb
|
2013-05-16 15:09:24 +02:00
|
|
|
|
2015-02-13 10:02:35 +01:00
|
|
|
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
from dumper import *
|
|
|
|
|
2013-04-11 17:06:17 +02:00
|
|
|
#######################################################################
|
|
|
|
#
|
|
|
|
# Helpers
|
|
|
|
#
|
|
|
|
#######################################################################
|
|
|
|
|
2013-06-14 15:15:09 +02:00
|
|
|
qqWatchpointOffset = 10000
|
2013-05-15 15:30:42 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def showException(msg, exType, exValue, exTraceback):
|
|
|
|
warn("**** CAUGHT EXCEPTION: %s ****" % msg)
|
2013-05-08 16:20:03 +02:00
|
|
|
import traceback
|
|
|
|
lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)]
|
|
|
|
warn('\n'.join(lines))
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def fileNameAsString(file):
|
2013-04-30 10:46:48 +02:00
|
|
|
return str(file) if file.IsValid() else ''
|
|
|
|
|
2013-04-11 17:06:17 +02:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def check(exp):
|
|
|
|
if not exp:
|
|
|
|
raise RuntimeError("Check failed")
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
class Dumper(DumperBase):
|
2013-04-30 10:46:48 +02:00
|
|
|
def __init__(self):
|
2013-09-11 21:35:39 +02:00
|
|
|
DumperBase.__init__(self)
|
2016-04-13 18:19:45 +02:00
|
|
|
lldb.theDumper = self
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-03-19 12:08:25 +01:00
|
|
|
self.outputLock = threading.Lock()
|
2013-04-30 10:46:48 +02:00
|
|
|
self.debugger = lldb.SBDebugger.Create()
|
2013-05-02 14:31:35 +02:00
|
|
|
#self.debugger.SetLoggingCallback(loggingCallback)
|
2015-02-04 14:15:14 +01:00
|
|
|
#def loggingCallback(args):
|
|
|
|
# s = args.strip()
|
|
|
|
# s = s.replace('"', "'")
|
|
|
|
# sys.stdout.write('log="%s"@\n' % s)
|
2013-04-30 10:46:48 +02:00
|
|
|
#Same as: self.debugger.HandleCommand("log enable lldb dyld step")
|
2015-02-04 14:15:14 +01:00
|
|
|
#self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state",
|
|
|
|
# "thread", "events",
|
2013-04-30 10:46:48 +02:00
|
|
|
# "communication", "unwind", "commands"])
|
|
|
|
#self.debugger.EnableLog("lldb", ["all"])
|
|
|
|
self.debugger.Initialize()
|
|
|
|
self.debugger.HandleCommand("settings set auto-confirm on")
|
2013-11-01 14:18:10 +01:00
|
|
|
|
|
|
|
# FIXME: warn("DISABLING DEFAULT FORMATTERS")
|
|
|
|
# It doesn't work at all with 179.5 and we have some bad
|
2016-09-06 08:54:43 +02:00
|
|
|
# interaction in 300
|
2013-11-01 14:18:10 +01:00
|
|
|
# if not hasattr(lldb.SBType, 'GetCanonicalType'): # "Test" for 179.5
|
2016-09-06 08:54:43 +02:00
|
|
|
#self.debugger.HandleCommand('type category delete gnu-libstdc++')
|
|
|
|
#self.debugger.HandleCommand('type category delete libcxx')
|
|
|
|
#self.debugger.HandleCommand('type category delete default')
|
|
|
|
self.debugger.DeleteCategory('gnu-libstdc++')
|
|
|
|
self.debugger.DeleteCategory('libcxx')
|
|
|
|
self.debugger.DeleteCategory('default')
|
|
|
|
self.debugger.DeleteCategory('cplusplus')
|
2013-11-01 14:18:10 +01:00
|
|
|
#for i in range(self.debugger.GetNumCategories()):
|
|
|
|
# self.debugger.GetCategoryAtIndex(i).SetEnabled(False)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
self.isLldb = True
|
2013-04-30 10:46:48 +02:00
|
|
|
self.process = None
|
|
|
|
self.target = None
|
|
|
|
self.eventState = lldb.eStateInvalid
|
|
|
|
self.expandedINames = {}
|
2013-10-31 09:17:49 +01:00
|
|
|
self.passExceptions = False
|
2015-12-16 14:13:44 +01:00
|
|
|
self.showQObjectNames = False
|
2013-05-22 12:06:56 +02:00
|
|
|
self.useLldbDumpers = False
|
2013-05-17 10:10:13 +02:00
|
|
|
self.autoDerefPointers = True
|
2013-05-29 14:54:47 +02:00
|
|
|
self.useDynamicType = True
|
2013-06-05 11:26:46 +02:00
|
|
|
self.useFancy = True
|
2013-06-11 14:24:26 +02:00
|
|
|
self.formats = {}
|
|
|
|
self.typeformats = {}
|
2016-09-06 08:54:43 +02:00
|
|
|
self.currentContextValue = None
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
self.currentIName = None
|
2014-05-16 00:18:17 +02:00
|
|
|
self.currentValue = ReportItem()
|
|
|
|
self.currentType = ReportItem()
|
2013-05-08 16:20:03 +02:00
|
|
|
self.currentNumChild = None
|
|
|
|
self.currentMaxNumChild = None
|
2016-07-21 09:19:30 +02:00
|
|
|
self.currentPrintsAddress = True
|
2013-05-08 16:20:03 +02:00
|
|
|
self.currentChildType = None
|
2015-03-26 13:03:38 +01:00
|
|
|
self.currentChildNumChild = -1
|
2013-05-30 15:35:52 +02:00
|
|
|
self.currentWatchers = {}
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-22 14:30:36 +02:00
|
|
|
self.executable_ = None
|
2013-10-01 02:30:12 +02:00
|
|
|
self.startMode_ = None
|
|
|
|
self.processArgs_ = None
|
|
|
|
self.attachPid_ = None
|
2015-12-08 16:58:20 +01:00
|
|
|
self.dyldImageSuffix = None
|
|
|
|
self.dyldLibraryPath = None
|
|
|
|
self.dyldFrameworkPath = None
|
2013-10-01 02:30:12 +02:00
|
|
|
|
2013-05-29 15:38:49 +02:00
|
|
|
self.isShuttingDown_ = False
|
2013-06-24 17:40:00 +02:00
|
|
|
self.isInterrupting_ = False
|
2015-10-09 15:00:20 +02:00
|
|
|
self.interpreterBreakpointResolvers = []
|
2013-05-17 13:53:49 +02:00
|
|
|
|
2015-02-13 10:02:35 +01:00
|
|
|
self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
|
|
|
|
self.reportState("enginesetupok")
|
2016-08-02 14:50:54 +02:00
|
|
|
self.debuggerCommandInProgress = False
|
2015-02-13 10:02:35 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def fromNativeValue(self, nativeValue):
|
|
|
|
nativeValue.SetPreferSyntheticValue(False)
|
2016-09-26 14:29:16 +02:00
|
|
|
nativeType = nativeValue.GetType()
|
2016-09-06 08:54:43 +02:00
|
|
|
val = self.Value(self)
|
2016-09-26 14:29:16 +02:00
|
|
|
val.type = self.fromNativeType(nativeType)
|
2016-09-06 08:54:43 +02:00
|
|
|
val.lIsInScope = nativeValue.IsInScope()
|
|
|
|
#val.name = nativeValue.GetName()
|
2016-09-26 14:29:16 +02:00
|
|
|
data = nativeValue.GetData()
|
|
|
|
error = lldb.SBError()
|
|
|
|
size = nativeValue.GetType().GetByteSize()
|
|
|
|
if size > 0: # Happens regularly e.g. for cross-shared-object types.
|
|
|
|
val.ldata = data.ReadRawData(error, 0, size)
|
|
|
|
code = nativeType.GetTypeClass()
|
|
|
|
if code not in (lldb.eTypeClassPointer, lldb.eTypeClassReference):
|
2016-09-06 08:54:43 +02:00
|
|
|
val.laddress = int(nativeValue.GetLoadAddress())
|
2016-09-26 14:29:16 +02:00
|
|
|
if code == lldb.eTypeClassEnumeration:
|
|
|
|
intval = nativeValue.GetValueAsSigned()
|
|
|
|
if hasattr(nativeType, 'get_enum_members_array'):
|
|
|
|
for enumMember in nativeType.get_enum_members_array():
|
|
|
|
# Even when asking for signed we get unsigned with LLDB 3.8.
|
|
|
|
diff = enumMember.GetValueAsSigned() - intval
|
|
|
|
mask = (1 << nativeType.GetByteSize() * 8) - 1
|
|
|
|
if diff & mask == 0:
|
|
|
|
path = nativeType.GetName().split('::')
|
|
|
|
path[-1] = enumMember.GetName()
|
|
|
|
val.ldisplay = "%s (%d)" % ('::'.join(path), intval)
|
|
|
|
val.ldisplay = "%d" % intval
|
|
|
|
elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat):
|
|
|
|
val.ldisplay = str(nativeValue.GetValue())
|
|
|
|
elif code == lldb.eTypeClassArray:
|
|
|
|
if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x
|
|
|
|
val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType())
|
|
|
|
else:
|
|
|
|
fields = nativeType.get_fields_array()
|
|
|
|
if len(fields):
|
|
|
|
val.type.ltarget = self.fromNativeType(fields[0])
|
|
|
|
elif code == lldb.eTypeClassVector:
|
|
|
|
val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType())
|
2016-09-06 08:54:43 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def fromNativeType(self, nativeType):
|
|
|
|
typeobj = self.Type(self)
|
|
|
|
if nativeType.IsPointerType():
|
|
|
|
typeobj.nativeType = nativeType
|
|
|
|
else:
|
|
|
|
# This strips typedefs for pointers. We don't want that.
|
|
|
|
typeobj.nativeType = nativeType.GetUnqualifiedType()
|
2016-09-15 10:25:24 +02:00
|
|
|
if hasattr(typeobj.nativeType, "GetDisplayTypeName"):
|
|
|
|
typeobj.name = typeobj.nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320)
|
|
|
|
else:
|
|
|
|
typeobj.name = typeobj.nativeType.GetName() # Xcode 5 (lldb-310)
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj.lbitsize = nativeType.GetByteSize() * 8
|
|
|
|
code = nativeType.GetTypeClass()
|
2016-09-19 12:05:16 +02:00
|
|
|
try:
|
|
|
|
typeobj.code = {
|
|
|
|
lldb.eTypeClassArray : TypeCodeArray,
|
|
|
|
lldb.eTypeClassVector : TypeCodeArray,
|
|
|
|
lldb.eTypeClassComplexInteger : TypeCodeComplex,
|
|
|
|
lldb.eTypeClassComplexFloat : TypeCodeComplex,
|
|
|
|
lldb.eTypeClassClass : TypeCodeStruct,
|
|
|
|
lldb.eTypeClassStruct : TypeCodeStruct,
|
|
|
|
lldb.eTypeClassUnion : TypeCodeStruct,
|
|
|
|
lldb.eTypeClassEnumeration : TypeCodeEnum,
|
|
|
|
lldb.eTypeClassTypedef : TypeCodeTypedef,
|
|
|
|
lldb.eTypeClassReference : TypeCodeReference,
|
|
|
|
lldb.eTypeClassPointer : TypeCodePointer,
|
|
|
|
lldb.eTypeClassFunction : TypeCodeFunction,
|
|
|
|
lldb.eTypeClassMemberPointer : TypeCodeMemberPointer
|
|
|
|
}[code]
|
|
|
|
except KeyError:
|
|
|
|
if code == lldb.eTypeClassBuiltin:
|
|
|
|
if isFloatingPointTypeName(typeobj.name):
|
|
|
|
typeobj.code = TypeCodeFloat
|
|
|
|
elif isIntegralTypeName(typeobj.name):
|
|
|
|
typeobj.code = TypeCodeIntegral
|
|
|
|
else:
|
|
|
|
warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code))
|
|
|
|
else:
|
|
|
|
warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code))
|
|
|
|
#warn("CREATE TYPE: %s CODE: %s" % (typeobj.name, typeobj.code))
|
2016-09-06 08:54:43 +02:00
|
|
|
return typeobj
|
|
|
|
|
|
|
|
def nativeTypeFields(self, nativeType):
|
|
|
|
fields = []
|
|
|
|
if self.currentContextValue is not None:
|
|
|
|
addr = self.currentContextValue.AddressOf().GetValueAsUnsigned()
|
|
|
|
else:
|
|
|
|
warn("CREATING DUMMY CONTEXT")
|
|
|
|
addr = 0 # FIXME: 0 doesn't produce valid member offsets.
|
|
|
|
addr = 0x7fffffffe0a0
|
|
|
|
sbaddr = lldb.SBAddress(addr, self.target)
|
|
|
|
dummyValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType)
|
2016-09-26 14:29:16 +02:00
|
|
|
dummyValue.SetPreferSyntheticValue(False)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
anonNumber = 0
|
|
|
|
|
|
|
|
baseNames = {}
|
|
|
|
virtualNames = {}
|
|
|
|
# baseNames = set(base.GetName() for base in nativeType.get_bases_array())
|
|
|
|
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
|
|
|
base = nativeType.GetDirectBaseClassAtIndex(i)
|
|
|
|
baseNames[base.GetName()] = i
|
|
|
|
|
|
|
|
for i in range(nativeType.GetNumberOfVirtualBaseClasses()):
|
|
|
|
base = nativeType.GetVirtualBaseClassAtIndex(i)
|
|
|
|
virtualNames[base.GetName()] = i
|
|
|
|
|
|
|
|
fieldBits = dict((field.name, (field.GetBitfieldSizeInBits(), field.GetOffsetInBits()))
|
|
|
|
for field in nativeType.get_fields_array())
|
|
|
|
|
|
|
|
#warn("BASE NAMES: %s" % baseNames)
|
|
|
|
#warn("VIRTUAL NAMES: %s" % virtualNames)
|
|
|
|
#warn("FIELD BITS: %s" % fieldBits)
|
2016-09-30 17:25:23 +02:00
|
|
|
fieldParentType = self.fromNativeType(nativeType).stripTypedefs()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
# This does not list empty base entries.
|
|
|
|
for i in xrange(dummyValue.GetNumChildren()):
|
|
|
|
dummyChild = dummyValue.GetChildAtIndex(i)
|
|
|
|
fieldName = dummyChild.GetName()
|
|
|
|
if fieldName is None:
|
|
|
|
anonNumber += 1
|
|
|
|
fieldName = "#%s" % anonNumber
|
|
|
|
fieldType = dummyChild.GetType()
|
2016-09-26 14:29:16 +02:00
|
|
|
#warn("CHILD AT: %s: %s %s" % (i, fieldName, fieldType.GetName()))
|
|
|
|
#warn(" AT: %s: %s %s" % (i, fieldName, fieldType.GetName()))
|
2016-09-06 08:54:43 +02:00
|
|
|
caddr = dummyChild.AddressOf().GetValueAsUnsigned()
|
|
|
|
child = self.Value(self)
|
|
|
|
child.type = self.fromNativeType(fieldType)
|
|
|
|
child.name = fieldName
|
|
|
|
field = self.Field(self)
|
|
|
|
field.value = child
|
2016-09-30 17:25:23 +02:00
|
|
|
field.parentType = fieldParentType
|
2016-09-06 08:54:43 +02:00
|
|
|
field.ltype = self.fromNativeType(fieldType)
|
|
|
|
field.nativeIndex = i
|
|
|
|
field.name = fieldName
|
|
|
|
if fieldName in fieldBits:
|
|
|
|
(field.lbitsize, field.lbitpos) = fieldBits[fieldName]
|
|
|
|
else:
|
|
|
|
field.lbitsize = fieldType.GetByteSize() * 8
|
|
|
|
field.lbitpos = (caddr - addr) * 8
|
|
|
|
if fieldName in baseNames:
|
|
|
|
#warn("BASE: %s P0S: 0x%x - 0x%x = %s" % (fieldName, caddr, addr, caddr - addr))
|
|
|
|
field.isBaseClass = True
|
|
|
|
field.baseIndex = baseNames[fieldName]
|
|
|
|
if fieldName in virtualNames:
|
|
|
|
field.isVirtualBase = True
|
|
|
|
#warn("ADDING VRITUAL BASE: %s" % fieldName)
|
|
|
|
fields.append(field)
|
|
|
|
|
|
|
|
# Add empty bases.
|
|
|
|
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
|
|
|
fieldObj = nativeType.GetDirectBaseClassAtIndex(i)
|
|
|
|
fieldType = fieldObj.GetType()
|
|
|
|
if fieldType.GetNumberOfFields() == 0:
|
|
|
|
if fieldType.GetNumberOfDirectBaseClasses() == 0:
|
|
|
|
fieldName = fieldObj.GetName()
|
|
|
|
child = self.Value(self)
|
|
|
|
child.type = self.fromNativeType(fieldType)
|
|
|
|
child.name = fieldName
|
|
|
|
child.ldata = bytes()
|
|
|
|
field = self.Field(self)
|
|
|
|
field.value = child
|
|
|
|
field.isBaseClass = True
|
|
|
|
field.baseIndex = baseNames[fieldName]
|
2016-09-30 17:25:23 +02:00
|
|
|
field.parentType = fieldParentType
|
2016-09-06 08:54:43 +02:00
|
|
|
field.ltype = self.fromNativeType(fieldType)
|
|
|
|
field.name = fieldName
|
|
|
|
field.lbitsize = 0
|
|
|
|
field.lbitpos = 0
|
|
|
|
fields.append(field)
|
|
|
|
|
|
|
|
#warn("FIELD NAMES: %s" % [field.name for field in fields])
|
|
|
|
#warn("FIELDS: %s" % fields)
|
|
|
|
return fields
|
|
|
|
|
|
|
|
def nativeTypeUnqualified(self, nativeType):
|
|
|
|
return self.fromNativeType(nativeType.GetUnqualifiedType())
|
|
|
|
|
|
|
|
def nativeTypePointer(self, nativeType):
|
|
|
|
return self.fromNativeType(nativeType.GetPointerType())
|
|
|
|
|
|
|
|
def nativeTypeStripTypedefs(self, typeobj):
|
|
|
|
if hasattr(typeobj, 'GetCanonicalType'):
|
|
|
|
return self.fromNativeType(typeobj.GetCanonicalType())
|
|
|
|
return self.fromNativeType(typeobj)
|
|
|
|
|
|
|
|
def nativeTypeFirstBase(self, nativeType):
|
|
|
|
#warn("FIRST BASE FROM: %s" % nativeType)
|
|
|
|
if nativeType.GetNumberOfDirectBaseClasses() == 0:
|
|
|
|
return None
|
|
|
|
t = nativeType.GetDirectBaseClassAtIndex(0)
|
|
|
|
#warn(" GOT BASE FROM: %s" % t)
|
|
|
|
return self.fromNativeType(nativeType.GetDirectBaseClassAtIndex(0).GetType())
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-09-15 12:31:28 +02:00
|
|
|
def nativeTypeEnumDisplay(self, nativeType, intval):
|
|
|
|
if hasattr(nativeType, 'get_enum_members_array'):
|
|
|
|
for enumMember in nativeType.get_enum_members_array():
|
|
|
|
# Even when asking for signed we get unsigned with LLDB 3.8.
|
|
|
|
diff = enumMember.GetValueAsSigned() - intval
|
|
|
|
mask = (1 << nativeType.GetByteSize() * 8) - 1
|
|
|
|
if diff & mask == 0:
|
|
|
|
path = nativeType.GetName().split('::')
|
|
|
|
path[-1] = enumMember.GetName()
|
|
|
|
return "%s (%d)" % ('::'.join(path), intval)
|
|
|
|
return "%d" % intval
|
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
def nativeDynamicTypeName(self, address, baseType):
|
|
|
|
return None # FIXME: Seems sufficient, no idea why.
|
|
|
|
addr = self.target.ResolveLoadAddress(address)
|
|
|
|
ctx = self.target.ResolveSymbolContextForAddress(addr, 0)
|
|
|
|
sym = ctx.GetSymbol()
|
|
|
|
return sym.GetName()
|
|
|
|
|
2015-02-04 14:15:14 +01:00
|
|
|
def stateName(self, s):
|
|
|
|
try:
|
|
|
|
# See db.StateType
|
|
|
|
return (
|
|
|
|
'invalid',
|
|
|
|
'unloaded', # Process is object is valid, but not currently loaded
|
|
|
|
'connected', # Process is connected to remote debug services,
|
|
|
|
# but not launched or attached to anything yet
|
|
|
|
'attaching', # Process is currently trying to attach
|
|
|
|
'launching', # Process is in the process of launching
|
|
|
|
'stopped', # Process or thread is stopped and can be examined.
|
|
|
|
'running', # Process or thread is running and can't be examined.
|
|
|
|
'stepping', # Process or thread is in the process of stepping
|
|
|
|
# and can not be examined.
|
|
|
|
'crashed', # Process or thread has crashed and can be examined.
|
|
|
|
'detached', # Process has been detached and can't be examined.
|
|
|
|
'exited', # Process has exited and can't be examined.
|
|
|
|
'suspended' # Process or thread is in a suspended state as far
|
|
|
|
)[s]
|
|
|
|
except:
|
|
|
|
return 'unknown(%s)' % s
|
|
|
|
|
|
|
|
def stopReason(self, s):
|
|
|
|
try:
|
|
|
|
return (
|
|
|
|
'invalid',
|
|
|
|
'none',
|
|
|
|
'trace',
|
|
|
|
'breakpoint',
|
|
|
|
'watchpoint',
|
|
|
|
'signal',
|
|
|
|
'exception',
|
|
|
|
'exec',
|
|
|
|
'plancomplete',
|
|
|
|
'threadexiting',
|
|
|
|
'instrumentation',
|
|
|
|
)[s]
|
|
|
|
except:
|
|
|
|
return 'unknown(%s)' % s
|
|
|
|
|
2014-01-10 20:01:35 +01:00
|
|
|
def enumExpression(self, enumType, enumValue):
|
|
|
|
ns = self.qtNamespace()
|
|
|
|
return ns + "Qt::" + enumType + "(" \
|
|
|
|
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def callHelper(self, rettype, value, func, args):
|
2013-09-11 21:35:39 +02:00
|
|
|
# args is a tuple.
|
|
|
|
arg = ','.join(args)
|
2016-09-06 08:54:43 +02:00
|
|
|
#warn("PRECALL: %s -> %s(%s)" % (value.address(), func, arg))
|
|
|
|
typename = value.type.name
|
|
|
|
exp = "((%s*)0x%x)->%s(%s)" % (typename, value.address(), func, arg)
|
|
|
|
#warn("CALL: %s" % exp)
|
|
|
|
result = self.currentContextValue.CreateValueFromExpression('', exp)
|
|
|
|
#warn(" -> %s" % result)
|
|
|
|
return self.fromNativeValue(result)
|
|
|
|
|
|
|
|
def pokeValue(self, typeName, *args):
|
2014-01-22 16:25:39 +01:00
|
|
|
thread = self.currentThread()
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
inner = ','.join(args)
|
2016-09-06 08:54:43 +02:00
|
|
|
value = frame.EvaluateExpression(typeName + '{' + inner + '}')
|
2014-09-22 18:00:06 +02:00
|
|
|
#self.warn(" TYPE: %s" % value.type)
|
|
|
|
#self.warn(" ADDR: 0x%x" % value.address)
|
|
|
|
#self.warn(" VALUE: %s" % value)
|
2014-01-22 16:25:39 +01:00
|
|
|
return value
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def parseAndEvaluate(self, exp):
|
2013-10-23 12:51:11 +02:00
|
|
|
thread = self.currentThread()
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
2016-09-06 08:54:43 +02:00
|
|
|
val = frame.EvaluateExpression(exp)
|
|
|
|
#options = lldb.SBExpressionOptions()
|
|
|
|
#val = self.target.EvaluateExpression(exp, options)
|
|
|
|
err = val.GetError()
|
|
|
|
if err.Fail():
|
|
|
|
#warn("FAILING TO EVAL: %s" % exp)
|
|
|
|
return None
|
|
|
|
#warn("NO ERROR.")
|
|
|
|
#warn("EVAL: %s -> %s" % (exp, val.IsValid()))
|
|
|
|
return self.fromNativeValue(val)
|
|
|
|
|
|
|
|
def nativeTypeTemplateArgument(self, nativeType, position, numeric = False):
|
|
|
|
if numeric:
|
|
|
|
# There seems no API to extract the numeric value.
|
|
|
|
inner = self.extractTemplateArgument(nativeType.GetName(), position)
|
|
|
|
innerType = nativeType.GetTemplateArgumentType(position)
|
|
|
|
basicType = innerType.GetBasicType()
|
|
|
|
value = toInteger(inner)
|
|
|
|
# Clang writes 'int' and '0xfffffff' into the debug info
|
|
|
|
# LLDB manages to read a value of 0xfffffff...
|
|
|
|
if basicType == lldb.eBasicTypeInt and value >= 0x8000000:
|
|
|
|
value -= 0x100000000
|
|
|
|
return value
|
|
|
|
else:
|
|
|
|
#warn("nativeTypeTemplateArgument: %s: pos %s" % (nativeType, position))
|
|
|
|
typeobj = nativeType.GetTemplateArgumentType(position).GetUnqualifiedType()
|
|
|
|
if typeobj.IsValid():
|
|
|
|
# warn("TYPE: %s" % typeobj)
|
|
|
|
return self.fromNativeType(typeobj)
|
|
|
|
inner = self.extractTemplateArgument(nativeType.GetName(), position)
|
|
|
|
#warn("INNER: %s" % inner)
|
|
|
|
return self.lookupType(inner)
|
2013-05-23 15:47:28 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def nativeTypeDereference(self, nativeType):
|
|
|
|
return self.fromNativeType(nativeType.GetPointeeType())
|
|
|
|
|
|
|
|
def nativeTypeTarget(self, nativeType):
|
|
|
|
code = nativeType.GetTypeClass()
|
|
|
|
if code == lldb.eTypeClassPointer:
|
|
|
|
return self.fromNativeType(nativeType.GetPointeeType())
|
|
|
|
if code == lldb.eTypeClassReference:
|
|
|
|
return self.fromNativeType(nativeType.GetDereferencedType())
|
|
|
|
if code == lldb.eTypeClassArray:
|
|
|
|
if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x
|
|
|
|
return self.fromNativeType(nativeType.GetArrayElementType())
|
|
|
|
fields = nativeType.get_fields_array()
|
|
|
|
return None if not len(fields) else self.nativeTypeTarget(fields[0])
|
|
|
|
if code == lldb.eTypeClassVector:
|
|
|
|
return self.fromNativeType(nativeType.GetVectorElementType())
|
|
|
|
return self.fromNativeType(nativeType)
|
|
|
|
|
2014-04-01 18:11:57 +02:00
|
|
|
def isWindowsTarget(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def isQnxTarget(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def isArmArchitecture(self):
|
|
|
|
return False
|
|
|
|
|
2014-01-09 13:25:17 +01:00
|
|
|
def qtVersionAndNamespace(self):
|
2014-03-12 18:04:51 +01:00
|
|
|
for func in self.target.FindFunctions('qVersion'):
|
|
|
|
name = func.GetSymbol().GetName()
|
2014-03-19 12:16:43 +01:00
|
|
|
if name.endswith('()'):
|
|
|
|
name = name[:-2]
|
2014-03-12 18:04:51 +01:00
|
|
|
if name.count(':') > 2:
|
|
|
|
continue
|
|
|
|
|
2014-03-19 12:16:43 +01:00
|
|
|
qtNamespace = name[:name.find('qVersion')]
|
|
|
|
self.qtNamespace = lambda: qtNamespace
|
|
|
|
|
2014-04-04 15:37:55 +02:00
|
|
|
options = lldb.SBExpressionOptions()
|
|
|
|
res = self.target.EvaluateExpression(name + '()', options)
|
|
|
|
|
|
|
|
if not res.IsValid() or not res.GetType().IsPointerType():
|
|
|
|
exp = '((const char*())%s)()' % name
|
|
|
|
res = self.target.EvaluateExpression(exp, options)
|
|
|
|
|
|
|
|
if not res.IsValid() or not res.GetType().IsPointerType():
|
|
|
|
exp = '((const char*())_Z8qVersionv)()'
|
|
|
|
res = self.target.EvaluateExpression(exp, options)
|
2014-03-12 18:04:51 +01:00
|
|
|
|
2014-04-04 15:37:55 +02:00
|
|
|
if not res.IsValid() or not res.GetType().IsPointerType():
|
|
|
|
continue
|
|
|
|
|
|
|
|
version = str(res)
|
2014-03-12 18:04:51 +01:00
|
|
|
if version.count('.') != 2:
|
|
|
|
continue
|
|
|
|
|
2014-03-19 12:16:43 +01:00
|
|
|
version.replace("'", '"') # Both seem possible
|
|
|
|
version = version[version.find('"')+1:version.rfind('"')]
|
2014-03-12 18:04:51 +01:00
|
|
|
|
|
|
|
(major, minor, patch) = version.split('.')
|
|
|
|
qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
|
|
|
|
self.qtVersion = lambda: qtVersion
|
|
|
|
|
|
|
|
return (qtNamespace, qtVersion)
|
|
|
|
|
|
|
|
return ('', 0x50200)
|
2014-01-09 13:25:17 +01:00
|
|
|
|
|
|
|
def qtNamespace(self):
|
2014-03-12 18:04:51 +01:00
|
|
|
return self.qtVersionAndNamespace()[0]
|
2014-01-09 13:25:17 +01:00
|
|
|
|
|
|
|
def qtVersion(self):
|
2014-01-09 16:23:17 +01:00
|
|
|
self.qtVersionAndNamespace()
|
2014-03-12 18:04:51 +01:00
|
|
|
return self.qtVersionAndNamespace()[1]
|
2013-06-27 10:42:32 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def handleCommand(self, command):
|
|
|
|
result = lldb.SBCommandReturnObject()
|
|
|
|
self.debugger.GetCommandInterpreter().HandleCommand(command, result)
|
|
|
|
success = result.Succeeded()
|
|
|
|
if success:
|
|
|
|
self.report('output="%s"' % result.GetOutput())
|
2013-04-10 13:55:15 +02:00
|
|
|
else:
|
2013-04-30 10:46:48 +02:00
|
|
|
self.report('error="%s"' % result.GetError())
|
|
|
|
|
|
|
|
def put(self, stuff):
|
2015-10-09 15:00:20 +02:00
|
|
|
self.output += stuff
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-01-16 14:23:53 +01:00
|
|
|
def canonicalTypeName(self, name):
|
|
|
|
return re.sub('\\bconst\\b', '', name).replace(' ', '')
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def lookupNativeType(self, name):
|
|
|
|
#warn("LOOKUP TYPE NAME: %s" % name)
|
2014-01-16 14:23:53 +01:00
|
|
|
typeobj = self.target.FindFirstType(name)
|
|
|
|
if typeobj.IsValid():
|
2016-09-06 08:54:43 +02:00
|
|
|
#warn("VALID FIRST : %s" % dir(typeobj))
|
2014-01-16 14:23:53 +01:00
|
|
|
return typeobj
|
2014-12-01 12:17:56 +01:00
|
|
|
typeobj = self.target.FindFirstType(name + '*')
|
|
|
|
if typeobj.IsValid():
|
|
|
|
return typeob.GetPointeeType()
|
|
|
|
typeobj = self.target.FindFirstType(name + '&')
|
|
|
|
if typeobj.IsValid():
|
|
|
|
return typeob.GetReferencedType()
|
|
|
|
if name.endswith('*'):
|
|
|
|
typeobj = self.target.FindFirstType(name[:-1].strip())
|
|
|
|
if typeobj.IsValid():
|
|
|
|
return typeobj.GetPointerType()
|
2016-09-06 08:54:43 +02:00
|
|
|
#warn("LOOKUP RESULT: %s" % typeobj.name)
|
|
|
|
#warn("LOOKUP VALID: %s" % typeobj.IsValid())
|
2014-12-01 12:17:56 +01:00
|
|
|
needle = self.canonicalTypeName(name)
|
|
|
|
#self.warn("NEEDLE: %s " % needle)
|
|
|
|
for i in xrange(self.target.GetNumModules()):
|
|
|
|
module = self.target.GetModuleAtIndex(i)
|
|
|
|
# SBModule.GetType is new somewhere after early 300.x
|
|
|
|
# So this may fail.
|
|
|
|
for t in module.GetTypes():
|
|
|
|
n = self.canonicalTypeName(t.GetName())
|
|
|
|
if n == needle:
|
|
|
|
#self.warn("FOUND TYPE DIRECT 2: %s " % t)
|
|
|
|
return t
|
|
|
|
if n == needle + '*':
|
|
|
|
#self.warn("FOUND TYPE BY POINTER 2: %s " % t.GetPointeeType())
|
|
|
|
return t.GetPointeeType()
|
|
|
|
if n == needle + '&':
|
|
|
|
#self.warn("FOUND TYPE BY REFERENCE 2: %s " % t)
|
|
|
|
return t.GetDereferencedType()
|
2016-09-06 08:54:43 +02:00
|
|
|
#warn("NOT FOUND: %s " % needle)
|
2014-01-16 14:23:53 +01:00
|
|
|
return None
|
2013-05-08 16:20:03 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def setupInferior(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
error = lldb.SBError()
|
2013-10-01 02:30:12 +02:00
|
|
|
|
|
|
|
self.executable_ = args['executable']
|
2015-10-27 15:50:41 +01:00
|
|
|
self.startMode_ = args.get('startmode', 1)
|
|
|
|
self.breakOnMain_ = args.get('breakonmain', 0)
|
|
|
|
self.useTerminal_ = args.get('useterminal', 0)
|
|
|
|
self.processArgs_ = args.get('processargs', [])
|
2015-12-08 16:58:20 +01:00
|
|
|
self.dyldImageSuffix = args.get('dyldimagesuffix', '')
|
|
|
|
self.dyldLibraryPath = args.get('dyldlibrarypath', '')
|
|
|
|
self.dyldFrameworkPath = args.get('dyldframeworkpath', '')
|
2016-05-11 12:15:37 +02:00
|
|
|
self.processArgs_ = list(map(lambda x: self.hexdecode(x), self.processArgs_))
|
2015-10-27 15:50:41 +01:00
|
|
|
self.attachPid_ = args.get('attachpid', 0)
|
|
|
|
self.sysRoot_ = args.get('sysroot', '')
|
|
|
|
self.remoteChannel_ = args.get('remotechannel', '')
|
2013-10-31 10:07:28 +01:00
|
|
|
self.platform_ = args.get('platform', '')
|
2015-10-09 15:00:20 +02:00
|
|
|
self.nativeMixed = int(args.get('nativemixed', 0))
|
2016-09-26 13:47:19 +02:00
|
|
|
self.workingDirectory_ = args.get('workingdirectory', '')
|
|
|
|
if self.workingDirectory_ == '':
|
|
|
|
self.workingDirectory_ = os.getcwd()
|
2013-10-01 02:30:12 +02:00
|
|
|
|
2015-02-04 14:25:59 +01:00
|
|
|
self.ignoreStops = 0
|
2015-02-27 11:56:03 +01:00
|
|
|
self.silentStops = 0
|
|
|
|
if platform.system() == "Linux":
|
|
|
|
if self.startMode_ == AttachCore:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
if self.useTerminal_:
|
|
|
|
self.ignoreStops = 2
|
|
|
|
else:
|
|
|
|
self.silentStops = 1
|
2014-03-03 16:59:56 +01:00
|
|
|
|
2015-02-27 16:56:51 +01:00
|
|
|
else:
|
|
|
|
if self.useTerminal_:
|
|
|
|
self.ignoreStops = 1
|
|
|
|
|
2013-10-31 10:07:28 +01:00
|
|
|
if self.platform_:
|
|
|
|
self.debugger.SetCurrentPlatform(self.platform_)
|
2013-12-10 12:53:20 +01:00
|
|
|
# sysroot has to be set *after* the platform
|
|
|
|
if self.sysRoot_:
|
|
|
|
self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
|
2014-02-04 18:36:32 +01:00
|
|
|
|
|
|
|
if os.path.isfile(self.executable_):
|
|
|
|
self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error)
|
|
|
|
else:
|
|
|
|
self.target = self.debugger.CreateTarget(None, None, None, True, error)
|
2013-05-29 14:55:57 +02:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
if self.nativeMixed:
|
|
|
|
self.interpreterEventBreakpoint = \
|
2015-10-14 13:26:22 +02:00
|
|
|
self.target.BreakpointCreateByName("qt_qmlDebugMessageAvailable")
|
2015-10-09 15:00:20 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
state = 1 if self.target.IsValid() else 0
|
|
|
|
self.reportResult('success="%s",msg="%s",exe="%s"' % (state, error, self.executable_), args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-02-27 11:56:03 +01:00
|
|
|
def runEngine(self, args):
|
|
|
|
self.prepare(args)
|
2013-05-31 15:27:54 +02:00
|
|
|
s = threading.Thread(target=self.loop, args=[])
|
|
|
|
s.start()
|
|
|
|
|
2015-02-27 11:56:03 +01:00
|
|
|
def prepare(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
error = lldb.SBError()
|
2013-05-31 15:27:54 +02:00
|
|
|
listener = self.debugger.GetListener()
|
|
|
|
|
2013-10-01 02:30:12 +02:00
|
|
|
if self.attachPid_ > 0:
|
|
|
|
attachInfo = lldb.SBAttachInfo(self.attachPid_)
|
|
|
|
self.process = self.target.Attach(attachInfo, error)
|
2013-10-31 10:07:28 +01:00
|
|
|
if not error.Success():
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("inferiorrunfailed")
|
2013-10-29 22:25:41 +01:00
|
|
|
return
|
|
|
|
self.report('pid="%s"' % self.process.GetProcessID())
|
2014-03-19 12:12:24 +01:00
|
|
|
# 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
|
2016-09-14 14:31:27 +02:00
|
|
|
# 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("enginerunandinferiorstopok")
|
|
|
|
else:
|
|
|
|
self.reportState("enginerunandinferiorrunok")
|
2014-07-01 12:30:38 +02:00
|
|
|
elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
|
2013-10-29 22:25:41 +01:00
|
|
|
self.process = self.target.ConnectRemote(
|
2014-06-02 17:05:52 +02:00
|
|
|
self.debugger.GetListener(),
|
|
|
|
self.remoteChannel_, None, error)
|
2013-10-31 10:07:28 +01:00
|
|
|
if not error.Success():
|
2015-09-09 16:34:09 +02:00
|
|
|
self.report(self.describeError(error))
|
2014-06-02 17:05:52 +02:00
|
|
|
self.reportState("enginerunfailed")
|
2013-10-31 10:07:28 +01:00
|
|
|
return
|
2014-03-19 12:12:24 +01:00
|
|
|
# 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.
|
|
|
|
self.reportState("enginerunandinferiorrunok")
|
2015-02-27 11:56:03 +01:00
|
|
|
elif self.startMode_ == AttachCore:
|
|
|
|
coreFile = args.get('coreFile', '');
|
|
|
|
self.process = self.target.LoadCore(coreFile)
|
|
|
|
self.reportState("enginerunokandinferiorunrunnable")
|
2013-10-01 02:30:12 +02:00
|
|
|
else:
|
2014-02-04 13:32:17 +01:00
|
|
|
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
|
2016-09-26 13:47:19 +02:00
|
|
|
launchInfo.SetWorkingDirectory(self.workingDirectory_)
|
2013-10-20 21:45:47 +02:00
|
|
|
environmentList = [key + "=" + value for key,value in os.environ.items()]
|
2015-12-08 16:58:20 +01:00
|
|
|
if self.dyldImageSuffix:
|
|
|
|
environmentList.append('DYLD_IMAGE_SUFFIX=' + self.dyldImageSuffix)
|
|
|
|
if self.dyldLibraryPath:
|
|
|
|
environmentList.append('DYLD_LIBRARY_PATH=' + self.dyldLibraryPath)
|
|
|
|
if self.dyldFrameworkPath:
|
|
|
|
environmentList.append('DYLD_FRAMEWORK_PATH=' + self.dyldFrameworkPath)
|
2013-10-20 21:45:47 +02:00
|
|
|
launchInfo.SetEnvironmentEntries(environmentList, False)
|
2014-02-28 13:03:21 +01:00
|
|
|
if self.breakOnMain_:
|
|
|
|
self.createBreakpointAtMain()
|
2013-10-01 02:30:12 +02:00
|
|
|
self.process = self.target.Launch(launchInfo, error)
|
2013-11-01 11:32:04 +01:00
|
|
|
if not error.Success():
|
2015-09-09 16:34:09 +02:00
|
|
|
self.report(self.describeError(error))
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("enginerunfailed")
|
2013-10-29 22:25:41 +01:00
|
|
|
return
|
|
|
|
self.report('pid="%s"' % self.process.GetProcessID())
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("enginerunandinferiorrunok")
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-09-22 17:55:20 +02:00
|
|
|
def loop(self):
|
2013-05-31 15:27:54 +02:00
|
|
|
event = lldb.SBEvent()
|
2014-09-22 17:55:20 +02:00
|
|
|
listener = self.debugger.GetListener()
|
2013-05-31 15:27:54 +02:00
|
|
|
while True:
|
|
|
|
if listener.WaitForEvent(10000000, event):
|
|
|
|
self.handleEvent(event)
|
|
|
|
else:
|
|
|
|
warn('TIMEOUT')
|
2013-05-13 16:04:00 +02:00
|
|
|
|
2013-05-07 08:46:51 +02:00
|
|
|
def describeError(self, error):
|
2013-04-30 10:46:48 +02:00
|
|
|
desc = lldb.SBStream()
|
|
|
|
error.GetDescription(desc)
|
2015-09-09 16:34:09 +02:00
|
|
|
result = 'success="%s",' % int(error.Success())
|
|
|
|
result += 'error={type="%s"' % error.GetType()
|
|
|
|
if error.GetType():
|
|
|
|
result += ',status="%s"' % error.GetCString()
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',code="%s"' % error.GetError()
|
|
|
|
result += ',desc="%s"}' % desc.GetData()
|
2013-05-07 08:46:51 +02:00
|
|
|
return result
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def describeStatus(self, status):
|
|
|
|
return 'status="%s",' % status
|
|
|
|
|
|
|
|
def describeLocation(self, frame):
|
|
|
|
if int(frame.pc) == 0xffffffffffffffff:
|
|
|
|
return ''
|
2015-10-09 15:00:20 +02:00
|
|
|
fileName = fileNameAsString(frame.line_entry.file)
|
|
|
|
function = frame.GetFunctionName()
|
2015-09-09 16:34:09 +02:00
|
|
|
line = frame.line_entry.line
|
2015-10-09 15:00:20 +02:00
|
|
|
return 'location={file="%s",line="%s",address="%s",function="%s"}' \
|
|
|
|
% (fileName, line, frame.pc, function)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
def currentThread(self):
|
2014-01-29 11:43:11 +01:00
|
|
|
return None if self.process is None else self.process.GetSelectedThread()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
def currentFrame(self):
|
2014-01-29 11:43:11 +01:00
|
|
|
thread = self.currentThread()
|
|
|
|
return None if thread is None else thread.GetSelectedFrame()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-11-11 15:27:24 +01:00
|
|
|
def firstStoppedThread(self):
|
|
|
|
for i in xrange(0, self.process.GetNumThreads()):
|
|
|
|
thread = self.process.GetThreadAtIndex(i)
|
2013-12-02 10:37:16 +01:00
|
|
|
reason = thread.GetStopReason()
|
|
|
|
if (reason == lldb.eStopReasonBreakpoint or
|
|
|
|
reason == lldb.eStopReasonException or
|
|
|
|
reason == lldb.eStopReasonPlanComplete or
|
|
|
|
reason == lldb.eStopReasonSignal or
|
|
|
|
reason == lldb.eStopReasonWatchpoint):
|
2013-11-11 15:27:24 +01:00
|
|
|
return thread
|
|
|
|
return None
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchThreads(self, args):
|
|
|
|
result = 'threads=['
|
2013-05-22 12:06:56 +02:00
|
|
|
for i in xrange(0, self.process.GetNumThreads()):
|
2013-05-02 14:57:06 +02:00
|
|
|
thread = self.process.GetThreadAtIndex(i)
|
2015-02-04 14:15:14 +01:00
|
|
|
if thread.is_stopped:
|
|
|
|
state = "stopped"
|
|
|
|
elif thread.is_suspended:
|
|
|
|
state = "suspended"
|
|
|
|
else:
|
|
|
|
state = "unknown"
|
|
|
|
reason = thread.GetStopReason()
|
2013-05-22 12:06:56 +02:00
|
|
|
result += '{id="%d"' % thread.GetThreadID()
|
|
|
|
result += ',index="%s"' % i
|
2013-05-29 16:59:16 +02:00
|
|
|
result += ',details="%s"' % thread.GetQueueName()
|
2015-02-04 14:15:14 +01:00
|
|
|
result += ',stop-reason="%s"' % self.stopReason(thread.GetStopReason())
|
|
|
|
result += ',state="%s"' % state
|
2013-05-02 14:57:06 +02:00
|
|
|
result += ',name="%s"' % thread.GetName()
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',frame={'
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
result += 'pc="0x%x"' % frame.pc
|
|
|
|
result += ',addr="0x%x"' % frame.pc
|
|
|
|
result += ',fp="0x%x"' % frame.fp
|
2013-05-29 16:59:16 +02:00
|
|
|
result += ',func="%s"' % frame.GetFunctionName()
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',line="%s"' % frame.line_entry.line
|
2015-10-08 16:19:57 +02:00
|
|
|
result += ',fullname="%s"' % fileNameAsString(frame.line_entry.file)
|
|
|
|
result += ',file="%s"' % fileNameAsString(frame.line_entry.file)
|
2013-04-30 10:46:48 +02:00
|
|
|
result += '}},'
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
result += '],current-thread-id="%s"' % self.currentThread().id
|
|
|
|
self.reportResult(result, args)
|
2015-03-25 16:34:03 +01:00
|
|
|
|
2013-11-11 15:27:24 +01:00
|
|
|
def firstUsableFrame(self, thread):
|
2013-07-02 15:43:29 +02:00
|
|
|
for i in xrange(10):
|
2013-06-14 10:03:00 +02:00
|
|
|
frame = thread.GetFrameAtIndex(i)
|
|
|
|
lineEntry = frame.GetLineEntry()
|
|
|
|
line = lineEntry.GetLine()
|
|
|
|
if line != 0:
|
|
|
|
return i
|
|
|
|
return None
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchStack(self, args):
|
2013-11-05 16:12:31 +01:00
|
|
|
if not self.process:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('msg="No process"', args)
|
2013-11-05 16:12:31 +01:00
|
|
|
return
|
|
|
|
thread = self.currentThread()
|
|
|
|
if not thread:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('msg="No thread"', args)
|
2013-11-05 16:12:31 +01:00
|
|
|
return
|
2014-02-03 13:47:26 +01:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
isNativeMixed = int(args.get('nativemixed', 0))
|
2014-02-03 13:47:26 +01:00
|
|
|
|
2015-02-05 14:19:32 +01:00
|
|
|
limit = args.get('stacklimit', -1)
|
|
|
|
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
|
2015-02-04 17:21:55 +01:00
|
|
|
self.currentCallContext = None
|
2014-03-06 12:04:47 +01:00
|
|
|
result = 'stack={current-thread="%s"' % thread.GetThreadID()
|
2013-11-05 16:12:31 +01:00
|
|
|
result += ',frames=['
|
|
|
|
for i in xrange(n):
|
|
|
|
frame = thread.GetFrameAtIndex(i)
|
2014-02-03 13:47:26 +01:00
|
|
|
if not frame.IsValid():
|
|
|
|
isLimited = False
|
|
|
|
break
|
2015-02-04 13:29:42 +01:00
|
|
|
|
2013-11-05 16:12:31 +01:00
|
|
|
lineEntry = frame.GetLineEntry()
|
2015-02-04 13:29:42 +01:00
|
|
|
lineNumber = lineEntry.GetLine()
|
|
|
|
|
|
|
|
pc = frame.GetPC()
|
|
|
|
level = frame.idx
|
|
|
|
addr = frame.GetPCAddress().GetLoadAddress(self.target)
|
2015-10-09 15:00:20 +02:00
|
|
|
|
2015-02-04 13:29:42 +01:00
|
|
|
functionName = frame.GetFunctionName()
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
if isNativeMixed and functionName == "::qt_qmlDebugMessageAvailable()":
|
2015-10-09 15:00:20 +02:00
|
|
|
interpreterStack = self.extractInterpreterStack()
|
|
|
|
for interpreterFrame in interpreterStack.get('frames', []):
|
|
|
|
function = interpreterFrame.get('function', '')
|
|
|
|
fileName = interpreterFrame.get('file', '')
|
|
|
|
language = interpreterFrame.get('language', '')
|
|
|
|
lineNumber = interpreterFrame.get('line', 0)
|
|
|
|
context = interpreterFrame.get('context', 0)
|
|
|
|
result += ('frame={function="%s",file="%s",'
|
|
|
|
'line="%s",language="%s",context="%s"}'
|
|
|
|
% (function, fileName, lineNumber, language, context))
|
|
|
|
|
|
|
|
fileName = fileNameAsString(lineEntry.file)
|
2015-02-04 13:29:42 +01:00
|
|
|
result += '{pc="0x%x"' % pc
|
|
|
|
result += ',level="%d"' % level
|
2015-10-08 16:19:57 +02:00
|
|
|
result += ',address="0x%x"' % addr
|
|
|
|
result += ',function="%s"' % functionName
|
2015-02-04 13:29:42 +01:00
|
|
|
result += ',line="%d"' % lineNumber
|
2015-10-08 16:19:57 +02:00
|
|
|
result += ',file="%s"},' % fileName
|
2014-02-03 13:47:26 +01:00
|
|
|
result += ']'
|
|
|
|
result += ',hasmore="%d"' % isLimited
|
|
|
|
result += ',limit="%d"' % limit
|
|
|
|
result += '}'
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(result, args)
|
|
|
|
|
|
|
|
def reportResult(self, result, args):
|
|
|
|
self.report('result={token="%s",%s}' % (args.get("token", 0), result))
|
2015-02-24 11:33:25 +01:00
|
|
|
|
2015-03-05 10:41:16 +01:00
|
|
|
def reportToken(self, args):
|
|
|
|
if "token" in args:
|
|
|
|
# Unusual syntax intended, to support the double-click in left
|
|
|
|
# logview pane feature.
|
|
|
|
self.report('token(\"%s\")' % args["token"])
|
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
def readRawMemory(self, address, size):
|
2013-05-22 14:30:36 +02:00
|
|
|
if size == 0:
|
2016-09-06 08:54:43 +02:00
|
|
|
return bytes()
|
2013-05-22 14:30:36 +02:00
|
|
|
error = lldb.SBError()
|
2016-09-06 08:54:43 +02:00
|
|
|
#warn("READ: %s %s" % (address, size))
|
|
|
|
res = self.process.ReadMemory(address, size, error)
|
|
|
|
if res is None:
|
|
|
|
return bytes()
|
|
|
|
return res
|
|
|
|
|
2014-04-11 13:20:59 +02:00
|
|
|
def findStaticMetaObject(self, typeName):
|
|
|
|
symbolName = self.mangleName(typeName + '::staticMetaObject')
|
2016-07-22 10:20:01 +02:00
|
|
|
symbol = self.target.FindFirstGlobalVariable(symbolName)
|
2016-09-06 08:54:43 +02:00
|
|
|
return symbol.AddressOf().GetValueAsUnsigned() if symbol.IsValid() else 0
|
2014-04-11 13:20:59 +02:00
|
|
|
|
2014-03-12 13:20:21 +01:00
|
|
|
def findSymbol(self, symbolName):
|
|
|
|
return self.target.FindFirstGlobalVariable(symbolName)
|
2013-07-03 13:32:19 +02:00
|
|
|
|
2014-01-22 14:01:07 +01:00
|
|
|
def warn(self, msg):
|
2014-09-22 18:00:06 +02:00
|
|
|
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
|
2014-01-22 14:01:07 +01:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
def fetchVariables(self, args):
|
|
|
|
(ok, res) = self.tryFetchInterpreterVariables(args)
|
|
|
|
if ok:
|
|
|
|
self.reportResult(res, args)
|
|
|
|
return
|
|
|
|
|
|
|
|
self.expandedINames = set(args.get('expanded', []))
|
|
|
|
self.autoDerefPointers = int(args.get('autoderef', '0'))
|
|
|
|
self.useDynamicType = int(args.get('dyntype', '0'))
|
|
|
|
self.useFancy = int(args.get('fancy', '0'))
|
|
|
|
self.passExceptions = int(args.get('passexceptions', '0'))
|
2015-12-16 14:13:44 +01:00
|
|
|
self.showQObjectNames = int(args.get('qobjectnames', '0'))
|
2015-10-09 15:00:20 +02:00
|
|
|
self.currentWatchers = args.get('watchers', {})
|
2015-10-27 15:50:41 +01:00
|
|
|
self.typeformats = args.get('typeformats', {})
|
|
|
|
self.formats = args.get('formats', {})
|
2014-03-19 12:08:25 +01:00
|
|
|
|
2014-01-29 11:43:11 +01:00
|
|
|
frame = self.currentFrame()
|
|
|
|
if frame is None:
|
2015-10-09 15:00:20 +02:00
|
|
|
self.reportResult('error="No frame"', args)
|
2014-01-29 11:43:11 +01:00
|
|
|
return
|
2015-03-26 13:03:38 +01:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
self.output = ''
|
2016-07-21 09:19:30 +02:00
|
|
|
self.currentAddress = None
|
2015-10-27 15:50:41 +01:00
|
|
|
partialVariable = args.get('partialvar', "")
|
2015-03-26 13:03:38 +01:00
|
|
|
isPartial = len(partialVariable) > 0
|
|
|
|
|
2013-05-30 15:35:52 +02:00
|
|
|
self.currentIName = 'local'
|
2015-09-09 16:34:09 +02:00
|
|
|
self.put('data=[')
|
2013-07-08 18:14:00 +02:00
|
|
|
self.anonNumber = 0
|
2013-05-30 15:35:52 +02:00
|
|
|
|
2014-02-04 19:32:24 +01:00
|
|
|
with SubItem(self, '[statics]'):
|
|
|
|
self.put('iname="%s",' % self.currentIName)
|
|
|
|
self.putEmptyValue()
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
statics = frame.GetVariables(False, False, True, False)
|
|
|
|
if len(statics):
|
|
|
|
for i in xrange(len(statics)):
|
|
|
|
staticVar = statics[i]
|
2016-09-26 14:29:16 +02:00
|
|
|
staticVar.SetPreferSyntheticValue(False)
|
2014-02-04 19:32:24 +01:00
|
|
|
typename = staticVar.GetType().GetName()
|
|
|
|
name = staticVar.GetName()
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.put('name="%s",' % name)
|
|
|
|
self.put('iname="%s",' % self.currentIName)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putItem(self.fromNativeValue(staticVar))
|
2014-02-04 19:32:24 +01:00
|
|
|
else:
|
|
|
|
with SubItem(self, "None"):
|
|
|
|
self.putEmptyValue()
|
|
|
|
self.putNumChild(0)
|
|
|
|
|
2016-09-20 11:52:06 +02:00
|
|
|
# FIXME: Implement shortcut for partial updates.
|
|
|
|
#if isPartial:
|
|
|
|
# values = [frame.FindVariable(partialVariable)]
|
|
|
|
#else:
|
|
|
|
if True:
|
|
|
|
values = list(frame.GetVariables(True, True, False, False))
|
|
|
|
values.reverse() # To get shadowed vars numbered backwards.
|
|
|
|
|
|
|
|
variables = []
|
|
|
|
for val in values:
|
2016-09-26 14:29:16 +02:00
|
|
|
val.SetPreferSyntheticValue(False)
|
2016-09-20 11:52:06 +02:00
|
|
|
if not val.IsValid():
|
|
|
|
continue
|
|
|
|
self.currentContextValue = val
|
|
|
|
name = val.GetName()
|
|
|
|
if name is None:
|
|
|
|
# This can happen for unnamed function parameters with
|
|
|
|
# default values: void foo(int = 0)
|
|
|
|
continue
|
|
|
|
value = self.fromNativeValue(val)
|
|
|
|
value.name = name
|
|
|
|
variables.append(value)
|
|
|
|
|
|
|
|
self.handleLocals(variables)
|
2015-03-26 13:03:38 +01:00
|
|
|
self.handleWatches(args)
|
2013-05-30 15:35:52 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
self.put('],partial="%d"' % isPartial)
|
2015-10-09 15:00:20 +02:00
|
|
|
self.reportResult(self.output, args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchRegisters(self, args = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2015-09-09 16:34:09 +02:00
|
|
|
result = 'process="none"'
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
|
|
|
frame = self.currentFrame()
|
2014-01-29 11:43:11 +01:00
|
|
|
if frame:
|
|
|
|
result = 'registers=['
|
|
|
|
for group in frame.GetRegisters():
|
|
|
|
for reg in group:
|
2015-08-27 13:38:41 +02:00
|
|
|
value = ''.join(["%02x" % x for x in reg.GetData().uint8s])
|
2014-01-29 11:43:11 +01:00
|
|
|
result += '{name="%s"' % reg.GetName()
|
2015-08-27 13:38:41 +02:00
|
|
|
result += ',value="0x%s"' % value
|
2014-12-17 13:14:29 +01:00
|
|
|
result += ',size="%s"' % reg.GetByteSize()
|
2014-01-29 11:43:11 +01:00
|
|
|
result += ',type="%s"},' % reg.GetType()
|
|
|
|
result += ']'
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(result, args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
def setRegister(self, args):
|
|
|
|
name = args["name"]
|
|
|
|
value = args["value"]
|
|
|
|
result = lldb.SBCommandReturnObject()
|
2015-08-27 13:38:41 +02:00
|
|
|
interp = self.debugger.GetCommandInterpreter()
|
|
|
|
interp.HandleCommand("register write %s %s" % (name, value), result)
|
2015-08-25 13:48:55 +02:00
|
|
|
success = result.Succeeded()
|
|
|
|
if success:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('output="%s"' % result.GetOutput(), args)
|
2015-08-27 13:38:41 +02:00
|
|
|
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:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('output="%s"' % result.GetOutput(), args)
|
|
|
|
else:
|
|
|
|
self.reportResult('error="%s"' % result.GetError(), args)
|
2015-08-25 13:48:55 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def report(self, stuff):
|
2014-03-19 12:08:25 +01:00
|
|
|
with self.outputLock:
|
2015-01-30 12:36:04 +01:00
|
|
|
sys.stdout.write("@\n" + stuff + "@\n")
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def reportState(self, state):
|
|
|
|
self.report('state="%s"' % state)
|
2014-02-06 16:47:07 +01:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def interruptInferior(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('status="No process to interrupt",success="0"', args)
|
|
|
|
else:
|
|
|
|
self.isInterrupting_ = True
|
|
|
|
error = self.process.Stop()
|
2015-10-09 15:00:20 +02:00
|
|
|
self.reportResult(self.describeError(error), args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def detachInferior(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('status="No process to detach from."', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
|
|
|
error = self.process.Detach()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeError(error), args)
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def continueInferior(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('status="No process to continue."', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
2015-09-09 16:34:09 +02:00
|
|
|
# Can fail when attaching to GDBserver.
|
2013-04-30 10:46:48 +02:00
|
|
|
error = self.process.Continue()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeError(error), args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def quitDebugger(self, args):
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("inferiorshutdownrequested")
|
2013-06-24 17:40:00 +02:00
|
|
|
self.process.Kill()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-06-24 17:40:00 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def handleEvent(self, event):
|
|
|
|
out = lldb.SBStream()
|
|
|
|
event.GetDescription(out)
|
2013-05-02 14:31:35 +02:00
|
|
|
#warn("EVENT: %s" % event)
|
2015-01-23 17:54:00 +01:00
|
|
|
eventType = event.GetType()
|
2013-04-30 10:46:48 +02:00
|
|
|
msg = lldb.SBEvent.GetCStringFromEvent(event)
|
|
|
|
flavor = event.GetDataFlavor()
|
2013-05-02 14:31:35 +02:00
|
|
|
state = lldb.SBProcess.GetStateFromEvent(event)
|
2015-02-04 13:29:42 +01:00
|
|
|
bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event)
|
2016-09-06 08:54:43 +02:00
|
|
|
skipEventReporting = self.debuggerCommandInProgress \
|
|
|
|
and eventType in (lldb.SBProcess.eBroadcastBitSTDOUT, lldb.SBProcess.eBroadcastBitSTDERR)
|
2015-02-04 13:29:42 +01:00
|
|
|
self.report('event={type="%s",data="%s",msg="%s",flavor="%s",state="%s",bp="%s"}'
|
2015-02-04 14:15:14 +01:00
|
|
|
% (eventType, out.GetData(), msg, flavor, self.stateName(state), bp))
|
2013-05-02 14:31:35 +02:00
|
|
|
if state != self.eventState:
|
2016-08-02 14:50:54 +02:00
|
|
|
if not skipEventReporting:
|
|
|
|
self.eventState = state
|
2013-05-22 14:30:36 +02:00
|
|
|
if state == lldb.eStateExited:
|
2013-05-29 15:38:49 +02:00
|
|
|
if self.isShuttingDown_:
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("inferiorshutdownok")
|
2013-05-29 15:38:49 +02:00
|
|
|
else:
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("inferiorexited")
|
2013-05-29 15:38:49 +02:00
|
|
|
self.report('exited={status="%s",desc="%s"}'
|
2013-05-22 14:30:36 +02:00
|
|
|
% (self.process.GetExitStatus(), self.process.GetExitDescription()))
|
2013-06-24 17:40:00 +02:00
|
|
|
elif state == lldb.eStateStopped:
|
2015-02-04 13:29:42 +01:00
|
|
|
stoppedThread = self.firstStoppedThread()
|
|
|
|
if stoppedThread:
|
|
|
|
#self.report("STOPPED THREAD: %s" % stoppedThread)
|
|
|
|
frame = stoppedThread.GetFrameAtIndex(0)
|
|
|
|
#self.report("FRAME: %s" % frame)
|
|
|
|
function = frame.GetFunction()
|
2015-10-09 15:00:20 +02:00
|
|
|
functionName = function.GetName()
|
|
|
|
if functionName == "::qt_qmlDebugConnectorOpen()":
|
|
|
|
self.report("RESOLVER HIT")
|
|
|
|
for resolver in self.interpreterBreakpointResolvers:
|
|
|
|
resolver()
|
|
|
|
self.report("AUTO-CONTINUE AFTER RESOLVING")
|
|
|
|
self.reportState("inferiorstopok")
|
2015-02-04 13:29:42 +01:00
|
|
|
self.process.Continue();
|
|
|
|
return
|
2015-10-14 13:26:22 +02:00
|
|
|
if functionName == "::qt_qmlDebugMessageAvailable()":
|
|
|
|
self.report("ASYNC MESSAGE FROM SERVICE")
|
|
|
|
res = self.handleInterpreterMessage()
|
2015-10-09 15:00:20 +02:00
|
|
|
if not res:
|
|
|
|
self.report("EVENT NEEDS NO STOP")
|
|
|
|
self.reportState("stopped")
|
|
|
|
self.process.Continue();
|
|
|
|
return
|
2013-06-24 17:40:00 +02:00
|
|
|
if self.isInterrupting_:
|
|
|
|
self.isInterrupting_ = False
|
2015-10-09 15:00:20 +02:00
|
|
|
self.reportState("stopped")
|
2014-03-03 16:59:56 +01:00
|
|
|
elif self.ignoreStops > 0:
|
|
|
|
self.ignoreStops -= 1
|
|
|
|
self.process.Continue()
|
2015-02-27 11:56:03 +01:00
|
|
|
elif self.silentStops > 0:
|
|
|
|
self.silentStops -= 1
|
2013-06-24 17:40:00 +02:00
|
|
|
else:
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("stopped")
|
2013-06-24 17:40:00 +02:00
|
|
|
else:
|
2016-08-02 14:50:54 +02:00
|
|
|
if not skipEventReporting:
|
|
|
|
self.reportState(self.stateName(state))
|
2015-01-23 17:54:00 +01:00
|
|
|
if eventType == lldb.SBProcess.eBroadcastBitStateChanged: # 1
|
2013-06-14 10:03:00 +02:00
|
|
|
state = self.process.GetState()
|
|
|
|
if state == lldb.eStateStopped:
|
2013-11-11 15:27:24 +01:00
|
|
|
stoppedThread = self.firstStoppedThread()
|
|
|
|
if stoppedThread:
|
|
|
|
self.process.SetSelectedThread(stoppedThread)
|
2015-01-23 17:54:00 +01:00
|
|
|
elif eventType == lldb.SBProcess.eBroadcastBitInterrupt: # 2
|
2013-04-30 10:46:48 +02:00
|
|
|
pass
|
2015-01-23 17:54:00 +01:00
|
|
|
elif eventType == lldb.SBProcess.eBroadcastBitSTDOUT:
|
2013-05-29 12:14:49 +02:00
|
|
|
# FIXME: Size?
|
|
|
|
msg = self.process.GetSTDOUT(1024)
|
2016-04-05 15:20:54 +02:00
|
|
|
if msg is not None:
|
|
|
|
self.report('output={channel="stdout",data="%s"}' % self.hexencode(msg))
|
2015-01-23 17:54:00 +01:00
|
|
|
elif eventType == lldb.SBProcess.eBroadcastBitSTDERR:
|
2013-05-29 12:14:49 +02:00
|
|
|
msg = self.process.GetSTDERR(1024)
|
2016-04-05 15:20:54 +02:00
|
|
|
if msg is not None:
|
|
|
|
self.report('output={channel="stderr",data="%s"}' % self.hexencode(msg))
|
2015-01-23 17:54:00 +01:00
|
|
|
elif eventType == lldb.SBProcess.eBroadcastBitProfileData:
|
2013-04-30 10:46:48 +02:00
|
|
|
pass
|
|
|
|
|
2014-03-05 19:06:24 +01:00
|
|
|
def describeBreakpoint(self, bp):
|
2013-06-14 15:15:09 +02:00
|
|
|
isWatch = isinstance(bp, lldb.SBWatchpoint)
|
|
|
|
if isWatch:
|
|
|
|
result = 'lldbid="%s"' % (qqWatchpointOffset + bp.GetID())
|
|
|
|
else:
|
|
|
|
result = 'lldbid="%s"' % bp.GetID()
|
2016-01-06 13:16:37 +01:00
|
|
|
result += ',valid="%s"' % (1 if bp.IsValid() else 0)
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',hitcount="%s"' % bp.GetHitCount()
|
2016-01-06 13:16:37 +01:00
|
|
|
if bp.IsValid():
|
|
|
|
if isinstance(bp, lldb.SBBreakpoint):
|
|
|
|
result += ',threadid="%s"' % bp.GetThreadID()
|
|
|
|
result += ',oneshot="%s"' % (1 if bp.IsOneShot() else 0)
|
2015-09-09 16:34:09 +02:00
|
|
|
cond = bp.GetCondition()
|
|
|
|
result += ',condition="%s"' % self.hexencode("" if cond is None else cond)
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',enabled="%s"' % (1 if bp.IsEnabled() else 0)
|
|
|
|
result += ',valid="%s"' % (1 if bp.IsValid() else 0)
|
|
|
|
result += ',ignorecount="%s"' % bp.GetIgnoreCount()
|
2016-01-06 13:16:37 +01:00
|
|
|
if bp.IsValid() and isinstance(bp, lldb.SBBreakpoint):
|
|
|
|
result += ',locations=['
|
|
|
|
lineEntry = None
|
|
|
|
for i in xrange(bp.GetNumLocations()):
|
|
|
|
loc = bp.GetLocationAtIndex(i)
|
|
|
|
addr = loc.GetAddress()
|
|
|
|
lineEntry = addr.GetLineEntry()
|
|
|
|
result += '{locid="%s"' % loc.GetID()
|
|
|
|
result += ',function="%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()
|
|
|
|
result += ',line="%s"' % lineEntry.GetLine()
|
2013-04-30 10:46:48 +02:00
|
|
|
return result
|
|
|
|
|
2014-02-28 13:03:21 +01:00
|
|
|
def createBreakpointAtMain(self):
|
|
|
|
return self.target.BreakpointCreateByName(
|
|
|
|
"main", self.target.GetExecutable().GetFilename())
|
|
|
|
|
2015-02-02 13:48:33 +01:00
|
|
|
def insertBreakpoint(self, args):
|
2015-02-04 13:29:42 +01:00
|
|
|
bpType = args["type"]
|
|
|
|
if bpType == BreakpointByFileAndLine:
|
2015-10-08 16:19:57 +02:00
|
|
|
fileName = args["file"]
|
2015-02-04 13:29:42 +01:00
|
|
|
if fileName.endswith(".js") or fileName.endswith(".qml"):
|
2015-10-14 13:26:22 +02:00
|
|
|
self.insertInterpreterBreakpoint(args)
|
2015-02-04 13:29:42 +01:00
|
|
|
return
|
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
extra = ''
|
2015-02-02 13:48:33 +01:00
|
|
|
more = True
|
2013-05-16 17:37:41 +02:00
|
|
|
if bpType == BreakpointByFileAndLine:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.BreakpointCreateByLocation(
|
2015-10-08 16:19:57 +02:00
|
|
|
str(args["file"]), int(args["line"]))
|
2013-05-16 17:37:41 +02:00
|
|
|
elif bpType == BreakpointByFunction:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.BreakpointCreateByName(args["function"])
|
2013-06-14 15:15:09 +02:00
|
|
|
elif bpType == BreakpointByAddress:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.BreakpointCreateByAddress(args["address"])
|
2013-05-16 17:37:41 +02:00
|
|
|
elif bpType == BreakpointAtMain:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.createBreakpointAtMain()
|
2013-06-13 18:22:44 +02:00
|
|
|
elif bpType == BreakpointAtThrow:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.BreakpointCreateForException(
|
2013-06-13 18:22:44 +02:00
|
|
|
lldb.eLanguageTypeC_plus_plus, False, True)
|
|
|
|
elif bpType == BreakpointAtCatch:
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.BreakpointCreateForException(
|
2013-06-13 18:22:44 +02:00
|
|
|
lldb.eLanguageTypeC_plus_plus, True, False)
|
2013-06-14 15:15:09 +02:00
|
|
|
elif bpType == WatchpointAtAddress:
|
|
|
|
error = lldb.SBError()
|
2016-01-06 13:16:37 +01:00
|
|
|
# This might yield bp.IsValid() == False and
|
|
|
|
# error.desc == "process is not alive".
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.WatchAddress(args["address"], 4, False, True, error)
|
2015-09-09 16:34:09 +02:00
|
|
|
extra = self.describeError(error)
|
2013-06-14 15:15:09 +02:00
|
|
|
elif bpType == WatchpointAtExpression:
|
|
|
|
# FIXME: Top level-only for now.
|
|
|
|
try:
|
|
|
|
frame = self.currentFrame()
|
|
|
|
value = frame.FindVariable(args["expression"])
|
|
|
|
error = lldb.SBError()
|
2014-03-05 19:06:24 +01:00
|
|
|
bp = self.target.WatchAddress(value.GetLoadAddress(),
|
2013-06-14 15:15:09 +02:00
|
|
|
value.GetByteSize(), False, True, error)
|
|
|
|
except:
|
2015-02-02 13:48:33 +01:00
|
|
|
bp = self.target.BreakpointCreateByName(None)
|
2013-05-16 17:37:41 +02:00
|
|
|
else:
|
2014-02-06 17:50:21 +01:00
|
|
|
# This leaves the unhandled breakpoint in a (harmless)
|
|
|
|
# "pending" state.
|
2015-02-02 13:48:33 +01:00
|
|
|
bp = self.target.BreakpointCreateByName(None)
|
|
|
|
more = False
|
|
|
|
|
2016-01-06 13:16:37 +01:00
|
|
|
if more and bp.IsValid():
|
2015-02-02 13:48:33 +01:00
|
|
|
bp.SetIgnoreCount(int(args["ignorecount"]))
|
2015-09-09 16:34:09 +02:00
|
|
|
bp.SetCondition(self.hexdecode(args["condition"]))
|
2015-04-28 15:26:35 -10:00
|
|
|
bp.SetEnabled(bool(args["enabled"]))
|
2016-04-13 18:19:45 +02:00
|
|
|
bp.SetScriptCallbackBody('\n'.join([
|
|
|
|
"def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):",
|
|
|
|
" " + self.hexdecode(args["command"]).replace('\n', '\n '),
|
|
|
|
"from cStringIO import StringIO",
|
|
|
|
"origout = sys.stdout",
|
|
|
|
"sys.stdout = StringIO()",
|
|
|
|
"result = foo()",
|
|
|
|
"d = lldb.theDumper",
|
|
|
|
"output = d.hexencode(sys.stdout.getvalue())",
|
|
|
|
"sys.stdout = origout",
|
|
|
|
"d.report('output={channel=\"stderr\",data=\"' + output + '\"}')",
|
|
|
|
"if result is False:",
|
|
|
|
" d.reportState('continueafternextstop')",
|
|
|
|
"return True"
|
|
|
|
]))
|
2016-01-06 13:16:37 +01:00
|
|
|
if isinstance(bp, lldb.SBBreakpoint):
|
|
|
|
bp.SetOneShot(bool(args["oneshot"]))
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeBreakpoint(bp) + extra, args)
|
2013-05-16 17:37:41 +02:00
|
|
|
|
|
|
|
def changeBreakpoint(self, args):
|
2015-02-02 13:48:33 +01:00
|
|
|
lldbId = int(args["lldbid"])
|
|
|
|
if lldbId > qqWatchpointOffset:
|
|
|
|
bp = self.target.FindWatchpointByID(lldbId)
|
2013-06-14 15:15:09 +02:00
|
|
|
else:
|
2015-02-02 13:48:33 +01:00
|
|
|
bp = self.target.FindBreakpointByID(lldbId)
|
2016-01-06 13:16:37 +01:00
|
|
|
if bp.IsValid():
|
|
|
|
bp.SetIgnoreCount(int(args["ignorecount"]))
|
|
|
|
bp.SetCondition(self.hexdecode(args["condition"]))
|
|
|
|
bp.SetEnabled(bool(args["enabled"]))
|
|
|
|
if isinstance(bp, lldb.SBBreakpoint):
|
|
|
|
bp.SetOneShot(bool(args["oneshot"]))
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeBreakpoint(bp), args)
|
2013-05-16 17:37:41 +02:00
|
|
|
|
|
|
|
def removeBreakpoint(self, args):
|
2015-02-02 13:48:33 +01:00
|
|
|
lldbId = int(args['lldbid'])
|
|
|
|
if lldbId > qqWatchpointOffset:
|
|
|
|
res = self.target.DeleteWatchpoint(lldbId - qqWatchpointOffset)
|
|
|
|
res = self.target.BreakpointDelete(lldbId)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('success="%s"' % int(res), args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchModules(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
result = 'modules=['
|
2013-05-22 14:30:36 +02:00
|
|
|
for i in xrange(self.target.GetNumModules()):
|
|
|
|
module = self.target.GetModuleAtIndex(i)
|
2013-05-29 16:06:07 +02:00
|
|
|
result += '{file="%s"' % module.file.fullpath
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',name="%s"' % module.file.basename
|
2013-05-07 11:39:31 +02:00
|
|
|
result += ',addrsize="%s"' % module.addr_size
|
|
|
|
result += ',triple="%s"' % module.triple
|
|
|
|
#result += ',sections={'
|
2013-04-30 10:46:48 +02:00
|
|
|
#for section in module.sections:
|
|
|
|
# result += '[name="%s"' % section.name
|
|
|
|
# result += ',addr="%s"' % section.addr
|
2013-05-07 11:39:31 +02:00
|
|
|
# result += ',size="%s"],' % section.size
|
2013-04-30 10:46:48 +02:00
|
|
|
#result += '}'
|
|
|
|
result += '},'
|
|
|
|
result += ']'
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(result, args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchSymbols(self, args):
|
2013-05-07 12:34:10 +02:00
|
|
|
moduleName = args['module']
|
2013-05-07 11:39:31 +02:00
|
|
|
#file = lldb.SBFileSpec(moduleName)
|
|
|
|
#module = self.target.FindModule(file)
|
2013-05-22 14:30:36 +02:00
|
|
|
for i in xrange(self.target.GetNumModules()):
|
|
|
|
module = self.target.GetModuleAtIndex(i)
|
2013-05-29 16:24:17 +02:00
|
|
|
if module.file.fullpath == moduleName:
|
2013-05-07 11:39:31 +02:00
|
|
|
break
|
2015-09-09 16:34:09 +02:00
|
|
|
result = 'symbols={valid="%s"' % module.IsValid()
|
2013-05-07 11:39:31 +02:00
|
|
|
result += ',sections="%s"' % module.GetNumSections()
|
|
|
|
result += ',symbols=['
|
|
|
|
for symbol in module.symbols:
|
|
|
|
startAddress = symbol.GetStartAddress().GetLoadAddress(self.target)
|
|
|
|
endAddress = symbol.GetEndAddress().GetLoadAddress(self.target)
|
|
|
|
result += '{type="%s"' % symbol.GetType()
|
|
|
|
result += ',name="%s"' % symbol.GetName()
|
|
|
|
result += ',address="0x%x"' % startAddress
|
|
|
|
result += ',demangled="%s"' % symbol.GetMangledName()
|
|
|
|
result += ',size="%s"' % (endAddress - startAddress)
|
|
|
|
result += '},'
|
|
|
|
result += ']}'
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(result, args)
|
2013-05-07 11:39:31 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def executeNext(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
self.currentThread().StepOver()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def executeNextI(self, args):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def executeStep(self, args):
|
2013-04-30 10:46:48 +02:00
|
|
|
self.currentThread().StepInto()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def shutdownInferior(self, args):
|
2013-05-29 15:38:49 +02:00
|
|
|
self.isShuttingDown_ = True
|
2014-06-02 16:45:12 +02:00
|
|
|
if self.process is None:
|
|
|
|
self.reportState("inferiorshutdownok")
|
|
|
|
else:
|
|
|
|
state = self.process.GetState()
|
|
|
|
if state == lldb.eStateStopped:
|
|
|
|
self.process.Kill()
|
|
|
|
self.reportState("inferiorshutdownok")
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-05-29 15:38:49 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def quit(self, args):
|
2014-03-19 12:12:24 +01:00
|
|
|
self.reportState("engineshutdownok")
|
2013-05-29 15:38:49 +02:00
|
|
|
self.process.Kill()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def executeStepI(self, args):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-03-05 10:41:16 +01:00
|
|
|
def executeStepOut(self, args = {}):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepOut()
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-02-06 16:47:07 +01:00
|
|
|
def executeRunToLocation(self, args):
|
2015-03-05 10:41:16 +01:00
|
|
|
self.reportToken(args)
|
2014-02-06 16:47:07 +01:00
|
|
|
addr = args.get('address', 0)
|
|
|
|
if addr:
|
2015-08-10 13:25:30 +02:00
|
|
|
# Does not seem to hit anything on Linux:
|
|
|
|
# self.currentThread().RunToAddress(addr)
|
|
|
|
bp = self.target.BreakpointCreateByAddress(addr)
|
|
|
|
if bp.GetNumLocations() == 0:
|
|
|
|
self.target.BreakpointDelete(bp.GetID())
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeStatus("No target location found.")
|
|
|
|
+ self.describeLocation(frame), args)
|
2015-08-10 13:25:30 +02:00
|
|
|
return
|
|
|
|
bp.SetOneShot(True)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2015-08-10 13:25:30 +02:00
|
|
|
self.process.Continue()
|
2014-02-06 16:47:07 +01:00
|
|
|
else:
|
|
|
|
frame = self.currentFrame()
|
|
|
|
file = args['file']
|
|
|
|
line = int(args['line'])
|
|
|
|
error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeError(error), args)
|
|
|
|
self.reportState("running")
|
|
|
|
self.reportState("stopped")
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-02-06 15:40:23 +01:00
|
|
|
def executeJumpToLocation(self, args):
|
2015-03-05 10:41:16 +01:00
|
|
|
self.reportToken(args)
|
2014-02-05 17:03:51 +01:00
|
|
|
frame = self.currentFrame()
|
|
|
|
if not frame:
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.describeStatus("No frame available."), args)
|
2014-02-05 17:03:51 +01:00
|
|
|
return
|
2014-02-06 15:40:23 +01:00
|
|
|
addr = args.get('address', 0)
|
|
|
|
if addr:
|
|
|
|
bp = self.target.BreakpointCreateByAddress(addr)
|
|
|
|
else:
|
|
|
|
bp = self.target.BreakpointCreateByLocation(
|
|
|
|
str(args['file']), int(args['line']))
|
2014-02-05 17:03:51 +01:00
|
|
|
if bp.GetNumLocations() == 0:
|
|
|
|
self.target.BreakpointDelete(bp.GetID())
|
2015-09-09 16:34:09 +02:00
|
|
|
status = "No target location found."
|
2015-02-27 15:01:29 +01:00
|
|
|
else:
|
2015-09-09 16:34:09 +02:00
|
|
|
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)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
def breakList(self):
|
|
|
|
result = lldb.SBCommandReturnObject()
|
|
|
|
self.debugger.GetCommandInterpreter().HandleCommand("break list", result)
|
|
|
|
self.report('success="%d",output="%s",error="%s"'
|
|
|
|
% (result.Succeeded(), result.GetOutput(), result.GetError()))
|
|
|
|
|
2013-05-24 10:14:11 +02:00
|
|
|
def activateFrame(self, args):
|
2015-09-07 12:16:05 +02:00
|
|
|
self.reportToken(args)
|
2014-02-03 13:47:26 +01:00
|
|
|
thread = args['thread']
|
2013-05-24 10:14:11 +02:00
|
|
|
self.currentThread().SetSelectedFrame(args['index'])
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-29 16:24:17 +02:00
|
|
|
def selectThread(self, args):
|
2015-09-07 12:16:05 +02:00
|
|
|
self.reportToken(args)
|
2013-05-29 16:24:17 +02:00
|
|
|
self.process.SetSelectedThreadByID(args['id'])
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult('', args)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchFullBacktrace(self, _ = None):
|
2014-03-11 16:40:07 +01:00
|
|
|
command = "thread backtrace all"
|
|
|
|
result = lldb.SBCommandReturnObject()
|
|
|
|
self.debugger.GetCommandInterpreter().HandleCommand(command, result)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(self.hexencode(result.GetOutput()), {})
|
2014-03-11 16:40:07 +01:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def executeDebuggerCommand(self, args):
|
2016-08-02 14:50:54 +02:00
|
|
|
self.debuggerCommandInProgress = True
|
2015-09-07 12:16:05 +02:00
|
|
|
self.reportToken(args)
|
2013-04-30 10:46:48 +02:00
|
|
|
result = lldb.SBCommandReturnObject()
|
2013-05-07 16:43:20 +02:00
|
|
|
command = args['command']
|
2013-04-30 10:46:48 +02:00
|
|
|
self.debugger.GetCommandInterpreter().HandleCommand(command, result)
|
|
|
|
success = result.Succeeded()
|
2013-05-29 15:38:49 +02:00
|
|
|
output = result.GetOutput()
|
|
|
|
error = str(result.GetError())
|
2013-04-30 10:46:48 +02:00
|
|
|
self.report('success="%d",output="%s",error="%s"' % (success, output, error))
|
2016-08-02 14:50:54 +02:00
|
|
|
self.debuggerCommandInProgress = False
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2015-09-09 16:34:09 +02:00
|
|
|
def fetchDisassembler(self, args):
|
2014-03-06 12:04:47 +01:00
|
|
|
functionName = args.get('function', '')
|
|
|
|
flavor = args.get('flavor', '')
|
|
|
|
function = None
|
|
|
|
if len(functionName):
|
|
|
|
functions = self.target.FindFunctions(functionName).functions
|
|
|
|
if len(functions):
|
|
|
|
function = functions[0]
|
|
|
|
if function:
|
|
|
|
base = function.GetStartAddress().GetLoadAddress(self.target)
|
|
|
|
instructions = function.GetInstructions(self.target)
|
|
|
|
else:
|
|
|
|
base = args.get('address', 0)
|
2015-02-04 17:21:55 +01:00
|
|
|
if int(base) == 0xffffffffffffffff:
|
|
|
|
warn("INVALID DISASSEMBLER BASE")
|
|
|
|
return
|
2014-03-06 12:04:47 +01:00
|
|
|
addr = lldb.SBAddress(base, self.target)
|
|
|
|
instructions = self.target.ReadInstructions(addr, 100)
|
|
|
|
|
2015-08-28 14:35:25 +02:00
|
|
|
currentFile = None
|
|
|
|
currentLine = None
|
|
|
|
hunks = dict()
|
|
|
|
sources = dict()
|
2015-09-09 16:34:09 +02:00
|
|
|
result = 'lines=['
|
2014-03-06 12:04:47 +01:00
|
|
|
for insn in instructions:
|
2013-05-03 17:18:07 +02:00
|
|
|
comment = insn.GetComment(self.target)
|
2015-08-28 14:35:25 +02:00
|
|
|
addr = insn.GetAddress()
|
|
|
|
loadAddr = addr.GetLoadAddress(self.target)
|
|
|
|
lineEntry = addr.GetLineEntry()
|
|
|
|
if lineEntry:
|
|
|
|
lineNumber = lineEntry.GetLine()
|
|
|
|
fileName = str(lineEntry.GetFileSpec())
|
|
|
|
if lineNumber != currentLine or fileName != currentFile:
|
|
|
|
currentLine = lineNumber
|
|
|
|
currentFile = fileName
|
|
|
|
key = "%s:%s" % (fileName, lineNumber)
|
|
|
|
hunk = hunks.get(key, 0) + 1
|
|
|
|
hunks[key] = hunk
|
|
|
|
source = sources.get(fileName, None)
|
|
|
|
if source is None:
|
2016-01-19 14:11:04 +01:00
|
|
|
try:
|
|
|
|
with open(fileName, 'r') as f:
|
|
|
|
source = f.read().splitlines()
|
|
|
|
sources[fileName] = source
|
|
|
|
except IOError as error:
|
|
|
|
# With lldb-3.8 files like /data/dev/creator-3.6/tests/
|
|
|
|
# auto/debugger/qt_tst_dumpers_StdVector_bfNWZa/main.cpp
|
|
|
|
# with non-existent directories appear.
|
|
|
|
warn("FILE: %s ERROR: %s" % (fileName, error))
|
|
|
|
source = ""
|
2015-08-28 14:35:25 +02:00
|
|
|
result += '{line="%s"' % lineNumber
|
|
|
|
result += ',file="%s"' % fileName
|
|
|
|
if 0 < lineNumber and lineNumber <= len(source):
|
2015-08-28 15:43:19 +02:00
|
|
|
result += ',data="%s"' % source[lineNumber - 1]
|
2015-08-28 14:35:25 +02:00
|
|
|
result += ',hunk="%s"}' % hunk
|
|
|
|
result += '{address="%s"' % loadAddr
|
2015-08-28 15:43:19 +02:00
|
|
|
result += ',data="%s %s"' % (insn.GetMnemonic(self.target),
|
2013-05-13 16:04:00 +02:00
|
|
|
insn.GetOperands(self.target))
|
2015-08-28 15:43:19 +02:00
|
|
|
result += ',function="%s"' % functionName
|
|
|
|
rawData = insn.GetData(lldb.target).uint8s
|
|
|
|
result += ',rawdata="%s"' % ' '.join(["%02x" % x for x in rawData])
|
2013-05-03 17:18:07 +02:00
|
|
|
if comment:
|
2016-04-13 19:37:31 +02:00
|
|
|
result += ',comment="%s"' % self.hexencode(comment)
|
2015-08-28 14:35:25 +02:00
|
|
|
result += ',offset="%s"}' % (loadAddr - base)
|
2015-09-09 16:34:09 +02:00
|
|
|
self.reportResult(result + ']', args)
|
2013-05-03 17:18:07 +02:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def fetchMemory(self, args):
|
2013-05-07 12:34:10 +02:00
|
|
|
address = args['address']
|
|
|
|
length = args['length']
|
2013-05-07 08:46:51 +02:00
|
|
|
error = lldb.SBError()
|
|
|
|
contents = self.process.ReadMemory(address, length, error)
|
2015-09-09 16:34:09 +02:00
|
|
|
result = 'address="%s",' % address
|
2013-05-07 08:46:51 +02:00
|
|
|
result += self.describeError(error)
|
2015-09-09 16:34:09 +02:00
|
|
|
result += ',contents="%s"' % self.hexencode(contents)
|
|
|
|
self.reportResult(result, args)
|
2013-05-07 08:46:51 +02:00
|
|
|
|
2013-06-11 18:55:09 +02:00
|
|
|
def findValueByExpression(self, exp):
|
|
|
|
# FIXME: Top level-only for now.
|
|
|
|
frame = self.currentFrame()
|
|
|
|
value = frame.FindVariable(exp)
|
|
|
|
return value
|
|
|
|
|
2013-05-30 15:35:52 +02:00
|
|
|
def assignValue(self, args):
|
2015-09-07 12:16:05 +02:00
|
|
|
self.reportToken(args)
|
2013-06-11 18:55:09 +02:00
|
|
|
error = lldb.SBError()
|
2014-01-23 15:30:51 +01:00
|
|
|
exp = self.hexdecode(args['exp'])
|
|
|
|
value = self.hexdecode(args['value'])
|
2013-06-11 18:55:09 +02:00
|
|
|
lhs = self.findValueByExpression(exp)
|
|
|
|
lhs.SetValueFromCString(value, error)
|
2015-10-09 15:00:20 +02:00
|
|
|
self.reportResult(self.describeError(error), args)
|
2013-05-30 15:35:52 +02:00
|
|
|
|
2015-02-04 16:27:46 +01:00
|
|
|
def createResolvePendingBreakpointsHookBreakpoint(self, args):
|
2015-10-09 15:00:20 +02:00
|
|
|
bp = self.target.BreakpointCreateByName("qt_qmlDebugConnectorOpen")
|
2015-02-04 13:29:42 +01:00
|
|
|
bp.SetOneShot(True)
|
2015-10-09 15:00:20 +02:00
|
|
|
self.interpreterBreakpointResolvers.append(
|
2015-10-14 13:26:22 +02:00
|
|
|
lambda: self.resolvePendingInterpreterBreakpoint(args))
|
2013-10-17 17:08:32 +02:00
|
|
|
|
2013-05-29 14:55:57 +02:00
|
|
|
|
2013-06-04 10:44:20 +02:00
|
|
|
# Used in dumper auto test.
|
2015-01-23 17:54:00 +01:00
|
|
|
class Tester(Dumper):
|
2015-11-10 09:23:58 +01:00
|
|
|
def __init__(self, binary, args):
|
2015-01-23 17:54:00 +01:00
|
|
|
Dumper.__init__(self)
|
|
|
|
lldb.theDumper = self
|
2015-09-09 16:34:09 +02:00
|
|
|
self.loadDumpers({'token': 1})
|
2015-01-23 17:54:00 +01:00
|
|
|
error = lldb.SBError()
|
2015-01-30 12:36:04 +01:00
|
|
|
self.target = self.debugger.CreateTarget(binary, None, None, True, error)
|
2013-06-04 10:44:20 +02:00
|
|
|
|
2015-01-23 17:54:00 +01:00
|
|
|
if error.GetType():
|
|
|
|
warn("ERROR: %s" % error)
|
|
|
|
return
|
|
|
|
|
2015-11-10 09:23:58 +01:00
|
|
|
s = threading.Thread(target=self.testLoop, args=(args,))
|
2015-01-23 17:54:00 +01:00
|
|
|
s.start()
|
2015-01-30 12:36:04 +01:00
|
|
|
s.join(30)
|
2013-06-04 10:44:20 +02:00
|
|
|
|
2015-11-10 09:23:58 +01:00
|
|
|
def testLoop(self, args):
|
2015-01-23 17:54:00 +01:00
|
|
|
# Disable intermediate reporting.
|
|
|
|
savedReport = self.report
|
|
|
|
self.report = lambda stuff: 0
|
2013-06-04 10:44:20 +02:00
|
|
|
|
2015-01-23 17:54:00 +01:00
|
|
|
error = lldb.SBError()
|
|
|
|
launchInfo = lldb.SBLaunchInfo([])
|
|
|
|
launchInfo.SetWorkingDirectory(os.getcwd())
|
|
|
|
environmentList = [key + "=" + value for key,value in os.environ.items()]
|
|
|
|
launchInfo.SetEnvironmentEntries(environmentList, False)
|
|
|
|
|
|
|
|
self.process = self.target.Launch(launchInfo, error)
|
|
|
|
if error.GetType():
|
|
|
|
warn("ERROR: %s" % error)
|
|
|
|
|
|
|
|
event = lldb.SBEvent()
|
|
|
|
listener = self.debugger.GetListener()
|
|
|
|
while True:
|
|
|
|
state = self.process.GetState()
|
|
|
|
if listener.WaitForEvent(100, event):
|
|
|
|
#warn("EVENT: %s" % event)
|
|
|
|
state = lldb.SBProcess.GetStateFromEvent(event)
|
2015-01-27 10:25:21 +01:00
|
|
|
if state == lldb.eStateExited: # 10
|
2015-01-23 17:54:00 +01:00
|
|
|
break
|
2015-01-27 10:25:21 +01:00
|
|
|
if state == lldb.eStateStopped: # 5
|
2015-04-14 09:06:28 +02:00
|
|
|
stoppedThread = None
|
|
|
|
for i in xrange(0, self.process.GetNumThreads()):
|
|
|
|
thread = self.process.GetThreadAtIndex(i)
|
|
|
|
reason = thread.GetStopReason()
|
|
|
|
#warn("THREAD: %s REASON: %s" % (thread, reason))
|
|
|
|
if (reason == lldb.eStopReasonBreakpoint or
|
|
|
|
reason == lldb.eStopReasonException or
|
|
|
|
reason == lldb.eStopReasonSignal):
|
|
|
|
stoppedThread = thread
|
|
|
|
|
|
|
|
if stoppedThread:
|
|
|
|
# This seems highly fragile and depending on the "No-ops" in the
|
|
|
|
# event handling above.
|
2015-01-27 10:25:21 +01:00
|
|
|
frame = stoppedThread.GetFrameAtIndex(0)
|
2015-04-14 09:06:28 +02:00
|
|
|
line = frame.line_entry.line
|
|
|
|
if line != 0:
|
|
|
|
self.report = savedReport
|
|
|
|
self.process.SetSelectedThread(stoppedThread)
|
2015-11-10 09:23:58 +01:00
|
|
|
self.fetchVariables(args)
|
2015-09-09 16:34:09 +02:00
|
|
|
#self.describeLocation(frame)
|
2015-04-14 09:06:28 +02:00
|
|
|
self.report("@NS@%s@" % self.qtNamespace())
|
|
|
|
#self.report("ENV=%s" % os.environ.items())
|
|
|
|
#self.report("DUMPER=%s" % self.qqDumpers)
|
|
|
|
break
|
|
|
|
|
2015-01-23 17:54:00 +01:00
|
|
|
else:
|
|
|
|
warn('TIMEOUT')
|
2015-04-14 09:06:28 +02:00
|
|
|
warn("Cannot determined stopped thread")
|
2014-01-17 16:13:03 +01:00
|
|
|
|
2015-01-23 17:54:00 +01:00
|
|
|
lldb.SBDebugger.Destroy(self.debugger)
|