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 <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2017-01-31 09:14:47 +01:00
parent 8f93ec3020
commit 1b5d8a84f8
5 changed files with 75 additions and 106 deletions

View File

@@ -66,6 +66,15 @@ class FakeVoidType(cdbext.Type):
except: except:
return FakeVoidType('void', self.dumper) 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): def stripTypedef(self):
return self return self
@@ -137,11 +146,10 @@ class Dumper(DumperBase):
nativeType = FakeVoidType(nativeType.name(), self) nativeType = FakeVoidType(nativeType.name(), self)
if code == TypeCodePointer: if code == TypeCodePointer:
return self.createPointerType(self.fromNativeType(nativeType.target())) return self.createPointerType(self.lookupType(nativeType.targetName(), nativeType.moduleId()))
if code == TypeCodeArray: if code == TypeCodeArray:
targetType = self.fromNativeType(nativeType.target()) return self.createArrayType(self.lookupType(nativeType.targetName(), nativeType.moduleId()), nativeType.arrayElements())
return self.createArrayType(targetType, nativeType.arrayElements())
typeId = self.nativeTypeId(nativeType) typeId = self.nativeTypeId(nativeType)
if self.typeData.get(typeId, None) is None: if self.typeData.get(typeId, None) is None:
@@ -389,19 +397,19 @@ class Dumper(DumperBase):
else: else:
return typeName return typeName
def lookupType(self, typeNameIn): def lookupType(self, typeNameIn, module = 0):
if len(typeNameIn) == 0: if len(typeNameIn) == 0:
return None return None
typeName = self.stripQintTypedefs(typeNameIn) typeName = self.stripQintTypedefs(typeNameIn)
if self.typeData.get(typeName, None) is None: 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 None if nativeType is None else self.fromNativeType(nativeType)
return self.Type(self, typeName) return self.Type(self, typeName)
def lookupNativeType(self, name): def lookupNativeType(self, name, module = 0):
if name.startswith('void'): if name.startswith('void'):
return FakeVoidType(name, self) return FakeVoidType(name, self)
return cdbext.lookupType(name) return cdbext.lookupType(name, module)
def reportResult(self, result, args): def reportResult(self, result, args):
self.report('result={%s}' % (result)) self.report('result={%s}' % (result))

View File

@@ -169,9 +169,10 @@ static PyObject *cdbext_getNameByAddress(PyObject *, PyObject *args)
static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type
{ {
char *type; char *type;
if (!PyArg_ParseTuple(args, "s", &type)) ULONG64 module;
if (!PyArg_ParseTuple(args, "sK", &type, &module))
Py_RETURN_NONE; Py_RETURN_NONE;
return createPythonObject(PyType::lookupType(type)); return createPythonObject(PyType::lookupType(type, module));
} }
static PyObject *cdbext_listOfLocals(PyObject *, PyObject *args) // -> [ Value ] static PyObject *cdbext_listOfLocals(PyObject *, PyObject *args) // -> [ Value ]
@@ -299,7 +300,7 @@ static PyObject *cdbext_createValue(PyObject *, PyObject *args)
if (offset == address) { if (offset == address) {
DEBUG_SYMBOL_PARAMETERS params; DEBUG_SYMBOL_PARAMETERS params;
if (SUCCEEDED(symbolGroup->GetSymbolParameters(index, 1, &params))) { if (SUCCEEDED(symbolGroup->GetSymbolParameters(index, 1, &params))) {
if (params.TypeId == type->impl->getTypeId() && params.Module == type->impl->getModule()) if (params.TypeId == type->impl->getTypeId() && params.Module == type->impl->moduleId())
break; break;
} }
} }

View File

@@ -46,9 +46,9 @@ PyField::PyField(std::string name, const PyType &parentType)
auto extcmd = ExtensionCommandContext::instance(); auto extcmd = ExtensionCommandContext::instance();
unsigned long typeID = 0; unsigned long typeID = 0;
if (SUCCEEDED(extcmd->symbols()->GetFieldTypeAndOffset( 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))) { &typeID, &d->offset))) {
d->type = PyType(d->parentType.getModule(), typeID); d->type = PyType(d->parentType.moduleId(), typeID);
} }
} }

View File

