From 78aa94c8c682498e55c7a27b50fcd1a53da8ed7d Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Thu, 23 Aug 2012 15:23:37 +0200
Subject: [PATCH] Debugger: Improve engine detection.

Remove the RunConfiguration parameter from guessCppEngineType()
and use the DebuggerStartParameter::toolChainAbi only.

Use fillParameter() to set the debugger command and toolchain
in order to prevent mismatches.

Add logic trying to figure out the profile to fillParameters()
in case the profile passed in is 0 for the command line cases.

Use CDB matcher for post mortem and Remote CDB, fix it to
prefer 64bit CDB on 64bit OS.

Change-Id: Icedc3883fe15660303060498ab609957e6d01cd1
Reviewed-by: hjk <qthjk@ovi.com>
---
 src/plugins/debugger/debuggerplugin.cpp       | 146 ++++++++++++++----
 src/plugins/debugger/debuggerrunner.cpp       |  28 ++--
 .../debugger/debuggerstartparameters.h        |   2 +-
 3 files changed, 127 insertions(+), 49 deletions(-)

diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index b1d45f4e4ef..95abdeacbaa 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -109,6 +109,7 @@
 #include <projectexplorer/target.h>
 #include <projectexplorer/toolchain.h>
 #include <projectexplorer/toolchainmanager.h>
+#include <projectexplorer/devicesupport/deviceprocesslist.h>
 
 #include <qtsupport/qtsupportconstants.h>
 
@@ -122,6 +123,9 @@
 #include <utils/proxyaction.h>
 #include <utils/statuslabel.h>
 #include <utils/fileutils.h>
+#ifdef Q_OS_WIN
+#  include <utils/winutils.h>
+#endif
 
 #include <QComboBox>
 #include <QDockWidget>
@@ -551,10 +555,112 @@ public:
 //
 ///////////////////////////////////////////////////////////////////////
 
-void fillParameters(DebuggerStartParameters *sp, Profile *profile)
+static inline QString executableForPid(qint64 pid)
+{
+    foreach (const ProjectExplorer::DeviceProcess &p, ProjectExplorer::DeviceProcessList::localProcesses())
+        if (p.pid == pid)
+            return p.exe;
+    return QString();
+}
+
+class AbiProfileMatcher : public ProfileMatcher
+{
+public:
+    explicit AbiProfileMatcher(const QList<Abi> &abis) : m_abis(abis) {}
+    bool matches(const Profile *p) const
+    {
+        if (const ToolChain *tc = ToolChainProfileInformation::toolChain(p))
+            return m_abis.contains(tc->targetAbi());
+        return false;
+    }
+
+private:
+    const QList<Abi> m_abis;
+};
+
+class CompatibleAbiProfileMatcher : public ProfileMatcher
+{
+public:
+    explicit CompatibleAbiProfileMatcher(const QList<Abi> &abis) : m_abis(abis) {}
+    bool matches(const Profile *p) const
+    {
+        if (const ToolChain *tc = ToolChainProfileInformation::toolChain(p))
+            foreach (const Abi &a, m_abis)
+                if (a.isCompatibleWith(tc->targetAbi()))
+                    return true;
+        return false;
+    }
+
+private:
+    const QList<Abi> m_abis;
+};
+
+class CdbMatcher : ProfileMatcher
+{
+public:
+    CdbMatcher(char wordWidth = 0) : m_wordWidth(wordWidth) {}
+
+    bool matches(const Profile *profile) const
+    {
+        const ToolChain *tc = ToolChainProfileInformation::toolChain(profile);
+        QTC_ASSERT(tc, return false);
+        const Abi abi = tc->targetAbi();
+        if (abi.architecture() != Abi::X86Architecture
+            || abi.os() != Abi::WindowsOS
+            || abi.binaryFormat() != Abi::PEFormat)
+            return false;
+        if (abi.osFlavor() == Abi::WindowsMSysFlavor
+            || abi.osFlavor() == Abi::WindowsCEFlavor)
+            return false;
+        if (m_wordWidth && abi.wordWidth() != m_wordWidth)
+            return false;
+        return true;
+    }
+
+    // Find a CDB profile for debugging unknown processes.
+    // On a 64bit OS, prefer a 64bit debugger.
+    static Profile *findUniversalCdbProfile()
+    {
+#ifdef Q_OS_WIN
+        if (Utils::winIs64BitSystem()) {
+            CdbMatcher matcher64(64);
+            if (Profile *cdb64Profile = ProfileManager::instance()->find(&matcher64))
+                return cdb64Profile;
+        }
+#endif
+        CdbMatcher matcher;
+        return ProfileManager::instance()->find(&matcher);
+    }
+
+private:
+    const char m_wordWidth;
+};
+
+void fillParameters(DebuggerStartParameters *sp, const Profile *profile /* = 0 */)
 {
-    if (!profile)
-        profile = ProfileManager::instance()->defaultProfile();
+    if (!profile) {
+        // This code can only be reached when starting via the command
+        // (-debug pid or executable) without specifying a profile.
+        // Try to find a profile via ABI.
+        if (sp->executable.isEmpty()
+            && (sp->startMode == AttachExternal || sp->startMode == AttachCrashedExternal)) {
+            sp->executable = executableForPid(sp->attachPID);
+        }
+        if (!sp->executable.isEmpty()) {
+            const QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(sp->executable));
+            if (!abis.isEmpty()) {
+                AbiProfileMatcher matcher(abis);
+                profile = ProfileManager::instance()->find(&matcher);
+                if (!profile) {
+                    CompatibleAbiProfileMatcher matcher(abis);
+                    profile = ProfileManager::instance()->find(&matcher);
+                }
+            }
+        }
+        if (!profile)
+            profile = ProfileManager::instance()->defaultProfile();
+    }
+
     sp->sysRoot = SysRootProfileInformation::sysRoot(profile).toString();
     sp->debuggerCommand = DebuggerProfileInformation::debuggerCommand(profile).toString();
 
