From 7f90f2942a6b712f2ddfb4b00aafb65508ac7d5f Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Wed, 19 May 2010 15:14:15 +0200
Subject: [PATCH] Debugger: Add incremental API for modules.

And use it from CDB's module load/unload callbacks
instead of re-setting all modules. Some cleanup./Fixed
conflicts in 2.0
Acked-by: hjk
---
 src/plugins/debugger/cdb/cdbdebugengine.cpp   | 20 ++++-
 src/plugins/debugger/cdb/cdbdebugengine_p.h   |  3 +-
 .../debugger/cdb/cdbdebugeventcallback.cpp    |  3 +-
 src/plugins/debugger/cdb/cdbmodules.cpp       | 58 +++++++++++---
 src/plugins/debugger/cdb/cdbmodules.h         |  2 +
 src/plugins/debugger/moduleshandler.cpp       | 79 ++++++++++++++++---
 src/plugins/debugger/moduleshandler.h         |  3 +
 7 files changed, 142 insertions(+), 26 deletions(-)

diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index afc938f2f65..30b8514a13c 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -1516,12 +1516,26 @@ void CdbDebugEnginePrivate::updateModules()
 
 static const char *dumperPrefixC = "dumper";
 
-void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
+void CdbDebugEnginePrivate::handleModuleLoad(quint64 offset, const QString &name)
 {
     if (debugCDB>2)
-        qDebug() << Q_FUNC_INFO << "\n    " << name;
+        qDebug() << Q_FUNC_INFO << "\n    " << offset << name;
+    Module module;
+    // Determine module parameters by offset. The callback has almost all the
+    // parameters we need with the exception of 'symbolsRead'. Retrieve the
+    // parameters by offset as to avoid a hack like 'check last module'.
+    QString errorMessage;
+    if (getModuleByOffset(interfaces().debugSymbols, offset, &module, &errorMessage)) {
+        manager()->modulesHandler()->addModule(module);
+    } else {
+        m_engine->warning(errorMessage);
+    }
     m_dumper->moduleLoadHook(name, m_hDebuggeeProcess);
-    updateModules();
+}
+
+void CdbDebugEnginePrivate::handleModuleUnload(const QString &imageName)
+{
+    manager()->modulesHandler()->removeModule(imageName);
 }
 
 void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 4c1b8442e4e..b8e4fe0abf5 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -87,7 +87,8 @@ public:
     void handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP);
     void cleanStackTrace();
     void clearForRun();
-    void handleModuleLoad(const QString &);
+    void handleModuleLoad(quint64 offset, const QString &);
+    void handleModuleUnload(const QString &name);
     CdbSymbolGroupContext *getSymbolGroupContext(int frameIndex, QString *errorMessage) const;
     void clearDisplay();
 
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 833bdb2d258..23d4b0f992e 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -174,7 +174,7 @@ STDMETHODIMP CdbDebugEventCallback::LoadModule(
     if (debugCDB > 1)
         qDebug() << Q_FUNC_INFO << ModuleName;
     handleModuleLoad();
-    m_pEngine->m_d->handleModuleLoad(QString::fromUtf16(reinterpret_cast<const ushort *>(ModuleName)));
+    m_pEngine->m_d->handleModuleLoad(BaseOffset, QString::fromUtf16(reinterpret_cast<const ushort *>(ModuleName)));
     return S_OK;
 }
 
