diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp
index 70e8bd7d52379716dd8c98965a6d490702cd9dbf..8dd52a0135331b66e73590aa217cab4ae31a7a50 100644
--- a/src/plugins/debugger/cdb/cdbmodules.cpp
+++ b/src/plugins/debugger/cdb/cdbmodules.cpp
@@ -31,6 +31,8 @@
 #include "moduleshandler.h"
 #include "cdbdebugengine_p.h"
 
+#include <QtCore/QFileInfo>
+
 namespace Debugger {
 namespace Internal {
 
@@ -82,11 +84,13 @@ bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
                    QStringList *matches, QString *errorMessage)
 {
     matches->clear();    
-    ULONG64 handle;
-    // E_NOINTERFACE means "no match"
+    ULONG64 handle = 0;
+    // E_NOINTERFACE means "no match". Apparently, it does not always
+    // set handle.
     HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
     if (hr == E_NOINTERFACE) {
-        syms->EndSymbolMatch(handle);
+        if (handle)
+            syms->EndSymbolMatch(handle);
         return true;
     }
     if (FAILED(hr)) {
@@ -133,5 +137,27 @@ ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
     return ResolveSymbolOk;
 }
 
+// List symbols of a module
+bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
+                      QList<Symbol> *symbols, QString *errorMessage)
+{
+    // Search all symbols and retrieve addresses
+    symbols->clear();
+    QStringList matches;
+    const QString pattern = QFileInfo(moduleName).baseName() + QLatin1String("!*");
+    if (!searchSymbols(syms, pattern, &matches, errorMessage))
+        return false;
+    const QString hexPrefix = QLatin1String("0x");
+    foreach (const QString &name, matches) {
+        Symbol symbol;
+        symbol.name = name;
+        ULONG64 offset = 0;
+        if (SUCCEEDED(syms->GetOffsetByNameWide(name.utf16(), &offset)))
+            symbol.address = hexPrefix + QString::number(offset, 16);
+        symbols->push_back(symbol);
+    }
+    return true;
+}
+
 }
 }
diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h
index a7be7a943215a24887f49b22a97640a67e55a827..d3058bc906f1972953d008dc5441b4ffe027f1fc 100644
--- a/src/plugins/debugger/cdb/cdbmodules.h
+++ b/src/plugins/debugger/cdb/cdbmodules.h
@@ -40,6 +40,7 @@ namespace Debugger {
 namespace Internal {
 
 class Module;
+class Symbol;
 
 bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
 // Search symbols matching a pattern
@@ -54,6 +55,10 @@ enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
 
 ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage);
 
+// List symbols of a module
+bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
+                      QList<Symbol> *symbols, QString *errorMessage);
+
 }
 }
 
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 9597c128c9b80a53bbdecf487ec20c277cb919f3..5f8f07aed0ec993e4049ddf7d2e5f763a630f2eb 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -175,7 +175,7 @@ void DebuggerManager::init()
     m_statusLabel = new QLabel;
     m_breakWindow = new BreakWindow;
     m_disassemblerWindow = new DisassemblerWindow;
-    m_modulesWindow = new ModulesWindow;
+    m_modulesWindow = new ModulesWindow(this);
     m_outputWindow = new DebuggerOutputWindow;
     m_registerWindow = new RegisterWindow;
     m_stackWindow = new StackWindow;
@@ -998,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module)
     m_engine->loadSymbols(module);
 }
 
+QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
+{
+    QTC_ASSERT(m_engine, return QList<Symbol>());
+    return m_engine->moduleSymbols(moduleName);
+}
+
 void DebuggerManager::stepExec()
 {
     QTC_ASSERT(m_engine, return);
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 72c1467c52efe4243c46dc8f40bc0bbe018f23dc..b9709a68fa59f1fe498b8af4b191b2722c81b53c 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -65,7 +65,7 @@ class WatchHandler;
 class SourceFilesWindow;
 class WatchData;
 class BreakpointData;
-
+class Symbol;
 
 // Note: the Debugger process itself is referred to as 'Debugger',
 // whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
@@ -309,6 +309,8 @@ public:
     int status() const { return m_status; }
     DebuggerStartMode startMode() const { return m_startMode; }
 
+    QList<Symbol> moduleSymbols(const QString &moduleName);
+
 signals:
     void debuggingFinished();
     void inferiorPidChanged(qint64 pid);
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index af3bde01f31ecc57a1bcd7685200d5653c5c0b71..0279c15181f724f4559f09a68dbe444fd222f52d 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -2389,6 +2389,40 @@ void GdbEngine::loadAllSymbols()
     reloadModules();
 }
 
+QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
+{
+    QList<Symbol> rc;
+    bool success = false;
+    QString errorMessage;
+    do {
+        const QString nmBinary = QLatin1String("nm");
+        QProcess proc;
+        proc.start(nmBinary, QStringList() << QLatin1String("-D") << moduleName);
+        if (!proc.waitForFinished()) {
+            errorMessage = tr("Unable to run '%1': %2").arg(nmBinary, proc.errorString());
+            break;
+        }
+        const QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
+        const QRegExp re(QLatin1String("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"));
+        Q_ASSERT(re.isValid());
+        foreach (const QString &line, contents.split(QLatin1Char('\n'))) {
+            if (re.indexIn(line) != -1) {
+                Symbol symbol;
+                symbol.address = re.cap(1);
+                symbol.state = re.cap(2);
+                symbol.name = re.cap(3);
+                rc.push_back(symbol);
+            } else {
+                qWarning("moduleSymbols: unhandled: %s", qPrintable(line));
+            }
+        }
+        success = true;
+    } while (false);
+    if (!success)
+        qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
+    return rc;
+}
+
 void GdbEngine::reloadModules()
 {
     sendCommand("info shared", ModulesList, QVariant());
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
index aebb5da6373ad95f508c4a944fe4adf162330988..b5f5868dcf57566244280517690f2d8c2a82395f 100644
--- a/src/plugins/debugger/gdbengine.h
+++ b/src/plugins/debugger/gdbengine.h
@@ -129,6 +129,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
 
     Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
     Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index 2bb44f8e47bd851695d0a844c90ebd97d3e74a61..0d3863a34e71eec3a2bf1b01bcbfaa292e56cdaa 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -31,6 +31,7 @@
 #define DEBUGGER_IDEBUGGERENGINE_H
 
 #include <QtCore/QObject>
+#include <QtCore/QList>
 
 QT_BEGIN_NAMESPACE
 class QPoint;
@@ -40,6 +41,8 @@ QT_END_NAMESPACE
 namespace Debugger {
 namespace Internal {
 
+class Symbol;
+
 class IDebuggerEngine : public QObject
 {
 public:
@@ -79,6 +82,7 @@ public:
     virtual void reloadModules() = 0;
     virtual void loadSymbols(const QString &moduleName) = 0;
     virtual void loadAllSymbols() = 0;
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
 
     virtual void reloadRegisters() = 0;
 
diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h
index 4c555c83929da5db324aa84e3bf16e322952791f..a6d77e4a28eef7cb8bcb0cdd0149b04451ccc69e 100644
--- a/src/plugins/debugger/moduleshandler.h
+++ b/src/plugins/debugger/moduleshandler.h
@@ -51,6 +51,19 @@ enum ModulesModelRoles
     LoadAllSymbolsRole
 };
 
+//////////////////////////////////////////////////////////////////
+//
+// Symbol
+//
+//////////////////////////////////////////////////////////////////
+
+class Symbol
+{
+public:
+    QString address;
+    QString state;
+    QString name;
+};
 
 //////////////////////////////////////////////////////////////////
 //
diff --git a/src/plugins/debugger/moduleswindow.cpp b/src/plugins/debugger/moduleswindow.cpp
index 8d87709eadc0d08c8501f89894eeba85c8e82af9..6435e8b65a6ee8f01c7e841111d90397c523adeb 100644
--- a/src/plugins/debugger/moduleswindow.cpp
+++ b/src/plugins/debugger/moduleswindow.cpp
@@ -29,6 +29,7 @@
 
 #include "moduleswindow.h"
 #include "moduleshandler.h" // for model roles
+#include "debuggermanager.h"
 
 #include <QtCore/QDebug>
 #include <QtCore/QProcess>
@@ -40,7 +41,7 @@
 #include <QtGui/QResizeEvent>
 #include <QtGui/QToolButton>
 #include <QtGui/QTreeWidget>
-
+#include <QtGui/QApplication>
 
 ///////////////////////////////////////////////////////////////////////////
 //
@@ -48,10 +49,14 @@
 //
 ///////////////////////////////////////////////////////////////////////////
 
-using Debugger::Internal::ModulesWindow;
+namespace Debugger {
+namespace Internal {
 
-ModulesWindow::ModulesWindow(QWidget *parent)
-    : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager,
+                             QWidget *parent)  :
+    QTreeView(parent),
+    m_alwaysResizeColumnsToContents(false),
+    m_debuggerManager(debuggerManager)
 {
     setWindowTitle(tr("Modules"));
     setSortingEnabled(true);
@@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event)
 
 void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
 {
+    QString name;
     QModelIndex index = indexAt(ev->pos());
-    index = index.sibling(index.row(), 0);
-    QString name = model()->data(index).toString();
+    if (index.isValid())
+        index = index.sibling(index.row(), 0);
+    if (index.isValid())
+        name = model()->data(index).toString();
 
     QMenu menu;
     QAction *act0 = new QAction(tr("Update module list"), &menu);
@@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
     act5->setDisabled(name.isEmpty());
     act6->setDisabled(name.isEmpty());
     act7->setDisabled(name.isEmpty());
-    #ifndef Q_OS_LINUX
-    act7->setDisabled(true);
-    #endif
 
     menu.addAction(act0);
     menu.addAction(act4);
@@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name)
 {
     if (name.isEmpty())
         return;
-    QProcess proc;
-    proc.start("nm", QStringList() << "-D" << name);
-    proc.waitForFinished();
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
+    QApplication::restoreOverrideCursor();
+    if (symbols.empty())
+        return;
     QTreeWidget *w = new QTreeWidget;
     w->setColumnCount(3);
     w->setRootIsDecorated(false);
     w->setAlternatingRowColors(true);
-    //w->header()->hide();
     w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
     w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
-    QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
-    QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)");
-    foreach (QString line, contents.split('\n')) {
-        if (re.indexIn(line) != -1) {
-            QTreeWidgetItem *it = new QTreeWidgetItem;
-            it->setData(0, Qt::DisplayRole, re.cap(1));
-            it->setData(1, Qt::DisplayRole, re.cap(2));
-            it->setData(2, Qt::DisplayRole, re.cap(3));
-            w->addTopLevelItem(it);
-        } else {
-            qDebug() << "UNHANDLED LINE" << line;
-        }
+    foreach (const Symbol &s, symbols) {
+        QTreeWidgetItem *it = new QTreeWidgetItem;
+        it->setData(0, Qt::DisplayRole, s.address);
+        it->setData(1, Qt::DisplayRole, s.state);
+        it->setData(2, Qt::DisplayRole, s.name);
+        w->addTopLevelItem(it);
     }
     emit newDockRequested(w);
 }
+
+}
+}
diff --git a/src/plugins/debugger/moduleswindow.h b/src/plugins/debugger/moduleswindow.h
index 36377fb58eeb657f5c742020391627a8be70ff0a..fc2b1af2acff4ee3f8a49fb340ad07823d7a3513 100644
--- a/src/plugins/debugger/moduleswindow.h
+++ b/src/plugins/debugger/moduleswindow.h
@@ -35,12 +35,14 @@
 namespace Debugger {
 namespace Internal {
 
+class DebuggerManager;
+
 class ModulesWindow : public QTreeView
 {
     Q_OBJECT
 
 public:
-    explicit ModulesWindow(QWidget *parent = 0);
+    explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0);
 
 signals:
     void reloadModulesRequested();
@@ -62,6 +64,7 @@ private:
     void setModel(QAbstractItemModel *model);
 
     bool m_alwaysResizeColumnsToContents;
+    DebuggerManager *m_debuggerManager;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/scriptengine.cpp b/src/plugins/debugger/scriptengine.cpp
index 3ee8b7f8697b7a7a5e47e45d90340baef5637c2e..4ab74e2154a399fd2229a8c24e7fcfe08d5fc93e 100644
--- a/src/plugins/debugger/scriptengine.cpp
+++ b/src/plugins/debugger/scriptengine.cpp
@@ -38,6 +38,7 @@
 #include "registerhandler.h"
 #include "stackhandler.h"
 #include "watchhandler.h"
+#include "moduleshandler.h"
 
 #include <utils/qtcassert.h>
 
@@ -405,6 +406,10 @@ void ScriptEngine::reloadModules()
 {
 }
 
+QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
+{
+    return QList<Symbol>();
+}
 
 
 //////////////////////////////////////////////////////////////////////
diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h
index 5e009327da7f63054ac4a551177cc59157385560..ee5612d09d84d3c59bf04f1849f36da2008d26c1 100644
--- a/src/plugins/debugger/scriptengine.h
+++ b/src/plugins/debugger/scriptengine.h
@@ -102,6 +102,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
     void reloadDisassembler();
     void reloadModules();
     void reloadRegisters() {}