forked from qt-creator/qt-creator
Debugger[New CDB]: Qualify some inner types by module.
in order to speed things up or make dumping of containers of classes possible. Fix a bug in stripPointerType.
This commit is contained in:
@@ -43,6 +43,8 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol
|
|||||||
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
|
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
|
||||||
typedef std::vector<int>::size_type VectorIndexType;
|
typedef std::vector<int>::size_type VectorIndexType;
|
||||||
|
|
||||||
|
enum { debugVector = 0 };
|
||||||
|
|
||||||
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
|
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
|
||||||
static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
|
static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
|
||||||
{
|
{
|
||||||
@@ -76,6 +78,18 @@ static inline void dump64bitPointerArray(std::ostream &os, const void *a, int co
|
|||||||
dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count);
|
dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix the inner type of containers (that is, make it work smoothly with AddSymbol)
|
||||||
|
// by prefixing it with the module except for well-known types like STL/Qt types
|
||||||
|
static inline std::string fixInnerType(std::string type, const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
const std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
|
||||||
|
const KnownType kt = knownType(stripped, false);
|
||||||
|
// Simple types and STL/Q-types (inexplicably) are fast.
|
||||||
|
if (kt & (KT_POD_Type|KT_Qt_Type|KT_STL_Type))
|
||||||
|
return stripped;
|
||||||
|
return SymbolGroupValue::resolveType(stripped, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// Return size from an STL vector (last/first iterators).
|
// Return size from an STL vector (last/first iterators).
|
||||||
static inline int msvcStdVectorSize(const SymbolGroupValue &v)
|
static inline int msvcStdVectorSize(const SymbolGroupValue &v)
|
||||||
{
|
{
|
||||||
@@ -89,7 +103,7 @@ static inline int msvcStdVectorSize(const SymbolGroupValue &v)
|
|||||||
return 0;
|
return 0;
|
||||||
// Subtract the pointers: We need to do the pointer arithmetics ourselves
|
// Subtract the pointers: We need to do the pointer arithmetics ourselves
|
||||||
// as we get char *pointers.
|
// as we get char *pointers.
|
||||||
const std::string innerType = SymbolGroupValue::stripPointerType(myFirstPtrV.type());
|
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v.context());
|
||||||
const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
|
const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -324,10 +338,15 @@ static inline AbstractSymbolGroupNodePtrVector
|
|||||||
SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
|
SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
|
||||||
if (!myFirst)
|
if (!myFirst)
|
||||||
myFirst = vec["_Myfirst"]; // MSVC2008
|
myFirst = vec["_Myfirst"]; // MSVC2008
|
||||||
if (myFirst)
|
if (myFirst) {
|
||||||
if (const ULONG64 address = myFirst.pointerValue())
|
if (const ULONG64 address = myFirst.pointerValue()) {
|
||||||
return arrayChildList(n->symbolGroup(), address,
|
const std::string firstType = myFirst.type();
|
||||||
SymbolGroupValue::stripPointerType(myFirst.type()), count);
|
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), ctx);
|
||||||
|
if (debugVector)
|
||||||
|
DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
|
||||||
|
return arrayChildList(n->symbolGroup(), address, innerType, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return AbstractSymbolGroupNodePtrVector();
|
return AbstractSymbolGroupNodePtrVector();
|
||||||
}
|
}
|
||||||
@@ -620,9 +639,12 @@ static inline AbstractSymbolGroupNodePtrVector
|
|||||||
// QVector<T>: p/array is declared as array of T. Dereference first
|
// QVector<T>: p/array is declared as array of T. Dereference first
|
||||||
// element to obtain address.
|
// element to obtain address.
|
||||||
const SymbolGroupValue vec(n, ctx);
|
const SymbolGroupValue vec(n, ctx);
|
||||||
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)])
|
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
|
||||||
if (const ULONG64 arrayAddress = firstElementV.address())
|
if (const ULONG64 arrayAddress = firstElementV.address()) {
|
||||||
return arrayChildList(n->symbolGroup(), arrayAddress, firstElementV.type(), count);
|
const std::string fixedInnerType = fixInnerType(firstElementV.type(), ctx);
|
||||||
|
return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return AbstractSymbolGroupNodePtrVector();
|
return AbstractSymbolGroupNodePtrVector();
|
||||||
}
|
}
|
||||||
@@ -663,7 +685,7 @@ static inline AbstractSymbolGroupNodePtrVector
|
|||||||
const std::vector<std::string> innerTypes = v.innerTypes();
|
const std::vector<std::string> innerTypes = v.innerTypes();
|
||||||
if (innerTypes.size() != 1)
|
if (innerTypes.size() != 1)
|
||||||
return AbstractSymbolGroupNodePtrVector();
|
return AbstractSymbolGroupNodePtrVector();
|
||||||
const std::string &innerType = innerTypes.front();
|
const std::string innerType = fixInnerType(innerTypes.front(), v.context());
|
||||||
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
|
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
|
||||||
if (!innerTypeSize)
|
if (!innerTypeSize)
|
||||||
return AbstractSymbolGroupNodePtrVector();
|
return AbstractSymbolGroupNodePtrVector();
|
||||||
|
|||||||
@@ -38,12 +38,19 @@
|
|||||||
enum KnownType
|
enum KnownType
|
||||||
{
|
{
|
||||||
KT_Unknown =0,
|
KT_Unknown =0,
|
||||||
KT_Qt_Type = 0x10000,
|
KT_POD_Type = 0x10000,
|
||||||
KT_Qt_PrimitiveType = 0x20000,
|
KT_Qt_Type = 0x20000,
|
||||||
KT_Qt_MovableType = 0x40000,
|
KT_Qt_PrimitiveType = 0x40000,
|
||||||
KT_STL_Type = 0x80000,
|
KT_Qt_MovableType = 0x80000,
|
||||||
KT_ContainerType = 0x100000,
|
KT_STL_Type = 0x100000,
|
||||||
KT_HasSimpleDumper = 0x200000,
|
KT_ContainerType = 0x200000,
|
||||||
|
KT_HasSimpleDumper = 0x400000,
|
||||||
|
// PODs
|
||||||
|
KT_Char = KT_POD_Type + 1,
|
||||||
|
KT_UnsignedChar = KT_POD_Type + 2,
|
||||||
|
KT_IntType = KT_POD_Type + 3, // any signed short, long, int
|
||||||
|
KT_UnsignedIntType = KT_POD_Type + 4, // any unsigned int
|
||||||
|
KT_FloatType = KT_POD_Type + 5, // float, double
|
||||||
// Qt Basic
|
// Qt Basic
|
||||||
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
|
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
|
||||||
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2,
|
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2,
|
||||||
@@ -156,7 +163,7 @@ enum KnownType
|
|||||||
KT_StdDeque = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 4,
|
KT_StdDeque = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 4,
|
||||||
KT_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5,
|
KT_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5,
|
||||||
KT_StdMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 6,
|
KT_StdMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 6,
|
||||||
KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7,
|
KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KNOWNTYPE_H
|
#endif // KNOWNTYPE_H
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ std::string SymbolGroupValue::error() const
|
|||||||
|
|
||||||
bool SymbolGroupValue::isPointerType(const std::string &t)
|
bool SymbolGroupValue::isPointerType(const std::string &t)
|
||||||
{
|
{
|
||||||
return endsWith(t, " *");
|
return endsWith(t, '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned SymbolGroupValue::pointerSize()
|
unsigned SymbolGroupValue::pointerSize()
|
||||||
@@ -277,7 +277,25 @@ unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field)
|
|||||||
|
|
||||||
std::string SymbolGroupValue::stripPointerType(const std::string &t)
|
std::string SymbolGroupValue::stripPointerType(const std::string &t)
|
||||||
{
|
{
|
||||||
return isPointerType(t) ? t.substr(0, t.size() - 2) : t;
|
// 'Foo *' -> 'Foo', 'Bar **' -> 'Bar *'.
|
||||||
|
if (endsWith(t, "**"))
|
||||||
|
return t.substr(0, t.size() - 1);
|
||||||
|
if (endsWith(t, " *"))
|
||||||
|
return t.substr(0, t.size() - 2);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip "class Foo", "struct Bar"-> "Foo", "Bar "
|
||||||
|
std::string SymbolGroupValue::stripClassPrefixes(const std::string &type)
|
||||||
|
{
|
||||||
|
std::string rc = type;
|
||||||
|
if (rc.compare(0, 6, "class ") == 0) {
|
||||||
|
rc.erase(0, 6);
|
||||||
|
} else {
|
||||||
|
if (rc.compare(0, 7, "struct ") == 0)
|
||||||
|
rc.erase(0, 7);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SymbolGroupValue::addPointerType(const std::string &t)
|
std::string SymbolGroupValue::addPointerType(const std::string &t)
|
||||||
@@ -371,13 +389,7 @@ std::string QtInfo::prependModuleAndNameSpace(const std::string &type,
|
|||||||
const std::string &aNameSpace)
|
const std::string &aNameSpace)
|
||||||
{
|
{
|
||||||
// Strip the prefixes "class ", "struct ".
|
// Strip the prefixes "class ", "struct ".
|
||||||
std::string rc = type;
|
std::string rc = SymbolGroupValue::stripClassPrefixes(type);
|
||||||
if (rc.compare(0, 6, "class ") == 0) {
|
|
||||||
rc.erase(0, 6);
|
|
||||||
} else {
|
|
||||||
if (rc.compare(0, 7, "struct ") == 0)
|
|
||||||
rc.erase(0, 7);
|
|
||||||
}
|
|
||||||
// Is the namespace 'nsp::' missing?
|
// Is the namespace 'nsp::' missing?
|
||||||
if (!aNameSpace.empty()) {
|
if (!aNameSpace.empty()) {
|
||||||
const bool nameSpaceMissing = rc.size() <= aNameSpace.size()
|
const bool nameSpaceMissing = rc.size() <= aNameSpace.size()
|
||||||
@@ -440,6 +452,42 @@ std::list<std::string>
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString')
|
||||||
|
std::string SymbolGroupValue::resolveType(const std::string &type, const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
enum { BufSize = 512 };
|
||||||
|
|
||||||
|
if (type.empty() || type.find('!') != std::string::npos)
|
||||||
|
return type;
|
||||||
|
|
||||||
|
const std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
|
||||||
|
|
||||||
|
// Obtain the base address of the module using an obscure ioctl() call.
|
||||||
|
// See inline implementation of GetTypeSize() and docs.
|
||||||
|
SYM_DUMP_PARAM symParameters = { sizeof (SYM_DUMP_PARAM), (PUCHAR)stripped.c_str(), DBG_DUMP_NO_PRINT, 0,
|
||||||
|
NULL, NULL, NULL, 0, NULL };
|
||||||
|
const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size);
|
||||||
|
if (!typeSize || !symParameters.ModBase) // Failed?
|
||||||
|
return type;
|
||||||
|
ULONG index = 0;
|
||||||
|
ULONG64 base = 0;
|
||||||
|
// Convert module base address to module index
|
||||||
|
HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return type;
|
||||||
|
// Obtain module name
|
||||||
|
char buf[BufSize];
|
||||||
|
buf[0] = '\0';
|
||||||
|
hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return type;
|
||||||
|
|
||||||
|
std::string rc = buf;
|
||||||
|
rc.push_back('!');
|
||||||
|
rc += type;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// get the inner types: "QMap<int, double>" -> "int", "double"
|
// get the inner types: "QMap<int, double>" -> "int", "double"
|
||||||
std::vector<std::string> SymbolGroupValue::innerTypesOf(const std::string &t)
|
std::vector<std::string> SymbolGroupValue::innerTypesOf(const std::string &t)
|
||||||
{
|
{
|
||||||
@@ -567,8 +615,45 @@ static inline void formatMilliSeconds(std::wostream &str, int milliSecs)
|
|||||||
static const char stdStringTypeC[] = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
|
static const char stdStringTypeC[] = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
|
||||||
static const char stdWStringTypeC[] = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
|
static const char stdWStringTypeC[] = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
|
||||||
|
|
||||||
|
static KnownType knownPODTypeHelper(const std::string &type)
|
||||||
|
{
|
||||||
|
if (type.empty())
|
||||||
|
return KT_Unknown;
|
||||||
|
switch (type.at(0)) {
|
||||||
|
case 'c':
|
||||||
|
if (type == "char")
|
||||||
|
return KT_Char;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
if (type == "double")
|
||||||
|
return KT_FloatType;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (type == "float")
|
||||||
|
return KT_FloatType;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (!type.compare(0, 4, "long"))
|
||||||
|
return KT_IntType;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
if (!type.compare(0, 3, "int"))
|
||||||
|
return KT_IntType;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (!type.compare(0, 5, "short"))
|
||||||
|
return KT_IntType;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (!type.compare(0, 8, "unsigned"))
|
||||||
|
return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return KT_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine type starting from a position (with/without 'class '/'struct ' prefix).
|
// Determine type starting from a position (with/without 'class '/'struct ' prefix).
|
||||||
static KnownType knownTypeHelper(const std::string &type, std::string::size_type pos)
|
static KnownType knownClassTypeHelper(const std::string &type, std::string::size_type pos)
|
||||||
{
|
{
|
||||||
// Strip pointer types.
|
// Strip pointer types.
|
||||||
const std::wstring::size_type compareLen =
|
const std::wstring::size_type compareLen =
|
||||||
@@ -901,20 +986,23 @@ KnownType knownType(const std::string &type, bool hasClassPrefix)
|
|||||||
{
|
{
|
||||||
if (type.empty())
|
if (type.empty())
|
||||||
return KT_Unknown;
|
return KT_Unknown;
|
||||||
|
const KnownType podType = knownPODTypeHelper(type);
|
||||||
|
if (podType != KT_Unknown)
|
||||||
|
return podType;
|
||||||
if (hasClassPrefix) {
|
if (hasClassPrefix) {
|
||||||
switch (type.at(0)) { // Check 'class X' or 'struct X'
|
switch (type.at(0)) { // Check 'class X' or 'struct X'
|
||||||
case 'c':
|
case 'c':
|
||||||
if (!type.compare(0, 6, "class "))
|
if (!type.compare(0, 6, "class "))
|
||||||
return knownTypeHelper(type, 6);
|
return knownClassTypeHelper(type, 6);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (!type.compare(0, 7, "struct "))
|
if (!type.compare(0, 7, "struct "))
|
||||||
return knownTypeHelper(type, 7);
|
return knownClassTypeHelper(type, 7);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No prefix, full check
|
// No prefix, full check
|
||||||
return knownTypeHelper(type, 0);
|
return knownClassTypeHelper(type, 0);
|
||||||
}
|
}
|
||||||
return KT_Unknown;
|
return KT_Unknown;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,9 +101,15 @@ public:
|
|||||||
// Offset of structure field: "!moduleQMapNode<K,T>", "value".
|
// Offset of structure field: "!moduleQMapNode<K,T>", "value".
|
||||||
static unsigned fieldOffset(const char *type, const char *field);
|
static unsigned fieldOffset(const char *type, const char *field);
|
||||||
static std::string stripPointerType(const std::string &);
|
static std::string stripPointerType(const std::string &);
|
||||||
|
// Strip "class ", "struct "
|
||||||
|
static std::string stripClassPrefixes(const std::string &);
|
||||||
static std::string addPointerType(const std::string &);
|
static std::string addPointerType(const std::string &);
|
||||||
static std::string stripArrayType(const std::string &);
|
static std::string stripArrayType(const std::string &);
|
||||||
static bool isPointerType(const std::string &);
|
static bool isPointerType(const std::string &);
|
||||||
|
// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString')
|
||||||
|
// Some operations on types (like adding symbols may fail non-deterministically
|
||||||
|
// or be slow when the module specification is omitted).
|
||||||
|
static std::string resolveType(const std::string &type, const SymbolGroupValueContext &ctx);
|
||||||
static std::list<std::string> resolveSymbol(const char *pattern,
|
static std::list<std::string> resolveSymbol(const char *pattern,
|
||||||
const SymbolGroupValueContext &c,
|
const SymbolGroupValueContext &c,
|
||||||
std::string *errorMessage = 0);
|
std::string *errorMessage = 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user