2013-09-11 21:35:39 +02:00
|
|
|
############################################################################
|
|
|
|
#
|
2014-01-07 13:27:11 +01:00
|
|
|
# Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2013-09-11 21:35:39 +02:00
|
|
|
# Contact: http://www.qt-project.org/legal
|
|
|
|
#
|
|
|
|
# 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
|
|
|
|
# a written agreement between you and Digia. For licensing terms and
|
|
|
|
# conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
# use the contact form at http://qt.digia.com/contact-us.
|
|
|
|
#
|
|
|
|
# GNU Lesser General Public License Usage
|
|
|
|
# Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
# General Public License version 2.1 as published by the Free Software
|
|
|
|
# Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
# packaging of this file. Please review the following information to
|
|
|
|
# ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
# will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
#
|
|
|
|
# In addition, as a special exception, Digia gives you certain additional
|
|
|
|
# rights. These rights are described in the Digia Qt LGPL Exception
|
|
|
|
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
#
|
|
|
|
#############################################################################
|
2013-04-11 17:06:17 +02:00
|
|
|
|
2013-05-16 17:37:41 +02:00
|
|
|
import atexit
|
2013-04-11 17:06:17 +02:00
|
|
|
import inspect
|
2013-10-17 17:08:32 +02:00
|
|
|
import json
|
2013-04-11 17:06:17 +02:00
|
|
|
import os
|
2013-10-21 12:02:57 +02:00
|
|
|
import re
|
2013-05-13 16:04:00 +02:00
|
|
|
import select
|
|
|
|
import sys
|
2013-05-16 15:09:24 +02:00
|
|
|
import subprocess
|
2013-10-21 12:02:57 +02:00
|
|
|
import threading
|
2013-05-16 15:09:24 +02:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
|
|
|
sys.path.insert(1, currentDir)
|
|
|
|
|
|
|
|
from dumper import *
|
|
|
|
from qttypes import *
|
2013-10-10 16:40:56 +02:00
|
|
|
from stdtypes import *
|
|
|
|
from misctypes import *
|
|
|
|
from boosttypes import *
|
2013-10-16 18:00:11 +02:00
|
|
|
from creatortypes import *
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2013-10-31 10:06:14 +01:00
|
|
|
lldbCmd = 'lldb'
|
|
|
|
if len(sys.argv) > 1:
|
|
|
|
lldbCmd = sys.argv[1]
|
2013-11-01 10:32:37 +01:00
|
|
|
|
2013-10-31 10:06:14 +01:00
|
|
|
proc = subprocess.Popen(args=[lldbCmd, '-P'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
2013-06-04 17:40:27 +02:00
|
|
|
(path, error) = proc.communicate()
|
2013-11-01 10:32:37 +01:00
|
|
|
|
2013-06-04 17:40:27 +02:00
|
|
|
if error.startswith('lldb: invalid option -- P'):
|
2013-11-01 10:32:37 +01:00
|
|
|
sys.stdout.write('msg=\'Could not run "%s -P". Trying to find lldb.so from Xcode.\'@\n' % lldbCmd)
|
2013-06-04 17:40:27 +02:00
|
|
|
proc = subprocess.Popen(args=['xcode-select', '--print-path'],
|
|
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
(path, error) = proc.communicate()
|
|
|
|
if len(error):
|
|
|
|
path = '/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
|
2013-11-01 10:32:37 +01:00
|
|
|
sys.stdout.write('msg=\'Could not run "xcode-select --print-path"@\n')
|
|
|
|
sys.stdout.write('msg=\'Using hardcoded fallback at %s\'@\n' % path)
|
2013-06-04 17:40:27 +02:00
|
|
|
else:
|
|
|
|
path = path.strip() + '/../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
|
2013-11-01 10:32:37 +01:00
|
|
|
sys.stdout.write('msg=\'Using fallback at %s\'@\n' % path)
|
2013-05-02 14:57:06 +02:00
|
|
|
|
2013-06-04 17:40:27 +02:00
|
|
|
sys.path.insert(1, path.strip())
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
import lldb
|
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
|
|
|
|
2014-01-24 17:02:23 +01:00
|
|
|
lldb.theDumper = None
|
2013-04-11 17:06:17 +02:00
|
|
|
|
|
|
|
def warn(message):
|
2013-09-11 21:35:39 +02:00
|
|
|
print('\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'"))
|
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
|
|
|
|
|
|
|
def fileName(file):
|
|
|
|
return str(file) if file.IsValid() else ''
|
|
|
|
|
2013-04-11 17:06:17 +02:00
|
|
|
|
2013-04-10 13:55:15 +02:00
|
|
|
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
|
|
|
|
UnknownType = 0
|
|
|
|
BreakpointByFileAndLine = 1
|
|
|
|
BreakpointByFunction = 2
|
|
|
|
BreakpointByAddress = 3
|
|
|
|
BreakpointAtThrow = 4
|
|
|
|
BreakpointAtCatch = 5
|
|
|
|
BreakpointAtMain = 6
|
|
|
|
BreakpointAtFork = 7
|
|
|
|
BreakpointAtExec = 8
|
2013-06-14 15:15:09 +02:00
|
|
|
BreakpointAtSysCall = 9
|
|
|
|
WatchpointAtAddress = 10
|
|
|
|
WatchpointAtExpression = 11
|
|
|
|
BreakpointOnQmlSignalEmit = 12
|
|
|
|
BreakpointAtJavaScriptThrow = 13
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
# See db.StateType
|
|
|
|
stateNames = ["invalid", "unloaded", "connected", "attaching", "launching", "stopped",
|
|
|
|
"running", "stepping", "crashed", "detached", "exited", "suspended" ]
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def loggingCallback(args):
|
|
|
|
s = args.strip()
|
|
|
|
s = s.replace('"', "'")
|
2013-11-01 10:32:37 +01:00
|
|
|
sys.stdout.write('log="%s"@\n' % s)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def check(exp):
|
|
|
|
if not exp:
|
|
|
|
raise RuntimeError("Check failed")
|
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
Value = lldb.SBValue
|
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def impl_SBValue__add__(self, offset):
|
|
|
|
if self.GetType().IsPointerType():
|
2013-05-17 17:14:45 +02:00
|
|
|
if isinstance(offset, int) or isinstance(offset, long):
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
offset = offset.GetValueAsSigned()
|
2013-05-23 16:58:59 +02:00
|
|
|
itemsize = self.GetType().GetPointeeType().GetByteSize()
|
2013-05-17 17:14:45 +02:00
|
|
|
address = self.GetValueAsUnsigned() + offset * itemsize
|
2013-05-17 13:53:49 +02:00
|
|
|
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
|
2013-11-07 14:41:31 +01:00
|
|
|
return self.CreateValueFromAddress(None, address,
|
|
|
|
self.GetType().GetPointeeType()).AddressOf()
|
2013-07-02 15:43:29 +02:00
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
|
2013-05-08 16:20:03 +02:00
|
|
|
return NotImplemented
|
|
|
|
|
2013-05-13 16:04:00 +02:00
|
|
|
def impl_SBValue__sub__(self, other):
|
2013-05-15 15:30:42 +02:00
|
|
|
if self.GetType().IsPointerType():
|
2013-05-17 17:14:45 +02:00
|
|
|
if isinstance(other, int) or isinstance(other, long):
|
|
|
|
address = self.GetValueAsUnsigned() - offset.GetValueAsSigned()
|
|
|
|
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
|
|
|
|
return self.CreateValueFromAddress(None, address, self.GetType())
|
2013-05-15 15:30:42 +02:00
|
|
|
if other.GetType().IsPointerType():
|
2013-05-23 16:58:59 +02:00
|
|
|
itemsize = self.GetType().GetPointeeType().GetByteSize()
|
|
|
|
return (self.GetValueAsUnsigned() - other.GetValueAsUnsigned()) / itemsize
|
2013-05-15 15:30:42 +02:00
|
|
|
raise RuntimeError("SBValue.__sub__ not implemented: %s" % self.GetType())
|
2013-05-13 16:04:00 +02:00
|
|
|
return NotImplemented
|
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
def impl_SBValue__le__(self, other):
|
|
|
|
if self.GetType().IsPointerType() and other.GetType().IsPointerType():
|
|
|
|
return int(self) <= int(other)
|
|
|
|
raise RuntimeError("SBValue.__le__ not implemented")
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def impl_SBValue__int__(self):
|
2013-05-17 17:14:45 +02:00
|
|
|
return self.GetValueAsSigned()
|
2013-07-04 10:17:51 +02:00
|
|
|
|
|
|
|
def impl_SBValue__float__(self):
|
|
|
|
error = lldb.SBError()
|
|
|
|
if self.GetType().GetByteSize() == 4:
|
|
|
|
result = self.GetData().GetFloat(error, 0)
|
|
|
|
else:
|
|
|
|
result = self.GetData().GetDouble(error, 0)
|
|
|
|
if error.Success():
|
|
|
|
return result
|
|
|
|
return NotImplemented
|
2013-05-13 16:39:51 +02:00
|
|
|
|
2013-05-17 13:53:49 +02:00
|
|
|
def impl_SBValue__long__(self):
|
|
|
|
return int(self.GetValue(), 0)
|
|
|
|
|
2013-06-10 14:50:22 +02:00
|
|
|
def impl_SBValue__getitem__(value, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
type = value.GetType()
|
|
|
|
if type.IsPointerType():
|
|
|
|
innertype = value.Dereference().GetType()
|
|
|
|
address = value.GetValueAsUnsigned() + index * innertype.GetByteSize()
|
|
|
|
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
|
|
|
|
return value.CreateValueFromAddress(None, address, innertype)
|
|
|
|
return value.GetChildAtIndex(index)
|
2014-01-24 17:02:23 +01:00
|
|
|
return value.GetChildMemberWithName(index)
|
2013-05-13 16:39:51 +02:00
|
|
|
|
2014-01-10 12:42:12 +01:00
|
|
|
def impl_SBValue__deref(value):
|
|
|
|
result = value.Dereference()
|
|
|
|
if result.IsValid():
|
|
|
|
return result
|
2014-01-30 18:13:45 +01:00
|
|
|
exp = "*(class %s*)0x%x" % (value.GetType().GetPointeeType(), value.GetValueAsUnsigned())
|
|
|
|
return value.CreateValueFromExpression(None, exp)
|
2014-01-10 12:42:12 +01:00
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
lldb.SBValue.__add__ = impl_SBValue__add__
|
2013-05-13 16:04:00 +02:00
|
|
|
lldb.SBValue.__sub__ = impl_SBValue__sub__
|
2013-05-13 16:39:51 +02:00
|
|
|
lldb.SBValue.__le__ = impl_SBValue__le__
|
2013-05-08 16:20:03 +02:00
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
|
|
|
|
lldb.SBValue.__int__ = impl_SBValue__int__
|
2013-07-04 10:17:51 +02:00
|
|
|
lldb.SBValue.__float__ = impl_SBValue__float__
|
2013-05-08 16:20:03 +02:00
|
|
|
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)
|
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
lldb.SBValue.code = lambda self: self.GetTypeClass()
|
2013-05-08 16:20:03 +02:00
|
|
|
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
|
2014-01-10 12:42:12 +01:00
|
|
|
lldb.SBValue.dereference = impl_SBValue__deref
|
2014-01-20 15:57:09 +01:00
|
|
|
lldb.SBValue.address = property(lambda self: self.GetLoadAddress())
|
2013-05-08 16:20:03 +02:00
|
|
|
|
|
|
|
lldb.SBType.pointer = lambda self: self.GetPointerType()
|
2013-11-06 17:57:12 +01:00
|
|
|
lldb.SBType.target = lambda self: self.GetPointeeType()
|
2013-05-13 16:39:51 +02:00
|
|
|
lldb.SBType.code = lambda self: self.GetTypeClass()
|
2013-05-08 16:20:03 +02:00
|
|
|
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
|
2013-06-24 16:49:46 +02:00
|
|
|
|
|
|
|
|
2013-07-05 09:22:55 +02:00
|
|
|
lldb.SBType.unqualified = \
|
|
|
|
lambda self: self.GetUnqualifiedType() if hasattr(self, 'GetUnqualifiedType') else self
|
2013-06-24 16:49:46 +02:00
|
|
|
lldb.SBType.strip_typedefs = \
|
|
|
|
lambda self: self.GetCanonicalType() if hasattr(self, 'GetCanonicalType') else self
|
2013-05-08 16:20:03 +02:00
|
|
|
|
2013-06-06 09:09:19 +02:00
|
|
|
lldb.SBType.__orig__str__ = lldb.SBType.__str__
|
|
|
|
lldb.SBType.__str__ = lldb.SBType.GetName
|
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def simpleEncoding(typeobj):
|
|
|
|
code = typeobj.GetTypeClass()
|
|
|
|
size = typeobj.sizeof
|
|
|
|
if code == lldb.eTypeClassBuiltin:
|
2013-06-05 11:26:46 +02:00
|
|
|
name = str(typeobj)
|
|
|
|
if name == "float":
|
|
|
|
return Hex2EncodedFloat4
|
|
|
|
if name == "double":
|
|
|
|
return Hex2EncodedFloat8
|
|
|
|
if name.find("unsigned") >= 0:
|
2013-05-08 16:20:03 +02:00
|
|
|
if size == 1:
|
|
|
|
return Hex2EncodedUInt1
|
|
|
|
if size == 2:
|
|
|
|
return Hex2EncodedUInt2
|
|
|
|
if size == 4:
|
|
|
|
return Hex2EncodedUInt4
|
|
|
|
if size == 8:
|
|
|
|
return Hex2EncodedUInt8
|
|
|
|
else:
|
|
|
|
if size == 1:
|
|
|
|
return Hex2EncodedInt1
|
|
|
|
if size == 2:
|
|
|
|
return Hex2EncodedInt2
|
|
|
|
if size == 4:
|
|
|
|
return Hex2EncodedInt4
|
|
|
|
if size == 8:
|
|
|
|
return Hex2EncodedInt8
|
|
|
|
return None
|
2013-05-07 16:43:20 +02:00
|
|
|
|
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)
|
|
|
|
|
2014-01-24 17:02:23 +01:00
|
|
|
lldb.theDumper = self
|
|
|
|
|
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)
|
2013-04-30 10:46:48 +02:00
|
|
|
#Same as: self.debugger.HandleCommand("log enable lldb dyld step")
|
|
|
|
#self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state", "thread", "events",
|
|
|
|
# "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
|
|
|
|
# interactonn in 3000
|
|
|
|
# if not hasattr(lldb.SBType, 'GetCanonicalType'): # "Test" for 179.5
|
|
|
|
self.debugger.HandleCommand('type category delete gnu-libstdc++')
|
|
|
|
self.debugger.HandleCommand('type category delete libcxx')
|
|
|
|
#for i in range(self.debugger.GetNumCategories()):
|
|
|
|
# self.debugger.GetCategoryAtIndex(i).SetEnabled(False)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
self.isLldb = True
|
2014-01-31 13:52:47 +01:00
|
|
|
self.isGoodLldb = hasattr(lldb.SBValue, "SetPreferDynamicValue")
|
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
|
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 = {}
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
self.currentIName = None
|
|
|
|
self.currentValuePriority = -100
|
|
|
|
self.currentValueEncoding = None
|
|
|
|
self.currentType = ""
|
|
|
|
self.currentTypePriority = -100
|
2013-05-13 16:04:00 +02:00
|
|
|
self.currentValue = None
|
2013-05-08 16:20:03 +02:00
|
|
|
self.currentNumChild = None
|
|
|
|
self.currentMaxNumChild = None
|
|
|
|
self.currentPrintsAddress = None
|
|
|
|
self.currentChildType = None
|
|
|
|
self.currentChildNumChild = None
|
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
|
|
|
|
|
2013-05-17 13:53:49 +02:00
|
|
|
self.charType_ = None
|
|
|
|
self.intType_ = None
|
2013-10-23 11:42:48 +02:00
|
|
|
self.int64Type_ = None
|
2013-05-17 13:53:49 +02:00
|
|
|
self.sizetType_ = None
|
|
|
|
self.charPtrType_ = None
|
2013-07-02 15:43:29 +02:00
|
|
|
self.voidPtrType_ = None
|
2013-05-29 15:38:49 +02:00
|
|
|
self.isShuttingDown_ = False
|
2013-06-24 17:40:00 +02:00
|
|
|
self.isInterrupting_ = False
|
2013-05-30 15:35:52 +02:00
|
|
|
self.dummyValue = None
|
2014-01-16 14:23:53 +01:00
|
|
|
self.types_ = {}
|
2013-05-17 13:53:49 +02:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def enterSubItem(self, item):
|
|
|
|
if isinstance(item.name, lldb.SBValue):
|
|
|
|
# Avoid $$__synth__ suffix on Mac.
|
|
|
|
value = item.name
|
2014-01-31 13:52:47 +01:00
|
|
|
if self.isGoodLldb:
|
|
|
|
value.SetPreferSyntheticValue(False)
|
2013-09-11 21:35:39 +02:00
|
|
|
item.name = value.GetName()
|
|
|
|
if item.name is None:
|
|
|
|
self.anonNumber += 1
|
|
|
|
item.name = "#%d" % self.anonNumber
|
2013-12-17 11:03:16 +01:00
|
|
|
if not item.iname:
|
|
|
|
item.iname = "%s.%s" % (self.currentIName, item.name)
|
2013-09-11 21:35:39 +02:00
|
|
|
self.put('{')
|
|
|
|
#if not item.name is None:
|
|
|
|
if isinstance(item.name, str):
|
|
|
|
if item.name == '**&':
|
|
|
|
item.name = '*'
|
|
|
|
self.put('name="%s",' % item.name)
|
|
|
|
item.savedIName = self.currentIName
|
|
|
|
item.savedValue = self.currentValue
|
|
|
|
item.savedValuePriority = self.currentValuePriority
|
|
|
|
item.savedValueEncoding = self.currentValueEncoding
|
|
|
|
item.savedType = self.currentType
|
|
|
|
item.savedTypePriority = self.currentTypePriority
|
|
|
|
self.currentIName = item.iname
|
|
|
|
self.currentValuePriority = -100
|
|
|
|
self.currentValueEncoding = None
|
|
|
|
self.currentType = ""
|
|
|
|
self.currentTypePriority = -100
|
|
|
|
|
|
|
|
def exitSubItem(self, item, exType, exValue, exTraceBack):
|
|
|
|
if not exType is None:
|
|
|
|
if self.passExceptions:
|
|
|
|
showException("SUBITEM", exType, exValue, exTraceBack)
|
|
|
|
self.putNumChild(0)
|
|
|
|
self.putValue("<not accessible>")
|
|
|
|
try:
|
|
|
|
typeName = self.currentType
|
|
|
|
if len(typeName) > 0 and typeName != self.currentChildType:
|
|
|
|
self.put('type="%s",' % typeName) # str(type.unqualified()) ?
|
|
|
|
if self.currentValue is None:
|
|
|
|
self.put('value="<not accessible>",numchild="0",')
|
|
|
|
else:
|
|
|
|
if not self.currentValueEncoding is None:
|
2014-01-10 20:01:35 +01:00
|
|
|
self.put('valueencoded="%s",' % self.currentValueEncoding)
|
2013-09-11 21:35:39 +02:00
|
|
|
self.put('value="%s",' % self.currentValue)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
self.put('},')
|
|
|
|
self.currentIName = item.savedIName
|
|
|
|
self.currentValue = item.savedValue
|
|
|
|
self.currentValuePriority = item.savedValuePriority
|
|
|
|
self.currentValueEncoding = item.savedValueEncoding
|
|
|
|
self.currentType = item.savedType
|
|
|
|
self.currentTypePriority = item.savedTypePriority
|
|
|
|
return True
|
|
|
|
|
|
|
|
def isSimpleType(self, typeobj):
|
|
|
|
typeClass = typeobj.GetTypeClass()
|
|
|
|
return typeClass == lldb.eTypeClassBuiltin
|
|
|
|
|
2014-01-20 15:03:27 +01:00
|
|
|
def childWithName(self, value, name):
|
|
|
|
child = value.GetChildMemberWithName(name)
|
|
|
|
return child if child.IsValid() else None
|
2014-01-15 17:38:23 +01:00
|
|
|
|
2014-01-31 16:56:32 +01:00
|
|
|
def simpleValue(self, value):
|
|
|
|
return str(value.value)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def childAt(self, value, index):
|
|
|
|
return value.GetChildAtIndex(index)
|
|
|
|
|
|
|
|
def fieldAt(self, type, index):
|
|
|
|
return type.GetFieldAtIndex(index)
|
|
|
|
|
|
|
|
def pointerValue(self, value):
|
|
|
|
return value.GetValueAsUnsigned()
|
|
|
|
|
2014-01-10 20:01:35 +01:00
|
|
|
def enumExpression(self, enumType, enumValue):
|
|
|
|
ns = self.qtNamespace()
|
|
|
|
return ns + "Qt::" + enumType + "(" \
|
|
|
|
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def call2(self, value, func, args):
|
|
|
|
# args is a tuple.
|
|
|
|
arg = ','.join(args)
|
|
|
|
#warn("CALL: %s -> %s(%s)" % (value, func, arg))
|
|
|
|
type = value.type.name
|
|
|
|
exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
|
|
|
#warn("CALL: %s" % exp)
|
2014-01-24 17:02:23 +01:00
|
|
|
result = value.CreateValueFromExpression('', exp)
|
2013-09-11 21:35:39 +02:00
|
|
|
#warn(" -> %s" % result)
|
|
|
|
return result
|
|
|
|
|
2014-01-22 16:25:39 +01:00
|
|
|
def makeValue(self, type, *args):
|
|
|
|
thread = self.currentThread()
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
inner = ','.join(args)
|
|
|
|
value = frame.EvaluateExpression(type + '{' + inner + '}')
|
|
|
|
#warn(" TYPE: %s" % value.type)
|
|
|
|
#warn(" ADDR: 0x%x" % value.address)
|
|
|
|
#warn(" VALUE: %s" % value)
|
|
|
|
return value
|
|
|
|
|
2013-10-23 12:51:11 +02:00
|
|
|
def parseAndEvaluate(self, expr):
|
|
|
|
thread = self.currentThread()
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
return frame.EvaluateExpression(expr)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def call(self, value, func, *args):
|
|
|
|
return self.call2(value, func, args)
|
|
|
|
|
|
|
|
def checkPointer(self, p, align = 1):
|
|
|
|
if not self.isNull(p):
|
|
|
|
p.Dereference()
|
|
|
|
|
|
|
|
def isNull(self, p):
|
|
|
|
return p.GetValueAsUnsigned() == 0
|
|
|
|
|
|
|
|
def directBaseClass(self, typeobj, index = 0):
|
|
|
|
return typeobj.GetDirectBaseClassAtIndex(index)
|
|
|
|
|
2013-05-23 15:47:28 +02:00
|
|
|
def templateArgument(self, typeobj, index):
|
2013-05-23 16:58:59 +02:00
|
|
|
type = typeobj.GetTemplateArgumentType(index)
|
2013-07-03 13:32:19 +02:00
|
|
|
if type.IsValid():
|
2013-05-23 16:58:59 +02:00
|
|
|
return type
|
|
|
|
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
|
|
|
return self.lookupType(inner)
|
|
|
|
|
|
|
|
def numericTemplateArgument(self, typeobj, index):
|
|
|
|
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
|
|
|
return int(inner)
|
2013-05-23 15:47:28 +02:00
|
|
|
|
2013-07-03 13:32:19 +02:00
|
|
|
def isReferenceType(self, typeobj):
|
|
|
|
return typeobj.IsReferenceType()
|
|
|
|
|
|
|
|
def isStructType(self, typeobj):
|
|
|
|
return typeobj.GetTypeClass() in (lldb.eTypeClassStruct, lldb.eTypeClassClass)
|
|
|
|
|
2014-01-09 13:25:17 +01:00
|
|
|
def qtVersionAndNamespace(self):
|
|
|
|
self.cachedQtNamespace = ""
|
2013-10-30 15:07:54 +01:00
|
|
|
self.cachedQtVersion = 0x0
|
2014-01-09 13:25:17 +01:00
|
|
|
|
2013-10-21 12:02:57 +02:00
|
|
|
coreExpression = re.compile(r"(lib)?Qt5?Core")
|
|
|
|
for n in range(0, self.target.GetNumModules()):
|
|
|
|
module = self.target.GetModuleAtIndex(n)
|
2014-01-09 16:23:17 +01:00
|
|
|
fileName = module.GetFileSpec().GetFilename()
|
|
|
|
if coreExpression.match(fileName):
|
2014-01-09 13:25:17 +01:00
|
|
|
# Extract version.
|
2013-10-21 12:02:57 +02:00
|
|
|
reverseVersion = module.GetVersion()
|
2014-01-09 16:23:17 +01:00
|
|
|
if len(reverseVersion):
|
|
|
|
# Mac, Clang?
|
|
|
|
reverseVersion.reverse()
|
|
|
|
shift = 0
|
|
|
|
for v in reverseVersion:
|
|
|
|
self.cachedQtVersion += v << shift
|
|
|
|
shift += 8
|
|
|
|
else:
|
|
|
|
# Linux, gcc?
|
|
|
|
if fileName.endswith(".5"):
|
|
|
|
self.cachedQtVersion = 0x50000
|
|
|
|
elif fileName.endswith(".4"):
|
|
|
|
self.cachedQtVersion = 0x40800
|
|
|
|
else:
|
|
|
|
warn("CANNOT GUESS QT VERSION")
|
|
|
|
|
2014-01-09 13:25:17 +01:00
|
|
|
|
|
|
|
# Look for some Qt symbol to extract namespace.
|
|
|
|
for symbol in module.symbols:
|
|
|
|
name = symbol.GetName()
|
|
|
|
pos = name.find("QString")
|
|
|
|
if pos >= 0:
|
|
|
|
name = name[:pos]
|
|
|
|
if name.endswith("::"):
|
|
|
|
self.cachedQtNamespace = re.sub('^.*[^\w]([\w]+)::$', '\\1', name) + '::'
|
|
|
|
break
|
2013-10-21 12:02:57 +02:00
|
|
|
break
|
2013-10-30 15:07:54 +01:00
|
|
|
|
|
|
|
# Memoize good results.
|
2014-01-09 13:25:17 +01:00
|
|
|
self.qtNamespace = lambda: self.cachedQtNamespace
|
2013-10-30 15:07:54 +01:00
|
|
|
self.qtVersion = lambda: self.cachedQtVersion
|
2014-01-09 13:25:17 +01:00
|
|
|
|
|
|
|
def qtNamespace(self):
|
|
|
|
self.qtVersionAndNamespace()
|
|
|
|
return self.cachedQtNamespace
|
|
|
|
|
|
|
|
def qtVersion(self):
|
2014-01-09 16:23:17 +01:00
|
|
|
self.qtVersionAndNamespace()
|
2013-10-30 15:07:54 +01:00
|
|
|
return self.cachedQtVersion
|
2013-06-27 10:42:32 +02:00
|
|
|
|
2013-07-02 15:43:29 +02:00
|
|
|
def intSize(self):
|
|
|
|
return 4
|
|
|
|
|
2013-05-17 13:53:49 +02:00
|
|
|
def intType(self):
|
|
|
|
if self.intType_ is None:
|
2013-05-22 14:30:36 +02:00
|
|
|
self.intType_ = self.target.FindFirstType('int')
|
2013-05-17 13:53:49 +02:00
|
|
|
return self.intType_
|
|
|
|
|
2013-10-23 11:42:48 +02:00
|
|
|
def int64Type(self):
|
|
|
|
if self.int64Type_ is None:
|
|
|
|
self.int64Type_ = self.target.FindFirstType('long long int')
|
|
|
|
return self.int64Type_
|
|
|
|
|
2013-05-17 13:53:49 +02:00
|
|
|
def charType(self):
|
|
|
|
if self.charType_ is None:
|
2013-05-22 14:30:36 +02:00
|
|
|
self.charType_ = self.target.FindFirstType('char')
|
2013-05-17 13:53:49 +02:00
|
|
|
return self.charType_
|
|
|
|
|
|
|
|
def charPtrType(self):
|
|
|
|
if self.charPtrType_ is None:
|
|
|
|
self.charPtrType_ = self.charType().GetPointerType()
|
|
|
|
return self.charPtrType_
|
|
|
|
|
|
|
|
def voidPtrType(self):
|
2013-07-02 15:43:29 +02:00
|
|
|
if self.voidPtrType_ is None:
|
|
|
|
self.voidPtrType_ = self.target.FindFirstType('void').GetPointerType()
|
|
|
|
return self.voidPtrType_
|
2013-05-17 13:53:49 +02:00
|
|
|
|
2013-07-02 15:43:29 +02:00
|
|
|
def ptrSize(self):
|
2013-05-17 13:53:49 +02:00
|
|
|
return self.charPtrType().GetByteSize()
|
|
|
|
|
|
|
|
def sizetType(self):
|
|
|
|
if self.sizetType_ is None:
|
|
|
|
self.sizetType_ = self.lookupType('size_t')
|
|
|
|
return self.sizetType_
|
|
|
|
|
2013-05-17 17:14:45 +02:00
|
|
|
def addressOf(self, value):
|
|
|
|
return int(value.GetLoadAddress())
|
|
|
|
|
2013-07-02 15:43:29 +02:00
|
|
|
def extractInt(self, address):
|
|
|
|
return int(self.createValue(address, self.intType()))
|
|
|
|
|
2013-10-23 11:42:48 +02:00
|
|
|
def extractInt64(self, address):
|
|
|
|
return int(self.createValue(address, self.int64Type()))
|
|
|
|
|
2013-07-09 14:19:45 -07:00
|
|
|
def extractByte(self, address):
|
|
|
|
return int(self.createValue(address, self.charType())) & 0xFF
|
|
|
|
|
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())
|
|
|
|
self.reportData()
|
|
|
|
|
|
|
|
def put(self, stuff):
|
|
|
|
sys.stdout.write(stuff)
|
|
|
|
|
2013-05-13 16:39:51 +02:00
|
|
|
def isMovableType(self, type):
|
2013-10-23 16:28:02 +02:00
|
|
|
if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
|
2013-05-13 16:39:51 +02:00
|
|
|
return True
|
2013-10-23 16:28:02 +02:00
|
|
|
return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
|
2013-05-13 16:39:51 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def putNumChild(self, numchild):
|
|
|
|
#warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
|
2013-05-07 16:43:20 +02:00
|
|
|
#if numchild != self.currentChildNumChild:
|
|
|
|
self.put('numchild="%s",' % numchild)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-01-21 18:13:02 +01:00
|
|
|
def putPointerValue(self, value):
|
|
|
|
# Use a lower priority
|
|
|
|
if value is None:
|
|
|
|
self.putEmptyValue(-1)
|
|
|
|
else:
|
|
|
|
self.putValue("0x%x" % value.Dereference())
|
|
|
|
|
2013-10-24 13:27:10 +02:00
|
|
|
def putSimpleValue(self, value, encoding = None, priority = 0):
|
|
|
|
self.putValue(value.GetValue(), encoding, priority)
|
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def tryPutArrayContents(self, typeobj, base, n):
|
2013-09-11 21:35:39 +02:00
|
|
|
if not self.isSimpleType(typeobj):
|
2013-05-08 16:20:03 +02:00
|
|
|
return False
|
|
|
|
size = n * typeobj.sizeof
|
|
|
|
self.put('childtype="%s",' % typeobj)
|
2013-05-17 13:53:49 +02:00
|
|
|
self.put('addrbase="0x%x",' % int(base))
|
|
|
|
self.put('addrstep="%d",' % typeobj.sizeof)
|
2013-05-08 16:20:03 +02:00
|
|
|
self.put('arrayencoding="%s",' % simpleEncoding(typeobj))
|
|
|
|
self.put('arraydata="')
|
2013-09-11 21:35:39 +02:00
|
|
|
self.put(self.readMemory(base, size))
|
2013-05-08 16:20:03 +02:00
|
|
|
self.put('",')
|
|
|
|
return True
|
|
|
|
|
|
|
|
def putArrayData(self, type, base, n,
|
|
|
|
childNumChild = None, maxNumChild = 10000):
|
|
|
|
if not self.tryPutArrayContents(type, base, n):
|
2013-07-08 13:00:52 +02:00
|
|
|
base = self.createPointerValue(base, type)
|
2013-05-08 16:20:03 +02:00
|
|
|
with Children(self, n, type, childNumChild, maxNumChild,
|
|
|
|
base, type.GetByteSize()):
|
|
|
|
for i in self.childRange():
|
|
|
|
self.putSubItem(i, (base + i).dereference())
|
|
|
|
|
2013-06-28 14:04:05 +02:00
|
|
|
def createPointerValue(self, address, pointeeType):
|
|
|
|
addr = int(address) & 0xFFFFFFFFFFFFFFFF
|
|
|
|
return self.context.CreateValueFromAddress(None, addr, pointeeType).AddressOf()
|
|
|
|
|
|
|
|
def createValue(self, address, referencedType):
|
|
|
|
addr = int(address) & 0xFFFFFFFFFFFFFFFF
|
|
|
|
return self.context.CreateValueFromAddress(None, addr, referencedType)
|
|
|
|
|
2013-06-05 16:49:50 +02:00
|
|
|
def putCallItem(self, name, value, func, *args):
|
2013-09-11 21:35:39 +02:00
|
|
|
result = self.call2(value, func, args)
|
2013-06-05 16:49:50 +02:00
|
|
|
with SubItem(self, name):
|
|
|
|
self.putItem(result)
|
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def childRange(self):
|
|
|
|
if self.currentMaxNumChild is None:
|
|
|
|
return xrange(0, self.currentNumChild)
|
|
|
|
return xrange(min(self.currentMaxNumChild, self.currentNumChild))
|
|
|
|
|
2014-01-16 14:23:53 +01:00
|
|
|
def canonicalTypeName(self, name):
|
|
|
|
return re.sub('\\bconst\\b', '', name).replace(' ', '')
|
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def lookupType(self, name):
|
2013-10-23 12:56:44 +02:00
|
|
|
#warn("LOOKUP TYPE NAME: %s" % name)
|
2013-07-03 13:32:19 +02:00
|
|
|
if name.endswith('*'):
|
2014-01-16 14:23:53 +01:00
|
|
|
typeobj = self.lookupType(name[:-1].strip())
|
|
|
|
return typeobj.GetPointerType() if type.IsValid() else None
|
|
|
|
typeobj = self.target.FindFirstType(name)
|
|
|
|
#warn("LOOKUP RESULT: %s" % typeobj.name)
|
|
|
|
#warn("LOOKUP VALID: %s" % typeobj.IsValid())
|
|
|
|
if typeobj.IsValid():
|
|
|
|
return typeobj
|
|
|
|
try:
|
|
|
|
if len(self.types_) == 0:
|
|
|
|
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())
|
|
|
|
self.types_[n] = t
|
|
|
|
return self.types_.get(self.canonicalTypeName(name))
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
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']
|
2013-10-21 15:39:15 +02:00
|
|
|
self.startMode_ = args.get('startMode', 1)
|
2014-02-04 13:32:17 +01:00
|
|
|
self.processArgs_ = args.get('processArgs', [])
|
|
|
|
self.processArgs_ = map(lambda x: self.hexdecode(x), self.processArgs_)
|
2013-10-21 15:39:15 +02:00
|
|
|
self.attachPid_ = args.get('attachPid', 0)
|
2013-10-10 15:15:49 +02:00
|
|
|
self.sysRoot_ = args.get('sysRoot', '')
|
2013-10-29 22:25:41 +01:00
|
|
|
self.remoteChannel_ = args.get('remoteChannel', '')
|
2013-10-31 10:07:28 +01:00
|
|
|
self.platform_ = args.get('platform', '')
|
2013-10-01 02:30:12 +02:00
|
|
|
|
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
|
|
|
self.importDumpers()
|
|
|
|
|
2013-10-01 02:30:12 +02:00
|
|
|
state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
|
|
|
|
self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def runEngine(self, _):
|
2013-05-31 15:27:54 +02:00
|
|
|
s = threading.Thread(target=self.loop, args=[])
|
|
|
|
s.start()
|
|
|
|
|
|
|
|
def loop(self):
|
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():
|
2013-10-29 22:25:41 +01:00
|
|
|
self.report('state="inferiorrunfailed"')
|
|
|
|
return
|
|
|
|
self.report('pid="%s"' % self.process.GetProcessID())
|
2013-11-19 10:45:00 +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.report('state="enginerunandinferiorrunok"')
|
2013-10-29 22:25:41 +01:00
|
|
|
elif len(self.remoteChannel_) > 0:
|
|
|
|
self.process = self.target.ConnectRemote(
|
|
|
|
self.debugger.GetListener(),
|
|
|
|
self.remoteChannel_, None, error)
|
2013-10-31 10:07:28 +01:00
|
|
|
if not error.Success():
|
|
|
|
self.report('state="inferiorrunfailed"')
|
|
|
|
return
|
2013-11-19 10:45:00 +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.report('state="enginerunandinferiorrunok"')
|
2013-10-01 02:30:12 +02:00
|
|
|
else:
|
2014-02-04 13:32:17 +01:00
|
|
|
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
|
2013-10-01 02:30:12 +02:00
|
|
|
launchInfo.SetWorkingDirectory(os.getcwd())
|
2013-10-20 21:45:47 +02:00
|
|
|
environmentList = [key + "=" + value for key,value in os.environ.items()]
|
|
|
|
launchInfo.SetEnvironmentEntries(environmentList, False)
|
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():
|
2013-11-11 16:16:58 +01:00
|
|
|
self.reportError(error)
|
|
|
|
self.report('state="enginerunfailed"')
|
2013-10-29 22:25:41 +01:00
|
|
|
return
|
|
|
|
self.report('pid="%s"' % self.process.GetProcessID())
|
|
|
|
self.report('state="enginerunandinferiorrunok"')
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-31 15:27:54 +02:00
|
|
|
event = lldb.SBEvent()
|
|
|
|
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)
|
|
|
|
result = 'error={type="%s"' % error.GetType()
|
|
|
|
result += ',code="%s"' % error.GetError()
|
|
|
|
result += ',desc="%s"}' % desc.GetData()
|
2013-05-07 08:46:51 +02:00
|
|
|
return result
|
|
|
|
|
|
|
|
def reportError(self, error):
|
|
|
|
self.report(self.describeError(error))
|
2014-02-06 16:47:07 +01:00
|
|
|
if error.GetType():
|
|
|
|
self.reportStatus(error.GetCString())
|
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
|
|
|
|
|
|
|
def reportLocation(self):
|
|
|
|
thread = self.currentThread()
|
2013-05-24 10:14:11 +02:00
|
|
|
frame = thread.GetSelectedFrame()
|
2013-04-30 10:46:48 +02:00
|
|
|
file = fileName(frame.line_entry.file)
|
|
|
|
line = frame.line_entry.line
|
|
|
|
self.report('location={file="%s",line="%s",addr="%s"}' % (file, line, frame.pc))
|
|
|
|
|
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
|
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def reportThreads(self):
|
2013-05-29 16:59:16 +02:00
|
|
|
reasons = ['None', 'Trace', 'Breakpoint', 'Watchpoint', 'Signal', 'Exception',
|
|
|
|
'Exec', 'PlanComplete']
|
2013-04-30 10:46:48 +02:00
|
|
|
result = 'threads={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)
|
2013-05-30 15:35:52 +02:00
|
|
|
stopReason = 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()
|
2013-05-30 15:35:52 +02:00
|
|
|
result += ',stop-reason="%s"' % stopReason
|
|
|
|
if stopReason >= 0 and stopReason < len(reasons):
|
|
|
|
result += ',state="%s"' % reasons[stopReason]
|
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
|
|
|
|
result += ',fullname="%s"' % fileName(frame.line_entry.file)
|
|
|
|
result += ',file="%s"' % fileName(frame.line_entry.file)
|
|
|
|
result += '}},'
|
|
|
|
|
|
|
|
result += '],current-thread-id="%s"},' % self.currentThread().id
|
|
|
|
self.report(result)
|
|
|
|
|
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
|
|
|
|
|
2014-02-03 13:47:26 +01:00
|
|
|
def reportStack(self, args = {}):
|
2013-11-05 16:12:31 +01:00
|
|
|
if not self.process:
|
2013-04-30 10:46:48 +02:00
|
|
|
self.report('msg="No process"')
|
2013-11-05 16:12:31 +01:00
|
|
|
return
|
|
|
|
thread = self.currentThread()
|
2014-02-03 13:47:26 +01:00
|
|
|
limit = args.get('stacklimit', -1)
|
2013-11-05 16:12:31 +01:00
|
|
|
if not thread:
|
|
|
|
self.report('msg="No thread"')
|
|
|
|
return
|
|
|
|
frame = thread.GetSelectedFrame()
|
|
|
|
if frame:
|
|
|
|
frameId = frame.GetFrameID()
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
2013-11-05 16:12:31 +01:00
|
|
|
frameId = 0;
|
2014-02-03 13:47:26 +01:00
|
|
|
|
|
|
|
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
|
|
|
|
|
2013-11-05 16:12:31 +01:00
|
|
|
result = 'stack={current-frame="%s"' % frameId
|
|
|
|
result += ',current-thread="%s"' % thread.GetThreadID()
|
|
|
|
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
|
2013-11-05 16:12:31 +01:00
|
|
|
lineEntry = frame.GetLineEntry()
|
|
|
|
line = lineEntry.GetLine()
|
|
|
|
usable = line != 0
|
|
|
|
result += '{pc="0x%x"' % frame.GetPC()
|
|
|
|
result += ',level="%d"' % frame.idx
|
|
|
|
result += ',addr="0x%x"' % frame.GetPCAddress().GetLoadAddress(self.target)
|
|
|
|
result += ',func="%s"' % frame.GetFunctionName()
|
|
|
|
result += ',line="%d"' % line
|
|
|
|
result += ',fullname="%s"' % fileName(lineEntry.file)
|
|
|
|
result += ',usable="%d"' % usable
|
|
|
|
result += ',file="%s"},' % fileName(lineEntry.file)
|
2014-02-03 13:47:26 +01:00
|
|
|
result += ']'
|
|
|
|
result += ',hasmore="%d"' % isLimited
|
|
|
|
result += ',limit="%d"' % limit
|
|
|
|
result += '}'
|
2013-11-05 16:12:31 +01:00
|
|
|
self.report(result)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-17 17:14:45 +02:00
|
|
|
def putBetterType(self, type):
|
|
|
|
try:
|
|
|
|
self.currentType = type.GetName()
|
|
|
|
except:
|
|
|
|
self.currentType = str(type)
|
2013-05-17 09:50:39 +02:00
|
|
|
self.currentTypePriority = self.currentTypePriority + 1
|
2013-06-05 11:26:46 +02:00
|
|
|
#warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
|
2013-05-07 16:43:20 +02:00
|
|
|
|
2014-01-23 15:30:51 +01:00
|
|
|
def extractBlob(self, base, size):
|
2013-05-22 14:30:36 +02:00
|
|
|
if size == 0:
|
2014-01-23 15:30:51 +01:00
|
|
|
return Blob("")
|
2013-05-17 17:14:45 +02:00
|
|
|
base = int(base) & 0xFFFFFFFFFFFFFFFF
|
|
|
|
size = int(size) & 0xFFFFFFFF
|
2013-05-22 14:30:36 +02:00
|
|
|
error = lldb.SBError()
|
2014-01-23 15:30:51 +01:00
|
|
|
return Blob(self.process.ReadMemory(base, size, error))
|
2013-05-07 16:43:20 +02:00
|
|
|
|
2014-01-24 16:55:44 +01:00
|
|
|
def toBlob(self, value):
|
|
|
|
data = value.GetData()
|
|
|
|
size = int(data.GetByteSize())
|
|
|
|
buf = bytearray(struct.pack('x' * size))
|
|
|
|
error = lldb.SBError()
|
|
|
|
#data.ReadRawData(error, 0, buf)
|
|
|
|
for i in range(size):
|
|
|
|
buf[i] = data.GetUnsignedInt8(error, i)
|
|
|
|
return Blob(bytes(buf))
|
|
|
|
|
2014-01-30 15:54:03 +01:00
|
|
|
def extractStaticMetaObjectHelper(self, typeobj):
|
|
|
|
if typeobj.GetTypeClass() in (lldb.eTypeClassStruct, lldb.eTypeClassClass):
|
|
|
|
needle = typeobj.GetUnqualifiedType().GetName() + "::staticMetaObject"
|
2014-01-31 18:08:13 +01:00
|
|
|
options = lldb.SBExpressionOptions()
|
|
|
|
result = self.target.EvaluateExpression(needle, options)
|
|
|
|
# Surprising results include:
|
|
|
|
# (lldb) script print lldb.target.FindFirstGlobalVariable(
|
|
|
|
# '::QSharedDataPointer<QDirPrivate>::staticMetaObject')
|
|
|
|
# (const QMetaObject) QAbstractAnimation::staticMetaObject = { d = { ... } }
|
|
|
|
#if result.GetName() != needle:
|
|
|
|
if result is None or not result.IsValid():
|
2014-01-30 15:54:03 +01:00
|
|
|
result = 0
|
|
|
|
else:
|
|
|
|
result = 0
|
|
|
|
self.knownStaticMetaObjects[typeobj.GetName()] = result
|
|
|
|
return result
|
|
|
|
|
2014-01-29 16:14:10 +01:00
|
|
|
def extractStaticMetaObject(self, typeobj):
|
2014-01-31 13:52:47 +01:00
|
|
|
if not self.isGoodLldb:
|
|
|
|
return 0
|
2014-01-30 15:54:03 +01:00
|
|
|
result = self.extractStaticMetaObjectHelper(typeobj)
|
|
|
|
if result:
|
|
|
|
return result
|
|
|
|
base = typeobj.GetDirectBaseClassAtIndex(0).GetType()
|
|
|
|
return self.extractStaticMetaObjectHelper(base)
|
2013-07-03 13:32:19 +02:00
|
|
|
|
2013-05-08 16:20:03 +02:00
|
|
|
def stripNamespaceFromType(self, typeName):
|
|
|
|
#type = stripClassTag(typeName)
|
|
|
|
type = typeName
|
2014-01-09 13:25:17 +01:00
|
|
|
ns = self.qtNamespace()
|
|
|
|
if len(ns) > 0 and type.startswith(ns):
|
|
|
|
type = type[len(ns):]
|
2013-05-08 16:20:03 +02:00
|
|
|
pos = type.find("<")
|
|
|
|
# FIXME: make it recognize foo<A>::bar<B>::iterator?
|
|
|
|
while pos != -1:
|
|
|
|
pos1 = type.rfind(">", pos)
|
|
|
|
type = type[0:pos] + type[pos1+1:]
|
|
|
|
pos = type.find("<")
|
2013-07-03 13:32:19 +02:00
|
|
|
if type.startswith("const "):
|
|
|
|
type = type[6:]
|
|
|
|
if type.startswith("volatile "):
|
|
|
|
type = type[9:]
|
2013-05-08 16:20:03 +02:00
|
|
|
return type
|
|
|
|
|
|
|
|
def putSubItem(self, component, value, tryDynamic=True):
|
2013-05-13 16:39:51 +02:00
|
|
|
if not value.IsValid():
|
2014-01-24 17:02:23 +01:00
|
|
|
warn("INVALID SUBITEM: %s" % value.GetName())
|
2013-05-13 16:39:51 +02:00
|
|
|
return
|
2013-05-08 16:20:03 +02:00
|
|
|
with SubItem(self, component):
|
|
|
|
self.putItem(value, tryDynamic)
|
|
|
|
|
2013-06-11 14:24:26 +02:00
|
|
|
def putAddress(self, addr):
|
2014-01-22 14:01:07 +01:00
|
|
|
#if int(addr) == 0xffffffffffffffff:
|
|
|
|
# raise RuntimeError("Illegal address")
|
|
|
|
if self.currentPrintsAddress and not addr is None:
|
|
|
|
self.put('addr="0x%x",' % int(addr))
|
2013-06-11 14:24:26 +02:00
|
|
|
|
2014-01-31 13:52:47 +01:00
|
|
|
def isFunctionType(self, typeobj):
|
|
|
|
if self.isGoodLldb:
|
|
|
|
return typeobj.IsFunctionType()
|
|
|
|
#warn("TYPE: %s" % typeobj)
|
|
|
|
return False
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def putItem(self, value, tryDynamic=True):
|
2013-05-07 16:43:20 +02:00
|
|
|
#value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
|
2014-01-09 16:23:17 +01:00
|
|
|
typeName = value.GetType().GetUnqualifiedType().GetName()
|
2014-01-31 13:52:47 +01:00
|
|
|
if self.isGoodLldb:
|
|
|
|
value.SetPreferDynamicValue(tryDynamic)
|
2013-07-03 13:32:19 +02:00
|
|
|
typeClass = value.GetType().GetTypeClass()
|
2013-05-08 16:20:03 +02:00
|
|
|
|
2013-06-11 14:24:26 +02:00
|
|
|
if tryDynamic:
|
2014-01-22 14:01:07 +01:00
|
|
|
self.putAddress(value.GetLoadAddress())
|
2013-06-11 14:24:26 +02:00
|
|
|
|
2013-05-22 12:06:56 +02:00
|
|
|
# Handle build-in LLDB visualizers if wanted.
|
2014-01-22 14:01:07 +01:00
|
|
|
if False and self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
|
2013-05-13 16:04:00 +02:00
|
|
|
# FIXME: print "official" summary?
|
|
|
|
summary = value.GetTypeSummary()
|
|
|
|
if summary.IsValid():
|
|
|
|
warn("DATA: %s" % summary.GetData())
|
2014-01-31 13:52:47 +01:00
|
|
|
if self.isGoodLldb:
|
|
|
|
value.SetPreferSyntheticValue(False)
|
2013-05-13 16:04:00 +02:00
|
|
|
provider = value.GetTypeSynthetic()
|
|
|
|
data = provider.GetData()
|
|
|
|
formatter = eval(data)(value, {})
|
|
|
|
formatter.update()
|
|
|
|
numchild = formatter.num_children()
|
2013-05-07 16:43:20 +02:00
|
|
|
self.put('iname="%s",' % self.currentIName)
|
2013-06-04 16:15:56 +02:00
|
|
|
self.putType(typeName)
|
2013-05-07 16:43:20 +02:00
|
|
|
self.put('numchild="%s",' % numchild)
|
|
|
|
self.put('addr="0x%x",' % value.GetLoadAddress())
|
2013-05-13 16:04:00 +02:00
|
|
|
self.putItemCount(numchild)
|
2013-05-07 16:43:20 +02:00
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
with Children(self):
|
2013-05-13 16:04:00 +02:00
|
|
|
for i in xrange(numchild):
|
|
|
|
child = formatter.get_child_at_index(i)
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.putItem(child)
|
|
|
|
return
|
|
|
|
|
2013-07-03 17:20:46 +02:00
|
|
|
# Typedefs
|
|
|
|
if typeClass == lldb.eTypeClassTypedef:
|
2013-10-30 15:07:54 +01:00
|
|
|
if typeName in self.qqDumpers:
|
2013-07-03 17:20:46 +02:00
|
|
|
self.putType(typeName)
|
|
|
|
self.context = value
|
2013-10-30 15:07:54 +01:00
|
|
|
self.qqDumpers[typeName](self, value)
|
2013-07-03 17:20:46 +02:00
|
|
|
return
|
2013-07-05 09:22:55 +02:00
|
|
|
realType = value.GetType()
|
|
|
|
if hasattr(realType, 'GetCanonicalType'):
|
2014-01-09 18:02:09 +01:00
|
|
|
baseType = realType.GetCanonicalType()
|
|
|
|
baseValue = value.Cast(baseType.unqualified())
|
|
|
|
self.putItem(baseValue)
|
|
|
|
self.putBetterType(realType)
|
2013-07-05 09:22:55 +02:00
|
|
|
return
|
2013-07-03 17:20:46 +02:00
|
|
|
|
2013-05-22 12:06:56 +02:00
|
|
|
# Our turf now.
|
2014-01-31 13:52:47 +01:00
|
|
|
if self.isGoodLldb:
|
|
|
|
value.SetPreferSyntheticValue(False)
|
2013-05-17 09:50:39 +02:00
|
|
|
|
2013-06-10 14:50:22 +02:00
|
|
|
# Arrays
|
2013-07-03 13:32:19 +02:00
|
|
|
if typeClass == lldb.eTypeClassArray:
|
2013-11-07 12:26:14 +01:00
|
|
|
self.putCStyleArray(value)
|
2013-06-10 14:50:22 +02:00
|
|
|
return
|
|
|
|
|
2013-10-24 18:46:07 +02:00
|
|
|
# Vectors like char __attribute__ ((vector_size (8)))
|
|
|
|
if typeClass == lldb.eTypeClassVector:
|
2013-11-07 12:26:14 +01:00
|
|
|
self.putCStyleArray(value)
|
2013-10-24 18:46:07 +02:00
|
|
|
return
|
|
|
|
|
2013-05-17 09:50:39 +02:00
|
|
|
# References
|
|
|
|
if value.GetType().IsReferenceType():
|
2013-06-04 16:15:56 +02:00
|
|
|
origType = value.GetTypeName();
|
2013-07-05 09:22:55 +02:00
|
|
|
type = value.GetType().GetDereferencedType().unqualified()
|
2013-07-03 13:32:19 +02:00
|
|
|
addr = int(value) & 0xFFFFFFFFFFFFFFFF
|
2013-07-02 15:43:29 +02:00
|
|
|
self.putItem(value.CreateValueFromAddress(None, addr, type))
|
2013-06-04 16:15:56 +02:00
|
|
|
self.putBetterType(origType)
|
2013-05-17 09:50:39 +02:00
|
|
|
return
|
|
|
|
|
2013-05-17 10:10:13 +02:00
|
|
|
# Pointers
|
2013-07-03 13:32:19 +02:00
|
|
|
if value.GetType().IsPointerType():
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putFormattedPointer(value)
|
|
|
|
return
|
2013-05-17 10:10:13 +02:00
|
|
|
|
2013-05-13 16:04:00 +02:00
|
|
|
#warn("VALUE: %s" % value)
|
2013-06-05 11:26:46 +02:00
|
|
|
#warn("FANCY: %s" % self.useFancy)
|
|
|
|
if self.useFancy:
|
|
|
|
stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
|
|
|
|
#warn("STRIPPED: %s" % stripped)
|
2013-10-30 15:07:54 +01:00
|
|
|
#warn("DUMPABLE: %s" % (stripped in self.qqDumpers))
|
|
|
|
if stripped in self.qqDumpers:
|
2013-06-05 11:26:46 +02:00
|
|
|
self.putType(typeName)
|
2013-07-02 15:43:29 +02:00
|
|
|
self.context = value
|
2013-10-30 15:07:54 +01:00
|
|
|
self.qqDumpers[stripped](self, value)
|
2013-06-05 11:26:46 +02:00
|
|
|
return
|
2013-05-13 16:04:00 +02:00
|
|
|
|
|
|
|
# Normal value
|
|
|
|
#numchild = 1 if value.MightHaveChildren() else 0
|
|
|
|
numchild = value.GetNumChildren()
|
2013-06-04 16:15:56 +02:00
|
|
|
self.putType(typeName)
|
2014-01-29 16:14:10 +01:00
|
|
|
self.putEmptyValue(-1)
|
|
|
|
staticMetaObject = self.extractStaticMetaObject(value.GetType())
|
|
|
|
if staticMetaObject:
|
|
|
|
self.context = value
|
|
|
|
self.putQObjectNameValue(value)
|
2013-07-03 13:32:19 +02:00
|
|
|
else:
|
|
|
|
v = value.GetValue()
|
|
|
|
if v:
|
|
|
|
self.putValue(v)
|
|
|
|
|
2013-05-13 16:04:00 +02:00
|
|
|
self.put('numchild="%s",' % numchild)
|
2014-01-22 14:01:07 +01:00
|
|
|
|
2013-05-13 16:04:00 +02:00
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(value)
|
2014-01-29 16:14:10 +01:00
|
|
|
if staticMetaObject:
|
|
|
|
self.putQObjectGuts(value, staticMetaObject)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-01-22 14:01:07 +01:00
|
|
|
def warn(self, msg):
|
|
|
|
self.put('{name="%s",value="",type=""},' % msg)
|
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
def putFields(self, value):
|
2013-07-04 16:01:43 +02:00
|
|
|
# Suppress printing of 'name' field for arrays.
|
|
|
|
if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
|
|
|
|
for i in xrange(value.GetNumChildren()):
|
|
|
|
child = value.GetChildAtIndex(i)
|
2013-07-08 16:24:34 +02:00
|
|
|
with UnnamedSubItem(self, str(i)):
|
2013-07-04 16:01:43 +02:00
|
|
|
self.putItem(child)
|
|
|
|
return
|
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
n = value.GetNumChildren()
|
2013-06-20 17:18:52 +02:00
|
|
|
m = value.GetType().GetNumberOfDirectBaseClasses()
|
2013-04-30 10:46:48 +02:00
|
|
|
if n > 10000:
|
|
|
|
n = 10000
|
2013-06-21 13:46:56 +02:00
|
|
|
# seems to happen in the 'inheritance' autotest
|
|
|
|
if m > n:
|
|
|
|
m = n
|
2013-06-20 17:18:52 +02:00
|
|
|
for i in xrange(m):
|
|
|
|
child = value.GetChildAtIndex(i)
|
|
|
|
with UnnamedSubItem(self, "@%d" % (i + 1)):
|
2013-07-09 17:26:19 +02:00
|
|
|
self.put('iname="%s",' % self.currentIName)
|
2013-06-20 17:18:52 +02:00
|
|
|
self.put('name="[%s]",' % child.name)
|
|
|
|
self.putItem(child)
|
|
|
|
for i in xrange(m, n):
|
2014-01-20 15:57:09 +01:00
|
|
|
#for i in range(n):
|
2013-05-07 16:43:20 +02:00
|
|
|
child = value.GetChildAtIndex(i)
|
2014-01-30 18:13:45 +01:00
|
|
|
# Only needed in the QVariant4 test.
|
2014-01-20 15:57:09 +01:00
|
|
|
if int(child.GetLoadAddress()) == 0xffffffffffffffff:
|
|
|
|
typeClass = child.GetType().GetTypeClass()
|
|
|
|
if typeClass != lldb.eTypeClassBuiltin:
|
|
|
|
field = value.GetType().GetFieldAtIndex(i)
|
|
|
|
addr = value.GetLoadAddress() + field.GetOffsetInBytes()
|
2014-01-22 14:01:07 +01:00
|
|
|
child = value.CreateValueFromAddress(child.GetName(), addr, child.GetType())
|
2013-07-05 09:22:55 +02:00
|
|
|
if child.IsValid(): # FIXME: Anon members?
|
|
|
|
with SubItem(self, child):
|
|
|
|
self.putItem(child)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def reportVariables(self, _ = None):
|
2014-01-29 11:43:11 +01:00
|
|
|
frame = self.currentFrame()
|
|
|
|
if frame is None:
|
|
|
|
return
|
2013-05-30 15:35:52 +02:00
|
|
|
self.currentIName = 'local'
|
2013-04-30 10:46:48 +02:00
|
|
|
self.put('data=[')
|
2013-07-08 18:14:00 +02:00
|
|
|
self.anonNumber = 0
|
2013-10-25 13:35:31 +02:00
|
|
|
shadowed = {}
|
2014-01-16 10:28:36 +01:00
|
|
|
ids = {} # Filter out duplicates entries at the same address.
|
2014-01-29 14:41:00 +01:00
|
|
|
values = list(frame.GetVariables(True, True, False, False))
|
|
|
|
|
2013-10-25 13:35:31 +02:00
|
|
|
values.reverse() # To get shadowed vars numbered backwards.
|
|
|
|
for value in values:
|
2014-01-16 10:28:36 +01:00
|
|
|
if not value.IsValid():
|
|
|
|
continue
|
|
|
|
name = value.GetName()
|
2014-01-20 15:57:09 +01:00
|
|
|
id = "%s:0x%x" % (name, value.GetLoadAddress())
|
2014-01-16 10:28:36 +01:00
|
|
|
if id in ids:
|
|
|
|
continue
|
|
|
|
ids[id] = True
|
2014-01-20 15:57:09 +01:00
|
|
|
#if self.dummyValue is None:
|
|
|
|
# self.dummyValue = value
|
2013-11-07 18:09:43 +01:00
|
|
|
if name is None:
|
|
|
|
warn("NO NAME FOR VALUE: %s" % value)
|
|
|
|
continue
|
2013-10-31 14:20:51 +01:00
|
|
|
if name in shadowed:
|
2013-10-25 13:35:31 +02:00
|
|
|
level = shadowed[name]
|
|
|
|
shadowed[name] = level + 1
|
|
|
|
name += "@%s" % level
|
|
|
|
else:
|
|
|
|
shadowed[name] = 1
|
2014-02-04 14:48:40 +01:00
|
|
|
|
|
|
|
if name == "argv" and value.GetType().GetName() == "char **":
|
|
|
|
self.putSpecialArgv(value)
|
|
|
|
else:
|
|
|
|
with SubItem(self, name):
|
|
|
|
self.put('iname="%s",' % self.currentIName)
|
|
|
|
self.putItem(value)
|
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]
|
|
|
|
typename = staticVar.GetType().GetName()
|
|
|
|
name = staticVar.GetName()
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.put('name="%s",' % name)
|
|
|
|
self.put('iname="%s",' % self.currentIName)
|
|
|
|
self.putItem(staticVar)
|
|
|
|
else:
|
|
|
|
with SubItem(self, "None"):
|
|
|
|
self.putEmptyValue()
|
|
|
|
self.putNumChild(0)
|
|
|
|
|
2013-05-30 15:35:52 +02:00
|
|
|
# 'watchers':[{'id':'watch.0','exp':'23'},...]
|
2014-01-20 15:57:09 +01:00
|
|
|
#if not self.dummyValue is None:
|
|
|
|
for watcher in self.currentWatchers:
|
|
|
|
iname = watcher['iname']
|
|
|
|
# could be 'watch.0' or 'tooltip.deadbead'
|
|
|
|
(base, component) = iname.split('.')
|
2014-01-23 15:30:51 +01:00
|
|
|
exp = self.hexdecode(watcher['exp'])
|
2014-01-20 15:57:09 +01:00
|
|
|
if exp == "":
|
|
|
|
self.put('type="",value="",exp=""')
|
|
|
|
continue
|
|
|
|
|
|
|
|
options = lldb.SBExpressionOptions()
|
|
|
|
value = self.target.EvaluateExpression(exp, options)
|
|
|
|
#value = self.target.EvaluateExpression(iname, exp)
|
|
|
|
self.currentIName = base
|
|
|
|
with SubItem(self, component):
|
|
|
|
self.put('exp="%s",' % exp)
|
2014-01-23 15:30:51 +01:00
|
|
|
self.put('wname="%s",' % self.hexencode(exp))
|
2014-01-20 15:57:09 +01:00
|
|
|
self.put('iname="%s",' % iname)
|
|
|
|
self.putItem(value)
|
2013-05-30 15:35:52 +02:00
|
|
|
|
2013-04-30 10:46:48 +02:00
|
|
|
self.put(']')
|
|
|
|
self.report('')
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def reportData(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
|
|
|
self.report('process="none"')
|
|
|
|
else:
|
|
|
|
state = self.process.GetState()
|
|
|
|
if state == lldb.eStateStopped:
|
|
|
|
self.reportStack()
|
|
|
|
self.reportThreads()
|
|
|
|
self.reportLocation()
|
|
|
|
self.reportVariables()
|
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def reportRegisters(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
|
|
|
self.report('process="none"')
|
|
|
|
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:
|
|
|
|
result += '{name="%s"' % reg.GetName()
|
|
|
|
result += ',value="%s"' % reg.GetValue()
|
|
|
|
result += ',type="%s"},' % reg.GetType()
|
|
|
|
result += ']'
|
|
|
|
self.report(result)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
def report(self, stuff):
|
2013-11-01 10:32:37 +01:00
|
|
|
sys.stdout.write(stuff + "@\n")
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-02-06 16:47:07 +01:00
|
|
|
def reportStatus(self, msg):
|
|
|
|
self.report('statusmessage="%s"' % msg)
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def interruptInferior(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2014-02-06 16:47:07 +01:00
|
|
|
self.reportStatus("No process to interrupt.")
|
2013-05-31 16:51:12 +02:00
|
|
|
return
|
2013-06-24 17:40:00 +02:00
|
|
|
self.isInterrupting_ = True
|
2013-05-31 16:51:12 +02:00
|
|
|
error = self.process.Stop()
|
|
|
|
self.reportError(error)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def detachInferior(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2014-02-06 16:47:07 +01:00
|
|
|
self.reportStatus("No process to detach from.")
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
|
|
|
error = self.process.Detach()
|
|
|
|
self.reportError(error)
|
|
|
|
self.reportData()
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def continueInferior(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
if self.process is None:
|
2014-02-06 16:47:07 +01:00
|
|
|
self.reportStatus("No process to continue.")
|
2013-04-30 10:46:48 +02:00
|
|
|
else:
|
|
|
|
error = self.process.Continue()
|
|
|
|
self.reportError(error)
|
|
|
|
|
2013-06-24 17:40:00 +02:00
|
|
|
def quitDebugger(self, _ = None):
|
|
|
|
self.report('state="inferiorshutdownrequested"')
|
|
|
|
self.process.Kill()
|
|
|
|
|
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)
|
2013-04-30 10:46:48 +02:00
|
|
|
type = event.GetType()
|
|
|
|
msg = lldb.SBEvent.GetCStringFromEvent(event)
|
|
|
|
flavor = event.GetDataFlavor()
|
2013-05-02 14:31:35 +02:00
|
|
|
state = lldb.SBProcess.GetStateFromEvent(event)
|
2013-04-30 10:46:48 +02:00
|
|
|
self.report('event={type="%s",data="%s",msg="%s",flavor="%s",state="%s"}'
|
2013-05-02 14:31:35 +02:00
|
|
|
% (type, out.GetData(), msg, flavor, state))
|
|
|
|
if state != self.eventState:
|
|
|
|
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_:
|
|
|
|
self.report('state="inferiorshutdownok"')
|
|
|
|
else:
|
|
|
|
self.report('state="inferiorexited"')
|
|
|
|
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:
|
|
|
|
if self.isInterrupting_:
|
|
|
|
self.isInterrupting_ = False
|
|
|
|
self.report('state="inferiorstopok"')
|
|
|
|
else:
|
|
|
|
self.report('state="stopped"')
|
|
|
|
else:
|
|
|
|
self.report('state="%s"' % stateNames[state])
|
2013-04-30 10:46:48 +02:00
|
|
|
if type == lldb.SBProcess.eBroadcastBitStateChanged:
|
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)
|
|
|
|
usableFrame = self.firstUsableFrame(stoppedThread)
|
|
|
|
if usableFrame:
|
|
|
|
stoppedThread.SetSelectedFrame(usableFrame)
|
2014-02-03 13:47:26 +01:00
|
|
|
self.reportStack({'stacklimit': 20})
|
2013-06-14 10:03:00 +02:00
|
|
|
self.reportThreads()
|
|
|
|
self.reportLocation()
|
|
|
|
self.reportVariables()
|
2013-11-05 12:33:14 +01:00
|
|
|
self.reportRegisters()
|
2013-04-30 10:46:48 +02:00
|
|
|
elif type == lldb.SBProcess.eBroadcastBitInterrupt:
|
|
|
|
pass
|
|
|
|
elif type == lldb.SBProcess.eBroadcastBitSTDOUT:
|
2013-05-29 12:14:49 +02:00
|
|
|
# FIXME: Size?
|
|
|
|
msg = self.process.GetSTDOUT(1024)
|
|
|
|
self.report('output={channel="stdout",data="%s"}'
|
2014-01-23 15:30:51 +01:00
|
|
|
% self.hexencode(msg))
|
2013-04-30 10:46:48 +02:00
|
|
|
elif type == lldb.SBProcess.eBroadcastBitSTDERR:
|
2013-05-29 12:14:49 +02:00
|
|
|
msg = self.process.GetSTDERR(1024)
|
2013-11-05 11:35:25 +01:00
|
|
|
self.report('output={channel="stderr",data="%s"}'
|
2014-01-23 15:30:51 +01:00
|
|
|
% self.hexencode(msg))
|
2013-04-30 10:46:48 +02:00
|
|
|
elif type == lldb.SBProcess.eBroadcastBitProfileData:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def describeBreakpoint(self, bp, modelId):
|
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()
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',modelid="%s"' % modelId
|
2013-06-14 15:15:09 +02:00
|
|
|
if not bp.IsValid():
|
|
|
|
return
|
2013-04-30 10:46:48 +02:00
|
|
|
result += ',hitcount="%s"' % bp.GetHitCount()
|
2013-06-14 15:15:09 +02:00
|
|
|
if hasattr(bp, 'GetThreadID'):
|
|
|
|
result += ',threadid="%s"' % bp.GetThreadID()
|
|
|
|
if hasattr(bp, 'IsOneShot'):
|
2013-05-02 14:31:35 +02:00
|
|
|
result += ',oneshot="%s"' % (1 if bp.IsOneShot() else 0)
|
2013-06-24 13:16:42 +02:00
|
|
|
if hasattr(bp, 'GetCondition'):
|
|
|
|
cond = bp.GetCondition()
|
2014-01-23 15:30:51 +01:00
|
|
|
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()
|
|
|
|
result += ',locations=['
|
2013-06-14 15:15:09 +02:00
|
|
|
if hasattr(bp, 'GetNumLocations'):
|
|
|
|
for i in xrange(bp.GetNumLocations()):
|
|
|
|
loc = bp.GetLocationAtIndex(i)
|
2014-01-29 11:43:11 +01:00
|
|
|
addr = loc.GetAddress()
|
2013-06-14 15:15:09 +02:00
|
|
|
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 += ',addr="%s"},' % loc.GetLoadAddress()
|
2013-05-07 10:45:53 +02:00
|
|
|
result += '],'
|
2013-04-30 10:46:48 +02:00
|
|
|
return result
|
|
|
|
|
2013-05-16 17:37:41 +02:00
|
|
|
def addBreakpoint(self, args):
|
|
|
|
bpType = args["type"]
|
|
|
|
if bpType == BreakpointByFileAndLine:
|
|
|
|
bpNew = self.target.BreakpointCreateByLocation(
|
|
|
|
str(args["file"]), int(args["line"]))
|
|
|
|
elif bpType == BreakpointByFunction:
|
|
|
|
bpNew = self.target.BreakpointCreateByName(args["function"])
|
2013-06-14 15:15:09 +02:00
|
|
|
elif bpType == BreakpointByAddress:
|
|
|
|
bpNew = self.target.BreakpointCreateByAddress(args["address"])
|
2013-05-16 17:37:41 +02:00
|
|
|
elif bpType == BreakpointAtMain:
|
|
|
|
bpNew = self.target.BreakpointCreateByName(
|
|
|
|
"main", self.target.GetExecutable().GetFilename())
|
2013-06-13 18:22:44 +02:00
|
|
|
elif bpType == BreakpointAtThrow:
|
|
|
|
bpNew = self.target.BreakpointCreateForException(
|
|
|
|
lldb.eLanguageTypeC_plus_plus, False, True)
|
|
|
|
elif bpType == BreakpointAtCatch:
|
|
|
|
bpNew = self.target.BreakpointCreateForException(
|
|
|
|
lldb.eLanguageTypeC_plus_plus, True, False)
|
2013-06-14 15:15:09 +02:00
|
|
|
elif bpType == WatchpointAtAddress:
|
|
|
|
error = lldb.SBError()
|
|
|
|
bpNew = self.target.WatchAddress(args["address"], 4, False, True, error)
|
|
|
|
#warn("BPNEW: %s" % bpNew)
|
|
|
|
self.reportError(error)
|
|
|
|
elif bpType == WatchpointAtExpression:
|
|
|
|
# FIXME: Top level-only for now.
|
|
|
|
try:
|
|
|
|
frame = self.currentFrame()
|
|
|
|
value = frame.FindVariable(args["expression"])
|
|
|
|
error = lldb.SBError()
|
2014-01-20 15:57:09 +01:00
|
|
|
bpNew = self.target.WatchAddress(value.GetLoadAddress(),
|
2013-06-14 15:15:09 +02:00
|
|
|
value.GetByteSize(), False, True, error)
|
|
|
|
except:
|
|
|
|
return
|
2013-05-16 17:37:41 +02:00
|
|
|
else:
|
2013-06-14 15:15:09 +02:00
|
|
|
warn("UNKNOWN BREAKPOINT TYPE: %s" % bpType)
|
|
|
|
return
|
2013-05-16 17:37:41 +02:00
|
|
|
bpNew.SetIgnoreCount(int(args["ignorecount"]))
|
2013-06-24 13:16:42 +02:00
|
|
|
if hasattr(bpNew, 'SetCondition'):
|
2014-01-23 15:30:51 +01:00
|
|
|
bpNew.SetCondition(self.hexdecode(args["condition"]))
|
2013-05-16 17:37:41 +02:00
|
|
|
bpNew.SetEnabled(int(args["enabled"]))
|
2013-06-14 15:15:09 +02:00
|
|
|
if hasattr(bpNew, 'SetOneShot'):
|
2013-05-16 17:37:41 +02:00
|
|
|
bpNew.SetOneShot(int(args["oneshot"]))
|
|
|
|
return bpNew
|
|
|
|
|
|
|
|
def changeBreakpoint(self, args):
|
2013-06-14 15:15:09 +02:00
|
|
|
id = int(args["lldbid"])
|
|
|
|
if id > qqWatchpointOffset:
|
|
|
|
bp = self.target.FindWatchpointByID(id)
|
|
|
|
else:
|
|
|
|
bp = self.target.FindBreakpointByID(id)
|
|
|
|
bp.SetIgnoreCount(int(args["ignorecount"]))
|
2014-01-23 15:30:51 +01:00
|
|
|
bp.SetCondition(self.hexdecode(args["condition"]))
|
2013-06-14 15:15:09 +02:00
|
|
|
bp.SetEnabled(int(args["enabled"]))
|
|
|
|
if hasattr(bp, 'SetOneShot'):
|
|
|
|
bp.SetOneShot(int(args["oneshot"]))
|
2013-05-16 17:37:41 +02:00
|
|
|
|
|
|
|
def removeBreakpoint(self, args):
|
2013-06-14 15:15:09 +02:00
|
|
|
id = int(args['lldbid'])
|
|
|
|
if id > qqWatchpointOffset:
|
|
|
|
return self.target.DeleteWatchpoint(id - qqWatchpointOffset)
|
|
|
|
return self.target.BreakpointDelete(id)
|
2013-05-16 17:37:41 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def handleBreakpoints(self, args):
|
2013-05-07 10:45:53 +02:00
|
|
|
result = 'bkpts=['
|
2013-05-07 12:34:10 +02:00
|
|
|
for bp in args['bkpts']:
|
2013-05-07 10:45:53 +02:00
|
|
|
operation = bp['operation']
|
|
|
|
|
|
|
|
if operation == 'add':
|
2013-05-16 17:37:41 +02:00
|
|
|
bpNew = self.addBreakpoint(bp)
|
|
|
|
result += '{operation="added",%s}' \
|
|
|
|
% self.describeBreakpoint(bpNew, bp["modelid"])
|
2013-05-07 10:45:53 +02:00
|
|
|
|
|
|
|
elif operation == 'change':
|
2013-05-16 17:37:41 +02:00
|
|
|
bpNew = self.changeBreakpoint(bp)
|
|
|
|
result += '{operation="changed",%s' \
|
|
|
|
% self.describeBreakpoint(bpNew, bp["modelid"])
|
2013-05-07 10:45:53 +02:00
|
|
|
|
|
|
|
elif operation == 'remove':
|
2013-05-16 17:37:41 +02:00
|
|
|
bpDead = self.removeBreakpoint(bp)
|
2013-05-07 10:45:53 +02:00
|
|
|
result += '{operation="removed",modelid="%s"}' % bp["modelid"]
|
|
|
|
|
|
|
|
result += "]"
|
2013-04-30 10:46:48 +02:00
|
|
|
self.report(result)
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def listModules(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 += ']'
|
|
|
|
self.report(result)
|
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def listSymbols(self, args):
|
|
|
|
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
|
|
|
|
result = 'symbols={module="%s"' % moduleName
|
|
|
|
result += ',valid="%s"' % module.IsValid()
|
|
|
|
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 += ']}'
|
|
|
|
self.report(result)
|
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def executeNext(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
self.currentThread().StepOver()
|
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def executeNextI(self, _ = None):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def executeStep(self, _ = None):
|
2013-04-30 10:46:48 +02:00
|
|
|
self.currentThread().StepInto()
|
|
|
|
|
2013-05-29 15:38:49 +02:00
|
|
|
def shutdownInferior(self, _ = None):
|
|
|
|
self.isShuttingDown_ = True
|
|
|
|
self.process.Kill()
|
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def quit(self, _ = None):
|
2013-05-29 15:38:49 +02:00
|
|
|
self.report('state="engineshutdownok"')
|
|
|
|
self.process.Kill()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def executeStepI(self, _ = None):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepInstruction(lldb.eOnlyThisThread)
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def executeStepOut(self, _ = None):
|
2013-05-24 08:32:12 +02:00
|
|
|
self.currentThread().StepOut()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-02-06 16:47:07 +01:00
|
|
|
def executeRunToLocation(self, args):
|
|
|
|
addr = args.get('address', 0)
|
|
|
|
if addr:
|
|
|
|
error = self.currentThread().RunToAddress(addr)
|
|
|
|
else:
|
|
|
|
frame = self.currentFrame()
|
|
|
|
file = args['file']
|
|
|
|
line = int(args['line'])
|
|
|
|
error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line)
|
|
|
|
if error.GetType():
|
|
|
|
self.report('state="running"')
|
|
|
|
self.report('state="stopped"')
|
|
|
|
self.reportError(error)
|
|
|
|
self.reportLocation()
|
|
|
|
else:
|
|
|
|
self.reportData()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2014-02-06 15:40:23 +01:00
|
|
|
def executeJumpToLocation(self, args):
|
2014-02-05 17:03:51 +01:00
|
|
|
frame = self.currentFrame()
|
|
|
|
self.report('state="stopped"')
|
|
|
|
if not frame:
|
2014-02-06 16:47:07 +01:00
|
|
|
self.reportStatus("No frame available.")
|
|
|
|
self.reportLocation()
|
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())
|
2014-02-06 16:47:07 +01:00
|
|
|
self.reportStatus("No target location found.")
|
|
|
|
self.reportLocation()
|
2014-02-05 17:03:51 +01:00
|
|
|
return
|
|
|
|
loc = bp.GetLocationAtIndex(0)
|
|
|
|
self.target.BreakpointDelete(bp.GetID())
|
|
|
|
frame.SetPC(loc.GetLoadAddress())
|
|
|
|
self.reportData()
|
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):
|
2014-02-03 13:47:26 +01:00
|
|
|
thread = args['thread']
|
2013-05-24 10:14:11 +02:00
|
|
|
self.currentThread().SetSelectedFrame(args['index'])
|
2014-02-03 13:47:26 +01:00
|
|
|
state = self.process.GetState()
|
|
|
|
if state == lldb.eStateStopped:
|
|
|
|
self.reportStack(args)
|
|
|
|
self.reportThreads()
|
|
|
|
self.reportLocation()
|
|
|
|
self.reportVariables()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
2013-05-29 16:24:17 +02:00
|
|
|
def selectThread(self, args):
|
|
|
|
self.process.SetSelectedThreadByID(args['id'])
|
|
|
|
self.reportData()
|
2013-04-30 10:46:48 +02:00
|
|
|
|
|
|
|
def requestModuleSymbols(self, frame):
|
|
|
|
self.handleCommand("target module list " + frame)
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def executeDebuggerCommand(self, 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))
|
2013-04-10 13:55:15 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def updateData(self, args):
|
2013-06-05 11:26:46 +02:00
|
|
|
if 'expanded' in args:
|
|
|
|
self.expandedINames = set(args['expanded'].split(','))
|
|
|
|
if 'autoderef' in args:
|
|
|
|
self.autoDerefPointers = int(args['autoderef'])
|
|
|
|
if 'dyntype' in args:
|
|
|
|
self.useDynamicType = int(args['dyntype'])
|
|
|
|
if 'fancy' in args:
|
|
|
|
self.useFancy = int(args['fancy'])
|
|
|
|
if 'passexceptions' in args:
|
|
|
|
self.passExceptions = int(args['passexceptions'])
|
2013-11-05 09:45:38 +01:00
|
|
|
if 'watchers' in args:
|
|
|
|
self.currentWatchers = args['watchers']
|
2013-05-30 15:35:52 +02:00
|
|
|
self.reportVariables(args)
|
2013-04-10 15:54:04 +02:00
|
|
|
|
2013-05-07 12:34:10 +02:00
|
|
|
def disassemble(self, args):
|
2013-05-03 17:18:07 +02:00
|
|
|
frame = self.currentFrame();
|
|
|
|
function = frame.GetFunction()
|
|
|
|
name = function.GetName()
|
2013-05-07 12:34:10 +02:00
|
|
|
result = 'disassembly={cookie="%s",' % args['cookie']
|
2013-05-07 08:46:51 +02:00
|
|
|
result += ',lines=['
|
2013-05-03 17:18:07 +02:00
|
|
|
base = function.GetStartAddress().GetLoadAddress(self.target)
|
|
|
|
for insn in function.GetInstructions(self.target):
|
|
|
|
comment = insn.GetComment(self.target)
|
|
|
|
addr = insn.GetAddress().GetLoadAddress(self.target)
|
|
|
|
result += '{address="%s"' % addr
|
2013-05-13 16:04:00 +02:00
|
|
|
result += ',inst="%s %s"' % (insn.GetMnemonic(self.target),
|
|
|
|
insn.GetOperands(self.target))
|
2013-05-03 17:18:07 +02:00
|
|
|
result += ',func_name="%s"' % name
|
|
|
|
if comment:
|
|
|
|
result += ',comment="%s"' % comment
|
|
|
|
result += ',offset="%s"},' % (addr - base)
|
|
|
|
self.report(result + ']')
|
|
|
|
|
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)
|
2013-05-07 12:34:10 +02:00
|
|
|
result = 'memory={cookie="%s",' % args['cookie']
|
2013-05-07 08:46:51 +02:00
|
|
|
result += ',address="%s",' % address
|
|
|
|
result += self.describeError(error)
|
2014-01-23 15:30:51 +01:00
|
|
|
result += ',contents="%s"}' % self.hexencode(contents)
|
2013-05-07 08:46:51 +02:00
|
|
|
self.report(result)
|
|
|
|
|
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):
|
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)
|
|
|
|
self.reportError(error)
|
2013-05-30 15:35:52 +02:00
|
|
|
self.reportVariables()
|
|
|
|
|
2013-10-30 15:07:54 +01:00
|
|
|
def registerDumper(self, function):
|
|
|
|
if hasattr(function, 'func_name'):
|
|
|
|
funcname = function.func_name
|
|
|
|
if funcname.startswith("qdump__"):
|
|
|
|
type = funcname[7:]
|
|
|
|
self.qqDumpers[type] = function
|
|
|
|
self.qqFormats[type] = self.qqFormats.get(type, "")
|
|
|
|
elif funcname.startswith("qform__"):
|
|
|
|
type = funcname[7:]
|
|
|
|
formats = ""
|
|
|
|
try:
|
|
|
|
formats = function()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
self.qqFormats[type] = formats
|
|
|
|
elif funcname.startswith("qedit__"):
|
|
|
|
type = funcname[7:]
|
|
|
|
try:
|
|
|
|
self.qqEditable[type] = function
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2013-05-07 16:43:20 +02:00
|
|
|
def importDumpers(self, _ = None):
|
|
|
|
result = lldb.SBCommandReturnObject()
|
|
|
|
interpreter = self.debugger.GetCommandInterpreter()
|
|
|
|
items = globals()
|
|
|
|
for key in items:
|
2013-10-30 15:07:54 +01:00
|
|
|
self.registerDumper(items[key])
|
2013-04-12 16:58:25 +02:00
|
|
|
|
2013-05-13 16:04:00 +02:00
|
|
|
def execute(self, args):
|
|
|
|
getattr(self, args['cmd'])(args)
|
|
|
|
self.report('token="%s"' % args['token'])
|
2013-05-22 14:30:36 +02:00
|
|
|
if 'continuation' in args:
|
2013-05-13 16:04:00 +02:00
|
|
|
cont = args['continuation']
|
|
|
|
self.report('continuation="%s"' % cont)
|
|
|
|
|
2013-05-29 14:55:57 +02:00
|
|
|
|
2013-10-17 17:08:32 +02:00
|
|
|
def convertHash(args):
|
|
|
|
if sys.version_info[0] == 3:
|
|
|
|
return args
|
2014-02-04 13:32:17 +01:00
|
|
|
if isinstance(args, str):
|
|
|
|
return args
|
|
|
|
if isinstance(args, unicode):
|
|
|
|
return args.encode('utf8')
|
2013-10-17 17:08:32 +02:00
|
|
|
cargs = {}
|
|
|
|
for arg in args:
|
|
|
|
rhs = args[arg]
|
|
|
|
if type(rhs) == type([]):
|
|
|
|
rhs = [convertHash(i) for i in rhs]
|
|
|
|
elif type(rhs) == type({}):
|
|
|
|
rhs = convertHash(rhs)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
rhs = rhs.encode('utf8')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
cargs[arg.encode('utf8')] = rhs
|
|
|
|
return cargs
|
|
|
|
|
2013-05-29 14:55:57 +02:00
|
|
|
|
2013-05-31 16:23:32 +02:00
|
|
|
def doit():
|
2013-05-22 14:30:36 +02:00
|
|
|
|
|
|
|
db = Dumper()
|
2013-07-09 14:49:38 +02:00
|
|
|
db.report('lldbversion="%s"' % lldb.SBDebugger.GetVersionString())
|
2013-05-02 14:31:35 +02:00
|
|
|
db.report('state="enginesetupok"')
|
2013-05-13 16:04:00 +02:00
|
|
|
|
2013-10-30 17:46:41 +01:00
|
|
|
line = sys.stdin.readline()
|
|
|
|
while line:
|
|
|
|
try:
|
|
|
|
db.execute(convertHash(json.loads(line)))
|
|
|
|
except:
|
2014-02-06 15:18:21 +01:00
|
|
|
(exType, exValue, exTraceback) = sys.exc_info()
|
|
|
|
showException("MAIN LOOP", exType, exValue, exTraceback)
|
2013-10-30 17:46:41 +01:00
|
|
|
line = sys.stdin.readline()
|
2013-05-31 16:23:32 +02:00
|
|
|
|
2013-05-16 17:37:41 +02:00
|
|
|
|
2013-06-04 10:44:20 +02:00
|
|
|
# Used in dumper auto test.
|
2013-09-25 18:22:01 +02:00
|
|
|
# Usage: python lldbbridge.py /path/to/testbinary comma-separated-inames
|
2013-06-04 10:44:20 +02:00
|
|
|
def testit():
|
|
|
|
|
|
|
|
db = Dumper()
|
|
|
|
|
|
|
|
# Disable intermediate reporting.
|
|
|
|
savedReport = db.report
|
|
|
|
db.report = lambda stuff: 0
|
|
|
|
|
|
|
|
db.debugger.SetAsync(False)
|
|
|
|
db.expandedINames = set(sys.argv[3].split(','))
|
2013-11-04 16:56:04 +01:00
|
|
|
db.passExceptions = True
|
2013-06-04 10:44:20 +02:00
|
|
|
|
|
|
|
db.setupInferior({'cmd':'setupInferior','executable':sys.argv[2],'token':1})
|
|
|
|
|
2014-01-17 16:13:03 +01:00
|
|
|
launchInfo = lldb.SBLaunchInfo([])
|
|
|
|
launchInfo.SetWorkingDirectory(os.getcwd())
|
|
|
|
environmentList = [key + "=" + value for key,value in os.environ.items()]
|
|
|
|
launchInfo.SetEnvironmentEntries(environmentList, False)
|
|
|
|
|
2013-06-04 10:44:20 +02:00
|
|
|
error = lldb.SBError()
|
2014-01-17 16:13:03 +01:00
|
|
|
db.process = db.target.Launch(launchInfo, error)
|
2013-06-04 10:44:20 +02:00
|
|
|
|
2014-01-16 17:25:29 +01:00
|
|
|
stoppedThread = db.firstStoppedThread()
|
|
|
|
if stoppedThread:
|
|
|
|
db.process.SetSelectedThread(stoppedThread)
|
|
|
|
|
2013-06-04 10:44:20 +02:00
|
|
|
db.report = savedReport
|
2014-01-09 16:23:17 +01:00
|
|
|
ns = db.qtNamespace()
|
2013-06-04 10:44:20 +02:00
|
|
|
db.reportVariables()
|
2014-01-09 16:23:17 +01:00
|
|
|
db.report("@NS@%s@" % ns)
|
2014-01-17 16:13:03 +01:00
|
|
|
#db.report("ENV=%s" % os.environ.items())
|
2014-01-16 17:25:29 +01:00
|
|
|
#db.report("DUMPER=%s" % db.qqDumpers)
|
2013-06-04 10:44:20 +02:00
|
|
|
|
2013-10-31 10:06:14 +01:00
|
|
|
if __name__ == "__main__":
|
|
|
|
if len(sys.argv) > 2:
|
|
|
|
testit()
|
|
|
|
else:
|
|
|
|
doit()
|
2013-06-11 18:55:09 +02:00
|
|
|
|