@@ -1279,8 +1385,8 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
             *errorMessage = msgParameterMissing(*it);
             return false;
         }
+        Profile *profile = 0;
         DebuggerStartParameters sp;
-        fillParameters(&sp, ProfileManager::instance()->defaultProfile());
         qulonglong pid = it->toULongLong();
         if (pid) {
             sp.startMode = AttachExternal;
@@ -1318,11 +1424,11 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
                     sp.startMessage = tr("Attaching to core file %1.").arg(sp.coreFile);
                 }
                 else if (key == QLatin1String("profile")) {
-                    Profile *profile = ProfileManager::instance()->find(Id(val));
-                    fillParameters(&sp, profile);
+                    profile = ProfileManager::instance()->find(Id(val));
                 }
             }
         }
+        fillParameters(&sp, profile);
         if (sp.startMode == StartExternal) {
             sp.displayName = tr("Executable file \"%1\"").arg(sp.executable);
             sp.startMessage = tr("Debugging file %1.").arg(sp.executable);
@@ -1342,7 +1448,7 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
             return false;
         }
         DebuggerStartParameters sp;
-        fillParameters(&sp, 0);
+        fillParameters(&sp, CdbMatcher::findUniversalCdbProfile());
         sp.startMode = AttachCrashedExternal;
         sp.crashParameter = it->section(QLatin1Char(':'), 0, 0);
         sp.attachPID = it->section(QLatin1Char(':'), 1, 1).toULongLong();
@@ -1491,35 +1597,11 @@ void DebuggerPluginPrivate::attachCore()
     DebuggerRunControlFactory::createAndScheduleRun(sp);
 }
 
