Cdbext: Optimize Qt detection.

Now supporting fast look up of linbinfix builds and
adding support for static namespace builds.

Change-Id: Iea234902e915b9a9d08ccf804ea4a37810aaa0d8
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
David Schulz
2015-03-06 09:13:36 +01:00
parent 22b0a061b0
commit bc124ff97f
2 changed files with 98 additions and 60 deletions

View File

@@ -652,75 +652,78 @@ const QtInfo &QtInfo::get(const SymbolGroupValueContext &ctx)
typedef std::list<std::string> StringList; typedef std::list<std::string> StringList;
typedef StringList::const_iterator StringListConstIt; typedef StringList::const_iterator StringListConstIt;
// Lookup qstrdup() to hopefully get module (potential libinfix) and namespace std::string moduleName;
// Typically, this resolves to 'QtGuid4!qstrdup' and 'QtCored4!qstrdup'... std::string::size_type exclPos = std::string::npos;
const char* qstrdupSymbol = "qstrdup"; std::string::size_type libPos = std::string::npos;
StringList modulePatterns;
modulePatterns.push_back("Qt5Cored!"); const StringList &modules = SymbolGroupValue::getAllModuleNames(ctx);
modulePatterns.push_back("QtCored4!"); for (StringListConstIt module = modules.begin(), total = modules.end();
modulePatterns.push_back("*"); module != total; ++module) {
moduleName = *module;
if (moduleName.find("Qt") != std::string::npos) {
libPos = moduleName.find("Core");
if (libPos != std::string::npos)
break;
}
}
if (libPos == std::string::npos)
moduleName.clear();
else
moduleName += '!';
const char* qstrdupSymbol = "*qstrdup";
std::string qualifiedSymbol; std::string qualifiedSymbol;
std::string::size_type exclPos; do {
std::string::size_type libPos; // Lookup qstrdup() to get the core module
for (StringListConstIt modulePattern = modulePatterns.begin(), total = modulePatterns.end(); const std::string pattern = moduleName + qstrdupSymbol;
modulePattern != total; ++modulePattern) {
const std::string pattern = *modulePattern + qstrdupSymbol;
const StringList &allMatches = SymbolGroupValue::resolveSymbolName(pattern.c_str(), ctx); const StringList &allMatches = SymbolGroupValue::resolveSymbolName(pattern.c_str(), ctx);
const bool wildcardPattern = *modulePattern == "*"; if (!allMatches.empty()) {
const StringListConstIt match = wildcardPattern qualifiedSymbol = allMatches.front();
? std::find_if(allMatches.begin(), allMatches.end(), SubStringPredicate("Core"))
: std::find_if(allMatches.begin(), allMatches.end(), SubStringPredicate(modulePattern->c_str()));
if (match != allMatches.end()) {
qualifiedSymbol = *match;
} else if (wildcardPattern && !allMatches.empty()) {
// Use the first qstrdup symbol if there is no Core in all available qstrdup symbols
// This is useful when qt is statically linked.
qualifiedSymbol = *allMatches.begin();
} else { } else {
// If we haven't found a match and this isn't the wildcard pattern we continue if (!moduleName.empty()) {
// we could still find a dynamic qt library with a libinfix // If there is no qstrdup symbol in the module fall back to a global lookup.
continue; moduleName.clear();
continue;
}
} }
exclPos = qualifiedSymbol.find('!'); // Resolved: 'QtCored4!qstrdup' exclPos = qualifiedSymbol.find('!');
libPos = qualifiedSymbol.find("Core"); libPos = qualifiedSymbol.find("Core");
if (exclPos != std::string::npos && libPos != std::string::npos)
break;
}
if (exclPos != std::string::npos) { if (exclPos != std::string::npos) {
if (libPos != std::string::npos) { if (!moduleName.empty()) {
// found the core module // found the core module
// determine the qt version from the module name // determine the qt version from the module name
if (isdigit(qualifiedSymbol.at(2))) if (isdigit(qualifiedSymbol.at(2)))
rc.version = qualifiedSymbol.at(2) - '0'; rc.version = qualifiedSymbol.at(2) - '0';
else else
rc.version = qualifiedSymbol.at(exclPos - 1) - '0'; rc.version = qualifiedSymbol.at(exclPos - 1) - '0';
rc.libInfix = qualifiedSymbol.substr(libPos + 4, exclPos - libPos - 4); rc.libInfix = qualifiedSymbol.substr(libPos + 4, exclPos - libPos - 4);
} else {
// Found the Qt symbol but in an unexpected module, most probably
// it is a static build.
rc.isStatic = true;
rc.libInfix = qualifiedSymbol.substr(0, exclPos);
// The Qt version cannot be determined by the module name. Looking up
// qInstallMessageHandler which is in Qt since 5.0 to determine the version.
const std::string pattern = rc.libInfix + "!*qInstallMessageHandler";
const StringList &allMatches = SymbolGroupValue::resolveSymbolName(pattern.c_str(), ctx);
const StringListConstIt match = std::find_if(allMatches.begin(), allMatches.end(),
SubStringPredicate(rc.libInfix.c_str()));
rc.version = match == allMatches.end() ? 4 : 5;
}
// Any namespace? 'QtCored4!nsp::qstrdup'
const std::string::size_type nameSpaceStart = exclPos + 1;
const std::string::size_type colonPos = qualifiedSymbol.find(':', nameSpaceStart);
if (colonPos != std::string::npos)
rc.nameSpace = qualifiedSymbol.substr(nameSpaceStart, colonPos - nameSpaceStart);
} else { } else {
// Found the Qt symbol but in an unexpected module, most probably // Can't find a basic Qt symbol so use a fallback
// it is a static build. rc.libInfix = "d4";
rc.isStatic = true; rc.version = 4;
rc.libInfix = qualifiedSymbol.substr(0, exclPos);
// The Qt version cannot be determined by the module name. Looking up
// qInstallMessageHandler which is in Qt since 5.0 to determine the version.
const std::string pattern = rc.libInfix + "!qInstallMessageHandler";
const StringList &allMatches = SymbolGroupValue::resolveSymbolName(pattern.c_str(), ctx);
const StringListConstIt match = std::find_if(allMatches.begin(), allMatches.end(),
SubStringPredicate(rc.libInfix.c_str()));
rc.version = match == allMatches.end() ? 4 : 5;
} }
// Any namespace? 'QtCored4!nsp::qstrdup' } while (false);
const std::string::size_type nameSpaceStart = exclPos + 1;
const std::string::size_type colonPos = qualifiedSymbol.find(':', nameSpaceStart);
if (colonPos != std::string::npos)
rc.nameSpace = qualifiedSymbol.substr(nameSpaceStart, colonPos - nameSpaceStart);
} else {
// Can't find a basic Qt symbol so use a fallback
rc.libInfix = "d4";
rc.version = 4;
}
rc.qObjectType = rc.prependQtCoreModule("QObject"); rc.qObjectType = rc.prependQtCoreModule("QObject");
rc.qObjectPrivateType = rc.prependQtCoreModule("QObjectPrivate"); rc.qObjectPrivateType = rc.prependQtCoreModule("QObjectPrivate");
@@ -842,6 +845,38 @@ SymbolGroupValue::SymbolList
return rc; return rc;
} }
std::list<std::string> SymbolGroupValue::getAllModuleNames(const SymbolGroupValueContext &c,
std::string *errorMessage)
{
enum { bufSize = 2048 };
std::list<std::string> rc;
ULONG moduleCount = 0;
ULONG unloaded = 0;
HRESULT hr = c.symbols->GetNumberModules(&moduleCount, &unloaded);
if (FAILED(hr)) {
if (errorMessage)
*errorMessage = msgDebugEngineComFailed("GetNumberModules", hr);
return rc;
}
moduleCount += unloaded;
// lookup module names
char moduleBuffer[bufSize];
for (ULONG index = 0; index < moduleCount; ++index) {
hr = c.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index,
NULL, moduleBuffer, bufSize - 1, NULL);
if (FAILED(hr)) {
if (errorMessage)
*errorMessage = msgDebugEngineComFailed("GetNumberModules", hr);
return rc;
}
rc.push_back(moduleBuffer);
}
return rc;
}
// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString') // Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString')
std::string SymbolGroupValue::resolveType(const std::string &typeIn, std::string SymbolGroupValue::resolveType(const std::string &typeIn,
const SymbolGroupValueContext &ctx, const SymbolGroupValueContext &ctx,

View File

@@ -139,6 +139,9 @@ public:
const SymbolGroupValueContext &c, const SymbolGroupValueContext &c,
std::string *errorMessage = 0); std::string *errorMessage = 0);
static std::list<std::string> getAllModuleNames(const SymbolGroupValueContext &c,
std::string *errorMessage = 0);
static unsigned char *readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length, static unsigned char *readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
std::string *errorMessage = 0); std::string *errorMessage = 0);
static ULONG64 readPointerValue(CIDebugDataSpaces *ds, ULONG64 address, static ULONG64 readPointerValue(CIDebugDataSpaces *ds, ULONG64 address,