2016-01-15 14:53:55 +01:00
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
2023-01-04 08:52:22 +01:00
|
|
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
import os
|
2017-03-16 15:37:44 +01:00
|
|
|
import codecs
|
2017-03-08 16:37:52 +01:00
|
|
|
import collections
|
2020-09-09 18:31:50 -07:00
|
|
|
import glob
|
2014-01-24 15:13:20 +01:00
|
|
|
import struct
|
2013-09-11 21:35:39 +02:00
|
|
|
import sys
|
2014-05-12 13:09:02 +02:00
|
|
|
import re
|
2015-01-21 15:18:57 +01:00
|
|
|
import time
|
2016-04-04 23:46:46 +02:00
|
|
|
import inspect
|
2020-02-21 10:10:00 +01:00
|
|
|
from utils import DisplayFormat, TypeCode
|
2015-01-23 19:09:08 +01:00
|
|
|
|
2017-07-20 11:36:19 +02:00
|
|
|
try:
|
|
|
|
# That's only used in native combined debugging right now, so
|
|
|
|
# we do not need to hard fail in cases of partial python installation
|
|
|
|
# that will never use this.
|
|
|
|
import json
|
2020-05-25 11:42:18 +02:00
|
|
|
except:
|
2020-05-11 10:13:54 +02:00
|
|
|
print("Python module json not found. "
|
|
|
|
"Native combined debugging might not work.")
|
2017-07-20 11:36:19 +02:00
|
|
|
pass
|
|
|
|
|
2022-06-22 12:12:27 +02:00
|
|
|
try:
|
|
|
|
# That fails on some QNX via Windows installations
|
|
|
|
import base64
|
|
|
|
def hexencode_(s):
|
|
|
|
return base64.b16encode(s).decode('utf8')
|
|
|
|
except:
|
|
|
|
def hexencode_(s):
|
|
|
|
return ''.join(["%x" % c for c in s])
|
2020-02-21 10:10:00 +01:00
|
|
|
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] >= 3:
|
|
|
|
toInteger = int
|
|
|
|
else:
|
|
|
|
toInteger = long
|
|
|
|
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class ReportItem():
|
2014-05-16 00:18:17 +02:00
|
|
|
"""
|
2016-10-07 11:49:51 +02:00
|
|
|
Helper structure to keep temporary 'best' information about a value
|
2014-05-16 00:18:17 +02:00
|
|
|
or a type scheduled to be reported. This might get overridden be
|
|
|
|
subsequent better guesses during a putItem() run.
|
|
|
|
"""
|
2020-02-24 14:37:56 +01:00
|
|
|
|
|
|
|
def __init__(self, value=None, encoding=None, priority=-100, elided=None):
|
2014-05-19 10:55:33 +02:00
|
|
|
self.value = value
|
|
|
|
self.priority = priority
|
|
|
|
self.encoding = encoding
|
|
|
|
self.elided = elided
|
|
|
|
|
|
|
|
def __str__(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
return 'Item(value: %s, encoding: %s, priority: %s, elided: %s)' \
|
2014-05-19 10:55:33 +02:00
|
|
|
% (self.value, self.encoding, self.priority, self.elided)
|
2014-05-16 00:18:17 +02:00
|
|
|
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class Timer():
|
2019-12-18 13:27:20 +01:00
|
|
|
def __init__(self, d, desc):
|
|
|
|
self.d = d
|
|
|
|
self.desc = desc + '-' + d.currentIName
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
self.starttime = time.time()
|
|
|
|
|
|
|
|
def __exit__(self, exType, exValue, exTraceBack):
|
|
|
|
elapsed = int(1000 * (time.time() - self.starttime))
|
|
|
|
self.d.timings.append([self.desc, elapsed])
|
|
|
|
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class Children():
|
|
|
|
def __init__(self, d, numChild=1, childType=None, childNumChild=None,
|
|
|
|
maxNumChild=None, addrBase=None, addrStep=None):
|
2013-09-11 21:35:39 +02:00
|
|
|
self.d = d
|
|
|
|
self.numChild = numChild
|
|
|
|
self.childNumChild = childNumChild
|
|
|
|
self.maxNumChild = maxNumChild
|
|
|
|
if childType is None:
|
|
|
|
self.childType = None
|
|
|
|
else:
|
2016-09-30 13:56:46 +02:00
|
|
|
self.childType = childType.name
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
if not self.d.isCli:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.d.putField('childtype', self.childType)
|
2016-09-15 17:55:56 +02:00
|
|
|
if childNumChild is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.d.putField('childnumchild', childNumChild)
|
2013-09-11 21:35:39 +02:00
|
|
|
self.childNumChild = childNumChild
|
2016-09-06 08:54:43 +02:00
|
|
|
if addrBase is not None and addrStep is not None:
|
|
|
|
self.d.put('addrbase="0x%x",addrstep="%d",' % (addrBase, addrStep))
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
self.savedChildType = self.d.currentChildType
|
|
|
|
self.savedChildNumChild = self.d.currentChildNumChild
|
|
|
|
self.savedNumChild = self.d.currentNumChild
|
|
|
|
self.savedMaxNumChild = self.d.currentMaxNumChild
|
|
|
|
self.d.currentChildType = self.childType
|
|
|
|
self.d.currentChildNumChild = self.childNumChild
|
|
|
|
self.d.currentNumChild = self.numChild
|
|
|
|
self.d.currentMaxNumChild = self.maxNumChild
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
self.d.put(self.d.childrenPrefix)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def __exit__(self, exType, exValue, exTraceBack):
|
2016-09-06 08:54:43 +02:00
|
|
|
if exType is not None:
|
2013-09-11 21:35:39 +02:00
|
|
|
if self.d.passExceptions:
|
2020-02-21 10:10:00 +01:00
|
|
|
self.d.showException('CHILDREN', exType, exValue, exTraceBack)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.d.putSpecialValue('notaccessible')
|
2016-09-06 08:54:43 +02:00
|
|
|
self.d.putNumChild(0)
|
|
|
|
if self.d.currentMaxNumChild is not None:
|
2013-09-11 21:35:39 +02:00
|
|
|
if self.d.currentMaxNumChild < self.d.currentNumChild:
|
2023-02-21 15:32:13 +01:00
|
|
|
self.d.put('{name="<load more>",value="",type="",numchild="1"},')
|
2013-09-11 21:35:39 +02:00
|
|
|
self.d.currentChildType = self.savedChildType
|
|
|
|
self.d.currentChildNumChild = self.savedChildNumChild
|
|
|
|
self.d.currentNumChild = self.savedNumChild
|
|
|
|
self.d.currentMaxNumChild = self.savedMaxNumChild
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.d.isCli:
|
2022-11-08 12:42:04 +01:00
|
|
|
self.d.put('\n' + ' ' * self.d.indent)
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
self.d.put(self.d.childrenSuffix)
|
2013-09-11 21:35:39 +02:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class SubItem():
|
2013-09-11 21:35:39 +02:00
|
|
|
def __init__(self, d, component):
|
|
|
|
self.d = d
|
|
|
|
self.name = component
|
|
|
|
self.iname = None
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
self.d.enterSubItem(self)
|
|
|
|
|
|
|
|
def __exit__(self, exType, exValue, exTraceBack):
|
|
|
|
return self.d.exitSubItem(self, exType, exValue, exTraceBack)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
class TopLevelItem(SubItem):
|
|
|
|
def __init__(self, d, iname):
|
|
|
|
self.d = d
|
|
|
|
self.iname = iname
|
|
|
|
self.name = None
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
class UnnamedSubItem(SubItem):
|
|
|
|
def __init__(self, d, component):
|
|
|
|
self.d = d
|
2016-10-07 11:49:51 +02:00
|
|
|
self.iname = '%s.%s' % (self.d.currentIName, component)
|
2013-09-11 21:35:39 +02:00
|
|
|
self.name = None
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
|
|
|
|
class DumperBase():
|
2017-05-15 16:14:58 +02:00
|
|
|
@staticmethod
|
|
|
|
def warn(message):
|
|
|
|
print('bridgemessage={msg="%s"},' % message.replace('"', '$').encode('latin1'))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def showException(msg, exType, exValue, exTraceback):
|
2020-02-24 10:14:27 +01:00
|
|
|
DumperBase.warn('**** CAUGHT EXCEPTION: %s ****' % msg)
|
2017-05-15 16:14:58 +02:00
|
|
|
try:
|
|
|
|
import traceback
|
|
|
|
for line in traceback.format_exception(exType, exValue, exTraceback):
|
2020-02-24 10:14:27 +01:00
|
|
|
DumperBase.warn('%s' % line)
|
2017-05-15 16:14:58 +02:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2019-12-18 13:27:20 +01:00
|
|
|
def timer(self, desc):
|
|
|
|
return Timer(self, desc)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def __init__(self):
|
|
|
|
self.isCdb = False
|
|
|
|
self.isGdb = False
|
|
|
|
self.isLldb = False
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
self.isCli = False
|
2023-02-27 09:15:17 +01:00
|
|
|
self.isDebugBuild = None
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2013-10-30 15:07:54 +01:00
|
|
|
# Later set, or not set:
|
|
|
|
self.stringCutOff = 10000
|
2014-05-16 00:18:17 +02:00
|
|
|
self.displayStringLimit = 100
|
2019-04-09 08:23:24 +02:00
|
|
|
self.useTimeStamps = False
|
2013-10-30 15:07:54 +01:00
|
|
|
|
2022-11-08 12:42:04 +01:00
|
|
|
self.output = []
|
2016-09-06 08:54:43 +02:00
|
|
|
self.typesReported = {}
|
|
|
|
self.typesToReport = {}
|
|
|
|
self.qtNamespaceToReport = None
|
2016-12-01 09:22:53 +01:00
|
|
|
self.qtCustomEventFunc = 0
|
2016-12-02 13:07:58 +01:00
|
|
|
self.qtCustomEventPltFunc = 0
|
2016-12-02 09:06:05 +01:00
|
|
|
self.qtPropertyFunc = 0
|
2022-05-03 18:34:33 +02:00
|
|
|
self.fallbackQtVersion = 0x60200
|
2016-09-27 09:00:13 +02:00
|
|
|
self.passExceptions = False
|
2016-11-07 08:57:26 +01:00
|
|
|
self.isTesting = False
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
self.typeData = {}
|
2016-11-07 08:57:26 +01:00
|
|
|
self.isBigEndian = False
|
|
|
|
self.packCode = '<'
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2015-07-10 10:09:25 +02:00
|
|
|
self.resetCaches()
|
2016-07-22 10:20:01 +02:00
|
|
|
self.resetStats()
|
2015-07-10 10:09:25 +02:00
|
|
|
|
|
|
|
self.childrenPrefix = 'children=['
|
|
|
|
self.childrenSuffix = '],'
|
|
|
|
|
|
|
|
self.dumpermodules = [
|
2020-09-09 18:31:50 -07:00
|
|
|
os.path.splitext(os.path.basename(p))[0] for p in
|
|
|
|
glob.glob(os.path.join(os.path.dirname(__file__), '*types.py'))
|
2015-07-10 10:09:25 +02:00
|
|
|
]
|
|
|
|
|
2016-10-07 12:23:35 +02:00
|
|
|
# These values are never used, but the variables need to have
|
|
|
|
# some value base for the swapping logic in Children.__enter__()
|
|
|
|
# and Children.__exit__().
|
|
|
|
self.currentIName = None
|
|
|
|
self.currentValue = None
|
|
|
|
self.currentType = None
|
|
|
|
self.currentNumChild = None
|
|
|
|
self.currentMaxNumChild = None
|
|
|
|
self.currentPrintsAddress = True
|
|
|
|
self.currentChildType = None
|
|
|
|
self.currentChildNumChild = None
|
2017-01-31 09:49:28 +01:00
|
|
|
self.registerKnownTypes()
|
2016-10-07 12:23:35 +02:00
|
|
|
|
|
|
|
def setVariableFetchingOptions(self, args):
|
|
|
|
self.resultVarName = args.get('resultvarname', '')
|
2023-02-21 15:32:13 +01:00
|
|
|
self.expandedINames = args.get('expanded', {})
|
2016-10-07 12:23:35 +02:00
|
|
|
self.stringCutOff = int(args.get('stringcutoff', 10000))
|
|
|
|
self.displayStringLimit = int(args.get('displaystringlimit', 100))
|
|
|
|
self.typeformats = args.get('typeformats', {})
|
|
|
|
self.formats = args.get('formats', {})
|
|
|
|
self.watchers = args.get('watchers', {})
|
|
|
|
self.useDynamicType = int(args.get('dyntype', '0'))
|
|
|
|
self.useFancy = int(args.get('fancy', '0'))
|
|
|
|
self.forceQtNamespace = int(args.get('forcens', '0'))
|
|
|
|
self.passExceptions = int(args.get('passexceptions', '0'))
|
2016-11-07 08:57:26 +01:00
|
|
|
self.isTesting = int(args.get('testing', '0'))
|
2016-12-01 09:22:53 +01:00
|
|
|
self.showQObjectNames = int(args.get('qobjectnames', '1'))
|
2016-10-07 12:23:35 +02:00
|
|
|
self.nativeMixed = int(args.get('nativemixed', '0'))
|
|
|
|
self.autoDerefPointers = int(args.get('autoderef', '0'))
|
2019-04-09 08:23:24 +02:00
|
|
|
self.useTimeStamps = int(args.get('timestamps', '0'))
|
2016-10-07 12:23:35 +02:00
|
|
|
self.partialVariable = args.get('partialvar', '')
|
2017-03-30 09:15:48 +02:00
|
|
|
self.uninitialized = args.get('uninitialized', [])
|
|
|
|
self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized))
|
2016-10-07 12:23:35 +02:00
|
|
|
self.partialUpdate = int(args.get('partial', '0'))
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('NAMESPACE: "%s"' % self.qtNamespace())
|
|
|
|
#DumperBase.warn('EXPANDED INAMES: %s' % self.expandedINames)
|
|
|
|
#DumperBase.warn('WATCHERS: %s' % self.watchers)
|
2016-10-07 12:23:35 +02:00
|
|
|
|
2021-11-09 14:15:38 +01:00
|
|
|
def setFallbackQtVersion(self, args):
|
2021-11-10 11:44:40 +01:00
|
|
|
version = int(args.get('version', self.fallbackQtVersion))
|
2021-10-25 12:03:34 +02:00
|
|
|
self.fallbackQtVersion = version
|
|
|
|
|
2018-10-17 16:05:14 +02:00
|
|
|
def resetPerStepCaches(self):
|
|
|
|
self.perStepCache = {}
|
|
|
|
pass
|
|
|
|
|
2015-07-10 10:09:25 +02:00
|
|
|
def resetCaches(self):
|
2013-10-30 15:07:54 +01:00
|
|
|
# This is a cache mapping from 'type name' to 'display alternatives'.
|
2020-02-24 15:10:47 +01:00
|
|
|
self.qqFormats = {'QVariant (QVariantMap)': [DisplayFormat.CompactMap]}
|
2013-10-30 15:07:54 +01:00
|
|
|
|
|
|
|
# This is a cache of all known dumpers.
|
2016-04-04 23:46:46 +02:00
|
|
|
self.qqDumpers = {} # Direct type match
|
|
|
|
self.qqDumpersEx = {} # Using regexp
|
2013-10-30 15:07:54 +01:00
|
|
|
|
|
|
|
# This is a cache of all dumpers that support writing.
|
|
|
|
self.qqEditable = {}
|
|
|
|
|
|
|
|
# This keeps canonical forms of the typenames, without array indices etc.
|
|
|
|
self.cachedFormats = {}
|
|
|
|
|
2014-01-28 23:23:01 +01:00
|
|
|
# Maps type names to static metaobjects. If a type is known
|
|
|
|
# to not be QObject derived, it contains a 0 value.
|
|
|
|
self.knownStaticMetaObjects = {}
|
2014-01-20 15:03:27 +01:00
|
|
|
|
2018-10-17 16:05:14 +02:00
|
|
|
# A dictionary to serve as a per debugging step cache.
|
|
|
|
# Cleared on each step over / into / continue.
|
|
|
|
self.perStepCache = {}
|
|
|
|
|
|
|
|
# A dictionary to serve as a general cache throughout the whole
|
|
|
|
# debug session.
|
|
|
|
self.generalCache = {}
|
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
self.counts = {}
|
2016-09-06 08:54:43 +02:00
|
|
|
self.structPatternCache = {}
|
2016-07-22 10:20:01 +02:00
|
|
|
self.timings = []
|
2020-05-29 13:08:07 +02:00
|
|
|
self.expandableINames = set({})
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
def resetStats(self):
|
|
|
|
# Timing collection
|
|
|
|
self.timings = []
|
|
|
|
pass
|
|
|
|
|
|
|
|
def dumpStats(self):
|
|
|
|
msg = [self.counts, self.timings]
|
|
|
|
self.resetStats()
|
|
|
|
return msg
|
|
|
|
|
|
|
|
def bump(self, key):
|
|
|
|
if key in self.counts:
|
|
|
|
self.counts[key] += 1
|
|
|
|
else:
|
|
|
|
self.counts[key] = 1
|
|
|
|
|
2016-09-28 08:55:13 +02:00
|
|
|
def childRange(self):
|
|
|
|
if self.currentMaxNumChild is None:
|
2020-02-24 10:37:40 +01:00
|
|
|
return range(0, self.currentNumChild)
|
|
|
|
return range(min(self.currentMaxNumChild, self.currentNumChild))
|
2016-09-28 08:55:13 +02:00
|
|
|
|
2023-02-21 15:32:13 +01:00
|
|
|
def maxArrayCount(self):
|
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
return self.expandedINames[self.currentIName]
|
|
|
|
return 100
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def enterSubItem(self, item):
|
2019-04-09 14:03:35 +02:00
|
|
|
if self.useTimeStamps:
|
|
|
|
item.startTime = time.time()
|
2016-09-06 08:54:43 +02:00
|
|
|
if not item.iname:
|
2016-10-07 11:49:51 +02:00
|
|
|
item.iname = '%s.%s' % (self.currentIName, item.name)
|
2016-09-19 09:14:05 +02:00
|
|
|
if not self.isCli:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.put('{')
|
|
|
|
if isinstance(item.name, str):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('name', item.name)
|
2016-09-19 09:14:05 +02:00
|
|
|
else:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.indent += 1
|
2022-11-08 12:42:04 +01:00
|
|
|
self.put('\n' + ' ' * self.indent)
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(item.name, str):
|
2022-11-08 12:42:04 +01:00
|
|
|
self.put(item.name + ' = ')
|
2016-09-06 08:54:43 +02:00
|
|
|
item.savedIName = self.currentIName
|
|
|
|
item.savedValue = self.currentValue
|
|
|
|
item.savedType = self.currentType
|
|
|
|
self.currentIName = item.iname
|
2020-02-24 14:37:56 +01:00
|
|
|
self.currentValue = ReportItem()
|
|
|
|
self.currentType = ReportItem()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def exitSubItem(self, item, exType, exValue, exTraceBack):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('CURRENT VALUE: %s: %s %s' %
|
2016-09-06 08:54:43 +02:00
|
|
|
# (self.currentIName, self.currentValue, self.currentType))
|
2020-02-24 14:37:56 +01:00
|
|
|
if exType is not None:
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.passExceptions:
|
2020-02-24 10:14:27 +01:00
|
|
|
self.showException('SUBITEM', exType, exValue, exTraceBack)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('notaccessible')
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putNumChild(0)
|
2016-09-19 09:14:05 +02:00
|
|
|
if not self.isCli:
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
|
|
|
if self.currentType.value:
|
|
|
|
typeName = self.currentType.value
|
|
|
|
if len(typeName) > 0 and typeName != self.currentChildType:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('type', typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.currentValue.value is None:
|
|
|
|
self.put('value="",encoding="notaccessible",numchild="0",')
|
|
|
|
else:
|
2020-02-24 14:37:56 +01:00
|
|
|
if self.currentValue.encoding is not None:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.put('valueencoded="%s",' % self.currentValue.encoding)
|
|
|
|
if self.currentValue.elided:
|
|
|
|
self.put('valueelided="%s",' % self.currentValue.elided)
|
|
|
|
self.put('value="%s",' % self.currentValue.value)
|
|
|
|
except:
|
|
|
|
pass
|
2019-04-09 14:03:35 +02:00
|
|
|
if self.useTimeStamps:
|
|
|
|
self.put('time="%s",' % (time.time() - item.startTime))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.put('},')
|
2016-09-19 09:14:05 +02:00
|
|
|
else:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.indent -= 1
|
|
|
|
try:
|
|
|
|
if self.currentType.value:
|
2016-09-30 13:56:46 +02:00
|
|
|
typeName = self.currentType.value
|
2016-09-06 08:54:43 +02:00
|
|
|
self.put('<%s> = {' % typeName)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
if self.currentValue.value is None:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.put('<not accessible>')
|
|
|
|
else:
|
|
|
|
value = self.currentValue.value
|
2016-10-07 11:49:51 +02:00
|
|
|
if self.currentValue.encoding == 'latin1':
|
2016-09-06 08:54:43 +02:00
|
|
|
value = self.hexdecode(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
elif self.currentValue.encoding == 'utf8':
|
2016-09-06 08:54:43 +02:00
|
|
|
value = self.hexdecode(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
elif self.currentValue.encoding == 'utf16':
|
2017-03-16 15:37:44 +01:00
|
|
|
b = bytes(bytearray.fromhex(value))
|
2016-09-06 08:54:43 +02:00
|
|
|
value = codecs.decode(b, 'utf-16')
|
|
|
|
self.put('"%s"' % value)
|
|
|
|
if self.currentValue.elided:
|
|
|
|
self.put('...')
|
|
|
|
|
|
|
|
if self.currentType.value:
|
|
|
|
self.put('}')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
self.currentIName = item.savedIName
|
|
|
|
self.currentValue = item.savedValue
|
|
|
|
self.currentType = item.savedType
|
|
|
|
return True
|
2013-10-30 15:07:54 +01:00
|
|
|
|
|
|
|
def stripForFormat(self, typeName):
|
2016-09-15 17:55:56 +02:00
|
|
|
if not isinstance(typeName, str):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected string in stripForFormat(), got %s' % type(typeName))
|
2013-10-30 15:07:54 +01:00
|
|
|
if typeName in self.cachedFormats:
|
|
|
|
return self.cachedFormats[typeName]
|
2016-10-07 11:49:51 +02:00
|
|
|
stripped = ''
|
2013-10-30 15:07:54 +01:00
|
|
|
inArray = 0
|
2016-09-30 13:56:46 +02:00
|
|
|
for c in typeName:
|
2013-10-30 15:07:54 +01:00
|
|
|
if c == '<':
|
|
|
|
break
|
|
|
|
if c == ' ':
|
|
|
|
continue
|
|
|
|
if c == '[':
|
|
|
|
inArray += 1
|
|
|
|
elif c == ']':
|
|
|
|
inArray -= 1
|
|
|
|
if inArray and ord(c) >= 48 and ord(c) <= 57:
|
|
|
|
continue
|
2020-02-24 14:37:56 +01:00
|
|
|
stripped += c
|
2013-10-30 15:07:54 +01:00
|
|
|
self.cachedFormats[typeName] = stripped
|
|
|
|
return stripped
|
|
|
|
|
2016-12-11 14:20:36 +02:00
|
|
|
def templateArgument(self, typeobj, position):
|
|
|
|
return typeobj.templateArgument(position)
|
|
|
|
|
2016-09-28 09:13:14 +02:00
|
|
|
def intType(self):
|
|
|
|
result = self.lookupType('int')
|
|
|
|
self.intType = lambda: result
|
|
|
|
return result
|
|
|
|
|
|
|
|
def charType(self):
|
|
|
|
result = self.lookupType('char')
|
|
|
|
self.intType = lambda: result
|
|
|
|
return result
|
|
|
|
|
|
|
|
def ptrSize(self):
|
|
|
|
result = self.lookupType('void*').size()
|
|
|
|
self.ptrSize = lambda: result
|
|
|
|
return result
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def lookupType(self, typeName):
|
|
|
|
nativeType = self.lookupNativeType(typeName)
|
|
|
|
return None if nativeType is None else self.fromNativeType(nativeType)
|
|
|
|
|
2017-01-31 09:49:28 +01:00
|
|
|
def registerKnownTypes(self):
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, 'unsigned short')
|
2017-01-31 15:01:48 +01:00
|
|
|
tdata.lbitsize = 16
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata.lalignment = 2
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Integral
|
2017-01-31 15:01:48 +01:00
|
|
|
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, 'QChar')
|
2017-01-31 09:49:28 +01:00
|
|
|
tdata.lbitsize = 16
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata.lalignment = 2
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Struct
|
2020-02-24 14:37:56 +01:00
|
|
|
tdata.lfields = [self.Field(dumper=self, name='ucs',
|
|
|
|
type='unsigned short', bitsize=16, bitpos=0)]
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata.templateArguments = lambda: []
|
2017-01-31 09:49:28 +01:00
|
|
|
|
2016-11-07 08:57:26 +01:00
|
|
|
def nativeDynamicType(self, address, baseType):
|
2020-02-24 14:37:56 +01:00
|
|
|
return baseType # Override in backends.
|
2016-11-07 08:57:26 +01:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def listTemplateParameters(self, typename):
|
2017-04-25 18:01:26 +02:00
|
|
|
return self.listTemplateParametersManually(typename)
|
|
|
|
|
|
|
|
def listTemplateParametersManually(self, typename):
|
2016-10-25 15:32:13 +02:00
|
|
|
targs = []
|
|
|
|
if not typename.endswith('>'):
|
|
|
|
return targs
|
|
|
|
|
|
|
|
def push(inner):
|
|
|
|
# Handle local struct definitions like QList<main(int, char**)::SomeStruct>
|
|
|
|
inner = inner.strip()[::-1]
|
|
|
|
p = inner.find(')::')
|
|
|
|
if p > -1:
|
2020-02-24 14:37:56 +01:00
|
|
|
inner = inner[p + 3:].strip()
|
2016-10-25 15:32:13 +02:00
|
|
|
if inner.startswith('const '):
|
|
|
|
inner = inner[6:].strip()
|
|
|
|
if inner.endswith(' const'):
|
|
|
|
inner = inner[:-6].strip()
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("FOUND: %s" % inner)
|
2016-10-25 15:32:13 +02:00
|
|
|
targs.append(inner)
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("SPLITTING %s" % typename)
|
2016-10-25 15:32:13 +02:00
|
|
|
level = 0
|
|
|
|
inner = ''
|
2020-02-24 14:37:56 +01:00
|
|
|
for c in typename[::-1]: # Reversed...
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("C: %s" % c)
|
2016-10-25 15:32:13 +02:00
|
|
|
if c == '>':
|
|
|
|
if level > 0:
|
|
|
|
inner += c
|
|
|
|
level += 1
|
|
|
|
elif c == '<':
|
|
|
|
level -= 1
|
|
|
|
if level > 0:
|
|
|
|
inner += c
|
|
|
|
else:
|
|
|
|
push(inner)
|
|
|
|
inner = ''
|
2017-06-16 18:12:07 +02:00
|
|
|
break
|
2016-10-25 15:32:13 +02:00
|
|
|
elif c == ',':
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('c: %s level: %s' % (c, level))
|
2016-10-25 15:32:13 +02:00
|
|
|
if level == 1:
|
|
|
|
push(inner)
|
|
|
|
inner = ''
|
|
|
|
else:
|
|
|
|
inner += c
|
|
|
|
else:
|
|
|
|
inner += c
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("TARGS: %s %s" % (typename, targs))
|
2016-10-25 15:32:13 +02:00
|
|
|
res = []
|
|
|
|
for item in targs[::-1]:
|
2017-07-05 09:30:03 +02:00
|
|
|
if len(item) == 0:
|
|
|
|
continue
|
2016-10-25 15:32:13 +02:00
|
|
|
c = ord(item[0])
|
2020-02-24 14:37:56 +01:00
|
|
|
if c in (45, 46) or (c >= 48 and c < 58): # '-', '.' or digit.
|
2016-10-25 15:32:13 +02:00
|
|
|
if item.find('.') > -1:
|
|
|
|
res.append(float(item))
|
|
|
|
else:
|
2017-04-25 18:01:26 +02:00
|
|
|
if item.endswith('l'):
|
|
|
|
item = item[:-1]
|
|
|
|
if item.endswith('u'):
|
|
|
|
item = item[:-1]
|
2021-09-23 12:31:49 +00:00
|
|
|
val = toInteger(item)
|
2016-10-25 15:32:13 +02:00
|
|
|
if val > 0x80000000:
|
|
|
|
val -= 0x100000000
|
|
|
|
res.append(val)
|
|
|
|
else:
|
|
|
|
res.append(self.Type(self, item))
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("RES: %s %s" % (typename, [(None if t is None else t.name) for t in res]))
|
2016-10-25 15:32:13 +02:00
|
|
|
return res
|
|
|
|
|
2014-01-24 15:13:20 +01:00
|
|
|
# Hex decoding operating on str, return str.
|
2021-07-23 13:02:02 +01:00
|
|
|
@staticmethod
|
|
|
|
def hexdecode(s, encoding='utf8'):
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] == 2:
|
|
|
|
# For python2 we need an extra str() call to return str instead of unicode
|
|
|
|
return str(s.decode('hex').decode(encoding))
|
2021-07-23 13:02:02 +01:00
|
|
|
return bytes.fromhex(s).decode(encoding)
|
2014-01-23 15:30:51 +01:00
|
|
|
|
2015-07-07 17:20:02 +02:00
|
|
|
# Hex encoding operating on str or bytes, return str.
|
2021-07-23 13:02:02 +01:00
|
|
|
@staticmethod
|
|
|
|
def hexencode(s):
|
2016-04-05 15:32:50 +02:00
|
|
|
if s is None:
|
|
|
|
s = ''
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] == 2:
|
|
|
|
if isinstance(s, buffer):
|
|
|
|
return bytes(s).encode('hex')
|
|
|
|
return s.encode('hex')
|
2014-01-24 15:13:20 +01:00
|
|
|
if isinstance(s, str):
|
2016-10-07 11:49:51 +02:00
|
|
|
s = s.encode('utf8')
|
2022-06-22 12:12:27 +02:00
|
|
|
return hexencode_(s)
|
2014-01-24 15:13:20 +01:00
|
|
|
|
2013-11-11 09:54:54 +01:00
|
|
|
def isQt3Support(self):
|
|
|
|
# assume no Qt 3 support by default
|
|
|
|
return False
|
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
# Clamps size to limit.
|
2013-09-11 21:35:39 +02:00
|
|
|
def computeLimit(self, size, limit):
|
2014-05-19 10:55:33 +02:00
|
|
|
if limit == 0:
|
|
|
|
limit = self.displayStringLimit
|
2014-05-16 00:18:17 +02:00
|
|
|
if limit is None or size <= limit:
|
|
|
|
return 0, size
|
|
|
|
return size, limit
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2020-11-24 18:28:22 +01:00
|
|
|
def vectorData(self, value):
|
2020-12-01 13:15:29 +01:00
|
|
|
if self.qtVersion() >= 0x060000:
|
|
|
|
data, size, alloc = self.qArrayData(value)
|
|
|
|
elif self.qtVersion() >= 0x050000:
|
|
|
|
vector_data_ptr = self.extractPointer(value)
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.ptrSize() == 4:
|
2020-05-29 13:08:55 +02:00
|
|
|
(ref, size, alloc, offset) = self.split('IIIp', vector_data_ptr)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2020-05-29 13:08:55 +02:00
|
|
|
(ref, size, alloc, pad, offset) = self.split('IIIIp', vector_data_ptr)
|
2016-09-06 08:54:43 +02:00
|
|
|
alloc = alloc & 0x7ffffff
|
2020-05-29 13:08:55 +02:00
|
|
|
data = vector_data_ptr + offset
|
2014-04-03 22:08:35 +02:00
|
|
|
else:
|
2020-12-01 13:15:29 +01:00
|
|
|
vector_data_ptr = self.extractPointer(value)
|
2020-05-29 13:08:55 +02:00
|
|
|
(ref, alloc, size) = self.split('III', vector_data_ptr)
|
|
|
|
data = vector_data_ptr + 16
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
|
2020-12-07 15:07:13 +01:00
|
|
|
return data, size
|
2014-04-03 22:08:35 +02:00
|
|
|
|
2020-11-24 17:53:08 +01:00
|
|
|
def qArrayData(self, value):
|
2020-11-25 17:18:24 +01:00
|
|
|
if self.qtVersion() >= 0x60000:
|
2020-11-30 16:40:54 +01:00
|
|
|
dd, data, size = self.split('ppp', value)
|
2020-11-25 17:18:24 +01:00
|
|
|
if dd:
|
2020-11-30 16:40:54 +01:00
|
|
|
_, _, alloc = self.split('iip', dd)
|
2020-11-25 17:18:24 +01:00
|
|
|
else: # fromRawData
|
|
|
|
alloc = size
|
|
|
|
return data, size, alloc
|
2020-11-24 17:53:08 +01:00
|
|
|
return self.qArrayDataHelper(self.extractPointer(value))
|
|
|
|
|
2020-11-24 12:38:52 +01:00
|
|
|
def qArrayDataHelper(self, array_data_ptr):
|
|
|
|
# array_data_ptr is what is e.g. stored in a QByteArray's d_ptr.
|
2013-09-11 21:35:39 +02:00
|
|
|
if self.qtVersion() >= 0x050000:
|
|
|
|
# QTypedArray:
|
|
|
|
# - QtPrivate::RefCount ref
|
|
|
|
# - int size
|
|
|
|
# - uint alloc : 31, capacityReserved : 1
|
|
|
|
# - qptrdiff offset
|
2020-11-24 12:38:52 +01:00
|
|
|
(ref, size, alloc, offset) = self.split('IIpp', array_data_ptr)
|
2016-09-06 08:54:43 +02:00
|
|
|
alloc = alloc & 0x7ffffff
|
2020-11-24 12:38:52 +01:00
|
|
|
data = array_data_ptr + offset
|
2013-09-26 23:38:17 +02:00
|
|
|
if self.ptrSize() == 4:
|
|
|
|
data = data & 0xffffffff
|
|
|
|
else:
|
|
|
|
data = data & 0xffffffffffffffff
|
2014-10-10 12:05:47 +02:00
|
|
|
elif self.qtVersion() >= 0x040000:
|
2013-09-11 21:35:39 +02:00
|
|
|
# Data:
|
|
|
|
# - QBasicAtomicInt ref;
|
|
|
|
# - int alloc, size;
|
|
|
|
# - [padding]
|
|
|
|
# - char *data;
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.ptrSize() == 4:
|
2020-11-24 12:38:52 +01:00
|
|
|
(ref, alloc, size, data) = self.split('IIIp', array_data_ptr)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2020-11-24 12:38:52 +01:00
|
|
|
(ref, alloc, size, pad, data) = self.split('IIIIp', array_data_ptr)
|
2014-10-10 12:05:47 +02:00
|
|
|
else:
|
|
|
|
# Data:
|
|
|
|
# - QShared count;
|
|
|
|
# - QChar *unicode
|
|
|
|
# - char *ascii
|
|
|
|
# - uint len: 30
|
2020-11-24 12:38:52 +01:00
|
|
|
(dummy, dummy, dummy, size) = self.split('IIIp', array_data_ptr)
|
|
|
|
size = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff
|
2014-10-10 12:05:47 +02:00
|
|
|
alloc = size # pretend.
|
2020-11-24 12:38:52 +01:00
|
|
|
data = self.extractPointer(array_data_ptr + self.ptrSize())
|
2013-09-11 21:35:39 +02:00
|
|
|
return data, size, alloc
|
|
|
|
|
2020-11-24 16:33:57 +01:00
|
|
|
def encodeStringHelper(self, value, limit):
|
2020-11-24 17:53:08 +01:00
|
|
|
data, size, alloc = self.qArrayData(value)
|
2013-09-11 21:35:39 +02:00
|
|
|
if alloc != 0:
|
2020-02-24 14:37:56 +01:00
|
|
|
self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000)
|
2020-11-30 16:40:54 +01:00
|
|
|
elided, shown = self.computeLimit(2 * size, 2 * limit)
|
|
|
|
return elided, self.readMemory(data, shown)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2020-11-24 15:44:49 +01:00
|
|
|
def encodeByteArrayHelper(self, value, limit):
|
2020-11-24 17:53:08 +01:00
|
|
|
data, size, alloc = self.qArrayData(value)
|
2013-09-11 21:35:39 +02:00
|
|
|
if alloc != 0:
|
2020-02-24 14:37:56 +01:00
|
|
|
self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000)
|
2014-05-16 00:18:17 +02:00
|
|
|
elided, shown = self.computeLimit(size, limit)
|
|
|
|
return elided, self.readMemory(data, shown)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2018-08-14 14:02:00 +02:00
|
|
|
def putCharArrayValue(self, data, size, charSize,
|
2020-02-24 15:10:47 +01:00
|
|
|
displayFormat=DisplayFormat.Automatic):
|
2015-01-14 15:00:09 +01:00
|
|
|
bytelen = size * charSize
|
|
|
|
elided, shown = self.computeLimit(bytelen, self.displayStringLimit)
|
|
|
|
mem = self.readMemory(data, shown)
|
|
|
|
if charSize == 1:
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat in (DisplayFormat.Latin1String, DisplayFormat.SeparateLatin1String):
|
2016-10-07 11:49:51 +02:00
|
|
|
encodingType = 'latin1'
|
2015-03-18 10:09:44 +01:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
encodingType = 'utf8'
|
|
|
|
#childType = 'char'
|
2015-01-14 15:00:09 +01:00
|
|
|
elif charSize == 2:
|
2016-10-07 11:49:51 +02:00
|
|
|
encodingType = 'utf16'
|
|
|
|
#childType = 'short'
|
2015-01-14 15:00:09 +01:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
encodingType = 'ucs4'
|
|
|
|
#childType = 'int'
|
2015-01-14 15:00:09 +01:00
|
|
|
|
|
|
|
self.putValue(mem, encodingType, elided=elided)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
if displayFormat in (
|
2020-02-24 15:10:47 +01:00
|
|
|
DisplayFormat.SeparateLatin1String,
|
|
|
|
DisplayFormat.SeparateUtf8String,
|
|
|
|
DisplayFormat.Separate):
|
2015-01-14 15:00:09 +01:00
|
|
|
elided, shown = self.computeLimit(bytelen, 100000)
|
2016-04-08 00:49:22 +02:00
|
|
|
self.putDisplay(encodingType + ':separate', self.readMemory(data, shown))
|
2015-01-14 15:00:09 +01:00
|
|
|
|
2018-08-14 14:02:00 +02:00
|
|
|
def putCharArrayHelper(self, data, size, charType,
|
2020-02-24 15:10:47 +01:00
|
|
|
displayFormat=DisplayFormat.Automatic,
|
2020-02-24 14:37:56 +01:00
|
|
|
makeExpandable=True):
|
2018-08-14 14:02:00 +02:00
|
|
|
charSize = charType.size()
|
2020-02-24 14:37:56 +01:00
|
|
|
self.putCharArrayValue(data, size, charSize, displayFormat=displayFormat)
|
2018-08-14 14:02:00 +02:00
|
|
|
|
2015-11-05 15:10:20 +01:00
|
|
|
if makeExpandable:
|
|
|
|
self.putNumChild(size)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
for i in range(size):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putSubItem(size, self.createValue(data + i * charSize, charType))
|
2015-11-05 15:10:20 +01:00
|
|
|
|
2014-01-23 15:30:51 +01:00
|
|
|
def readMemory(self, addr, size):
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.hexencode(bytes(self.readRawMemory(addr, size)))
|
2014-01-23 15:30:51 +01:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def encodeByteArray(self, value, limit=0):
|
2020-11-24 15:44:49 +01:00
|
|
|
elided, data = self.encodeByteArrayHelper(value, limit)
|
2014-05-16 00:18:17 +02:00
|
|
|
return data
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-05-19 10:55:33 +02:00
|
|
|
def putByteArrayValue(self, value):
|
2020-11-24 15:44:49 +01:00
|
|
|
elided, data = self.encodeByteArrayHelper(value, self.displayStringLimit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'latin1', elided=elided)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def encodeString(self, value, limit=0):
|
2020-11-30 16:40:54 +01:00
|
|
|
elided, data = self.encodeStringHelper(value, limit)
|
|
|
|
return data
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-12-12 08:19:06 +01:00
|
|
|
def encodedUtf16ToUtf8(self, s):
|
2020-02-24 14:37:56 +01:00
|
|
|
return ''.join([chr(int(s[i:i + 2], 16)) for i in range(0, len(s), 4)])
|
2014-12-12 08:19:06 +01:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def encodeStringUtf8(self, value, limit=0):
|
2014-12-12 08:19:06 +01:00
|
|
|
return self.encodedUtf16ToUtf8(self.encodeString(value, limit))
|
|
|
|
|
2020-11-19 15:57:11 +01:00
|
|
|
def stringData(self, value): # -> (data, size, alloc)
|
2020-12-01 13:15:29 +01:00
|
|
|
return self.qArrayData(value)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2013-10-28 11:35:45 +01:00
|
|
|
def extractTemplateArgument(self, typename, position):
|
|
|
|
level = 0
|
|
|
|
skipSpace = False
|
|
|
|
inner = ''
|
2020-02-24 14:37:56 +01:00
|
|
|
for c in typename[typename.find('<') + 1: -1]:
|
2013-10-28 11:35:45 +01:00
|
|
|
if c == '<':
|
|
|
|
inner += c
|
|
|
|
level += 1
|
|
|
|
elif c == '>':
|
|
|
|
level -= 1
|
|
|
|
inner += c
|
|
|
|
elif c == ',':
|
|
|
|
if level == 0:
|
|
|
|
if position == 0:
|
|
|
|
return inner.strip()
|
|
|
|
position -= 1
|
|
|
|
inner = ''
|
|
|
|
else:
|
|
|
|
inner += c
|
|
|
|
skipSpace = True
|
|
|
|
else:
|
|
|
|
if skipSpace and c == ' ':
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
inner += c
|
|
|
|
skipSpace = False
|
2015-12-08 14:27:42 +01:00
|
|
|
# Handle local struct definitions like QList<main(int, char**)::SomeStruct>
|
|
|
|
inner = inner.strip()
|
|
|
|
p = inner.find(')::')
|
|
|
|
if p > -1:
|
2020-02-24 14:37:56 +01:00
|
|
|
inner = inner[p + 3:]
|
2015-12-08 14:27:42 +01:00
|
|
|
return inner
|
2013-10-28 11:35:45 +01:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def putStringValue(self, value):
|
2020-11-30 16:40:54 +01:00
|
|
|
elided, data = self.encodeStringHelper(value, self.displayStringLimit)
|
|
|
|
self.putValue(data, 'utf16', elided=elided)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-09-27 09:00:13 +02:00
|
|
|
def putPtrItem(self, name, value):
|
|
|
|
with SubItem(self, name):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % value)
|
|
|
|
self.putType('void*')
|
2016-09-27 09:00:13 +02:00
|
|
|
|
2013-11-01 12:49:14 +01:00
|
|
|
def putIntItem(self, name, value):
|
|
|
|
with SubItem(self, name):
|
2016-09-26 14:29:16 +02:00
|
|
|
if isinstance(value, self.Value):
|
|
|
|
self.putValue(value.display())
|
|
|
|
else:
|
|
|
|
self.putValue(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType('int')
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2019-02-19 12:50:49 +01:00
|
|
|
def putEnumItem(self, name, ival, typish):
|
|
|
|
buf = bytearray(struct.pack('i', ival))
|
|
|
|
val = self.Value(self)
|
|
|
|
val.ldata = bytes(buf)
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.createType(typish)
|
2019-02-19 12:50:49 +01:00
|
|
|
with SubItem(self, name):
|
|
|
|
self.putItem(val)
|
|
|
|
|
2013-11-01 12:49:14 +01:00
|
|
|
def putBoolItem(self, name, value):
|
|
|
|
with SubItem(self, name):
|
|
|
|
self.putValue(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType('bool')
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2016-11-23 17:51:59 +01:00
|
|
|
def putPairItem(self, index, pair, keyName='first', valueName='second'):
|
2016-09-21 16:54:30 +02:00
|
|
|
with SubItem(self, index):
|
2016-11-23 17:51:59 +01:00
|
|
|
self.putPairContents(index, pair, keyName, valueName)
|
2016-11-23 16:07:45 +01:00
|
|
|
|
|
|
|
def putPairContents(self, index, pair, kname, vname):
|
|
|
|
with Children(self):
|
|
|
|
first, second = pair if isinstance(pair, tuple) else pair.members(False)
|
|
|
|
key = self.putSubItem(kname, first)
|
|
|
|
value = self.putSubItem(vname, second)
|
2020-05-29 13:08:07 +02:00
|
|
|
if self.isCli:
|
|
|
|
self.putEmptyValue()
|
|
|
|
else:
|
|
|
|
if index is not None:
|
|
|
|
self.putField('keyprefix', '[%s] ' % index)
|
|
|
|
self.putField('key', key.value)
|
|
|
|
if key.encoding is not None:
|
|
|
|
self.putField('keyencoded', key.encoding)
|
|
|
|
self.putValue(value.value, value.encoding)
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2019-02-19 12:50:49 +01:00
|
|
|
def putEnumValue(self, ival, vals):
|
2016-12-01 00:42:10 +01:00
|
|
|
nice = vals.get(ival, None)
|
|
|
|
display = ('%d' % ival) if nice is None else ('%s (%d)' % (nice, ival))
|
|
|
|
self.putValue(display)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def putCallItem(self, name, rettype, value, func, *args):
|
|
|
|
with SubItem(self, name):
|
|
|
|
try:
|
|
|
|
result = self.callHelper(rettype, value, func, args)
|
2016-09-21 16:54:30 +02:00
|
|
|
except Exception as error:
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.passExceptions:
|
|
|
|
raise error
|
2016-09-26 14:29:16 +02:00
|
|
|
children = [('error', error)]
|
|
|
|
self.putSpecialValue("notcallable", children=children)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2014-04-03 11:23:31 +02:00
|
|
|
self.putItem(result)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def call(self, rettype, value, func, *args):
|
|
|
|
return self.callHelper(rettype, value, func, args)
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def putAddress(self, address):
|
|
|
|
if address is not None and not self.isCli:
|
|
|
|
self.put('address="0x%x",' % address)
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putPlainChildren(self, value, dumpBase=True):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2014-03-20 15:16:56 +01:00
|
|
|
if self.isExpanded():
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putEmptyValue(-99)
|
2014-03-20 15:16:56 +01:00
|
|
|
with Children(self):
|
|
|
|
self.putFields(value, dumpBase)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def putNamedChildren(self, values, names):
|
|
|
|
self.putEmptyValue(-99)
|
2020-06-02 10:38:25 +02:00
|
|
|
self.putExpandable()
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
for n, v in zip(names, values):
|
|
|
|
self.putSubItem(n, v)
|
|
|
|
|
2016-10-31 17:59:49 +01:00
|
|
|
def prettySymbolByAddress(self, address):
|
|
|
|
return '0x%x' % address
|
|
|
|
|
|
|
|
def putSymbolValue(self, address):
|
|
|
|
self.putValue(self.prettySymbolByAddress(address))
|
|
|
|
|
2017-01-20 09:05:23 +01:00
|
|
|
def putVTableChildren(self, item, itemCount):
|
|
|
|
p = item.pointer()
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(itemCount):
|
2017-01-20 09:05:23 +01:00
|
|
|
deref = self.extractPointer(p)
|
|
|
|
if deref == 0:
|
|
|
|
itemCount = i
|
|
|
|
break
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.putItem(self.createPointerValue(deref, 'void'))
|
|
|
|
p += self.ptrSize()
|
|
|
|
return itemCount
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putFields(self, value, dumpBase=True):
|
2016-11-04 18:16:28 +01:00
|
|
|
baseIndex = 0
|
2016-11-01 09:50:31 +01:00
|
|
|
for item in value.members(True):
|
2016-11-17 13:47:28 +01:00
|
|
|
if item.name is not None:
|
|
|
|
if item.name.startswith('_vptr.') or item.name.startswith('__vfptr'):
|
|
|
|
with SubItem(self, '[vptr]'):
|
|
|
|
# int (**)(void)
|
|
|
|
self.putType(' ')
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(20)
|
2016-11-17 13:47:28 +01:00
|
|
|
self.putValue(item.name)
|
2017-01-20 09:05:23 +01:00
|
|
|
n = 100
|
2016-11-17 13:47:28 +01:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
2017-01-20 09:05:23 +01:00
|
|
|
n = self.putVTableChildren(item, n)
|
2016-11-17 13:47:28 +01:00
|
|
|
self.putNumChild(n)
|
|
|
|
continue
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
if item.isBaseClass and dumpBase:
|
2016-11-07 08:57:26 +01:00
|
|
|
baseIndex += 1
|
2016-09-06 08:54:43 +02:00
|
|
|
# We cannot use nativeField.name as part of the iname as
|
|
|
|
# it might contain spaces and other strange characters.
|
2016-11-04 18:16:28 +01:00
|
|
|
with UnnamedSubItem(self, "@%d" % baseIndex):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('iname', self.currentIName)
|
2016-11-01 09:50:31 +01:00
|
|
|
self.putField('name', '[%s]' % item.name)
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putSortGroup(1000 - baseIndex)
|
|
|
|
self.putAddress(item.address())
|
2016-11-01 09:50:31 +01:00
|
|
|
self.putItem(item)
|
2016-09-06 08:54:43 +02:00
|
|
|
continue
|
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
with SubItem(self, item.name):
|
|
|
|
self.putItem(item)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-05-29 13:08:07 +02:00
|
|
|
def putExpandable(self):
|
|
|
|
self.putNumChild(1)
|
|
|
|
self.expandableINames.add(self.currentIName)
|
|
|
|
if self.isCli:
|
|
|
|
self.putValue('{...}', -99)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putMembersItem(self, value, sortorder=10):
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[members]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(sortorder)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putPlainChildren(value)
|
|
|
|
|
2016-12-16 09:28:40 +01:00
|
|
|
def put(self, stuff):
|
2022-11-08 12:42:04 +01:00
|
|
|
self.output.append(stuff)
|
|
|
|
|
|
|
|
def takeOutput(self):
|
2023-03-09 22:03:42 +01:00
|
|
|
res = ''.join(self.output)
|
2022-11-08 12:42:04 +01:00
|
|
|
self.output = []
|
|
|
|
return res
|
2016-12-16 09:28:40 +01:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def check(self, exp):
|
|
|
|
if not exp:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Check failed: %s' % exp)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def checkRef(self, ref):
|
|
|
|
# Assume there aren't a million references to any object.
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check(ref >= -1)
|
|
|
|
self.check(ref < 1000000)
|
|
|
|
|
|
|
|
def checkIntType(self, thing):
|
2021-09-23 12:31:49 +00:00
|
|
|
if not self.isInt(thing):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected an integral value, got %s' % type(thing))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def readToFirstZero(self, base, tsize, maximum):
|
|
|
|
self.checkIntType(base)
|
|
|
|
self.checkIntType(tsize)
|
|
|
|
self.checkIntType(maximum)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-11-07 08:57:26 +01:00
|
|
|
code = self.packCode + (None, 'b', 'H', None, 'I')[tsize]
|
2016-10-25 15:32:13 +02:00
|
|
|
#blob = self.readRawMemory(base, 1)
|
2016-09-06 08:54:43 +02:00
|
|
|
blob = bytes()
|
|
|
|
while maximum > 1:
|
|
|
|
try:
|
|
|
|
blob = self.readRawMemory(base, maximum)
|
|
|
|
break
|
|
|
|
except:
|
|
|
|
maximum = int(maximum / 2)
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('REDUCING READING MAXIMUM TO %s' % maximum)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, tsize, maximum))
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(0, maximum, tsize):
|
2014-10-10 01:33:35 +02:00
|
|
|
t = struct.unpack_from(code, blob, i)[0]
|
|
|
|
if t == 0:
|
|
|
|
return 0, i, self.hexencode(blob[:i])
|
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
# Real end is unknown.
|
2014-10-10 01:33:35 +02:00
|
|
|
return -1, maximum, self.hexencode(blob[:maximum])
|
2013-10-16 18:39:01 +02:00
|
|
|
|
2014-10-10 01:33:35 +02:00
|
|
|
def encodeCArray(self, p, tsize, limit):
|
|
|
|
elided, shown, blob = self.readToFirstZero(p, tsize, limit)
|
|
|
|
return elided, blob
|
2013-10-16 18:39:01 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putItemCount(self, count, maximum=1000000000):
|
2013-11-01 12:49:14 +01:00
|
|
|
# This needs to override the default value, so don't use 'put' directly.
|
|
|
|
if count > maximum:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', maximum)
|
2013-11-01 12:49:14 +01:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('itemcount', count)
|
2014-05-06 15:20:36 +02:00
|
|
|
self.putNumChild(count)
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
def resultToMi(self, value):
|
2020-02-24 14:37:56 +01:00
|
|
|
if isinstance(value, bool):
|
2015-10-08 16:19:57 +02:00
|
|
|
return '"%d"' % int(value)
|
2020-02-24 14:37:56 +01:00
|
|
|
if isinstance(value, dict):
|
2015-10-14 13:26:22 +02:00
|
|
|
return '{' + ','.join(['%s=%s' % (k, self.resultToMi(v))
|
2020-02-24 14:37:56 +01:00
|
|
|
for (k, v) in list(value.items())]) + '}'
|
|
|
|
if isinstance(value, list):
|
2015-10-14 13:26:22 +02:00
|
|
|
return '[' + ','.join([self.resultToMi(k)
|
2021-01-07 13:28:05 +01:00
|
|
|
for k in value]) + ']'
|
2015-10-14 13:26:22 +02:00
|
|
|
return '"%s"' % value
|
|
|
|
|
|
|
|
def variablesToMi(self, value, prefix):
|
2020-02-24 14:37:56 +01:00
|
|
|
if isinstance(value, bool):
|
2015-10-14 13:26:22 +02:00
|
|
|
return '"%d"' % int(value)
|
2020-02-24 14:37:56 +01:00
|
|
|
if isinstance(value, dict):
|
2015-10-14 13:26:22 +02:00
|
|
|
pairs = []
|
|
|
|
for (k, v) in list(value.items()):
|
|
|
|
if k == 'iname':
|
|
|
|
if v.startswith('.'):
|
|
|
|
v = '"%s%s"' % (prefix, v)
|
|
|
|
else:
|
|
|
|
v = '"%s"' % v
|
|
|
|
else:
|
|
|
|
v = self.variablesToMi(v, prefix)
|
|
|
|
pairs.append('%s=%s' % (k, v))
|
|
|
|
return '{' + ','.join(pairs) + '}'
|
2020-02-24 14:37:56 +01:00
|
|
|
if isinstance(value, list):
|
2015-10-09 15:00:20 +02:00
|
|
|
index = 0
|
|
|
|
pairs = []
|
|
|
|
for item in value:
|
2015-10-14 13:26:22 +02:00
|
|
|
if item.get('type', '') == 'function':
|
|
|
|
continue
|
2015-10-09 15:00:20 +02:00
|
|
|
name = item.get('name', '')
|
|
|
|
if len(name) == 0:
|
|
|
|
name = str(index)
|
|
|
|
index += 1
|
2015-10-14 13:26:22 +02:00
|
|
|
pairs.append((name, self.variablesToMi(item, prefix)))
|
2020-02-24 14:37:56 +01:00
|
|
|
pairs.sort(key=lambda pair: pair[0])
|
2015-10-09 15:00:20 +02:00
|
|
|
return '[' + ','.join([pair[1] for pair in pairs]) + ']'
|
2015-10-08 16:19:57 +02:00
|
|
|
return '"%s"' % value
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
def filterPrefix(self, prefix, items):
|
|
|
|
return [i[len(prefix):] for i in items if i.startswith(prefix)]
|
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
def tryFetchInterpreterVariables(self, args):
|
|
|
|
if not int(args.get('nativemixed', 0)):
|
|
|
|
return (False, '')
|
|
|
|
context = args.get('context', '')
|
|
|
|
if not len(context):
|
|
|
|
return (False, '')
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
expanded = args.get('expanded')
|
|
|
|
args['expanded'] = self.filterPrefix('local', expanded)
|
|
|
|
|
|
|
|
res = self.sendInterpreterRequest('variables', args)
|
|
|
|
if not res:
|
|
|
|
return (False, '')
|
|
|
|
|
|
|
|
reslist = []
|
|
|
|
for item in res.get('variables', {}):
|
2019-05-02 18:16:47 +02:00
|
|
|
if 'iname' not in item:
|
2015-10-14 13:26:22 +02:00
|
|
|
item['iname'] = '.' + item.get('name')
|
|
|
|
reslist.append(self.variablesToMi(item, 'local'))
|
|
|
|
|
|
|
|
watchers = args.get('watchers', None)
|
|
|
|
if watchers:
|
|
|
|
toevaluate = []
|
|
|
|
name2expr = {}
|
|
|
|
seq = 0
|
|
|
|
for watcher in watchers:
|
|
|
|
expr = self.hexdecode(watcher.get('exp'))
|
|
|
|
name = str(seq)
|
|
|
|
toevaluate.append({'name': name, 'expression': expr})
|
|
|
|
name2expr[name] = expr
|
|
|
|
seq += 1
|
|
|
|
args['expressions'] = toevaluate
|
|
|
|
|
|
|
|
args['expanded'] = self.filterPrefix('watch', expanded)
|
|
|
|
del args['watchers']
|
|
|
|
res = self.sendInterpreterRequest('expressions', args)
|
|
|
|
|
|
|
|
if res:
|
|
|
|
for item in res.get('expressions', {}):
|
|
|
|
name = item.get('name')
|
|
|
|
iname = 'watch.' + name
|
|
|
|
expr = name2expr.get(name)
|
|
|
|
item['iname'] = iname
|
|
|
|
item['wname'] = self.hexencode(expr)
|
|
|
|
item['exp'] = expr
|
|
|
|
reslist.append(self.variablesToMi(item, 'watch'))
|
|
|
|
|
|
|
|
return (True, 'data=[%s]' % ','.join(reslist))
|
2015-10-09 15:00:20 +02:00
|
|
|
|
2013-11-07 13:04:09 +01:00
|
|
|
def putField(self, name, value):
|
|
|
|
self.put('%s="%s",' % (name, value))
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putType(self, typish, priority=0):
|
2013-11-07 13:04:09 +01:00
|
|
|
# Higher priority values override lower ones.
|
2014-05-16 00:18:17 +02:00
|
|
|
if priority >= self.currentType.priority:
|
2021-09-23 12:31:49 +00:00
|
|
|
types = (str) if sys.version_info[0] >= 3 else (str, unicode)
|
|
|
|
if isinstance(typish, types):
|
2016-09-15 17:55:56 +02:00
|
|
|
self.currentType.value = typish
|
|
|
|
else:
|
|
|
|
self.currentType.value = typish.name
|
2014-05-16 00:18:17 +02:00
|
|
|
self.currentType.priority = priority
|
2013-11-07 13:04:09 +01:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putValue(self, value, encoding=None, priority=0, elided=None):
|
2013-11-07 13:04:09 +01:00
|
|
|
# Higher priority values override lower ones.
|
2014-05-16 00:18:17 +02:00
|
|
|
# elided = 0 indicates all data is available in value,
|
|
|
|
# otherwise it's the true length.
|
|
|
|
if priority >= self.currentValue.priority:
|
2014-05-19 10:55:33 +02:00
|
|
|
self.currentValue = ReportItem(value, encoding, priority, elided)
|
2013-11-07 13:04:09 +01:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putSpecialValue(self, encoding, value='', children=None):
|
2015-07-20 14:23:54 +02:00
|
|
|
self.putValue(value, encoding)
|
2016-09-06 08:54:43 +02:00
|
|
|
if children is not None:
|
2020-06-02 10:38:25 +02:00
|
|
|
self.putExpandable()
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
for name, value in children:
|
|
|
|
with SubItem(self, name):
|
|
|
|
self.putValue(str(value).replace('"', '$'))
|
2015-07-20 14:23:54 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putEmptyValue(self, priority=-10):
|
2014-05-16 00:18:17 +02:00
|
|
|
if priority >= self.currentValue.priority:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.currentValue = ReportItem('', None, priority, None)
|
2013-11-07 13:04:09 +01:00
|
|
|
|
|
|
|
def putName(self, name):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('name', name)
|
2013-11-07 13:04:09 +01:00
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def putBetterType(self, typish):
|
|
|
|
if isinstance(typish, ReportItem):
|
|
|
|
self.currentType.value = typish.value
|
|
|
|
elif isinstance(typish, str):
|
2020-12-01 16:24:47 +01:00
|
|
|
self.currentType.value = typish.replace('@', self.qtNamespace())
|
2014-05-19 10:55:33 +02:00
|
|
|
else:
|
2016-09-15 17:55:56 +02:00
|
|
|
self.currentType.value = typish.name
|
2014-05-16 00:18:17 +02:00
|
|
|
self.currentType.priority += 1
|
|
|
|
|
2013-11-01 12:49:14 +01:00
|
|
|
def putNoType(self):
|
|
|
|
# FIXME: replace with something that does not need special handling
|
|
|
|
# in SubItem.__exit__().
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putBetterType(' ')
|
2013-11-01 12:49:14 +01:00
|
|
|
|
|
|
|
def putInaccessible(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
#self.putBetterType(' ')
|
2013-11-01 12:49:14 +01:00
|
|
|
self.putNumChild(0)
|
2014-05-16 00:18:17 +02:00
|
|
|
self.currentValue.value = None
|
2013-11-01 12:49:14 +01:00
|
|
|
|
2013-11-07 13:04:09 +01:00
|
|
|
def putNamedSubItem(self, component, value, name):
|
|
|
|
with SubItem(self, component):
|
|
|
|
self.putName(name)
|
|
|
|
self.putItem(value)
|
|
|
|
|
|
|
|
def isExpanded(self):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('IS EXPANDED: %s in %s: %s' % (self.currentIName,
|
2013-11-07 13:04:09 +01:00
|
|
|
# self.expandedINames, self.currentIName in self.expandedINames))
|
|
|
|
return self.currentIName in self.expandedINames
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def mangleName(self, typeName):
|
2016-10-07 11:49:51 +02:00
|
|
|
return '_ZN%sE' % ''.join(map(lambda x: '%d%s' % (len(x), x),
|
2020-02-24 14:37:56 +01:00
|
|
|
typeName.split('::')))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-05-07 09:56:52 +02:00
|
|
|
def arrayItemCountFromTypeName(self, typeName, fallbackMax=1):
|
|
|
|
itemCount = typeName[typeName.find('[') + 1:typeName.find(']')]
|
|
|
|
return int(itemCount) if itemCount else fallbackMax
|
|
|
|
|
2013-11-07 12:26:14 +01:00
|
|
|
def putCStyleArray(self, value):
|
2015-03-05 17:39:32 +01:00
|
|
|
arrayType = value.type.unqualified()
|
2016-09-26 14:29:16 +02:00
|
|
|
innerType = arrayType.ltarget
|
|
|
|
if innerType is None:
|
2016-09-29 00:04:04 +02:00
|
|
|
innerType = value.type.target().unqualified()
|
2016-09-06 08:54:43 +02:00
|
|
|
address = value.address()
|
|
|
|
if address:
|
2020-02-24 14:37:56 +01:00
|
|
|
self.putValue('@0x%x' % address, priority=-1)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2015-03-17 15:59:39 +01:00
|
|
|
self.putEmptyValue()
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(arrayType)
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
displayFormat = self.currentItemFormat()
|
2016-09-06 08:54:43 +02:00
|
|
|
arrayByteSize = arrayType.size()
|
2015-07-22 11:16:20 +02:00
|
|
|
if arrayByteSize == 0:
|
|
|
|
# This should not happen. But it does, see QTCREATORBUG-14755.
|
|
|
|
# GDB/GCC produce sizeof == 0 for QProcess arr[3]
|
2016-04-04 21:51:31 +02:00
|
|
|
# And in the Nim string dumper.
|
2020-05-07 09:56:52 +02:00
|
|
|
itemCount = self.arrayItemCountFromTypeName(value.type.name, 100)
|
2020-02-24 14:37:56 +01:00
|
|
|
arrayByteSize = int(itemCount) * innerType.size()
|
2015-07-22 11:16:20 +02:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
n = arrayByteSize // innerType.size()
|
2016-09-06 08:54:43 +02:00
|
|
|
p = value.address()
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat != DisplayFormat.Raw and p:
|
2020-02-24 14:37:56 +01:00
|
|
|
if innerType.name in (
|
|
|
|
'char',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int8_t',
|
|
|
|
'qint8',
|
2020-02-24 14:37:56 +01:00
|
|
|
'wchar_t',
|
|
|
|
'unsigned char',
|
2021-10-29 14:11:10 +02:00
|
|
|
'uint8_t',
|
2021-10-31 14:28:45 +01:00
|
|
|
'quint8',
|
2020-02-24 14:37:56 +01:00
|
|
|
'signed char',
|
|
|
|
'CHAR',
|
2021-10-31 14:28:45 +01:00
|
|
|
'WCHAR',
|
|
|
|
'char8_t',
|
|
|
|
'char16_t',
|
|
|
|
'char32_t'
|
2020-02-24 14:37:56 +01:00
|
|
|
):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(),
|
2020-02-24 14:37:56 +01:00
|
|
|
makeExpandable=False)
|
2015-08-12 09:05:28 +02:00
|
|
|
else:
|
2016-09-29 00:04:04 +02:00
|
|
|
self.tryPutSimpleFormattedPointer(p, arrayType, innerType,
|
2020-02-24 14:37:56 +01:00
|
|
|
displayFormat, arrayByteSize)
|
2015-04-01 17:19:43 +02:00
|
|
|
self.putNumChild(n)
|
2013-11-07 12:26:14 +01:00
|
|
|
|
2015-04-01 08:32:50 +02:00
|
|
|
if self.isExpanded():
|
2015-12-10 11:36:44 +01:00
|
|
|
self.putArrayData(p, n, innerType)
|
2013-11-07 12:26:14 +01:00
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
self.putPlotDataHelper(p, n, innerType)
|
2015-04-01 08:32:50 +02:00
|
|
|
|
2014-01-21 18:13:02 +01:00
|
|
|
def cleanAddress(self, addr):
|
|
|
|
if addr is None:
|
2016-10-07 11:49:51 +02:00
|
|
|
return '<no address>'
|
2021-09-23 12:31:49 +00:00
|
|
|
return '0x%x' % toInteger(hex(addr), 16)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def stripNamespaceFromType(self, typeName):
|
|
|
|
ns = self.qtNamespace()
|
2016-09-30 13:56:46 +02:00
|
|
|
if len(ns) > 0 and typeName.startswith(ns):
|
|
|
|
typeName = typeName[len(ns):]
|
2020-02-21 10:10:00 +01:00
|
|
|
# DumperBase.warn( 'stripping %s' % typeName )
|
2019-07-05 15:53:23 +02:00
|
|
|
lvl = 0
|
|
|
|
pos = None
|
|
|
|
stripChunks = []
|
|
|
|
sz = len(typeName)
|
|
|
|
for index in range(0, sz):
|
|
|
|
s = typeName[index]
|
|
|
|
if s == '<':
|
|
|
|
lvl += 1
|
|
|
|
if lvl == 1:
|
|
|
|
pos = index
|
|
|
|
continue
|
|
|
|
elif s == '>':
|
|
|
|
lvl -= 1
|
2020-02-24 14:37:56 +01:00
|
|
|
if lvl < 0:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError("Unbalanced '<' in type, @index %d" % index)
|
2019-07-05 15:53:23 +02:00
|
|
|
if lvl == 0:
|
2020-02-24 14:37:56 +01:00
|
|
|
stripChunks.append((pos, index + 1))
|
2019-07-05 15:53:23 +02:00
|
|
|
if lvl != 0:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError("unbalanced at end of type name")
|
2019-07-05 15:53:23 +02:00
|
|
|
for (f, l) in reversed(stripChunks):
|
|
|
|
typeName = typeName[:f] + typeName[l:]
|
2016-09-30 13:56:46 +02:00
|
|
|
return typeName
|
2014-01-21 18:13:02 +01:00
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
def tryPutPrettyItem(self, typeName, value):
|
2016-09-06 08:54:43 +02:00
|
|
|
value.check()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.useFancy and self.currentItemFormat() != DisplayFormat.Raw:
|
2015-03-20 16:03:59 +01:00
|
|
|
self.putType(typeName)
|
|
|
|
|
|
|
|
nsStrippedType = self.stripNamespaceFromType(typeName)\
|
2016-10-07 11:49:51 +02:00
|
|
|
.replace('::', '__')
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2020-09-03 22:36:54 +03:00
|
|
|
# Strip leading 'struct' for C structs
|
|
|
|
if nsStrippedType.startswith('struct '):
|
|
|
|
nsStrippedType = nsStrippedType[7:]
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('STRIPPED: %s' % nsStrippedType)
|
2015-03-20 16:03:59 +01:00
|
|
|
# The following block is only needed for D.
|
2016-10-07 11:49:51 +02:00
|
|
|
if nsStrippedType.startswith('_A'):
|
2015-03-20 16:03:59 +01:00
|
|
|
# DMD v2.058 encodes string[] as _Array_uns long long.
|
|
|
|
# With spaces.
|
2016-10-07 11:49:51 +02:00
|
|
|
if nsStrippedType.startswith('_Array_'):
|
2015-03-20 16:03:59 +01:00
|
|
|
qdump_Array(self, value)
|
|
|
|
return True
|
2016-10-07 11:49:51 +02:00
|
|
|
if nsStrippedType.startswith('_AArray_'):
|
2015-03-20 16:03:59 +01:00
|
|
|
qdump_AArray(self, value)
|
|
|
|
return True
|
|
|
|
|
|
|
|
dumper = self.qqDumpers.get(nsStrippedType)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('DUMPER: %s' % dumper)
|
2016-09-06 08:54:43 +02:00
|
|
|
if dumper is not None:
|
2015-03-20 16:03:59 +01:00
|
|
|
dumper(self, value)
|
|
|
|
return True
|
|
|
|
|
2016-04-04 23:46:46 +02:00
|
|
|
for pattern in self.qqDumpersEx.keys():
|
|
|
|
dumper = self.qqDumpersEx[pattern]
|
|
|
|
if re.match(pattern, nsStrippedType):
|
|
|
|
dumper(self, value)
|
|
|
|
return True
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
return False
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putSimpleCharArray(self, base, size=None):
|
2014-09-01 23:35:11 +02:00
|
|
|
if size is None:
|
2014-10-10 01:33:35 +02:00
|
|
|
elided, shown, data = self.readToFirstZero(base, 1, self.displayStringLimit)
|
2014-09-01 23:35:11 +02:00
|
|
|
else:
|
|
|
|
elided, shown = self.computeLimit(int(size), self.displayStringLimit)
|
2014-10-14 16:27:11 +02:00
|
|
|
data = self.readMemory(base, shown)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'latin1', elided=elided)
|
2014-09-01 23:35:11 +02:00
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
def putDisplay(self, editFormat, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('editformat', editFormat)
|
|
|
|
self.putField('editvalue', value)
|
2014-05-27 22:35:54 +02:00
|
|
|
|
2015-03-05 17:39:32 +01:00
|
|
|
# This is shared by pointer and array formatting.
|
2016-09-29 00:04:04 +02:00
|
|
|
def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit):
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Automatic:
|
2020-09-24 14:05:13 +02:00
|
|
|
targetType = innerType
|
|
|
|
if innerType.code == TypeCode.Typedef:
|
|
|
|
targetType = innerType.ltarget
|
|
|
|
|
2021-10-29 14:11:10 +02:00
|
|
|
if targetType.name in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'):
|
2016-04-08 17:58:12 +02:00
|
|
|
# Use UTF-8 as default for char *.
|
2016-04-08 17:00:13 +02:00
|
|
|
self.putType(typeName)
|
2016-09-29 00:04:04 +02:00
|
|
|
(elided, shown, data) = self.readToFirstZero(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf8', elided=elided)
|
2016-09-29 00:04:04 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
self.putArrayData(ptr, shown, innerType)
|
2016-04-08 17:00:13 +02:00
|
|
|
return True
|
|
|
|
|
2020-09-24 14:05:13 +02:00
|
|
|
if targetType.name in ('wchar_t', 'WCHAR'):
|
2016-04-08 17:00:13 +02:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
charSize = self.lookupType('wchar_t').size()
|
|
|
|
(elided, data) = self.encodeCArray(ptr, charSize, limit)
|
2016-04-08 17:00:13 +02:00
|
|
|
if charSize == 2:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf16', elided=elided)
|
2016-04-08 17:00:13 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'ucs4', elided=elided)
|
2016-04-08 17:00:13 +02:00
|
|
|
return True
|
2015-03-05 17:39:32 +01:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Latin1String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'latin1', elided=elided)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.SeparateLatin1String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'latin1', elided=elided)
|
|
|
|
self.putDisplay('latin1:separate', data)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Utf8String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf8', elided=elided)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.SeparateUtf8String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf8', elided=elided)
|
|
|
|
self.putDisplay('utf8:separate', data)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Local8BitString:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 1, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'local8bit', elided=elided)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Utf16String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 2, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf16', elided=elided)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Ucs4String:
|
2015-03-05 17:39:32 +01:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
(elided, data) = self.encodeCArray(ptr, 4, limit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'ucs4', elided=elided)
|
2015-03-05 17:39:32 +01:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2013-11-06 17:57:12 +01:00
|
|
|
def putFormattedPointer(self, value):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('formattedPointer'):
|
2016-11-07 08:57:26 +01:00
|
|
|
self.putFormattedPointerX(value)
|
|
|
|
|
2017-04-24 16:42:30 +02:00
|
|
|
def putDerefedPointer(self, value):
|
|
|
|
derefValue = value.dereference()
|
2020-02-24 14:37:56 +01:00
|
|
|
innerType = value.type.target() # .unqualified()
|
2017-04-24 16:42:30 +02:00
|
|
|
self.putType(innerType)
|
|
|
|
savedCurrentChildType = self.currentChildType
|
|
|
|
self.currentChildType = innerType.name
|
|
|
|
derefValue.name = '*'
|
2021-02-17 08:40:48 +01:00
|
|
|
derefValue.autoDerefCount = value.autoDerefCount + 1
|
|
|
|
|
|
|
|
if derefValue.type.code != TypeCode.Pointer:
|
|
|
|
self.putField('autoderefcount', '{}'.format(derefValue.autoDerefCount))
|
|
|
|
|
2017-04-24 16:42:30 +02:00
|
|
|
self.putItem(derefValue)
|
|
|
|
self.currentChildType = savedCurrentChildType
|
|
|
|
|
2016-11-07 08:57:26 +01:00
|
|
|
def putFormattedPointerX(self, value):
|
2017-05-08 14:50:33 +03:00
|
|
|
self.putOriginalAddress(value.address())
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("PUT FORMATTED: %s" % value)
|
2016-09-06 08:54:43 +02:00
|
|
|
pointer = value.pointer()
|
2017-05-10 11:22:15 +03:00
|
|
|
self.putAddress(pointer)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('POINTER: 0x%x' % pointer)
|
2016-09-06 08:54:43 +02:00
|
|
|
if pointer == 0:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('NULL POINTER')
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(value.type)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x0')
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
typeName = value.type.name
|
2015-04-13 15:52:07 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
|
|
|
self.readRawMemory(pointer, 1)
|
|
|
|
except:
|
2013-11-06 17:57:12 +01:00
|
|
|
# Failure to dereference a pointer should at least
|
|
|
|
# show the value of a pointer.
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('BAD POINTER: %s' % value)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % pointer)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2017-04-24 16:42:30 +02:00
|
|
|
if self.currentIName.endswith('.this'):
|
|
|
|
self.putDerefedPointer(value)
|
|
|
|
return
|
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
displayFormat = self.currentItemFormat(value.type.name)
|
2020-02-24 14:37:56 +01:00
|
|
|
innerType = value.type.target() # .unqualified()
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
if innerType.name == 'void':
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('VOID POINTER: %s' % displayFormat)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2016-10-31 17:59:49 +01:00
|
|
|
self.putSymbolValue(pointer)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat == DisplayFormat.Raw:
|
2013-11-06 17:57:12 +01:00
|
|
|
# Explicitly requested bald pointer.
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('RAW')
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % pointer)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2013-11-06 17:57:12 +01:00
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
with Children(self):
|
|
|
|
with SubItem(self, '*'):
|
|
|
|
self.putItem(value.dereference())
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2015-03-05 17:39:32 +01:00
|
|
|
limit = self.displayStringLimit
|
2020-02-24 15:10:47 +01:00
|
|
|
if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String):
|
2015-03-05 17:39:32 +01:00
|
|
|
limit = 1000000
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.tryPutSimpleFormattedPointer(pointer, typeName,
|
2016-09-29 00:04:04 +02:00
|
|
|
innerType, displayFormat, limit):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array1000:
|
|
|
|
n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10]
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2013-11-22 01:21:57 +01:00
|
|
|
self.putItemCount(n)
|
2017-05-15 09:32:23 +02:00
|
|
|
self.putArrayData(value.pointer(), n, innerType)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if innerType.code == TypeCode.Function:
|
2013-11-06 17:57:12 +01:00
|
|
|
# A function pointer.
|
2016-10-31 17:59:49 +01:00
|
|
|
self.putSymbolValue(pointer)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeName)
|
2013-11-06 17:57:12 +01:00
|
|
|
return
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers)
|
|
|
|
#DumperBase.warn('INAME: %s' % self.currentIName)
|
|
|
|
#DumperBase.warn('INNER: %s' % innerType.name)
|
2017-04-24 16:42:30 +02:00
|
|
|
if self.autoDerefPointers:
|
|
|
|
# Generic pointer type with AutomaticFormat, but never dereference char types:
|
2020-02-24 14:37:56 +01:00
|
|
|
if innerType.name not in (
|
|
|
|
'char',
|
|
|
|
'signed char',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int8_t',
|
|
|
|
'qint8',
|
2020-02-24 14:37:56 +01:00
|
|
|
'unsigned char',
|
2021-10-29 14:11:10 +02:00
|
|
|
'uint8_t',
|
2021-10-31 14:28:45 +01:00
|
|
|
'quint8',
|
2020-02-24 14:37:56 +01:00
|
|
|
'wchar_t',
|
|
|
|
'CHAR',
|
2021-10-31 14:28:45 +01:00
|
|
|
'WCHAR',
|
|
|
|
'char8_t',
|
|
|
|
'char16_t',
|
|
|
|
'char32_t'
|
2020-02-24 14:37:56 +01:00
|
|
|
):
|
2017-04-24 16:42:30 +02:00
|
|
|
self.putDerefedPointer(value)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type)
|
|
|
|
#DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2016-11-03 17:08:55 +01:00
|
|
|
self.putSymbolValue(pointer)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2013-11-06 17:57:12 +01:00
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '*'):
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putItem(value.dereference())
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def putOriginalAddress(self, address):
|
|
|
|
if address is not None:
|
|
|
|
self.put('origaddr="0x%x",' % address)
|
Debugger: Make dumpers somewhat work in command line GDB
With
python sys.path.insert(1, '/data/dev/creator/share/qtcreator/debugger/')
python from gdbbridge import *
in .gdbinit there's a new "GDB command", called "pp".
With code like
int main(int argc, char *argv[])
{
QString ss = "Hello";
QApplication app(argc, argv);
app.setObjectName(ss);
// break here
}
the 'pp' command can be used as follows:
(gdb) pp app
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = <Myns::QObjectList> = {"<3 items>"}
[properties] = "<>0 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp app [properties],[children]
app =
[
<Myns::QGuiApplication> = {"Hello"}
staticMetaObject = <Myns::QMetaObject> = {""}
[parent] = <Myns::QObject *> = {"0x0"}
[children] = [
<Myns::QObject> = {""}
<Myns::QObject> = {""}
<Myns::QObject> = {"fusion"}
],<Myns::QObjectList> = {"<3 items>"}
[properties] = [
windowIcon = <Myns::QVariant (QIcon)> = {""}
cursorFlashTime = <Myns::QVariant (int)> = {"1000"}
doubleClickInterval = <Myns::QVariant (int)> = {"400"}
keyboardInputInterval = <Myns::QVariant (int)> = {"400"}
wheelScrollLines = <Myns::QVariant (int)> = {"3"}
globalStrut = <Myns::QVariant (QSize)> = {"(0, 0)"}
startDragTime = <Myns::QVariant (int)> = {"500"}
startDragDistance = <Myns::QVariant (int)> = {"10"}
styleSheet = <Myns::QVariant (QString)> = {""}
autoSipEnabled = <Myns::QVariant (bool)> = {"true"}
],"<10 items>"
[methods] = "<6 items>"
[signals] = "<1 items>"
],<Myns::QApplication> = {"Hello"}
(gdb) pp ss
ss =
<Myns::QString> = {"Hello"}
Change-Id: I6e4714a5cfe34c38917500d114ad9a70d20cff39
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
2014-06-13 17:45:34 +02:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def putQObjectNameValue(self, value):
|
|
|
|
try:
|
2016-10-07 11:49:51 +02:00
|
|
|
# dd = value['d_ptr']['d'] is just behind the vtable.
|
|
|
|
(vtable, dd) = self.split('pp', value)
|
2016-12-01 09:22:53 +01:00
|
|
|
if not self.couldBeQObjectVTable(vtable):
|
|
|
|
return False
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
intSize = 4
|
|
|
|
ptrSize = self.ptrSize()
|
2020-11-25 17:18:24 +01:00
|
|
|
if self.qtVersion() >= 0x060000:
|
2021-03-19 09:34:09 +01:00
|
|
|
# Size of QObjectData: 9 pointer + 2 int
|
2020-11-25 17:18:24 +01:00
|
|
|
# - vtable
|
2013-09-11 21:35:39 +02:00
|
|
|
# - QObject *q_ptr;
|
|
|
|
# - QObject *parent;
|
|
|
|
# - QObjectList children;
|
2020-11-25 17:18:24 +01:00
|
|
|
# - uint isWidget : 1; etc...
|
2013-09-11 21:35:39 +02:00
|
|
|
# - int postedEvents;
|
2020-11-25 17:18:24 +01:00
|
|
|
# - QDynamicMetaObjectData *metaObject;
|
2021-03-19 09:34:09 +01:00
|
|
|
# - QBindingStorage bindingStorage;
|
|
|
|
extra = self.extractPointer(dd + 9 * ptrSize + 2 * intSize)
|
2020-11-25 17:18:24 +01:00
|
|
|
if extra == 0:
|
|
|
|
return False
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2020-11-25 17:18:24 +01:00
|
|
|
# Offset of objectName in ExtraData: 12 pointer
|
|
|
|
# - QList<QByteArray> propertyNames;
|
|
|
|
# - QList<QVariant> propertyValues;
|
|
|
|
# - QVector<int> runningTimers;
|
|
|
|
# - QList<QPointer<QObject> > eventFilters;
|
2013-09-11 21:35:39 +02:00
|
|
|
# - QString objectName
|
2020-11-25 17:18:24 +01:00
|
|
|
objectNameAddress = extra + 12 * ptrSize
|
|
|
|
elif self.qtVersion() >= 0x050000:
|
2013-09-11 21:35:39 +02:00
|
|
|
# Size of QObjectData: 5 pointer + 2 int
|
|
|
|
# - vtable
|
|
|
|
# - QObject *q_ptr;
|
|
|
|
# - QObject *parent;
|
|
|
|
# - QObjectList children;
|
|
|
|
# - uint isWidget : 1; etc...
|
|
|
|
# - int postedEvents;
|
|
|
|
# - QDynamicMetaObjectData *metaObject;
|
2014-01-30 16:15:22 +01:00
|
|
|
extra = self.extractPointer(dd + 5 * ptrSize + 2 * intSize)
|
2013-09-11 21:35:39 +02:00
|
|
|
if extra == 0:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Offset of objectName in ExtraData: 6 pointer
|
|
|
|
# - QVector<QObjectUserData *> userData; only #ifndef QT_NO_USERDATA
|
|
|
|
# - QList<QByteArray> propertyNames;
|
|
|
|
# - QList<QVariant> propertyValues;
|
|
|
|
# - QVector<int> runningTimers;
|
|
|
|
# - QList<QPointer<QObject> > eventFilters;
|
|
|
|
# - QString objectName
|
2020-11-24 17:53:08 +01:00
|
|
|
objectNameAddress = extra + 5 * ptrSize
|
2020-11-25 17:18:24 +01:00
|
|
|
else:
|
|
|
|
# Size of QObjectData: 5 pointer + 2 int
|
|
|
|
# - vtable
|
|
|
|
# - QObject *q_ptr;
|
|
|
|
# - QObject *parent;
|
|
|
|
# - QObjectList children;
|
|
|
|
# - uint isWidget : 1; etc..
|
|
|
|
# - int postedEvents;
|
|
|
|
# - QMetaObject *metaObject;
|
|
|
|
|
|
|
|
# Offset of objectName in QObjectPrivate: 5 pointer + 2 int
|
|
|
|
# - [QObjectData base]
|
|
|
|
# - QString objectName
|
|
|
|
objectNameAddress = dd + 5 * ptrSize + 2 * intSize
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2020-11-24 17:53:08 +01:00
|
|
|
data, size, alloc = self.qArrayData(objectNameAddress)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-05-30 10:11:10 +02:00
|
|
|
# Object names are short, and GDB can crash on to big chunks.
|
|
|
|
# Since this here is a convenience feature only, limit it.
|
|
|
|
if size <= 0 or size > 80:
|
2013-09-11 21:35:39 +02:00
|
|
|
return False
|
|
|
|
|
2014-01-20 15:03:27 +01:00
|
|
|
raw = self.readMemory(data, 2 * size)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(raw, 'utf16', 1)
|
2013-09-11 21:35:39 +02:00
|
|
|
return True
|
|
|
|
|
|
|
|
except:
|
2020-02-24 14:37:56 +01:00
|
|
|
# warn('NO QOBJECT: %s' % value.type)
|
2016-12-01 09:22:53 +01:00
|
|
|
return False
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
def couldBePointer(self, p):
|
2016-09-26 14:29:16 +02:00
|
|
|
if self.ptrSize() == 4:
|
|
|
|
return p > 100000 and (p & 0x3 == 0)
|
|
|
|
else:
|
|
|
|
return p > 100000 and (p & 0x7 == 0) and (p < 0x7fffffffffff)
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
def couldBeVTableEntry(self, p):
|
2016-11-02 13:04:21 +01:00
|
|
|
if self.ptrSize() == 4:
|
|
|
|
return p > 100000 and (p & 0x1 == 0)
|
|
|
|
else:
|
|
|
|
return p > 100000 and (p & 0x1 == 0) and (p < 0x7fffffffffff)
|
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
def couldBeQObjectPointer(self, objectPtr):
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
2016-12-01 09:22:53 +01:00
|
|
|
vtablePtr, dd = self.split('pp', objectPtr)
|
2016-09-06 08:54:43 +02:00
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('nostruct-1')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-11-02 13:04:21 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
2016-12-01 09:22:53 +01:00
|
|
|
dvtablePtr, qptr, parentPtr = self.split('ppp', dd)
|
2016-09-06 08:54:43 +02:00
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('nostruct-2')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
|
|
|
# Check d_ptr.d.q_ptr == objectPtr
|
|
|
|
if qptr != objectPtr:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('q_ptr')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-12-01 09:22:53 +01:00
|
|
|
|
|
|
|
return self.couldBeQObjectVTable(vtablePtr)
|
|
|
|
|
|
|
|
def couldBeQObjectVTable(self, vtablePtr):
|
2017-03-14 07:36:33 +01:00
|
|
|
def getJumpAddress_x86(dumper, address):
|
|
|
|
relativeJumpCode = 0xe9
|
|
|
|
jumpCode = 0xff
|
2017-03-31 10:44:28 +02:00
|
|
|
try:
|
|
|
|
data = dumper.readRawMemory(address, 6)
|
|
|
|
except:
|
|
|
|
return 0
|
2017-03-14 07:36:33 +01:00
|
|
|
primaryOpcode = data[0]
|
|
|
|
if primaryOpcode == relativeJumpCode:
|
|
|
|
# relative jump on 32 and 64 bit with a 32bit offset
|
|
|
|
offset = int.from_bytes(data[1:5], byteorder='little')
|
|
|
|
return address + 5 + offset
|
|
|
|
if primaryOpcode == jumpCode:
|
2020-02-24 14:37:56 +01:00
|
|
|
if data[1] != 0x25: # check for known extended opcode
|
2017-03-14 07:36:33 +01:00
|
|
|
return 0
|
|
|
|
# 0xff25 is a relative jump on 64bit and an absolute jump on 32 bit
|
|
|
|
if self.ptrSize() == 8:
|
|
|
|
offset = int.from_bytes(data[2:6], byteorder='little')
|
|
|
|
return address + 6 + offset
|
|
|
|
else:
|
|
|
|
return int.from_bytes(data[2:6], byteorder='little')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
# Do not try to extract a function pointer if there are no values to compare with
|
|
|
|
if self.qtCustomEventFunc == 0 and self.qtCustomEventPltFunc == 0:
|
|
|
|
return False
|
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
try:
|
2017-03-14 07:36:33 +01:00
|
|
|
customEventOffset = 8 if self.isMsvcTarget() else 9
|
|
|
|
customEventFunc = self.extractPointer(vtablePtr + customEventOffset * self.ptrSize())
|
2016-12-01 09:22:53 +01:00
|
|
|
except:
|
|
|
|
self.bump('nostruct-3')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
|
|
|
|
2017-03-14 07:36:33 +01:00
|
|
|
if self.isWindowsTarget():
|
|
|
|
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
|
|
|
|
return True
|
|
|
|
# The vtable may point to a function that is just calling the customEvent function
|
|
|
|
customEventFunc = getJumpAddress_x86(self, customEventFunc)
|
|
|
|
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
|
|
|
|
return True
|
|
|
|
customEventFunc = self.extractPointer(customEventFunc)
|
|
|
|
if customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc):
|
|
|
|
return True
|
|
|
|
# If the object is defined in another module there may be another level of indirection
|
|
|
|
customEventFunc = getJumpAddress_x86(self, customEventFunc)
|
2020-05-29 13:08:07 +02:00
|
|
|
|
2016-12-02 13:07:58 +01:00
|
|
|
return customEventFunc in (self.qtCustomEventFunc, self.qtCustomEventPltFunc)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2017-03-16 15:44:47 +01:00
|
|
|
# def extractQObjectProperty(objectPtr):
|
|
|
|
# vtablePtr = self.extractPointer(objectPtr)
|
|
|
|
# metaObjectFunc = self.extractPointer(vtablePtr)
|
|
|
|
# cmd = '((void*(*)(void*))0x%x)((void*)0x%x)' % (metaObjectFunc, objectPtr)
|
|
|
|
# try:
|
2020-02-21 10:10:00 +01:00
|
|
|
# #DumperBase.warn('MO CMD: %s' % cmd)
|
2017-03-16 15:44:47 +01:00
|
|
|
# res = self.parseAndEvaluate(cmd)
|
2020-02-21 10:10:00 +01:00
|
|
|
# #DumperBase.warn('MO RES: %s' % res)
|
2017-03-16 15:44:47 +01:00
|
|
|
# self.bump('successfulMetaObjectCall')
|
|
|
|
# return res.pointer()
|
|
|
|
# except:
|
|
|
|
# self.bump('failedMetaObjectCall')
|
2020-02-21 10:10:00 +01:00
|
|
|
# #DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
|
2017-03-16 15:44:47 +01:00
|
|
|
# return 0
|
2016-12-02 09:06:05 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def extractMetaObjectPtr(self, objectPtr, typeobj):
|
|
|
|
""" objectPtr - address of *potential* instance of QObject derived class
|
|
|
|
typeobj - type of *objectPtr if known, None otherwise. """
|
|
|
|
|
|
|
|
if objectPtr is not None:
|
|
|
|
self.checkIntType(objectPtr)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
def extractMetaObjectPtrFromAddress():
|
2016-12-01 09:22:53 +01:00
|
|
|
#return 0
|
2016-10-07 11:49:51 +02:00
|
|
|
# FIXME: Calling 'works' but seems to impact memory contents(!)
|
2016-08-01 12:22:26 +02:00
|
|
|
# in relevant places. One symptom is that object name
|
2016-10-07 11:49:51 +02:00
|
|
|
# contents 'vanishes' as the reported size of the string
|
2016-08-01 12:22:26 +02:00
|
|
|
# gets zeroed out(?).
|
2016-07-22 10:20:01 +02:00
|
|
|
# Try vtable, metaObject() is the first entry.
|
|
|
|
vtablePtr = self.extractPointer(objectPtr)
|
|
|
|
metaObjectFunc = self.extractPointer(vtablePtr)
|
2016-10-07 11:49:51 +02:00
|
|
|
cmd = '((void*(*)(void*))0x%x)((void*)0x%x)' % (metaObjectFunc, objectPtr)
|
2016-07-22 10:20:01 +02:00
|
|
|
try:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('MO CMD: %s' % cmd)
|
2016-07-22 10:20:01 +02:00
|
|
|
res = self.parseAndEvaluate(cmd)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('MO RES: %s' % res)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('successfulMetaObjectCall')
|
2016-12-01 09:22:53 +01:00
|
|
|
return res.pointer()
|
2016-07-22 10:20:01 +02:00
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('failedMetaObjectCall')
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
|
2016-07-22 10:20:01 +02:00
|
|
|
return 0
|
2014-03-19 16:08:45 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def extractStaticMetaObjectFromTypeHelper(someTypeObj):
|
|
|
|
if someTypeObj.isSimpleType():
|
2014-03-19 16:08:45 +01:00
|
|
|
return 0
|
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
typeName = someTypeObj.name
|
2016-10-07 11:49:51 +02:00
|
|
|
isQObjectProper = typeName == self.qtNamespace() + 'QObject'
|
2016-07-22 10:20:01 +02:00
|
|
|
|
2016-11-02 13:04:21 +01:00
|
|
|
# No templates for now.
|
|
|
|
if typeName.find('<') >= 0:
|
|
|
|
return 0
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2017-03-07 08:40:43 +01:00
|
|
|
result = self.findStaticMetaObject(someTypeObj)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
# We need to distinguish Q_OBJECT from Q_GADGET:
|
|
|
|
# a Q_OBJECT SMO has a non-null superdata (unless it's QObject itself),
|
|
|
|
# a Q_GADGET SMO has a null superdata (hopefully)
|
|
|
|
if result and not isQObjectProper:
|
2020-12-11 13:48:08 +01:00
|
|
|
if self.qtVersion() >= 0x60000 and self.isWindowsTarget():
|
|
|
|
(direct, indirect) = self.split('pp', result)
|
|
|
|
# since Qt 6 there is an additional indirect super data getter on windows
|
|
|
|
if direct == 0 and indirect == 0:
|
|
|
|
# This looks like a Q_GADGET
|
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
if self.extractPointer(result) == 0:
|
|
|
|
# This looks like a Q_GADGET
|
|
|
|
return 0
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
def extractStaticMetaObjectPtrFromType(someTypeObj):
|
|
|
|
if someTypeObj is None:
|
2014-03-27 17:41:16 +01:00
|
|
|
return 0
|
2016-09-15 17:55:56 +02:00
|
|
|
someTypeName = someTypeObj.name
|
2016-07-22 10:20:01 +02:00
|
|
|
self.bump('metaObjectFromType')
|
|
|
|
known = self.knownStaticMetaObjects.get(someTypeName, None)
|
2020-02-24 14:37:56 +01:00
|
|
|
if known is not None: # Is 0 or the static metaobject.
|
2016-07-22 10:20:01 +02:00
|
|
|
return known
|
|
|
|
|
|
|
|
result = 0
|
|
|
|
#try:
|
|
|
|
result = extractStaticMetaObjectFromTypeHelper(someTypeObj)
|
|
|
|
#except RuntimeError as error:
|
2016-10-07 11:49:51 +02:00
|
|
|
# warn('METAOBJECT EXTRACTION FAILED: %s' % error)
|
2016-07-22 10:20:01 +02:00
|
|
|
#except:
|
2016-10-07 11:49:51 +02:00
|
|
|
# warn('METAOBJECT EXTRACTION FAILED FOR UNKNOWN REASON')
|
2016-07-22 10:20:01 +02:00
|
|
|
|
2016-11-02 13:04:21 +01:00
|
|
|
#if not result:
|
|
|
|
# base = someTypeObj.firstBase()
|
|
|
|
# if base is not None and base != someTypeObj: # sanity check
|
|
|
|
# result = extractStaticMetaObjectPtrFromType(base)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
if result:
|
|
|
|
self.knownStaticMetaObjects[someTypeName] = result
|
2016-07-22 10:20:01 +02:00
|
|
|
return result
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2014-03-19 16:08:45 +01:00
|
|
|
if not self.useFancy:
|
|
|
|
return 0
|
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
ptrSize = self.ptrSize()
|
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
typeName = typeobj.name
|
2014-03-12 13:20:21 +01:00
|
|
|
result = self.knownStaticMetaObjects.get(typeName, None)
|
2020-02-24 14:37:56 +01:00
|
|
|
if result is not None: # Is 0 or the static metaobject.
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('typecached')
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('CACHED RESULT: %s %s 0x%x' % (self.currentIName, typeName, result))
|
2014-03-12 13:20:21 +01:00
|
|
|
return result
|
|
|
|
|
2016-12-01 09:22:53 +01:00
|
|
|
if not self.couldBeQObjectPointer(objectPtr):
|
2016-07-22 10:20:01 +02:00
|
|
|
self.bump('cannotBeQObject')
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('DOES NOT LOOK LIKE A QOBJECT: %s' % self.currentIName)
|
2016-07-22 10:20:01 +02:00
|
|
|
return 0
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
metaObjectPtr = 0
|
|
|
|
if not metaObjectPtr:
|
|
|
|
# measured: 3 ms (example had one level of inheritance)
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('metaObjectType-' + self.currentIName):
|
2016-07-22 10:20:01 +02:00
|
|
|
metaObjectPtr = extractStaticMetaObjectPtrFromType(typeobj)
|
|
|
|
|
2020-05-05 11:30:51 +02:00
|
|
|
if not metaObjectPtr and not self.isWindowsTarget():
|
2016-07-22 10:20:01 +02:00
|
|
|
# measured: 200 ms (example had one level of inheritance)
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('metaObjectCall-' + self.currentIName):
|
2016-07-22 10:20:01 +02:00
|
|
|
metaObjectPtr = extractMetaObjectPtrFromAddress()
|
|
|
|
|
|
|
|
#if metaObjectPtr:
|
|
|
|
# self.bump('foundMetaObject')
|
|
|
|
# self.knownStaticMetaObjects[typeName] = metaObjectPtr
|
|
|
|
|
|
|
|
return metaObjectPtr
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def split(self, pattern, value):
|
|
|
|
if isinstance(value, self.Value):
|
|
|
|
return value.split(pattern)
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.isInt(value):
|
2016-09-06 08:54:43 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val.laddress = value
|
|
|
|
return val.split(pattern)
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('CANNOT EXTRACT STRUCT FROM %s' % type(value))
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2014-01-29 13:40:09 +01:00
|
|
|
def extractCString(self, addr):
|
|
|
|
result = bytearray()
|
|
|
|
while True:
|
|
|
|
d = self.extractByte(addr)
|
|
|
|
if d == 0:
|
|
|
|
break
|
|
|
|
result.append(d)
|
|
|
|
addr += 1
|
|
|
|
return result
|
|
|
|
|
2020-12-07 15:15:58 +01:00
|
|
|
def listData(self, value, check=True):
|
|
|
|
if self.qtVersion() >= 0x60000:
|
|
|
|
dd, data, size = self.split('ppi', value)
|
|
|
|
return data, size
|
|
|
|
|
|
|
|
base = self.extractPointer(value)
|
2016-09-06 08:54:43 +02:00
|
|
|
(ref, alloc, begin, end) = self.split('IIII', base)
|
2014-03-20 12:38:56 +01:00
|
|
|
array = base + 16
|
|
|
|
if self.qtVersion() < 0x50000:
|
|
|
|
array += self.ptrSize()
|
2014-02-07 23:00:26 +01:00
|
|
|
size = end - begin
|
2020-12-07 15:15:58 +01:00
|
|
|
|
|
|
|
if check:
|
|
|
|
self.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
|
|
|
|
size = end - begin
|
|
|
|
self.check(size >= 0)
|
|
|
|
|
2014-03-20 12:38:56 +01:00
|
|
|
stepSize = self.ptrSize()
|
2016-09-06 08:54:43 +02:00
|
|
|
data = array + begin * stepSize
|
2020-12-07 15:15:58 +01:00
|
|
|
return data, size
|
2015-11-09 13:23:20 +01:00
|
|
|
|
2016-08-01 12:32:38 +02:00
|
|
|
def putTypedPointer(self, name, addr, typeName):
|
|
|
|
""" Prints a typed pointer, expandable if the type can be resolved,
|
|
|
|
and without children otherwise """
|
|
|
|
with SubItem(self, name):
|
|
|
|
self.putAddress(addr)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('@0x%x' % addr)
|
2016-08-01 12:32:38 +02:00
|
|
|
typeObj = self.lookupType(typeName)
|
|
|
|
if typeObj:
|
|
|
|
self.putType(typeObj)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-08-01 12:32:38 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(self.createValue(addr, typeObj))
|
|
|
|
else:
|
|
|
|
self.putType(typeName)
|
|
|
|
|
2014-01-20 15:03:27 +01:00
|
|
|
# This is called is when a QObject derived class is expanded
|
2016-12-01 09:22:53 +01:00
|
|
|
def tryPutQObjectGuts(self, value):
|
|
|
|
metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
|
|
|
|
if metaObjectPtr:
|
|
|
|
self.putQObjectGutsHelper(value, value.address(),
|
|
|
|
-1, metaObjectPtr, 'QObject')
|
2014-04-03 22:08:35 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def metaString(self, metaObjectPtr, index, revision):
|
2016-07-22 10:20:01 +02:00
|
|
|
ptrSize = self.ptrSize()
|
2021-03-19 13:42:05 +01:00
|
|
|
stringdataOffset = ptrSize
|
2021-04-14 09:41:09 +02:00
|
|
|
if self.isWindowsTarget() and self.qtVersion() >= 0x060000:
|
2021-03-19 13:42:05 +01:00
|
|
|
stringdataOffset += ptrSize # indirect super data member
|
2021-09-23 12:31:49 +00:00
|
|
|
stringdata = self.extractPointer(toInteger(metaObjectPtr) + stringdataOffset)
|
2020-11-26 12:37:45 +01:00
|
|
|
|
|
|
|
def unpackString(base, size):
|
2016-07-14 13:13:16 +02:00
|
|
|
try:
|
2020-11-26 12:37:45 +01:00
|
|
|
s = struct.unpack_from('%ds' % size, self.readRawMemory(base, size))[0]
|
2021-09-23 12:31:49 +00:00
|
|
|
return s if sys.version_info[0] == 2 else s.decode('utf8')
|
2016-07-14 13:13:16 +02:00
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
return '<not available>'
|
2020-11-26 12:37:45 +01:00
|
|
|
|
|
|
|
if revision >= 9: # Qt 6.
|
|
|
|
pos, size = self.split('II', stringdata + 8 * index)
|
|
|
|
return unpackString(stringdata + pos, size)
|
|
|
|
|
|
|
|
if revision >= 7: # Qt 5.
|
|
|
|
byteArrayDataSize = 24 if ptrSize == 8 else 16
|
2021-09-23 12:31:49 +00:00
|
|
|
literal = stringdata + toInteger(index) * byteArrayDataSize
|
2020-11-26 12:37:45 +01:00
|
|
|
base, size, _ = self.qArrayDataHelper(literal)
|
|
|
|
return unpackString(base, size)
|
|
|
|
|
|
|
|
ldata = stringdata + index
|
|
|
|
return self.extractCString(ldata).decode('utf8')
|
2016-07-13 14:17:18 +02:00
|
|
|
|
2020-05-29 13:08:07 +02:00
|
|
|
def putSortGroup(self, sortorder):
|
|
|
|
if not self.isCli:
|
|
|
|
self.putField('sortgroup', sortorder)
|
|
|
|
|
2016-07-14 13:13:16 +02:00
|
|
|
def putQMetaStuff(self, value, origType):
|
2020-11-26 12:37:45 +01:00
|
|
|
if self.qtVersion() >= 0x060000:
|
|
|
|
metaObjectPtr, handle = value.split('pp')
|
|
|
|
else:
|
|
|
|
metaObjectPtr, handle = value.split('pI')
|
2016-09-06 08:54:43 +02:00
|
|
|
if metaObjectPtr != 0:
|
2020-11-26 12:37:45 +01:00
|
|
|
if self.qtVersion() >= 0x060000:
|
2020-12-09 13:25:09 +01:00
|
|
|
if handle == 0:
|
|
|
|
self.putEmptyValue()
|
|
|
|
return
|
2020-11-26 12:37:45 +01:00
|
|
|
revision = 9
|
|
|
|
name, alias, flags, keyCount, data = self.split('IIIII', handle)
|
|
|
|
index = name
|
|
|
|
elif self.qtVersion() >= 0x050000:
|
|
|
|
revision = 7
|
|
|
|
dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
|
|
|
|
index = self.extractInt(dataPtr + 4 * handle)
|
|
|
|
else:
|
|
|
|
revision = 6
|
|
|
|
dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
|
|
|
|
index = self.extractInt(dataPtr + 4 * handle)
|
|
|
|
#self.putValue("index: %s rev: %s" % (index, revision))
|
2016-09-06 08:54:43 +02:00
|
|
|
name = self.metaString(metaObjectPtr, index, revision)
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putValue(name)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-07-14 13:13:16 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(value)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putQObjectGutsHelper(0, 0, handle, metaObjectPtr, origType)
|
2016-07-14 13:13:16 +02:00
|
|
|
else:
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putEmptyValue()
|
2016-07-14 13:13:16 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(value)
|
2016-07-13 14:17:18 +02:00
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
# basically all meta things go through this here.
|
|
|
|
# qobject and qobjectPtr are non-null if coming from a real structure display
|
|
|
|
# qobject == 0, qobjectPtr != 0 is possible for builds without QObject debug info
|
|
|
|
# if qobject == 0, properties and d-ptr cannot be shown.
|
2016-09-06 08:54:43 +02:00
|
|
|
# handle is what's store in QMetaMethod etc, pass -1 for QObject/QMetaObject
|
|
|
|
# itself metaObjectPtr needs to point to a valid QMetaObject.
|
2016-07-22 10:20:01 +02:00
|
|
|
def putQObjectGutsHelper(self, qobject, qobjectPtr, handle, metaObjectPtr, origType):
|
2016-07-13 14:17:18 +02:00
|
|
|
ptrSize = self.ptrSize()
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putt(name, value, typeName=' '):
|
2016-07-13 14:17:18 +02:00
|
|
|
with SubItem(self, name):
|
|
|
|
self.putValue(value)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putType(typeName)
|
2016-07-13 14:17:18 +02:00
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
def extractSuperDataPtr(someMetaObjectPtr):
|
|
|
|
#return someMetaObjectPtr['d']['superdata']
|
|
|
|
return self.extractPointer(someMetaObjectPtr)
|
|
|
|
|
|
|
|
def extractDataPtr(someMetaObjectPtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
# dataPtr = metaObjectPtr['d']['data']
|
2020-12-11 13:48:08 +01:00
|
|
|
if self.qtVersion() >= 0x60000 and self.isWindowsTarget():
|
|
|
|
offset = 3
|
|
|
|
else:
|
|
|
|
offset = 2
|
|
|
|
return self.extractPointer(someMetaObjectPtr + offset * ptrSize)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
isQMetaObject = origType == 'QMetaObject'
|
|
|
|
isQObject = origType == 'QObject'
|
2016-07-14 13:13:16 +02:00
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('OBJECT GUTS: %s 0x%x ' % (self.currentIName, metaObjectPtr))
|
2016-07-22 10:20:01 +02:00
|
|
|
dataPtr = extractDataPtr(metaObjectPtr)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('DATA PTRS: %s 0x%x ' % (self.currentIName, dataPtr))
|
2016-07-22 10:20:01 +02:00
|
|
|
(revision, classname,
|
|
|
|
classinfo, classinfo2,
|
|
|
|
methodCount, methods,
|
|
|
|
propertyCount, properties,
|
|
|
|
enumCount, enums,
|
|
|
|
constructorCount, constructors,
|
2016-09-06 08:54:43 +02:00
|
|
|
flags, signalCount) = self.split('I' * 14, dataPtr)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
largestStringIndex = -1
|
|
|
|
for i in range(methodCount):
|
2016-09-06 08:54:43 +02:00
|
|
|
t = self.split('IIIII', dataPtr + 56 + i * 20)
|
2016-07-14 13:13:16 +02:00
|
|
|
if largestStringIndex < t[0]:
|
|
|
|
largestStringIndex = t[0]
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
ns = self.qtNamespace()
|
2016-07-22 10:20:01 +02:00
|
|
|
extraData = 0
|
|
|
|
if qobjectPtr:
|
|
|
|
dd = self.extractPointer(qobjectPtr + ptrSize)
|
2021-03-19 14:56:11 +01:00
|
|
|
if self.qtVersion() >= 0x60000:
|
|
|
|
(dvtablePtr, qptr, parent, children, bindingStorageData, bindingStatus,
|
|
|
|
flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData.
|
|
|
|
extraData, threadDataPtr, connectionListsPtr,
|
|
|
|
sendersPtr, currentSenderPtr) \
|
|
|
|
= self.split('pp{@QObject*}{@QList<@QObject *>}ppIIp' + 'ppppp', dd)
|
|
|
|
elif self.qtVersion() >= 0x50000:
|
2020-12-09 15:23:07 +01:00
|
|
|
(dvtablePtr, qptr, parent, children, flags, postedEvents,
|
2020-02-24 14:37:56 +01:00
|
|
|
dynMetaObjectPtr, # Up to here QObjectData.
|
2016-09-06 08:54:43 +02:00
|
|
|
extraData, threadDataPtr, connectionListsPtr,
|
|
|
|
sendersPtr, currentSenderPtr) \
|
2020-12-10 11:02:47 +01:00
|
|
|
= self.split('pp{@QObject*}{@QList<@QObject *>}IIp' + 'ppppp', dd)
|
2016-08-01 12:32:38 +02:00
|
|
|
else:
|
2020-12-09 15:23:07 +01:00
|
|
|
(dvtablePtr, qptr, parent, children, flags, postedEvents,
|
2020-02-24 14:37:56 +01:00
|
|
|
dynMetaObjectPtr, # Up to here QObjectData
|
2016-09-06 08:54:43 +02:00
|
|
|
objectName, extraData, threadDataPtr, connectionListsPtr,
|
|
|
|
sendersPtr, currentSenderPtr) \
|
2020-12-10 11:02:47 +01:00
|
|
|
= self.split('pp{@QObject*}{@QList<@QObject *>}IIp' + 'pppppp', dd)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[parent]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putSortGroup(9)
|
2020-12-09 15:23:07 +01:00
|
|
|
self.putItem(parent)
|
2020-11-26 13:14:20 +01:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[children]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putSortGroup(8)
|
2020-12-08 11:58:00 +01:00
|
|
|
|
2020-12-10 11:02:47 +01:00
|
|
|
dvtablePtr, qptr, parentPtr, children = self.split('ppp{QList<QObject *>}', dd)
|
|
|
|
self.putItem(children)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[strings]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putSortGroup(2)
|
2016-07-22 10:20:01 +02:00
|
|
|
if largestStringIndex > 0:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', largestStringIndex)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-07-22 10:20:01 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self, largestStringIndex + 1):
|
|
|
|
for i in self.childRange():
|
|
|
|
with SubItem(self, i):
|
2016-09-06 08:54:43 +02:00
|
|
|
s = self.metaString(metaObjectPtr, i, revision)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(self.hexencode(s), 'latin1')
|
2016-07-22 10:20:01 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(' ')
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[raw]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(1)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putEmptyValue()
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-07-14 13:13:16 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
putt('revision', revision)
|
|
|
|
putt('classname', classname)
|
|
|
|
putt('classinfo', classinfo)
|
|
|
|
putt('methods', '%d %d' % (methodCount, methods))
|
|
|
|
putt('properties', '%d %d' % (propertyCount, properties))
|
|
|
|
putt('enums/sets', '%d %d' % (enumCount, enums))
|
|
|
|
putt('constructors', '%d %d' % (constructorCount, constructors))
|
|
|
|
putt('flags', flags)
|
|
|
|
putt('signalCount', signalCount)
|
2016-07-14 13:13:16 +02:00
|
|
|
for i in range(methodCount):
|
2016-09-06 08:54:43 +02:00
|
|
|
t = self.split('IIIII', dataPtr + 56 + i * 20)
|
2016-10-07 11:49:51 +02:00
|
|
|
putt('method %d' % i, '%s %s %s %s %s' % t)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
2016-08-01 12:32:38 +02:00
|
|
|
if isQObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[extra]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(1)
|
2016-08-01 12:32:38 +02:00
|
|
|
self.putEmptyValue()
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-08-01 12:32:38 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
if extraData:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putTypedPointer('[extraData]', extraData,
|
2020-02-24 14:37:56 +01:00
|
|
|
ns + 'QObjectPrivate::ExtraData')
|
2016-08-01 12:32:38 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[metaObject]'):
|
2016-08-01 12:32:38 +02:00
|
|
|
self.putAddress(metaObjectPtr)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-08-01 12:32:38 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
2020-02-24 14:37:56 +01:00
|
|
|
self.putQObjectGutsHelper(
|
|
|
|
0, 0, -1, metaObjectPtr, 'QMetaObject')
|
2016-08-01 12:32:38 +02:00
|
|
|
|
2019-07-31 12:37:43 +02:00
|
|
|
if False:
|
2020-02-24 14:37:56 +01:00
|
|
|
with SubItem(self, '[connections]'):
|
|
|
|
if connectionListsPtr:
|
|
|
|
typeName = '@QObjectConnectionListVector'
|
|
|
|
self.putItem(self.createValue(connectionListsPtr, typeName))
|
|
|
|
else:
|
|
|
|
self.putItemCount(0)
|
2017-03-15 12:12:05 +01:00
|
|
|
|
2019-07-31 12:37:43 +02:00
|
|
|
if False:
|
2020-02-24 14:37:56 +01:00
|
|
|
with SubItem(self, '[signals]'):
|
|
|
|
self.putItemCount(signalCount)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
j = -1
|
|
|
|
for i in range(signalCount):
|
|
|
|
t = self.split('IIIII', dataPtr + 56 + 20 * i)
|
|
|
|
flags = t[4]
|
|
|
|
if flags != 0x06:
|
|
|
|
continue
|
|
|
|
j += 1
|
|
|
|
with SubItem(self, j):
|
|
|
|
name = self.metaString(
|
|
|
|
metaObjectPtr, t[0], revision)
|
|
|
|
self.putType(' ')
|
|
|
|
self.putValue(name)
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2020-02-24 14:37:56 +01:00
|
|
|
with Children(self):
|
|
|
|
putt('[nameindex]', t[0])
|
|
|
|
#putt('[type]', 'signal')
|
|
|
|
putt('[argc]', t[1])
|
|
|
|
putt('[parameter]', t[2])
|
|
|
|
putt('[tag]', t[3])
|
|
|
|
putt('[flags]', t[4])
|
|
|
|
putt('[localindex]', str(i))
|
|
|
|
putt('[globalindex]', str(globalOffset + i))
|
|
|
|
#self.putQObjectConnections(dd)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject or isQObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[properties]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(5)
|
2016-07-13 14:17:18 +02:00
|
|
|
if self.isExpanded():
|
2016-08-01 12:52:40 +02:00
|
|
|
dynamicPropertyCount = 0
|
2016-07-13 14:17:18 +02:00
|
|
|
with Children(self):
|
|
|
|
# Static properties.
|
|
|
|
for i in range(propertyCount):
|
2020-12-03 16:33:02 +01:00
|
|
|
if self.qtVersion() >= 0x60000:
|
|
|
|
t = self.split('IIIII', dataPtr + properties * 4 + 20 * i)
|
|
|
|
else:
|
|
|
|
t = self.split('III', dataPtr + properties * 4 + 12 * i)
|
2016-09-06 08:54:43 +02:00
|
|
|
name = self.metaString(metaObjectPtr, t[0], revision)
|
2016-12-14 08:27:01 +01:00
|
|
|
if qobject and self.qtPropertyFunc:
|
2020-02-24 14:37:56 +01:00
|
|
|
# LLDB doesn't like calling it on a derived class, possibly
|
|
|
|
# due to type information living in a different shared object.
|
|
|
|
#base = self.createValue(qobjectPtr, '@QObject')
|
|
|
|
#DumperBase.warn("CALL FUNC: 0x%x" % self.qtPropertyFunc)
|
2016-12-02 09:06:05 +01:00
|
|
|
cmd = '((QVariant(*)(void*,char*))0x%x)((void*)0x%x,"%s")' \
|
2020-02-24 14:37:56 +01:00
|
|
|
% (self.qtPropertyFunc, qobjectPtr, name)
|
2016-12-02 09:06:05 +01:00
|
|
|
try:
|
2020-02-24 14:37:56 +01:00
|
|
|
#DumperBase.warn('PROP CMD: %s' % cmd)
|
2016-12-02 09:06:05 +01:00
|
|
|
res = self.parseAndEvaluate(cmd)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('PROP RES: %s' % res)
|
2016-12-02 09:06:05 +01:00
|
|
|
except:
|
|
|
|
self.bump('failedMetaObjectCall')
|
|
|
|
putt(name, ' ')
|
|
|
|
continue
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('COULD NOT EXECUTE: %s' % cmd)
|
2016-12-02 09:06:05 +01:00
|
|
|
#self.putCallItem(name, '@QVariant', base, 'property', '"' + name + '"')
|
2016-12-14 08:27:01 +01:00
|
|
|
if res is None:
|
|
|
|
self.bump('failedMetaObjectCall2')
|
|
|
|
putt(name, ' ')
|
|
|
|
continue
|
2016-12-02 09:06:05 +01:00
|
|
|
self.putSubItem(name, res)
|
2016-07-14 13:13:16 +02:00
|
|
|
else:
|
|
|
|
putt(name, ' ')
|
2016-07-13 14:17:18 +02:00
|
|
|
|
|
|
|
# Dynamic properties.
|
|
|
|
if extraData:
|
2020-12-03 16:33:02 +01:00
|
|
|
def list6Generator(addr, innerType):
|
|
|
|
data, size = self.listData(addr)
|
|
|
|
for i in range(size):
|
|
|
|
yield self.createValue(data + i * innerType.size(), innerType)
|
|
|
|
|
|
|
|
def list5Generator(addr, innerType):
|
|
|
|
data, size = self.listData(addr)
|
|
|
|
for i in range(size):
|
|
|
|
yield self.createValue(data + i * ptrSize, innerType)
|
|
|
|
|
|
|
|
def vectorGenerator(addr, innerType):
|
|
|
|
data, size = self.vectorData(addr)
|
|
|
|
for i in range(size):
|
|
|
|
yield self.createValue(data + i * innerType.size(), innerType)
|
|
|
|
|
2020-11-30 15:25:30 +01:00
|
|
|
byteArrayType = self.createType('@QByteArray')
|
|
|
|
variantType = self.createType('@QVariant')
|
2020-12-03 16:33:02 +01:00
|
|
|
if self.qtVersion() >= 0x60000:
|
|
|
|
values = vectorGenerator(extraData + 3 * ptrSize, variantType)
|
|
|
|
elif self.qtVersion() >= 0x50600:
|
|
|
|
values = vectorGenerator(extraData + 2 * ptrSize, variantType)
|
2016-09-06 08:54:43 +02:00
|
|
|
elif self.qtVersion() >= 0x50000:
|
2020-12-03 16:33:02 +01:00
|
|
|
values = list5Generator(extraData + 2 * ptrSize, variantType)
|
2016-07-13 14:17:18 +02:00
|
|
|
else:
|
2020-12-03 16:33:02 +01:00
|
|
|
values = list5Generator(extraData + 2 * ptrSize,
|
|
|
|
variantType.pointer())
|
|
|
|
|
|
|
|
if self.qtVersion() >= 0x60000:
|
|
|
|
names = list6Generator(extraData, byteArrayType)
|
2016-07-13 14:17:18 +02:00
|
|
|
else:
|
2020-12-03 16:33:02 +01:00
|
|
|
names = list5Generator(extraData + ptrSize, byteArrayType)
|
|
|
|
|
2016-07-13 14:17:18 +02:00
|
|
|
for (k, v) in zip(names, values):
|
2016-08-01 12:52:40 +02:00
|
|
|
with SubItem(self, propertyCount + dynamicPropertyCount):
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putField('key', self.encodeByteArray(k))
|
|
|
|
self.putField('keyencoded', 'latin1')
|
2016-07-13 14:17:18 +02:00
|
|
|
self.putItem(v)
|
2016-08-01 12:52:40 +02:00
|
|
|
dynamicPropertyCount += 1
|
|
|
|
self.putItemCount(propertyCount + dynamicPropertyCount)
|
2016-07-13 14:17:18 +02:00
|
|
|
else:
|
|
|
|
# We need a handle to [x] for the user to expand the item
|
|
|
|
# before we know whether there are actual children. Counting
|
|
|
|
# them is too expensive.
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', propertyCount)
|
2020-06-02 10:38:25 +02:00
|
|
|
self.putExpandable()
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
superDataPtr = extractSuperDataPtr(metaObjectPtr)
|
|
|
|
|
|
|
|
globalOffset = 0
|
|
|
|
superDataIterator = superDataPtr
|
|
|
|
while superDataIterator:
|
|
|
|
sdata = extractDataPtr(superDataIterator)
|
2020-02-24 14:37:56 +01:00
|
|
|
globalOffset += self.extractInt(sdata + 16) # methodCount member
|
2016-07-22 10:20:01 +02:00
|
|
|
superDataIterator = extractSuperDataPtr(superDataIterator)
|
2014-02-07 23:00:26 +01:00
|
|
|
|
2016-07-14 13:13:16 +02:00
|
|
|
if isQMetaObject or isQObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[methods]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(3)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putItemCount(methodCount)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
for i in range(methodCount):
|
2016-10-07 11:49:51 +02:00
|
|
|
t = self.split('IIIII', dataPtr + 56 + 20 * i)
|
2016-09-06 08:54:43 +02:00
|
|
|
name = self.metaString(metaObjectPtr, t[0], revision)
|
2016-07-14 13:13:16 +02:00
|
|
|
with SubItem(self, i):
|
|
|
|
self.putValue(name)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType(' ')
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putNumChild(1)
|
|
|
|
isSignal = False
|
2016-07-13 14:17:18 +02:00
|
|
|
flags = t[4]
|
|
|
|
if flags == 0x06:
|
2016-10-07 11:49:51 +02:00
|
|
|
typ = 'signal'
|
2016-07-14 13:13:16 +02:00
|
|
|
isSignal = True
|
2016-07-13 14:17:18 +02:00
|
|
|
elif flags == 0x0a:
|
2016-10-07 11:49:51 +02:00
|
|
|
typ = 'slot'
|
2016-07-13 14:17:18 +02:00
|
|
|
elif flags == 0x0a:
|
2016-10-07 11:49:51 +02:00
|
|
|
typ = 'invokable'
|
2016-07-14 13:13:16 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
typ = '<unknown>'
|
2016-07-14 13:13:16 +02:00
|
|
|
with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
putt('[nameindex]', t[0])
|
|
|
|
putt('[type]', typ)
|
|
|
|
putt('[argc]', t[1])
|
|
|
|
putt('[parameter]', t[2])
|
|
|
|
putt('[tag]', t[3])
|
|
|
|
putt('[flags]', t[4])
|
|
|
|
putt('[localindex]', str(i))
|
|
|
|
putt('[globalindex]', str(globalOffset + i))
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[d]'):
|
2016-10-07 13:08:49 +02:00
|
|
|
self.putItem(self.createValue(dd, '@QObjectPrivate'))
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(15)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[superdata]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(12)
|
2016-07-22 10:20:01 +02:00
|
|
|
if superDataPtr:
|
2016-10-07 13:08:49 +02:00
|
|
|
self.putType('@QMetaObject')
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putAddress(superDataPtr)
|
2020-06-02 10:38:25 +02:00
|
|
|
self.putExpandable()
|
2016-07-14 13:13:16 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putQObjectGutsHelper(0, 0, -1, superDataPtr, 'QMetaObject')
|
2016-07-14 13:13:16 +02:00
|
|
|
else:
|
2016-10-07 13:08:49 +02:00
|
|
|
self.putType('@QMetaObject *')
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x0')
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if handle >= 0:
|
2016-07-22 10:20:01 +02:00
|
|
|
localIndex = int((handle - methods) / 5)
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[localindex]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(12)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putValue(localIndex)
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[globalindex]'):
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putSortGroup(11)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putValue(globalOffset + localIndex)
|
|
|
|
|
2016-07-13 14:17:18 +02:00
|
|
|
def putQObjectConnections(self, dd):
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[connections]'):
|
2014-04-10 15:02:29 +02:00
|
|
|
ptrSize = self.ptrSize()
|
2014-04-03 22:08:35 +02:00
|
|
|
self.putNoType()
|
2016-10-07 13:08:49 +02:00
|
|
|
privateType = self.createType('@QObjectPrivate')
|
2014-04-03 22:08:35 +02:00
|
|
|
d_ptr = dd.cast(privateType.pointer()).dereference()
|
2016-10-07 11:49:51 +02:00
|
|
|
connections = d_ptr['connectionLists']
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.connections.integer() == 0:
|
2014-04-10 15:02:29 +02:00
|
|
|
self.putItemCount(0)
|
|
|
|
else:
|
|
|
|
connections = connections.dereference()
|
2016-11-02 13:04:21 +01:00
|
|
|
#connections = connections.cast(connections.type.firstBase())
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', 0)
|
2020-06-02 10:38:25 +02:00
|
|
|
self.putExpandable()
|
2014-04-03 22:08:35 +02:00
|
|
|
if self.isExpanded():
|
|
|
|
pp = 0
|
|
|
|
with Children(self):
|
2016-09-06 08:54:43 +02:00
|
|
|
innerType = connections.type[0]
|
2014-04-03 22:08:35 +02:00
|
|
|
# Should check: innerType == ns::QObjectPrivate::ConnectionList
|
2020-12-07 15:07:13 +01:00
|
|
|
data, size = self.vectorData(connections)
|
2016-10-25 15:32:13 +02:00
|
|
|
connectionType = self.createType('@QObjectPrivate::Connection')
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(size):
|
2014-04-03 22:08:35 +02:00
|
|
|
first = self.extractPointer(data + i * 2 * ptrSize)
|
2014-04-10 15:02:29 +02:00
|
|
|
while first:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSubItem('%s' % pp,
|
2020-02-24 14:37:56 +01:00
|
|
|
self.createPointerValue(first, connectionType))
|
2014-04-03 22:08:35 +02:00
|
|
|
first = self.extractPointer(first + 3 * ptrSize)
|
|
|
|
# We need to enforce some upper limit.
|
|
|
|
pp += 1
|
|
|
|
if pp > 1000:
|
|
|
|
break
|
2014-01-20 15:03:27 +01:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def currentItemFormat(self, typeName=None):
|
2020-02-24 15:10:47 +01:00
|
|
|
displayFormat = self.formats.get(self.currentIName, DisplayFormat.Automatic)
|
|
|
|
if displayFormat == DisplayFormat.Automatic:
|
2016-09-15 17:55:56 +02:00
|
|
|
if typeName is None:
|
|
|
|
typeName = self.currentType.value
|
|
|
|
needle = None if typeName is None else self.stripForFormat(typeName)
|
2020-02-24 15:10:47 +01:00
|
|
|
displayFormat = self.typeformats.get(needle, DisplayFormat.Automatic)
|
2015-03-20 16:03:59 +01:00
|
|
|
return displayFormat
|
2013-10-23 16:28:02 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putSubItem(self, component, value): # -> ReportItem
|
2016-09-06 08:54:43 +02:00
|
|
|
if not isinstance(value, self.Value):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('WRONG VALUE TYPE IN putSubItem: %s' % type(value))
|
2016-09-06 08:54:43 +02:00
|
|
|
if not isinstance(value.type, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('WRONG TYPE TYPE IN putSubItem: %s' % type(value.type))
|
2016-11-01 09:50:31 +01:00
|
|
|
res = None
|
2016-09-06 08:54:43 +02:00
|
|
|
with SubItem(self, component):
|
2016-09-26 14:29:16 +02:00
|
|
|
self.putItem(value)
|
2016-11-01 09:50:31 +01:00
|
|
|
res = self.currentValue
|
|
|
|
return res # The 'short' display.
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2023-02-21 15:32:13 +01:00
|
|
|
def putArrayData(self, base, n, innerType, childNumChild=None):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.checkIntType(base)
|
|
|
|
self.checkIntType(n)
|
|
|
|
addrBase = base
|
|
|
|
innerSize = innerType.size()
|
2016-10-25 15:32:13 +02:00
|
|
|
self.putNumChild(n)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
|
2016-09-15 17:55:56 +02:00
|
|
|
enc = innerType.simpleEncoding()
|
2023-02-21 15:32:13 +01:00
|
|
|
maxNumChild = self.maxArrayCount()
|
2015-04-14 11:24:07 +02:00
|
|
|
if enc:
|
2016-09-15 17:55:56 +02:00
|
|
|
self.put('childtype="%s",' % innerType.name)
|
2015-04-14 11:24:07 +02:00
|
|
|
self.put('addrbase="0x%x",' % addrBase)
|
|
|
|
self.put('addrstep="0x%x",' % innerSize)
|
|
|
|
self.put('arrayencoding="%s",' % enc)
|
2022-09-04 17:37:22 +03:00
|
|
|
self.put('endian="%s",' % self.packCode)
|
2016-04-12 11:43:13 +02:00
|
|
|
if n > maxNumChild:
|
2023-02-21 15:32:13 +01:00
|
|
|
self.put('childrenelided="%s",' % n)
|
2016-04-12 11:43:13 +02:00
|
|
|
n = maxNumChild
|
2015-04-14 11:24:07 +02:00
|
|
|
self.put('arraydata="')
|
|
|
|
self.put(self.readMemory(addrBase, n * innerSize))
|
|
|
|
self.put('",')
|
|
|
|
else:
|
2014-05-05 18:28:34 +02:00
|
|
|
with Children(self, n, innerType, childNumChild, maxNumChild,
|
2020-02-24 14:37:56 +01:00
|
|
|
addrBase=addrBase, addrStep=innerSize):
|
2014-05-05 18:28:34 +02:00
|
|
|
for i in self.childRange():
|
2015-04-14 11:24:07 +02:00
|
|
|
self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType))
|
2014-05-05 18:28:34 +02:00
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
def putArrayItem(self, name, addr, n, typeName):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.checkIntType(addr)
|
|
|
|
self.checkIntType(n)
|
2014-05-05 18:28:34 +02:00
|
|
|
with SubItem(self, name):
|
|
|
|
self.putEmptyValue()
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType('%s [%d]' % (typeName, n))
|
2014-05-05 18:28:34 +02:00
|
|
|
self.putArrayData(addr, n, self.lookupType(typeName))
|
|
|
|
self.putAddress(addr)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putPlotDataHelper(self, base, n, innerType, maxNumChild=1000 * 1000):
|
2016-04-12 11:43:13 +02:00
|
|
|
if n > maxNumChild:
|
2020-02-24 14:37:56 +01:00
|
|
|
self.putField('plotelided', n) # FIXME: Act on that in frontend
|
2016-04-12 11:43:13 +02:00
|
|
|
n = maxNumChild
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.currentItemFormat() == DisplayFormat.ArrayPlot and innerType.isSimpleType():
|
2016-09-15 17:55:56 +02:00
|
|
|
enc = innerType.simpleEncoding()
|
2015-04-01 17:19:43 +02:00
|
|
|
if enc:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('editencoding', enc)
|
|
|
|
self.putDisplay('plotdata:separate',
|
2016-09-06 08:54:43 +02:00
|
|
|
self.readMemory(base, n * innerType.size()))
|
2015-04-01 17:19:43 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def putPlotData(self, base, n, innerType, maxNumChild=1000 * 1000):
|
2016-04-12 11:43:13 +02:00
|
|
|
self.putPlotDataHelper(base, n, innerType, maxNumChild=maxNumChild)
|
2014-01-04 00:39:23 +01:00
|
|
|
if self.isExpanded():
|
2023-02-21 15:32:13 +01:00
|
|
|
self.putArrayData(base, n, innerType)
|
2014-01-04 00:39:23 +01:00
|
|
|
|
2014-02-04 14:48:40 +01:00
|
|
|
def putSpecialArgv(self, value):
|
|
|
|
"""
|
|
|
|
Special handling for char** argv.
|
|
|
|
"""
|
|
|
|
n = 0
|
|
|
|
p = value
|
|
|
|
# p is 0 for "optimized out" cases. Or contains rubbish.
|
|
|
|
try:
|
2016-09-06 08:54:43 +02:00
|
|
|
if value.integer():
|
|
|
|
while p.dereference().integer() and n <= 100:
|
2014-02-04 14:48:40 +01:00
|
|
|
p += 1
|
|
|
|
n += 1
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
with TopLevelItem(self, 'local.argv'):
|
|
|
|
self.put('iname="local.argv",name="argv",')
|
|
|
|
self.putItemCount(n, 100)
|
|
|
|
self.putType('char **')
|
|
|
|
if self.currentIName in self.expandedINames:
|
|
|
|
p = value
|
|
|
|
with Children(self, n):
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(n):
|
2014-02-04 14:48:40 +01:00
|
|
|
self.putSubItem(i, p.dereference())
|
|
|
|
p += 1
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def extractPointer(self, value):
|
2018-03-22 14:10:58 +02:00
|
|
|
try:
|
2020-02-24 15:10:47 +01:00
|
|
|
if value.type.code == TypeCode.Array:
|
2018-03-22 14:10:58 +02:00
|
|
|
return value.address()
|
|
|
|
except:
|
|
|
|
pass
|
2016-10-07 11:49:51 +02:00
|
|
|
code = 'I' if self.ptrSize() == 4 else 'Q'
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.extractSomething(value, code, 8 * self.ptrSize())
|
|
|
|
|
|
|
|
def extractInt64(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'q', 64)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def extractUInt64(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'Q', 64)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractInt(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'i', 32)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractUInt(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'I', 32)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractShort(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'h', 16)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractUShort(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'H', 16)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractByte(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractSomething(value, 'b', 8)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractSomething(self, value, pattern, bitsize):
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.isInt(value):
|
2016-09-06 08:54:43 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val.laddress = value
|
|
|
|
return val.extractSomething(pattern, bitsize)
|
|
|
|
if isinstance(value, self.Value):
|
|
|
|
return value.extractSomething(pattern, bitsize)
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('CANT EXTRACT FROM %s' % type(value))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2014-05-12 13:09:02 +02:00
|
|
|
# Parses a..b and a.(s).b
|
|
|
|
def parseRange(self, exp):
|
2014-05-14 00:57:31 +02:00
|
|
|
|
|
|
|
# Search for the first unbalanced delimiter in s
|
|
|
|
def searchUnbalanced(s, upwards):
|
|
|
|
paran = 0
|
|
|
|
bracket = 0
|
|
|
|
if upwards:
|
|
|
|
open_p, close_p, open_b, close_b = '(', ')', '[', ']'
|
|
|
|
else:
|
|
|
|
open_p, close_p, open_b, close_b = ')', '(', ']', '['
|
|
|
|
for i in range(len(s)):
|
|
|
|
c = s[i]
|
|
|
|
if c == open_p:
|
|
|
|
paran += 1
|
|
|
|
elif c == open_b:
|
|
|
|
bracket += 1
|
|
|
|
elif c == close_p:
|
|
|
|
paran -= 1
|
|
|
|
if paran < 0:
|
|
|
|
return i
|
|
|
|
elif c == close_b:
|
|
|
|
bracket -= 1
|
|
|
|
if bracket < 0:
|
|
|
|
return i
|
|
|
|
return len(s)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
match = re.search(r'(\.)(\(.+?\))?(\.)', exp)
|
2014-05-12 13:09:02 +02:00
|
|
|
if match:
|
|
|
|
s = match.group(2)
|
2014-05-14 00:57:31 +02:00
|
|
|
left_e = match.start(1)
|
2020-02-24 14:37:56 +01:00
|
|
|
left_s = 1 + left_e - searchUnbalanced(exp[left_e::-1], False)
|
2014-05-14 00:57:31 +02:00
|
|
|
right_s = match.end(3)
|
|
|
|
right_e = right_s + searchUnbalanced(exp[right_s:], True)
|
2020-02-24 14:37:56 +01:00
|
|
|
template = exp[:left_s] + '%s' + exp[right_e:]
|
2014-05-14 00:57:31 +02:00
|
|
|
|
|
|
|
a = exp[left_s:left_e]
|
|
|
|
b = exp[right_s:right_e]
|
|
|
|
|
2014-05-12 13:09:02 +02:00
|
|
|
try:
|
2014-05-14 00:57:31 +02:00
|
|
|
# Allow integral expressions.
|
2020-02-24 14:37:56 +01:00
|
|
|
ss = self.parseAndEvaluate(s[1:len(s) - 1]).integer() if s else 1
|
2016-09-06 08:54:43 +02:00
|
|
|
aa = self.parseAndEvaluate(a).integer()
|
|
|
|
bb = self.parseAndEvaluate(b).integer()
|
2014-05-14 00:57:31 +02:00
|
|
|
if aa < bb and ss > 0:
|
|
|
|
return True, aa, ss, bb + 1, template
|
2014-05-12 13:09:02 +02:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return False, 0, 1, 1, exp
|
|
|
|
|
2015-03-26 13:03:38 +01:00
|
|
|
def putNumChild(self, numchild):
|
|
|
|
if numchild != self.currentChildNumChild:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('numchild', numchild)
|
2015-03-26 13:03:38 +01:00
|
|
|
|
2016-09-20 11:52:06 +02:00
|
|
|
def handleLocals(self, variables):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('VARIABLES: %s' % variables)
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('locals'):
|
2016-09-20 11:52:06 +02:00
|
|
|
shadowed = {}
|
|
|
|
for value in variables:
|
2016-11-03 15:37:08 +01:00
|
|
|
if value.name == 'argv':
|
2020-02-24 15:10:47 +01:00
|
|
|
if value.type.code == TypeCode.Pointer:
|
|
|
|
if value.type.ltarget.code == TypeCode.Pointer:
|
2016-11-03 15:37:08 +01:00
|
|
|
if value.type.ltarget.ltarget.name == 'char':
|
|
|
|
self.putSpecialArgv(value)
|
|
|
|
continue
|
|
|
|
|
|
|
|
name = value.name
|
|
|
|
if name in shadowed:
|
|
|
|
level = shadowed[name]
|
|
|
|
shadowed[name] = level + 1
|
|
|
|
name += '@%d' % level
|
2016-09-20 11:52:06 +02:00
|
|
|
else:
|
2016-11-03 15:37:08 +01:00
|
|
|
shadowed[name] = 1
|
|
|
|
# A 'normal' local variable or parameter.
|
|
|
|
iname = value.iname if hasattr(value, 'iname') else 'local.' + name
|
|
|
|
with TopLevelItem(self, iname):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('all-' + iname):
|
2016-11-03 15:37:08 +01:00
|
|
|
self.putField('iname', iname)
|
|
|
|
self.putField('name', name)
|
|
|
|
self.putItem(value)
|
2016-09-20 11:52:06 +02:00
|
|
|
|
2015-03-26 13:03:38 +01:00
|
|
|
def handleWatches(self, args):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('watches'):
|
2016-10-07 11:49:51 +02:00
|
|
|
for watcher in args.get('watchers', []):
|
2015-03-26 13:03:38 +01:00
|
|
|
iname = watcher['iname']
|
|
|
|
exp = self.hexdecode(watcher['exp'])
|
|
|
|
self.handleWatch(exp, exp, iname)
|
|
|
|
|
2014-05-12 13:09:02 +02:00
|
|
|
def handleWatch(self, origexp, exp, iname):
|
|
|
|
exp = str(exp).strip()
|
|
|
|
escapedExp = self.hexencode(exp)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('HANDLING WATCH %s -> %s, INAME: "%s"' % (origexp, exp, iname))
|
2014-05-12 13:09:02 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
# Grouped items separated by semicolon.
|
|
|
|
if exp.find(';') >= 0:
|
2014-05-12 13:09:02 +02:00
|
|
|
exps = exp.split(';')
|
|
|
|
n = len(exps)
|
|
|
|
with TopLevelItem(self, iname):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('iname', iname)
|
|
|
|
#self.putField('wname', escapedExp)
|
|
|
|
self.putField('name', exp)
|
|
|
|
self.putField('exp', exp)
|
2014-05-12 13:09:02 +02:00
|
|
|
self.putItemCount(n)
|
|
|
|
self.putNoType()
|
2020-02-24 10:37:40 +01:00
|
|
|
for i in range(n):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.handleWatch(exps[i], exps[i], '%s.%d' % (iname, i))
|
2014-05-12 13:09:02 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
# Special array index: e.g a[1..199] or a[1.(3).199] for stride 3.
|
|
|
|
isRange, begin, step, end, template = self.parseRange(exp)
|
|
|
|
if isRange:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('RANGE: %s %s %s in %s' % (begin, step, end, template))
|
2014-05-12 13:09:02 +02:00
|
|
|
r = range(begin, end, step)
|
|
|
|
n = len(r)
|
|
|
|
with TopLevelItem(self, iname):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('iname', iname)
|
|
|
|
#self.putField('wname', escapedExp)
|
|
|
|
self.putField('name', exp)
|
|
|
|
self.putField('exp', exp)
|
2014-05-12 13:09:02 +02:00
|
|
|
self.putItemCount(n)
|
|
|
|
self.putNoType()
|
|
|
|
with Children(self, n):
|
|
|
|
for i in r:
|
|
|
|
e = template % i
|
2016-10-07 11:49:51 +02:00
|
|
|
self.handleWatch(e, e, '%s.%s' % (iname, i))
|
2014-05-12 13:09:02 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
# Fall back to less special syntax
|
|
|
|
#return self.handleWatch(origexp, exp, iname)
|
|
|
|
|
|
|
|
with TopLevelItem(self, iname):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('iname', iname)
|
|
|
|
self.putField('wname', escapedExp)
|
2014-07-07 10:33:38 +02:00
|
|
|
try:
|
|
|
|
value = self.parseAndEvaluate(exp)
|
|
|
|
self.putItem(value)
|
2016-09-21 16:54:30 +02:00
|
|
|
except Exception:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.currentType.value = ' '
|
|
|
|
self.currentValue.value = '<no such value>'
|
2014-07-07 10:33:38 +02:00
|
|
|
self.currentChildNumChild = -1
|
|
|
|
self.currentNumChild = 0
|
2014-05-12 13:09:02 +02:00
|
|
|
self.putNumChild(0)
|
|
|
|
|
2015-01-23 19:09:08 +01:00
|
|
|
def registerDumper(self, funcname, function):
|
|
|
|
try:
|
2016-10-07 11:49:51 +02:00
|
|
|
if funcname.startswith('qdump__'):
|
2015-01-23 19:09:08 +01:00
|
|
|
typename = funcname[7:]
|
2023-01-07 20:02:38 +01:00
|
|
|
if sys.version_info > (3,):
|
|
|
|
spec = inspect.getfullargspec(function)
|
|
|
|
else:
|
|
|
|
spec = inspect.getargspec(function)
|
2016-04-04 23:46:46 +02:00
|
|
|
if len(spec.args) == 2:
|
|
|
|
self.qqDumpers[typename] = function
|
|
|
|
elif len(spec.args) == 3 and len(spec.defaults) == 1:
|
|
|
|
self.qqDumpersEx[spec.defaults[0]] = function
|
2015-03-20 16:03:59 +01:00
|
|
|
self.qqFormats[typename] = self.qqFormats.get(typename, [])
|
2016-10-07 11:49:51 +02:00
|
|
|
elif funcname.startswith('qform__'):
|
2015-01-23 19:09:08 +01:00
|
|
|
typename = funcname[7:]
|
|
|
|
try:
|
2015-03-20 16:03:59 +01:00
|
|
|
self.qqFormats[typename] = function()
|
2015-01-23 19:09:08 +01:00
|
|
|
except:
|
2015-03-20 16:03:59 +01:00
|
|
|
self.qqFormats[typename] = []
|
2016-10-07 11:49:51 +02:00
|
|
|
elif funcname.startswith('qedit__'):
|
2015-01-23 19:09:08 +01:00
|
|
|
typename = funcname[7:]
|
|
|
|
try:
|
|
|
|
self.qqEditable[typename] = function
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def setupDumpers(self, _={}):
|
2015-07-10 10:09:25 +02:00
|
|
|
self.resetCaches()
|
2015-01-23 19:09:08 +01:00
|
|
|
|
2015-01-30 09:22:52 +01:00
|
|
|
for mod in self.dumpermodules:
|
2022-08-11 15:46:34 +02:00
|
|
|
try:
|
|
|
|
m = __import__(mod)
|
|
|
|
dic = m.__dict__
|
|
|
|
for name in dic.keys():
|
|
|
|
item = dic[name]
|
|
|
|
self.registerDumper(name, item)
|
|
|
|
except Exception as e:
|
|
|
|
print('Failed to load dumper module: %s (%s)' % (mod, e))
|
2015-01-23 19:09:08 +01:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
msg = 'dumpers=['
|
2015-01-23 19:09:08 +01:00
|
|
|
for key, value in self.qqFormats.items():
|
2015-03-20 16:03:59 +01:00
|
|
|
editable = ',editable="true"' if key in self.qqEditable else ''
|
|
|
|
formats = (',formats=\"%s\"' % str(value)[1:-1]) if len(value) else ''
|
|
|
|
msg += '{type="%s"%s%s},' % (key, editable, formats)
|
2015-09-17 09:47:36 +02:00
|
|
|
msg += '],'
|
|
|
|
v = 10000 * sys.version_info[0] + 100 * sys.version_info[1] + sys.version_info[2]
|
|
|
|
msg += 'python="%d"' % v
|
2015-09-09 16:34:09 +02:00
|
|
|
return msg
|
2015-03-18 16:48:57 +01:00
|
|
|
|
|
|
|
def reloadDumpers(self, args):
|
2015-01-30 09:22:52 +01:00
|
|
|
for mod in self.dumpermodules:
|
2015-01-23 19:09:08 +01:00
|
|
|
m = sys.modules[mod]
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] >= 3:
|
|
|
|
import importlib
|
|
|
|
importlib.reload(m)
|
|
|
|
else:
|
|
|
|
reload(m)
|
2015-03-18 16:48:57 +01:00
|
|
|
self.setupDumpers(args)
|
2014-05-12 13:09:02 +02:00
|
|
|
|
2016-09-28 12:04:27 +02:00
|
|
|
def loadDumpers(self, args):
|
|
|
|
msg = self.setupDumpers()
|
|
|
|
self.reportResult(msg, args)
|
|
|
|
|
2015-02-11 12:20:21 +01:00
|
|
|
def addDumperModule(self, args):
|
|
|
|
path = args['path']
|
2015-01-30 09:22:52 +01:00
|
|
|
(head, tail) = os.path.split(path)
|
|
|
|
sys.path.insert(1, head)
|
|
|
|
self.dumpermodules.append(os.path.splitext(tail)[0])
|
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def extractQStringFromQDataStream(self, buf, offset):
|
|
|
|
""" Read a QString from the stream """
|
2016-10-07 11:49:51 +02:00
|
|
|
size = struct.unpack_from('!I', buf, offset)[0]
|
2015-10-08 16:19:57 +02:00
|
|
|
offset += 4
|
|
|
|
string = buf[offset:offset + size].decode('utf-16be')
|
|
|
|
return (string, offset + size)
|
|
|
|
|
|
|
|
def extractQByteArrayFromQDataStream(self, buf, offset):
|
|
|
|
""" Read a QByteArray from the stream """
|
2016-10-07 11:49:51 +02:00
|
|
|
size = struct.unpack_from('!I', buf, offset)[0]
|
2015-10-08 16:19:57 +02:00
|
|
|
offset += 4
|
|
|
|
string = buf[offset:offset + size].decode('latin1')
|
|
|
|
return (string, offset + size)
|
|
|
|
|
|
|
|
def extractIntFromQDataStream(self, buf, offset):
|
|
|
|
""" Read an int from the stream """
|
2016-10-07 11:49:51 +02:00
|
|
|
value = struct.unpack_from('!I', buf, offset)[0]
|
2015-10-08 16:19:57 +02:00
|
|
|
return (value, offset + 4)
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
def handleInterpreterMessage(self):
|
2015-10-08 16:19:57 +02:00
|
|
|
""" Return True if inferior stopped """
|
2015-10-14 13:26:22 +02:00
|
|
|
resdict = self.fetchInterpreterResult()
|
2015-10-08 16:19:57 +02:00
|
|
|
return resdict.get('event') == 'break'
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
def reportInterpreterResult(self, resdict, args):
|
|
|
|
print('interpreterresult=%s,token="%s"'
|
2020-02-24 14:37:56 +01:00
|
|
|
% (self.resultToMi(resdict), args.get('token', -1)))
|
2015-10-14 13:26:22 +02:00
|
|
|
|
|
|
|
def reportInterpreterAsync(self, resdict, asyncclass):
|
|
|
|
print('interpreterasync=%s,asyncclass="%s"'
|
2020-02-24 14:37:56 +01:00
|
|
|
% (self.resultToMi(resdict), asyncclass))
|
2015-10-14 13:26:22 +02:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def removeInterpreterBreakpoint(self, args):
|
2020-02-24 14:37:56 +01:00
|
|
|
res = self.sendInterpreterRequest('removebreakpoint', {'id': args['id']})
|
2015-10-08 16:19:57 +02:00
|
|
|
return res
|
|
|
|
|
|
|
|
def insertInterpreterBreakpoint(self, args):
|
|
|
|
args['condition'] = self.hexdecode(args.get('condition', ''))
|
2015-10-14 13:26:22 +02:00
|
|
|
# Will fail if the service is not yet up and running.
|
|
|
|
response = self.sendInterpreterRequest('setbreakpoint', args)
|
|
|
|
resdict = args.copy()
|
2016-10-07 11:49:51 +02:00
|
|
|
bp = None if response is None else response.get('breakpoint', None)
|
2015-10-14 13:26:22 +02:00
|
|
|
if bp:
|
|
|
|
resdict['number'] = bp
|
|
|
|
resdict['pending'] = 0
|
|
|
|
else:
|
|
|
|
self.createResolvePendingBreakpointsHookBreakpoint(args)
|
|
|
|
resdict['number'] = -1
|
|
|
|
resdict['pending'] = 1
|
|
|
|
resdict['warning'] = 'Direct interpreter breakpoint insertion failed.'
|
|
|
|
self.reportInterpreterResult(resdict, args)
|
|
|
|
|
|
|
|
def resolvePendingInterpreterBreakpoint(self, args):
|
|
|
|
self.parseAndEvaluate('qt_qmlDebugEnableService("NativeQmlDebugger")')
|
|
|
|
response = self.sendInterpreterRequest('setbreakpoint', args)
|
2016-10-07 11:49:51 +02:00
|
|
|
bp = None if response is None else response.get('breakpoint', None)
|
2015-10-14 13:26:22 +02:00
|
|
|
resdict = args.copy()
|
|
|
|
if bp:
|
|
|
|
resdict['number'] = bp
|
|
|
|
resdict['pending'] = 0
|
|
|
|
else:
|
|
|
|
resdict['number'] = -1
|
|
|
|
resdict['pending'] = 0
|
|
|
|
resdict['error'] = 'Pending interpreter breakpoint insertion failed.'
|
|
|
|
self.reportInterpreterAsync(resdict, 'breakpointmodified')
|
|
|
|
|
|
|
|
def fetchInterpreterResult(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
buf = self.parseAndEvaluate('qt_qmlDebugMessageBuffer')
|
|
|
|
size = self.parseAndEvaluate('qt_qmlDebugMessageLength')
|
2015-10-14 13:26:22 +02:00
|
|
|
msg = self.hexdecode(self.readMemory(buf, size))
|
|
|
|
# msg is a sequence of 'servicename<space>msglen<space>msg' items.
|
|
|
|
resdict = {} # Native payload.
|
|
|
|
while len(msg):
|
2020-02-24 14:37:56 +01:00
|
|
|
pos0 = msg.index(' ') # End of service name
|
|
|
|
pos1 = msg.index(' ', pos0 + 1) # End of message length
|
2015-10-14 13:26:22 +02:00
|
|
|
service = msg[0:pos0]
|
2020-02-24 14:37:56 +01:00
|
|
|
msglen = int(msg[pos0 + 1:pos1])
|
|
|
|
msgend = pos1 + 1 + msglen
|
|
|
|
payload = msg[pos1 + 1:msgend]
|
2015-10-14 13:26:22 +02:00
|
|
|
msg = msg[msgend:]
|
|
|
|
if service == 'NativeQmlDebugger':
|
|
|
|
try:
|
|
|
|
resdict = json.loads(payload)
|
|
|
|
continue
|
|
|
|
except:
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('Cannot parse native payload: %s' % payload)
|
2015-10-14 13:26:22 +02:00
|
|
|
else:
|
|
|
|
print('interpreteralien=%s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% {'service': service, 'payload': self.hexencode(payload)})
|
2015-10-14 13:26:22 +02:00
|
|
|
try:
|
|
|
|
expr = 'qt_qmlDebugClearBuffer()'
|
|
|
|
res = self.parseAndEvaluate(expr)
|
|
|
|
except RuntimeError as error:
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('Cleaning buffer failed: %s: %s' % (expr, error))
|
2015-10-14 13:26:22 +02:00
|
|
|
|
|
|
|
return resdict
|
2015-10-08 16:19:57 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def sendInterpreterRequest(self, command, args={}):
|
|
|
|
encoded = json.dumps({'command': command, 'arguments': args})
|
2015-10-08 16:19:57 +02:00
|
|
|
hexdata = self.hexencode(encoded)
|
|
|
|
expr = 'qt_qmlDebugSendDataToService("NativeQmlDebugger","%s")' % hexdata
|
2015-02-04 10:48:33 +01:00
|
|
|
try:
|
|
|
|
res = self.parseAndEvaluate(expr)
|
|
|
|
except RuntimeError as error:
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('Interpreter command failed: %s: %s' % (encoded, error))
|
2015-10-08 16:19:57 +02:00
|
|
|
return {}
|
2015-02-04 13:29:42 +01:00
|
|
|
except AttributeError as error:
|
|
|
|
# Happens with LLDB and 'None' current thread.
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('Interpreter command failed: %s: %s' % (encoded, error))
|
2015-10-08 16:19:57 +02:00
|
|
|
return {}
|
|
|
|
if not res:
|
2020-02-21 10:10:00 +01:00
|
|
|
self.warn('Interpreter command failed: %s ' % encoded)
|
2015-10-08 16:19:57 +02:00
|
|
|
return {}
|
2015-10-14 13:26:22 +02:00
|
|
|
return self.fetchInterpreterResult()
|
2015-10-08 16:19:57 +02:00
|
|
|
|
|
|
|
def executeStep(self, args):
|
|
|
|
if self.nativeMixed:
|
|
|
|
response = self.sendInterpreterRequest('stepin', args)
|
|
|
|
self.doContinue()
|
|
|
|
|
|
|
|
def executeStepOut(self, args):
|
|
|
|
if self.nativeMixed:
|
|
|
|
response = self.sendInterpreterRequest('stepout', args)
|
|
|
|
self.doContinue()
|
|
|
|
|
|
|
|
def executeNext(self, args):
|
|
|
|
if self.nativeMixed:
|
|
|
|
response = self.sendInterpreterRequest('stepover', args)
|
|
|
|
self.doContinue()
|
|
|
|
|
|
|
|
def executeContinue(self, args):
|
|
|
|
if self.nativeMixed:
|
|
|
|
response = self.sendInterpreterRequest('continue', args)
|
|
|
|
self.doContinue()
|
|
|
|
|
|
|
|
def doInsertInterpreterBreakpoint(self, args, wasPending):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('DO INSERT INTERPRETER BREAKPOINT, WAS PENDING: %s' % wasPending)
|
2015-10-08 16:19:57 +02:00
|
|
|
# Will fail if the service is not yet up and running.
|
|
|
|
response = self.sendInterpreterRequest('setbreakpoint', args)
|
2016-10-07 11:49:51 +02:00
|
|
|
bp = None if response is None else response.get('breakpoint', None)
|
2015-10-08 16:19:57 +02:00
|
|
|
if wasPending:
|
|
|
|
if not bp:
|
2015-10-14 13:26:22 +02:00
|
|
|
self.reportInterpreterResult({'bpnr': -1, 'pending': 1,
|
2020-02-24 14:37:56 +01:00
|
|
|
'error': 'Pending interpreter breakpoint insertion failed.'}, args)
|
2015-10-14 13:26:22 +02:00
|
|
|
return
|
2015-10-08 16:19:57 +02:00
|
|
|
else:
|
|
|
|
if not bp:
|
2015-10-14 13:26:22 +02:00
|
|
|
self.reportInterpreterResult({'bpnr': -1, 'pending': 1,
|
2020-02-24 14:37:56 +01:00
|
|
|
'warning': 'Direct interpreter breakpoint insertion failed.'}, args)
|
2015-10-08 16:19:57 +02:00
|
|
|
self.createResolvePendingBreakpointsHookBreakpoint(args)
|
2015-10-14 13:26:22 +02:00
|
|
|
return
|
|
|
|
self.reportInterpreterResult({'bpnr': bp, 'pending': 0}, args)
|
2015-02-04 10:48:33 +01:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def isInternalInterpreterFrame(self, functionName):
|
2015-02-04 13:29:42 +01:00
|
|
|
if functionName is None:
|
|
|
|
return False
|
2016-10-07 11:49:51 +02:00
|
|
|
if functionName.startswith('qt_v4'):
|
2015-02-04 13:29:42 +01:00
|
|
|
return True
|
2016-10-07 11:49:51 +02:00
|
|
|
return functionName.startswith(self.qtNamespace() + 'QV4::')
|
2015-02-04 13:29:42 +01:00
|
|
|
|
2015-04-15 12:38:11 +02:00
|
|
|
# Hack to avoid QDate* dumper timeouts with GDB 7.4 on 32 bit
|
|
|
|
# due to misaligned %ebx in SSE calls (qstring.cpp:findChar)
|
|
|
|
def canCallLocale(self):
|
|
|
|
return True
|
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def isReportableInterpreterFrame(self, functionName):
|
2016-10-07 11:49:51 +02:00
|
|
|
return functionName and functionName.find('QV4::Moth::VME::exec') >= 0
|
2015-02-04 13:29:42 +01:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def extractInterpreterStack(self):
|
2020-02-24 14:37:56 +01:00
|
|
|
return self.sendInterpreterRequest('backtrace', {'limit': 10})
|
2015-02-05 12:51:25 +01:00
|
|
|
|
2021-09-23 12:31:49 +00:00
|
|
|
def isInt(self, thing):
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(thing, int):
|
|
|
|
return True
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] == 2:
|
|
|
|
if isinstance(thing, long):
|
|
|
|
return True
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
|
|
|
|
2016-11-18 12:07:55 +01:00
|
|
|
def putItems(self, count, generator, maxNumChild=10000):
|
|
|
|
self.putItemCount(count)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self, count, maxNumChild=maxNumChild):
|
|
|
|
for i, val in zip(self.childRange(), generator):
|
|
|
|
self.putSubItem(i, val)
|
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
def putItem(self, value):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer('putItem'):
|
2016-11-07 08:57:26 +01:00
|
|
|
self.putItemX(value)
|
|
|
|
|
|
|
|
def putItemX(self, value):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('PUT ITEM: %s' % value.stringify())
|
2016-09-19 12:05:16 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
typeobj = value.type # unqualified()
|
2016-09-06 08:54:43 +02:00
|
|
|
typeName = typeobj.name
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
self.addToCache(typeobj) # Fill type cache
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
if not value.lIsInScope:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('optimizedout')
|
2016-09-06 08:54:43 +02:00
|
|
|
#self.putType(typeobj)
|
|
|
|
#self.putSpecialValue('outofscope')
|
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
|
|
|
if not isinstance(value, self.Value):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('WRONG TYPE IN putItem: %s' % type(self.Value))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
# Try on possibly typedefed type first.
|
|
|
|
if self.tryPutPrettyItem(typeName, value):
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Pointer:
|
2017-05-08 14:50:33 +03:00
|
|
|
self.putOriginalAddress(value.address())
|
|
|
|
else:
|
|
|
|
self.putAddress(value.address())
|
2016-09-06 08:54:43 +02:00
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Typedef:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('TYPEDEF VALUE: %s' % value.stringify())
|
2016-10-25 15:32:13 +02:00
|
|
|
self.putItem(value.detypedef())
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putBetterType(typeName)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Pointer:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putFormattedPointer(value)
|
2017-08-15 15:17:12 +02:00
|
|
|
if value.summary and self.useFancy:
|
|
|
|
self.putValue(self.hexencode(value.summary), 'utf8:1:0')
|
2016-09-06 08:54:43 +02:00
|
|
|
return
|
|
|
|
|
2017-05-08 14:50:33 +03:00
|
|
|
self.putAddress(value.address())
|
2023-03-01 12:29:03 +01:00
|
|
|
if value.lbitsize is not None:
|
|
|
|
self.putField('size', value.lbitsize // 8)
|
2017-05-08 14:50:33 +03:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Function:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('FUNCTION VALUE: %s' % value)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeobj)
|
2016-10-31 17:59:49 +01:00
|
|
|
self.putSymbolValue(value.pointer())
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Enum:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('ENUM VALUE: %s' % value.stringify())
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeobj.name)
|
|
|
|
self.putValue(value.display())
|
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Array:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('ARRAY VALUE: %s' % value)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putCStyleArray(value)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Bitfield:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('BITFIELD VALUE: %s %d %s' % (value.name, value.lvalue, typeName))
|
2016-11-07 08:57:26 +01:00
|
|
|
self.putNumChild(0)
|
2022-08-12 14:42:06 +02:00
|
|
|
dd = typeobj.ltarget.tdata.enumDisplay
|
2020-02-24 14:37:56 +01:00
|
|
|
self.putValue(str(value.lvalue) if dd is None else dd(
|
|
|
|
value.lvalue, value.laddress, '%d'))
|
2016-11-07 08:57:26 +01:00
|
|
|
self.putType(typeName)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Integral:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('INTEGER: %s %s' % (value.name, value))
|
2016-11-01 09:50:31 +01:00
|
|
|
val = value.value()
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putNumChild(0)
|
2016-11-01 09:50:31 +01:00
|
|
|
self.putValue(val)
|
2016-10-06 00:59:11 +02:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Float:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('FLOAT VALUE: %s' % value)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putValue(value.value())
|
|
|
|
self.putNumChild(0)
|
|
|
|
self.putType(typeobj.name)
|
|
|
|
return
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('REFERENCE VALUE: %s' % value)
|
2016-10-25 15:32:13 +02:00
|
|
|
val = value.dereference()
|
2018-10-30 11:20:07 +01:00
|
|
|
if val.laddress != 0:
|
|
|
|
self.putItem(val)
|
|
|
|
else:
|
|
|
|
self.putSpecialValue('nullreference')
|
2016-10-25 15:32:13 +02:00
|
|
|
self.putBetterType(typeName)
|
2016-09-26 14:29:16 +02:00
|
|
|
return
|
2016-09-19 12:05:16 +02:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.Complex:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeobj)
|
|
|
|
self.putValue(value.display())
|
|
|
|
self.putNumChild(0)
|
2016-09-21 16:54:30 +02:00
|
|
|
return
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if typeobj.code == TypeCode.FortranString:
|
2019-09-20 15:45:11 +02:00
|
|
|
self.putValue(self.hexencode(value.data()), 'latin1')
|
|
|
|
self.putNumChild(0)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeobj)
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
if typeName.endswith('[]'):
|
2016-09-06 08:54:43 +02:00
|
|
|
# D arrays, gdc compiled.
|
2016-10-07 11:49:51 +02:00
|
|
|
n = value['length']
|
|
|
|
base = value['ptr']
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeName)
|
|
|
|
self.putItemCount(n)
|
|
|
|
if self.isExpanded():
|
2016-09-29 00:04:04 +02:00
|
|
|
self.putArrayData(base.pointer(), n, base.type.target())
|
2016-09-06 08:54:43 +02:00
|
|
|
return
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('SOME VALUE: %s' % value)
|
|
|
|
#DumperBase.warn('GENERIC STRUCT: %s' % typeobj)
|
|
|
|
#DumperBase.warn('INAME: %s ' % self.currentIName)
|
|
|
|
#DumperBase.warn('INAMES: %s ' % self.expandedINames)
|
|
|
|
#DumperBase.warn('EXPANDED: %s ' % (self.currentIName in self.expandedINames))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeName)
|
2017-08-15 15:17:12 +02:00
|
|
|
|
|
|
|
if value.summary is not None and self.useFancy:
|
|
|
|
self.putValue(self.hexencode(value.summary), 'utf8:1:0')
|
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
2020-05-29 13:08:07 +02:00
|
|
|
self.putExpandable()
|
2016-09-20 12:07:46 +02:00
|
|
|
self.putEmptyValue()
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
|
2016-09-20 12:07:46 +02:00
|
|
|
if self.showQObjectNames:
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.timer(self.currentIName):
|
2016-09-20 12:07:46 +02:00
|
|
|
self.putQObjectNameValue(value)
|
|
|
|
if self.isExpanded():
|
2020-05-29 13:08:07 +02:00
|
|
|
if not self.isCli:
|
|
|
|
self.putField('sortable', 1)
|
2016-09-20 12:07:46 +02:00
|
|
|
with Children(self, 1, childType=None):
|
|
|
|
self.putFields(value)
|
2016-12-01 09:22:53 +01:00
|
|
|
if self.showQObjectNames:
|
|
|
|
self.tryPutQObjectGuts(value)
|
2016-09-20 12:07:46 +02:00
|
|
|
|
2016-09-23 17:23:41 +02:00
|
|
|
def symbolAddress(self, symbolName):
|
2016-11-01 17:22:56 +01:00
|
|
|
res = self.parseAndEvaluate('(size_t)&' + symbolName)
|
|
|
|
return None if res is None else res.pointer()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-11-02 08:31:22 +01:00
|
|
|
def qtHookDataSymbolName(self):
|
|
|
|
return 'qtHookData'
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def qtTypeInfoVersion(self):
|
2016-11-02 08:31:22 +01:00
|
|
|
addr = self.symbolAddress(self.qtHookDataSymbolName())
|
2016-09-23 17:23:41 +02:00
|
|
|
if addr:
|
|
|
|
# Only available with Qt 5.3+
|
|
|
|
(hookVersion, x, x, x, x, x, tiVersion) = self.split('ppppppp', addr)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('HOOK: %s TI: %s' % (hookVersion, tiVersion))
|
2016-09-23 17:23:41 +02:00
|
|
|
if hookVersion >= 3:
|
|
|
|
self.qtTypeInfoVersion = lambda: tiVersion
|
|
|
|
return tiVersion
|
|
|
|
return None
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-11-18 13:00:32 +01:00
|
|
|
def qtDeclarativeHookDataSymbolName(self):
|
|
|
|
return 'qtDeclarativeHookData'
|
|
|
|
|
|
|
|
def qtDeclarativeTypeInfoVersion(self):
|
|
|
|
addr = self.symbolAddress(self.qtDeclarativeHookDataSymbolName())
|
|
|
|
if addr:
|
|
|
|
# Only available with Qt 5.6+
|
|
|
|
(hookVersion, x, tiVersion) = self.split('ppp', addr)
|
|
|
|
if hookVersion >= 1:
|
|
|
|
self.qtTypeInfoVersion = lambda: tiVersion
|
|
|
|
return tiVersion
|
|
|
|
return None
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def addToCache(self, typeobj):
|
|
|
|
typename = typeobj.name
|
|
|
|
if typename in self.typesReported:
|
|
|
|
return
|
|
|
|
self.typesReported[typename] = True
|
|
|
|
self.typesToReport[typename] = typeobj
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class Value():
|
2016-09-06 08:54:43 +02:00
|
|
|
def __init__(self, dumper):
|
2022-08-04 15:40:04 +02:00
|
|
|
# This can be helpful to track down from where a Value was created
|
|
|
|
#self._stack = inspect.stack()
|
2016-09-06 08:54:43 +02:00
|
|
|
self.dumper = dumper
|
|
|
|
self.name = None
|
2021-01-19 16:02:48 +01:00
|
|
|
self._type = None
|
2020-02-24 14:37:56 +01:00
|
|
|
self.ldata = None # Target address in case of references and pointers.
|
|
|
|
self.laddress = None # Own address.
|
Debugger: Retrieve and remember int from native GDB value
When adding expressions for bitfield members in the
debugger's expression view, their corresponding 'gdb.Value'
does not expose the fact that those are actually bitfields,
so e.g. an 'int : 3' is exposed like a "normal" 'int'.
Previously, this would result in wrong values being
retrieved in the 'DumperBase::Value::integer()' function,
when trying to read the value from the corresponding
memory address.
To avoid this, retrieve the actual int representation
for numeric values from the corresponding native 'gdb.Value',
remember them and return that one, similar to how it
is already done for known bitfield members
(s. 'Dumper::memberFromNativeFieldAndValue').
The conversion from the 'gdb.Value' does not work
for integers of a size larger than 64 bits
(like '__int128' used in the "Int128" dumper test).
Therefore, just ignore conversion failures and don't
remember any value explicitly for those cases,
so the same handling as previously used is applied.
(At a quick glance, the reason seems to be that this
is because GDB's corresponding functions use 'int64'
as a return value of the relevant functions [1] [2],
but I did not look closer into what GDB does
internally.)
Corresponding tests will be added in a separate commit.
[1] https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdbsupport/common-types.h;h=f5b2f3d249177acea77231c21c5601f959c18d2f;hb=f3034e25fa98d44b775970f40c9ec85eeae096e6#l33
[2] https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/python/py-value.c;h=6e29284aad11ff344789152a4f601b3474d86bb5;hb=f3034e25fa98d44b775970f40c9ec85eeae096e6#l1706
Fixes: QTCREATORBUG-24693
Change-Id: Idfc3390115e8796f3c778070c23424c3dbdfeddd
Reviewed-by: hjk <hjk@qt.io>
2020-09-24 12:02:06 +02:00
|
|
|
self.lvalue = None
|
2016-09-06 08:54:43 +02:00
|
|
|
self.lIsInScope = True
|
2016-09-26 14:29:16 +02:00
|
|
|
self.ldisplay = None
|
2020-02-24 14:37:56 +01:00
|
|
|
self.summary = None # Always hexencoded UTF-8.
|
2016-11-01 09:50:31 +01:00
|
|
|
self.lbitpos = None
|
2016-10-06 00:59:11 +02:00
|
|
|
self.lbitsize = None
|
2020-02-24 14:37:56 +01:00
|
|
|
self.targetValue = None # For references.
|
2016-11-01 09:50:31 +01:00
|
|
|
self.isBaseClass = None
|
2017-03-08 16:37:52 +01:00
|
|
|
self.nativeValue = None
|
2021-02-17 08:40:48 +01:00
|
|
|
self.autoDerefCount = 0
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-11-14 12:24:56 +01:00
|
|
|
def copy(self):
|
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.dumper = self.dumper
|
|
|
|
val.name = self.name
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self._type
|
2016-11-14 12:24:56 +01:00
|
|
|
val.ldata = self.ldata
|
|
|
|
val.laddress = self.laddress
|
|
|
|
val.lIsInScope = self.lIsInScope
|
|
|
|
val.ldisplay = self.ldisplay
|
2017-08-15 15:17:12 +02:00
|
|
|
val.summary = self.summary
|
2016-11-14 12:24:56 +01:00
|
|
|
val.lbitpos = self.lbitpos
|
|
|
|
val.lbitsize = self.lbitsize
|
|
|
|
val.targetValue = self.targetValue
|
2017-03-08 16:37:52 +01:00
|
|
|
val.nativeValue = self.nativeValue
|
2016-11-14 12:24:56 +01:00
|
|
|
return val
|
|
|
|
|
2021-01-19 16:02:48 +01:00
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
if self._type is None and self.nativeValue is not None:
|
|
|
|
self._type = self.dumper.nativeValueType(self.nativeValue)
|
|
|
|
return self._type
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def check(self):
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.laddress is not None and not self.dumper.isInt(self.laddress):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('INCONSISTENT ADDRESS: %s' % type(self.laddress))
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.type is not None and not isinstance(self.type, self.dumper.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('INCONSISTENT TYPE: %s' % type(self.type))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
2020-02-21 10:10:00 +01:00
|
|
|
#raise RuntimeError('Not implemented')
|
2016-09-15 12:31:28 +02:00
|
|
|
return self.stringify()
|
|
|
|
|
2016-09-29 17:42:23 +03:00
|
|
|
def __int__(self):
|
|
|
|
return self.integer()
|
|
|
|
|
2016-09-15 12:31:28 +02:00
|
|
|
def stringify(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
addr = 'None' if self.laddress is None else ('0x%x' % self.laddress)
|
2016-11-01 09:50:31 +01:00
|
|
|
return "Value(name='%s',type=%s,bsize=%s,bpos=%s,data=%s,address=%s)" \
|
2020-02-24 14:37:56 +01:00
|
|
|
% (self.name, self.type.name, self.lbitsize, self.lbitpos,
|
|
|
|
self.dumper.hexencode(self.ldata), addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2018-12-11 15:15:48 +01:00
|
|
|
def displayEnum(self, form='%d', bitsize=None):
|
|
|
|
intval = self.integer(bitsize)
|
2022-08-12 14:42:06 +02:00
|
|
|
dd = self.type.tdata.enumDisplay
|
2018-03-21 17:10:24 +01:00
|
|
|
if dd is None:
|
|
|
|
return str(intval)
|
|
|
|
return dd(intval, self.laddress, form)
|
|
|
|
|
|
|
|
def display(self):
|
2020-07-31 14:09:29 +02:00
|
|
|
if self.ldisplay is not None:
|
|
|
|
return self.ldisplay
|
2016-09-06 08:54:43 +02:00
|
|
|
simple = self.value()
|
|
|
|
if simple is not None:
|
|
|
|
return str(simple)
|
2016-09-26 14:29:16 +02:00
|
|
|
#if self.ldata is not None:
|
2021-09-23 12:31:49 +00:00
|
|
|
# if sys.version_info[0] == 2 and isinstance(self.ldata, buffer):
|
|
|
|
# return bytes(self.ldata).encode('hex')
|
2016-10-07 11:49:51 +02:00
|
|
|
# return self.ldata.encode('hex')
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.laddress is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
return 'value of type %s at address 0x%x' % (self.type.name, self.laddress)
|
|
|
|
return '<unknown data>'
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def pointer(self):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.detypedef().pointer()
|
|
|
|
return self.extractInteger(self.dumper.ptrSize() * 8, True)
|
|
|
|
|
2018-12-11 15:15:48 +01:00
|
|
|
def integer(self, bitsize=None):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.detypedef().integer()
|
Debugger: Retrieve and remember int from native GDB value
When adding expressions for bitfield members in the
debugger's expression view, their corresponding 'gdb.Value'
does not expose the fact that those are actually bitfields,
so e.g. an 'int : 3' is exposed like a "normal" 'int'.
Previously, this would result in wrong values being
retrieved in the 'DumperBase::Value::integer()' function,
when trying to read the value from the corresponding
memory address.
To avoid this, retrieve the actual int representation
for numeric values from the corresponding native 'gdb.Value',
remember them and return that one, similar to how it
is already done for known bitfield members
(s. 'Dumper::memberFromNativeFieldAndValue').
The conversion from the 'gdb.Value' does not work
for integers of a size larger than 64 bits
(like '__int128' used in the "Int128" dumper test).
Therefore, just ignore conversion failures and don't
remember any value explicitly for those cases,
so the same handling as previously used is applied.
(At a quick glance, the reason seems to be that this
is because GDB's corresponding functions use 'int64'
as a return value of the relevant functions [1] [2],
but I did not look closer into what GDB does
internally.)
Corresponding tests will be added in a separate commit.
[1] https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdbsupport/common-types.h;h=f5b2f3d249177acea77231c21c5601f959c18d2f;hb=f3034e25fa98d44b775970f40c9ec85eeae096e6#l33
[2] https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/python/py-value.c;h=6e29284aad11ff344789152a4f601b3474d86bb5;hb=f3034e25fa98d44b775970f40c9ec85eeae096e6#l1706
Fixes: QTCREATORBUG-24693
Change-Id: Idfc3390115e8796f3c778070c23424c3dbdfeddd
Reviewed-by: hjk <hjk@qt.io>
2020-09-24 12:02:06 +02:00
|
|
|
elif isinstance(self.lvalue, int):
|
2017-02-08 17:40:22 +02:00
|
|
|
return self.lvalue
|
2018-10-02 11:29:57 +02:00
|
|
|
# Could be something like 'short unsigned int'
|
|
|
|
unsigned = self.type.name == 'unsigned' \
|
2020-02-24 14:37:56 +01:00
|
|
|
or self.type.name.startswith('unsigned ') \
|
|
|
|
or self.type.name.find(' unsigned ') != -1
|
2018-12-11 15:15:48 +01:00
|
|
|
if bitsize is None:
|
|
|
|
bitsize = self.type.bitsize()
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.extractInteger(bitsize, unsigned)
|
|
|
|
|
|
|
|
def floatingPoint(self):
|
2017-04-25 11:03:36 +02:00
|
|
|
if self.nativeValue is not None and not self.dumper.isCdb:
|
|
|
|
return str(self.nativeValue)
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.detypedef().floatingPoint()
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.type.size() == 8:
|
|
|
|
return self.extractSomething('d', 64)
|
|
|
|
if self.type.size() == 4:
|
|
|
|
return self.extractSomething('f', 32)
|
2017-04-25 11:03:36 +02:00
|
|
|
# Fall back in case we don't have a nativeValue at hand.
|
|
|
|
# FIXME: This assumes Intel's 80bit extended floats. Which might
|
|
|
|
# be wrong.
|
|
|
|
l, h = self.split('QQ')
|
|
|
|
if True: # 80 bit floats
|
|
|
|
sign = (h >> 15) & 1
|
|
|
|
exp = (h & 0x7fff)
|
|
|
|
fraction = l
|
|
|
|
bit63 = (l >> 63) & 1
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("SIGN: %s EXP: %s H: 0x%x L: 0x%x" % (sign, exp, h, l))
|
2017-04-25 11:03:36 +02:00
|
|
|
if exp == 0:
|
|
|
|
if bit63 == 0:
|
|
|
|
if l == 0:
|
|
|
|
res = '-0' if sign else '0'
|
|
|
|
else:
|
|
|
|
res = (-1)**sign * l * 2**(-16382) # subnormal
|
|
|
|
else:
|
|
|
|
res = 'pseudodenormal'
|
|
|
|
elif exp == 0x7fff:
|
|
|
|
res = 'special'
|
|
|
|
else:
|
|
|
|
res = (-1)**sign * l * 2**(exp - 16383 - 63)
|
|
|
|
else: # 128 bits
|
|
|
|
sign = h >> 63
|
|
|
|
exp = (h >> 48) & 0x7fff
|
|
|
|
fraction = h & (2**48 - 1)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("SIGN: %s EXP: %s FRAC: %s H: 0x%x L: 0x%x" % (sign, exp, fraction, h, l))
|
2017-04-25 11:03:36 +02:00
|
|
|
if exp == 0:
|
|
|
|
if fraction == 0:
|
|
|
|
res = -0.0 if sign else 0.0
|
|
|
|
else:
|
|
|
|
res = (-1)**sign * fraction / 2**48 * 2**(-62) # subnormal
|
|
|
|
elif exp == 0x7fff:
|
|
|
|
res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
|
|
|
|
else:
|
|
|
|
res = (-1)**sign * (1 + fraction / 2**48) * 2**(exp - 63)
|
|
|
|
return res
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def value(self):
|
|
|
|
if self.type is not None:
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Enum:
|
2018-11-15 09:04:39 +01:00
|
|
|
return self.displayEnum()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.detypedef().value()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Integral:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.integer()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Bitfield:
|
2016-11-07 08:57:26 +01:00
|
|
|
return self.integer()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Float:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.floatingPoint()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Pointer:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.pointer()
|
|
|
|
return None
|
|
|
|
|
|
|
|
def extractPointer(self):
|
|
|
|
return self.split('p')[0]
|
|
|
|
|
2020-12-15 14:22:37 +01:00
|
|
|
def hasMember(self, name):
|
|
|
|
return self.findMemberByName(name) is not None
|
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
def findMemberByName(self, name):
|
|
|
|
self.check()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-11-01 09:50:31 +01:00
|
|
|
return self.findMemberByName(self.detypedef())
|
2020-02-24 14:37:56 +01:00
|
|
|
if self.type.code in (
|
2020-02-24 15:10:47 +01:00
|
|
|
TypeCode.Pointer,
|
|
|
|
TypeCode.Reference,
|
|
|
|
TypeCode.RValueReference):
|
2016-11-01 09:50:31 +01:00
|
|
|
res = self.dereference().findMemberByName(name)
|
|
|
|
if res is not None:
|
|
|
|
return res
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Struct:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, self.type.name))
|
2016-11-01 09:50:31 +01:00
|
|
|
members = self.members(True)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('MEMBERS: %s' % members)
|
2016-11-01 09:50:31 +01:00
|
|
|
for member in members:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('CHECKING FIELD %s' % member.name)
|
2020-02-24 15:10:47 +01:00
|
|
|
if member.type.code == TypeCode.Typedef:
|
2016-11-14 12:24:56 +01:00
|
|
|
member = member.detypedef()
|
2016-11-01 09:50:31 +01:00
|
|
|
if member.name == name:
|
|
|
|
return member
|
|
|
|
for member in members:
|
2020-02-24 15:10:47 +01:00
|
|
|
if member.type.code == TypeCode.Typedef:
|
2016-11-14 12:24:56 +01:00
|
|
|
member = member.detypedef()
|
2020-02-24 14:37:56 +01:00
|
|
|
if member.name == name: # Could be base class.
|
2016-11-14 12:24:56 +01:00
|
|
|
return member
|
2020-02-24 15:10:47 +01:00
|
|
|
if member.type.code == TypeCode.Struct:
|
2016-11-01 09:50:31 +01:00
|
|
|
res = member.findMemberByName(name)
|
|
|
|
if res is not None:
|
|
|
|
return res
|
|
|
|
return None
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def __getitem__(self, index):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('GET ITEM %s %s' % (self, index))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('GET ITEM STRIP TYPEDEFS TO %s' % self.type.ltarget)
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.cast(self.type.ltarget).__getitem__(index)
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(index, str):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Pointer:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('GET ITEM %s DEREFERENCE TO %s' % (self, self.dereference()))
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.dereference().__getitem__(index)
|
2016-11-01 09:50:31 +01:00
|
|
|
res = self.findMemberByName(index)
|
|
|
|
if res is None:
|
|
|
|
raise RuntimeError('No member named %s in type %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% (index, self.type.name))
|
2016-11-01 09:50:31 +01:00
|
|
|
return res
|
2016-09-06 08:54:43 +02:00
|
|
|
elif isinstance(index, self.dumper.Field):
|
|
|
|
field = index
|
2021-09-23 12:31:49 +00:00
|
|
|
elif self.dumper.isInt(index):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Array:
|
2016-12-13 16:24:57 +01:00
|
|
|
addr = self.laddress + int(index) * self.type.ltarget.size()
|
|
|
|
return self.dumper.createValue(addr, self.type.ltarget)
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Pointer:
|
2016-12-13 16:24:57 +01:00
|
|
|
addr = self.pointer() + int(index) * self.type.ltarget.size()
|
|
|
|
return self.dumper.createValue(addr, self.type.ltarget)
|
2016-11-01 09:50:31 +01:00
|
|
|
return self.members(False)[index]
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('BAD INDEX TYPE %s' % type(index))
|
2016-09-06 08:54:43 +02:00
|
|
|
field.check()
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('EXTRACT FIELD: %s, BASE 0x%x' % (field, self.address()))
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Pointer:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('IS TYPEDEFED POINTER!')
|
2016-09-06 08:54:43 +02:00
|
|
|
res = self.dereference()
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('WAS POINTER: %s' % res)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2017-03-08 16:37:52 +01:00
|
|
|
return field.extract(self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractField(self, field):
|
2017-03-08 16:37:52 +01:00
|
|
|
if not isinstance(field, self.dumper.Field):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('BAD INDEX TYPE %s' % type(field))
|
2017-03-08 16:37:52 +01:00
|
|
|
|
|
|
|
if field.extractor is not None:
|
|
|
|
val = field.extractor(self)
|
|
|
|
if val is not None:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('EXTRACTOR SUCCEEDED: %s ' % val)
|
2017-03-08 16:37:52 +01:00
|
|
|
return val
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.cast(self.type.ltarget).extractField(field)
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code in (TypeCode.Reference, TypeCode.RValueReference):
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.dereference().extractField(field)
|
2022-08-02 14:51:23 +02:00
|
|
|
#DumperBase.warn('FIELD: %s ' % (field,))
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.name = field.name
|
2017-03-08 16:37:52 +01:00
|
|
|
val.isBaseClass = field.isBase
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = field.fieldType()
|
2016-11-07 08:57:26 +01:00
|
|
|
|
|
|
|
if field.isArtificial:
|
|
|
|
if self.laddress is not None:
|
|
|
|
val.laddress = self.laddress
|
|
|
|
if self.ldata is not None:
|
|
|
|
val.ldata = self.ldata
|
|
|
|
return val
|
|
|
|
|
2017-03-08 16:37:52 +01:00
|
|
|
fieldBitsize = field.bitsize
|
2016-11-07 08:57:26 +01:00
|
|
|
fieldSize = (fieldBitsize + 7) // 8
|
2017-03-08 16:37:52 +01:00
|
|
|
fieldBitpos = field.bitpos
|
2016-11-07 08:57:26 +01:00
|
|
|
fieldOffset = fieldBitpos // 8
|
|
|
|
fieldType = field.fieldType()
|
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if fieldType.code == TypeCode.Bitfield:
|
2016-11-07 08:57:26 +01:00
|
|
|
fieldBitpos -= fieldOffset * 8
|
|
|
|
ldata = self.data()
|
|
|
|
data = 0
|
|
|
|
for i in range(fieldSize):
|
|
|
|
data = data << 8
|
|
|
|
if self.dumper.isBigEndian:
|
2020-12-10 15:27:13 +01:00
|
|
|
lbyte = ldata[i]
|
2016-11-07 08:57:26 +01:00
|
|
|
else:
|
2020-12-10 15:27:13 +01:00
|
|
|
lbyte = ldata[fieldOffset + fieldSize - 1 - i]
|
2022-08-04 08:30:48 +02:00
|
|
|
if isinstance(lbyte, (str, bytes)):
|
|
|
|
data += ord(lbyte)
|
|
|
|
else:
|
|
|
|
data += lbyte
|
2016-11-07 08:57:26 +01:00
|
|
|
data = data >> fieldBitpos
|
|
|
|
data = data & ((1 << fieldBitsize) - 1)
|
|
|
|
val.lvalue = data
|
|
|
|
val.laddress = None
|
|
|
|
return val
|
2016-09-26 14:29:16 +02:00
|
|
|
|
|
|
|
if self.laddress is not None:
|
|
|
|
val.laddress = self.laddress + fieldOffset
|
|
|
|
elif self.ldata is not None:
|
|
|
|
val.ldata = self.ldata[fieldOffset:fieldOffset + fieldSize]
|
|
|
|
else:
|
|
|
|
self.dumper.check(False)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-02-24 15:10:47 +01:00
|
|
|
if fieldType.code in (TypeCode.Reference, TypeCode.RValueReference):
|
2016-11-07 08:57:26 +01:00
|
|
|
if val.laddress is not None:
|
|
|
|
val = self.dumper.createReferenceValue(val.laddress, fieldType.ltarget)
|
|
|
|
val.name = field.name
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('GOT VAL %s FOR FIELD %s' % (val, field))
|
2016-09-26 14:29:16 +02:00
|
|
|
val.lbitsize = fieldBitsize
|
2016-11-08 16:45:24 +01:00
|
|
|
val.check()
|
2016-09-06 08:54:43 +02:00
|
|
|
return val
|
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
# This is the generic version for synthetic values.
|
|
|
|
# The native backends replace it in their fromNativeValue()
|
|
|
|
# implementations.
|
|
|
|
def members(self, includeBases):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("LISTING MEMBERS OF %s" % self)
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-11-01 09:50:31 +01:00
|
|
|
return self.detypedef().members(includeBases)
|
2016-11-07 08:57:26 +01:00
|
|
|
|
2022-08-12 14:42:06 +02:00
|
|
|
tdata = self.type.tdata
|
2016-11-07 08:57:26 +01:00
|
|
|
#if isinstance(tdata.lfields, list):
|
|
|
|
# return tdata.lfields
|
|
|
|
|
|
|
|
fields = []
|
|
|
|
if tdata.lfields is not None:
|
|
|
|
if isinstance(tdata.lfields, list):
|
|
|
|
fields = tdata.lfields
|
|
|
|
else:
|
|
|
|
fields = list(tdata.lfields(self))
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("FIELDS: %s" % fields)
|
2016-11-01 09:50:31 +01:00
|
|
|
res = []
|
2016-11-07 08:57:26 +01:00
|
|
|
for field in fields:
|
2016-11-14 12:24:56 +01:00
|
|
|
if isinstance(field, self.dumper.Value):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("USING VALUE DIRECTLY %s" % field.name)
|
2016-11-14 12:24:56 +01:00
|
|
|
res.append(field)
|
|
|
|
continue
|
2017-03-08 16:37:52 +01:00
|
|
|
if field.isBase and not includeBases:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("DROPPING BASE %s" % field.name)
|
2016-11-01 09:50:31 +01:00
|
|
|
continue
|
2016-11-07 08:57:26 +01:00
|
|
|
res.append(self.extractField(field))
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("GOT MEMBERS: %s" % res)
|
2016-11-01 09:50:31 +01:00
|
|
|
return res
|
2016-09-21 18:52:49 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def __add__(self, other):
|
|
|
|
self.check()
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.dumper.isInt(other):
|
2016-09-26 14:29:16 +02:00
|
|
|
stripped = self.type.stripTypedefs()
|
2020-02-24 15:10:47 +01:00
|
|
|
if stripped.code == TypeCode.Pointer:
|
2017-05-04 23:10:31 +03:00
|
|
|
address = self.pointer() + stripped.dereference().size() * other
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.laddress = None
|
2016-11-07 08:57:26 +01:00
|
|
|
val.ldata = bytes(struct.pack(self.dumper.packCode + 'Q', address))
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self._type
|
2016-09-26 14:29:16 +02:00
|
|
|
return val
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('BAD DATA TO ADD TO: %s %s' % (self.type, other))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2017-05-29 12:07:06 +03:00
|
|
|
def __sub__(self, other):
|
|
|
|
self.check()
|
|
|
|
if self.type.name == other.type.name:
|
|
|
|
stripped = self.type.stripTypedefs()
|
2020-02-24 15:10:47 +01:00
|
|
|
if stripped.code == TypeCode.Pointer:
|
2017-05-29 12:07:06 +03:00
|
|
|
return (self.pointer() - other.pointer()) // stripped.dereference().size()
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('BAD DATA TO SUB TO: %s %s' % (self.type, other))
|
2017-05-29 12:07:06 +03:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def dereference(self):
|
|
|
|
self.check()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.detypedef().dereference()
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.dumper.Value(self.dumper)
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code in (TypeCode.Reference, TypeCode.RValueReference):
|
2017-08-15 15:17:12 +02:00
|
|
|
val.summary = self.summary
|
2017-03-08 16:37:52 +01:00
|
|
|
if self.nativeValue is None:
|
|
|
|
val.laddress = self.pointer()
|
|
|
|
if val.laddress is None and self.laddress is not None:
|
|
|
|
val.laddress = self.laddress
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.type.dereference()
|
2020-06-29 09:34:57 +03:00
|
|
|
if self.dumper.useDynamicType:
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.dumper.nativeDynamicType(val.laddress, val.type)
|
2017-03-08 16:37:52 +01:00
|
|
|
else:
|
2017-03-22 14:19:50 +01:00
|
|
|
val = self.dumper.nativeValueDereferenceReference(self)
|
2020-02-24 15:10:47 +01:00
|
|
|
elif self.type.code == TypeCode.Pointer:
|
2023-02-17 14:29:53 +01:00
|
|
|
try:
|
|
|
|
val = self.dumper.nativeValueDereferencePointer(self)
|
|
|
|
except:
|
2017-03-08 16:37:52 +01:00
|
|
|
val.laddress = self.pointer()
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.type.dereference()
|
2020-06-29 09:34:57 +03:00
|
|
|
if self.dumper.useDynamicType:
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.dumper.nativeDynamicType(val.laddress, val.type)
|
2016-10-25 15:32:13 +02:00
|
|
|
else:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError("WRONG: %s" % self.type.code)
|
|
|
|
#DumperBase.warn("DEREFERENCING FROM: %s" % self)
|
|
|
|
#DumperBase.warn("DEREFERENCING TO: %s" % val)
|
2016-10-25 15:32:13 +02:00
|
|
|
#dynTypeName = val.type.dynamicTypeName(val.laddress)
|
|
|
|
#if dynTypeName is not None:
|
2021-01-19 16:02:48 +01:00
|
|
|
# val._type = self.dumper.createType(dynTypeName)
|
2016-10-25 15:32:13 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def detypedef(self):
|
|
|
|
self.check()
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.type.code != TypeCode.Typedef:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError("WRONG")
|
2016-11-14 12:24:56 +01:00
|
|
|
val = self.copy()
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.type.ltarget
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("DETYPEDEF FROM: %s" % self)
|
|
|
|
#DumperBase.warn("DETYPEDEF TO: %s" % val)
|
2016-09-26 14:29:16 +02:00
|
|
|
return val
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-15 12:31:28 +02:00
|
|
|
def extend(self, size):
|
|
|
|
if self.type.size() < size:
|
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.laddress = None
|
2016-10-25 15:32:13 +02:00
|
|
|
val.ldata = self.zeroExtend(self.ldata)
|
2016-09-15 12:31:28 +02:00
|
|
|
return val
|
|
|
|
if self.type.size() == size:
|
|
|
|
return self
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('NOT IMPLEMENTED')
|
2016-09-15 12:31:28 +02:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def zeroExtend(self, data, size):
|
2016-11-07 08:57:26 +01:00
|
|
|
ext = '\0' * (size - len(data))
|
2021-09-23 12:31:49 +00:00
|
|
|
if sys.version_info[0] == 3:
|
|
|
|
pad = bytes(ext, encoding='latin1')
|
|
|
|
else:
|
|
|
|
pad = bytes(ext)
|
2016-11-07 08:57:26 +01:00
|
|
|
return pad + data if self.dumper.isBigEndian else data + pad
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2016-09-14 12:29:25 +02:00
|
|
|
def cast(self, typish):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.laddress = self.laddress
|
2016-10-06 00:59:11 +02:00
|
|
|
val.lbitsize = self.lbitsize
|
2016-09-06 08:54:43 +02:00
|
|
|
val.ldata = self.ldata
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.dumper.createType(typish)
|
2016-09-06 08:54:43 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def address(self):
|
|
|
|
self.check()
|
|
|
|
return self.laddress
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def data(self, size=None):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
|
|
|
if self.ldata is not None:
|
|
|
|
if len(self.ldata) > 0:
|
2016-09-15 12:31:28 +02:00
|
|
|
if size is None:
|
|
|
|
return self.ldata
|
|
|
|
if size == len(self.ldata):
|
|
|
|
return self.ldata
|
|
|
|
if size < len(self.ldata):
|
|
|
|
return self.ldata[:size]
|
2020-02-21 10:10:00 +01:00
|
|
|
#raise RuntimeError('ZERO-EXTENDING DATA TO %s BYTES: %s' % (size, self))
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.zeroExtend(self.ldata, size)
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.laddress is not None:
|
|
|
|
if size is None:
|
|
|
|
size = self.type.size()
|
|
|
|
res = self.dumper.readRawMemory(self.laddress, size)
|
|
|
|
if len(res) > 0:
|
|
|
|
return res
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('CANNOT CONVERT ADDRESS TO BYTES: %s' % self)
|
|
|
|
raise RuntimeError('CANNOT CONVERT TO BYTES: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractInteger(self, bitsize, unsigned):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.dumper.timer('extractInt'):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
2016-09-26 14:29:16 +02:00
|
|
|
if bitsize > 32:
|
|
|
|
size = 8
|
2016-10-07 11:49:51 +02:00
|
|
|
code = 'Q' if unsigned else 'q'
|
2016-09-26 14:29:16 +02:00
|
|
|
elif bitsize > 16:
|
|
|
|
size = 4
|
2016-10-07 11:49:51 +02:00
|
|
|
code = 'I' if unsigned else 'i'
|
2016-09-26 14:29:16 +02:00
|
|
|
elif bitsize > 8:
|
|
|
|
size = 2
|
2016-10-07 11:49:51 +02:00
|
|
|
code = 'H' if unsigned else 'h'
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2016-09-26 14:29:16 +02:00
|
|
|
size = 1
|
2016-10-07 11:49:51 +02:00
|
|
|
code = 'B' if unsigned else 'b'
|
2016-09-06 08:54:43 +02:00
|
|
|
rawBytes = self.data(size)
|
2016-11-07 08:57:26 +01:00
|
|
|
res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('Extract: Code: %s Bytes: %s Bitsize: %s Size: %s'
|
2016-11-07 08:57:26 +01:00
|
|
|
# % (self.dumper.packCode + code, self.dumper.hexencode(rawBytes), bitsize, size))
|
|
|
|
return res
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractSomething(self, code, bitsize):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.dumper.timer('extractSomething'):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
|
|
|
size = (bitsize + 7) >> 3
|
|
|
|
rawBytes = self.data(size)
|
2016-11-07 08:57:26 +01:00
|
|
|
res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
|
|
|
|
return res
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def to(self, pattern):
|
|
|
|
return self.split(pattern)[0]
|
|
|
|
|
|
|
|
def split(self, pattern):
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.dumper.timer('split'):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('EXTRACT STRUCT FROM: %s' % self.type)
|
2016-09-06 08:54:43 +02:00
|
|
|
(pp, size, fields) = self.dumper.describeStruct(pattern)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('SIZE: %s ' % size)
|
2016-11-07 08:57:26 +01:00
|
|
|
result = struct.unpack_from(self.dumper.packCode + pp, self.data(size))
|
2020-02-24 14:37:56 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def structFixer(field, thing):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('STRUCT MEMBER: %s' % type(thing))
|
2016-09-06 08:54:43 +02:00
|
|
|
if field.isStruct:
|
2017-03-08 16:37:52 +01:00
|
|
|
#if field.type != field.fieldType():
|
2020-02-21 10:10:00 +01:00
|
|
|
# raise RuntimeError('DO NOT SIMPLIFY')
|
|
|
|
#DumperBase.warn('FIELD POS: %s' % field.type.stringify())
|
|
|
|
#DumperBase.warn('FIELD TYE: %s' % field.fieldType().stringify())
|
2016-09-06 08:54:43 +02:00
|
|
|
res = self.dumper.createValue(thing, field.fieldType())
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('RES TYPE: %s' % res.type)
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.laddress is not None:
|
|
|
|
res.laddress = self.laddress + field.offset()
|
|
|
|
return res
|
|
|
|
return thing
|
|
|
|
if len(fields) != len(result):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('STRUCT ERROR: %s %s' % (fields, result))
|
2016-09-06 08:54:43 +02:00
|
|
|
return tuple(map(structFixer, fields, result))
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def checkPointer(self, p, align=1):
|
2021-09-23 12:31:49 +00:00
|
|
|
ptr = p if self.isInt(p) else p.pointer()
|
2016-09-06 08:54:43 +02:00
|
|
|
self.readRawMemory(ptr, 1)
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def type(self, typeId):
|
|
|
|
return self.typeData.get(typeId)
|
2016-09-26 14:29:16 +02:00
|
|
|
|
2018-12-12 10:45:04 +01:00
|
|
|
def splitArrayType(self, type_name):
|
|
|
|
# "foo[2][3][4]" -> ("foo", "[3][4]", 2)
|
|
|
|
pos1 = len(type_name)
|
|
|
|
# In case there are more dimensions we need the inner one.
|
|
|
|
while True:
|
|
|
|
pos1 = type_name.rfind('[', 0, pos1 - 1)
|
|
|
|
pos2 = type_name.find(']', pos1)
|
|
|
|
if type_name[pos1 - 1] != ']':
|
|
|
|
break
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
item_count = type_name[pos1 + 1:pos2]
|
|
|
|
return (type_name[0:pos1].strip(), type_name[pos2 + 1:].strip(), int(item_count))
|
2018-12-12 10:45:04 +01:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def registerTypeAlias(self, existingTypeId, aliasId):
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('REGISTER ALIAS %s FOR %s' % (aliasId, existingTypeId))
|
2016-10-25 15:32:13 +02:00
|
|
|
self.typeData[aliasId] = self.typeData[existingTypeId]
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class TypeData():
|
2022-08-23 17:49:31 +02:00
|
|
|
def __init__(self, dumper, type_id):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.dumper = dumper
|
2020-02-24 14:37:56 +01:00
|
|
|
self.lfields = None # None or Value -> list of member Values
|
|
|
|
self.lalignment = None # Function returning alignment of this struct
|
2016-09-06 08:54:43 +02:00
|
|
|
self.lbitsize = None
|
2020-02-24 14:37:56 +01:00
|
|
|
self.ltarget = None # Inner type for arrays
|
2022-08-12 12:34:32 +02:00
|
|
|
self.templateArguments = None
|
2016-09-19 12:05:16 +02:00
|
|
|
self.code = None
|
2022-08-23 17:49:31 +02:00
|
|
|
self.name = type_id
|
|
|
|
self.typeId = type_id
|
2018-03-21 17:10:24 +01:00
|
|
|
self.enumDisplay = None
|
2017-03-07 08:40:43 +01:00
|
|
|
self.moduleName = None
|
2022-08-23 17:49:31 +02:00
|
|
|
#DumperBase.warn('REGISTER TYPE: %s' % type_id)
|
|
|
|
dumper.typeData[type_id] = self
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
def copy(self):
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.dumper.TypeData(self.dumper, self.typeId)
|
2016-11-01 09:50:31 +01:00
|
|
|
tdata.dumper = self.dumper
|
|
|
|
tdata.lfields = self.lfields
|
|
|
|
tdata.lalignment = self.lalignment
|
|
|
|
tdata.lbitsize = self.lbitsize
|
|
|
|
tdata.ltarget = self.ltarget
|
|
|
|
tdata.templateArguments = self.templateArguments
|
|
|
|
tdata.code = self.code
|
|
|
|
tdata.name = self.name
|
|
|
|
tdata.typeId = self.typeId
|
|
|
|
tdata.enumDisplay = self.enumDisplay
|
2017-03-07 08:40:43 +01:00
|
|
|
tdata.moduleName = self.moduleName
|
2016-11-01 09:50:31 +01:00
|
|
|
return tdata
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class Type():
|
2016-10-25 15:32:13 +02:00
|
|
|
def __init__(self, dumper, typeId):
|
|
|
|
self.typeId = typeId
|
|
|
|
self.dumper = dumper
|
2022-08-12 14:42:06 +02:00
|
|
|
self.tdata = dumper.typeData.get(typeId, None)
|
|
|
|
if self.tdata is None:
|
|
|
|
#DumperBase.warn('USING : %s' % self.typeId)
|
|
|
|
self.dumper.lookupType(self.typeId)
|
|
|
|
self.tdata = self.dumper.typeData.get(self.typeId)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
2016-10-25 15:32:13 +02:00
|
|
|
#return self.typeId
|
|
|
|
return self.stringify()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
2017-03-07 14:44:04 +01:00
|
|
|
tdata = self.dumper.typeData.get(self.typeId)
|
2016-10-25 15:32:13 +02:00
|
|
|
if tdata is None:
|
|
|
|
return self.typeId
|
|
|
|
return tdata.name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def code(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.code
|
2016-10-25 15:32:13 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def lbitsize(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.lbitsize
|
2016-10-25 15:32:13 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def lbitpos(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.lbitpos
|
2016-10-25 15:32:13 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def ltarget(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.ltarget
|
2016-09-15 12:31:28 +02:00
|
|
|
|
2017-03-07 08:40:43 +01:00
|
|
|
@property
|
|
|
|
def moduleName(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.moduleName
|
2017-03-07 08:40:43 +01:00
|
|
|
|
2016-09-15 12:31:28 +02:00
|
|
|
def stringify(self):
|
2016-11-07 08:57:26 +01:00
|
|
|
return 'Type(name="%s",bsize=%s,code=%s)' \
|
2022-08-12 14:42:06 +02:00
|
|
|
% (self.tdata.name, self.tdata.lbitsize, self.tdata.code)
|
2016-09-15 17:55:56 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def __getitem__(self, index):
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.dumper.isInt(index):
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.templateArgument(index)
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('CANNOT INDEX TYPE')
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def dynamicTypeName(self, address):
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata.code != TypeCode.Struct:
|
2016-10-25 15:32:13 +02:00
|
|
|
return None
|
|
|
|
try:
|
|
|
|
vtbl = self.dumper.extractPointer(address)
|
|
|
|
except:
|
|
|
|
return None
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('VTBL: 0x%x' % vtbl)
|
2016-12-01 09:22:53 +01:00
|
|
|
if not self.dumper.couldBePointer(vtbl):
|
2016-10-25 15:32:13 +02:00
|
|
|
return None
|
|
|
|
return self.dumper.nativeDynamicTypeName(address, self)
|
|
|
|
|
|
|
|
def dynamicType(self, address):
|
2016-11-07 08:57:26 +01:00
|
|
|
# FIXME: That buys some performance at the cost of a fail
|
|
|
|
# of Gdb13393 dumper test.
|
|
|
|
#return self
|
2019-12-18 13:27:20 +01:00
|
|
|
#with self.dumper.timer('dynamicType %s 0x%s' % (self.name, address)):
|
2016-10-25 15:32:13 +02:00
|
|
|
dynTypeName = self.dynamicTypeName(address)
|
|
|
|
if dynTypeName is not None:
|
|
|
|
return self.dumper.createType(dynTypeName)
|
|
|
|
return self
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def check(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata.name is None:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('TYPE WITHOUT NAME: %s' % self.typeId)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def dereference(self):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.code == TypeCode.Typedef:
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.ltarget.dereference()
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.ltarget
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def unqualified(self):
|
|
|
|
return self
|
|
|
|
|
2016-11-18 12:07:55 +01:00
|
|
|
def templateArguments(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata is None:
|
2016-11-18 12:07:55 +01:00
|
|
|
return self.dumper.listTemplateParameters(self.typeId)
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.templateArguments()
|
2016-11-18 12:07:55 +01:00
|
|
|
|
2016-11-08 16:45:24 +01:00
|
|
|
def templateArgument(self, position):
|
2022-08-12 14:42:06 +02:00
|
|
|
#DumperBase.warn('TDATA: %s' % self.tdata)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('ID: %s' % self.typeId)
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata is None:
|
2016-10-25 15:32:13 +02:00
|
|
|
# Native lookups didn't help. Happens for 'wrong' placement of 'const'
|
|
|
|
# etc. with LLDB. But not all is lost:
|
|
|
|
ta = self.dumper.listTemplateParameters(self.typeId)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('MANUAL: %s' % ta)
|
2016-10-25 15:32:13 +02:00
|
|
|
res = ta[position]
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('RES: %s' % res.typeId)
|
2016-10-25 15:32:13 +02:00
|
|
|
return res
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('TA: %s %s' % (position, self.typeId))
|
2022-08-12 14:42:06 +02:00
|
|
|
#DumperBase.warn('ARGS: %s' % self.tdata.templateArguments())
|
|
|
|
return self.tdata.templateArguments()[position]
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def simpleEncoding(self):
|
|
|
|
res = {
|
2020-02-24 14:37:56 +01:00
|
|
|
'bool': 'int:1',
|
|
|
|
'char': 'int:1',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int8_t': 'int:1',
|
|
|
|
'qint8': 'int:1',
|
2020-02-24 14:37:56 +01:00
|
|
|
'signed char': 'int:1',
|
2021-10-31 14:28:45 +01:00
|
|
|
'char8_t': 'uint:1',
|
2020-02-24 14:37:56 +01:00
|
|
|
'unsigned char': 'uint:1',
|
2021-10-29 14:11:10 +02:00
|
|
|
'uint8_t': 'uint:1',
|
2021-10-31 14:28:45 +01:00
|
|
|
'quint8': 'uint:1',
|
2020-02-24 14:37:56 +01:00
|
|
|
'short': 'int:2',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int16_t': 'int:2',
|
|
|
|
'qint16': 'int:2',
|
2020-02-24 14:37:56 +01:00
|
|
|
'unsigned short': 'uint:2',
|
2021-10-31 14:28:45 +01:00
|
|
|
'char16_t': 'uint:2',
|
|
|
|
'uint16_t': 'uint:2',
|
|
|
|
'quint16': 'uint:2',
|
2020-02-24 14:37:56 +01:00
|
|
|
'int': 'int:4',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int32_t': 'int:4',
|
|
|
|
'qint32': 'int:4',
|
2020-02-24 14:37:56 +01:00
|
|
|
'unsigned int': 'uint:4',
|
2021-10-31 14:28:45 +01:00
|
|
|
'char32_t': 'uint:4',
|
|
|
|
'uint32_t': 'uint:4',
|
|
|
|
'quint32': 'uint:4',
|
2020-02-24 14:37:56 +01:00
|
|
|
'long long': 'int:8',
|
2021-10-31 14:28:45 +01:00
|
|
|
'int64_t': 'int:8',
|
|
|
|
'qint64': 'int:8',
|
2020-02-24 14:37:56 +01:00
|
|
|
'unsigned long long': 'uint:8',
|
2021-10-31 14:28:45 +01:00
|
|
|
'uint64_t': 'uint:8',
|
|
|
|
'quint64': 'uint:8',
|
2016-09-15 17:55:56 +02:00
|
|
|
'float': 'float:4',
|
2020-09-22 09:17:16 +02:00
|
|
|
'double': 'float:8',
|
|
|
|
'QChar': 'uint:2'
|
2016-09-15 17:55:56 +02:00
|
|
|
}.get(self.name, None)
|
|
|
|
return res
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def isSimpleType(self):
|
2020-02-24 15:10:47 +01:00
|
|
|
return self.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def alignment(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata.code == TypeCode.Typedef:
|
|
|
|
return self.tdata.ltarget.alignment()
|
|
|
|
if self.tdata.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum):
|
|
|
|
if self.tdata.name in ('double', 'long long', 'unsigned long long'):
|
2017-03-03 12:18:50 +01:00
|
|
|
# Crude approximation.
|
|
|
|
return 8 if self.dumper.isWindowsTarget() else self.dumper.ptrSize()
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.size()
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata.code in (TypeCode.Pointer, TypeCode.Reference, TypeCode.RValueReference):
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.dumper.ptrSize()
|
2022-08-12 14:42:06 +02:00
|
|
|
if self.tdata.lalignment is not None:
|
|
|
|
#if isinstance(self.tdata.lalignment, function): # Does not work that way.
|
|
|
|
if hasattr(self.tdata.lalignment, '__call__'):
|
|
|
|
return self.tdata.lalignment()
|
|
|
|
return self.tdata.lalignment
|
2016-11-01 09:50:31 +01:00
|
|
|
return 1
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def pointer(self):
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.dumper.createPointerType(self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def target(self):
|
2022-08-12 14:42:06 +02:00
|
|
|
return self.tdata.ltarget
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def stripTypedefs(self):
|
2020-02-24 15:10:47 +01:00
|
|
|
if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('NO TYPEDEF: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
return self
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.ltarget
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def size(self):
|
|
|
|
bs = self.bitsize()
|
|
|
|
if bs % 8 != 0:
|
2020-02-21 10:10:00 +01:00
|
|
|
DumperBase.warn('ODD SIZE: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
return (7 + bs) >> 3
|
|
|
|
|
|
|
|
def bitsize(self):
|
|
|
|
if self.lbitsize is not None:
|
|
|
|
return self.lbitsize
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('DONT KNOW SIZE: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def isMovableType(self):
|
2020-02-24 15:10:47 +01:00
|
|
|
if self.code in (TypeCode.Pointer, TypeCode.Integral, TypeCode.Float):
|
2016-09-06 08:54:43 +02:00
|
|
|
return True
|
|
|
|
strippedName = self.dumper.stripNamespaceFromType(self.name)
|
|
|
|
if strippedName in (
|
2016-10-07 11:49:51 +02:00
|
|
|
'QBrush', 'QBitArray', 'QByteArray', 'QCustomTypeInfo',
|
|
|
|
'QChar', 'QDate', 'QDateTime', 'QFileInfo', 'QFixed',
|
|
|
|
'QFixedPoint', 'QFixedSize', 'QHashDummyValue', 'QIcon',
|
|
|
|
'QImage', 'QLine', 'QLineF', 'QLatin1Char', 'QLocale',
|
|
|
|
'QMatrix', 'QModelIndex', 'QPoint', 'QPointF', 'QPen',
|
|
|
|
'QPersistentModelIndex', 'QResourceRoot', 'QRect', 'QRectF',
|
|
|
|
'QRegExp', 'QSize', 'QSizeF', 'QString', 'QTime', 'QTextBlock',
|
|
|
|
'QUrl', 'QVariant',
|
|
|
|
'QXmlStreamAttribute', 'QXmlStreamNamespaceDeclaration',
|
|
|
|
'QXmlStreamNotationDeclaration', 'QXmlStreamEntityDeclaration'
|
2020-02-24 14:37:56 +01:00
|
|
|
):
|
2016-09-06 08:54:43 +02:00
|
|
|
return True
|
2018-03-19 15:47:36 +01:00
|
|
|
if strippedName == 'QStringList':
|
|
|
|
return self.dumper.qtVersion() >= 0x050000
|
|
|
|
if strippedName == 'QList':
|
|
|
|
return self.dumper.qtVersion() >= 0x050600
|
|
|
|
return False
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2017-03-08 16:37:52 +01:00
|
|
|
class Field(collections.namedtuple('Field',
|
2020-02-24 14:37:56 +01:00
|
|
|
['dumper', 'name', 'type', 'bitsize', 'bitpos',
|
|
|
|
'extractor', 'isBase', 'isStruct', 'isArtificial'])):
|
2017-03-08 16:37:52 +01:00
|
|
|
|
|
|
|
def __new__(cls, dumper, name=None, type=None, bitsize=None, bitpos=None,
|
|
|
|
extractor=None, isBase=False, isStruct=False, isArtificial=False):
|
|
|
|
return super(DumperBase.Field, cls).__new__(
|
2020-02-24 14:37:56 +01:00
|
|
|
cls, dumper, name, type, bitsize, bitpos,
|
|
|
|
extractor, isBase, isStruct, isArtificial)
|
2017-03-08 16:37:52 +01:00
|
|
|
|
|
|
|
__slots__ = ()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
2017-03-08 16:37:52 +01:00
|
|
|
return self.stringify()
|
|
|
|
|
|
|
|
def stringify(self):
|
|
|
|
#return 'Field(name="%s")' % self.name
|
|
|
|
typename = None if self.type is None else self.type.stringify()
|
|
|
|
return 'Field(name="%s",type=%s,bitpos=%s,bitsize=%s)' \
|
2020-02-24 14:37:56 +01:00
|
|
|
% (self.name, typename, self.bitpos, self.bitsize)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def check(self):
|
2016-11-01 09:50:31 +01:00
|
|
|
pass
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def size(self):
|
2017-03-08 16:37:52 +01:00
|
|
|
return self.bitsize() // 8
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def offset(self):
|
2017-03-08 16:37:52 +01:00
|
|
|
return self.bitpos // 8
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def fieldType(self):
|
2017-03-08 16:37:52 +01:00
|
|
|
if self.type is not None:
|
|
|
|
return self.type
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('CANT GET FIELD TYPE FOR %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
return None
|
|
|
|
|
2016-11-07 08:57:26 +01:00
|
|
|
def ptrCode(self):
|
|
|
|
return 'I' if self.ptrSize() == 4 else 'Q'
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def toPointerData(self, address):
|
2021-09-23 12:31:49 +00:00
|
|
|
if not self.isInt(address):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('wrong')
|
2016-11-07 08:57:26 +01:00
|
|
|
return bytes(struct.pack(self.packCode + self.ptrCode(), address))
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2018-10-17 16:05:14 +02:00
|
|
|
def fromPointerData(self, bytes_value):
|
|
|
|
return struct.unpack(self.packCode + self.ptrCode(), bytes_value)
|
|
|
|
|
2016-11-01 09:50:31 +01:00
|
|
|
def createPointerValue(self, targetAddress, targetTypish):
|
|
|
|
if not isinstance(targetTypish, self.Type) and not isinstance(targetTypish, str):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createPointerValue(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetTypish))
|
2021-09-23 12:31:49 +00:00
|
|
|
if not self.isInt(targetAddress):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected integral address value in createPointerValue(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetTypish))
|
2016-10-25 15:32:13 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val.ldata = self.toPointerData(targetAddress)
|
2020-06-29 09:34:57 +03:00
|
|
|
targetType = self.createType(targetTypish)
|
|
|
|
if self.useDynamicType:
|
|
|
|
targetType = targetType.dynamicType(targetAddress)
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.createPointerType(targetType)
|
2016-10-25 15:32:13 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def createReferenceValue(self, targetAddress, targetType):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createReferenceValue(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2021-09-23 12:31:49 +00:00
|
|
|
if not self.isInt(targetAddress):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected integral address value in createReferenceValue(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2016-10-25 15:32:13 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val.ldata = self.toPointerData(targetAddress)
|
2020-06-29 09:34:57 +03:00
|
|
|
if self.useDynamicType:
|
|
|
|
targetType = targetType.dynamicType(targetAddress)
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.createReferenceType(targetType)
|
2016-10-25 15:32:13 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def createPointerType(self, targetType):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createPointerType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2016-10-25 15:32:13 +02:00
|
|
|
typeId = targetType.typeId + ' *'
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.name = targetType.name + '*'
|
|
|
|
tdata.lbitsize = 8 * self.ptrSize()
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Pointer
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.ltarget = targetType
|
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
|
|
|
def createReferenceType(self, targetType):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createReferenceType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2016-10-25 15:32:13 +02:00
|
|
|
typeId = targetType.typeId + ' &'
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.name = targetType.name + ' &'
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Reference
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.ltarget = targetType
|
|
|
|
tdata.lbitsize = 8 * self.ptrSize() # Needed for Gdb13393 test.
|
|
|
|
#tdata.lbitsize = None
|
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
2019-01-08 16:18:25 +01:00
|
|
|
def createRValueReferenceType(self, targetType):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createRValueReferenceType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2019-01-08 16:18:25 +01:00
|
|
|
typeId = targetType.typeId + ' &&'
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2019-01-08 16:18:25 +01:00
|
|
|
tdata.name = targetType.name + ' &&'
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.RValueReference
|
2019-01-08 16:18:25 +01:00
|
|
|
tdata.ltarget = targetType
|
|
|
|
tdata.lbitsize = None
|
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
def createArrayType(self, targetType, count):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createArrayType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2016-11-01 09:50:31 +01:00
|
|
|
targetTypeId = targetType.typeId
|
2018-12-12 10:45:04 +01:00
|
|
|
|
|
|
|
if targetTypeId.endswith(']'):
|
|
|
|
(prefix, suffix, inner_count) = self.splitArrayType(targetTypeId)
|
|
|
|
type_id = '%s[%d][%d]%s' % (prefix, count, inner_count, suffix)
|
|
|
|
type_name = type_id
|
|
|
|
else:
|
|
|
|
type_id = '%s[%d]' % (targetTypeId, count)
|
|
|
|
type_name = '%s[%d]' % (targetType.name, count)
|
|
|
|
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, type_id)
|
2018-12-12 10:45:04 +01:00
|
|
|
tdata.name = type_name
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Array
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.ltarget = targetType
|
2018-12-12 10:45:04 +01:00
|
|
|
tdata.lbitsize = targetType.lbitsize * count
|
|
|
|
return self.Type(self, type_id)
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2017-06-02 15:04:40 +03:00
|
|
|
def createBitfieldType(self, targetType, bitsize):
|
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createBitfieldType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2017-06-02 15:04:40 +03:00
|
|
|
typeId = '%s:%d' % (targetType.typeId, bitsize)
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2017-06-02 15:04:40 +03:00
|
|
|
tdata.name = '%s : %d' % (targetType.typeId, bitsize)
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Bitfield
|
2017-06-02 15:04:40 +03:00
|
|
|
tdata.ltarget = targetType
|
2016-11-07 08:57:26 +01:00
|
|
|
tdata.lbitsize = bitsize
|
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def createTypedefedType(self, targetType, typeName, typeId=None):
|
2017-04-20 08:47:34 +02:00
|
|
|
if typeId is None:
|
|
|
|
typeId = typeName
|
2016-10-25 15:32:13 +02:00
|
|
|
if not isinstance(targetType, self.Type):
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('Expected type in createTypedefType(), got %s'
|
2020-02-24 14:37:56 +01:00
|
|
|
% type(targetType))
|
2016-10-25 15:32:13 +02:00
|
|
|
# Happens for C-style struct in GDB: typedef { int x; } struct S1;
|
|
|
|
if targetType.typeId == typeId:
|
|
|
|
return targetType
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typeId)
|
2017-04-20 08:47:34 +02:00
|
|
|
tdata.name = typeName
|
2020-02-24 15:10:47 +01:00
|
|
|
tdata.code = TypeCode.Typedef
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata.ltarget = targetType
|
|
|
|
tdata.lbitsize = targetType.lbitsize
|
2016-11-01 09:50:31 +01:00
|
|
|
#tdata.lfields = targetType.lfields
|
2017-04-20 08:47:34 +02:00
|
|
|
tdata.lbitsize = targetType.lbitsize
|
2016-10-25 15:32:13 +02:00
|
|
|
return self.Type(self, typeId)
|
|
|
|
|
2020-12-08 07:40:01 +01:00
|
|
|
def knownArrayTypeSize(self):
|
|
|
|
return 3 * self.ptrSize() if self.qtVersion() >= 0x060000 else self.ptrSize()
|
|
|
|
|
|
|
|
def knownTypeSize(self, typish):
|
|
|
|
if typish[0] == 'Q':
|
|
|
|
if typish.startswith('QList<') or typish.startswith('QVector<'):
|
|
|
|
return self.knownArrayTypeSize()
|
|
|
|
if typish == 'QObject':
|
|
|
|
return 2 * self.ptrSize()
|
|
|
|
if typish == 'QStandardItemData':
|
|
|
|
return 4 * self.ptrSize() if self.qtVersion() >= 0x060000 else 2 * self.ptrSize()
|
|
|
|
if typish == 'Qt::ItemDataRole':
|
|
|
|
return 4
|
|
|
|
if typish == 'QChar':
|
|
|
|
return 2
|
|
|
|
if typish in ('quint32', 'qint32'):
|
|
|
|
return 4
|
|
|
|
return None
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def createType(self, typish, size=None):
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(typish, self.Type):
|
2016-10-25 15:32:13 +02:00
|
|
|
#typish.check()
|
2020-12-08 12:19:19 +01:00
|
|
|
if hasattr(typish, 'lbitsize') and typish.lbitsize is not None and typish.lbitsize > 0:
|
|
|
|
return typish
|
|
|
|
# Size 0 is sometimes reported by GDB but doesn't help at all.
|
|
|
|
# Force using the fallback:
|
|
|
|
typish = typish.name
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(typish, str):
|
2016-10-07 13:08:49 +02:00
|
|
|
ns = self.qtNamespace()
|
|
|
|
typish = typish.replace('@', ns)
|
2020-12-08 07:40:01 +01:00
|
|
|
if typish.startswith(ns):
|
|
|
|
if size is None:
|
|
|
|
size = self.knownTypeSize(typish[len(ns):])
|
|
|
|
else:
|
|
|
|
if size is None:
|
|
|
|
size = self.knownTypeSize(typish)
|
|
|
|
if size is not None:
|
|
|
|
typish = ns + typish
|
|
|
|
|
2016-10-25 15:32:13 +02:00
|
|
|
tdata = self.typeData.get(typish, None)
|
|
|
|
if tdata is not None:
|
2020-12-08 12:19:19 +01:00
|
|
|
if tdata.lbitsize is not None:
|
|
|
|
if tdata.lbitsize > 0:
|
|
|
|
return self.Type(self, typish)
|
2016-10-25 15:32:13 +02:00
|
|
|
|
|
|
|
knownType = self.lookupType(typish)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('KNOWN: %s' % knownType)
|
2016-10-25 15:32:13 +02:00
|
|
|
if knownType is not None:
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('USE FROM NATIVE')
|
2016-10-25 15:32:13 +02:00
|
|
|
return knownType
|
|
|
|
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('FAKING: %s SIZE: %s' % (typish, size))
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, typish)
|
2022-08-12 12:34:32 +02:00
|
|
|
tdata.templateArguments = lambda: self.listTemplateParameters(typish)
|
2016-10-25 15:32:13 +02:00
|
|
|
if size is not None:
|
|
|
|
tdata.lbitsize = 8 * size
|
2020-12-08 12:19:19 +01:00
|
|
|
if typish.endswith('*'):
|
|
|
|
tdata.code = TypeCode.Pointer
|
|
|
|
tdata.lbitsize = 8 * self.ptrSize()
|
2020-12-10 11:04:41 +01:00
|
|
|
tdata.ltarget = self.createType(typish[:-1].strip())
|
2016-10-25 15:32:13 +02:00
|
|
|
|
2022-08-23 17:49:31 +02:00
|
|
|
typeobj = self.Type(self, tdata.typeId)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify())
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj.check()
|
|
|
|
return typeobj
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('NEED TYPE, NOT %s' % type(typish))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2022-08-04 15:40:04 +02:00
|
|
|
def createValueFromAddressAndType(self, address, typish):
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.Value(self)
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.createType(typish)
|
2022-08-04 15:40:04 +02:00
|
|
|
#DumperBase.warn('CREATING %s AT 0x%x' % (val.type.name, datish))
|
|
|
|
val.laddress = address
|
|
|
|
if self.useDynamicType:
|
|
|
|
val._type = val.type.dynamicType(address)
|
|
|
|
return val
|
|
|
|
|
|
|
|
def createValue(self, datish, typish):
|
2021-09-23 12:31:49 +00:00
|
|
|
if self.isInt(datish): # Used as address.
|
2022-08-04 15:40:04 +02:00
|
|
|
return self.createValueFromAddressAndType(datish, typish)
|
2016-10-25 15:32:13 +02:00
|
|
|
if isinstance(datish, bytes):
|
2022-08-04 15:40:04 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val._type = self.createType(typish)
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
|
2016-10-25 15:32:13 +02:00
|
|
|
val.ldata = datish
|
|
|
|
val.check()
|
|
|
|
return val
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-05-29 13:08:55 +02:00
|
|
|
def createProxyValue(self, proxy_data, type_name):
|
2022-08-23 17:49:31 +02:00
|
|
|
tdata = self.TypeData(self, type_name)
|
2020-05-29 13:08:55 +02:00
|
|
|
tdata.code = TypeCode.Struct
|
|
|
|
val = self.Value(self)
|
2021-01-19 16:02:48 +01:00
|
|
|
val._type = self.Type(self, type_name)
|
2020-05-29 13:08:55 +02:00
|
|
|
val.ldata = proxy_data
|
|
|
|
return val
|
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
class StructBuilder():
|
2016-09-06 08:54:43 +02:00
|
|
|
def __init__(self, dumper):
|
|
|
|
self.dumper = dumper
|
2016-10-07 11:49:51 +02:00
|
|
|
self.pattern = ''
|
2016-09-06 08:54:43 +02:00
|
|
|
self.currentBitsize = 0
|
|
|
|
self.fields = []
|
|
|
|
self.autoPadNext = False
|
2016-11-01 17:22:56 +01:00
|
|
|
self.maxAlign = 1
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2020-02-24 14:37:56 +01:00
|
|
|
def addField(self, fieldSize, fieldCode=None, fieldIsStruct=False,
|
|
|
|
fieldName=None, fieldType=None, fieldAlign=1):
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
if fieldType is not None:
|
|
|
|
fieldType = self.dumper.createType(fieldType)
|
|
|
|
if fieldSize is None and fieldType is not None:
|
|
|
|
fieldSize = fieldType.size()
|
|
|
|
if fieldCode is None:
|
2016-10-07 11:49:51 +02:00
|
|
|
fieldCode = '%ss' % fieldSize
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
if self.autoPadNext:
|
|
|
|
self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte.
|
2016-11-01 17:22:56 +01:00
|
|
|
padding = (fieldAlign - (self.currentBitsize >> 3)) % fieldAlign
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
|
2017-03-08 16:37:52 +01:00
|
|
|
field = self.dumper.Field(self.dumper, bitpos=self.currentBitsize,
|
2020-02-24 14:37:56 +01:00
|
|
|
bitsize=padding * 8)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.pattern += '%ds' % padding
|
2016-09-06 08:54:43 +02:00
|
|
|
self.currentBitsize += padding * 8
|
|
|
|
self.fields.append(field)
|
|
|
|
self.autoPadNext = False
|
|
|
|
|
2016-11-01 17:22:56 +01:00
|
|
|
if fieldAlign > self.maxAlign:
|
|
|
|
self.maxAlign = fieldAlign
|
2020-02-21 10:10:00 +01:00
|
|
|
#DumperBase.warn("MAX ALIGN: %s" % self.maxAlign)
|
2016-11-01 17:22:56 +01:00
|
|
|
|
2017-03-08 16:37:52 +01:00
|
|
|
field = self.dumper.Field(dumper=self.dumper, name=fieldName, type=fieldType,
|
|
|
|
isStruct=fieldIsStruct, bitpos=self.currentBitsize,
|
|
|
|
bitsize=fieldSize * 8)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
self.pattern += fieldCode
|
|
|
|
self.currentBitsize += fieldSize * 8
|
|
|
|
self.fields.append(field)
|
|
|
|
|
|
|
|
def describeStruct(self, pattern):
|
|
|
|
if pattern in self.structPatternCache:
|
|
|
|
return self.structPatternCache[pattern]
|
|
|
|
ptrSize = self.ptrSize()
|
|
|
|
builder = self.StructBuilder(self)
|
|
|
|
n = None
|
2016-10-07 11:49:51 +02:00
|
|
|
typeName = ''
|
2016-09-06 08:54:43 +02:00
|
|
|
readingTypeName = False
|
|
|
|
for c in pattern:
|
|
|
|
if readingTypeName:
|
|
|
|
if c == '}':
|
|
|
|
readingTypeName = False
|
2016-11-01 17:22:56 +01:00
|
|
|
fieldType = self.createType(typeName)
|
|
|
|
fieldAlign = fieldType.alignment()
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(n, fieldIsStruct=True,
|
|
|
|
fieldType=fieldType, fieldAlign=fieldAlign)
|
2016-09-06 08:54:43 +02:00
|
|
|
typeName = None
|
|
|
|
n = None
|
|
|
|
else:
|
|
|
|
typeName += c
|
2020-02-24 14:37:56 +01:00
|
|
|
elif c == 't': # size_t
|
|
|
|
builder.addField(ptrSize, self.ptrCode(), fieldAlign=ptrSize)
|
|
|
|
elif c == 'p': # Pointer as int
|
|
|
|
builder.addField(ptrSize, self.ptrCode(), fieldAlign=ptrSize)
|
|
|
|
elif c == 'P': # Pointer as Value
|
|
|
|
builder.addField(ptrSize, '%ss' % ptrSize, fieldAlign=ptrSize)
|
2016-10-13 12:41:31 +02:00
|
|
|
elif c in ('d'):
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(8, c, fieldAlign=ptrSize) # fieldType = 'double' ?
|
2016-10-13 12:41:31 +02:00
|
|
|
elif c in ('q', 'Q'):
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(8, c, fieldAlign=ptrSize)
|
2016-09-06 08:54:43 +02:00
|
|
|
elif c in ('i', 'I', 'f'):
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(4, c, fieldAlign=4)
|
2016-09-06 08:54:43 +02:00
|
|
|
elif c in ('h', 'H'):
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(2, c, fieldAlign=2)
|
2016-09-06 08:54:43 +02:00
|
|
|
elif c in ('b', 'B', 'c'):
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(1, c, fieldAlign=1)
|
2016-09-06 08:54:43 +02:00
|
|
|
elif c >= '0' and c <= '9':
|
|
|
|
if n is None:
|
2016-10-07 11:49:51 +02:00
|
|
|
n = ''
|
2016-09-06 08:54:43 +02:00
|
|
|
n += c
|
|
|
|
elif c == 's':
|
2020-02-24 14:37:56 +01:00
|
|
|
builder.addField(int(n), fieldAlign=1)
|
2016-09-06 08:54:43 +02:00
|
|
|
n = None
|
|
|
|
elif c == '{':
|
|
|
|
readingTypeName = True
|
2016-10-07 11:49:51 +02:00
|
|
|
typeName = ''
|
2016-10-04 11:33:32 +02:00
|
|
|
elif c == '@':
|
|
|
|
if n is None:
|
|
|
|
# Automatic padding depending on next item
|
|
|
|
builder.autoPadNext = True
|
|
|
|
else:
|
|
|
|
# Explicit padding.
|
|
|
|
builder.currentBitsize = 8 * ((builder.currentBitsize + 7) >> 3)
|
|
|
|
padding = (int(n) - (builder.currentBitsize >> 3)) % int(n)
|
|
|
|
field = self.Field(self)
|
2016-10-07 11:49:51 +02:00
|
|
|
builder.pattern += '%ds' % padding
|
2016-10-04 11:33:32 +02:00
|
|
|
builder.currentBitsize += padding * 8
|
|
|
|
builder.fields.append(field)
|
|
|
|
n = None
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2020-02-21 10:10:00 +01:00
|
|
|
raise RuntimeError('UNKNOWN STRUCT CODE: %s' % c)
|
2016-09-06 08:54:43 +02:00
|
|
|
pp = builder.pattern
|
2016-11-01 17:22:56 +01:00
|
|
|
size = (builder.currentBitsize + 7) >> 3
|
2016-09-06 08:54:43 +02:00
|
|
|
fields = builder.fields
|
2016-11-01 17:22:56 +01:00
|
|
|
tailPad = (builder.maxAlign - size) % builder.maxAlign
|
|
|
|
size += tailPad
|
2016-09-06 08:54:43 +02:00
|
|
|
self.structPatternCache[pattern] = (pp, size, fields)
|
|
|
|
return (pp, size, fields)
|