forked from qt-creator/qt-creator
Debugger: Create a copy of the current dumper code
The current code supports Python 2 and Python 3 based debugger backends (gdb, lldb) at the same time, but we'd like to drop Python 2 support so we can take advantage of some of Python 3's goodies. This copy here is not meant to be used in general but could perhaps be used to replace the main code in situations that cannot use Python 3 yet. Change-Id: I62273bc41b5a1e3a24720e167e64e4eac2e0c056 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
8
share/qtcreator/debugger/python2/README.txt
Normal file
8
share/qtcreator/debugger/python2/README.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
This is a copy of a previous version of share/qtcreator/debugger/*.py
|
||||||
|
which supported Python 2 and Python 3 based debugger backends (gdb,
|
||||||
|
lldb) at the same time.
|
||||||
|
|
||||||
|
The code there is now Python-3-only. This copy here is not meant to be
|
||||||
|
used in general but could perhaps be used to replace the main code
|
||||||
|
in situations that cannot use Python 3 yet.
|
133
share/qtcreator/debugger/python2/android_stdtypes.py
Normal file
133
share/qtcreator/debugger/python2/android_stdtypes.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
# Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
|
||||||
|
from dumper import DumperBase
|
||||||
|
from utils import DisplayFormat
|
||||||
|
|
||||||
|
import stdtypes
|
||||||
|
import libcpp_stdtypes
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__array():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__array(d, value):
|
||||||
|
stdtypes.qdump__std__array(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__complex(d, value):
|
||||||
|
stdtypes.qdump__std__complex(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__deque(d, value):
|
||||||
|
stdtypes.qdumpHelper__std__deque__libcxx(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__list(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__list(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__set(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__multiset(d, value):
|
||||||
|
qdump__std____ndk1__set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__map():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__map(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__map(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__multimap():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__multimap(d, value):
|
||||||
|
qdump__std____ndk1__map(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__map__iterator(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__map__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__map__const_iterator(d, value):
|
||||||
|
qdump__std____ndk1__map__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__set__iterator(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__set__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__set_const_iterator(d, value):
|
||||||
|
qdump__std____ndk1__set__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__stack(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__stack(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__string(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__string(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__wstring(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__wstring(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__basic_string(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__basic_string(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__shared_ptr(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__shared_ptr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__weak_ptr(d, value):
|
||||||
|
return qdump__std____ndk1__shared_ptr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__unique_ptr(d, value):
|
||||||
|
stdtypes.qdump__std__unique_ptr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__unordered_map():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__unordered_map(d, value):
|
||||||
|
libcpp_stdtypes.qdump__std____1__unordered_map(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__unordered_set(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__unordered_set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__unordered_multiset(d, value):
|
||||||
|
qdump__std____ndk1__unordered_set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__valarray():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__valarray(d, value):
|
||||||
|
return libcpp_stdtypes.qdump__std____1__valarray(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____ndk1__vector():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__vector(d, value):
|
||||||
|
stdtypes.qdumpHelper__std__vector__libcxx(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____ndk1__once_flag(d, value):
|
||||||
|
stdtypes.qdump__std__once_flag(d, value)
|
184
share/qtcreator/debugger/python2/boosttypes.py
Normal file
184
share/qtcreator/debugger/python2/boosttypes.py
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
from utils import DisplayFormat
|
||||||
|
from dumper import Children
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__bimaps__bimap(d, value):
|
||||||
|
#leftType = value.type[0]
|
||||||
|
#rightType = value.type[1]
|
||||||
|
size = value["core"]["node_count"].integer()
|
||||||
|
d.putItemCount(size)
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__optional(d, value):
|
||||||
|
innerType = value.type[0]
|
||||||
|
(initialized, pad, payload) = d.split('b@{%s}' % innerType.name, value)
|
||||||
|
if initialized:
|
||||||
|
d.putItem(payload)
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
else:
|
||||||
|
d.putSpecialValue("uninitialized")
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__shared_ptr(d, value):
|
||||||
|
# s boost::shared_ptr<int>
|
||||||
|
# px 0x0 int *
|
||||||
|
# pn boost::detail::shared_count
|
||||||
|
# pi_ 0x0 boost::detail::sp_counted_base *
|
||||||
|
(px, pi) = value.split("pp")
|
||||||
|
if pi == 0:
|
||||||
|
d.putValue("(null)")
|
||||||
|
return
|
||||||
|
|
||||||
|
if px == 0:
|
||||||
|
d.putValue("(null)")
|
||||||
|
return
|
||||||
|
|
||||||
|
(vptr, usecount, weakcount) = d.split('pii', pi)
|
||||||
|
d.check(weakcount >= 0)
|
||||||
|
d.check(weakcount <= usecount)
|
||||||
|
d.check(usecount <= 10 * 1000 * 1000)
|
||||||
|
d.putItem(d.createValue(px, value.type[0]))
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__container__list(d, value):
|
||||||
|
try:
|
||||||
|
m_icont = value["m_icont"]
|
||||||
|
except:
|
||||||
|
m_icont = value["members_"]["m_icont"]
|
||||||
|
r = m_icont["data_"]["root_plus_size_"]
|
||||||
|
n = r["size_"].integer()
|
||||||
|
d.putItemCount(n)
|
||||||
|
if d.isExpanded():
|
||||||
|
innerType = value.type[0]
|
||||||
|
offset = 2 * d.ptrSize()
|
||||||
|
with Children(d, n):
|
||||||
|
try:
|
||||||
|
root = r["root_"]
|
||||||
|
except:
|
||||||
|
root = r["m_header"]
|
||||||
|
p = root["next_"].extractPointer()
|
||||||
|
for i in d.childRange():
|
||||||
|
d.putSubItem(i, d.createValue(p + offset, innerType))
|
||||||
|
p = d.extractPointer(p)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__boost__container__vector():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__container__vector(d, value):
|
||||||
|
holder = value["m_holder"]
|
||||||
|
size = holder["m_size"].integer()
|
||||||
|
d.putItemCount(size)
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
T = value.type[0]
|
||||||
|
try:
|
||||||
|
start = holder["m_start"].pointer()
|
||||||
|
except:
|
||||||
|
start = holder["storage"].address()
|
||||||
|
d.putPlotData(start, size, T)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__boost__container__static_vector():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__container__static_vector(d, value):
|
||||||
|
qdump__boost__container__vector(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__boost__container__small_vector():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__container__small_vector(d, value):
|
||||||
|
qdump__boost__container__vector(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__gregorian__date(d, value):
|
||||||
|
d.putValue(value.integer(), "juliandate")
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__posix_time__ptime(d, value):
|
||||||
|
ms = int(value.integer() / 1000)
|
||||||
|
d.putValue("%s/%s" % divmod(ms, 86400000), "juliandateandmillisecondssincemidnight")
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__posix_time__time_duration(d, value):
|
||||||
|
d.putValue(int(value.integer() / 1000), "millisecondssincemidnight")
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__unordered__unordered_set(d, value):
|
||||||
|
innerType = value.type[0]
|
||||||
|
if value.type.size() == 7 * d.ptrSize(): # 56 for boost 1.79+
|
||||||
|
bases, bucketCount, bcountLog2, size, mlf, maxload, buckets = value.split('ttttttp')
|
||||||
|
forward = True
|
||||||
|
elif value.type.size() == 6 * d.ptrSize(): # 48 for boost 1.55+
|
||||||
|
# boost 1.58 or 1.55
|
||||||
|
# bases are 3? bytes, and mlf is actually a float, but since
|
||||||
|
# its followed by size_t maxload, it's # effectively padded to a size_t
|
||||||
|
bases, bucketCount, size, mlf, maxload, buckets = value.split('tttttp')
|
||||||
|
# Distinguish 1.58 and 1.55. 1.58 used one template argument, 1.55 two.
|
||||||
|
try:
|
||||||
|
ittype = d.lookupType(value.type.name + '::iterator').target()
|
||||||
|
forward = len(ittype.templateArguments()) == 1
|
||||||
|
except:
|
||||||
|
forward = True
|
||||||
|
elif value.type.size() == 5 * d.ptrSize(): # 40 for boost 1.48
|
||||||
|
# boost 1.48
|
||||||
|
# Values are stored before the next pointers. Determine the offset.
|
||||||
|
buckets, bucketCount, size, mlf, maxload = value.split('ptttt')
|
||||||
|
forward = False
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown boost::unordered_set layout")
|
||||||
|
|
||||||
|
if forward:
|
||||||
|
# boost >= 1.58
|
||||||
|
code = 'pp{%s}' % innerType.name
|
||||||
|
|
||||||
|
def children(p):
|
||||||
|
while True:
|
||||||
|
p, dummy, val = d.split(code, p)
|
||||||
|
yield val
|
||||||
|
else:
|
||||||
|
# boost 1.48 or 1.55
|
||||||
|
code = '{%s}@p' % innerType.name
|
||||||
|
(pp, ssize, fields) = d.describeStruct(code)
|
||||||
|
offset = fields[2].offset()
|
||||||
|
|
||||||
|
def children(p):
|
||||||
|
while True:
|
||||||
|
val, pad, p = d.split(code, p - offset)
|
||||||
|
yield val
|
||||||
|
|
||||||
|
p = d.extractPointer(buckets + bucketCount * d.ptrSize())
|
||||||
|
d.putItems(size, children(p), maxNumChild=10000)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__variant(d, value):
|
||||||
|
allTypes = value.type.templateArguments()
|
||||||
|
realType = allTypes[value.split('i')[0]]
|
||||||
|
alignment = max([t.alignment() for t in allTypes])
|
||||||
|
dummy, val = value.split('%is{%s}' % (max(4, alignment), realType.name))
|
||||||
|
d.putItem(val)
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__boost__container__devector(d, value):
|
||||||
|
inner_type = value.type[0]
|
||||||
|
buffer = value["m_"]["buffer"].pointer()
|
||||||
|
front_idx = value["m_"]["front_idx"].integer()
|
||||||
|
back_idx = value["m_"]["back_idx"].integer()
|
||||||
|
start = buffer + (front_idx * inner_type.size())
|
||||||
|
size = int(back_idx - front_idx)
|
||||||
|
if size > 0:
|
||||||
|
d.checkPointer(start)
|
||||||
|
d.putItemCount(size)
|
||||||
|
d.putPlotData(start, size, inner_type)
|
514
share/qtcreator/debugger/python2/cdbbridge.py
Normal file
514
share/qtcreator/debugger/python2/cdbbridge.py
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import cdbext
|
||||||
|
import re
|
||||||
|
import threading
|
||||||
|
from utils import TypeCode
|
||||||
|
|
||||||
|
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
||||||
|
|
||||||
|
from dumper import DumperBase, SubItem
|
||||||
|
|
||||||
|
|
||||||
|
class FakeVoidType(cdbext.Type):
|
||||||
|
def __init__(self, name, dumper):
|
||||||
|
cdbext.Type.__init__(self)
|
||||||
|
self.typeName = name.strip()
|
||||||
|
self.dumper = dumper
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return self.typeName
|
||||||
|
|
||||||
|
def bitsize(self):
|
||||||
|
return self.dumper.ptrSize() * 8
|
||||||
|
|
||||||
|
def code(self):
|
||||||
|
if self.typeName.endswith('*'):
|
||||||
|
return TypeCode.Pointer
|
||||||
|
if self.typeName.endswith(']'):
|
||||||
|
return TypeCode.Array
|
||||||
|
return TypeCode.Void
|
||||||
|
|
||||||
|
def unqualified(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def target(self):
|
||||||
|
code = self.code()
|
||||||
|
if code == TypeCode.Pointer:
|
||||||
|
return FakeVoidType(self.typeName[:-1], self.dumper)
|
||||||
|
if code == TypeCode.Void:
|
||||||
|
return self
|
||||||
|
try:
|
||||||
|
return FakeVoidType(self.typeName[:self.typeName.rindex('[')], self.dumper)
|
||||||
|
except:
|
||||||
|
return FakeVoidType('void', self.dumper)
|
||||||
|
|
||||||
|
def targetName(self):
|
||||||
|
return self.target().name()
|
||||||
|
|
||||||
|
def arrayElements(self):
|
||||||
|
try:
|
||||||
|
return int(self.typeName[self.typeName.rindex('[') + 1:self.typeName.rindex(']')])
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def stripTypedef(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def fields(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def templateArgument(self, pos, numeric):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def templateArguments(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class Dumper(DumperBase):
|
||||||
|
def __init__(self):
|
||||||
|
DumperBase.__init__(self)
|
||||||
|
self.outputLock = threading.Lock()
|
||||||
|
self.isCdb = True
|
||||||
|
|
||||||
|
def enumValue(self, nativeValue):
|
||||||
|
val = nativeValue.nativeDebuggerValue()
|
||||||
|
# remove '0n' decimal prefix of the native cdb value output
|
||||||
|
return val.replace('(0n', '(')
|
||||||
|
|
||||||
|
def fromNativeValue(self, nativeValue):
|
||||||
|
self.check(isinstance(nativeValue, cdbext.Value))
|
||||||
|
val = self.Value(self)
|
||||||
|
val.name = nativeValue.name()
|
||||||
|
val._type = self.fromNativeType(nativeValue.type())
|
||||||
|
# There is no cdb api for the size of bitfields.
|
||||||
|
# Workaround this issue by parsing the native debugger text for integral types.
|
||||||
|
if val._type.code == TypeCode.Integral:
|
||||||
|
try:
|
||||||
|
integerString = nativeValue.nativeDebuggerValue()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
integerString = '' # cannot decode - read raw
|
||||||
|
if integerString == 'true':
|
||||||
|
val.ldata = int(1).to_bytes(1, byteorder='little')
|
||||||
|
elif integerString == 'false':
|
||||||
|
val.ldata = int(0).to_bytes(1, byteorder='little')
|
||||||
|
else:
|
||||||
|
integerString = integerString.replace('`', '')
|
||||||
|
integerString = integerString.split(' ')[0]
|
||||||
|
if integerString.startswith('0n'):
|
||||||
|
integerString = integerString[2:]
|
||||||
|
base = 10
|
||||||
|
elif integerString.startswith('0x'):
|
||||||
|
base = 16
|
||||||
|
else:
|
||||||
|
base = 10
|
||||||
|
signed = not val._type.name.startswith('unsigned')
|
||||||
|
try:
|
||||||
|
val.ldata = int(integerString, base).to_bytes(val._type.size(),
|
||||||
|
byteorder='little', signed=signed)
|
||||||
|
except:
|
||||||
|
# read raw memory in case the integerString can not be interpreted
|
||||||
|
pass
|
||||||
|
if val._type.code == TypeCode.Enum:
|
||||||
|
val.ldisplay = self.enumValue(nativeValue)
|
||||||
|
val.isBaseClass = val.name == val._type.name
|
||||||
|
val.nativeValue = nativeValue
|
||||||
|
val.laddress = nativeValue.address()
|
||||||
|
val.lbitsize = nativeValue.bitsize()
|
||||||
|
return val
|
||||||
|
|
||||||
|
def nativeTypeId(self, nativeType):
|
||||||
|
self.check(isinstance(nativeType, cdbext.Type))
|
||||||
|
name = nativeType.name()
|
||||||
|
if name is None or len(name) == 0:
|
||||||
|
c = '0'
|
||||||
|
elif name == 'struct {...}':
|
||||||
|
c = 's'
|
||||||
|
elif name == 'union {...}':
|
||||||
|
c = 'u'
|
||||||
|
else:
|
||||||
|
return name
|
||||||
|
typeId = c + ''.join(['{%s:%s}' % (f.name(), self.nativeTypeId(f.type()))
|
||||||
|
for f in nativeType.fields()])
|
||||||
|
return typeId
|
||||||
|
|
||||||
|
def fromNativeType(self, nativeType):
|
||||||
|
self.check(isinstance(nativeType, cdbext.Type))
|
||||||
|
typeId = self.nativeTypeId(nativeType)
|
||||||
|
if self.typeData.get(typeId, None) is not None:
|
||||||
|
return self.Type(self, typeId)
|
||||||
|
|
||||||
|
if nativeType.name().startswith('void'):
|
||||||
|
nativeType = FakeVoidType(nativeType.name(), self)
|
||||||
|
|
||||||
|
code = nativeType.code()
|
||||||
|
if code == TypeCode.Pointer:
|
||||||
|
if nativeType.name().startswith('<function>'):
|
||||||
|
code = TypeCode.Function
|
||||||
|
elif nativeType.targetName() != nativeType.name():
|
||||||
|
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
||||||
|
if targetType is not None and targetType is not nativeType:
|
||||||
|
return self.createPointerType(targetType)
|
||||||
|
|
||||||
|
if code == TypeCode.Array:
|
||||||
|
# cdb reports virtual function tables as arrays those ar handled separetly by
|
||||||
|
# the DumperBase. Declare those types as structs prevents a lookup to a
|
||||||
|
# none existing type
|
||||||
|
if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith('<gentype '):
|
||||||
|
targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId())
|
||||||
|
if targetType is not None:
|
||||||
|
return self.createArrayType(targetType, nativeType.arrayElements())
|
||||||
|
code = TypeCode.Struct
|
||||||
|
|
||||||
|
tdata = self.TypeData(self, typeId)
|
||||||
|
tdata.name = nativeType.name()
|
||||||
|
tdata.lbitsize = nativeType.bitsize()
|
||||||
|
tdata.code = code
|
||||||
|
tdata.moduleName = nativeType.module()
|
||||||
|
if code == TypeCode.Struct:
|
||||||
|
tdata.lfields = lambda value: \
|
||||||
|
self.listFields(nativeType, value)
|
||||||
|
tdata.lalignment = lambda: \
|
||||||
|
self.nativeStructAlignment(nativeType)
|
||||||
|
if code == TypeCode.Enum:
|
||||||
|
tdata.enumDisplay = lambda intval, addr, form: \
|
||||||
|
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||||
|
tdata.templateArguments = lambda: \
|
||||||
|
self.listTemplateParameters(nativeType.name())
|
||||||
|
return self.Type(self, typeId)
|
||||||
|
|
||||||
|
def listFields(self, nativeType, value):
|
||||||
|
if value.address() is None or value.address() == 0:
|
||||||
|
raise Exception("")
|
||||||
|
nativeValue = value.nativeValue
|
||||||
|
if nativeValue is None:
|
||||||
|
nativeValue = cdbext.createValue(value.address(), nativeType)
|
||||||
|
index = 0
|
||||||
|
nativeMember = nativeValue.childFromIndex(index)
|
||||||
|
while nativeMember is not None:
|
||||||
|
yield self.fromNativeValue(nativeMember)
|
||||||
|
index += 1
|
||||||
|
nativeMember = nativeValue.childFromIndex(index)
|
||||||
|
|
||||||
|
def nativeStructAlignment(self, nativeType):
|
||||||
|
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
||||||
|
def handleItem(nativeFieldType, align):
|
||||||
|
a = self.fromNativeType(nativeFieldType).alignment()
|
||||||
|
return a if a > align else align
|
||||||
|
align = 1
|
||||||
|
for f in nativeType.fields():
|
||||||
|
align = handleItem(f.type(), align)
|
||||||
|
return align
|
||||||
|
|
||||||
|
def nativeTypeEnumDisplay(self, nativeType, intval, form):
|
||||||
|
value = self.nativeParseAndEvaluate('(%s)%d' % (nativeType.name(), intval))
|
||||||
|
if value is None:
|
||||||
|
return ''
|
||||||
|
return self.enumValue(value)
|
||||||
|
|
||||||
|
def enumExpression(self, enumType, enumValue):
|
||||||
|
ns = self.qtNamespace()
|
||||||
|
return ns + "Qt::" + enumType + "(" \
|
||||||
|
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
|
||||||
|
|
||||||
|
def pokeValue(self, typeName, *args):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parseAndEvaluate(self, exp):
|
||||||
|
return self.fromNativeValue(self.nativeParseAndEvaluate(exp))
|
||||||
|
|
||||||
|
def nativeParseAndEvaluate(self, exp):
|
||||||
|
return cdbext.parseAndEvaluate(exp)
|
||||||
|
|
||||||
|
def isWindowsTarget(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isQnxTarget(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isArmArchitecture(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isMsvcTarget(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def qtCoreModuleName(self):
|
||||||
|
modules = cdbext.listOfModules()
|
||||||
|
# first check for an exact module name match
|
||||||
|
for coreName in ['Qt6Core', 'Qt6Cored', 'Qt5Cored', 'Qt5Core', 'QtCored4', 'QtCore4']:
|
||||||
|
if coreName in modules:
|
||||||
|
self.qtCoreModuleName = lambda: coreName
|
||||||
|
return coreName
|
||||||
|
# maybe we have a libinfix build.
|
||||||
|
for pattern in ['Qt6Core.*', 'Qt5Core.*', 'QtCore.*']:
|
||||||
|
matches = [module for module in modules if re.match(pattern, module)]
|
||||||
|
if matches:
|
||||||
|
coreName = matches[0]
|
||||||
|
self.qtCoreModuleName = lambda: coreName
|
||||||
|
return coreName
|
||||||
|
return None
|
||||||
|
|
||||||
|
def qtDeclarativeModuleName(self):
|
||||||
|
modules = cdbext.listOfModules()
|
||||||
|
for declarativeModuleName in ['Qt6Qmld', 'Qt6Qml', 'Qt5Qmld', 'Qt5Qml']:
|
||||||
|
if declarativeModuleName in modules:
|
||||||
|
self.qtDeclarativeModuleName = lambda: declarativeModuleName
|
||||||
|
return declarativeModuleName
|
||||||
|
matches = [module for module in modules if re.match('Qt[56]Qml.*', module)]
|
||||||
|
if matches:
|
||||||
|
declarativeModuleName = matches[0]
|
||||||
|
self.qtDeclarativeModuleName = lambda: declarativeModuleName
|
||||||
|
return declarativeModuleName
|
||||||
|
return None
|
||||||
|
|
||||||
|
def qtHookDataSymbolName(self):
|
||||||
|
hookSymbolName = 'qtHookData'
|
||||||
|
coreModuleName = self.qtCoreModuleName()
|
||||||
|
if coreModuleName is not None:
|
||||||
|
hookSymbolName = '%s!%s%s' % (coreModuleName, self.qtNamespace(), hookSymbolName)
|
||||||
|
else:
|
||||||
|
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
|
||||||
|
if resolved:
|
||||||
|
hookSymbolName = resolved[0]
|
||||||
|
else:
|
||||||
|
hookSymbolName = '*%s' % hookSymbolName
|
||||||
|
self.qtHookDataSymbolName = lambda: hookSymbolName
|
||||||
|
return hookSymbolName
|
||||||
|
|
||||||
|
def qtDeclarativeHookDataSymbolName(self):
|
||||||
|
hookSymbolName = 'qtDeclarativeHookData'
|
||||||
|
declarativeModuleName = self.qtDeclarativeModuleName()
|
||||||
|
if declarativeModuleName is not None:
|
||||||
|
hookSymbolName = '%s!%s%s' % (declarativeModuleName, self.qtNamespace(), hookSymbolName)
|
||||||
|
else:
|
||||||
|
resolved = cdbext.resolveSymbol('*' + hookSymbolName)
|
||||||
|
if resolved:
|
||||||
|
hookSymbolName = resolved[0]
|
||||||
|
else:
|
||||||
|
hookSymbolName = '*%s' % hookSymbolName
|
||||||
|
|
||||||
|
self.qtDeclarativeHookDataSymbolName = lambda: hookSymbolName
|
||||||
|
return hookSymbolName
|
||||||
|
|
||||||
|
def qtNamespace(self):
|
||||||
|
namespace = ''
|
||||||
|
qstrdupSymbolName = '*qstrdup'
|
||||||
|
coreModuleName = self.qtCoreModuleName()
|
||||||
|
if coreModuleName is not None:
|
||||||
|
qstrdupSymbolName = '%s!%s' % (coreModuleName, qstrdupSymbolName)
|
||||||
|
resolved = cdbext.resolveSymbol(qstrdupSymbolName)
|
||||||
|
if resolved:
|
||||||
|
name = resolved[0].split('!')[1]
|
||||||
|
namespaceIndex = name.find('::')
|
||||||
|
if namespaceIndex > 0:
|
||||||
|
namespace = name[:namespaceIndex + 2]
|
||||||
|
self.qtCustomEventFunc = self.parseAndEvaluate(
|
||||||
|
'%s!%sQObject::customEvent' %
|
||||||
|
(self.qtCoreModuleName(), namespace)).address()
|
||||||
|
self.qtNamespace = lambda: namespace
|
||||||
|
return namespace
|
||||||
|
|
||||||
|
def qtVersion(self):
|
||||||
|
qtVersion = None
|
||||||
|
try:
|
||||||
|
qtVersion = self.parseAndEvaluate(
|
||||||
|
'((void**)&%s)[2]' % self.qtHookDataSymbolName()).integer()
|
||||||
|
except:
|
||||||
|
if self.qtCoreModuleName() is not None:
|
||||||
|
try:
|
||||||
|
versionValue = cdbext.call(self.qtCoreModuleName() + '!qVersion()')
|
||||||
|
version = self.extractCString(self.fromNativeValue(versionValue).address())
|
||||||
|
(major, minor, patch) = version.decode('latin1').split('.')
|
||||||
|
qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if qtVersion is None:
|
||||||
|
qtVersion = self.fallbackQtVersion
|
||||||
|
self.qtVersion = lambda: qtVersion
|
||||||
|
return qtVersion
|
||||||
|
|
||||||
|
def putVtableItem(self, address):
|
||||||
|
funcName = cdbext.getNameByAddress(address)
|
||||||
|
if funcName is None:
|
||||||
|
self.putItem(self.createPointerValue(address, 'void'))
|
||||||
|
else:
|
||||||
|
self.putValue(funcName)
|
||||||
|
self.putType('void*')
|
||||||
|
self.putAddress(address)
|
||||||
|
|
||||||
|
def putVTableChildren(self, item, itemCount):
|
||||||
|
p = item.address()
|
||||||
|
for i in range(itemCount):
|
||||||
|
deref = self.extractPointer(p)
|
||||||
|
if deref == 0:
|
||||||
|
n = i
|
||||||
|
break
|
||||||
|
with SubItem(self, i):
|
||||||
|
self.putVtableItem(deref)
|
||||||
|
p += self.ptrSize()
|
||||||
|
return itemCount
|
||||||
|
|
||||||
|
def ptrSize(self):
|
||||||
|
size = cdbext.pointerSize()
|
||||||
|
self.ptrSize = lambda: size
|
||||||
|
return size
|
||||||
|
|
||||||
|
def stripQintTypedefs(self, typeName):
|
||||||
|
if typeName.startswith('qint'):
|
||||||
|
prefix = ''
|
||||||
|
size = typeName[4:]
|
||||||
|
elif typeName.startswith('quint'):
|
||||||
|
prefix = 'unsigned '
|
||||||
|
size = typeName[5:]
|
||||||
|
else:
|
||||||
|
return typeName
|
||||||
|
if size == '8':
|
||||||
|
return '%schar' % prefix
|
||||||
|
elif size == '16':
|
||||||
|
return '%sshort' % prefix
|
||||||
|
elif size == '32':
|
||||||
|
return '%sint' % prefix
|
||||||
|
elif size == '64':
|
||||||
|
return '%sint64' % prefix
|
||||||
|
else:
|
||||||
|
return typeName
|
||||||
|
|
||||||
|
def lookupType(self, typeNameIn, module=0):
|
||||||
|
if len(typeNameIn) == 0:
|
||||||
|
return None
|
||||||
|
typeName = self.stripQintTypedefs(typeNameIn)
|
||||||
|
if self.typeData.get(typeName, None) is None:
|
||||||
|
nativeType = self.lookupNativeType(typeName, module)
|
||||||
|
if nativeType is None:
|
||||||
|
return None
|
||||||
|
_type = self.fromNativeType(nativeType)
|
||||||
|
if _type.typeId != typeName:
|
||||||
|
self.registerTypeAlias(_type.typeId, typeName)
|
||||||
|
return _type
|
||||||
|
return self.Type(self, typeName)
|
||||||
|
|
||||||
|
def lookupNativeType(self, name, module=0):
|
||||||
|
if name.startswith('void'):
|
||||||
|
return FakeVoidType(name, self)
|
||||||
|
return cdbext.lookupType(name, module)
|
||||||
|
|
||||||
|
def reportResult(self, result, args):
|
||||||
|
cdbext.reportResult('result={%s}' % result)
|
||||||
|
|
||||||
|
def readRawMemory(self, address, size):
|
||||||
|
mem = cdbext.readRawMemory(address, size)
|
||||||
|
if len(mem) != size:
|
||||||
|
raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
|
||||||
|
return mem
|
||||||
|
|
||||||
|
def findStaticMetaObject(self, type):
|
||||||
|
typeName = type.name
|
||||||
|
if type.moduleName is not None:
|
||||||
|
typeName = type.moduleName + '!' + typeName
|
||||||
|
ptr = cdbext.getAddressByName(typeName + '::staticMetaObject')
|
||||||
|
return ptr
|
||||||
|
|
||||||
|
def warn(self, msg):
|
||||||
|
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
|
||||||
|
|
||||||
|
def fetchVariables(self, args):
|
||||||
|
self.resetStats()
|
||||||
|
(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||||
|
if ok:
|
||||||
|
self.reportResult(res, args)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.setVariableFetchingOptions(args)
|
||||||
|
|
||||||
|
self.output = []
|
||||||
|
|
||||||
|
self.currentIName = 'local'
|
||||||
|
self.put('data=[')
|
||||||
|
self.anonNumber = 0
|
||||||
|
|
||||||
|
variables = []
|
||||||
|
for val in cdbext.listOfLocals(self.partialVariable):
|
||||||
|
dumperVal = self.fromNativeValue(val)
|
||||||
|
dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
|
||||||
|
variables.append(dumperVal)
|
||||||
|
|
||||||
|
self.handleLocals(variables)
|
||||||
|
self.handleWatches(args)
|
||||||
|
|
||||||
|
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
|
||||||
|
self.put(',timings=%s' % self.timings)
|
||||||
|
|
||||||
|
if self.forceQtNamespace:
|
||||||
|
self.qtNamespaceToReport = self.qtNamespace()
|
||||||
|
|
||||||
|
if self.qtNamespaceToReport:
|
||||||
|
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
||||||
|
self.qtNamespaceToReport = None
|
||||||
|
|
||||||
|
self.reportResult(''.join(self.output), args)
|
||||||
|
self.output = []
|
||||||
|
|
||||||
|
def report(self, stuff):
|
||||||
|
sys.stdout.write(stuff + "\n")
|
||||||
|
|
||||||
|
def findValueByExpression(self, exp):
|
||||||
|
return cdbext.parseAndEvaluate(exp)
|
||||||
|
|
||||||
|
def nativeDynamicTypeName(self, address, baseType):
|
||||||
|
return None # Does not work with cdb
|
||||||
|
|
||||||
|
def nativeValueDereferenceReference(self, value):
|
||||||
|
return self.nativeValueDereferencePointer(value)
|
||||||
|
|
||||||
|
def nativeValueDereferencePointer(self, value):
|
||||||
|
def nativeVtCastValue(nativeValue):
|
||||||
|
# If we have a pointer to a derived instance of the pointer type cdb adds a
|
||||||
|
# synthetic '__vtcast_<derived type name>' member as the first child
|
||||||
|
if nativeValue.hasChildren():
|
||||||
|
vtcastCandidate = nativeValue.childFromIndex(0)
|
||||||
|
vtcastCandidateName = vtcastCandidate.name()
|
||||||
|
if vtcastCandidateName.startswith('__vtcast_'):
|
||||||
|
# found a __vtcast member
|
||||||
|
# make sure that it is not an actual field
|
||||||
|
for field in nativeValue.type().fields():
|
||||||
|
if field.name() == vtcastCandidateName:
|
||||||
|
return None
|
||||||
|
return vtcastCandidate
|
||||||
|
return None
|
||||||
|
|
||||||
|
nativeValue = value.nativeValue
|
||||||
|
if nativeValue is None:
|
||||||
|
if not self.isExpanded():
|
||||||
|
raise Exception("Casting not expanded values is to expensive")
|
||||||
|
nativeValue = self.nativeParseAndEvaluate('(%s)0x%x' % (value.type.name, value.pointer()))
|
||||||
|
castVal = nativeVtCastValue(nativeValue)
|
||||||
|
if castVal is not None:
|
||||||
|
val = self.fromNativeValue(castVal)
|
||||||
|
else:
|
||||||
|
val = self.Value(self)
|
||||||
|
val.laddress = value.pointer()
|
||||||
|
val._type = value.type.dereference()
|
||||||
|
val.nativeValue = value.nativeValue
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
|
def callHelper(self, rettype, value, function, args):
|
||||||
|
raise Exception("cdb does not support calling functions")
|
||||||
|
|
||||||
|
def nameForCoreId(self, id):
|
||||||
|
for dll in ['Utilsd', 'Utils']:
|
||||||
|
idName = cdbext.call('%s!Utils::nameForId(%d)' % (dll, id))
|
||||||
|
if idName is not None:
|
||||||
|
break
|
||||||
|
return self.fromNativeValue(idName)
|
||||||
|
|
||||||
|
def putCallItem(self, name, rettype, value, func, *args):
|
||||||
|
return
|
||||||
|
|
||||||
|
def symbolAddress(self, symbolName):
|
||||||
|
res = self.nativeParseAndEvaluate(symbolName)
|
||||||
|
return None if res is None else res.address()
|
371
share/qtcreator/debugger/python2/creatortypes.py
Normal file
371
share/qtcreator/debugger/python2/creatortypes.py
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
from dumper import Children
|
||||||
|
|
||||||
|
|
||||||
|
def typeTarget(type):
|
||||||
|
target = type.target()
|
||||||
|
if target:
|
||||||
|
return target
|
||||||
|
return type
|
||||||
|
|
||||||
|
|
||||||
|
def stripTypeName(value):
|
||||||
|
return typeTarget(value.type).unqualified().name
|
||||||
|
|
||||||
|
|
||||||
|
def extractPointerType(d, value):
|
||||||
|
postfix = ""
|
||||||
|
while stripTypeName(value) == "CPlusPlus::PointerType":
|
||||||
|
postfix += "*"
|
||||||
|
value = value["_elementType"]["_type"]
|
||||||
|
try:
|
||||||
|
return readLiteral(d, value["_name"]) + postfix
|
||||||
|
except:
|
||||||
|
typeName = typeTarget(value.type.unqualified()).name
|
||||||
|
if typeName == "CPlusPlus::IntegerType":
|
||||||
|
return "int" + postfix
|
||||||
|
elif typeName == "CPlusPlus::VoidType":
|
||||||
|
return "void" + postfix
|
||||||
|
return "<unsupported>"
|
||||||
|
|
||||||
|
|
||||||
|
def readTemplateName(d, value):
|
||||||
|
name = readLiteral(d, value["_identifier"]) + "<"
|
||||||
|
args = value["_templateArguments"]
|
||||||
|
impl = args["_M_impl"]
|
||||||
|
start = impl["_M_start"]
|
||||||
|
size = impl["_M_finish"] - start
|
||||||
|
try:
|
||||||
|
d.check(0 <= size and size <= 100)
|
||||||
|
d.checkPointer(start)
|
||||||
|
for i in range(int(size)):
|
||||||
|
if i > 0:
|
||||||
|
name += ", "
|
||||||
|
name += extractPointerType(d, start[i]["_type"])
|
||||||
|
except:
|
||||||
|
return "<not accessible>"
|
||||||
|
name += ">"
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def readLiteral(d, value):
|
||||||
|
if not value.integer():
|
||||||
|
return "<null>"
|
||||||
|
type = typeTarget(value.type.unqualified())
|
||||||
|
if type and (type.name == "CPlusPlus::TemplateNameId"):
|
||||||
|
return readTemplateName(d, value)
|
||||||
|
elif type and (type.name == "CPlusPlus::QualifiedNameId"):
|
||||||
|
return readLiteral(d, value["_base"]) + "::" + readLiteral(d, value["_name"])
|
||||||
|
try:
|
||||||
|
return bytes(d.readRawMemory(value["_chars"], value["_size"])).decode('latin1')
|
||||||
|
except:
|
||||||
|
return "<unsupported>"
|
||||||
|
|
||||||
|
|
||||||
|
def dumpLiteral(d, value):
|
||||||
|
d.putValue(d.hexencode(readLiteral(d, value)), "latin1")
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__Id(d, value):
|
||||||
|
val = value.extractPointer()
|
||||||
|
if True:
|
||||||
|
if d.isMsvcTarget():
|
||||||
|
name = d.nameForCoreId(val).address()
|
||||||
|
else:
|
||||||
|
name = d.parseAndEvaluate("Utils::nameForId(0x%x)" % val).pointer()
|
||||||
|
d.putSimpleCharArray(name)
|
||||||
|
else:
|
||||||
|
d.putValue(val)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__Key(d, value):
|
||||||
|
d.putByteArrayValue(value["data"])
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__GdbMi(d, value):
|
||||||
|
val = d.encodeString(value["m_name"]) + "3a002000" \
|
||||||
|
+ d.encodeString(value["m_data"])
|
||||||
|
d.putValue(val, "utf16")
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__DisassemblerLine(d, value):
|
||||||
|
d.putByteArrayValue(value["m_data"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__WatchData(d, value):
|
||||||
|
d.putStringValue(value["iname"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__WatchItem(d, value):
|
||||||
|
d.putStringValue(value["iname"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__BreakpointModelId(d, value):
|
||||||
|
d.putValue("%s.%s" % (value["m_majorPart"].integer(), value["m_minorPart"].integer()))
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Debugger__Internal__ThreadId(d, value):
|
||||||
|
d.putValue("%s" % value["m_id"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__ByteArrayRef(d, value):
|
||||||
|
d.putSimpleCharArray(value["m_start"], value["m_length"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Identifier(d, value):
|
||||||
|
try:
|
||||||
|
d.putSimpleCharArray(value["_chars"], value["_size"])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Symbol(d, value):
|
||||||
|
dumpLiteral(d, value["_name"])
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Class(d, value):
|
||||||
|
qdump__CPlusPlus__Symbol(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def kindName(d, value):
|
||||||
|
e = value.integer()
|
||||||
|
if e:
|
||||||
|
kindType = d.lookupType("CPlusPlus::Kind")
|
||||||
|
return kindType.tdata.enumDisplay(e, value.address(), '%d')[11:]
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__IntegerType(d, value):
|
||||||
|
d.putValue(kindName(d, value["_kind"]))
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__FullySpecifiedType(d, value):
|
||||||
|
type = value["_type"]
|
||||||
|
typeName = stripTypeName(type)
|
||||||
|
if typeName == "CPlusPlus::NamedType":
|
||||||
|
dumpLiteral(d, type["_name"])
|
||||||
|
elif typeName == "CPlusPlus::PointerType":
|
||||||
|
d.putValue(d.hexencode(extractPointerType(d, type)), "latin1")
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__NamedType(d, value):
|
||||||
|
dumpLiteral(d, value["_name"])
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__PointerType(d, value):
|
||||||
|
d.putValue(d.hexencode(extractPointerType(d, value)), "latin1")
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__TemplateNameId(d, value):
|
||||||
|
dumpLiteral(d, value)
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__QualifiedNameId(d, value):
|
||||||
|
dumpLiteral(d, value)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Literal(d, value):
|
||||||
|
dumpLiteral(d, value)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__StringLiteral(d, value):
|
||||||
|
d.putSimpleCharArray(value["_chars"], value["_size"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Internal__Value(d, value):
|
||||||
|
d.putValue(value["l"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__FilePath(d, value):
|
||||||
|
data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value)
|
||||||
|
elided, enc = d.encodeStringHelper(data, d.displayStringLimit)
|
||||||
|
# enc is concatenated path + scheme + host
|
||||||
|
if scheme_len:
|
||||||
|
scheme_pos = path_len * 4
|
||||||
|
host_pos = scheme_pos + scheme_len * 4
|
||||||
|
path_enc = enc[0 : path_len * 4]
|
||||||
|
scheme_enc = enc[scheme_pos : scheme_pos + scheme_len * 4]
|
||||||
|
host_enc = enc[host_pos : host_pos + host_len * 4]
|
||||||
|
slash = "2F00"
|
||||||
|
dot = "2E00"
|
||||||
|
colon = "3A00"
|
||||||
|
val = scheme_enc + colon + slash + slash + host_enc
|
||||||
|
if not path_enc.startswith(slash):
|
||||||
|
val += slash + dot + slash
|
||||||
|
val += path_enc
|
||||||
|
else:
|
||||||
|
val = enc
|
||||||
|
d.putValue(val, "utf16", elided=elided)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__FileName(d, value):
|
||||||
|
qdump__Utils__FilePath(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__ElfSection(d, value):
|
||||||
|
d.putByteArrayValue(value["name"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__Port(d, value):
|
||||||
|
d.putValue(d.extractInt(value))
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def x_qdump__Utils__Environment(d, value):
|
||||||
|
qdump__Utils__NameValueDictionary(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__DictKey(d, value):
|
||||||
|
d.putStringValue(value["name"])
|
||||||
|
|
||||||
|
|
||||||
|
def x_qdump__Utils__NameValueDictionary(d, value):
|
||||||
|
dptr = d.extractPointer(value)
|
||||||
|
if d.qtVersion() >= 0x60000:
|
||||||
|
if dptr == 0:
|
||||||
|
d.putItemCount(0)
|
||||||
|
return
|
||||||
|
m = value['d']['d']['m']
|
||||||
|
d.putItem(m)
|
||||||
|
d.putBetterType('Utils::NameValueDictionary')
|
||||||
|
else: # Qt5
|
||||||
|
(ref, n) = d.split('ii', dptr)
|
||||||
|
d.check(0 <= n and n <= 100 * 1000 * 1000)
|
||||||
|
d.check(-1 <= ref and ref < 100000)
|
||||||
|
|
||||||
|
d.putItemCount(n)
|
||||||
|
if d.isExpanded():
|
||||||
|
if n > 10000:
|
||||||
|
n = 10000
|
||||||
|
|
||||||
|
typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "@QPair<@QString,bool>")
|
||||||
|
|
||||||
|
def helper(node):
|
||||||
|
(p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)
|
||||||
|
if left:
|
||||||
|
for res in helper(left):
|
||||||
|
yield res
|
||||||
|
yield (key["name"], value)
|
||||||
|
if right:
|
||||||
|
for res in helper(right):
|
||||||
|
yield res
|
||||||
|
|
||||||
|
with Children(d, n):
|
||||||
|
for (pair, i) in zip(helper(dptr + 8), range(n)):
|
||||||
|
d.putPairItem(i, pair, 'key', 'value')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utf8String(d, value):
|
||||||
|
d.putByteArrayValue(value['byteArray'])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Token(d, value):
|
||||||
|
k = value["f"]["kind"]
|
||||||
|
e = k.lvalue
|
||||||
|
type = kindName(d, k)
|
||||||
|
try:
|
||||||
|
if e == 6:
|
||||||
|
type = readLiteral(d, value["identifier"]) + " (%s)" % type
|
||||||
|
elif e >= 7 and e <= 23:
|
||||||
|
type = readLiteral(d, value["literal"]) + " (%s)" % type
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
d.putValue(type)
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CPlusPlus__Internal__PPToken(d, value):
|
||||||
|
data, size, alloc = d.qArrayData(value["m_src"])
|
||||||
|
length = value["f"]["utf16chars"].integer()
|
||||||
|
offset = value["utf16charOffset"].integer()
|
||||||
|
#DumperBase.warn("size: %s, alloc: %s, offset: %s, length: %s, data: %s"
|
||||||
|
# % (size, alloc, offset, length, data))
|
||||||
|
d.putValue(d.readMemory(data + offset, min(100, length)), "latin1")
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__ProString(d, value):
|
||||||
|
try:
|
||||||
|
s = value["m_string"]
|
||||||
|
data, size, alloc = d.stringData(s)
|
||||||
|
data += 2 * value["m_offset"].integer()
|
||||||
|
size = value["m_length"].integer()
|
||||||
|
s = d.readMemory(data, 2 * size)
|
||||||
|
d.putValue(s, "utf16")
|
||||||
|
except:
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__ProKey(d, value):
|
||||||
|
qdump__ProString(d, value)
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Core__GeneratedFile(d, value):
|
||||||
|
d.putStringValue(value["m_d"]["d"]["path"])
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
#def qdump__ProjectExplorer__Node(d, value):
|
||||||
|
# d.putStringValue(value["m_filePath"])
|
||||||
|
# d.putPlainChildren(value)
|
||||||
|
#
|
||||||
|
#def qdump__ProjectExplorer__FolderNode(d, value):
|
||||||
|
# d.putStringValue(value["m_displayName"])
|
||||||
|
# d.putPlainChildren(value)
|
||||||
|
|
||||||
|
# Broke when moving to unique_ptr
|
||||||
|
#def qdump__ProjectExplorer__ToolChain(d, value):
|
||||||
|
# d.putStringValue(value["d"]["m_displayName"])
|
||||||
|
# d.putPlainChildren(value)
|
||||||
|
|
||||||
|
# Broke when moving to unique_ptr
|
||||||
|
#def qdump__ProjectExplorer__Kit(d, value):
|
||||||
|
# d.putStringValue(value["d"]["m_unexpandedDisplayName"])
|
||||||
|
# d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__ProjectExplorer__ProjectNode(d, value):
|
||||||
|
qdump__ProjectExplorer__FolderNode(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__CMakeProjectManager__Internal__CMakeProjectNode(d, value):
|
||||||
|
qdump__ProjectExplorer__FolderNode(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QmakeProjectManager__QmakePriFileNode(d, value):
|
||||||
|
qdump__ProjectExplorer__FolderNode(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QmakeProjectManager__QmakeProFileNode(d, value):
|
||||||
|
qdump__ProjectExplorer__FolderNode(d, value)
|
4094
share/qtcreator/debugger/python2/dumper.py
Normal file
4094
share/qtcreator/debugger/python2/dumper.py
Normal file
File diff suppressed because it is too large
Load Diff
1624
share/qtcreator/debugger/python2/gdbbridge.py
Normal file
1624
share/qtcreator/debugger/python2/gdbbridge.py
Normal file
File diff suppressed because it is too large
Load Diff
377
share/qtcreator/debugger/python2/gdbtracepoint.py
Normal file
377
share/qtcreator/debugger/python2/gdbtracepoint.py
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
# Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# for ProcessName capture
|
||||||
|
try:
|
||||||
|
import psutil
|
||||||
|
except:
|
||||||
|
psutil = None
|
||||||
|
|
||||||
|
# Caps types
|
||||||
|
Address, \
|
||||||
|
Caller, \
|
||||||
|
Callstack, \
|
||||||
|
FilePos, \
|
||||||
|
Function, \
|
||||||
|
Pid, \
|
||||||
|
ProcessName, \
|
||||||
|
Tick, \
|
||||||
|
Tid, \
|
||||||
|
ThreadName, \
|
||||||
|
Expression, \
|
||||||
|
= range(0, 11)
|
||||||
|
|
||||||
|
class GDBTracepoint(gdb.Breakpoint):
|
||||||
|
"""
|
||||||
|
Python Breakpoint extension for "tracepoints", breakpoints that do not stop the inferior
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create(args, onModified, onHit, onExpression):
|
||||||
|
"""
|
||||||
|
Static creator function
|
||||||
|
"""
|
||||||
|
tp_kwargs = {}
|
||||||
|
if 'temporary' in args.keys():
|
||||||
|
tp_kwargs['temporary'] = args['temporary']
|
||||||
|
spec = args['spec']
|
||||||
|
tp = GDBTracepoint(spec, **tp_kwargs)
|
||||||
|
tp.onModified = onModified
|
||||||
|
tp.onHit = onHit
|
||||||
|
tp.onExpression = onExpression
|
||||||
|
if 'ignore_count' in args.keys():
|
||||||
|
tp.ignore_count = args['ignore_count']
|
||||||
|
if 'enabled' in args.keys():
|
||||||
|
tp.enabled = args['enabled']
|
||||||
|
if 'thread' in args.keys():
|
||||||
|
tp.thread = args['thread']
|
||||||
|
if 'condition' in args.keys():
|
||||||
|
tp.condition = args['condition']
|
||||||
|
if 'caps' in args.keys():
|
||||||
|
for ce in args['caps']:
|
||||||
|
tp.addCaps(ce[0], ce[1])
|
||||||
|
return tp
|
||||||
|
|
||||||
|
def __init__(self, spec, **kwargs):
|
||||||
|
"""
|
||||||
|
Constructor
|
||||||
|
"""
|
||||||
|
kwargs['internal'] = True
|
||||||
|
super(GDBTracepoint, self).__init__(spec, **kwargs)
|
||||||
|
self.caps = []
|
||||||
|
|
||||||
|
_hexSize = 8 if sys.maxsize > 2**32 else 4
|
||||||
|
_hasMonotonicTime = False if sys.version_info[0] <= 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 3) else True
|
||||||
|
|
||||||
|
def dicts(self):
|
||||||
|
"""
|
||||||
|
Returns dictionareis for mi representation
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
result = {}
|
||||||
|
result['number'] = str(self.number)
|
||||||
|
result['enabled'] = 'y' if self.enabled else 'n'
|
||||||
|
result['type'] = 'pseudo_tracepoint'
|
||||||
|
result['disp'] = 'del' if self.temporary else 'keep'
|
||||||
|
result['times'] = str(self.hit_count)
|
||||||
|
result['original-location'] = self.location
|
||||||
|
try:
|
||||||
|
d = gdb.decode_line(self.location)
|
||||||
|
if d[1] is None:
|
||||||
|
result['addr'] = '<PENDING>'
|
||||||
|
result['pending'] = self.location
|
||||||
|
results.append(result)
|
||||||
|
else:
|
||||||
|
if len(d[1]) > 1:
|
||||||
|
result['addr'] = '<MULTIPLE>'
|
||||||
|
results.append(result)
|
||||||
|
for i, sl in enumerate(d[1]):
|
||||||
|
result_ = {}
|
||||||
|
result_['number'] = result['number'] + "." + str(i + 1)
|
||||||
|
result_['enabled'] = 'y' if self.enabled else 'n'
|
||||||
|
if sl.pc is None:
|
||||||
|
result_['addr'] = '<no address>'
|
||||||
|
else:
|
||||||
|
result_['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
|
||||||
|
if sl.symtab and sl.symtab.is_valid():
|
||||||
|
func = self._getFunctionFromAddr(sl.pc)
|
||||||
|
if func:
|
||||||
|
result_['func'] = func.print_name
|
||||||
|
result_['file'] = sl.symtab.filename
|
||||||
|
result_['fullname'] = sl.symtab.fullname()
|
||||||
|
result_['line'] = sl.line
|
||||||
|
results.append(result_)
|
||||||
|
else:
|
||||||
|
sl = d[1][0]
|
||||||
|
if sl.pc is None:
|
||||||
|
result['addr'] = '<no address>'
|
||||||
|
else:
|
||||||
|
result['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
|
||||||
|
if sl.symtab and sl.symtab.is_valid():
|
||||||
|
func = self._getFunctionFromAddr(sl.pc)
|
||||||
|
if func:
|
||||||
|
result['func'] = func.print_name
|
||||||
|
result['file'] = sl.symtab.filename
|
||||||
|
result['fullname'] = sl.symtab.fullname()
|
||||||
|
result['line'] = sl.line
|
||||||
|
results.append(result)
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
result['addr'] = '<PENDING>'
|
||||||
|
result['pending'] = self.location
|
||||||
|
results.append(result)
|
||||||
|
return results
|
||||||
|
|
||||||
|
def addCaps(self, capsType, expression=None):
|
||||||
|
"""
|
||||||
|
Adds capture expressions for a tracepoint
|
||||||
|
|
||||||
|
:param caps_type: Type of capture
|
||||||
|
:param expression: Expression for Expression caps type
|
||||||
|
"""
|
||||||
|
if capsType != Expression:
|
||||||
|
expression = None
|
||||||
|
else:
|
||||||
|
if expression is None:
|
||||||
|
expression = ''
|
||||||
|
self.caps.append((self.capsMap[capsType], expression))
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Overridden stop function, this evaluates conditions and captures data from the inferior
|
||||||
|
|
||||||
|
:return: Always False
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.onModified(self)
|
||||||
|
result = {}
|
||||||
|
result['number'] = self.number
|
||||||
|
try:
|
||||||
|
if self.condition:
|
||||||
|
try:
|
||||||
|
result = gdb.parse_and_eval(self.condition)
|
||||||
|
if result.type.code == gdb.TYPE_CODE_BOOL and str(result) == 'false':
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if self.ignore_count > 0:
|
||||||
|
return False
|
||||||
|
if self.thread and gdb.selected_thread().global_num != self.thread:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
result['warning'] = str(e)
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
if len(self.caps) > 0:
|
||||||
|
caps = []
|
||||||
|
try:
|
||||||
|
for func, expr in self.caps:
|
||||||
|
if expr is None:
|
||||||
|
caps.append(func(self))
|
||||||
|
else:
|
||||||
|
caps.append(func(self, expr))
|
||||||
|
except Exception as e:
|
||||||
|
result['warning'] = str(e)
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
result['caps'] = caps
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
# Always return false, regardless...
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _getFunctionFromAddr(self, addr):
|
||||||
|
try:
|
||||||
|
block = gdb.block_for_pc(addr)
|
||||||
|
while block and not block.function:
|
||||||
|
block = block.superblock
|
||||||
|
if block is None:
|
||||||
|
return None
|
||||||
|
return block.function
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _getAddress(self):
|
||||||
|
"""
|
||||||
|
Capture function for Address
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
return '{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<null address>'
|
||||||
|
|
||||||
|
def _getCaller(self):
|
||||||
|
"""
|
||||||
|
Capture function for Caller
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
frame = frame.older()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
name = frame.name()
|
||||||
|
if name is None:
|
||||||
|
return '<unknown caller>'
|
||||||
|
return name
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown caller>'
|
||||||
|
|
||||||
|
def _getCallstack(self):
|
||||||
|
"""
|
||||||
|
Capture function for Callstack
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frames = []
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if (frame is None) or (not frame.is_valid()):
|
||||||
|
frames.append('<unknown frame>')
|
||||||
|
return str(frames)
|
||||||
|
while not (frame is None):
|
||||||
|
func = frame.function()
|
||||||
|
if func is None:
|
||||||
|
frames.append('{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2))
|
||||||
|
else:
|
||||||
|
sl = frame.find_sal()
|
||||||
|
if sl is None:
|
||||||
|
frames.append(func.symtab.filename)
|
||||||
|
else:
|
||||||
|
frames.append(func.symtab.filename + ':' + str(sl.line))
|
||||||
|
frame = frame.older()
|
||||||
|
return frames
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
def _getFilePos(self):
|
||||||
|
"""
|
||||||
|
Capture function for FilePos
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if (frame is None) or (not frame.is_valid()):
|
||||||
|
return '<unknown file pos>'
|
||||||
|
sl = frame.find_sal()
|
||||||
|
if sl is None:
|
||||||
|
return '<unknown file pos>'
|
||||||
|
return sl.symtab.filename + ':' + str(sl.line)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
def _getFunction(self):
|
||||||
|
"""
|
||||||
|
Capture function for Function
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None):
|
||||||
|
return str(frame.name())
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown function>'
|
||||||
|
|
||||||
|
def _getPid(self):
|
||||||
|
"""
|
||||||
|
Capture function for Pid
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
(pid, lwpid, tid) = thread.ptid
|
||||||
|
return str(pid)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown pid>'
|
||||||
|
|
||||||
|
def _getProcessName(slef):
|
||||||
|
"""
|
||||||
|
Capture for ProcessName
|
||||||
|
"""
|
||||||
|
# gdb does not expose process name, neither does (standard) python
|
||||||
|
# You can use for example psutil, but it might not be present.
|
||||||
|
# Default to name of thread with ID 1
|
||||||
|
inf = gdb.selected_inferior()
|
||||||
|
if psutil is None:
|
||||||
|
try:
|
||||||
|
if inf is None:
|
||||||
|
return '<unknown process name>'
|
||||||
|
threads = filter(lambda t: t.num == 1, list(inf.threads()))
|
||||||
|
if len(threads) < 1:
|
||||||
|
return '<unknown process name>'
|
||||||
|
thread = threads[0]
|
||||||
|
# use thread name
|
||||||
|
return thread.name
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
else:
|
||||||
|
return psutil.Process(inf.pid).name()
|
||||||
|
|
||||||
|
def _getTick(self):
|
||||||
|
"""
|
||||||
|
Capture function for Tick
|
||||||
|
"""
|
||||||
|
if self._hasMonotonicTime:
|
||||||
|
return str(int(time.monotonic() * 1000))
|
||||||
|
else:
|
||||||
|
return '<monotonic time not available>'
|
||||||
|
|
||||||
|
def _getTid(self):
|
||||||
|
"""
|
||||||
|
Capture function for Tid
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
(pid, lwpid, tid) = thread.ptid
|
||||||
|
if tid == 0:
|
||||||
|
return str(lwpid)
|
||||||
|
else:
|
||||||
|
return str(tid)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown tid>'
|
||||||
|
|
||||||
|
def _getThreadName(self):
|
||||||
|
"""
|
||||||
|
Capture function for ThreadName
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
return str(thread.name)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown thread name>'
|
||||||
|
|
||||||
|
def _getExpression(self, expression):
|
||||||
|
"""
|
||||||
|
Capture function for Expression
|
||||||
|
|
||||||
|
:param expr: The expression to evaluate
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
value = gdb.parse_and_eval(expression)
|
||||||
|
if value:
|
||||||
|
return self.onExpression(self, expression, value)
|
||||||
|
except Exception as e:
|
||||||
|
return self.onExpression(self, expression, e)
|
||||||
|
|
||||||
|
capsMap = {Address: _getAddress,
|
||||||
|
Caller: _getCaller,
|
||||||
|
Callstack: _getCallstack,
|
||||||
|
FilePos: _getFilePos,
|
||||||
|
Function: _getFunction,
|
||||||
|
Pid: _getPid,
|
||||||
|
ProcessName: _getProcessName,
|
||||||
|
Tid: _getTid,
|
||||||
|
Tick: _getTick,
|
||||||
|
ThreadName: _getThreadName,
|
||||||
|
Expression: _getExpression}
|
527
share/qtcreator/debugger/python2/libcpp_stdtypes.py
Normal file
527
share/qtcreator/debugger/python2/libcpp_stdtypes.py
Normal file
@@ -0,0 +1,527 @@
|
|||||||
|
# Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
from stdtypes import qdump__std__array, qdump__std__complex, qdump__std__once_flag, qdump__std__unique_ptr, qdumpHelper__std__deque__libcxx, qdumpHelper__std__vector__libcxx
|
||||||
|
from utils import DisplayFormat
|
||||||
|
from dumper import Children, DumperBase
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__array():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__array(d, value):
|
||||||
|
qdump__std__array(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__complex(d, value):
|
||||||
|
qdump__std__complex(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__deque(d, value):
|
||||||
|
qdumpHelper__std__deque__libcxx(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__list(d, value):
|
||||||
|
if value.type.size() == 3 * d.ptrSize():
|
||||||
|
# C++11 only.
|
||||||
|
(dummy1, dummy2, size) = value.split("ppp")
|
||||||
|
d.putItemCount(size)
|
||||||
|
else:
|
||||||
|
# Need to count manually.
|
||||||
|
p = d.extractPointer(value)
|
||||||
|
head = value.address()
|
||||||
|
size = 0
|
||||||
|
while head != p and size < 1001:
|
||||||
|
size += 1
|
||||||
|
p = d.extractPointer(p)
|
||||||
|
d.putItemCount(size, 1000)
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
(prev, p) = value.split("pp")
|
||||||
|
innerType = value.type[0]
|
||||||
|
typeCode = "pp{%s}" % innerType.name
|
||||||
|
with Children(d, size, maxNumChild=1000, childType=innerType):
|
||||||
|
for i in d.childRange():
|
||||||
|
(prev, p, val) = d.split(typeCode, p)
|
||||||
|
d.putSubItem(i, val)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__set(d, value):
|
||||||
|
(proxy, head, size) = value.split("ppp")
|
||||||
|
|
||||||
|
d.check(0 <= size and size <= 100 * 1000 * 1000)
|
||||||
|
d.putItemCount(size)
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
valueType = value.type[0]
|
||||||
|
|
||||||
|
def in_order_traversal(node):
|
||||||
|
(left, right, parent, color, pad, data) = d.split("pppB@{%s}" % (valueType.name), node)
|
||||||
|
|
||||||
|
if left:
|
||||||
|
for res in in_order_traversal(left):
|
||||||
|
yield res
|
||||||
|
|
||||||
|
yield data
|
||||||
|
|
||||||
|
if right:
|
||||||
|
for res in in_order_traversal(right):
|
||||||
|
yield res
|
||||||
|
|
||||||
|
with Children(d, size, maxNumChild=1000):
|
||||||
|
for (i, data) in zip(d.childRange(), in_order_traversal(head)):
|
||||||
|
d.putSubItem(i, data)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__multiset(d, value):
|
||||||
|
qdump__std____1__set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__map():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__map(d, value):
|
||||||
|
try:
|
||||||
|
(proxy, head, size) = value.split("ppp")
|
||||||
|
d.check(0 <= size and size <= 100 * 1000 * 1000)
|
||||||
|
|
||||||
|
# Sometimes there is extra data at the front. Don't know why at the moment.
|
||||||
|
except RuntimeError:
|
||||||
|
(junk, proxy, head, size) = value.split("pppp")
|
||||||
|
d.check(0 <= size and size <= 100 * 1000 * 1000)
|
||||||
|
|
||||||
|
d.putItemCount(size)
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
keyType = value.type[0]
|
||||||
|
valueType = value.type[1]
|
||||||
|
pairType = value.type[3][0]
|
||||||
|
|
||||||
|
def in_order_traversal(node):
|
||||||
|
(left, right, parent, color, pad, pair) = d.split("pppB@{%s}" % (pairType.name), node)
|
||||||
|
|
||||||
|
if left:
|
||||||
|
for res in in_order_traversal(left):
|
||||||
|
yield res
|
||||||
|
|
||||||
|
yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2]
|
||||||
|
|
||||||
|
if right:
|
||||||
|
for res in in_order_traversal(right):
|
||||||
|
yield res
|
||||||
|
|
||||||
|
with Children(d, size, maxNumChild=1000):
|
||||||
|
for (i, pair) in zip(d.childRange(), in_order_traversal(head)):
|
||||||
|
d.putPairItem(i, pair)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__multimap():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__multimap(d, value):
|
||||||
|
qdump__std____1__map(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__map__iterator(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
node = value['__i_']['__ptr_'].dereference()['__value_']['__cc']
|
||||||
|
d.putSubItem('first', node['first'])
|
||||||
|
d.putSubItem('second', node['second'])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__map__const_iterator(d, value):
|
||||||
|
qdump__std____1__map__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__set__iterator(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if value.type.name.endswith("::iterator"):
|
||||||
|
treeTypeName = value.type.name[:-len("::iterator")]
|
||||||
|
elif value.type.name.endswith("::const_iterator"):
|
||||||
|
treeTypeName = value.type.name[:-len("::const_iterator")]
|
||||||
|
treeType = d.lookupType(treeTypeName)
|
||||||
|
keyType = treeType[0]
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
node = value['__ptr_'].dereference()['__value_']
|
||||||
|
node = node.cast(keyType)
|
||||||
|
d.putSubItem('value', node)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__set_const_iterator(d, value):
|
||||||
|
qdump__std____1__set__iterator(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__stack(d, value):
|
||||||
|
d.putItem(value["c"])
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def GetChildMemberWithName(value, name):
|
||||||
|
members = value.members(True)
|
||||||
|
|
||||||
|
for member in members:
|
||||||
|
if member.name == name:
|
||||||
|
return member
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def GetIndexOfChildWithName(value, name):
|
||||||
|
members = value.members(True)
|
||||||
|
|
||||||
|
for i, member in enumerate(members):
|
||||||
|
if member.name == name:
|
||||||
|
return i
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class StringLayout:
|
||||||
|
CSD = 0
|
||||||
|
DSC = 1
|
||||||
|
|
||||||
|
|
||||||
|
def std_1_string_dumper_v2(d, value):
|
||||||
|
charType = value['__l']['__data_'].dereference().type
|
||||||
|
|
||||||
|
R = GetChildMemberWithName(value, "__r_")
|
||||||
|
if not R:
|
||||||
|
raise Exception("Could not find __r_")
|
||||||
|
|
||||||
|
# __r_ is a compressed_pair of the actual data and the allocator. The data we
|
||||||
|
# want is in the first base class.
|
||||||
|
R_Base_SP = R[0]
|
||||||
|
|
||||||
|
if not R_Base_SP:
|
||||||
|
raise Exception("Could not find R_Base_SP")
|
||||||
|
|
||||||
|
Rep_Sp = GetChildMemberWithName(R_Base_SP, "__value_")
|
||||||
|
|
||||||
|
if not Rep_Sp:
|
||||||
|
raise Exception("Could not find __value_")
|
||||||
|
|
||||||
|
# Our layout seems a little different
|
||||||
|
Rep_Sp = Rep_Sp[0]
|
||||||
|
|
||||||
|
if not Rep_Sp:
|
||||||
|
raise Exception("Could not find Rep_Sp")
|
||||||
|
|
||||||
|
L = GetChildMemberWithName(Rep_Sp, "__l")
|
||||||
|
|
||||||
|
if not L:
|
||||||
|
raise Exception("Could not find __l")
|
||||||
|
|
||||||
|
layout = StringLayout.CSD
|
||||||
|
if GetIndexOfChildWithName(L, "__data_") == 0:
|
||||||
|
layout = StringLayout.DSC
|
||||||
|
|
||||||
|
short_mode = False
|
||||||
|
using_bitmasks = True
|
||||||
|
size = 0
|
||||||
|
size_mode_value = 0
|
||||||
|
|
||||||
|
Short_Sp = GetChildMemberWithName(Rep_Sp, "__s")
|
||||||
|
if not Short_Sp:
|
||||||
|
raise Exception("Could not find __s")
|
||||||
|
|
||||||
|
Is_Long = GetChildMemberWithName(Short_Sp, "__is_long_")
|
||||||
|
Size_Sp = GetChildMemberWithName(Short_Sp, "__size_")
|
||||||
|
if not Size_Sp:
|
||||||
|
raise Exception("Could not find __size_")
|
||||||
|
|
||||||
|
if Is_Long:
|
||||||
|
using_bitmasks = False
|
||||||
|
short_mode = Is_Long.integer() == 0
|
||||||
|
size = Size_Sp.integer()
|
||||||
|
else:
|
||||||
|
size_mode_value = Size_Sp.integer()
|
||||||
|
mode_mask = 1
|
||||||
|
if layout == StringLayout.DSC:
|
||||||
|
mode_mask = 0x80
|
||||||
|
short_mode = (size_mode_value & mode_mask) == 0
|
||||||
|
|
||||||
|
if short_mode:
|
||||||
|
Location_Sp = GetChildMemberWithName(Short_Sp, "__data_")
|
||||||
|
|
||||||
|
if using_bitmasks:
|
||||||
|
size = ((size_mode_value >> 1) % 256)
|
||||||
|
if layout == StringLayout.DSC:
|
||||||
|
size = size_mode_value
|
||||||
|
|
||||||
|
# The string is most likely not initialized yet
|
||||||
|
if size > 100 or not Location_Sp:
|
||||||
|
raise Exception("Probably not initialized yet")
|
||||||
|
|
||||||
|
d.putCharArrayHelper(d.extractPointer(Location_Sp), size,
|
||||||
|
charType, d.currentItemFormat())
|
||||||
|
return
|
||||||
|
|
||||||
|
Location_Sp = GetChildMemberWithName(L, "__data_")
|
||||||
|
Size_Vo = GetChildMemberWithName(L, "__size_")
|
||||||
|
Capacity_Vo = GetChildMemberWithName(L, "__cap_")
|
||||||
|
|
||||||
|
if not Location_Sp or not Size_Vo or not Capacity_Vo:
|
||||||
|
raise Exception("Could not find Location_Sp, Size_Vo or Capacity_Vo")
|
||||||
|
|
||||||
|
size = Size_Vo.integer()
|
||||||
|
capacity = Capacity_Vo.integer()
|
||||||
|
if not using_bitmasks and layout == StringLayout.CSD:
|
||||||
|
capacity *= 2
|
||||||
|
if capacity < size:
|
||||||
|
raise Exception("Capacity is less than size")
|
||||||
|
|
||||||
|
d.putCharArrayHelper(d.extractPointer(Location_Sp), size,
|
||||||
|
charType, d.currentItemFormat())
|
||||||
|
|
||||||
|
|
||||||
|
def std_1_string_dumper_v1(d, value):
|
||||||
|
charType = value['__l']['__data_'].dereference().type
|
||||||
|
D = None
|
||||||
|
|
||||||
|
if d.isLldb:
|
||||||
|
D = value[0][0][0][0]
|
||||||
|
elif d.isGdb:
|
||||||
|
D = value["__r_"].members(True)[0][0][0]
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown debugger (neither gdb nor lldb)")
|
||||||
|
|
||||||
|
layoutDecider = D[0][0]
|
||||||
|
if not layoutDecider:
|
||||||
|
raise Exception("Could not find layoutDecider")
|
||||||
|
|
||||||
|
size = 0
|
||||||
|
size_mode_value = 0
|
||||||
|
short_mode = False
|
||||||
|
libcxx_version = 14
|
||||||
|
|
||||||
|
layoutModeIsDSC = layoutDecider.name == '__data_'
|
||||||
|
if (layoutModeIsDSC):
|
||||||
|
size_mode = D[1][1][0]
|
||||||
|
if not size_mode:
|
||||||
|
raise Exception("Could not find size_mode")
|
||||||
|
if not size_mode.name == '__size_':
|
||||||
|
size_mode = D[1][1][1]
|
||||||
|
if not size_mode:
|
||||||
|
raise Exception("Could not find size_mode")
|
||||||
|
|
||||||
|
size_mode_value = size_mode.integer()
|
||||||
|
short_mode = ((size_mode_value & 0x80) == 0)
|
||||||
|
else:
|
||||||
|
size_mode = D[1][0][0]
|
||||||
|
if not size_mode:
|
||||||
|
raise Exception("Could not find size_mode")
|
||||||
|
|
||||||
|
if size_mode.name == '__is_long_':
|
||||||
|
libcxx_version = 15
|
||||||
|
short_mode = (size_mode.integer() == 0)
|
||||||
|
|
||||||
|
size_mode = D[1][0][1]
|
||||||
|
size_mode_value = size_mode.integer()
|
||||||
|
else:
|
||||||
|
size_mode_value = size_mode.integer()
|
||||||
|
short_mode = ((size_mode_value & 1) == 0)
|
||||||
|
|
||||||
|
if short_mode:
|
||||||
|
s = D[1]
|
||||||
|
|
||||||
|
if not s:
|
||||||
|
raise Exception("Could not find s")
|
||||||
|
|
||||||
|
if libcxx_version == 14:
|
||||||
|
location_sp = s[0] if layoutModeIsDSC else s[1]
|
||||||
|
size = size_mode_value if layoutModeIsDSC else ((size_mode_value >> 1) % 256)
|
||||||
|
elif libcxx_version == 15:
|
||||||
|
location_sp = s[0] if layoutModeIsDSC else s[2]
|
||||||
|
size = size_mode_value
|
||||||
|
|
||||||
|
else:
|
||||||
|
l = D[0]
|
||||||
|
if not l:
|
||||||
|
raise Exception("Could not find l")
|
||||||
|
|
||||||
|
# we can use the layout_decider object as the data pointer
|
||||||
|
location_sp = layoutDecider if layoutModeIsDSC else l[2]
|
||||||
|
size_vo = l[1]
|
||||||
|
if not size_vo or not location_sp:
|
||||||
|
raise Exception("Could not find size_vo or location_sp")
|
||||||
|
size = size_vo.integer()
|
||||||
|
|
||||||
|
if short_mode and location_sp:
|
||||||
|
d.putCharArrayHelper(d.extractPointer(location_sp), size,
|
||||||
|
charType, d.currentItemFormat())
|
||||||
|
else:
|
||||||
|
d.putCharArrayHelper(location_sp.integer(),
|
||||||
|
size, charType, d.currentItemFormat())
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def qdump__std____1__string(d, value):
|
||||||
|
try:
|
||||||
|
std_1_string_dumper_v2(d, value)
|
||||||
|
except Exception as eV2:
|
||||||
|
try:
|
||||||
|
std_1_string_dumper_v1(d, value)
|
||||||
|
except Exception as eV1:
|
||||||
|
d.putValue("Could not parse: %s, %s" % (eV1, eV2))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__wstring(d, value):
|
||||||
|
try:
|
||||||
|
std_1_string_dumper_v2(d, value)
|
||||||
|
except Exception as eV2:
|
||||||
|
try:
|
||||||
|
std_1_string_dumper_v1(d, value)
|
||||||
|
except Exception as eV1:
|
||||||
|
d.putValue("Could not parse: %s, %s" % (eV1, eV2))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__basic_string(d, value):
|
||||||
|
innerType = value.type[0].name
|
||||||
|
if innerType in ("char", "char8_t", "char16_t"):
|
||||||
|
qdump__std____1__string(d, value)
|
||||||
|
elif innerType in ("wchar_t", "char32_t"):
|
||||||
|
qdump__std____1__wstring(d, value)
|
||||||
|
else:
|
||||||
|
d.warn("UNKNOWN INNER TYPE %s" % innerType)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__shared_ptr(d, value):
|
||||||
|
i = value["__ptr_"]
|
||||||
|
if i.pointer() == 0:
|
||||||
|
d.putValue("(null)")
|
||||||
|
else:
|
||||||
|
d.putItem(i.dereference())
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__weak_ptr(d, value):
|
||||||
|
return qdump__std____1__shared_ptr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__unique_ptr(d, value):
|
||||||
|
if value.type.size() == d.ptrSize():
|
||||||
|
p = d.extractPointer(value)
|
||||||
|
else:
|
||||||
|
_, p = value.split("pp"); # For custom deleters.
|
||||||
|
if p == 0:
|
||||||
|
d.putValue("(null)")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
d.putItem(value["__value_"])
|
||||||
|
d.putValue(d.currentValue.value, d.currentValue.encoding)
|
||||||
|
except:
|
||||||
|
d.putItem(d.createValue(p, value.type[0]))
|
||||||
|
d.putBetterType(value.type)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__unordered_map():
|
||||||
|
return [DisplayFormat.CompactMap]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__unordered_map(d, value):
|
||||||
|
(size, _) = value["__table_"]["__p2_"].split("pp")
|
||||||
|
d.putItemCount(size)
|
||||||
|
|
||||||
|
keyType = value.type[0]
|
||||||
|
valueType = value.type[1]
|
||||||
|
pairType = value.type[4][0]
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
curr = value["__table_"]["__p1_"].split("pp")[0]
|
||||||
|
|
||||||
|
def traverse_list(node):
|
||||||
|
while node:
|
||||||
|
(next_, _, pad, pair) = d.split("pp@{%s}" % (pairType.name), node)
|
||||||
|
yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2]
|
||||||
|
node = next_
|
||||||
|
|
||||||
|
with Children(d, size, childType=value.type[0], maxNumChild=1000):
|
||||||
|
for (i, value) in zip(d.childRange(), traverse_list(curr)):
|
||||||
|
d.putPairItem(i, value, 'key', 'value')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__unordered_set(d, value):
|
||||||
|
(size, _) = value["__table_"]["__p2_"].split("pp")
|
||||||
|
d.putItemCount(size)
|
||||||
|
|
||||||
|
valueType = value.type[0]
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
curr = value["__table_"]["__p1_"].split("pp")[0]
|
||||||
|
|
||||||
|
def traverse_list(node):
|
||||||
|
while node:
|
||||||
|
(next_, _, pad, val) = d.split("pp@{%s}" % (valueType.name), node)
|
||||||
|
yield val
|
||||||
|
node = next_
|
||||||
|
|
||||||
|
with Children(d, size, childType=value.type[0], maxNumChild=1000):
|
||||||
|
for (i, value) in zip(d.childRange(), traverse_list(curr)):
|
||||||
|
d.putSubItem(i, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__unordered_multiset(d, value):
|
||||||
|
qdump__std____1__unordered_set(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__valarray():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__valarray(d, value):
|
||||||
|
innerType = value.type[0]
|
||||||
|
(begin, end) = value.split('pp')
|
||||||
|
size = int((end - begin) / innerType.size())
|
||||||
|
d.putItemCount(size)
|
||||||
|
d.putPlotData(begin, size, innerType)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std____1__vector():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__vector(d, value):
|
||||||
|
qdumpHelper__std__vector__libcxx(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__once_flag(d, value):
|
||||||
|
qdump__std__once_flag(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__variant(d, value):
|
||||||
|
index = value['__impl']['__index']
|
||||||
|
index_num = int(index)
|
||||||
|
value_type = d.templateArgument(value.type, index_num)
|
||||||
|
d.putValue("<%s:%s>" % (index_num, value_type.name))
|
||||||
|
|
||||||
|
d.putNumChild(2)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("index", index)
|
||||||
|
d.putSubItem("value", value.cast(value_type))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__optional(d, value):
|
||||||
|
if value['__engaged_'].integer() == 0:
|
||||||
|
d.putSpecialValue("empty")
|
||||||
|
else:
|
||||||
|
d.putItem(value['#1']['__val_'])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__std____1__tuple(d, value):
|
||||||
|
values = []
|
||||||
|
for member in value['__base_'].members(False):
|
||||||
|
values.append(member['__value_'])
|
||||||
|
d.putItemCount(len(values))
|
||||||
|
d.putNumChild(len(values))
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
count = 0
|
||||||
|
for internal_value in values:
|
||||||
|
d.putSubItem("[%i]" % count, internal_value)
|
||||||
|
count += 1
|
2505
share/qtcreator/debugger/python2/lldbbridge.py
Normal file
2505
share/qtcreator/debugger/python2/lldbbridge.py
Normal file
File diff suppressed because it is too large
Load Diff
588
share/qtcreator/debugger/python2/misctypes.py
Normal file
588
share/qtcreator/debugger/python2/misctypes.py
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
from dumper import Children, SubItem
|
||||||
|
from utils import TypeCode, DisplayFormat
|
||||||
|
import re
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# SSE
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m128(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 4, d.lookupType('float'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m256(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 8, d.lookupType('float'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m512(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 16, d.lookupType('float'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m128d(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 2, d.lookupType('double'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m256d(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 4, d.lookupType('double'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m512d(d, value):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putArrayData(value.address(), 8, d.lookupType('double'))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m128i(d, value):
|
||||||
|
data = d.hexencode(value.data(16))
|
||||||
|
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 32, 4)))
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
addr = value.address()
|
||||||
|
d.putArrayItem('uint8x16', addr, 16, 'unsigned char')
|
||||||
|
d.putArrayItem('uint16x8', addr, 8, 'unsigned short')
|
||||||
|
d.putArrayItem('uint32x4', addr, 4, 'unsigned int')
|
||||||
|
d.putArrayItem('uint64x2', addr, 2, 'unsigned long long')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m256i(d, value):
|
||||||
|
data = d.hexencode(value.data(32))
|
||||||
|
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4)))
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
addr = value.address()
|
||||||
|
d.putArrayItem('uint8x32', addr, 32, 'unsigned char')
|
||||||
|
d.putArrayItem('uint16x16', addr, 16, 'unsigned short')
|
||||||
|
d.putArrayItem('uint32x8', addr, 8, 'unsigned int')
|
||||||
|
d.putArrayItem('uint64x4', addr, 4, 'unsigned long long')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump____m512i(d, value):
|
||||||
|
data = d.hexencode(value.data(64))
|
||||||
|
d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4))
|
||||||
|
+ ', ' + ':'.join('%04x' % int(data[i:i + 4], 16) for i in range(64, 128, 4)))
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putArrayItem('uint32x16', value.address(), 16, 'unsigned int')
|
||||||
|
d.putArrayItem('uint64x8', value.address(), 8, 'unsigned long long')
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# GSL
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def qform__std__array():
|
||||||
|
return [DisplayFormat.ArrayPlot]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__gsl__span(d, value):
|
||||||
|
size, pointer = value.split('pp')
|
||||||
|
d.putItemCount(size)
|
||||||
|
if d.isExpanded():
|
||||||
|
d.putPlotData(pointer, size, value.type[0])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__gsl__byte(d, value):
|
||||||
|
d.putValue(value.integer())
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Eigen
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
#def qform__Eigen__Matrix():
|
||||||
|
# return 'Transposed'
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Eigen__Matrix(d, value):
|
||||||
|
innerType = value.type[0]
|
||||||
|
argRow = value.type[1]
|
||||||
|
argCol = value.type[2]
|
||||||
|
options = value.type[3]
|
||||||
|
rowMajor = (int(options) & 0x1)
|
||||||
|
# The magic dimension value is -1 in Eigen3, but 10000 in Eigen2.
|
||||||
|
# 10000 x 10000 matrices are rare, vectors of dim 10000 less so.
|
||||||
|
# So 'fix' only the matrix case:
|
||||||
|
if argCol == 10000 and argRow == 10000:
|
||||||
|
argCol = -1
|
||||||
|
argRow = -1
|
||||||
|
if argCol != -1 and argRow != -1:
|
||||||
|
nrows = argRow
|
||||||
|
ncols = argCol
|
||||||
|
p = value.address()
|
||||||
|
else:
|
||||||
|
storage = value['m_storage']
|
||||||
|
nrows = storage['m_rows'].integer() if argRow == -1 else argRow
|
||||||
|
ncols = storage['m_cols'].integer() if argCol == -1 else argCol
|
||||||
|
p = storage['m_data'].pointer()
|
||||||
|
innerSize = innerType.size()
|
||||||
|
d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor]))
|
||||||
|
d.putField('keeporder', '1')
|
||||||
|
d.putNumChild(nrows * ncols)
|
||||||
|
|
||||||
|
limit = 10000
|
||||||
|
nncols = min(ncols, limit)
|
||||||
|
nnrows = min(nrows, limit * limit / nncols)
|
||||||
|
if d.isExpanded():
|
||||||
|
#format = d.currentItemFormat() # format == 1 is 'Transposed'
|
||||||
|
with Children(d, nrows * ncols, childType=innerType):
|
||||||
|
if ncols == 1 or nrows == 1:
|
||||||
|
for i in range(0, min(nrows * ncols, 10000)):
|
||||||
|
d.putSubItem(i, d.createValue(p + i * innerSize, innerType))
|
||||||
|
elif rowMajor == 1:
|
||||||
|
s = 0
|
||||||
|
for i in range(0, nnrows):
|
||||||
|
for j in range(0, nncols):
|
||||||
|
v = d.createValue(p + (i * ncols + j) * innerSize, innerType)
|
||||||
|
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
|
||||||
|
s = s + 1
|
||||||
|
else:
|
||||||
|
s = 0
|
||||||
|
for j in range(0, nncols):
|
||||||
|
for i in range(0, nnrows):
|
||||||
|
v = d.createValue(p + (i + j * nrows) * innerSize, innerType)
|
||||||
|
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
|
||||||
|
s = s + 1
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Nim
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def qdump__NimStringDesc(d, value):
|
||||||
|
size, reserved = value.split('pp')
|
||||||
|
data = value.address() + 2 * d.ptrSize()
|
||||||
|
d.putBetterType('string')
|
||||||
|
d.putCharArrayHelper(data, size, d.createType('char'), 'utf8')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__NimGenericSequence__(d, value, regex=r'^TY[\d]+$'):
|
||||||
|
code = value.type.stripTypedefs().code
|
||||||
|
if code == TypeCode.Struct:
|
||||||
|
size, reserved = d.split('pp', value)
|
||||||
|
data = value.address() + 2 * d.ptrSize()
|
||||||
|
typeobj = value['data'].type.dereference()
|
||||||
|
d.putItemCount(size)
|
||||||
|
d.putArrayData(data, size, typeobj)
|
||||||
|
d.putBetterType('%s (%s[%s])' % (value.type.name, typeobj.name, size))
|
||||||
|
else:
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__TNimNode(d, value):
|
||||||
|
name = value['name'].pointer()
|
||||||
|
d.putSimpleCharArray(name) if name != 0 else d.putEmptyValue()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
sons = value['sons'].pointer()
|
||||||
|
size = value['len'].integer()
|
||||||
|
for i in range(size):
|
||||||
|
val = d.createValue(d.extractPointer(sons + i * d.ptrSize()), value.type)
|
||||||
|
with SubItem(d, '[%d]' % i):
|
||||||
|
d.putItem(val)
|
||||||
|
with SubItem(d, '[raw]'):
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# D
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def cleanDType(type):
|
||||||
|
return str(type).replace('uns long long', 'string')
|
||||||
|
|
||||||
|
|
||||||
|
def qdump_Array(d, value):
|
||||||
|
n = value['length']
|
||||||
|
p = value['ptr']
|
||||||
|
t = cleanDType(value.type)[7:]
|
||||||
|
d.putType('%s[%d]' % (t, n))
|
||||||
|
if t == 'char':
|
||||||
|
d.putValue(encodeCharArray(p, 100), 'local8bit')
|
||||||
|
else:
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putNumChild(n)
|
||||||
|
innerType = p.type
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d, n, childType=innerType):
|
||||||
|
for i in range(0, n):
|
||||||
|
d.putSubItem(i, p.dereference())
|
||||||
|
p = p + 1
|
||||||
|
|
||||||
|
|
||||||
|
def qdump_AArray(d, value):
|
||||||
|
#n = value['length']
|
||||||
|
# This ends up as _AArray_<key>_<value> with a single .ptr
|
||||||
|
# member of type void *. Not much that can be done here.
|
||||||
|
p = value['ptr']
|
||||||
|
t = cleanDType(value.type)[8:]
|
||||||
|
d.putType('%s]' % t.replace('_', '['))
|
||||||
|
d.putEmptyValue()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d, 1):
|
||||||
|
d.putSubItem('ptr', p)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# MPI
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
if False:
|
||||||
|
|
||||||
|
def qdump__tree_entry(d, value):
|
||||||
|
d.putValue('len: %s, offset: %s, type: %s' %
|
||||||
|
(value['blocklength'], value['offset'], value['type']))
|
||||||
|
|
||||||
|
def qdump__tree(d, value):
|
||||||
|
count = value['count']
|
||||||
|
entries = value['entries']
|
||||||
|
base = value['base'].pointer()
|
||||||
|
d.putItemCount(count)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
with SubItem(d, 'tree'):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putNoType()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
for i in range(count):
|
||||||
|
d.putSubItem(Item(entries[i], iname))
|
||||||
|
with SubItem(d, 'data'):
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putNoType()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
for i in range(count):
|
||||||
|
with SubItem(d, i):
|
||||||
|
entry = entries[i]
|
||||||
|
mpitype = str(entry['type'])
|
||||||
|
d.putType(mpitype)
|
||||||
|
length = int(entry['blocklength'])
|
||||||
|
offset = int(entry['offset'])
|
||||||
|
d.putValue('%s items at %s' % (length, offset))
|
||||||
|
if mpitype == 'MPI_INT':
|
||||||
|
innerType = 'int'
|
||||||
|
elif mpitype == 'MPI_CHAR':
|
||||||
|
innerType = 'char'
|
||||||
|
elif mpitype == 'MPI_DOUBLE':
|
||||||
|
innerType = 'double'
|
||||||
|
else:
|
||||||
|
length = 0
|
||||||
|
d.putNumChild(length)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
t = d.lookupType(innerType).pointer()
|
||||||
|
p = (base + offset).cast(t)
|
||||||
|
for j in range(length):
|
||||||
|
d.putSubItem(j, p.dereference())
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# KDSoap
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def qdump__KDSoapValue1(d, value):
|
||||||
|
inner = value['d']['d'].dereference()
|
||||||
|
d.putStringValue(inner['m_name'])
|
||||||
|
d.putPlainChildren(inner)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__KDSoapValue(d, value):
|
||||||
|
p = (value.cast(d.lookupType('char*')) + 4).dereference().cast(d.lookupType('QString'))
|
||||||
|
d.putStringValue(p)
|
||||||
|
d.putPlainChildren(value['d']['d'].dereference())
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Webkit
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def qdump__WTF__String(d, value):
|
||||||
|
# WTF::String -> WTF::RefPtr<WTF::StringImpl> -> WTF::StringImpl*
|
||||||
|
data = value['m_impl']['m_ptr']
|
||||||
|
d.checkPointer(data)
|
||||||
|
|
||||||
|
stringLength = int(data['m_length'])
|
||||||
|
d.check(0 <= stringLength and stringLength <= 100000000)
|
||||||
|
|
||||||
|
# WTF::StringImpl* -> WTF::StringImpl -> sizeof(WTF::StringImpl)
|
||||||
|
offsetToData = data.type.target().size()
|
||||||
|
bufferPtr = data.pointer() + offsetToData
|
||||||
|
|
||||||
|
is8Bit = data['m_is8Bit']
|
||||||
|
charSize = 1
|
||||||
|
if not is8Bit:
|
||||||
|
charSize = 2
|
||||||
|
|
||||||
|
d.putCharArrayHelper(bufferPtr, stringLength, charSize)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Python
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def get_python_interpreter_major_version(d):
|
||||||
|
key = 'python_interpreter_major_version'
|
||||||
|
if key in d.generalCache:
|
||||||
|
return d.generalCache[key]
|
||||||
|
|
||||||
|
e = "(char*)Py_GetVersion()"
|
||||||
|
result = d.nativeParseAndEvaluate(e)
|
||||||
|
result_str = str(result)
|
||||||
|
matches = re.search(r'(\d+?)\.(\d+?)\.(\d+?)', result_str)
|
||||||
|
if matches:
|
||||||
|
result_str = matches.group(1)
|
||||||
|
d.generalCache[key] = result_str
|
||||||
|
return result_str
|
||||||
|
|
||||||
|
|
||||||
|
def is_python_3(d):
|
||||||
|
return get_python_interpreter_major_version(d) == '3'
|
||||||
|
|
||||||
|
|
||||||
|
def repr_cache_decorator(namespace):
|
||||||
|
def real_decorator(func_to_decorate):
|
||||||
|
def wrapper(d, address):
|
||||||
|
if namespace in d.perStepCache and address in d.perStepCache[namespace]:
|
||||||
|
return d.perStepCache[namespace][address]
|
||||||
|
|
||||||
|
if namespace not in d.perStepCache:
|
||||||
|
d.perStepCache[namespace] = {}
|
||||||
|
|
||||||
|
if address == 0:
|
||||||
|
result_str = d.perStepCache[namespace][address] = "<nullptr>"
|
||||||
|
return result_str
|
||||||
|
|
||||||
|
result = func_to_decorate(d, address)
|
||||||
|
d.perStepCache[namespace][address] = result
|
||||||
|
return result
|
||||||
|
return wrapper
|
||||||
|
return real_decorator
|
||||||
|
|
||||||
|
|
||||||
|
@repr_cache_decorator('py_object')
|
||||||
|
def get_py_object_repr_helper(d, address):
|
||||||
|
# The code below is a long way to evaluate:
|
||||||
|
# ((PyBytesObject *)PyUnicode_AsEncodedString(PyObject_Repr(
|
||||||
|
# (PyObject*){}), \"utf-8\", \"backslashreplace\"))->ob_sval"
|
||||||
|
# But with proper object cleanup.
|
||||||
|
|
||||||
|
e_decref = "Py_DecRef((PyObject *){})"
|
||||||
|
|
||||||
|
e = "PyObject_Repr((PyObject*){})"
|
||||||
|
repr_object_value = d.parseAndEvaluate(e.format(address))
|
||||||
|
repr_object_address = d.fromPointerData(repr_object_value.ldata)[0]
|
||||||
|
|
||||||
|
if is_python_3(d):
|
||||||
|
# Try to get a UTF-8 encoded string from the repr object.
|
||||||
|
e = "PyUnicode_AsEncodedString((PyObject*){}, \"utf-8\", \"backslashreplace\")"
|
||||||
|
string_object_value = d.parseAndEvaluate(e.format(repr_object_address))
|
||||||
|
string_object_address = d.fromPointerData(string_object_value.ldata)[0]
|
||||||
|
|
||||||
|
e = "(char*)(((PyBytesObject *){})->ob_sval)"
|
||||||
|
result = d.nativeParseAndEvaluate(e.format(string_object_address))
|
||||||
|
|
||||||
|
# It's important to stringify the result before any other evaluations happen.
|
||||||
|
result_str = str(result)
|
||||||
|
|
||||||
|
# Clean up.
|
||||||
|
d.nativeParseAndEvaluate(e_decref.format(string_object_address))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Retrieve non-unicode string.
|
||||||
|
e = "(char*)(PyString_AsString((PyObject*){}))"
|
||||||
|
result = d.nativeParseAndEvaluate(e.format(repr_object_address))
|
||||||
|
|
||||||
|
# It's important to stringify the result before any other evaluations happen.
|
||||||
|
result_str = str(result)
|
||||||
|
|
||||||
|
# Do some string stripping.
|
||||||
|
# FIXME when using cdb engine.
|
||||||
|
matches = re.search(r'.+?"(.+)"$', result_str)
|
||||||
|
if matches:
|
||||||
|
result_str = matches.group(1)
|
||||||
|
|
||||||
|
# Clean up.
|
||||||
|
d.nativeParseAndEvaluate(e_decref.format(repr_object_address))
|
||||||
|
|
||||||
|
return result_str
|
||||||
|
|
||||||
|
|
||||||
|
@repr_cache_decorator('py_object_type')
|
||||||
|
def get_py_object_type(d, object_address):
|
||||||
|
e = "((PyObject *){})->ob_type"
|
||||||
|
type_value = d.parseAndEvaluate(e.format(object_address))
|
||||||
|
type_address = d.fromPointerData(type_value.ldata)[0]
|
||||||
|
type_repr = get_py_object_repr_helper(d, type_address)
|
||||||
|
return type_repr
|
||||||
|
|
||||||
|
|
||||||
|
@repr_cache_decorator('py_object_meta_type')
|
||||||
|
def get_py_object_meta_type(d, object_address):
|
||||||
|
# The python3 object layout has a few more indirections.
|
||||||
|
if is_python_3(d):
|
||||||
|
e = "((PyObject *){})->ob_type->ob_base->ob_base->ob_type"
|
||||||
|
else:
|
||||||
|
e = "((PyObject *){})->ob_type->ob_type"
|
||||||
|
type_value = d.parseAndEvaluate(e.format(object_address))
|
||||||
|
type_address = d.fromPointerData(type_value.ldata)[0]
|
||||||
|
type_repr = get_py_object_repr_helper(d, type_address)
|
||||||
|
return type_repr
|
||||||
|
|
||||||
|
|
||||||
|
@repr_cache_decorator('py_object_base_class')
|
||||||
|
def get_py_object_base_class(d, object_address):
|
||||||
|
e = "((PyObject *){})->ob_type->tp_base"
|
||||||
|
base_value = d.parseAndEvaluate(e.format(object_address))
|
||||||
|
base_address = d.fromPointerData(base_value.ldata)[0]
|
||||||
|
base_repr = get_py_object_repr_helper(d, base_address)
|
||||||
|
return base_repr
|
||||||
|
|
||||||
|
|
||||||
|
def get_py_object_repr(d, value):
|
||||||
|
address = value.address()
|
||||||
|
repr_available = False
|
||||||
|
try:
|
||||||
|
result = get_py_object_repr_helper(d, address)
|
||||||
|
d.putValue(d.hexencode(result), encoding='utf8')
|
||||||
|
repr_available = True
|
||||||
|
except:
|
||||||
|
d.putEmptyValue()
|
||||||
|
|
||||||
|
def sub_item(name, functor, address):
|
||||||
|
with SubItem(d, '[{}]'.format(name)):
|
||||||
|
sub_value = functor(d, address)
|
||||||
|
d.putValue(d.hexencode(sub_value), encoding='utf8')
|
||||||
|
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
if repr_available:
|
||||||
|
sub_item('class', get_py_object_type, address)
|
||||||
|
sub_item('super class', get_py_object_base_class, address)
|
||||||
|
sub_item('meta type', get_py_object_meta_type, address)
|
||||||
|
d.putFields(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__PyTypeObject(d, value):
|
||||||
|
get_py_object_repr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump___typeobject(d, value):
|
||||||
|
get_py_object_repr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__PyObject(d, value):
|
||||||
|
get_py_object_repr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__PyVarObject(d, value):
|
||||||
|
get_py_object_repr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Internal test
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_FieldAccessByIndex(d, value):
|
||||||
|
d.putValue(value["d"][2].integer())
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_PointerArray(d, value):
|
||||||
|
foos = value["foos"]
|
||||||
|
d.putItemCount(10)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d, 10):
|
||||||
|
for i in d.childRange():
|
||||||
|
d.putSubItem(i, foos[i])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_BufArray(d, value):
|
||||||
|
maxItems = 1000
|
||||||
|
buffer = value['buffer']
|
||||||
|
count = int(value['count'])
|
||||||
|
objsize = int(value['objSize'])
|
||||||
|
valueType = value.type.templateArgument(0)
|
||||||
|
d.putItemCount(count, maxItems)
|
||||||
|
d.putNumChild(count)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d, count, maxNumChild=maxItems, childType=valueType):
|
||||||
|
for i in d.childRange():
|
||||||
|
d.putSubItem(i, (buffer + (i * objsize)).dereference().cast(valueType))
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_List__NodeX(d, value):
|
||||||
|
typename = value.type.unqualified().name
|
||||||
|
pos0 = typename.find('<')
|
||||||
|
pos1 = typename.find('>')
|
||||||
|
tName = typename[pos0 + 1:pos1]
|
||||||
|
d.putBetterType('QtcDumperTest_List<' + tName + '>::Node')
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
obj_type = d.lookupType(tName)
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("this", value.cast(obj_type))
|
||||||
|
d.putFields(value)
|
||||||
|
#d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_List(d, value):
|
||||||
|
innerType = value.type[0]
|
||||||
|
d.putExpandable()
|
||||||
|
p = value['root']
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("[p]", p)
|
||||||
|
d.putSubItem("[root]", value["root"].cast(innerType))
|
||||||
|
d.putFields(value)
|
||||||
|
#d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QtcDumperTest_String(d, value):
|
||||||
|
with Children(d):
|
||||||
|
first = d.hexdecode(d.putSubItem('first', value['first']).value)
|
||||||
|
second = d.hexdecode(d.putSubItem('second', value['second']).value)
|
||||||
|
third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1]
|
||||||
|
d.putValue(first + ', ' + second + ', ' + third)
|
44
share/qtcreator/debugger/python2/opencvtypes.py
Normal file
44
share/qtcreator/debugger/python2/opencvtypes.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
from dumper import Children, SubItem
|
||||||
|
from utils import TypeCode, DisplayFormat
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__cv__Size_(d, value):
|
||||||
|
d.putValue('(%s, %s)' % (value[0].display(), value[1].display()))
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qform__cv__Mat():
|
||||||
|
return [DisplayFormat.Separate]
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__cv__Mat(d, value):
|
||||||
|
(flag, dims, rows, cols, data, refcount, datastart, dataend,
|
||||||
|
datalimit, allocator, size, stepp) \
|
||||||
|
= value.split('iiiipppppppp')
|
||||||
|
steps = d.split('p' * dims, stepp)
|
||||||
|
innerSize = 0 if dims == 0 else steps[dims - 1]
|
||||||
|
if dims != 2:
|
||||||
|
d.putEmptyValue()
|
||||||
|
d.putPlainChildren(value)
|
||||||
|
return
|
||||||
|
|
||||||
|
if d.currentItemFormat() == DisplayFormat.Separate:
|
||||||
|
rs = steps[0] * innerSize
|
||||||
|
cs = cols * innerSize
|
||||||
|
dform = 'arraydata:separate:int:%d::2:%d:%d' % (innerSize, cols, rows)
|
||||||
|
out = ''.join(d.readMemory(data + i * rs, cs) for i in range(rows))
|
||||||
|
d.putDisplay(dform, out)
|
||||||
|
|
||||||
|
d.putValue('(%s x %s)' % (rows, cols))
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
innerType = d.createType(TypeCode.Integral, innerSize)
|
||||||
|
for i in range(rows):
|
||||||
|
for j in range(cols):
|
||||||
|
with SubItem(d, None):
|
||||||
|
d.putName('[%d,%d]' % (i, j))
|
||||||
|
addr = data + (i * steps[0] + j) * innerSize
|
||||||
|
d.putItem(d.createValue(addr, innerType))
|
1726
share/qtcreator/debugger/python2/pdbbridge.py
Normal file
1726
share/qtcreator/debugger/python2/pdbbridge.py
Normal file
File diff suppressed because it is too large
Load Diff
40
share/qtcreator/debugger/python2/personaltypes.py
Normal file
40
share/qtcreator/debugger/python2/personaltypes.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
# This is a place to add your own dumpers for testing purposes.
|
||||||
|
# Any contents here will be picked up by GDB, LLDB, and CDB based
|
||||||
|
# debugging in Qt Creator automatically.
|
||||||
|
|
||||||
|
# NOTE: This file will get overwritten when updating Qt Creator.
|
||||||
|
#
|
||||||
|
# To add dumpers that don't get overwritten, copy this file here
|
||||||
|
# to a safe location outside the Qt Creator installation and
|
||||||
|
# make this location known to Qt Creator using the Debugger >
|
||||||
|
# Locals & Expressions > Extra Debugging Helpers setting.
|
||||||
|
|
||||||
|
# Example to display a simple type
|
||||||
|
# template<typename U, typename V> struct MapNode
|
||||||
|
# {
|
||||||
|
# U key;
|
||||||
|
# V data;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# def qdump__MapNode(d, value):
|
||||||
|
# d.putValue("This is the value column contents")
|
||||||
|
# d.putExpandable()
|
||||||
|
# if d.isExpanded():
|
||||||
|
# with Children(d):
|
||||||
|
# # Compact simple case.
|
||||||
|
# d.putSubItem("key", value["key"])
|
||||||
|
# # Same effect, with more customization possibilities.
|
||||||
|
# with SubItem(d, "data")
|
||||||
|
# d.putItem("data", value["data"])
|
||||||
|
|
||||||
|
# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
|
||||||
|
# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
|
||||||
|
# for more complex examples.
|
||||||
|
|
||||||
|
from dumper import Children, SubItem, UnnamedSubItem, DumperBase
|
||||||
|
from utils import DisplayFormat, TypeCode
|
||||||
|
|
||||||
|
######################## Your code below #######################
|
3674
share/qtcreator/debugger/python2/qttypes.py
Normal file
3674
share/qtcreator/debugger/python2/qttypes.py
Normal file
File diff suppressed because it is too large
Load Diff
1115
share/qtcreator/debugger/python2/stdtypes.py
Normal file
1115
share/qtcreator/debugger/python2/stdtypes.py
Normal file
File diff suppressed because it is too large
Load Diff
129
share/qtcreator/debugger/python2/utils.py
Normal file
129
share/qtcreator/debugger/python2/utils.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
# Debugger start modes. Keep in sync with DebuggerStartMode in debuggerconstants.h
|
||||||
|
|
||||||
|
|
||||||
|
# MT: Why does this not match (anymore?) to debuggerconstants.h : DebuggerStartMode ?
|
||||||
|
class DebuggerStartMode():
|
||||||
|
(
|
||||||
|
NoStartMode,
|
||||||
|
StartInternal,
|
||||||
|
StartExternal,
|
||||||
|
AttachExternal,
|
||||||
|
AttachCrashedExternal,
|
||||||
|
AttachCore,
|
||||||
|
AttachToRemoteServer,
|
||||||
|
AttachToRemoteProcess,
|
||||||
|
StartRemoteProcess,
|
||||||
|
) = range(0, 9)
|
||||||
|
|
||||||
|
|
||||||
|
# Known special formats. Keep in sync with DisplayFormat in debuggerprotocol.h
|
||||||
|
class DisplayFormat():
|
||||||
|
(
|
||||||
|
Automatic,
|
||||||
|
Raw,
|
||||||
|
Simple,
|
||||||
|
Enhanced,
|
||||||
|
Separate,
|
||||||
|
Latin1String,
|
||||||
|
SeparateLatin1String,
|
||||||
|
Utf8String,
|
||||||
|
SeparateUtf8String,
|
||||||
|
Local8BitString,
|
||||||
|
Utf16String,
|
||||||
|
Ucs4String,
|
||||||
|
Array10,
|
||||||
|
Array100,
|
||||||
|
Array1000,
|
||||||
|
Array10000,
|
||||||
|
ArrayPlot,
|
||||||
|
CompactMap,
|
||||||
|
DirectQListStorage,
|
||||||
|
IndirectQListStorage,
|
||||||
|
) = range(0, 20)
|
||||||
|
|
||||||
|
|
||||||
|
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
|
||||||
|
class BreakpointType():
|
||||||
|
(
|
||||||
|
UnknownType,
|
||||||
|
BreakpointByFileAndLine,
|
||||||
|
BreakpointByFunction,
|
||||||
|
BreakpointByAddress,
|
||||||
|
BreakpointAtThrow,
|
||||||
|
BreakpointAtCatch,
|
||||||
|
BreakpointAtMain,
|
||||||
|
BreakpointAtFork,
|
||||||
|
BreakpointAtExec,
|
||||||
|
BreakpointAtSysCall,
|
||||||
|
WatchpointAtAddress,
|
||||||
|
WatchpointAtExpression,
|
||||||
|
BreakpointOnQmlSignalEmit,
|
||||||
|
BreakpointAtJavaScriptThrow,
|
||||||
|
) = range(0, 14)
|
||||||
|
|
||||||
|
|
||||||
|
# Internal codes for types. Keep in sync with cdbextensions pytype.cpp
|
||||||
|
class TypeCode():
|
||||||
|
(
|
||||||
|
Typedef,
|
||||||
|
Struct,
|
||||||
|
Void,
|
||||||
|
Integral,
|
||||||
|
Float,
|
||||||
|
Enum,
|
||||||
|
Pointer,
|
||||||
|
Array,
|
||||||
|
Complex,
|
||||||
|
Reference,
|
||||||
|
Function,
|
||||||
|
MemberPointer,
|
||||||
|
FortranString,
|
||||||
|
Unresolvable,
|
||||||
|
Bitfield,
|
||||||
|
RValueReference,
|
||||||
|
) = range(0, 16)
|
||||||
|
|
||||||
|
|
||||||
|
# Internal codes for logging channels. Keep in sync woth debuggerconstants.h
|
||||||
|
class LogChannel():
|
||||||
|
(
|
||||||
|
LogInput, # Used for user input
|
||||||
|
LogMiscInput, # Used for misc stuff in the input pane
|
||||||
|
LogOutput,
|
||||||
|
LogWarning,
|
||||||
|
LogError,
|
||||||
|
LogStatus, # Used for status changed messages
|
||||||
|
LogTime, # Used for time stamp messages
|
||||||
|
LogDebug,
|
||||||
|
LogMisc,
|
||||||
|
AppOutput, # stdout
|
||||||
|
AppError, # stderr
|
||||||
|
AppStuff, # (possibly) windows debug channel
|
||||||
|
StatusBar, # LogStatus and also put to the status bar
|
||||||
|
ConsoleOutput # Used to output to console
|
||||||
|
) = range(0, 14)
|
||||||
|
|
||||||
|
|
||||||
|
def isIntegralTypeName(name):
|
||||||
|
return name in (
|
||||||
|
"int",
|
||||||
|
"unsigned int",
|
||||||
|
"signed int",
|
||||||
|
"short",
|
||||||
|
"unsigned short",
|
||||||
|
"long",
|
||||||
|
"unsigned long",
|
||||||
|
"long long",
|
||||||
|
"unsigned long long",
|
||||||
|
"char",
|
||||||
|
"signed char",
|
||||||
|
"unsigned char",
|
||||||
|
"bool",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def isFloatingPointTypeName(name):
|
||||||
|
return name in ("float", "double", "long double")
|
Reference in New Issue
Block a user