Commit 7e054be6 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

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.
parent 8b6dfab9
......@@ -43,6 +43,8 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
typedef std::vector<int>::size_type VectorIndexType;
enum { debugVector = 0 };
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
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);
}
// 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).
static inline int msvcStdVectorSize(const SymbolGroupValue &v)
{
......@@ -89,7 +103,7 @@ static inline int msvcStdVectorSize(const SymbolGroupValue &v)
return 0;
// Subtract the pointers: We need to do the pointer arithmetics ourselves
// 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());
if (size == 0)
return -1;
......@@ -324,10 +338,15 @@ static inline AbstractSymbolGroupNodePtrVector
SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
if (!myFirst)
myFirst = vec["_Myfirst"]; // MSVC2008
if (myFirst)
if (const ULONG64 address = myFirst.pointerValue())
return arrayChildList(n->symbolGroup(), address,
SymbolGroupValue::stripPointerType(myFirst.type()), count);
if (myFirst) {
if (const ULONG64 address = myFirst.pointerValue()) {
const std::string firstType = myFirst.type();
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();
}
......@@ -620,9 +639,12 @@ static inline AbstractSymbolGroupNodePtrVector
// QVector<T>: p/array is declared as array of T. Dereference first
// element to obtain address.
const SymbolGroupValue vec(n, ctx);
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)])
if (const ULONG64 arrayAddress = firstElementV.address())
return arrayChildList(n->symbolGroup(), arrayAddress, firstElementV.type(), count);
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
if (const ULONG64 arrayAddress = firstElementV.address()) {
const std::string fixedInnerType = fixInnerType(firstElementV.type(), ctx);
return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count);
}
}
}
return AbstractSymbolGroupNodePtrVector();
}
......@@ -663,7 +685,7 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = v.innerTypes();
if (innerTypes.size() != 1)
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());
if (!innerTypeSize)
return AbstractSymbolGroupNodePtrVector();
......
......@@ -38,12 +38,19 @@
enum KnownType
{
KT_Unknown =0,
KT_Qt_Type = 0x10000,
KT_Qt_PrimitiveType = 0x20000,
KT_Qt_MovableType = 0x40000,
KT_STL_Type = 0x80000,
KT_ContainerType = 0x100000,
KT_HasSimpleDumper = 0x200000,
KT_POD_Type = 0x10000,
KT_Qt_Type = 0x20000,
KT_Qt_PrimitiveType = 0x40000,
KT_Qt_MovableType = 0x80000,
KT_STL_Type = 0x100000,
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
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
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_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5,
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
......@@ -252,7 +252,7 @@ std::string SymbolGroupValue::error() const
bool SymbolGroupValue::isPointerType(const std::string &t)
{
return endsWith(t, " *");
return endsWith(t, '*');
}
unsigned SymbolGroupValue::pointerSize()
......@@ -277,7 +277,25 @@ unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field)
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)
......@@ -371,13 +389,7 @@ std::string QtInfo::prependModuleAndNameSpace(const std::string &type,
const std::string &aNameSpace)
{
// Strip the prefixes "class ", "struct ".
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);
}
std::string rc = SymbolGroupValue::stripClassPrefixes(type);
// Is the namespace 'nsp::' missing?
if (!aNameSpace.empty()) {
const bool nameSpaceMissing = rc.size() <= aNameSpace.size()
......@@ -440,6 +452,42 @@ std::list<std::string>
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"
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 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).
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.
const std::wstring::size_type compareLen =
......@@ -901,20 +986,23 @@ KnownType knownType(const std::string &type, bool hasClassPrefix)
{
if (type.empty())
return KT_Unknown;
const KnownType podType = knownPODTypeHelper(type);
if (podType != KT_Unknown)
return podType;
if (hasClassPrefix) {
switch (type.at(0)) { // Check 'class X' or 'struct X'
case 'c':
if (!type.compare(0, 6, "class "))
return knownTypeHelper(type, 6);
return knownClassTypeHelper(type, 6);
break;
case 's':
if (!type.compare(0, 7, "struct "))
return knownTypeHelper(type, 7);
return knownClassTypeHelper(type, 7);
break;
}
} else {
// No prefix, full check
return knownTypeHelper(type, 0);
return knownClassTypeHelper(type, 0);
}
return KT_Unknown;
}
......
......@@ -101,9 +101,15 @@ public:
// Offset of structure field: "!moduleQMapNode<K,T>", "value".
static unsigned fieldOffset(const char *type, const char *field);
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 stripArrayType(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,
const SymbolGroupValueContext &c,
std::string *errorMessage = 0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment