| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | ############################################################################ | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (C) 2016 The Qt Company Ltd. | 
					
						
							|  |  |  | # Contact: https://www.qt.io/licensing/ | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This file is part of Qt Creator. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Commercial License Usage | 
					
						
							|  |  |  | # Licensees holding valid commercial Qt licenses may use this file in | 
					
						
							|  |  |  | # accordance with the commercial license agreement provided with the | 
					
						
							|  |  |  | # Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | # a written agreement between you and The Qt Company. For licensing terms | 
					
						
							|  |  |  | # and conditions see https://www.qt.io/terms-conditions. For further | 
					
						
							|  |  |  | # information use the contact form at https://www.qt.io/contact-us. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # GNU General Public License Usage | 
					
						
							|  |  |  | # Alternatively, this file may be used under the terms of the GNU | 
					
						
							|  |  |  | # General Public License version 3 as published by the Free Software | 
					
						
							|  |  |  | # Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
					
						
							|  |  |  | # included in the packaging of this file. Please review the following | 
					
						
							|  |  |  | # information to ensure the GNU General Public License requirements will | 
					
						
							|  |  |  | # be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | ############################################################################ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import inspect | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import cdbext | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from dumper import * | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 14:50:10 +02:00
										 |  |  | class FakeVoidType(cdbext.Type): | 
					
						
							|  |  |  |     def __init__(self, name , dumper): | 
					
						
							|  |  |  |         cdbext.Type.__init__(self) | 
					
						
							|  |  |  |         self.typeName = name.strip() | 
					
						
							|  |  |  |         self.dumper = dumper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def name(self): | 
					
						
							|  |  |  |         return self.typeName | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def bitsize(self): | 
					
						
							| 
									
										
										
										
											2016-11-07 07:48:02 +01:00
										 |  |  |         return self.dumper.ptrSize() * 8 | 
					
						
							| 
									
										
										
										
											2016-10-28 14:50:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def code(self): | 
					
						
							|  |  |  |         if self.typeName.endswith('*'): | 
					
						
							|  |  |  |             return TypeCodePointer | 
					
						
							|  |  |  |         if self.typeName.endswith(']'): | 
					
						
							|  |  |  |             return TypeCodeArray | 
					
						
							|  |  |  |         return TypeCodeVoid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def unqualified(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def target(self): | 
					
						
							|  |  |  |         code = self.code() | 
					
						
							|  |  |  |         if code == TypeCodePointer: | 
					
						
							|  |  |  |             return FakeVoidType(self.typeName[:-1], self.dumper) | 
					
						
							|  |  |  |         if code == TypeCodeVoid: | 
					
						
							|  |  |  |             return self | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return FakeVoidType(self.typeName[:self.typeName.rindex('[')], self.dumper) | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             return FakeVoidType('void', self.dumper) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def stripTypedef(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fields(self): | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def templateArgument(self, pos, numeric): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def templateArguments(self): | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | class Dumper(DumperBase): | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         DumperBase.__init__(self) | 
					
						
							|  |  |  |         self.outputLock = threading.Lock() | 
					
						
							|  |  |  |         self.isCdb = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fromNativeValue(self, nativeValue): | 
					
						
							|  |  |  |         val = self.Value(self) | 
					
						
							| 
									
										
										
										
											2016-11-03 15:29:06 +01:00
										 |  |  |         val.name = nativeValue.name() | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |         val.type = self.fromNativeType(nativeValue.type()) | 
					
						
							| 
									
										
										
										
											2016-11-17 13:58:41 +01:00
										 |  |  |         val.isBaseClass = val.name == val.type.name | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |         val.lIsInScope = True | 
					
						
							|  |  |  |         val.laddress = nativeValue.address() | 
					
						
							|  |  |  |         return val | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |     def nativeTypeId(self, nativeType): | 
					
						
							|  |  |  |         self.check(isinstance(nativeType, cdbext.Type)) | 
					
						
							|  |  |  |         name = nativeType.name() | 
					
						
							|  |  |  |         if name is None or len(name) == 0: | 
					
						
							|  |  |  |             c = '0' | 
					
						
							|  |  |  |         elif name == 'struct {...}': | 
					
						
							|  |  |  |             c = 's' | 
					
						
							|  |  |  |         elif name == 'union {...}': | 
					
						
							|  |  |  |             c = 'u' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return name | 
					
						
							|  |  |  |         typeId = c + ''.join(['{%s:%s}' % (f.name(), self.nativeTypeId(f.type())) for f in nativeType.fields()]) | 
					
						
							|  |  |  |         return typeId | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |     def fromNativeType(self, nativeType): | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |         self.check(isinstance(nativeType, cdbext.Type)) | 
					
						
							|  |  |  |         code = nativeType.code() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 07:50:07 +01:00
										 |  |  |         if nativeType.name().startswith('void'): | 
					
						
							|  |  |  |             nativeType = FakeVoidType(nativeType.name(), self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |         if code == TypeCodePointer: | 
					
						
							| 
									
										
										
										
											2016-11-17 15:53:00 +01:00
										 |  |  |             return self.createPointerType(self.fromNativeType(nativeType.target())) | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if code == TypeCodeArray: | 
					
						
							| 
									
										
										
										
											2016-11-17 15:53:00 +01:00
										 |  |  |             targetType = self.fromNativeType(nativeType.target()) | 
					
						
							|  |  |  |             return self.createArrayType(targetType, nativeType.arrayElements()) | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         typeId = self.nativeTypeId(nativeType) | 
					
						
							|  |  |  |         if self.typeData.get(typeId, None) is None: | 
					
						
							|  |  |  |             tdata = self.TypeData(self) | 
					
						
							|  |  |  |             tdata.name = nativeType.name() | 
					
						
							|  |  |  |             tdata.typeId = typeId | 
					
						
							|  |  |  |             tdata.lbitsize = nativeType.bitsize() | 
					
						
							|  |  |  |             tdata.code = code | 
					
						
							|  |  |  |             self.registerType(typeId, tdata) # Prevent recursion in fields. | 
					
						
							| 
									
										
										
										
											2016-11-03 15:34:37 +01:00
										 |  |  |             if  code == TypeCodeStruct: | 
					
						
							|  |  |  |                 tdata.lfields = lambda value : \ | 
					
						
							|  |  |  |                     self.listFields(nativeType, value) | 
					
						
							|  |  |  |                 tdata.lalignment = lambda : \ | 
					
						
							|  |  |  |                     self.nativeStructAlignment(nativeType) | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |             tdata.templateArguments = self.listTemplateParameters(nativeType) | 
					
						
							|  |  |  |             self.registerType(typeId, tdata) # Fix up fields and template args | 
					
						
							|  |  |  |         return self.Type(self, typeId) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 15:34:37 +01:00
										 |  |  |     def listFields(self, nativeType, value): | 
					
						
							|  |  |  |         if value.address() is None or value.address() == 0: | 
					
						
							|  |  |  |             raise Exception("") | 
					
						
							|  |  |  |         nativeValue = cdbext.createValue(value.address(), nativeType) | 
					
						
							|  |  |  |         index = 0 | 
					
						
							|  |  |  |         nativeMember = nativeValue.childFromIndex(index) | 
					
						
							|  |  |  |         while nativeMember is not None: | 
					
						
							|  |  |  |             yield self.fromNativeValue(nativeMember) | 
					
						
							|  |  |  |             index += 1 | 
					
						
							|  |  |  |             nativeMember = nativeValue.childFromIndex(index) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def nativeStructAlignment(self, nativeType): | 
					
						
							|  |  |  |         #warn("NATIVE ALIGN FOR %s" % nativeType.name) | 
					
						
							|  |  |  |         def handleItem(nativeFieldType, align): | 
					
						
							|  |  |  |             a = self.fromNativeType(nativeFieldType).alignment() | 
					
						
							|  |  |  |             return a if a > align else align | 
					
						
							|  |  |  |         align = 1 | 
					
						
							|  |  |  |         for f in nativeType.fields(): | 
					
						
							|  |  |  |             align = handleItem(f.type(), align) | 
					
						
							|  |  |  |         return align | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |     def listTemplateParameters(self, nativeType): | 
					
						
							|  |  |  |         targs = [] | 
					
						
							|  |  |  |         for targ in nativeType.templateArguments(): | 
					
						
							|  |  |  |             if isinstance(targ, str): | 
					
						
							|  |  |  |                 if self.typeData.get(targ, None) is None: | 
					
						
							|  |  |  |                     targs.append(self.lookupType(targ)) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     targs.append(self.Type(self, targ)) | 
					
						
							|  |  |  |             elif isinstance(targ, int): | 
					
						
							| 
									
										
										
										
											2016-11-17 13:53:03 +01:00
										 |  |  |                 targs.append(targ) | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 error('CDBCRAP %s' % type(targ)) | 
					
						
							|  |  |  |         return targs | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def nativeTypeEnumDisplay(self, nativeType, intval): | 
					
						
							|  |  |  |         # TODO: generate fake value | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def enumExpression(self, enumType, enumValue): | 
					
						
							|  |  |  |         ns = self.qtNamespace() | 
					
						
							|  |  |  |         return ns + "Qt::" + enumType + "(" \ | 
					
						
							|  |  |  |             + ns + "Qt::" + enumType + "::" + enumValue + ")" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pokeValue(self, typeName, *args): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parseAndEvaluate(self, exp): | 
					
						
							| 
									
										
										
										
											2016-11-01 09:23:30 +01:00
										 |  |  |         val = cdbext.parseAndEvaluate(exp) | 
					
						
							|  |  |  |         if val is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         value = self.Value(self) | 
					
						
							|  |  |  |         value.type = self.lookupType('void *') | 
					
						
							|  |  |  |         value.ldata = val.to_bytes(8, sys.byteorder) | 
					
						
							|  |  |  |         return value | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def isWindowsTarget(self): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isQnxTarget(self): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isArmArchitecture(self): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isMsvcTarget(self): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 08:31:22 +01:00
										 |  |  |     def qtHookDataSymbolName(self): | 
					
						
							|  |  |  |         return 'Qt5Cored#!qtHookData' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |     def qtVersionAndNamespace(self): | 
					
						
							|  |  |  |         return ('', 0x50700) #FIXME: use a general approach in dumper or qttypes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def qtNamespace(self): | 
					
						
							|  |  |  |         return self.qtVersionAndNamespace()[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def qtVersion(self): | 
					
						
							|  |  |  |         return self.qtVersionAndNamespace()[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ptrSize(self): | 
					
						
							|  |  |  |         return cdbext.pointerSize() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def put(self, stuff): | 
					
						
							|  |  |  |         self.output += stuff | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-31 10:54:51 +01:00
										 |  |  |     def lookupType(self, typeName): | 
					
						
							|  |  |  |         if len(typeName) == 0: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         if self.typeData.get(typeName, None) is None: | 
					
						
							|  |  |  |             nativeType = self.lookupNativeType(typeName) | 
					
						
							|  |  |  |             return None if nativeType is None else self.fromNativeType(nativeType) | 
					
						
							|  |  |  |         return self.Type(self, typeName) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |     def lookupNativeType(self, name): | 
					
						
							| 
									
										
										
										
											2016-10-28 14:50:10 +02:00
										 |  |  |         if name.startswith('void'): | 
					
						
							|  |  |  |             return FakeVoidType(name, self) | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |         return cdbext.lookupType(name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def reportResult(self, result, args): | 
					
						
							|  |  |  |         self.report('result={%s}' % (result)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def readRawMemory(self, address, size): | 
					
						
							| 
									
										
										
										
											2016-11-25 13:00:03 +01:00
										 |  |  |         mem = cdbext.readRawMemory(address, size) | 
					
						
							|  |  |  |         if len(mem) != size: | 
					
						
							|  |  |  |             raise Exception("Invalid memory request") | 
					
						
							|  |  |  |         return mem | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def findStaticMetaObject(self, typeName): | 
					
						
							| 
									
										
										
										
											2016-11-01 08:32:58 +01:00
										 |  |  |         ptr = self.findValueByExpression('&' + typeName + '::staticMetaObject') | 
					
						
							|  |  |  |         return ptr | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def warn(self, msg): | 
					
						
							|  |  |  |         self.put('{name="%s",value="",type="",numchild="0"},' % msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fetchVariables(self, args): | 
					
						
							|  |  |  |         (ok, res) = self.tryFetchInterpreterVariables(args) | 
					
						
							|  |  |  |         if ok: | 
					
						
							|  |  |  |             self.reportResult(res, args) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-07 12:23:35 +02:00
										 |  |  |         self.setVariableFetchingOptions(args) | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.output = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.currentIName = 'local' | 
					
						
							|  |  |  |         self.put('data=[') | 
					
						
							|  |  |  |         self.anonNumber = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         variables = [] | 
					
						
							| 
									
										
										
										
											2016-12-08 15:51:49 +01:00
										 |  |  |         for val in cdbext.listOfLocals(self.partialVariable): | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |             value = self.fromNativeValue(val) | 
					
						
							| 
									
										
										
										
											2016-12-08 15:51:49 +01:00
										 |  |  |             value.name = val.name() | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |             variables.append(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.handleLocals(variables) | 
					
						
							|  |  |  |         self.handleWatches(args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-07 12:23:35 +02:00
										 |  |  |         self.put('],partial="%d"' % (len(self.partialVariable) > 0)) | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  |         self.reportResult(self.output, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def report(self, stuff): | 
					
						
							| 
									
										
										
										
											2016-10-07 11:13:11 +02:00
										 |  |  |         sys.stdout.write(stuff + "\n") | 
					
						
							| 
									
										
										
										
											2016-10-06 13:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def loadDumpers(self, args): | 
					
						
							|  |  |  |         msg = self.setupDumpers() | 
					
						
							|  |  |  |         self.reportResult(msg, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def findValueByExpression(self, exp): | 
					
						
							|  |  |  |         return cdbext.parseAndEvaluate(exp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def nativeDynamicTypeName(self, address, baseType): | 
					
						
							|  |  |  |         return None # FIXME: Seems sufficient, no idea why. | 
					
						
							| 
									
										
										
										
											2016-10-12 14:38:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def callHelper(self, rettype, value, function, args): | 
					
						
							|  |  |  |         raise Exception("cdb does not support calling functions") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def putCallItem(self, name, rettype, value, func, *args): | 
					
						
							|  |  |  |         return |