2013-09-11 21:35:39 +02:00
|
|
|
############################################################################
|
|
|
|
#
|
2016-01-15 14:53:55 +01:00
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
# Contact: https://www.qt.io/licensing/
|
2013-09-11 21:35:39 +02:00
|
|
|
#
|
|
|
|
# This file is part of Qt Creator.
|
|
|
|
#
|
|
|
|
# Commercial License Usage
|
|
|
|
# Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
# accordance with the commercial license agreement provided with the
|
|
|
|
# Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:53:55 +01:00
|
|
|
# a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
# and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
# information use the contact form at https://www.qt.io/contact-us.
|
2013-09-11 21:35:39 +02:00
|
|
|
#
|
2016-01-15 14:53:55 +01:00
|
|
|
# GNU General Public License Usage
|
|
|
|
# Alternatively, this file may be used under the terms of the GNU
|
|
|
|
# General Public License version 3 as published by the Free Software
|
|
|
|
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
# included in the packaging of this file. Please review the following
|
|
|
|
# information to ensure the GNU General Public License requirements will
|
|
|
|
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-09-11 21:35:39 +02:00
|
|
|
#
|
|
|
|
############################################################################
|
|
|
|
|
|
|
|
import os
|
2016-09-06 08:54:43 +02:00
|
|
|
import copy
|
2014-01-24 15:13:20 +01:00
|
|
|
import struct
|
2013-09-11 21:35:39 +02:00
|
|
|
import sys
|
|
|
|
import base64
|
2014-05-12 13:09:02 +02:00
|
|
|
import re
|
2015-01-21 15:18:57 +01:00
|
|
|
import time
|
2015-10-08 16:19:57 +02:00
|
|
|
import json
|
2016-04-04 23:46:46 +02:00
|
|
|
import inspect
|
2016-10-07 11:13:11 +02:00
|
|
|
import threading
|
2015-01-23 19:09:08 +01:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
if sys.version_info[0] >= 3:
|
|
|
|
xrange = range
|
|
|
|
toInteger = int
|
|
|
|
else:
|
|
|
|
toInteger = long
|
|
|
|
|
|
|
|
|
2014-06-02 17:05:52 +02:00
|
|
|
# Debugger start modes. Keep in sync with DebuggerStartMode in debuggerconstants.h
|
|
|
|
NoStartMode, \
|
|
|
|
StartInternal, \
|
|
|
|
StartExternal, \
|
|
|
|
AttachExternal, \
|
|
|
|
AttachCrashedExternal, \
|
|
|
|
AttachCore, \
|
|
|
|
AttachToRemoteServer, \
|
|
|
|
AttachToRemoteProcess, \
|
|
|
|
StartRemoteProcess, \
|
2014-10-14 19:08:58 +03:00
|
|
|
= range(0, 9)
|
2014-06-02 17:05:52 +02:00
|
|
|
|
|
|
|
|
2015-08-12 11:26:10 +02:00
|
|
|
# Known special formats. Keep in sync with DisplayFormat in debuggerprotocol.h
|
2015-03-20 16:03:59 +01:00
|
|
|
AutomaticFormat, \
|
|
|
|
RawFormat, \
|
|
|
|
SimpleFormat, \
|
|
|
|
EnhancedFormat, \
|
|
|
|
SeparateFormat, \
|
2014-04-15 18:13:03 +02:00
|
|
|
Latin1StringFormat, \
|
2015-03-20 16:03:59 +01:00
|
|
|
SeparateLatin1StringFormat, \
|
2014-04-15 18:13:03 +02:00
|
|
|
Utf8StringFormat, \
|
2015-03-20 16:03:59 +01:00
|
|
|
SeparateUtf8StringFormat, \
|
2014-04-15 18:13:03 +02:00
|
|
|
Local8BitStringFormat, \
|
|
|
|
Utf16StringFormat, \
|
|
|
|
Ucs4StringFormat, \
|
|
|
|
Array10Format, \
|
|
|
|
Array100Format, \
|
|
|
|
Array1000Format, \
|
2014-05-27 22:35:54 +02:00
|
|
|
Array10000Format, \
|
2015-03-20 16:03:59 +01:00
|
|
|
ArrayPlotFormat, \
|
|
|
|
CompactMapFormat, \
|
|
|
|
DirectQListStorageFormat, \
|
|
|
|
IndirectQListStorageFormat, \
|
|
|
|
= range(0, 20)
|
2014-04-15 18:13:03 +02:00
|
|
|
|
2015-02-13 10:02:35 +01:00
|
|
|
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
|
|
|
|
UnknownType, \
|
|
|
|
BreakpointByFileAndLine, \
|
|
|
|
BreakpointByFunction, \
|
|
|
|
BreakpointByAddress, \
|
|
|
|
BreakpointAtThrow, \
|
|
|
|
BreakpointAtCatch, \
|
|
|
|
BreakpointAtMain, \
|
|
|
|
BreakpointAtFork, \
|
|
|
|
BreakpointAtExec, \
|
|
|
|
BreakpointAtSysCall, \
|
|
|
|
WatchpointAtAddress, \
|
|
|
|
WatchpointAtExpression, \
|
|
|
|
BreakpointOnQmlSignalEmit, \
|
|
|
|
BreakpointAtJavaScriptThrow, \
|
|
|
|
= range(0, 14)
|
2015-01-21 15:18:57 +01:00
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
|
2016-10-06 13:36:02 +02:00
|
|
|
# Internal codes for types keep in sync with cdbextensions pytype.cpp
|
2016-09-19 12:05:16 +02:00
|
|
|
TypeCodeTypedef, \
|
|
|
|
TypeCodeStruct, \
|
|
|
|
TypeCodeVoid, \
|
|
|
|
TypeCodeIntegral, \
|
|
|
|
TypeCodeFloat, \
|
|
|
|
TypeCodeEnum, \
|
|
|
|
TypeCodePointer, \
|
|
|
|
TypeCodeArray, \
|
|
|
|
TypeCodeComplex, \
|
|
|
|
TypeCodeReference, \
|
|
|
|
TypeCodeFunction, \
|
|
|
|
TypeCodeMemberPointer, \
|
|
|
|
TypeCodeFortranString, \
|
|
|
|
= range(0, 13)
|
|
|
|
|
|
|
|
def isIntegralTypeName(name):
|
|
|
|
return name in ('int', 'unsigned int', 'signed int',
|
|
|
|
'short', 'unsigned short',
|
|
|
|
'long', 'unsigned long',
|
|
|
|
'long long', 'unsigned long long',
|
|
|
|
'char', 'signed char', 'unsigned char',
|
|
|
|
'bool')
|
|
|
|
|
|
|
|
def isFloatingPointTypeName(name):
|
|
|
|
return name in ('float', 'double')
|
|
|
|
|
|
|
|
|
2015-01-21 15:18:57 +01:00
|
|
|
def arrayForms():
|
2015-04-01 17:19:43 +02:00
|
|
|
return [ArrayPlotFormat]
|
2015-01-21 15:18:57 +01:00
|
|
|
|
|
|
|
def mapForms():
|
2015-03-20 16:03:59 +01:00
|
|
|
return [CompactMapFormat]
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
class ReportItem:
|
|
|
|
"""
|
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.
|
|
|
|
"""
|
2014-05-19 10:55:33 +02:00
|
|
|
def __init__(self, value = None, encoding = None, priority = -100, elided = None):
|
|
|
|
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
|
|
|
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def warn(message):
|
2016-10-07 11:49:51 +02:00
|
|
|
print('bridgemessage={msg="%s"},' % message.replace('"', '$').encode('latin1'))
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def error(message):
|
|
|
|
raise RuntimeError(message)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def showException(msg, exType, exValue, exTraceback):
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('**** CAUGHT EXCEPTION: %s ****' % msg)
|
2013-09-11 21:35:39 +02:00
|
|
|
try:
|
|
|
|
import traceback
|
|
|
|
for line in traceback.format_exception(exType, exValue, exTraceback):
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('%s' % line)
|
2013-09-11 21:35:39 +02:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class Children:
|
|
|
|
def __init__(self, d, numChild = 1, childType = None, childNumChild = None,
|
|
|
|
maxNumChild = None, addrBase = None, addrStep = None):
|
|
|
|
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:
|
2016-10-07 11:49:51 +02:00
|
|
|
showException('CHILDREN', exType, exValue, exTraceBack)
|
|
|
|
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:
|
|
|
|
self.d.put('{name="<incomplete>",value="",type="",numchild="0"},')
|
|
|
|
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:
|
|
|
|
self.output += '\n' + ' ' * self.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
|
|
|
|
|
2014-01-13 18:23:22 +01:00
|
|
|
class PairedChildrenData:
|
2016-09-26 14:29:16 +02:00
|
|
|
def __init__(self, d, pairType, keyType, valueType):
|
2014-01-13 18:23:22 +01:00
|
|
|
self.pairType = pairType
|
2014-01-15 14:56:27 +01:00
|
|
|
self.keyType = keyType
|
|
|
|
self.valueType = valueType
|
2014-01-13 18:23:22 +01:00
|
|
|
self.isCompact = d.isMapCompact(self.keyType, self.valueType)
|
2014-01-15 14:56:27 +01:00
|
|
|
self.childType = valueType if self.isCompact else pairType
|
2014-01-13 18:23:22 +01:00
|
|
|
|
2014-01-14 18:24:55 +01:00
|
|
|
class PairedChildren(Children):
|
2014-01-15 15:45:48 +01:00
|
|
|
def __init__(self, d, numChild, useKeyAndValue = False,
|
|
|
|
pairType = None, keyType = None, valueType = None, maxNumChild = None):
|
2014-01-13 18:23:22 +01:00
|
|
|
self.d = d
|
2014-01-15 14:56:27 +01:00
|
|
|
if keyType is None:
|
2016-09-06 08:54:43 +02:00
|
|
|
keyType = pairType[0].unqualified()
|
2014-01-15 14:56:27 +01:00
|
|
|
if valueType is None:
|
2016-09-06 08:54:43 +02:00
|
|
|
valueType = pairType[1]
|
2016-09-26 14:29:16 +02:00
|
|
|
d.pairData = PairedChildrenData(d, pairType, keyType, valueType)
|
2016-10-07 11:49:51 +02:00
|
|
|
d.pairData.kname = 'key' if useKeyAndValue else 'first'
|
|
|
|
d.pairData.vname = 'value' if useKeyAndValue else 'second'
|
2014-01-15 14:56:27 +01:00
|
|
|
|
2014-01-13 18:23:22 +01:00
|
|
|
Children.__init__(self, d, numChild,
|
2014-01-15 14:56:27 +01:00
|
|
|
d.pairData.childType,
|
|
|
|
maxNumChild = maxNumChild,
|
|
|
|
addrBase = None, addrStep = None)
|
2014-01-13 18:23:22 +01:00
|
|
|
|
|
|
|
def __enter__(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.savedPairData = self.d.pairData if hasattr(self.d, 'pairData') else None
|
2014-01-13 18:23:22 +01:00
|
|
|
Children.__enter__(self)
|
|
|
|
|
|
|
|
def __exit__(self, exType, exValue, exTraceBack):
|
|
|
|
Children.__exit__(self, exType, exValue, exTraceBack)
|
|
|
|
self.d.pairData = self.savedPairData if self.savedPairData else None
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
class SubItem:
|
|
|
|
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)
|
|
|
|
|
|
|
|
class TopLevelItem(SubItem):
|
|
|
|
def __init__(self, d, iname):
|
|
|
|
self.d = d
|
|
|
|
self.iname = iname
|
|
|
|
self.name = None
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
class DumperBase:
|
|
|
|
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
|
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
|
2013-10-30 15:07:54 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
self.typesReported = {}
|
|
|
|
self.typesToReport = {}
|
|
|
|
self.qtNamespaceToReport = None
|
2016-09-27 09:00:13 +02:00
|
|
|
self.passExceptions = False
|
2016-09-06 08:54:43 +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 = [
|
2016-10-07 11:49:51 +02:00
|
|
|
'qttypes',
|
|
|
|
'stdtypes',
|
|
|
|
'misctypes',
|
|
|
|
'boosttypes',
|
|
|
|
'opencvtypes',
|
|
|
|
'creatortypes',
|
|
|
|
'personaltypes',
|
2015-07-10 10:09:25 +02:00
|
|
|
]
|
|
|
|
|
2016-10-11 16:09:59 +02:00
|
|
|
self.currentQtNamespaceGuess = None
|
|
|
|
|
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
|
|
|
|
|
|
|
|
def setVariableFetchingOptions(self, args):
|
|
|
|
self.resultVarName = args.get('resultvarname', '')
|
|
|
|
self.expandedINames = set(args.get('expanded', []))
|
|
|
|
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'))
|
|
|
|
self.showQObjectNames = int(args.get('qobjectnames', '0'))
|
|
|
|
self.nativeMixed = int(args.get('nativemixed', '0'))
|
|
|
|
self.autoDerefPointers = int(args.get('autoderef', '0'))
|
|
|
|
self.partialVariable = args.get('partialvar', '')
|
|
|
|
self.partialUpdate = int(args.get('partial', '0'))
|
|
|
|
self.fallbackQtVersion = 0x50200
|
|
|
|
#warn('NAMESPACE: "%s"' % self.qtNamespace())
|
|
|
|
#warn('EXPANDED INAMES: %s' % self.expandedINames)
|
|
|
|
#warn('WATCHERS: %s' % self.watchers)
|
|
|
|
|
|
|
|
# The guess does not need to be updated during a fetchVariables()
|
|
|
|
# as the result is fixed during that time (ignoring "active"
|
|
|
|
# dumpers causing loading of shared objects etc).
|
|
|
|
self.currentQtNamespaceGuess = None
|
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'.
|
2016-10-07 11:49:51 +02:00
|
|
|
self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() }
|
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
|
|
|
|
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.pretimings = {}
|
|
|
|
self.timings = []
|
|
|
|
|
|
|
|
def resetStats(self):
|
|
|
|
# Timing collection
|
|
|
|
self.pretimings = {}
|
|
|
|
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
|
|
|
|
|
|
|
|
def preping(self, key):
|
|
|
|
import time
|
|
|
|
self.pretimings[key] = time.time()
|
|
|
|
|
|
|
|
def ping(self, key):
|
|
|
|
import time
|
|
|
|
elapsed = int(1000000 * (time.time() - self.pretimings[key]))
|
|
|
|
self.timings.append([key, elapsed])
|
2015-01-30 09:22:52 +01:00
|
|
|
|
2016-09-28 08:55:13 +02:00
|
|
|
def childRange(self):
|
|
|
|
if self.currentMaxNumChild is None:
|
|
|
|
return xrange(0, self.currentNumChild)
|
|
|
|
return xrange(min(self.currentMaxNumChild, self.currentNumChild))
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def enterSubItem(self, item):
|
|
|
|
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
|
|
|
|
self.output += '\n' + ' ' * self.indent
|
|
|
|
if isinstance(item.name, str):
|
|
|
|
self.output += item.name + ' = '
|
|
|
|
item.savedIName = self.currentIName
|
|
|
|
item.savedValue = self.currentValue
|
|
|
|
item.savedType = self.currentType
|
|
|
|
self.currentIName = item.iname
|
|
|
|
self.currentValue = ReportItem();
|
|
|
|
self.currentType = ReportItem();
|
|
|
|
|
|
|
|
|
|
|
|
def exitSubItem(self, item, exType, exValue, exTraceBack):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('CURRENT VALUE: %s: %s %s' %
|
2016-09-06 08:54:43 +02:00
|
|
|
# (self.currentIName, self.currentValue, self.currentType))
|
|
|
|
if not exType is None:
|
|
|
|
if self.passExceptions:
|
2016-10-07 11:49:51 +02:00
|
|
|
showException('SUBITEM', exType, exValue, exTraceBack)
|
|
|
|
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:
|
|
|
|
if not self.currentValue.encoding is None:
|
|
|
|
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
|
|
|
|
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)
|
|
|
|
|
|
|
|
if self.currentValue.value is None:
|
|
|
|
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':
|
2016-09-06 08:54:43 +02:00
|
|
|
b = bytes.fromhex(value)
|
|
|
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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
|
|
|
|
stripped += c
|
|
|
|
self.cachedFormats[typeName] = stripped
|
|
|
|
return stripped
|
|
|
|
|
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
|
|
|
|
|
2014-01-24 15:13:20 +01:00
|
|
|
# Hex decoding operating on str, return str.
|
2014-01-23 15:30:51 +01:00
|
|
|
def hexdecode(self, s):
|
|
|
|
if sys.version_info[0] == 2:
|
2016-10-07 11:49:51 +02:00
|
|
|
return s.decode('hex')
|
|
|
|
return bytes.fromhex(s).decode('utf8')
|
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.
|
2014-01-23 15:30:51 +01:00
|
|
|
def hexencode(self, s):
|
2016-04-05 15:32:50 +02:00
|
|
|
if s is None:
|
|
|
|
s = ''
|
2014-01-23 15:30:51 +01:00
|
|
|
if sys.version_info[0] == 2:
|
2016-09-06 08:54:43 +02:00
|
|
|
if isinstance(s, buffer):
|
2016-10-07 11:49:51 +02:00
|
|
|
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')
|
|
|
|
return base64.b16encode(s).decode('utf8')
|
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
|
|
|
|
2014-04-03 22:08:35 +02:00
|
|
|
def vectorDataHelper(self, addr):
|
|
|
|
if self.qtVersion() >= 0x050000:
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.ptrSize() == 4:
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, size, alloc, offset) = self.split('IIIp', addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, size, alloc, pad, offset) = self.split('IIIIp', addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
alloc = alloc & 0x7ffffff
|
|
|
|
data = addr + offset
|
2014-04-03 22:08:35 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, alloc, size) = self.split('III', addr)
|
2014-04-03 22:08:35 +02:00
|
|
|
data = addr + 16
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
|
2014-04-03 22:08:35 +02:00
|
|
|
return data, size, alloc
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def byteArrayDataHelper(self, addr):
|
|
|
|
if self.qtVersion() >= 0x050000:
|
|
|
|
# QTypedArray:
|
|
|
|
# - QtPrivate::RefCount ref
|
|
|
|
# - int size
|
|
|
|
# - uint alloc : 31, capacityReserved : 1
|
|
|
|
# - qptrdiff offset
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, size, alloc, offset) = self.split('IIpp', addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
alloc = alloc & 0x7ffffff
|
|
|
|
data = addr + 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:
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, alloc, size, data) = self.split('IIIp', addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
(ref, alloc, size, pad, data) = self.split('IIIIp', addr)
|
2014-10-10 12:05:47 +02:00
|
|
|
else:
|
|
|
|
# Data:
|
|
|
|
# - QShared count;
|
|
|
|
# - QChar *unicode
|
|
|
|
# - char *ascii
|
|
|
|
# - uint len: 30
|
2016-10-07 11:49:51 +02:00
|
|
|
(dummy, dummy, dummy, size) = self.split('IIIp', addr)
|
2014-10-10 12:05:47 +02:00
|
|
|
size = self.extractInt(addr + 3 * self.ptrSize()) & 0x3ffffff
|
|
|
|
alloc = size # pretend.
|
|
|
|
data = self.extractPointer(addr + self.ptrSize())
|
2013-09-11 21:35:39 +02:00
|
|
|
return data, size, alloc
|
|
|
|
|
|
|
|
# addr is the begin of a QByteArrayData structure
|
2014-05-16 00:18:17 +02:00
|
|
|
def encodeStringHelper(self, addr, limit):
|
2013-09-11 21:35:39 +02:00
|
|
|
# Should not happen, but we get it with LLDB as result
|
|
|
|
# of inferior calls
|
|
|
|
if addr == 0:
|
2016-10-07 11:49:51 +02:00
|
|
|
return 0, ''
|
2013-09-11 21:35:39 +02:00
|
|
|
data, size, alloc = self.byteArrayDataHelper(addr)
|
|
|
|
if alloc != 0:
|
|
|
|
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, 2 * shown)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
def encodeByteArrayHelper(self, addr, limit):
|
2013-09-11 21:35:39 +02:00
|
|
|
data, size, alloc = self.byteArrayDataHelper(addr)
|
|
|
|
if alloc != 0:
|
|
|
|
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
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def putCharArrayHelper(self, data, size, charType,
|
2015-11-05 15:10:20 +01:00
|
|
|
displayFormat = AutomaticFormat,
|
|
|
|
makeExpandable = True):
|
2016-09-06 08:54:43 +02:00
|
|
|
charSize = charType.size()
|
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:
|
2016-09-06 08:54:43 +02:00
|
|
|
if displayFormat in (Latin1StringFormat, SeparateLatin1StringFormat):
|
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)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
if displayFormat in (SeparateLatin1StringFormat, SeparateUtf8StringFormat, SeparateFormat):
|
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
|
|
|
|
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
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
def encodeByteArray(self, value, limit = 0):
|
2014-05-16 00:18:17 +02:00
|
|
|
elided, data = self.encodeByteArrayHelper(self.extractPointer(value), limit)
|
|
|
|
return data
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def byteArrayData(self, value):
|
2014-01-28 13:20:05 +01:00
|
|
|
return self.byteArrayDataHelper(self.extractPointer(value))
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-05-19 10:55:33 +02:00
|
|
|
def putByteArrayValue(self, value):
|
|
|
|
elided, data = self.encodeByteArrayHelper(self.extractPointer(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
|
|
|
|
2014-05-16 00:18:17 +02:00
|
|
|
def encodeString(self, value, limit = 0):
|
2014-05-16 00:18:17 +02:00
|
|
|
elided, data = self.encodeStringHelper(self.extractPointer(value), limit)
|
|
|
|
return data
|
2013-09-11 21:35:39 +02:00
|
|
|
|
2014-12-12 08:19:06 +01:00
|
|
|
def encodedUtf16ToUtf8(self, s):
|
|
|
|
return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 4)])
|
|
|
|
|
|
|
|
def encodeStringUtf8(self, value, limit = 0):
|
|
|
|
return self.encodedUtf16ToUtf8(self.encodeString(value, limit))
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def stringData(self, value):
|
2014-01-28 13:20:05 +01:00
|
|
|
return self.byteArrayDataHelper(self.extractPointer(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 = ''
|
|
|
|
for c in typename[typename.find('<') + 1 : -1]:
|
|
|
|
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:
|
|
|
|
inner = inner[p+3:]
|
|
|
|
return inner
|
2013-10-28 11:35:45 +01:00
|
|
|
|
2014-05-19 10:55:33 +02:00
|
|
|
def putStringValueByAddress(self, addr):
|
|
|
|
elided, data = self.encodeStringHelper(addr, self.displayStringLimit)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'utf16', elided=elided)
|
2014-05-19 10:55:33 +02:00
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def putStringValue(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
addr = self.extractPointer(value)
|
|
|
|
elided, data = self.encodeStringHelper(addr, 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
|
|
|
self.putNumChild(0)
|
|
|
|
|
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
|
|
|
self.putNumChild(0)
|
|
|
|
|
|
|
|
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
|
|
|
self.putNumChild(0)
|
|
|
|
|
2016-09-21 16:54:30 +02:00
|
|
|
def putPairItem(self, index, pair):
|
2016-09-26 14:29:16 +02:00
|
|
|
(first, second) = pair if isinstance(pair, tuple) else pair.members()
|
2016-09-21 16:54:30 +02:00
|
|
|
with SubItem(self, index):
|
|
|
|
with Children(self):
|
2016-09-27 18:10:13 +02:00
|
|
|
key = self.putSubItem(self.pairData.kname, first)
|
|
|
|
value = self.putSubItem(self.pairData.vname, second)
|
2016-09-21 16:54:30 +02:00
|
|
|
if index is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('keyprefix', '[%s] ' % index)
|
|
|
|
self.putField('key', key.value)
|
2016-09-27 18:10:13 +02:00
|
|
|
if key.encoding is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('keyencoded', key.encoding)
|
2016-09-27 18:10:13 +02:00
|
|
|
self.putValue(value.value, value.encoding)
|
2013-11-01 12:49:14 +01:00
|
|
|
|
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
|
|
|
|
2014-03-20 15:16:56 +01:00
|
|
|
def putPlainChildren(self, value, dumpBase = True):
|
|
|
|
self.putEmptyValue(-99)
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(value, dumpBase)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def putNamedChildren(self, values, names):
|
|
|
|
self.putEmptyValue(-99)
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
for n, v in zip(names, values):
|
|
|
|
self.putSubItem(n, v)
|
|
|
|
|
|
|
|
def putFields(self, value, dumpBase = True):
|
|
|
|
for field in value.type.fields():
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELD: %s' % field)
|
|
|
|
if field.name is not None and field.name.startswith('_vptr.'):
|
|
|
|
with SubItem(self, '[vptr]'):
|
2016-09-06 08:54:43 +02:00
|
|
|
# int (**)(void)
|
|
|
|
n = 100
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType(' ')
|
|
|
|
self.putField('sortgroup', 20)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putValue(field.name)
|
|
|
|
self.putNumChild(n)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
p = value[field.name]
|
|
|
|
for i in xrange(n):
|
|
|
|
if p.dereference().integer() != 0:
|
|
|
|
with SubItem(self, i):
|
|
|
|
self.putItem(p.dereference())
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putType(' ')
|
2016-09-06 08:54:43 +02:00
|
|
|
p = p + 1
|
|
|
|
continue
|
|
|
|
|
|
|
|
if field.isBaseClass and dumpBase:
|
|
|
|
# We cannot use nativeField.name as part of the iname as
|
|
|
|
# it might contain spaces and other strange characters.
|
|
|
|
with UnnamedSubItem(self, "@%d" % (field.baseIndex + 1)):
|
|
|
|
baseValue = value[field]
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('iname', self.currentIName)
|
|
|
|
self.putField('name', '[%s]' % field.name)
|
|
|
|
self.putField('sortgroup', 1000 - field.baseIndex)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putAddress(baseValue.address())
|
2016-09-26 14:29:16 +02:00
|
|
|
self.putItem(baseValue)
|
2016-09-06 08:54:43 +02:00
|
|
|
continue
|
|
|
|
|
2016-09-14 16:43:35 +02:00
|
|
|
with SubItem(self, field.name):
|
2016-10-06 00:59:11 +02:00
|
|
|
self.putItem(value.extractField(field))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
|
2016-07-14 13:13:16 +02:00
|
|
|
def putMembersItem(self, value, sortorder = 10):
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[members]'):
|
|
|
|
self.putField('sortgroup', sortorder)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putPlainChildren(value)
|
|
|
|
|
2013-09-11 21:35:39 +02:00
|
|
|
def isMapCompact(self, keyType, valueType):
|
2015-03-20 16:03:59 +01:00
|
|
|
if self.currentItemFormat() == CompactMapFormat:
|
|
|
|
return True
|
2016-09-06 08:54:43 +02:00
|
|
|
return keyType.isSimpleType() and valueType.isSimpleType()
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
def check(self, exp):
|
|
|
|
if not exp:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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):
|
|
|
|
if not self.isInt(thing):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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-10-07 11:49:51 +02:00
|
|
|
code = (None, 'b', 'H', None, 'I')[tsize]
|
2016-09-06 08:54:43 +02:00
|
|
|
#blob = self.readRawMemory(base, maximum)
|
|
|
|
|
|
|
|
blob = bytes()
|
|
|
|
while maximum > 1:
|
|
|
|
try:
|
|
|
|
blob = self.readRawMemory(base, maximum)
|
|
|
|
break
|
|
|
|
except:
|
|
|
|
maximum = int(maximum / 2)
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('REDUCING READING MAXIMUM TO %s' % maximum)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, tsize, maximum))
|
2015-08-10 11:50:18 +02:00
|
|
|
for i in xrange(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
|
|
|
|
2013-11-01 12:49:14 +01:00
|
|
|
def putItemCount(self, count, maximum = 1000000000):
|
|
|
|
# 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):
|
2015-10-08 16:19:57 +02:00
|
|
|
if type(value) is bool:
|
|
|
|
return '"%d"' % int(value)
|
|
|
|
if type(value) is dict:
|
2015-10-14 13:26:22 +02:00
|
|
|
return '{' + ','.join(['%s=%s' % (k, self.resultToMi(v))
|
2015-10-08 16:19:57 +02:00
|
|
|
for (k, v) in list(value.items())]) + '}'
|
2015-10-14 13:26:22 +02:00
|
|
|
if type(value) is list:
|
|
|
|
return '[' + ','.join([self.resultToMi(k)
|
|
|
|
for k in list(value.items())]) + ']'
|
|
|
|
return '"%s"' % value
|
|
|
|
|
|
|
|
def variablesToMi(self, value, prefix):
|
|
|
|
if type(value) is bool:
|
|
|
|
return '"%d"' % int(value)
|
|
|
|
if type(value) is dict:
|
|
|
|
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) + '}'
|
2015-10-08 16:19:57 +02:00
|
|
|
if type(value) is 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)))
|
2015-10-09 15:00:20 +02:00
|
|
|
pairs.sort(key = lambda pair: pair[0])
|
|
|
|
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', {}):
|
|
|
|
if not 'iname' in item:
|
|
|
|
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))
|
|
|
|
|
2016-09-15 17:55:56 +02: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:
|
2016-09-15 17:55:56 +02:00
|
|
|
if isinstance(typish, str):
|
|
|
|
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
|
|
|
|
2014-05-16 00:18:17 +02: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
|
|
|
|
2016-10-07 11:49:51 +02: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:
|
|
|
|
self.putNumChild(1)
|
|
|
|
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
|
|
|
|
2013-11-07 13:04:09 +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):
|
|
|
|
self.currentType.value = typish
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
#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),
|
2016-09-06 08:54:43 +02:00
|
|
|
typeName.split('::')))
|
|
|
|
|
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:
|
2016-10-07 11:49:51 +02: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.
|
|
|
|
s = value.type.name
|
2016-01-11 15:26:07 +02:00
|
|
|
itemCount = s[s.find('[')+1:s.find(']')]
|
|
|
|
if not itemCount:
|
|
|
|
itemCount = '100'
|
2016-09-06 08:54:43 +02:00
|
|
|
arrayByteSize = int(itemCount) * innerType.size();
|
2015-07-22 11:16:20 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
n = int(arrayByteSize / innerType.size())
|
|
|
|
p = value.address()
|
2015-08-12 09:05:28 +02:00
|
|
|
if displayFormat != RawFormat and p:
|
2016-10-07 11:49:51 +02:00
|
|
|
if innerType.name in ('char', 'wchar_t'):
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(),
|
2015-11-05 15:10:20 +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,
|
2015-07-22 11:16:20 +02: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>'
|
|
|
|
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):]
|
2016-10-07 11:49:51 +02:00
|
|
|
pos = typeName.find('<')
|
2016-09-06 08:54:43 +02:00
|
|
|
# FIXME: make it recognize foo<A>::bar<B>::iterator?
|
|
|
|
while pos != -1:
|
2016-10-07 11:49:51 +02:00
|
|
|
pos1 = typeName.rfind('>', pos)
|
2016-09-30 13:56:46 +02:00
|
|
|
typeName = typeName[0:pos] + typeName[pos1+1:]
|
2016-10-07 11:49:51 +02:00
|
|
|
pos = typeName.find('<')
|
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()
|
2015-03-20 16:03:59 +01:00
|
|
|
if self.useFancy and self.currentItemFormat() != RawFormat:
|
|
|
|
self.putType(typeName)
|
|
|
|
|
|
|
|
nsStrippedType = self.stripNamespaceFromType(typeName)\
|
2016-10-07 11:49:51 +02:00
|
|
|
.replace('::', '__')
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#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)
|
2016-10-07 11:49:51 +02:00
|
|
|
#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
|
|
|
|
|
2014-09-01 23:35:11 +02:00
|
|
|
def putSimpleCharArray(self, base, size = None):
|
|
|
|
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):
|
2016-04-08 17:00:13 +02:00
|
|
|
if displayFormat == AutomaticFormat:
|
2016-10-07 11:49:51 +02:00
|
|
|
if innerType.name == '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
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
if innerType.name == 'wchar_t':
|
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
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == Latin1StringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == SeparateLatin1StringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == Utf8StringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == SeparateUtf8StringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == Local8BitStringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == Utf16StringFormat:
|
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
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == Ucs4StringFormat:
|
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):
|
2016-09-06 08:54:43 +02:00
|
|
|
pointer = value.pointer()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('POINTER: %s' % pointer)
|
2016-09-06 08:54:43 +02:00
|
|
|
if pointer == 0:
|
2016-10-07 11:49:51 +02:00
|
|
|
#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')
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putNumChild(0)
|
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
|
|
|
self.putAddress(pointer)
|
2016-03-20 13:01:27 +02:00
|
|
|
self.putOriginalAddress(value)
|
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.
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('BAD POINTER: %s' % value)
|
|
|
|
self.putValue('0x%x' % pointer)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
|
|
|
self.putNumChild(0)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
displayFormat = self.currentItemFormat(value.type.name)
|
2015-04-30 15:52:33 +02: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':
|
|
|
|
#warn('VOID POINTER: %s' % displayFormat)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % pointer)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putNumChild(0)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if displayFormat == RawFormat:
|
2013-11-06 17:57:12 +01:00
|
|
|
# Explicitly requested bald pointer.
|
2016-10-07 11:49:51 +02:00
|
|
|
#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)
|
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
|
2016-09-06 08:54:43 +02:00
|
|
|
if displayFormat in (SeparateLatin1StringFormat, SeparateUtf8StringFormat):
|
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):
|
|
|
|
self.putNumChild(1)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
if Array10Format <= displayFormat and displayFormat <= Array1000Format:
|
|
|
|
n = (10, 100, 1000, 10000)[displayFormat - Array10Format]
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2013-11-22 01:21:57 +01:00
|
|
|
self.putItemCount(n)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putArrayData(value.address(), n, innerType)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if innerType.code == TypeCodeFunction:
|
2013-11-06 17:57:12 +01:00
|
|
|
# A function pointer.
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % pointer)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeName)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('AUTODEREF: %s' % self.autoDerefPointers)
|
|
|
|
#warn('INAME: %s' % self.currentIName)
|
|
|
|
#warn('INNER: %s' % innerType.name)
|
2013-11-06 17:57:12 +01:00
|
|
|
if self.autoDerefPointers or self.currentIName.endswith('.this'):
|
2015-03-20 16:03:59 +01:00
|
|
|
# Generic pointer type with AutomaticFormat.
|
2013-11-06 17:57:12 +01:00
|
|
|
# Never dereference char types.
|
2016-10-07 11:49:51 +02:00
|
|
|
if innerType.name not in ('char', 'signed char', 'unsigned char', 'wchar_t'):
|
2016-09-29 00:04:04 +02:00
|
|
|
self.putType(innerType)
|
2013-11-06 17:57:12 +01:00
|
|
|
savedCurrentChildType = self.currentChildType
|
2016-09-30 13:56:46 +02:00
|
|
|
self.currentChildType = innerType.name
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putItem(value.dereference())
|
|
|
|
self.currentChildType = savedCurrentChildType
|
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.putOriginalAddress(value)
|
2014-01-25 15:32:10 +01:00
|
|
|
return
|
2013-11-06 17:57:12 +01:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GENERIC PLAIN POINTER: %s' % value.type)
|
|
|
|
#warn('ADDR PLAIN POINTER: 0x%x' % value.address)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putType(typeName)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue('0x%x' % pointer)
|
2013-11-06 17:57:12 +01:00
|
|
|
self.putNumChild(1)
|
|
|
|
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())
|
|
|
|
|
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
|
|
|
def putOriginalAddress(self, value):
|
2016-09-06 08:54:43 +02:00
|
|
|
if value.address() is not None:
|
|
|
|
self.put('origaddr="0x%x",' % value.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-09-06 08:54:43 +02:00
|
|
|
intSize = 4
|
2013-09-11 21:35:39 +02:00
|
|
|
ptrSize = self.ptrSize()
|
2016-10-07 11:49:51 +02:00
|
|
|
# dd = value['d_ptr']['d'] is just behind the vtable.
|
|
|
|
(vtable, dd) = self.split('pp', value)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
if self.qtVersion() < 0x050000:
|
|
|
|
# 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
|
2014-01-30 16:15:22 +01:00
|
|
|
objectName = self.extractPointer(dd + 5 * ptrSize + 2 * intSize)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
else:
|
|
|
|
# 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
|
2014-01-30 16:15:22 +01:00
|
|
|
objectName = self.extractPointer(extra + 5 * ptrSize)
|
2013-09-11 21:35:39 +02:00
|
|
|
|
|
|
|
data, size, alloc = self.byteArrayDataHelper(objectName)
|
|
|
|
|
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:
|
2016-10-07 11:49:51 +02:00
|
|
|
# warn('NO QOBJECT: %s' % value.type)
|
2013-09-11 21:35:39 +02:00
|
|
|
pass
|
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
def canBePointer(self, p):
|
|
|
|
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-09-26 14:29:16 +02:00
|
|
|
def couldBeQObject(self, objectPtr):
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
|
|
|
(vtablePtr, dd) = self.split('pp', objectPtr)
|
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('nostruct-1')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-09-26 14:29:16 +02:00
|
|
|
if not self.canBePointer(vtablePtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('vtable')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-09-26 14:29:16 +02:00
|
|
|
if not self.canBePointer(dd):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('d_d_ptr')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2014-03-19 16:08:45 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
try:
|
|
|
|
(dvtablePtr, qptr, parentPtr, childrenDPtr, flags) \
|
|
|
|
= self.split('ppppI', dd)
|
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('nostruct-2')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('STRUCT DD: %s 0x%x' % (self.currentIName, qptr))
|
2016-09-26 14:29:16 +02:00
|
|
|
if not self.canBePointer(dvtablePtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('dvtable')
|
|
|
|
#warn('DVT: 0x%x' % dvtablePtr)
|
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
|
|
|
#warn('QPTR: 0x%x 0x%x' % (qptr, objectPtr))
|
|
|
|
self.bump('q_ptr')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-09-26 14:29:16 +02:00
|
|
|
if parentPtr and not self.canBePointer(parentPtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('PAREN')
|
|
|
|
self.bump('parent')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
2016-09-26 14:29:16 +02:00
|
|
|
if not self.canBePointer(childrenDPtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('CHILD')
|
|
|
|
self.bump('children')
|
2016-09-06 08:54:43 +02:00
|
|
|
return False
|
|
|
|
#if flags >= 0x80: # Only 7 flags are defined
|
2016-10-07 11:49:51 +02:00
|
|
|
# warn('FLAGS: 0x%x %s' % (flags, self.currentIName))
|
|
|
|
# self.bump('flags')
|
2016-09-06 08:54:43 +02:00
|
|
|
# return False
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('OK')
|
2016-09-26 14:29:16 +02:00
|
|
|
#if dynMetaObjectPtr and not self.canBePointer(dynMetaObjectPtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
# self.bump('dynmo')
|
2016-09-06 08:54:43 +02:00
|
|
|
# return False
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('couldBeQObject')
|
2016-09-06 08:54:43 +02:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
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-08-01 12:22:26 +02: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:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('MO CMD: %s' % cmd)
|
2016-07-22 10:20:01 +02:00
|
|
|
res = self.parseAndEvaluate(cmd)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('MO RES: %s' % res)
|
|
|
|
self.bump('successfulMetaObjectCall')
|
2016-07-22 10:20:01 +02:00
|
|
|
return toInteger(res)
|
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('failedMetaObjectCall')
|
|
|
|
#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
|
|
|
|
|
|
|
if not isQObjectProper:
|
2016-09-06 08:54:43 +02:00
|
|
|
if someTypeObj.firstBase() is None:
|
2016-07-22 10:20:01 +02:00
|
|
|
return 0
|
|
|
|
|
|
|
|
# No templates for now.
|
|
|
|
if typeName.find('<') >= 0:
|
|
|
|
return 0
|
2014-03-12 13:20:21 +01:00
|
|
|
|
2016-07-22 10:20:01 +02:00
|
|
|
result = self.findStaticMetaObject(typeName)
|
|
|
|
|
|
|
|
# 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:
|
|
|
|
superdata = self.extractPointer(result)
|
|
|
|
if superdata == 0:
|
|
|
|
# This looks like a Q_GADGET
|
|
|
|
return 0
|
|
|
|
|
|
|
|
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)
|
|
|
|
if known is not None: # Is 0 or the static metaobject.
|
|
|
|
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
|
|
|
|
|
|
|
if not result:
|
2016-09-06 08:54:43 +02:00
|
|
|
base = someTypeObj.firstBase()
|
|
|
|
if base is not None and base != someTypeObj: # sanity check
|
2016-07-22 10:20:01 +02:00
|
|
|
result = extractStaticMetaObjectPtrFromType(base)
|
|
|
|
|
|
|
|
self.knownStaticMetaObjects[someTypeName] = result
|
|
|
|
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)
|
|
|
|
if result is not None: # Is 0 or the static metaobject.
|
2016-10-07 11:49:51 +02:00
|
|
|
self.bump('typecached')
|
|
|
|
#warn('CACHED RESULT: %s %s 0x%x' % (self.currentIName, typeName, result))
|
2014-03-12 13:20:21 +01:00
|
|
|
return result
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
if not self.couldBeQObject(objectPtr):
|
2016-07-22 10:20:01 +02:00
|
|
|
self.bump('cannotBeQObject')
|
2016-10-07 11:49:51 +02:00
|
|
|
#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)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.preping('metaObjectType-' + self.currentIName)
|
2016-07-22 10:20:01 +02:00
|
|
|
metaObjectPtr = extractStaticMetaObjectPtrFromType(typeobj)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.ping('metaObjectType-' + self.currentIName)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
if not metaObjectPtr:
|
|
|
|
# measured: 200 ms (example had one level of inheritance)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.preping('metaObjectCall-' + self.currentIName)
|
2016-07-22 10:20:01 +02:00
|
|
|
metaObjectPtr = extractMetaObjectPtrFromAddress()
|
2016-10-07 11:49:51 +02:00
|
|
|
self.ping('metaObjectCall-' + self.currentIName)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
#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)
|
|
|
|
if self.isInt(value):
|
|
|
|
val = self.Value(self)
|
|
|
|
val.laddress = value
|
|
|
|
return val.split(pattern)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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
|
|
|
|
|
2015-11-09 13:23:20 +01:00
|
|
|
def listChildrenGenerator(self, addr, innerType):
|
2014-04-03 17:44:48 +02:00
|
|
|
base = self.extractPointer(addr)
|
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
|
2014-03-20 12:38:56 +01:00
|
|
|
stepSize = self.ptrSize()
|
2016-09-06 08:54:43 +02:00
|
|
|
data = array + begin * stepSize
|
2014-03-20 12:38:56 +01:00
|
|
|
for i in range(size):
|
2016-09-06 08:54:43 +02:00
|
|
|
yield self.createValue(data + i * stepSize, innerType)
|
2016-10-07 11:49:51 +02:00
|
|
|
#yield self.createValue(data + i * stepSize, 'void*')
|
2014-02-07 23:00:26 +01:00
|
|
|
|
2015-11-09 13:23:20 +01:00
|
|
|
def vectorChildrenGenerator(self, addr, innerType):
|
|
|
|
base = self.extractPointer(addr)
|
2016-10-04 12:48:43 +02:00
|
|
|
data, size, alloc = self.vectorDataHelper(base)
|
2015-11-09 13:23:20 +01:00
|
|
|
for i in range(size):
|
2016-10-04 12:48:43 +02:00
|
|
|
yield self.createValue(data + i * innerType.size(), innerType)
|
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)
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
self.putFields(self.createValue(addr, typeObj))
|
|
|
|
else:
|
|
|
|
self.putType(typeName)
|
|
|
|
self.putNumChild(0)
|
|
|
|
|
2014-01-20 15:03:27 +01:00
|
|
|
# This is called is when a QObject derived class is expanded
|
2016-07-22 10:20:01 +02:00
|
|
|
def putQObjectGuts(self, qobject, metaObjectPtr):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putQObjectGutsHelper(qobject, qobject.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()
|
|
|
|
stringdata = self.extractPointer(toInteger(metaObjectPtr) + ptrSize)
|
2016-07-14 13:13:16 +02:00
|
|
|
if revision >= 7: # Qt 5.
|
2016-07-22 10:20:01 +02:00
|
|
|
byteArrayDataSize = 24 if ptrSize == 8 else 16
|
|
|
|
literal = stringdata + toInteger(index) * byteArrayDataSize
|
2016-07-14 13:13:16 +02:00
|
|
|
ldata, lsize, lalloc = self.byteArrayDataHelper(literal)
|
|
|
|
try:
|
2016-10-07 11:49:51 +02:00
|
|
|
s = struct.unpack_from('%ds' % lsize, self.readRawMemory(ldata, lsize))[0]
|
|
|
|
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>'
|
2016-07-14 13:13:16 +02:00
|
|
|
else: # Qt 4.
|
2016-07-22 10:20:01 +02:00
|
|
|
ldata = stringdata + index
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.extractCString(ldata).decode('utf8')
|
2016-07-13 14:17:18 +02:00
|
|
|
|
2016-07-14 13:13:16 +02:00
|
|
|
def putQMetaStuff(self, value, origType):
|
2016-09-06 08:54:43 +02:00
|
|
|
(metaObjectPtr, handle) = value.split('pI')
|
|
|
|
if metaObjectPtr != 0:
|
|
|
|
dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
|
|
|
|
index = self.extractInt(dataPtr + 4 * handle)
|
|
|
|
revision = 7 if self.qtVersion() >= 0x050000 else 6
|
|
|
|
name = self.metaString(metaObjectPtr, index, revision)
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putValue(name)
|
|
|
|
self.putNumChild(1)
|
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-09-06 08:54:43 +02:00
|
|
|
intSize = 4
|
2016-07-13 14:17:18 +02:00
|
|
|
ptrSize = self.ptrSize()
|
|
|
|
|
2016-07-14 13:13:16 +02: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
|
|
|
self.putNumChild(0)
|
|
|
|
|
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']
|
2016-07-22 10:20:01 +02:00
|
|
|
return self.extractPointer(someMetaObjectPtr + 2 * 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
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('OBJECT GUTS: %s 0x%x ' % (self.currentIName, metaObjectPtr))
|
2016-07-22 10:20:01 +02:00
|
|
|
dataPtr = extractDataPtr(metaObjectPtr)
|
2016-10-07 11:49:51 +02:00
|
|
|
#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)
|
2016-08-01 12:32:38 +02:00
|
|
|
if self.qtVersion() >= 0x50000:
|
2016-09-06 08:54:43 +02:00
|
|
|
(dvtablePtr, qptr, parentPtr, childrenDPtr, flags, postedEvents,
|
|
|
|
dynMetaObjectPtr, # Up to here QObjectData.
|
|
|
|
extraData, threadDataPtr, connectionListsPtr,
|
|
|
|
sendersPtr, currentSenderPtr) \
|
|
|
|
= self.split('ppppIIp' + 'ppppp', dd)
|
2016-08-01 12:32:38 +02:00
|
|
|
else:
|
2016-09-06 08:54:43 +02:00
|
|
|
(dvtablePtr, qptr, parentPtr, childrenDPtr, flags, postedEvents,
|
|
|
|
dynMetaObjectPtr, # Up to here QObjectData
|
|
|
|
objectName, extraData, threadDataPtr, connectionListsPtr,
|
|
|
|
sendersPtr, currentSenderPtr) \
|
|
|
|
= self.split('ppppIIp' + 'pppppp', dd)
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
if qobjectPtr:
|
2016-10-07 13:08:49 +02:00
|
|
|
qobjectType = self.createType('QObject')
|
|
|
|
qobjectPtrType = self.createType('QObject') # FIXME.
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[parent]'):
|
|
|
|
self.putField('sortgroup', 9)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putItem(self.createValue(dd + 2 * ptrSize, qobjectPtrType))
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[children]'):
|
|
|
|
self.putField('sortgroup', 8)
|
2016-07-22 10:20:01 +02:00
|
|
|
base = self.extractPointer(dd + 3 * ptrSize) # It's a QList<QObject *>
|
|
|
|
begin = self.extractInt(base + 8)
|
|
|
|
end = self.extractInt(base + 12)
|
|
|
|
array = base + 16
|
|
|
|
if self.qtVersion() < 0x50000:
|
|
|
|
array += ptrSize
|
|
|
|
self.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
|
|
|
|
size = end - begin
|
|
|
|
self.check(size >= 0)
|
|
|
|
self.putItemCount(size)
|
2016-07-14 13:13:16 +02:00
|
|
|
if self.isExpanded():
|
2016-07-22 10:20:01 +02:00
|
|
|
addrBase = array + begin * ptrSize
|
|
|
|
with Children(self, size):
|
2016-07-14 13:13:16 +02:00
|
|
|
for i in self.childRange():
|
|
|
|
with SubItem(self, i):
|
2016-07-22 10:20:01 +02:00
|
|
|
childPtr = self.extractPointer(addrBase + i * ptrSize)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putItem(self.createValue(childPtr, qobjectType))
|
2016-07-22 10:20:01 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[strings]'):
|
|
|
|
self.putField('sortgroup', 2)
|
2016-07-22 10:20:01 +02:00
|
|
|
if largestStringIndex > 0:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', largestStringIndex)
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putNumChild(1)
|
|
|
|
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
|
|
|
self.putNumChild(0)
|
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(' ')
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putNumChild(0)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[raw]'):
|
|
|
|
self.putField('sortgroup', 1)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putEmptyValue()
|
|
|
|
self.putNumChild(1)
|
|
|
|
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]'):
|
|
|
|
self.putField('sortgroup', 1)
|
2016-08-01 12:32:38 +02:00
|
|
|
self.putEmptyValue()
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
|
|
|
if extraData:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putTypedPointer('[extraData]', extraData,
|
|
|
|
ns + 'QObjectPrivate::ExtraData')
|
2016-08-01 12:32:38 +02:00
|
|
|
|
|
|
|
if connectionListsPtr:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putTypedPointer('[connectionLists]', connectionListsPtr,
|
|
|
|
ns + 'QObjectConnectionListVector')
|
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)
|
|
|
|
self.putNumChild(1)
|
|
|
|
if self.isExpanded():
|
|
|
|
with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putQObjectGutsHelper(0, 0, -1, metaObjectPtr, 'QMetaObject')
|
2016-08-01 12:32:38 +02:00
|
|
|
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject or isQObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[properties]'):
|
|
|
|
self.putField('sortgroup', 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):
|
2016-10-07 11:49:51 +02:00
|
|
|
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-07-14 13:13:16 +02:00
|
|
|
if qobject:
|
2016-09-06 08:54:43 +02:00
|
|
|
# LLDB doesn't like calling it on a derived class, possibly
|
|
|
|
# due to type information living in a different shared object.
|
2016-10-07 13:08:49 +02:00
|
|
|
base = self.createValue(qobjectPtr, '@QObject')
|
|
|
|
self.putCallItem(name, '@QVariant', base, 'property', '"' + name + '"')
|
2016-07-14 13:13:16 +02:00
|
|
|
else:
|
|
|
|
putt(name, ' ')
|
2016-07-13 14:17:18 +02:00
|
|
|
|
|
|
|
# Dynamic properties.
|
|
|
|
if extraData:
|
2016-10-07 11:49:51 +02:00
|
|
|
byteArrayType = self.createType('QByteArray')
|
|
|
|
variantType = self.createType('QVariant')
|
2016-09-30 15:44:04 +02:00
|
|
|
if self.qtVersion() >= 0x50600:
|
2016-09-06 08:54:43 +02:00
|
|
|
values = self.vectorChildrenGenerator(
|
|
|
|
extraData + 2 * ptrSize, variantType)
|
|
|
|
elif self.qtVersion() >= 0x50000:
|
|
|
|
values = self.listChildrenGenerator(
|
|
|
|
extraData + 2 * ptrSize, variantType)
|
2016-07-13 14:17:18 +02:00
|
|
|
else:
|
2016-09-06 08:54:43 +02:00
|
|
|
values = self.listChildrenGenerator(
|
|
|
|
extraData + 2 * ptrSize, variantType.pointer())
|
|
|
|
names = self.listChildrenGenerator(
|
|
|
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
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)
|
2016-07-22 10:20:01 +02:00
|
|
|
self.putNumChild(1)
|
|
|
|
|
|
|
|
superDataPtr = extractSuperDataPtr(metaObjectPtr)
|
|
|
|
|
|
|
|
globalOffset = 0
|
|
|
|
superDataIterator = superDataPtr
|
|
|
|
while superDataIterator:
|
|
|
|
sdata = extractDataPtr(superDataIterator)
|
|
|
|
globalOffset += self.extractInt(sdata + 16) # methodCount member
|
|
|
|
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]'):
|
|
|
|
self.putField('sortgroup', 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'))
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('sortgroup', 15)
|
2016-07-14 13:13:16 +02:00
|
|
|
|
|
|
|
if isQMetaObject:
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[superdata]'):
|
|
|
|
self.putField('sortgroup', 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)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putNumChild(1)
|
|
|
|
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
|
|
|
self.putNumChild(0)
|
|
|
|
|
|
|
|
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]'):
|
|
|
|
self.putField('sortgroup', 12)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putValue(localIndex)
|
2016-10-07 11:49:51 +02:00
|
|
|
with SubItem(self, '[globalindex]'):
|
|
|
|
self.putField('sortgroup', 11)
|
2016-07-14 13:13:16 +02:00
|
|
|
self.putValue(globalOffset + localIndex)
|
|
|
|
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#with SubItem(self, '[signals]'):
|
2016-07-14 13:13:16 +02:00
|
|
|
# self.putItemCount(signalCount)
|
|
|
|
# signalNames = metaData(52, -14, 5)
|
2016-10-07 11:49:51 +02:00
|
|
|
# warn('NAMES: %s' % signalNames)
|
2016-07-14 13:13:16 +02:00
|
|
|
# if self.isExpanded():
|
|
|
|
# with Children(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
# putt('A', 'b')
|
2016-07-14 13:13:16 +02:00
|
|
|
# for i in range(signalCount):
|
|
|
|
# k = signalNames[i]
|
|
|
|
# with SubItem(self, k):
|
|
|
|
# self.putEmptyValue()
|
|
|
|
# if dd:
|
|
|
|
# self.putQObjectConnections(dd)
|
2014-04-03 22:08:35 +02:00
|
|
|
|
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-09-06 08:54:43 +02:00
|
|
|
connections = connections.cast(connections.type.firstBase())
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putSpecialValue('minimumitemcount', 0)
|
2014-04-10 15:02:29 +02:00
|
|
|
self.putNumChild(1)
|
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
|
2014-04-10 15:02:29 +02:00
|
|
|
base = self.extractPointer(connections)
|
2014-04-03 22:08:35 +02:00
|
|
|
data, size, alloc = self.vectorDataHelper(base)
|
2016-10-07 13:08:49 +02:00
|
|
|
connectionType = self.createType('@QObjectPrivate::Connection*')
|
2014-04-03 22:08:35 +02:00
|
|
|
for i in xrange(size):
|
|
|
|
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,
|
2016-09-06 08:54:43 +02:00
|
|
|
self.createValue(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
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def currentItemFormat(self, typeName = None):
|
2015-03-20 16:03:59 +01:00
|
|
|
displayFormat = self.formats.get(self.currentIName, AutomaticFormat)
|
|
|
|
if displayFormat == AutomaticFormat:
|
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)
|
2015-03-20 16:03:59 +01:00
|
|
|
displayFormat = self.typeformats.get(needle, AutomaticFormat)
|
|
|
|
return displayFormat
|
2013-10-23 16:28:02 +02:00
|
|
|
|
2016-09-27 18:10:13 +02:00
|
|
|
def putSubItem(self, component, value): # -> ReportItem
|
2016-09-06 08:54:43 +02:00
|
|
|
if not isinstance(value, self.Value):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('WRONG VALUE TYPE IN putSubItem: %s' % type(value))
|
2016-09-06 08:54:43 +02:00
|
|
|
if not isinstance(value.type, self.Type):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('WRONG TYPE TYPE IN putSubItem: %s' % type(value.type))
|
2016-09-06 08:54:43 +02:00
|
|
|
with SubItem(self, component):
|
2016-09-26 14:29:16 +02:00
|
|
|
self.putItem(value)
|
2016-09-27 18:10:13 +02:00
|
|
|
value = self.currentValue
|
2016-10-07 11:49:51 +02:00
|
|
|
return value # The 'short' display.
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def putArrayData(self, base, n, innerType, childNumChild = None, maxNumChild = 10000):
|
|
|
|
self.checkIntType(base)
|
|
|
|
self.checkIntType(n)
|
|
|
|
addrBase = base
|
|
|
|
innerSize = innerType.size()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('ADDRESS: %s INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
|
2016-09-15 17:55:56 +02:00
|
|
|
enc = innerType.simpleEncoding()
|
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)
|
2016-04-12 11:43:13 +02:00
|
|
|
if n > maxNumChild:
|
|
|
|
self.put('childrenelided="%s",' % n) # FIXME: Act on that in frontend
|
|
|
|
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,
|
2015-04-14 11:24:07 +02: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)
|
|
|
|
|
2016-04-12 11:43:13 +02:00
|
|
|
def putPlotDataHelper(self, base, n, innerType, maxNumChild = 1000*1000):
|
|
|
|
if n > maxNumChild:
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('plotelided', n) # FIXME: Act on that in frontend
|
2016-04-12 11:43:13 +02:00
|
|
|
n = maxNumChild
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.currentItemFormat() == ArrayPlotFormat 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
|
|
|
|
2016-04-12 11:43:13 +02:00
|
|
|
def putPlotData(self, base, n, innerType, maxNumChild = 1000*1000):
|
|
|
|
self.putPlotDataHelper(base, n, innerType, maxNumChild=maxNumChild)
|
2014-01-04 00:39:23 +01:00
|
|
|
if self.isExpanded():
|
2016-04-12 11:43:13 +02:00
|
|
|
self.putArrayData(base, n, innerType, maxNumChild=maxNumChild)
|
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):
|
|
|
|
for i in xrange(n):
|
|
|
|
self.putSubItem(i, p.dereference())
|
|
|
|
p += 1
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def extractPointer(self, value):
|
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):
|
|
|
|
if self.isInt(value):
|
|
|
|
val = self.Value(self)
|
|
|
|
val.laddress = value
|
|
|
|
return val.extractSomething(pattern, bitsize)
|
|
|
|
if isinstance(value, self.Value):
|
|
|
|
return value.extractSomething(pattern, bitsize)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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)
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
match = re.search('(\.)(\(.+?\))?(\.)', 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)
|
|
|
|
left_s = 1 + left_e - searchUnbalanced(exp[left_e::-1], False)
|
|
|
|
right_s = match.end(3)
|
|
|
|
right_e = right_s + searchUnbalanced(exp[right_s:], True)
|
|
|
|
template = exp[:left_s] + '%s' + exp[right_e:]
|
|
|
|
|
|
|
|
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.
|
2016-09-06 08:54:43 +02:00
|
|
|
ss = self.parseAndEvaluate(s[1:len(s)-1]).integer() if s else 1
|
|
|
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('VARIABLES: %s' % variables)
|
|
|
|
self.preping('locals')
|
2016-09-20 11:52:06 +02:00
|
|
|
shadowed = {}
|
|
|
|
for value in variables:
|
|
|
|
self.anonNumber = 0
|
2016-10-07 11:49:51 +02:00
|
|
|
if value.name == 'argv' and value.type.name == 'char **':
|
2016-09-20 11:52:06 +02:00
|
|
|
self.putSpecialArgv(value)
|
|
|
|
else:
|
|
|
|
name = value.name
|
|
|
|
if name in shadowed:
|
|
|
|
level = shadowed[name]
|
|
|
|
shadowed[name] = level + 1
|
2016-10-07 11:49:51 +02:00
|
|
|
name += '@%d' % level
|
2016-09-20 11:52:06 +02:00
|
|
|
else:
|
|
|
|
shadowed[name] = 1
|
2016-10-07 11:49:51 +02:00
|
|
|
# A 'normal' local variable or parameter.
|
|
|
|
iname = value.iname if hasattr(value, 'iname') else 'local.' + name
|
2016-09-20 11:52:06 +02:00
|
|
|
with TopLevelItem(self, iname):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.preping('all-' + iname)
|
|
|
|
self.putField('iname', iname)
|
|
|
|
self.putField('name', name)
|
2016-09-20 11:52:06 +02:00
|
|
|
self.putItem(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.ping('all-' + iname)
|
|
|
|
self.ping('locals')
|
2016-09-20 11:52:06 +02:00
|
|
|
|
2015-03-26 13:03:38 +01:00
|
|
|
def handleWatches(self, args):
|
2016-10-07 11:49:51 +02:00
|
|
|
self.preping('watches')
|
|
|
|
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)
|
2016-10-07 11:49:51 +02:00
|
|
|
self.ping('watches')
|
2015-03-26 13:03:38 +01:00
|
|
|
|
2014-05-12 13:09:02 +02:00
|
|
|
def handleWatch(self, origexp, exp, iname):
|
|
|
|
exp = str(exp).strip()
|
|
|
|
escapedExp = self.hexencode(exp)
|
2016-10-07 11:49:51 +02:00
|
|
|
#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()
|
|
|
|
for i in xrange(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:
|
2016-10-07 11:49:51 +02:00
|
|
|
#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:]
|
2016-04-04 23:46:46 +02:00
|
|
|
spec = inspect.getargspec(function)
|
|
|
|
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
|
|
|
|
|
2015-03-18 16:48:57 +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:
|
2015-09-17 11:57:30 +02:00
|
|
|
m = __import__(mod)
|
2015-01-23 19:09:08 +01:00
|
|
|
dic = m.__dict__
|
|
|
|
for name in dic.keys():
|
|
|
|
item = dic[name]
|
|
|
|
self.registerDumper(name, item)
|
|
|
|
|
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]
|
|
|
|
if sys.version_info[0] >= 3:
|
2015-09-17 11:57:30 +02:00
|
|
|
import importlib
|
2015-01-23 19:09:08 +01:00
|
|
|
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"'
|
|
|
|
% (self.resultToMi(resdict), args.get('token', -1)))
|
|
|
|
|
|
|
|
def reportInterpreterAsync(self, resdict, asyncclass):
|
|
|
|
print('interpreterasync=%s,asyncclass="%s"'
|
|
|
|
% (self.resultToMi(resdict), asyncclass))
|
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
def removeInterpreterBreakpoint(self, args):
|
|
|
|
res = self.sendInterpreterRequest('removebreakpoint', { 'id' : args['id'] })
|
|
|
|
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):
|
|
|
|
pos0 = msg.index(' ') # End of service name
|
|
|
|
pos1 = msg.index(' ', pos0 + 1) # End of message length
|
|
|
|
service = msg[0:pos0]
|
|
|
|
msglen = int(msg[pos0+1:pos1])
|
|
|
|
msgend = pos1+1+msglen
|
|
|
|
payload = msg[pos1+1:msgend]
|
|
|
|
msg = msg[msgend:]
|
|
|
|
if service == 'NativeQmlDebugger':
|
|
|
|
try:
|
|
|
|
resdict = json.loads(payload)
|
|
|
|
continue
|
|
|
|
except:
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('Cannot parse native payload: %s' % payload)
|
2015-10-14 13:26:22 +02:00
|
|
|
else:
|
|
|
|
print('interpreteralien=%s'
|
|
|
|
% {'service': service, 'payload': self.hexencode(payload)})
|
|
|
|
try:
|
|
|
|
expr = 'qt_qmlDebugClearBuffer()'
|
|
|
|
res = self.parseAndEvaluate(expr)
|
|
|
|
except RuntimeError as error:
|
2016-10-07 11:49:51 +02:00
|
|
|
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
|
|
|
|
|
|
|
def sendInterpreterRequest(self, command, args = {}):
|
2015-10-14 13:26:22 +02:00
|
|
|
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:
|
2016-10-07 11:49:51 +02:00
|
|
|
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.
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('Interpreter command failed: %s: %s' % (encoded, error))
|
2015-10-08 16:19:57 +02:00
|
|
|
return {}
|
|
|
|
if not res:
|
2016-10-07 11:49:51 +02:00
|
|
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
#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,
|
|
|
|
'error': 'Pending interpreter breakpoint insertion failed.'}, args)
|
|
|
|
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,
|
|
|
|
'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):
|
|
|
|
return self.sendInterpreterRequest('backtrace', {'limit': 10 })
|
2015-02-05 12:51:25 +01:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def isInt(self, thing):
|
|
|
|
if isinstance(thing, int):
|
|
|
|
return True
|
|
|
|
if sys.version_info[0] == 2:
|
|
|
|
if isinstance(thing, long):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
def putItem(self, value):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('ITEM: %s' % value.stringify())
|
2016-09-19 12:05:16 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj = value.type #unqualified()
|
|
|
|
typeName = typeobj.name
|
|
|
|
|
|
|
|
self.addToCache(typeobj) # Fill type cache
|
2016-09-26 14:29:16 +02:00
|
|
|
self.putAddress(value.address())
|
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):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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):
|
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeTypedef:
|
2016-09-06 08:54:43 +02:00
|
|
|
strippedType = typeobj.stripTypedefs()
|
|
|
|
self.putItem(value.cast(strippedType))
|
2016-10-06 00:59:11 +02:00
|
|
|
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
|
2016-10-07 11:49:51 +02:00
|
|
|
typeName += ' : %s' % value.lbitsize
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putBetterType(typeName)
|
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodePointer:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putFormattedPointer(value)
|
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeFunction:
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeobj)
|
|
|
|
self.putValue(value)
|
|
|
|
self.putNumChild(0)
|
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeEnum:
|
2016-10-07 11:49:51 +02:00
|
|
|
#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
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeArray:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('ARRAY VALUE: %s' % value)
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putCStyleArray(value)
|
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeIntegral:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('INTEGER: %s %s' % (value.name, value))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putValue(value.value())
|
|
|
|
self.putNumChild(0)
|
2016-10-06 00:59:11 +02:00
|
|
|
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
|
2016-10-07 11:49:51 +02:00
|
|
|
typeName += ' : %s' % value.lbitsize
|
2016-10-06 00:59:11 +02:00
|
|
|
self.putType(typeName)
|
2016-09-06 08:54:43 +02:00
|
|
|
return
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeFloat:
|
2016-10-07 11:49:51 +02:00
|
|
|
#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
|
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeReference:
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.isLldb:
|
2016-09-26 14:29:16 +02:00
|
|
|
item = value.cast(typeobj.target().pointer()).dereference()
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2016-09-26 14:29:16 +02:00
|
|
|
item = value.cast(typeobj.target().unqualified())
|
|
|
|
self.putItem(item)
|
|
|
|
self.putBetterType(typeobj.name)
|
|
|
|
return
|
2016-09-19 12:05:16 +02:00
|
|
|
|
|
|
|
if typeobj.code == TypeCodeComplex:
|
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
|
|
|
|
2016-09-19 12:05:16 +02:00
|
|
|
if typeobj.code == TypeCodeFortranString:
|
2016-09-06 08:54:43 +02:00
|
|
|
data = self.value.data()
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putValue(data, 'latin1', 1)
|
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
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('SOME VALUE: %s' % value)
|
|
|
|
#warn('HAS CHILDREN VALUE: %s' % value.hasChildren())
|
|
|
|
#warn('GENERIC STRUCT: %s' % typeobj)
|
|
|
|
#warn('INAME: %s ' % self.currentIName)
|
|
|
|
#warn('INAMES: %s ' % self.expandedINames)
|
|
|
|
#warn('EXPANDED: %s ' % (self.currentIName in self.expandedINames))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.putType(typeName)
|
|
|
|
self.putNumChild(1)
|
2016-09-20 12:07:46 +02:00
|
|
|
self.putEmptyValue()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('STRUCT GUTS: %s ADDRESS: %s ' % (value.name, value.address()))
|
2016-09-20 12:07:46 +02:00
|
|
|
#metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
|
|
|
|
if self.showQObjectNames:
|
|
|
|
self.preping(self.currentIName)
|
|
|
|
metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
|
|
|
|
self.ping(self.currentIName)
|
|
|
|
if metaObjectPtr:
|
|
|
|
self.context = value
|
|
|
|
self.putQObjectNameValue(value)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('STRUCT GUTS: %s MO: 0x%x ' % (self.currentIName, metaObjectPtr))
|
2016-09-20 12:07:46 +02:00
|
|
|
if self.isExpanded():
|
2016-10-07 11:49:51 +02:00
|
|
|
self.putField('sortable', 1)
|
2016-09-20 12:07:46 +02:00
|
|
|
with Children(self, 1, childType=None):
|
|
|
|
self.putFields(value)
|
|
|
|
if not self.showQObjectNames:
|
|
|
|
metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
|
|
|
|
if metaObjectPtr:
|
|
|
|
self.putQObjectGuts(value, metaObjectPtr)
|
|
|
|
|
2016-09-23 17:23:41 +02:00
|
|
|
def symbolAddress(self, symbolName):
|
2016-10-07 11:49:51 +02:00
|
|
|
return self.parseAndEvaluate('(size_t)&' + symbolName).pointer()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def qtTypeInfoVersion(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
addr = self.symbolAddress('qtHookData')
|
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)
|
2016-10-07 11:49:51 +02:00
|
|
|
#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
|
|
|
|
|
|
|
def lookupType(self, typestring):
|
|
|
|
return self.fromNativeType(self.lookupNativeType(typestring))
|
|
|
|
|
|
|
|
def addToCache(self, typeobj):
|
|
|
|
typename = typeobj.name
|
|
|
|
if typename in self.typesReported:
|
|
|
|
return
|
|
|
|
self.typesReported[typename] = True
|
|
|
|
self.typesToReport[typename] = typeobj
|
|
|
|
|
|
|
|
class Value:
|
|
|
|
def __init__(self, dumper):
|
|
|
|
self.dumper = dumper
|
|
|
|
self.name = None
|
|
|
|
self.type = None
|
|
|
|
self.ldata = None
|
|
|
|
self.laddress = None
|
|
|
|
self.lIsInScope = True
|
2016-09-26 14:29:16 +02:00
|
|
|
self.ldisplay = None
|
2016-10-06 00:59:11 +02:00
|
|
|
self.lbitsize = None
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def check(self):
|
|
|
|
if self.laddress is not None and not self.dumper.isInt(self.laddress):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('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):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('INCONSISTENT TYPE: %s' % type(self.type))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
#error('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-10-06 00:59:11 +02:00
|
|
|
return "Value(name='%s',type=%s,bsize=%s,data=%s,address=%s)" \
|
|
|
|
% (self.name, self.type.name, self.lbitsize,
|
|
|
|
self.dumper.hexencode(self.ldata), addr)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def display(self):
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodeEnum:
|
|
|
|
return self.type.enumDisplay(self.extractInteger(self.type.bitsize(), False))
|
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.ldisplay is not None:
|
|
|
|
return self.ldisplay
|
|
|
|
#if self.ldata is not None:
|
|
|
|
# if sys.version_info[0] == 2 and isinstance(self.ldata, buffer):
|
2016-10-07 11:49:51 +02:00
|
|
|
# return bytes(self.ldata).encode('hex')
|
|
|
|
# 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
|
|
|
|
|
|
|
def integer(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
unsigned = self.type.stripTypedefs().name.startswith('unsigned')
|
2016-09-06 08:54:43 +02:00
|
|
|
bitsize = self.type.bitsize()
|
|
|
|
return self.extractInteger(bitsize, unsigned)
|
|
|
|
|
|
|
|
def floatingPoint(self):
|
|
|
|
if self.type.size() == 8:
|
|
|
|
return self.extractSomething('d', 64)
|
|
|
|
if self.type.size() == 4:
|
|
|
|
return self.extractSomething('f', 32)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('BAD FLOAT DATA: %s SIZE: %s' % (self, self.type.size()))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def pointer(self):
|
|
|
|
return self.extractInteger(8 * self.dumper.ptrSize(), True)
|
|
|
|
|
|
|
|
def value(self):
|
|
|
|
if self.type is not None:
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodeIntegral:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.integer()
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodeFloat:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.floatingPoint()
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodeTypedef:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.cast(self.type.stripTypedefs()).value()
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.stripTypedefs().code == TypeCodePointer:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.pointer()
|
|
|
|
return None
|
|
|
|
|
|
|
|
def extractPointer(self):
|
|
|
|
return self.split('p')[0]
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GET ITEM %s %s' % (self, index))
|
2016-09-06 08:54:43 +02:00
|
|
|
self.check()
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodeTypedef:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GET ITEM %s STRIP TYPEDEFS TO %s' % (self, self.type.stripTypedefs()))
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.cast(self.type.stripTypedefs()).__getitem__(index)
|
|
|
|
if isinstance(index, str):
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodePointer:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GET ITEM %s DEREFERENCE TO %s' % (self, self.dereference()))
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.dereference().__getitem__(index)
|
|
|
|
field = self.dumper.Field(self.dumper)
|
|
|
|
field.parentType = self.type
|
|
|
|
field.name = index
|
|
|
|
elif isinstance(index, self.dumper.Field):
|
|
|
|
field = index
|
2016-09-21 18:52:49 +02:00
|
|
|
elif self.dumper.isInt(index):
|
|
|
|
return self.members()[index]
|
2016-09-06 08:54:43 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('BAD INDEX TYPE %s' % type(index))
|
2016-09-06 08:54:43 +02:00
|
|
|
field.check()
|
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('EXTRACT FIELD: %s, BASE 0x%x' % (field, self.address()))
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.type.code == TypeCodePointer:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('IS TYPEDEFED POINTER!')
|
2016-09-06 08:54:43 +02:00
|
|
|
res = self.dereference()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('WAS POINTER: %s' % res)
|
2016-09-06 08:54:43 +02:00
|
|
|
return res.extractField(field)
|
|
|
|
|
|
|
|
return self.extractField(field)
|
|
|
|
|
|
|
|
def extractField(self, field):
|
2016-09-30 17:25:23 +02:00
|
|
|
if self.type.code == TypeCodeTypedef:
|
|
|
|
return self.cast(self.type.stripTypedefs()).extractField(field)
|
2016-09-06 08:54:43 +02:00
|
|
|
if not isinstance(field, self.dumper.Field):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('BAD INDEX TYPE %s' % type(field))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELD: %s ' % field)
|
2016-09-06 08:54:43 +02:00
|
|
|
fieldBitsize = field.bitsize()
|
|
|
|
fieldSize = None if fieldBitsize is None else fieldBitsize >> 3
|
2016-09-26 14:29:16 +02:00
|
|
|
fieldBitpos = field.bitpos()
|
|
|
|
fieldOffset = fieldBitpos >> 3
|
|
|
|
fieldBitpos -= fieldOffset * 8
|
2016-10-06 00:59:11 +02:00
|
|
|
fieldType = field.fieldType()
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.name = field.name
|
|
|
|
|
|
|
|
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
|
|
|
|
2016-10-06 00:59:11 +02:00
|
|
|
if fieldBitsize is not None and fieldBitsize != fieldType.size() * 8:
|
2016-09-06 08:54:43 +02:00
|
|
|
data = val.extractInteger(fieldBitsize, True)
|
2016-09-26 14:29:16 +02:00
|
|
|
data = data >> fieldBitpos
|
2016-09-06 08:54:43 +02:00
|
|
|
data = data & ((1 << fieldBitsize) - 1)
|
|
|
|
val.laddress = None
|
|
|
|
val.ldata = bytes(struct.pack('Q', data))
|
2016-09-26 14:29:16 +02:00
|
|
|
|
|
|
|
val.type = None
|
|
|
|
if val.laddress is not None and fieldType is not None:
|
|
|
|
if fieldType.code in (TypeCodePointer, TypeCodeReference):
|
|
|
|
baseType = fieldType.dereference()
|
|
|
|
address = self.dumper.extractPointer(val.laddress)
|
|
|
|
dynTypeName = self.dumper.dynamicTypeName(baseType, address)
|
|
|
|
if dynTypeName is not None:
|
|
|
|
if fieldType.code == TypeCodePointer:
|
|
|
|
val.type = self.dumper.createType(dynTypeName + '*')
|
|
|
|
else:
|
|
|
|
val.type = self.dumper.createType(dynTypeName + ' &')
|
|
|
|
if val.type is None:
|
|
|
|
val.type = fieldType
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GOT VAL %s FOR FIELD %s' % (val, field))
|
2016-09-06 08:54:43 +02:00
|
|
|
val.check()
|
2016-09-26 14:29:16 +02:00
|
|
|
val.lbitsize = fieldBitsize
|
2016-09-06 08:54:43 +02:00
|
|
|
return val
|
|
|
|
|
2016-09-21 18:52:49 +02:00
|
|
|
def members(self):
|
|
|
|
members = []
|
|
|
|
for field in self.type.fields():
|
|
|
|
if not field.isBaseClass:
|
|
|
|
members.append(self.extractField(field))
|
|
|
|
return members
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def __add__(self, other):
|
|
|
|
self.check()
|
|
|
|
if self.dumper.isInt(other):
|
2016-09-26 14:29:16 +02:00
|
|
|
stripped = self.type.stripTypedefs()
|
|
|
|
if stripped.code == TypeCodePointer:
|
|
|
|
address = self.pointer() + stripped.dereference().size()
|
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.laddress = None
|
|
|
|
val.ldata = bytes(struct.pack('Q', address))
|
|
|
|
val.type = self.type
|
|
|
|
return val
|
2016-10-07 11:49:51 +02:00
|
|
|
error('BAD DATA TO ADD TO: %s %s' % (self.type, other))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def dereference(self):
|
|
|
|
self.check()
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.dumper.Value(self.dumper)
|
|
|
|
val.type = self.type.dereference()
|
|
|
|
val.laddress = self.pointer()
|
|
|
|
dynTypeName = self.dumper.dynamicTypeName(val.type, val.laddress)
|
|
|
|
if dynTypeName is not None:
|
|
|
|
val.type = self.dumper.createType(dynTypeName)
|
|
|
|
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
|
|
|
|
if sys.version_info[0] == 3:
|
|
|
|
val.ldata = self.ldata + bytes('\0' * (size - self.type.size()), encoding='latin1')
|
|
|
|
else:
|
|
|
|
val.ldata = self.ldata + bytes('\0' * (size - self.type.size()))
|
|
|
|
return val
|
|
|
|
if self.type.size() == size:
|
|
|
|
return self
|
2016-10-07 11:49:51 +02:00
|
|
|
error('NOT IMPLEMENTED')
|
2016-09-15 12:31:28 +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
|
2016-09-26 14:29:16 +02:00
|
|
|
val.type = self.dumper.createType(typish)
|
2016-09-06 08:54:43 +02:00
|
|
|
return val
|
|
|
|
|
|
|
|
def downcast(self):
|
|
|
|
self.check()
|
|
|
|
return self
|
|
|
|
|
|
|
|
def address(self):
|
|
|
|
self.check()
|
|
|
|
return self.laddress
|
|
|
|
|
|
|
|
def data(self, size = None):
|
|
|
|
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]
|
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
|
2016-10-07 11:49:51 +02:00
|
|
|
error('CANNOT CONVERT TO BYTES: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractInteger(self, bitsize, unsigned):
|
|
|
|
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-09-15 12:31:28 +02:00
|
|
|
try:
|
|
|
|
return struct.unpack_from(code, rawBytes, 0)[0]
|
|
|
|
except:
|
|
|
|
pass
|
2016-10-07 11:49:51 +02:00
|
|
|
error('Cannot extract: Code: %s Bytes: %s Bitsize: %s Size: %s'
|
2016-09-15 12:31:28 +02:00
|
|
|
% (code, self.dumper.hexencode(rawBytes), bitsize, size))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def extractSomething(self, code, bitsize):
|
|
|
|
self.check()
|
|
|
|
size = (bitsize + 7) >> 3
|
|
|
|
rawBytes = self.data(size)
|
|
|
|
return struct.unpack_from(code, rawBytes, 0)[0]
|
|
|
|
|
|
|
|
def to(self, pattern):
|
|
|
|
return self.split(pattern)[0]
|
|
|
|
|
|
|
|
def split(self, pattern):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('EXTRACT STRUCT FROM: %s' % self.type)
|
2016-09-06 08:54:43 +02:00
|
|
|
(pp, size, fields) = self.dumper.describeStruct(pattern)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('SIZE: %s ' % size)
|
2016-09-06 08:54:43 +02:00
|
|
|
result = struct.unpack_from(pp, self.data(size))
|
|
|
|
def structFixer(field, thing):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('STRUCT MEMBER: %s' % type(thing))
|
2016-09-06 08:54:43 +02:00
|
|
|
if field.isStruct:
|
|
|
|
if field.ltype != field.fieldType():
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DO NOT SIMPLIFY')
|
|
|
|
#warn('FIELD POS: %s' % field.ltype)
|
|
|
|
#warn('FIELD TYE: %s' % field.fieldType())
|
2016-09-06 08:54:43 +02:00
|
|
|
res = self.dumper.createValue(thing, field.fieldType())
|
2016-10-07 11:49:51 +02:00
|
|
|
#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):
|
2016-10-07 11:49:51 +02:00
|
|
|
error('STRUCT ERROR: %s %s' (fields, result))
|
2016-09-06 08:54:43 +02:00
|
|
|
return tuple(map(structFixer, fields, result))
|
|
|
|
|
|
|
|
def checkPointer(self, p, align = 1):
|
|
|
|
ptr = p if self.isInt(p) else p.pointer()
|
|
|
|
self.readRawMemory(ptr, 1)
|
|
|
|
|
2016-09-26 14:29:16 +02:00
|
|
|
def dynamicTypeName(self, baseType, address):
|
|
|
|
if baseType.code != TypeCodeStruct:
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
vtbl = self.extractPointer(address)
|
|
|
|
except:
|
|
|
|
return None
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('VTBL: 0x%x' % vtbl)
|
2016-09-26 14:29:16 +02:00
|
|
|
if not self.canBePointer(vtbl):
|
|
|
|
return None
|
|
|
|
return self.nativeDynamicTypeName(address, baseType)
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
class Type:
|
|
|
|
def __init__(self, dumper):
|
|
|
|
self.dumper = dumper
|
|
|
|
self.name = None
|
|
|
|
self.nativeType = None
|
|
|
|
self.lfields = None
|
|
|
|
self.lbitsize = None
|
|
|
|
self.lbitpos = None
|
2016-09-26 14:29:16 +02:00
|
|
|
self.ltarget = None # Inner type for arrays
|
2016-09-06 08:54:43 +02:00
|
|
|
self.templateArguments = None
|
2016-09-19 12:05:16 +02:00
|
|
|
self.code = None
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
self.check()
|
2016-10-07 11:49:51 +02:00
|
|
|
error('Not implemented')
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.name
|
2016-10-07 11:49:51 +02:00
|
|
|
#error('Not implemented')
|
2016-09-15 12:31:28 +02:00
|
|
|
|
|
|
|
def stringify(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
return 'Type(name="%s",bsize=%s,bpos=%s,code=%s,ntype=%s)' \
|
2016-10-06 00:59:11 +02:00
|
|
|
% (self.name, self.lbitsize, self.lbitpos, self.code, self.nativeType)
|
2016-09-15 17:55:56 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def __getitem__(self, index):
|
|
|
|
if self.dumper.isInt(index):
|
|
|
|
return self.templateArgument(index)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('CANNOT INDEX TYPE')
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def check(self):
|
|
|
|
if self.name is None:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('TYPE WITHOUT NAME')
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def dereference(self):
|
|
|
|
self.check()
|
|
|
|
if self.nativeType is not None:
|
|
|
|
return self.dumper.nativeTypeDereference(self.nativeType)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW HOW TO DEREF: %s' % self.name)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def unqualified(self):
|
|
|
|
if self.nativeType is not None:
|
|
|
|
return self.dumper.nativeTypeUnqualified(self.nativeType)
|
|
|
|
return self
|
|
|
|
|
|
|
|
def templateArgument(self, position, numeric = False):
|
|
|
|
if self.templateArguments is not None:
|
|
|
|
return self.templateArguments[position]
|
|
|
|
nativeType = self.nativeType
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('NATIVE TYPE 0: %s' % dir(nativeType))
|
2016-09-06 08:54:43 +02:00
|
|
|
if nativeType is None:
|
|
|
|
nativeType = self.dumper.lookupNativeType(self.name)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('NATIVE TYPE 1: %s' % dir(nativeType))
|
2016-09-06 08:54:43 +02:00
|
|
|
if nativeType is not None:
|
|
|
|
return self.dumper.nativeTypeTemplateArgument(nativeType, position, numeric)
|
|
|
|
res = self.dumper.extractTemplateArgument(self.name, position)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('TEMPLATE ARG: RES: %s' % res)
|
2016-09-06 08:54:43 +02:00
|
|
|
if numeric:
|
|
|
|
return int(res)
|
|
|
|
return self.dumper.createType(res)
|
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def simpleEncoding(self):
|
|
|
|
res = {
|
|
|
|
'bool' : 'int:1',
|
|
|
|
'char' : 'int:1',
|
|
|
|
'signed char' : 'int:1',
|
|
|
|
'unsigned char' : 'uint:1',
|
|
|
|
'short' : 'int:2',
|
|
|
|
'unsigned short' : 'uint:2',
|
|
|
|
'int' : 'int:4',
|
|
|
|
'unsigned int' : 'uint:4',
|
|
|
|
'long long' : 'int:8',
|
|
|
|
'unsigned long long' : 'uint:8',
|
|
|
|
'float': 'float:4',
|
|
|
|
'double': 'float:8'
|
|
|
|
}.get(self.name, None)
|
|
|
|
return res
|
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
def isSimpleType(self):
|
2016-09-19 12:05:16 +02:00
|
|
|
return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def alignment(self):
|
|
|
|
if self.isSimpleType():
|
|
|
|
if self.name == 'double':
|
|
|
|
return self.dumper.ptrSize() # Crude approximation.
|
|
|
|
return self.size()
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.code == TypeCodePointer:
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.dumper.ptrSize()
|
|
|
|
fields = self.fields()
|
|
|
|
align = 1
|
|
|
|
for field in fields:
|
|
|
|
a = field.fieldType().alignment()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn(' SUBFIELD: %s ALIGN: %s' % (field.name, a))
|
2016-09-06 08:54:43 +02:00
|
|
|
if a is not None and a > align:
|
|
|
|
align = a
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('COMPUTED ALIGNMENT: %s ' % align)
|
2016-09-06 08:54:43 +02:00
|
|
|
return align
|
|
|
|
|
|
|
|
def pointer(self):
|
|
|
|
if self.nativeType is not None:
|
|
|
|
return self.dumper.nativeTypePointer(self.nativeType)
|
2016-10-07 11:49:51 +02:00
|
|
|
error('Cannot create pointer type for %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def splitArrayType(self):
|
|
|
|
# -> (inner type, count)
|
2016-09-19 12:05:16 +02:00
|
|
|
if not self.code == TypeCodeArray:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('Not an array')
|
2016-09-06 08:54:43 +02:00
|
|
|
s = self.name
|
|
|
|
pos1 = s.rfind('[')
|
|
|
|
pos2 = s.find(']', pos1)
|
|
|
|
itemCount = s[pos1+1:pos2]
|
|
|
|
return (self.dumper.createType(s[0:pos1].strip()), int(s[pos1+1:pos2]))
|
|
|
|
|
|
|
|
def target(self):
|
|
|
|
if self.nativeType is not None:
|
|
|
|
target = self.dumper.nativeTypeTarget(self.nativeType)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('DEREFERENCING: %s -> %s ' % (self.nativeType, target))
|
2016-09-06 08:54:43 +02:00
|
|
|
if target is not None:
|
|
|
|
return target
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.code == TypeCodeArray:
|
2016-09-06 08:54:43 +02:00
|
|
|
(innerType, itemCount) = self.splitArrayType()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('EXTRACTING ARRAY TYPE: %s -> %s' % (self, innerType))
|
2016-09-19 12:05:16 +02:00
|
|
|
# HACK for LLDB 320:
|
|
|
|
if innerType.code is None and innerType.name.endswith(']'):
|
|
|
|
innerType.code = TypeCodeArray
|
2016-09-06 08:54:43 +02:00
|
|
|
return innerType
|
|
|
|
|
2016-10-07 14:51:40 +02:00
|
|
|
strippedType = self.stripTypedefs()
|
2016-09-06 08:54:43 +02:00
|
|
|
if strippedType.name != self.name:
|
|
|
|
return strippedType.target()
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW TARGET FOR: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def fields(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GETTING FIELDS FOR: %s' % self.name)
|
2016-09-06 08:54:43 +02:00
|
|
|
if self.lfields is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
warn('USING LFIELDS: %s' % self.lfields)
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.lfields
|
|
|
|
nativeType = self.nativeType
|
|
|
|
if nativeType is None:
|
|
|
|
nativeType = self.dumper.lookupNativeType(self.name)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELDS LOOKING UP NATIVE TYPE FOR %s -> %s' % (self.name, nativeType))
|
2016-09-06 08:54:43 +02:00
|
|
|
if nativeType is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELDS USING NATIVE TYPE %s' % nativeType)
|
2016-09-06 08:54:43 +02:00
|
|
|
fields = self.dumper.nativeTypeFields(nativeType)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELDS RES: %s FOR %s' % (fields, nativeType))
|
2016-09-06 08:54:43 +02:00
|
|
|
return fields
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW FIELDS FOR: %s' % self.stringify())
|
2016-09-06 08:54:43 +02:00
|
|
|
return []
|
|
|
|
|
|
|
|
def firstBase(self):
|
|
|
|
if self.nativeType is not None:
|
|
|
|
return self.dumper.nativeTypeFirstBase(self.nativeType)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def field(self, name, bitoffset = 0):
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GETTING FIELD %s FOR: %s' % (name, self.name))
|
2016-09-06 08:54:43 +02:00
|
|
|
for f in self.fields():
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('EXAMINING MEMBER %s' % f.name)
|
2016-09-06 08:54:43 +02:00
|
|
|
if f.name == name:
|
|
|
|
ff = copy.copy(f)
|
|
|
|
if ff.lbitpos is None:
|
|
|
|
ff.lbitpos = bitoffset
|
|
|
|
else:
|
|
|
|
ff.lbitpos += bitoffset
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FOUND: %s' % ff)
|
2016-09-06 08:54:43 +02:00
|
|
|
return ff
|
|
|
|
if f.isBaseClass:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('EXAMINING BASE %s' % f.ltype)
|
2016-09-06 08:54:43 +02:00
|
|
|
res = f.ltype.field(name, bitoffset + f.bitpos())
|
|
|
|
if res is not None:
|
|
|
|
return res
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FIELD %s NOT FOUND IN %s' % (name, self))
|
2016-09-06 08:54:43 +02:00
|
|
|
return None
|
|
|
|
|
|
|
|
def stripTypedefs(self):
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.code != TypeCodeTypedef:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('NO TYPEDEF: %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
return self
|
|
|
|
if self.nativeType is not None:
|
|
|
|
res = self.dumper.nativeTypeStripTypedefs(self.nativeType)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('STRIP TYPEDEF: %s -> %s' % (self, res))
|
2016-09-06 08:54:43 +02:00
|
|
|
return res
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW HOW TO STRIP TYPEDEFS FROM %s' % s)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def size(self):
|
|
|
|
bs = self.bitsize()
|
|
|
|
if bs % 8 != 0:
|
2016-10-07 11:49:51 +02:00
|
|
|
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
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.code == TypeCodeArray:
|
2016-09-06 08:54:43 +02:00
|
|
|
(innerType, itemCount) = self.splitArrayType()
|
|
|
|
return itemCount * innerType.bitsize()
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW SIZE: %s' % self.name)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def isMovableType(self):
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.code in (TypeCodePointer, TypeCodeIntegral, TypeCodeFloat):
|
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'
|
2016-09-06 08:54:43 +02:00
|
|
|
):
|
|
|
|
return True
|
2016-10-07 11:49:51 +02:00
|
|
|
return strippedName == 'QStringList' and self.dumper.qtVersion() >= 0x050000
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-15 12:31:28 +02:00
|
|
|
def enumDisplay(self, intval):
|
|
|
|
if self.nativeType is not None:
|
|
|
|
return self.dumper.nativeTypeEnumDisplay(self.nativeType, intval)
|
2016-10-07 11:49:51 +02:00
|
|
|
return '%d' % intval
|
2016-09-15 12:31:28 +02:00
|
|
|
|
2016-09-06 08:54:43 +02:00
|
|
|
class Field:
|
|
|
|
def __init__(self, dumper):
|
|
|
|
self.dumper = dumper
|
|
|
|
self.name = None
|
|
|
|
self.baseIndex = None # Base class index if parent is structure
|
|
|
|
self.nativeIndex = None # Backend-defined index value
|
|
|
|
self.isBaseClass = False
|
|
|
|
self.isVirtualBase = False
|
|
|
|
self.ltype = None
|
|
|
|
self.parentType = None
|
|
|
|
self.lbitsize = None
|
|
|
|
self.lbitpos = None
|
|
|
|
self.isStruct = False
|
|
|
|
|
|
|
|
def __str__(self):
|
2016-10-07 11:49:51 +02:00
|
|
|
return ('Field(name="%s",ltype=%s,parentType=%s,bpos=%s,bsize=%s,'
|
|
|
|
+ 'bidx=%s,nidx=%s)') \
|
2016-09-26 14:29:16 +02:00
|
|
|
% (self.name,
|
|
|
|
None if self.ltype is None else self.ltype.name,
|
|
|
|
None if self.parentType is None else self.parentType.name,
|
2016-09-06 08:54:43 +02:00
|
|
|
self.lbitpos, self.lbitsize,
|
2016-09-14 16:43:35 +02:00
|
|
|
self.baseIndex, self.nativeIndex)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def check(self):
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.parentType.code == TypeCodePointer:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('POINTER NOT POSSIBLE AS FIELD PARENT')
|
2016-09-19 12:05:16 +02:00
|
|
|
if self.parentType.code == TypeCodeTypedef:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('TYPEDEFS NOT ALLOWED AS FIELD PARENT')
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def size(self):
|
|
|
|
return self.bitsize() >> 3
|
|
|
|
|
|
|
|
def offset(self):
|
|
|
|
return self.bitpos() >> 3
|
|
|
|
|
|
|
|
def bitsize(self):
|
|
|
|
self.check()
|
|
|
|
if self.lbitsize is not None:
|
|
|
|
return self.lbitsize
|
|
|
|
fieldType = self.fieldType()
|
|
|
|
# FIXME: enforce return value != None.
|
|
|
|
if fieldType is not None:
|
|
|
|
return fieldType.bitsize()
|
|
|
|
return None
|
|
|
|
|
|
|
|
def bitpos(self):
|
|
|
|
if self.lbitpos is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('BITPOS KNOWN: %s %s' % (self.name, self.lbitpos))
|
2016-09-06 08:54:43 +02:00
|
|
|
return self.lbitpos
|
|
|
|
self.check()
|
|
|
|
f = self.parentType.field(self.name)
|
|
|
|
if f is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('BITPOS FROM PARENT: %s' % self.parentType)
|
2016-09-06 08:54:43 +02:00
|
|
|
return f.bitpos()
|
2016-10-07 11:49:51 +02:00
|
|
|
error('DONT KNOW BITPOS FOR FIELD: %s ' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def fieldType(self):
|
|
|
|
if self.ltype is not None:
|
|
|
|
return self.ltype
|
|
|
|
if self.name is not None:
|
|
|
|
field = self.parentType.field(self.name)
|
|
|
|
if field is not None:
|
|
|
|
return field.fieldType()
|
2016-10-07 11:49:51 +02:00
|
|
|
#error('CANT GET FIELD TYPE FOR %s' % self)
|
2016-09-06 08:54:43 +02:00
|
|
|
return None
|
|
|
|
|
|
|
|
def createType(self, typish, size = None):
|
|
|
|
if isinstance(typish, self.Type):
|
|
|
|
typish.check()
|
|
|
|
return typish
|
|
|
|
if isinstance(typish, str):
|
2016-10-07 13:08:49 +02:00
|
|
|
def knownSize(tn):
|
|
|
|
if tn[0] == 'Q':
|
|
|
|
if tn in ('QByteArray', 'QString', 'QList', 'QStringList',
|
|
|
|
'QStringDataPtr'):
|
|
|
|
return self.ptrSize()
|
|
|
|
if tn in ('QImage', 'QObject'):
|
|
|
|
return 2 * self.ptrSize()
|
|
|
|
if tn == 'QVariant':
|
|
|
|
return 8 + self.ptrSize()
|
|
|
|
if typish in ('QPointF', 'QDateTime', 'QRect'):
|
|
|
|
return 16
|
|
|
|
if typish == 'QPoint':
|
|
|
|
return 8
|
|
|
|
if typish == 'QChar':
|
|
|
|
return 2
|
|
|
|
if typish in ('quint32', 'qint32'):
|
|
|
|
return 4
|
|
|
|
return None
|
|
|
|
|
|
|
|
ns = self.qtNamespace()
|
|
|
|
typish = typish.replace('@', ns)
|
|
|
|
if typish.startswith(ns):
|
|
|
|
size = knownSize(typish[len(ns):])
|
|
|
|
else:
|
|
|
|
size = knownSize(typish)
|
|
|
|
if size is not None:
|
|
|
|
typish = ns + typish
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
#typeobj = self.Type(self)
|
|
|
|
#typeobj.name = typish
|
|
|
|
nativeType = self.lookupNativeType(typish) # FIXME: Remove?
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FOUND NAT TYPE: %s' % dir(nativeType))
|
2016-09-06 08:54:43 +02:00
|
|
|
if nativeType is not None:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('USE FROM NATIVE')
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj = self.fromNativeType(nativeType)
|
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('FAKING')
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj = self.Type(self)
|
|
|
|
typeobj.name = typish
|
|
|
|
if size is not None:
|
|
|
|
typeobj.lbitsize = 8 * size
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('CREATE TYPE: %s' % typeobj)
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj.check()
|
|
|
|
return typeobj
|
2016-10-07 11:49:51 +02:00
|
|
|
error('NEED TYPE, NOT %s' % type(typish))
|
2016-09-06 08:54:43 +02:00
|
|
|
|
|
|
|
def createValue(self, datish, typish):
|
2016-09-26 14:29:16 +02:00
|
|
|
val = self.Value(self)
|
|
|
|
val.type = self.createType(typish)
|
2016-09-14 12:29:25 +02:00
|
|
|
if self.isInt(datish): # Used as address.
|
2016-09-06 08:54:43 +02:00
|
|
|
val.laddress = datish
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('CREATING %s AT 0x%x' % (val.type.name, address))
|
2016-09-26 14:29:16 +02:00
|
|
|
elif isinstance(datish, bytes):
|
2016-09-06 08:54:43 +02:00
|
|
|
val.ldata = datish
|
|
|
|
val.type.lbitsize = 8 * len(datish)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
|
2016-09-26 14:29:16 +02:00
|
|
|
else:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish))
|
2016-09-26 14:29:16 +02:00
|
|
|
val.check()
|
|
|
|
return val
|
2016-09-06 08:54:43 +02:00
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def createListItem(self, data, innerTypish):
|
|
|
|
innerType = self.createType(innerTypish)
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj = self.Type(self)
|
2016-10-07 11:49:51 +02:00
|
|
|
typeobj.name = self.qtNamespace() + 'QList<%s>' % innerType.name
|
2016-09-15 17:55:56 +02:00
|
|
|
typeobj.templateArguments = [innerType]
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj.lbitsize = 8 * self.ptrSize()
|
|
|
|
val = self.Value(self)
|
|
|
|
val.ldata = data
|
|
|
|
val.type = typeobj
|
|
|
|
return val
|
|
|
|
|
2016-09-15 17:55:56 +02:00
|
|
|
def createVectorItem(self, data, innerTypish):
|
|
|
|
innerType = self.createType(innerTypish)
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj = self.Type(self)
|
2016-10-07 11:49:51 +02:00
|
|
|
typeobj.name = self.qtNamespace() + 'QVector<%s>' % innerType.name
|
2016-09-15 17:55:56 +02:00
|
|
|
typeobj.templateArguments = [innerType]
|
2016-09-06 08:54:43 +02:00
|
|
|
typeobj.lbitsize = 8 * self.ptrSize()
|
|
|
|
val = self.Value(self)
|
|
|
|
val.ldata = data
|
|
|
|
val.type = typeobj
|
|
|
|
return val
|
|
|
|
|
|
|
|
class StructBuilder:
|
|
|
|
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
|
|
|
|
|
|
|
|
def fieldAlignment(self, fieldSize, fieldType):
|
|
|
|
if fieldType is not None:
|
|
|
|
align = self.dumper.createType(fieldType).alignment()
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('COMPUTED ALIGNMENT FOR %s: %s' % (fieldType, align))
|
2016-09-06 08:54:43 +02:00
|
|
|
if align is not None:
|
|
|
|
return align
|
|
|
|
if fieldSize <= 8:
|
|
|
|
align = (0, 1, 2, 4, 4, 8, 8, 8, 8)[fieldSize]
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GUESSED ALIGNMENT FROM SIZE: %s' % align)
|
2016-09-06 08:54:43 +02:00
|
|
|
return align
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('GUESSED ALIGNMENT: %s' % 8)
|
2016-09-06 08:54:43 +02:00
|
|
|
return 8
|
|
|
|
|
|
|
|
def addField(self, fieldSize, fieldCode = None, fieldIsStruct = False,
|
|
|
|
fieldName = None, fieldType = None):
|
|
|
|
|
|
|
|
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:
|
|
|
|
align = self.fieldAlignment(fieldSize, fieldType)
|
|
|
|
self.currentBitsize = 8 * ((self.currentBitsize + 7) >> 3) # Fill up byte.
|
|
|
|
padding = (align - (self.currentBitsize >> 3)) % align
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('AUTO PADDING AT %s BITS BY %s BYTES' % (self.currentBitsize, padding))
|
2016-09-06 08:54:43 +02:00
|
|
|
field = self.dumper.Field(self.dumper)
|
|
|
|
field.code = None
|
|
|
|
#field.lbitpos = self.currentBitsize
|
|
|
|
#field.lbitsize = 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
|
|
|
|
|
|
|
|
field = self.dumper.Field(self.dumper)
|
|
|
|
field.name = fieldName
|
|
|
|
field.ltype = fieldType
|
|
|
|
field.code = fieldCode
|
|
|
|
field.isStruct = fieldIsStruct
|
|
|
|
field.lbitpos = self.currentBitsize
|
|
|
|
field.lbitsize = fieldSize * 8
|
|
|
|
|
|
|
|
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
|
|
|
|
builder.addField(n, fieldIsStruct = True, fieldType = typeName)
|
|
|
|
typeName = None
|
|
|
|
n = None
|
|
|
|
else:
|
|
|
|
typeName += c
|
|
|
|
elif c == 'p': # Pointer as int
|
|
|
|
builder.addField(ptrSize, 'Q' if ptrSize == 8 else 'I')
|
|
|
|
elif c == 'P': # Pointer as Value
|
|
|
|
builder.addField(ptrSize, '%ss' % ptrSize)
|
|
|
|
elif c in ('q', 'Q', 'd'):
|
|
|
|
builder.addField(8, c)
|
|
|
|
elif c in ('i', 'I', 'f'):
|
|
|
|
builder.addField(4, c)
|
|
|
|
elif c in ('h', 'H'):
|
|
|
|
builder.addField(2, c)
|
|
|
|
elif c in ('b', 'B', 'c'):
|
|
|
|
builder.addField(1, c)
|
|
|
|
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':
|
|
|
|
builder.addField(int(n))
|
|
|
|
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)
|
|
|
|
field.code = None
|
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:
|
2016-10-07 11:49:51 +02:00
|
|
|
error('UNKNOWN STRUCT CODE: %s' % c)
|
2016-09-06 08:54:43 +02:00
|
|
|
pp = builder.pattern
|
|
|
|
size = (builder.currentBitsize + 7) >> 3 # FIXME: Tail padding missing.
|
|
|
|
fields = builder.fields
|
|
|
|
self.structPatternCache[pattern] = (pp, size, fields)
|
2016-10-07 11:49:51 +02:00
|
|
|
#warn('PP: %s -> %s %s %s' % (pattern, pp, size, fields))
|
2016-09-06 08:54:43 +02:00
|
|
|
return (pp, size, fields)
|