Debugger: Create reference types for arrays and pointers

Directly looking up array and pointer types is more
likely to fail than looking up the target type.

Change-Id: Icea8320e2eedd34f6d81692c5eacf50f644100bc
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2016-11-17 15:53:00 +01:00
parent 03bbd88eb1
commit 1df8f19257
3 changed files with 187 additions and 50 deletions

View File

@@ -115,14 +115,11 @@ class Dumper(DumperBase):
nativeType = FakeVoidType(nativeType.name(), self)
if code == TypeCodePointer:
targetType = self.fromNativeType(nativeType.target().unqualified())
return self.createPointerType(targetType)
return self.createPointerType(self.fromNativeType(nativeType.target()))
if code == TypeCodeArray:
nativeTargetType = nativeType.target().unqualified()
targetType = self.fromNativeType(nativeTargetType)
count = nativeType.bitsize() // nativeTargetType.bitsize()
return self.createArrayType(targetType, count)
targetType = self.fromNativeType(nativeType.target())
return self.createArrayType(targetType, nativeType.arrayElements())
typeId = self.nativeTypeId(nativeType)
if self.typeData.get(typeId, None) is None:

View File

@@ -33,8 +33,8 @@
#include "stringutils.h"
#include "symbolgroupvalue.h"
constexpr bool debugPyType = false;
constexpr bool debuggingEnabled() { return debugPyType || debugPyCdbextModule; }
constexpr bool debugPyType = true;
constexpr bool debuggingTypeEnabled() { return debugPyType || debugPyCdbextModule; }
enum TypeCodes {
TypeCodeTypedef,
@@ -53,39 +53,102 @@ enum TypeCodes {
TypeCodeUnresolvable
};
bool isArrayPointerAtPosition(const std::string &typeName, size_t position)
{
if (typeName.length() < position + 3)
return false;
return typeName.at(position) == '('
&& typeName.at(position + 1) == '*'
&& typeName.at(position + 2) == ')';
}
bool isPointerType(const std::string &typeName)
{
if (typeName.empty())
return false;
if (endsWith(typeName, '*'))
return true;
// 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);
}
bool isArrayType(const std::string &typeName)
{
if (!endsWith(typeName, ']'))
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);
}
std::string &stripPointerType(std::string &typeName)
{
if (endsWith(typeName, '*')) {
typeName.pop_back();
} else {
const auto arrayPosition = typeName.find_first_of('[');
if (arrayPosition != std::string::npos
&& arrayPosition >= 3 && isArrayPointerAtPosition(typeName, arrayPosition - 3)) {
typeName.erase(arrayPosition - 3, 3);
}
}
trimBack(typeName);
return typeName;
}
ULONG extractArrrayCount(const std::string &typeName, size_t openArrayPos = 0)
{
if (openArrayPos == 0)
openArrayPos = typeName.find_last_of('[');
const auto closeArrayPos = typeName.find_last_of(']');
if (openArrayPos == std::string::npos || closeArrayPos == std::string::npos)
return 0;
const std::string arrayCountString = typeName.substr(openArrayPos + 1,
closeArrayPos - openArrayPos - 1);
try {
return std::stoul(arrayCountString);
}
catch (const std::invalid_argument &) {} // fall through
catch (const std::out_of_range &) {} // fall through
return 0;
}
PyObject *lookupArrayType(const std::string &typeName)
{
size_t openArrayPos = typeName.find_last_of('[');
if (ULONG arrayCount = extractArrrayCount(typeName, openArrayPos))
return createArrayType(arrayCount, (Type*)lookupType(typeName.substr(0, openArrayPos)));
return createUnresolvedType(typeName);
}
PyObject *lookupType(const std::string &typeNameIn)
{
if (debuggingEnabled())
if (debuggingTypeEnabled())
DebugPrint() << "lookup type '" << typeNameIn << "'";
std::string typeName = typeNameIn;
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
trimBack(typeName);
trimFront(typeName);
if (isPointerType(typeName))
return createPointerType((Type*)lookupType(stripPointerType(typeName)));
if (SymbolGroupValue::isArrayType(typeName))
return lookupArrayType(typeName);
if (typeName.find("enum ") == 0)
typeName.erase(0, 5);
trimBack(typeName);
if (typeName == "__int64" || typeName == "unsigned __int64")
typeName.erase(typeName.find("__"), 2);
std::string fullTypeName = typeName;
// GetSymbolTypeId doesn't support pointer types so we need to strip off the '*' first
while (endsWith(typeName, '*')) {
typeName.pop_back();
trimBack(typeName);
}
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG64 module;
ULONG typeId;
if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module)))
return createUnresolvedType(typeNameIn);
if (typeName != fullTypeName) {
if (module == 0) { // found some builtin type like char so we take the first module available to look up the pointer type
ULONG loaded, unloaded;
if (FAILED(symbols->GetNumberModules(&loaded, &unloaded)))
return createUnresolvedType(typeNameIn);
if ((loaded + unloaded == 0) || FAILED(symbols->GetModuleByIndex(0, &module)))
return createUnresolvedType(typeNameIn);
}
if (FAILED(symbols->GetTypeId(module, fullTypeName.c_str(), &typeId)))
return createUnresolvedType(typeNameIn);
}
return createType(module, typeId);
return createUnresolvedType(typeName);
return createType(module, typeId, typeName);
}
char *getTypeName(ULONG64 module, ULONG typeId)
@@ -109,8 +172,19 @@ char *getTypeName(ULONG64 module, ULONG typeId)
const char *getTypeName(Type *type)
{
if (type->m_name == 0)
type->m_name = getTypeName(type->m_module, type->m_typeId);
if (type->m_name == nullptr) {
if (type->m_targetType) {
std::ostringstream str;
str << getTypeName(type->m_targetType);
if (type->m_arraySize)
str << '[' << type->m_arraySize << ']';
else
str << '*';
type->m_name = strdup(str.str().c_str());
} else {
type->m_name = getTypeName(type->m_module, type->m_typeId);
}
}
return type->m_name;
}
@@ -119,17 +193,26 @@ PyObject *type_Name(Type *self)
return Py_BuildValue("s", getTypeName(self));
}
ULONG typeBitSize(Type *type)
{
if (!type->m_resolved)
return 0;
if (type->m_targetType && type->m_arraySize != 0)
return type->m_arraySize * typeBitSize(type->m_targetType);
if ((type->m_targetType && type->m_arraySize == 0) || isPointerType(getTypeName(type)))
return pointerSize() * 8;
ULONG size = 0;
ExtensionCommandContext::instance()->symbols()->GetTypeSize(
type->m_module, type->m_typeId, &size);
if (size == 0)
return 0;
return size * 8;
}
PyObject *type_bitSize(Type *self)
{
ULONG size;
auto extcmd = ExtensionCommandContext::instance();
if (!self->m_resolved)
size = 0;
else if (endsWith(getTypeName(self), '*'))
size = SUCCEEDED(ExtensionCommandContext::instance()->control()->IsPointer64Bit()) ? 8 : 4;
else if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &size)))
Py_RETURN_NONE;
return Py_BuildValue("k", size * 8);
return Py_BuildValue("k", typeBitSize(self));
}
bool isType(const std::string &typeName, const std::vector<std::string> &types)
@@ -148,16 +231,18 @@ PyObject *type_Code(Type *self)
TypeCodes code = TypeCodeStruct;
if (!self->m_resolved) {
code = TypeCodeUnresolvable;
} else if (self->m_targetType) {
code = self->m_arraySize == 0 ? TypeCodePointer : TypeCodeArray;
} else {
const char *typeNameCstr = getTypeName(self);
if (typeNameCstr == 0)
Py_RETURN_NONE;
const std::string typeName(typeNameCstr);
if (SymbolGroupValue::isArrayType(typeName))
if (isArrayType(typeName))
code = TypeCodeArray;
else if (typeName.find("<function>") != std::string::npos)
code = TypeCodeFunction;
else if (endsWith(typeName, "*"))
else if (isPointerType(typeName))
code = TypeCodePointer;
else if (isType(typeName, integralTypes))
code = TypeCodeIntegral;
@@ -176,13 +261,19 @@ PyObject *type_Unqualified(Type *self)
PyObject *type_Target(Type *self)
{
std::string typeName(getTypeName(self));
if (endsWith(typeName, "*")) {
typeName.pop_back();
return lookupType(typeName);
if (self->m_targetType) {
auto target = reinterpret_cast<PyObject *>(self->m_targetType);
Py_IncRef(target);
return target;
}
std::string typeName(getTypeName(self));
if (isPointerType(typeName))
return lookupType(stripPointerType(typeName));
if (SymbolGroupValue::isArrayType(typeName)) {
typeName.pop_back();
while (!endsWith(typeName, '[') && !typeName.empty())
typeName.pop_back();
if (typeName.empty())
Py_RETURN_NONE;
typeName.pop_back();
return lookupType(typeName);
}
@@ -201,6 +292,8 @@ PyObject *type_Fields(Type *self)
{
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
auto fields = PyList_New(0);
if (self->m_targetType)
return fields;
for (ULONG fieldIndex = 0;; ++fieldIndex) {
ULONG fieldNameSize = 0;
symbols->GetFieldName(self->m_module, self->m_typeId, fieldIndex, NULL, 0, &fieldNameSize);
@@ -227,6 +320,8 @@ PyObject *type_Fields(Type *self)
PyObject *type_Module(Type *self)
{
if (self->m_targetType)
return type_Module(self->m_targetType);
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG size;
symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, DEBUG_ANY_ID, self->m_module, NULL, 0, &size);
@@ -241,6 +336,13 @@ PyObject *type_Module(Type *self)
return ret;
}
PyObject *type_ArrayElements(Type *self)
{
if (self->m_arraySize)
return Py_BuildValue("k", self->m_arraySize);
return Py_BuildValue("k", extractArrrayCount(getTypeName(self)));
}
std::vector<std::string> innerTypesOf(const std::string &t)
{
std::vector<std::string> rc;
@@ -319,11 +421,11 @@ PyObject *type_TemplateArgument(Type *self, PyObject *args)
PyObject *type_TemplateArguments(Type *self)
{
std::vector<std::string> innerTypes = innerTypesOf(getTypeName(self));
if (debuggingEnabled())
if (debuggingTypeEnabled())
DebugPrint() << "template arguments of: " << getTypeName(self);
auto templateArguments = PyList_New(0);
for (const std::string &innerType : innerTypes) {
if (debuggingEnabled())
if (debuggingTypeEnabled())
DebugPrint() << " template argument: " << innerType;
PyObject* childValue;
try {
@@ -358,9 +460,18 @@ void type_Dealloc(Type *self)
PyObject *createType(ULONG64 module, ULONG typeId, const std::string &name)
{
std::string typeName = SymbolGroupValue::stripClassPrefixes(name);
if (!typeName.empty()) {
if (isPointerType(typeName))
return createPointerType((Type*)lookupType(stripPointerType(typeName)));
if (isArrayType(typeName))
return lookupArrayType(typeName);
}
Type *type = PyObject_New(Type, type_pytype());
type->m_module = module;
type->m_typeId = typeId;
type->m_arraySize = 0;
type->m_targetType = nullptr;
type->m_resolved = true;
type->m_name = typeName.empty() ? nullptr : strdup(typeName.c_str());
return reinterpret_cast<PyObject *>(type);
@@ -371,11 +482,30 @@ PyObject *createUnresolvedType(const std::string &name)
Type *type = PyObject_New(Type, type_pytype());
type->m_module = 0;
type->m_typeId = 0;
type->m_arraySize = 0;
type->m_targetType = nullptr;
type->m_name = strdup(name.c_str());
type->m_resolved = false;
return reinterpret_cast<PyObject *>(type);
}
PyObject *createArrayType(ULONG arraySize, Type *targetType)
{
Type *type = PyObject_New(Type, type_pytype());
type->m_module = 0;
type->m_typeId = 0;
type->m_arraySize = arraySize;
type->m_targetType = targetType;
type->m_name = nullptr;
type->m_resolved = true;
return reinterpret_cast<PyObject *>(type);
}
PyObject *createPointerType(Type *targetType)
{
return createArrayType(0, targetType);
}
static PyMethodDef typeMethods[] = {
{"name", PyCFunction(type_Name), METH_NOARGS,
"Return the type name"},
@@ -393,6 +523,8 @@ static PyMethodDef typeMethods[] = {
"List of fields (member and base classes) of this type"},
{"module", PyCFunction(type_Module), METH_NOARGS,
"Returns name for the module containing this type"},
{"arrayElements", PyCFunction(type_ArrayElements), METH_NOARGS,
"Returns the number of elements in an array or 0 for non array types"},
{"templateArgument", PyCFunction(type_TemplateArgument), METH_VARARGS,
"Returns template argument at position"},

View File

@@ -37,6 +37,8 @@ struct Type
PyObject_HEAD
ULONG m_typeId;
ULONG64 m_module;
ULONG m_arraySize;
Type *m_targetType;
bool m_resolved;
char *m_name; // owned
};
@@ -45,5 +47,11 @@ PyTypeObject *type_pytype();
char *getTypeName(ULONG64 module, ULONG typeId);
PyObject *lookupType(const std::string &typeName);
PyObject *createType(ULONG64 module, ULONG typeId, const std::string &name = std::string());
PyObject *createUnresolvedType(const std::string &name);
PyObject *createArrayType(ULONG arraySize, Type *targetType);
PyObject *createPointerType(Type *targetType);
bool isPointerType(const std::string &typeName);
std::string &stripPointerType(std::string &typeName);