@@ -188,6 +188,7 @@ STDMETHODIMP CdbDebugEventCallback::UnloadModule(
     Q_UNUSED(BaseOffset)
     if (debugCDB > 1)
         qDebug() << Q_FUNC_INFO << ImageBaseName;
+    m_pEngine->m_d->handleModuleUnload(QString::fromUtf16(reinterpret_cast<const ushort *>(ImageBaseName)));
     handleModuleUnload();
     m_pEngine->m_d->updateModules();
     return S_OK;
diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp
index 439c87b14a9..eaad0eaf730 100644
--- a/src/plugins/debugger/cdb/cdbmodules.cpp
+++ b/src/plugins/debugger/cdb/cdbmodules.cpp
@@ -63,6 +63,51 @@ bool getModuleNameList(CIDebugSymbols *syms, QStringList *modules, QString *erro
     return true;
 }
 
+// Get basic module parameters from struct (except name)
+static inline void getBasicModuleParameters(const DEBUG_MODULE_PARAMETERS &p,
+                                            Module *module)
+{
+    const QString hexPrefix = QLatin1String("0x");
+    module->symbolsRead = (p.Flags & DEBUG_MODULE_USER_MODE)
+                          && (p.SymbolType != DEBUG_SYMTYPE_NONE);
+    module->startAddress = hexPrefix + QString::number(p.Base, 16);
+    module->endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
+}
+
+// Get module name by index
+static inline bool getModuleName(CIDebugSymbols *syms, ULONG index, QString *n, QString *errorMessage)
+{
+    WCHAR wszBuf[MAX_PATH];
+    const HRESULT hr = syms->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, index, 0, wszBuf, MAX_PATH - 1, 0);
+    if (FAILED(hr) && hr != E_INVALIDARG) {
+        *errorMessage= CdbCore::msgComFailed("GetModuleNameStringWide", hr);
+        return false;
+    }
+    *n = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+    return true;
+}
+
+bool getModuleByOffset(CIDebugSymbols *syms, quint64 offset,
+                       Module *module, QString *errorMessage)
+{
+    // Find by base address and set parameters
+    ULONG index;
+    HRESULT hr = syms->GetModuleByOffset(offset, 0, &index, 0);
+    if (FAILED(hr)) {
+        *errorMessage= CdbCore::msgComFailed("GetModuleByOffset", hr);
+        return false;
+    }
+    DEBUG_MODULE_PARAMETERS parameters;
+    memset(&parameters, 0, sizeof(DEBUG_MODULE_PARAMETERS));
+    hr = syms->GetModuleParameters(1, 0, 0u, &parameters);
+    if (FAILED(hr)) {
+        *errorMessage= CdbCore::msgComFailed("GetModuleParameters", hr);
+        return false;
+    }
+    getBasicModuleParameters(parameters, module);
+    return getModuleName(syms, index, &(module->moduleName), errorMessage);
+}
+
 bool getModuleList(CIDebugSymbols *syms, QList<Module> *modules, QString *errorMessage)
 {
     ULONG count;
@@ -79,22 +124,13 @@ bool getModuleList(CIDebugSymbols *syms, QList<Module> *modules, QString *errorM
         return false;
     }
     // fill array
-    const QString hexPrefix = QLatin1String("0x");
-    WCHAR wszBuf[MAX_PATH];
     for (ULONG m = 0; m < count; m++) {
         const DEBUG_MODULE_PARAMETERS &p = parameters.at(m);
         if (p.Base != DEBUG_INVALID_OFFSET) { // Partial results?
             Module module;
-            module.symbolsRead = (p.Flags & DEBUG_MODULE_USER_MODE)
-                            && (p.SymbolType != DEBUG_SYMTYPE_NONE);
-            module.startAddress = hexPrefix + QString::number(p.Base, 16);
-            module.endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
-            hr = syms->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0);
-            if (FAILED(hr) && hr != E_INVALIDARG) {
-                *errorMessage= CdbCore::msgComFailed("GetModuleNameStringWide", hr);
+            getBasicModuleParameters(p, &module);
+            if (!getModuleName(syms, m, &(module.moduleName), errorMessage))
                 return false;
-            }
-            module.moduleName = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
             modules->push_back(module);
         }
     }
diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h
index 768e9b495d4..792ba526fac 100644
--- a/src/plugins/debugger/cdb/cdbmodules.h
+++ b/src/plugins/debugger/cdb/cdbmodules.h
@@ -42,6 +42,8 @@ class Symbol;
 
 bool getModuleList(CIDebugSymbols *syms, QList<Module> *modules, QString *errorMessage);
 bool getModuleNameList(CIDebugSymbols *syms, QStringList *modules, QString *errorMessage);
+bool getModuleByOffset(CIDebugSymbols *syms, quint64 offset, Module *module, QString *errorMessage);
+
 // Search symbols matching a pattern. Does not filter on module names.
 bool searchSymbols(CIDebugSymbols *syms, const QString &pattern,
                    QStringList *matches, QString *errorMessage);
diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp
index dc7c1ac0c75..d92ae7660db 100644
--- a/src/plugins/debugger/moduleshandler.cpp
+++ b/src/plugins/debugger/moduleshandler.cpp
@@ -56,9 +56,7 @@ class Debugger::Internal::ModulesModel : public QAbstractItemModel
     Q_OBJECT
 
 public:
