From 1b5d8a84f808af4fe7c586719789e218289eb68d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 31 Jan 2017 09:14:47 +0100 Subject: [PATCH] Debugger: Let the python bridge handle reference types Create pointer and array types in the python code. Uses the type cache which leads to less type lookup calls. Change-Id: I970bbb04da2e8051ed66b4b12dfb62076d7f214d Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 22 ++- src/libs/qtcreatorcdbext/pycdbextmodule.cpp | 7 +- src/libs/qtcreatorcdbext/pyfield.cpp | 4 +- src/libs/qtcreatorcdbext/pytype.cpp | 141 ++++++++------------ src/libs/qtcreatorcdbext/pytype.h | 7 +- 5 files changed, 75 insertions(+), 106 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index 23fe7c95105..021c4bf5146 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -66,6 +66,15 @@ class FakeVoidType(cdbext.Type): except: return FakeVoidType('void', self.dumper) + def targetName(self): + return self.target().name() + + def arrayElements(self): + try: + return int(self.typeName[self.typeName.rindex('[') + 1:self.typeName.rindex(']')]) + except: + return 0 + def stripTypedef(self): return self @@ -137,11 +146,10 @@ class Dumper(DumperBase): nativeType = FakeVoidType(nativeType.name(), self) if code == TypeCodePointer: - return self.createPointerType(self.fromNativeType(nativeType.target())) + return self.createPointerType(self.lookupType(nativeType.targetName(), nativeType.moduleId())) if code == TypeCodeArray: - targetType = self.fromNativeType(nativeType.target()) - return self.createArrayType(targetType, nativeType.arrayElements()) + return self.createArrayType(self.lookupType(nativeType.targetName(), nativeType.moduleId()), nativeType.arrayElements()) typeId = self.nativeTypeId(nativeType) if self.typeData.get(typeId, None) is None: @@ -389,19 +397,19 @@ class Dumper(DumperBase): else: return typeName - def lookupType(self, typeNameIn): + def lookupType(self, typeNameIn, module = 0): if len(typeNameIn) == 0: return None typeName = self.stripQintTypedefs(typeNameIn) if self.typeData.get(typeName, None) is None: - nativeType = self.lookupNativeType(typeName) + nativeType = self.lookupNativeType(typeName, module) return None if nativeType is None else self.fromNativeType(nativeType) return self.Type(self, typeName) - def lookupNativeType(self, name): + def lookupNativeType(self, name, module = 0): if name.startswith('void'): return FakeVoidType(name, self) - return cdbext.lookupType(name) + return cdbext.lookupType(name, module) def reportResult(self, result, args): self.report('result={%s}' % (result)) diff --git a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp index abd466b33d7..d3866b611bb 100644 --- a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp +++ b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp @@ -169,9 +169,10 @@ static PyObject *cdbext_getNameByAddress(PyObject *, PyObject *args) static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type { char *type; - if (!PyArg_ParseTuple(args, "s", &type)) + ULONG64 module; + if (!PyArg_ParseTuple(args, "sK", &type, &module)) Py_RETURN_NONE; - return createPythonObject(PyType::lookupType(type)); + return createPythonObject(PyType::lookupType(type, module)); } static PyObject *cdbext_listOfLocals(PyObject *, PyObject *args) // -> [ Value ] @@ -299,7 +300,7 @@ static PyObject *cdbext_createValue(PyObject *, PyObject *args) if (offset == address) { DEBUG_SYMBOL_PARAMETERS params; if (SUCCEEDED(symbolGroup->GetSymbolParameters(index, 1, ¶ms))) { - if (params.TypeId == type->impl->getTypeId() && params.Module == type->impl->getModule()) + if (params.TypeId == type->impl->getTypeId() && params.Module == type->impl->moduleId()) break; } } diff --git a/src/libs/qtcreatorcdbext/pyfield.cpp b/src/libs/qtcreatorcdbext/pyfield.cpp index 96afe60969f..75f0ebf28c2 100644 --- a/src/libs/qtcreatorcdbext/pyfield.cpp +++ b/src/libs/qtcreatorcdbext/pyfield.cpp @@ -46,9 +46,9 @@ PyField::PyField(std::string name, const PyType &parentType) auto extcmd = ExtensionCommandContext::instance(); unsigned long typeID = 0; if (SUCCEEDED(extcmd->symbols()->GetFieldTypeAndOffset( - d->parentType.getModule(), d->parentType.getTypeId(), d->name.c_str(), + d->parentType.moduleId(), d->parentType.getTypeId(), d->name.c_str(), &typeID, &d->offset))) { - d->type = PyType(d->parentType.getModule(), typeID); + d->type = PyType(d->parentType.moduleId(), typeID); } } diff --git a/src/libs/qtcreatorcdbext/pytype.cpp b/src/libs/qtcreatorcdbext/pytype.cpp index 668b5795bc7..d984d1c8be7 100644 --- a/src/libs/qtcreatorcdbext/pytype.cpp +++ b/src/libs/qtcreatorcdbext/pytype.cpp @@ -81,12 +81,13 @@ static bool isArrayPointerAtPosition(const std::string &typeName, size_t positio static bool isArrayType(const std::string &typeName) { - if (typeName.empty() || typeName.back() != ']') + if (typeName.empty() || typeName.back() != ']' || (typeName.find('[') == std::string::npos)) return false; // check for types like "int (*)[3]" which is a pointer to an integer array with 3 elements const auto arrayPosition = typeName.find_first_of('['); - return arrayPosition == std::string::npos - || arrayPosition < 3 || !isArrayPointerAtPosition(typeName, arrayPosition - 3); + const bool isArrayPointer = arrayPosition != std::string::npos + && arrayPosition >= 3 && isArrayPointerAtPosition(typeName, arrayPosition - 3); + return !isArrayPointer && (typeName.compare(0, 8, "__fptr()") != 0); } static ULONG extractArraySize(const std::string &typeName, size_t openArrayPos = 0) @@ -211,31 +212,10 @@ PyType::PyType(ULONG64 module, unsigned long typeId, const std::string &name) m_name.erase(0, 6); if (m_name == " *") m_name.erase(10); - - const std::string &typeName = this->name(); - if (isPointerType(typeName)) { - m_targetType.reset(new PyType(lookupType(stripPointerType(typeName), m_module))); - } else if (isArrayType(typeName)) { - const size_t openArrayPos = typeName.find_last_of('['); - if (openArrayPos != std::string::npos) { - m_targetType.reset(new PyType(lookupType(typeName.substr(0, openArrayPos), module))); - m_arraySize = extractArraySize(typeName, openArrayPos); - } - } } std::string PyType::name(bool withModule) const { - if (m_targetType && m_targetType->isValid()) { - std::ostringstream str; - str << m_targetType->name(withModule); - if (m_arraySize) - str << '[' << m_arraySize << ']'; - else - str << '*'; - return str.str(); - } - if (m_name.empty()) { auto symbols = ExtensionCommandContext::instance()->symbols(); ULONG size = 0; @@ -265,12 +245,6 @@ ULONG64 PyType::bitsize() const { if (!m_resolved) return 0; - if (m_targetType && m_targetType->isValid()) { - if (m_arraySize != 0) - return m_arraySize * m_targetType->bitsize(); - if (m_arraySize == 0 || isPointerType(name())) - return pointerSize() * 8; - } ULONG size = 0; auto symbols = ExtensionCommandContext::instance()->symbols(); @@ -281,38 +255,47 @@ ULONG64 PyType::bitsize() const int PyType::code() const { - TypeCodes code = TypeCodeStruct; - if (!m_resolved) { - code = TypeCodeUnresolvable; - } else if (m_targetType) { - if (m_targetType->isValid()) - code = m_arraySize == 0 ? TypeCodePointer : TypeCodeArray; - else - code = TypeCodeUnresolvable; - } else { - const std::string &typeName = name(); - if (typeName.empty()) - TypeCodeUnresolvable; - if (typeName.find("") != std::string::npos) - code = TypeCodeFunction; - else if (isIntegralType(typeName)) - code = TypeCodeIntegral; - else if (isFloatType(typeName)) - code = TypeCodeFloat; - } - return code; + if (!m_resolved) + return TypeCodeUnresolvable; + const std::string &typeName = name(); + if (typeName.empty()) + return TypeCodeUnresolvable; + if (isPointerType(typeName)) + return TypeCodePointer; + if (isArrayType(typeName)) + return TypeCodeArray; + if (typeName.find("") != std::string::npos) + return TypeCodeFunction; + if (isIntegralType(typeName)) + return TypeCodeIntegral; + if (isFloatType(typeName)) + return TypeCodeFloat; + return TypeCodeStruct; } PyType PyType::target() const { - return (m_targetType && m_targetType->isValid()) ? *m_targetType : PyType(); + const std::string &typeName = name(); + if (isPointerType(typeName) || isArrayType(typeName)) + return lookupType(targetName(), m_module); + return PyType(); +} + +std::string PyType::targetName() const +{ + const std::string &typeName = name(); + if (isPointerType(typeName)) + return stripPointerType(typeName); + if (isArrayType(typeName)) + return typeName.substr(0, typeName.find_last_of('[')); + return typeName; } PyFields PyType::fields() const { CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); PyFields fields; - if (m_targetType && m_targetType->isValid()) + if (isArrayType(name()) || isPointerType(name())) return fields; for (ULONG fieldIndex = 0;; ++fieldIndex) { ULONG size = 0; @@ -330,8 +313,6 @@ PyFields PyType::fields() const std::string PyType::module() const { - if (m_targetType && m_targetType->isValid()) - return m_targetType->module(); CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); ULONG size; symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID, m_module, NULL, 0, &size); @@ -343,9 +324,14 @@ std::string PyType::module() const return std::string(); } +ULONG64 PyType::moduleId() const +{ + return m_module; +} + int PyType::arrayElements() const { - return m_arraySize; + return extractArraySize(name()); } PyType::TemplateArguments PyType::templateArguments() @@ -379,15 +365,8 @@ PyType PyType::lookupType(const std::string &typeNameIn, ULONG64 module) trimBack(typeName); trimFront(typeName); - if (isPointerType(typeName)) - return createPointerType(lookupType(stripPointerType(typeName), module)); - if (isArrayType(typeName)) { - size_t openArrayPos = typeName.find_last_of('['); - if (openArrayPos == std::string::npos) - return createUnresolvedType(typeName); - return createArrayType(lookupType(typeName.substr(0, openArrayPos), module), - extractArraySize(typeName, openArrayPos)); - } + if (isPointerType(typeName) || isArrayType(typeName)) + return PyType(0, 0, typeName); if (typeName.find("enum ") == 0) typeName.erase(0, 5); @@ -398,10 +377,10 @@ PyType PyType::lookupType(const std::string &typeNameIn, ULONG64 module) CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); ULONG typeId; - HRESULT result; - if (module != 0) + HRESULT result = S_FALSE; + if (module != 0 && !isIntegralType(typeName) && !isFloatType(typeName)) result = symbols->GetTypeId(module, typeName.c_str(), &typeId); - else + if (FAILED(result) || result == S_FALSE) result = symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module); if (FAILED(result)) return createUnresolvedType(typeName); @@ -416,28 +395,6 @@ PyType PyType::createUnresolvedType(const std::string &typeName) return unresolvedType; } -PyType PyType::createPointerType(const PyType &targetType) -{ - PyType pointerType; - pointerType.m_targetType.reset(new PyType(targetType)); - pointerType.m_resolved = true; - return pointerType; -} - -PyType PyType::createArrayType(const PyType &elementType, unsigned long size) -{ - PyType arrayType; - arrayType.m_targetType.reset(new PyType(elementType)); - arrayType.m_resolved = true; - arrayType.m_arraySize = size; - return arrayType; -} - -ULONG64 PyType::getModule() const -{ - return m_module; -} - unsigned long PyType::getTypeId() const { return m_typeId; @@ -459,9 +416,11 @@ PY_FUNC(bitsize, PY_OBJ_NAME, "k") PY_FUNC(code, PY_OBJ_NAME, "k") PY_FUNC_RET_SELF(unqualified, PY_OBJ_NAME) PY_FUNC_RET_OBJECT(target, PY_OBJ_NAME) +PY_FUNC_RET_STD_STRING(targetName, PY_OBJ_NAME) PY_FUNC_RET_SELF(stripTypedef, PY_OBJ_NAME) PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME) PY_FUNC_RET_STD_STRING(module, PY_OBJ_NAME) +PY_FUNC(moduleId, PY_OBJ_NAME, "K") PY_FUNC(arrayElements, PY_OBJ_NAME, "k") PY_FUNC_DECL(templateArguments, PY_OBJ_NAME) { @@ -484,12 +443,16 @@ static PyMethodDef typeMethods[] = { "Type without const/volatile"}, {"target", PyCFunction(target), METH_NOARGS, "Type dereferenced if it is a pointer type, element if array etc"}, + {"targetName", PyCFunction(targetName), METH_NOARGS, + "Typename dereferenced if it is a pointer type, element if array etc"}, {"stripTypedef", PyCFunction(stripTypedef), METH_NOARGS, "Type with typedefs removed"}, {"fields", PyCFunction(fields), METH_NOARGS, "List of fields (member and base classes) of this type"}, {"module", PyCFunction(module), METH_NOARGS, "Returns name for the module containing this type"}, + {"moduleId", PyCFunction(moduleId), METH_NOARGS, + "Returns id for the module containing this type"}, {"arrayElements", PyCFunction(arrayElements), METH_NOARGS, "Returns the number of elements in an array or 0 for non array types"}, {"templateArguments", PyCFunction(templateArguments), METH_NOARGS, diff --git a/src/libs/qtcreatorcdbext/pytype.h b/src/libs/qtcreatorcdbext/pytype.h index 108579157e3..fe0c2e5f3e5 100644 --- a/src/libs/qtcreatorcdbext/pytype.h +++ b/src/libs/qtcreatorcdbext/pytype.h @@ -43,8 +43,10 @@ public: ULONG64 bitsize() const; int code() const; PyType target() const; + std::string targetName() const; PyFields fields() const; std::string module() const; + ULONG64 moduleId() const; int arrayElements() const; struct TemplateArgument @@ -61,7 +63,6 @@ public: TemplateArguments templateArguments(); - ULONG64 getModule() const; unsigned long getTypeId() const; bool isValid() const; @@ -69,13 +70,9 @@ public: private: static PyType createUnresolvedType(const std::string &typeName); - static PyType createPointerType(const PyType &pointerType); - static PyType createArrayType(const PyType &targetType, unsigned long size); unsigned long m_typeId = 0; ULONG64 m_module = 0; - unsigned long m_arraySize = 0; - std::shared_ptr m_targetType; bool m_resolved = false; mutable std::string m_name; };