-struct RemoteCdbMatcher : ProfileMatcher
-{
-    RemoteCdbMatcher() : m_hostAbi(Abi::hostAbi()) {}
-
-    bool matches(const Profile *profile) const
-    {
-        ToolChain *tc = ToolChainProfileInformation::toolChain(profile);
-        QTC_ASSERT(tc, return false);
-        Abi abi = tc->targetAbi();
-        if (abi.architecture() != m_hostAbi.architecture()
-                || abi.os() != Abi::WindowsOS
-                || abi.binaryFormat() != Abi::PEFormat
-                || abi.wordWidth() != m_hostAbi.wordWidth())
-            return false;
-        if (abi.osFlavor() == Abi::WindowsMSysFlavor
-                || abi.osFlavor() == Abi::WindowsCEFlavor)
-            return false;
-        return true;
-    }
-
-    Abi m_hostAbi;
-};
-
 void DebuggerPluginPrivate::startRemoteCdbSession()
 {
     const QString connectionKey = _("CdbRemoteConnection");
     DebuggerStartParameters sp;
-    RemoteCdbMatcher matcher;
-    Profile *profile = ProfileManager::instance()->find(&matcher);
+    Profile *profile = CdbMatcher::findUniversalCdbProfile();
     QTC_ASSERT(profile, return);
     fillParameters(&sp, profile);
     sp.startMode = AttachToRemoteServer;
diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp
index e32359c7cc8..69a084b3e5b 100644
--- a/src/plugins/debugger/debuggerrunner.cpp
+++ b/src/plugins/debugger/debuggerrunner.cpp
@@ -578,17 +578,12 @@ static DebuggerEngineType guessCppEngineTypeForAbi(const DebuggerStartParameters
     return NoEngineType;
 }
 
-static DebuggerEngineType guessCppEngineType(const DebuggerStartParameters &sp, RunConfiguration *rc)
+static DebuggerEngineType guessCppEngineType(const DebuggerStartParameters &sp)
 {
-    if (rc) {
-        if (Target *target = rc->target()) {
-            Profile *profile = target->profile();
-            if (ToolChain *tc = ToolChainProfileInformation::toolChain(profile)) {
-                DebuggerEngineType et = guessCppEngineTypeForAbi(sp, tc->targetAbi());
-                if (et != NoEngineType)
-                    return et;
-            }
-        }
+    if (sp.toolChainAbi.isValid()) {
+        const  DebuggerEngineType et = guessCppEngineTypeForAbi(sp, sp.toolChainAbi);
+        if (et != NoEngineType)
+            return et;
     }
 
     #ifdef Q_OS_WIN
@@ -628,23 +623,24 @@ static void fixupEngineTypes(DebuggerStartParameters &sp, RunConfiguration *rc)
 
     if (rc) {
         DebuggerRunConfigurationAspect *aspect = rc->debuggerAspect();
-        bool useCppDebugger = aspect->useCppDebugger();
-        bool useQmlDebugger = aspect->useQmlDebugger();
+        if (const Target *target = rc->target())
+            fillParameters(&sp, target->profile());
+        const bool useCppDebugger = aspect->useCppDebugger();
+        const bool useQmlDebugger = aspect->useQmlDebugger();
         if (useQmlDebugger) {
             if (useCppDebugger) {
                 sp.masterEngineType = QmlCppEngineType;
-                sp.firstSlaveEngineType = guessCppEngineType(sp, rc);
+                sp.firstSlaveEngineType = guessCppEngineType(sp);
                 sp.secondSlaveEngineType = QmlCppEngineType;
             } else {
                 sp.masterEngineType = QmlEngineType;
             }
         } else {
-            sp.masterEngineType = guessCppEngineType(sp, rc);
+            sp.masterEngineType = guessCppEngineType(sp);
         }
         return;
     }
-
-    sp.masterEngineType = guessCppEngineType(sp, rc);
+    sp.masterEngineType = guessCppEngineType(sp);
 }
 
 DebuggerRunControl *DebuggerRunControlFactory::doCreate
diff --git a/src/plugins/debugger/debuggerstartparameters.h b/src/plugins/debugger/debuggerstartparameters.h
index 74c7e2d5599..acb28354dbd 100644
--- a/src/plugins/debugger/debuggerstartparameters.h
+++ b/src/plugins/debugger/debuggerstartparameters.h
@@ -140,7 +140,7 @@ public:
 
 namespace Internal {
 
-void fillParameters(DebuggerStartParameters *sp, ProjectExplorer::Profile *profile);
+void fillParameters(DebuggerStartParameters *sp, const ProjectExplorer::Profile *profile = 0);
 
 } // namespace Internal
 } // namespace Debugger
-- 
GitLab