-    ModulesModel(ModulesHandler *parent)
-      : QAbstractItemModel(parent)
-    {}
+    explicit ModulesModel(ModulesHandler *parent);
 
     // QAbstractItemModel
     int columnCount(const QModelIndex &parent) const
@@ -72,13 +70,27 @@ public:
     QVariant data(const QModelIndex &index, int role) const;
     bool setData(const QModelIndex &index, const QVariant &value, int role);
 
-    void clearModel() { if (!m_modules.isEmpty()) { m_modules.clear(); update(); } }
-    void update() { reset(); }
+    void clearModel();
+    void addModule(const Module &m);
+    void removeModule(const QString &moduleName);
+    void setModules(const QList<Module> &m);
 
-public:
+    const QList<Module> &modules() const { return m_modules; }
+
+private:
+    int indexOfModule(const QString &name) const;
+
+    const QVariant m_yes;
+    const QVariant m_no;
     QList<Module> m_modules;
 };
 
+ModulesModel::ModulesModel(ModulesHandler *parent)  :
+    QAbstractItemModel(parent),
+    m_yes(tr("yes")), m_no(tr("no"))
+{
+}
+
 QVariant ModulesModel::headerData(int section,
     Qt::Orientation orientation, int role) const
 {
@@ -112,7 +124,7 @@ QVariant ModulesModel::data(const QModelIndex &index, int role) const
             break;
         case 1:
             if (role == Qt::DisplayRole)
-                return module.symbolsRead ? "yes" : "no";
+                return module.symbolsRead ? m_yes : m_no;
             break;
         case 2:
             if (role == Qt::DisplayRole)
@@ -131,6 +143,45 @@ bool ModulesModel::setData(const QModelIndex &index, const QVariant &value, int
     return QAbstractItemModel::setData(index, value, role);
 }
 
+void ModulesModel::addModule(const Module &m)
+{
+    beginInsertRows(QModelIndex(), m_modules.size(), m_modules.size());
+    m_modules.push_back(m);
+    endInsertRows();
+}
+
+void ModulesModel::setModules(const QList<Module> &m)
+{
+    m_modules = m;
+    reset();
+}
+
+void ModulesModel::clearModel()
+{
+    if (!m_modules.isEmpty()) {
+        m_modules.clear();
+        reset();
+    }
+}
+
+int ModulesModel::indexOfModule(const QString &name) const
+{
+    // Recent modules are more likely to be unloaded first.
+    for (int i = m_modules.size() - 1; i >= 0; i--)
+        if (m_modules.at(i).moduleName == name)
+            return i;
+    return -1;
+}
+
+void ModulesModel::removeModule(const QString &moduleName)
+{
+    const int index = indexOfModule(moduleName);
+    QTC_ASSERT(index != -1, return);
+
+    beginRemoveRows(QModelIndex(), index, index);
+    m_modules.removeAt(index);
+    endRemoveRows();
+}
 
 //////////////////////////////////////////////////////////////////
 //
@@ -155,16 +206,24 @@ void ModulesHandler::removeAll()
     m_model->clearModel();
 }
 
+void ModulesHandler::addModule(const Module &module)
+{
+    m_model->addModule(module);
+}
+
+void ModulesHandler::removeModule(const QString &moduleName)
+{
+    m_model->removeModule(moduleName);
+}
 
 void ModulesHandler::setModules(const QList<Module> &modules)
 {
-    m_model->m_modules = modules;
-    m_model->update();
+    m_model->setModules(modules);
 }
 
 QList<Module> ModulesHandler::modules() const
 {
-    return m_model->m_modules;
+    return m_model->modules();
 }
 
 #include "moduleshandler.moc"
diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h
index 249d6ca242e..c0f8d19f736 100644
--- a/src/plugins/debugger/moduleshandler.h
+++ b/src/plugins/debugger/moduleshandler.h
@@ -100,6 +100,9 @@ public:
     QAbstractItemModel *model() const;
 
     void setModules(const QList<Module> &modules);
+    void addModule(const Module &module);
+    void removeModule(const QString &moduleName);
+
     QList<Module> modules() const;
     void removeAll();
 
-- 
GitLab