@@ -81,12 +81,13 @@ static bool isArrayPointerAtPosition(const std::string &typeName, size_t positio
static bool isArrayType(const std::string &typeName) static bool isArrayType(const std::string &typeName)
{ {
if (typeName.empty() || typeName.back() != ']') if (typeName.empty() || typeName.back() != ']' || (typeName.find('[') == std::string::npos))
return false; return false;
// check for types like "int (*)[3]" which is a pointer to an integer array with 3 elements // check for types like "int (*)[3]" which is a pointer to an integer array with 3 elements
const auto arrayPosition = typeName.find_first_of('['); const auto arrayPosition = typeName.find_first_of('[');
return arrayPosition == std::string::npos const bool isArrayPointer = arrayPosition != std::string::npos
|| arrayPosition < 3 || !isArrayPointerAtPosition(typeName, arrayPosition - 3); && 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) 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); m_name.erase(0, 6);
if (m_name == "<function> *") if (m_name == "<function> *")
m_name.erase(10); 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 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()) { if (m_name.empty()) {
auto symbols = ExtensionCommandContext::instance()->symbols(); auto symbols = ExtensionCommandContext::instance()->symbols();
ULONG size = 0; ULONG size = 0;
@@ -265,12 +245,6 @@ ULONG64 PyType::bitsize() const
{ {
if (!m_resolved) if (!m_resolved)
return 0; 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; ULONG size = 0;
auto symbols = ExtensionCommandContext::instance()->symbols(); auto symbols = ExtensionCommandContext::instance()->symbols();
@@ -281,38 +255,47 @@ ULONG64 PyType::bitsize() const
int PyType::code() const int PyType::code() const
{ {
TypeCodes code = TypeCodeStruct; if (!m_resolved)
if (!m_resolved) { return TypeCodeUnresolvable;
code = TypeCodeUnresolvable; const std::string &typeName = name();
} else if (m_targetType) { if (typeName.empty())
if (m_targetType->isValid()) return TypeCodeUnresolvable;
code = m_arraySize == 0 ? TypeCodePointer : TypeCodeArray; if (isPointerType(typeName))
else return TypeCodePointer;
code = TypeCodeUnresolvable; if (isArrayType(typeName))
} else { return TypeCodeArray;
const std::string &typeName = name(); if (typeName.find("<function>") != std::string::npos)
if (typeName.empty()) return TypeCodeFunction;
TypeCodeUnresolvable; if (isIntegralType(typeName))
if (typeName.find("<function>") != std::string::npos) return TypeCodeIntegral;
code = TypeCodeFunction; if (isFloatType(typeName))
else if (isIntegralType(typeName)) return TypeCodeFloat;
code = TypeCodeIntegral; return TypeCodeStruct;
else if (isFloatType(typeName))
code = TypeCodeFloat;
}
return code;
} }
PyType PyType::target() const 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 PyFields PyType::fields() const
{ {
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
PyFields fields; PyFields fields;
if (m_targetType && m_targetType->isValid()) if (isArrayType(name()) || isPointerType(name()))
return fields; return fields;
for (ULONG fieldIndex = 0;; ++fieldIndex) { for (ULONG fieldIndex = 0;; ++fieldIndex) {
ULONG size = 0; ULONG size = 0;
@@ -330,8 +313,6 @@ PyFields PyType::fields() const
std::string PyType::module() const std::string PyType::module() const
{ {
if (m_targetType && m_targetType->isValid())
return m_targetType->module();
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG size; ULONG size;
symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID, m_module, NULL, 0, &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(); return std::string();
} }
ULONG64 PyType::moduleId() const
{
return m_module;
}
int PyType::arrayElements() const int PyType::arrayElements() const
{ {
return m_arraySize; return extractArraySize(name());
} }
PyType::TemplateArguments PyType::templateArguments() PyType::TemplateArguments PyType::templateArguments()
@@ -379,15 +365,8 @@ PyType PyType::lookupType(const std::string &typeNameIn, ULONG64 module)
trimBack(typeName); trimBack(typeName);
trimFront(typeName); trimFront(typeName);
if (isPointerType(typeName)) if (isPointerType(typeName) || isArrayType(typeName))
return createPointerType(lookupType(stripPointerType(typeName), module)); return PyType(0, 0, typeName);
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 (typeName.find("enum ") == 0) if (typeName.find("enum ") == 0)
typeName.erase(0, 5); typeName.erase(0, 5);
@@ -398,10 +377,10 @@ PyType PyType::lookupType(const std::string &typeNameIn, ULONG64 module)
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols(); CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG typeId; ULONG typeId;
HRESULT result; HRESULT result = S_FALSE;
if (module != 0) if (module != 0 && !isIntegralType(typeName) && !isFloatType(typeName))
result = symbols->GetTypeId(module, typeName.c_str(), &typeId); result = symbols->GetTypeId(module, typeName.c_str(), &typeId);
else if (FAILED(result) || result == S_FALSE)
result = symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module); result = symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module);
if (FAILED(result)) if (FAILED(result))
return createUnresolvedType(typeName); return createUnresolvedType(typeName);
@@ -416,28 +395,6 @@ PyType PyType::createUnresolvedType(const std::string &typeName)
return unresolvedType; 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 unsigned long PyType::getTypeId() const
{ {
return m_typeId; return m_typeId;
@@ -459,9 +416,11 @@ PY_FUNC(bitsize, PY_OBJ_NAME, "k")
PY_FUNC(code, PY_OBJ_NAME, "k") PY_FUNC(code, PY_OBJ_NAME, "k")
PY_FUNC_RET_SELF(unqualified, PY_OBJ_NAME) PY_FUNC_RET_SELF(unqualified, PY_OBJ_NAME)
PY_FUNC_RET_OBJECT(target, 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_SELF(stripTypedef, PY_OBJ_NAME)
PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME) PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME)
PY_FUNC_RET_STD_STRING(module, 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(arrayElements, PY_OBJ_NAME, "k")
PY_FUNC_DECL(templateArguments, PY_OBJ_NAME) PY_FUNC_DECL(templateArguments, PY_OBJ_NAME)
{ {
@@ -484,12 +443,16 @@ static PyMethodDef typeMethods[] = {
"Type without const/volatile"}, "Type without const/volatile"},
{"target", PyCFunction(target), METH_NOARGS, {"target", PyCFunction(target), METH_NOARGS,
"Type dereferenced if it is a pointer type, element if array etc"}, "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, {"stripTypedef", PyCFunction(stripTypedef), METH_NOARGS,
"Type with typedefs removed"}, "Type with typedefs removed"},
{"fields", PyCFunction(fields), METH_NOARGS, {"fields", PyCFunction(fields), METH_NOARGS,
"List of fields (member and base classes) of this type"}, "List of fields (member and base classes) of this type"},
{"module", PyCFunction(module), METH_NOARGS, {"module", PyCFunction(module), METH_NOARGS,
"Returns name for the module containing this type"}, "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, {"arrayElements", PyCFunction(arrayElements), METH_NOARGS,
"Returns the number of elements in an array or 0 for non array types"}, "Returns the number of elements in an array or 0 for non array types"},
{"templateArguments", PyCFunction(templateArguments), METH_NOARGS, {"templateArguments", PyCFunction(templateArguments), METH_NOARGS,

View File

@@ -43,8 +43,10 @@ public:
ULONG64 bitsize() const; ULONG64 bitsize() const;
int code() const; int code() const;
PyType target() const; PyType target() const;
std::string targetName() const;
PyFields fields() const; PyFields fields() const;
std::string module() const; std::string module() const;
ULONG64 moduleId() const;
int arrayElements() const; int arrayElements() const;
struct TemplateArgument struct TemplateArgument
@@ -61,7 +63,6 @@ public:
TemplateArguments templateArguments(); TemplateArguments templateArguments();
ULONG64 getModule() const;
unsigned long getTypeId() const; unsigned long getTypeId() const;
bool isValid() const; bool isValid() const;
@@ -69,13 +70,9 @@ public:
private: private:
static PyType createUnresolvedType(const std::string &typeName); 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; unsigned long m_typeId = 0;
ULONG64 m_module = 0; ULONG64 m_module = 0;
unsigned long m_arraySize = 0;
std::shared_ptr<PyType> m_targetType;
bool m_resolved = false; bool m_resolved = false;
mutable std::string m_name; mutable std::string m_name;
}; };