OSDN Git Service

Debugger: Expose which languages (QML, C++, Any) an engine supports
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / cdb / cdbengine.cpp
index 1aba5dc..587662c 100644 (file)
@@ -4,30 +4,29 @@
 **
 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 **
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Contact: Nokia Corporation (info@qt.nokia.com)
 **
-** No Commercial Usage
-**
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
 **
 ** GNU Lesser General Public License Usage
 **
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
 ** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
+** Nokia at info@qt.nokia.com.
 **
 **************************************************************************/
 
@@ -45,6 +44,7 @@
 #include "threadshandler.h"
 #include "moduleshandler.h"
 #include "debuggeractions.h"
+#include "debuggerinternalconstants.h"
 #include "debuggercore.h"
 #include "registerhandler.h"
 #include "disassembleragent.h"
@@ -56,6 +56,8 @@
 #include "gdb/gdbmi.h"
 #include "shared/cdbsymbolpathlisteditor.h"
 
+#include <TranslationUnit.h>
+
 #include <coreplugin/icore.h>
 #include <texteditor/itexteditor.h>
 #include <projectexplorer/abi.h>
 #include <utils/qtcassert.h>
 #include <utils/savedaction.h>
 #include <utils/consoleprocess.h>
+#include <utils/fileutils.h>
+
+#include <cplusplus/findcdbbreakpoint.h>
+#include <cplusplus/CppDocument.h>
+#include <cplusplus/ModelManagerInterface.h>
 
 #include <QtCore/QCoreApplication>
 #include <QtCore/QFileInfo>
@@ -89,6 +96,7 @@ Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
 
 enum { debug = 0 };
 enum { debugLocals = 0 };
+enum { debugSourceMapping = 0 };
 enum { debugWatches = 0 };
 enum { debugBreakpoints = 0 };
 
@@ -182,19 +190,27 @@ struct MemoryChangeCookie
     QByteArray data;
 };
 
+struct ConditionalBreakPointCookie
+{
+    ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
+    BreakpointModelId id;
+    GdbMi stopReason;
+};
+
 } // namespace Internal
 } // namespace Debugger
 
 Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
 Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
+Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
 
 namespace Debugger {
 namespace Internal {
 
-static inline bool isConsole(const DebuggerStartParameters &sp)
+static inline bool isCreatorConsole(const DebuggerStartParameters &sp, const CdbOptions &o)
 {
-    return (sp.startMode == StartInternal || sp.startMode == StartExternal)
-        && sp.useTerminal;
+    return !o.cdbConsole && sp.useTerminal
+           && (sp.startMode == StartInternal || sp.startMode == StartExternal);
 }
 
 static QMessageBox *
@@ -300,8 +316,6 @@ static inline bool validMode(DebuggerStartMode sm)
 {
     switch (sm) {
     case NoStartMode:
-    case AttachTcf:
-    case AttachCore:
     case StartRemoteGdb:
         return false;
     default:
@@ -338,17 +352,24 @@ bool isCdbEngineEnabled()
 #endif
 }
 
-static inline QString msgNoCdbBinaryForToolChain(const ProjectExplorer::Abi &tc)
+static inline QString msgNoCdbBinaryForToolChain(const Abi &tc)
 {
     return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
 }
 
+static inline bool isMsvcFlavor(Abi::OSFlavor osf)
+{
+  return osf == Abi::WindowsMsvc2005Flavor
+      || osf == Abi::WindowsMsvc2008Flavor
+      || osf == Abi::WindowsMsvc2010Flavor;
+}
+
 static QString cdbBinary(const DebuggerStartParameters &sp)
 {
     if (!sp.debuggerCommand.isEmpty()) {
         // Do not use a GDB binary if we got started for a project with MinGW runtime.
-        const bool abiMatch = sp.toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS
-                    && sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvcFlavor;
+        const bool abiMatch = sp.toolChainAbi.os() == Abi::WindowsOS
+                   && isMsvcFlavor(sp.toolChainAbi.osFlavor());
         if (abiMatch)
             return sp.debuggerCommand;
     }
@@ -377,10 +398,15 @@ bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck
         return false;
     }
 
+    if (sp.startMode == AttachCore && !isMsvcFlavor(sp.toolChainAbi.osFlavor())) {
+        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine cannot debug gdb core files."));
+        return false;
+    }
+
     if (cdbBinary(sp).isEmpty()) {
         check->errorDetails.push_back(msgNoCdbBinaryForToolChain(sp.toolChainAbi));
-        check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
-        check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
+        check->settingsCategory = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
+        check->settingsPage = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
         return false;
     }
 
@@ -410,12 +436,11 @@ static inline Utils::SavedAction *theAssemblerAction()
 
 CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
         DebuggerEngine *masterEngine, const OptionsPtr &options) :
-    DebuggerEngine(sp, masterEngine),
+    DebuggerEngine(sp, CppLanguage, masterEngine),
     m_creatorExtPrefix("<qtcreatorcdbext>|"),
     m_tokenPrefix("<token>"),
     m_options(options),
     m_effectiveStartMode(NoStartMode),
-    m_inferiorPid(0),
     m_accessible(false),
     m_specialStopMode(NoSpecialStop),
     m_nextCommandToken(0),
@@ -443,7 +468,7 @@ CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
 void CdbEngine::init()
 {
     m_effectiveStartMode = NoStartMode;
-    m_inferiorPid = 0;
+    notifyInferiorPid(0);
     m_accessible = false;
     m_specialStopMode = NoSpecialStop;
     m_nextCommandToken  = 0;
@@ -462,6 +487,21 @@ void CdbEngine::init()
     m_extensionMessageBuffer.clear();
     m_pendingBreakpointMap.clear();
     m_customSpecialStopData.clear();
+    m_symbolAddressCache.clear();
+    m_coreStopReason.reset();
+
+    // Create local list of mappings in native separators
+    m_sourcePathMappings.clear();
+    const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
+    if (!globalOptions->sourcePathMap.isEmpty()) {
+        typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
+        m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
+        const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
+        for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
+            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
+                                                             QDir::toNativeSeparators(it.value())));
+        }
+    }
     QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process); )
 }
 
@@ -471,12 +511,10 @@ CdbEngine::~CdbEngine()
 
 void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
 {
-    if (state() == InferiorStopOk) {
+    // To be set next time session becomes accessible
+    m_operateByInstructionPending = operateByInstruction;
+    if (state() == InferiorStopOk)
         syncOperateByInstruction(operateByInstruction);
-    } else {
-        // To be set next time session becomes accessible
-        m_operateByInstructionPending = operateByInstruction;
-    }
 }
 
 void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
@@ -504,18 +542,26 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
     int line;
     int column;
     DebuggerToolTipContext context = contextIn;
-    const QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
+    QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
     // Are we in the current stack frame
     if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
         return false;
     // No numerical or any other expressions [yet]
     if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
         return false;
-    const QByteArray iname = QByteArray(localsPrefixC) + exp.toAscii();
-    const QModelIndex index = watchHandler()->itemIndex(iname);
-    if (!index.isValid())
-        return false;
-    DebuggerTreeViewToolTipWidget *tw = new DebuggerTreeViewToolTipWidget;
+    // Can this be found as a local variable?
+    const QByteArray localsPrefix(localsPrefixC);
+    QByteArray iname = localsPrefix + exp.toAscii();
+    QModelIndex index = watchHandler()->itemIndex(iname);
+    if (!index.isValid()) {
+        // Nope, try a 'local.this.m_foo'.
+        exp.prepend(QLatin1String("this."));
+        iname.insert(localsPrefix.size(), "this.");
+        index = watchHandler()->itemIndex(iname);
+        if (!index.isValid())
+            return false;
+    }
+    DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
     tw->setContext(context);
     tw->setDebuggerModel(LocalsWatch);
     tw->setExpression(exp);
@@ -579,8 +625,8 @@ bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMe
         qDebug("startConsole %s", qPrintable(sp.executable));
     m_consoleStub.reset(new Utils::ConsoleProcess);
     m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
-    connect(m_consoleStub.data(), SIGNAL(processMessage(QString, bool)),
-            SLOT(consoleStubMessage(QString, bool)));
+    connect(m_consoleStub.data(), SIGNAL(processError(QString)),
+            SLOT(consoleStubError(QString)));
     connect(m_consoleStub.data(), SIGNAL(processStarted()),
             SLOT(consoleStubProcessStarted()));
     connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
@@ -595,22 +641,18 @@ bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMe
     return true;
 }
 
-void CdbEngine::consoleStubMessage(const QString &msg, bool isError)
+void CdbEngine::consoleStubError(const QString &msg)
 {
     if (debug)
-        qDebug("consoleStubProcessMessage() in %s error=%d %s", stateName(state()), isError, qPrintable(msg));
-    if (isError) {
-        if (state() == EngineSetupRequested) {
-            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
-            notifyEngineSetupFailed();
-        } else {
-            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
-            notifyEngineIll();
-        }
-        nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
+        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
+    if (state() == EngineSetupRequested) {
+        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
+        notifyEngineSetupFailed();
     } else {
-        showMessage(msg, AppOutput);
+        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
+        notifyEngineIll();
     }
+    nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
 }
 
 void CdbEngine::consoleStubProcessStarted()
@@ -623,6 +665,7 @@ void CdbEngine::consoleStubProcessStarted()
     attachParameters.processArgs.clear();
     attachParameters.attachPID = m_consoleStub->applicationPID();
     attachParameters.startMode = AttachExternal;
+    attachParameters.useTerminal = false;
     showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
     QString errorMessage;
     if (!launchCDB(attachParameters, &errorMessage)) {
@@ -654,7 +697,7 @@ void CdbEngine::setupEngine()
     // console, too, but that immediately closes when the debuggee quits.
     // Use the Creator stub instead.
     const DebuggerStartParameters &sp = startParameters();
-    const bool launchConsole = isConsole(sp);
+    const bool launchConsole = isCreatorConsole(sp, *m_options);
     m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
     const bool ok = launchConsole ?
                 startConsole(startParameters(), &errorMessage) :
@@ -698,7 +741,7 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
     const QString extensionFileName = extensionFi.fileName();
     // Prepare arguments
     QStringList arguments;
-    const bool isRemote = sp.startMode == AttachToRemote;
+    const bool isRemote = sp.startMode == AttachToRemoteServer;
     if (isRemote) { // Must be first
         arguments << QLatin1String("-remote") << sp.remoteChannel;
     } else {
@@ -708,7 +751,7 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
     arguments << QLatin1String("-lines") << QLatin1String("-G")
     // register idle (debuggee stop) notification
               << QLatin1String("-c")
-              << QString::fromAscii(".idle_cmd " + m_extensionCommandPrefixBA + "idle");
+              << QLatin1String(".idle_cmd ") + QString::fromAscii(m_extensionCommandPrefixBA) + QLatin1String("idle");
     if (sp.useTerminal) // Separate console
         arguments << QLatin1String("-2");
     if (!m_options->symbolPaths.isEmpty())
@@ -724,13 +767,20 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
             nativeArguments.push_back(blank);
         nativeArguments += QDir::toNativeSeparators(sp.executable);
         break;
-    case AttachToRemote:
+    case AttachToRemoteServer:
         break;
     case AttachExternal:
     case AttachCrashedExternal:
         arguments << QLatin1String("-p") << QString::number(sp.attachPID);
-        if (sp.startMode == AttachCrashedExternal)
+        if (sp.startMode == AttachCrashedExternal) {
             arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
+        } else {
+            if (isCreatorConsole(startParameters(), *m_options))
+                arguments << QLatin1String("-pr") << QLatin1String("-pb");
+        }
+        break;
+    case AttachCore:
+        arguments << QLatin1String("-z") << sp.coreFile;
         break;
     default:
         *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
@@ -790,8 +840,16 @@ void CdbEngine::setupInferior()
 {
     if (debug)
         qDebug("setupInferior");
+    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
+    // (attemptBreakpointSynchronization() will be directly called then)
     attemptBreakpointSynchronization();
+    if (startParameters().breakOnMain) {
+        const BreakpointParameters bp(BreakpointAtMain);
+        postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
+                                            BreakpointModelId(-1), true), 0);
+    }
     postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
+    postCommand(".asm source_line", 0); // Source line in assembly
     postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
 }
 
@@ -799,12 +857,15 @@ void CdbEngine::runEngine()
 {
     if (debug)
         qDebug("runEngine");
-    // Resume the threads frozen by the console stub.
-    if (isConsole(startParameters()))
-        postCommand("~* m", 0);
     foreach (const QString &breakEvent, m_options->breakEvents)
             postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
-    postCommand("g", 0);
+    if (startParameters().startMode == AttachCore) {
+        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
+        notifyInferiorUnrunnable();
+        processStop(*m_coreStopReason, false);
+    } else {
+        postCommand("g", 0);
+    }
 }
 
 bool CdbEngine::commandsPending() const
@@ -826,8 +887,8 @@ void CdbEngine::shutdownInferior()
         return;
     }
 
-    if (m_accessible) {
-        if (m_effectiveStartMode == AttachExternal || m_effectiveStartMode == AttachCrashedExternal)
+    if (m_accessible) { // except console.
+        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
             detachDebugger();
         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
         notifyInferiorShutdownOk();
@@ -875,11 +936,11 @@ void CdbEngine::shutdownEngine()
     m_ignoreCdbOutput = true;
     // Go for kill if there are commands pending.
     if (m_accessible && !commandsPending()) {
-        // detach: Wait for debugger to finish.
-        if (m_effectiveStartMode == AttachExternal)
+        // detach (except console): Wait for debugger to finish.
+        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
             detachDebugger();
         // Remote requires a bit more force to quit.
-        if (m_effectiveStartMode == AttachToRemote) {
+        if (m_effectiveStartMode == AttachToRemoteServer) {
             postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
             postCommand("qq", 0);
         } else {
@@ -926,8 +987,15 @@ void CdbEngine::processFinished()
             notifyEngineShutdownOk();
         }
     } else {
-        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
-        notifyEngineSpontaneousShutdown();
+        // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
+        // Otherwise, we take a shortcut.
+        if (isSlaveEngine()) {
+            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
+            notifyInferiorExited();
+        } else {
+            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
+            notifyEngineSpontaneousShutdown();
+        }
     }
 }
 
@@ -1026,9 +1094,13 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
 unsigned CdbEngine::debuggerCapabilities() const
 {
     return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
-           |WatchpointCapability|JumpToLineCapability|AddWatcherCapability
+           |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
+           |ReloadModuleCapability
            |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
-           |BreakModuleCapability;
+           |BreakConditionCapability|TracePointCapability
+           |BreakModuleCapability
+           |OperateByInstructionCapability
+           |RunToLineCapability;
 }
 
 void CdbEngine::executeStep()
@@ -1078,7 +1150,7 @@ void CdbEngine::doContinueInferior()
 
 bool CdbEngine::canInterruptInferior() const
 {
-    return m_effectiveStartMode != AttachToRemote && m_inferiorPid;
+    return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
 }
 
 void CdbEngine::interruptInferior()
@@ -1111,10 +1183,10 @@ void CdbEngine::doInterruptInferior(SpecialStopMode sm)
     const SpecialStopMode oldSpecialMode = m_specialStopMode;
     m_specialStopMode = sm;
     QString errorMessage;
-    showMessage(QString::fromLatin1("Interrupting process %1...").arg(m_inferiorPid), LogMisc);
-    if (!winDebugBreakProcess(m_inferiorPid, &errorMessage)) {
+    showMessage(QString::fromLatin1("Interrupting process %1...").arg(inferiorPid()), LogMisc);
+    if (!winDebugBreakProcess(inferiorPid(), &errorMessage)) {
         m_specialStopMode = oldSpecialMode;
-        showMessage(QString::fromLatin1("Cannot interrupt process %1: %2").arg(m_inferiorPid).arg(errorMessage), LogError);
+        showMessage(QString::fromLatin1("Cannot interrupt process %1: %2").arg(inferiorPid()).arg(errorMessage), LogError);
     }
 #else
     Q_UNUSED(sm)
@@ -1133,7 +1205,7 @@ void CdbEngine::executeRunToLine(const ContextData &data)
         bp.fileName = data.fileName;
         bp.lineNumber = data.lineNumber;
     }
-    postCommand(cdbAddBreakpointCommand(bp, BreakpointId(-1), true), 0);
+    postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(-1), true), 0);
     continueInferior();
 }
 
@@ -1143,7 +1215,7 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
     BreakpointParameters bp(BreakpointByFunction);
     bp.functionName = functionName;
 
-    postCommand(cdbAddBreakpointCommand(bp, BreakpointId(-1), true), 0);
+    postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(-1), true), 0);
     continueInferior();
 }
 
@@ -1210,6 +1282,15 @@ void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cm
     }
 }
 
+static inline bool isAsciiWord(const QString &s)
+{
+    foreach (const QChar &c, s) {
+        if (!c.isLetterOrNumber() || c.toAscii() == 0)
+            return false;
+    }
+    return true;
+}
+
 void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value)
 {
     if (debug)
@@ -1219,10 +1300,28 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c
         qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame.");
         return;
     }
-
     QByteArray cmd;
     ByteArrayInputStream str(cmd);
-    str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' << value.toString();
+    switch (value.type()) {
+    case QVariant::String: {
+        // Convert qstring to Utf16 data not considering endianness for Windows.
+        const QString s = value.toString();
+        if (isAsciiWord(s)) {
+            str << m_extensionCommandPrefixBA << "assign \"" << w->iname << '='
+                << s.toLatin1() << '"';
+        } else {
+            const QByteArray utf16(reinterpret_cast<const char *>(s.utf16()), 2 * s.size());
+            str << m_extensionCommandPrefixBA << "assign -u " << w->iname << '='
+                << utf16.toHex();
+        }
+    }
+        break;
+    default:
+        str << m_extensionCommandPrefixBA << "assign " << w->iname << '='
+            << value.toString();
+        break;
+    }
+
     postCommand(cmd, 0);
     // Update all locals in case we change a union or something pointed to
     // that affects other variables, too.
@@ -1408,19 +1507,21 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
         }
     }
     addLocalsOptions(str);
-    // Uninitialized variables if desired
+    // Uninitialized variables if desired. Quote as safeguard against shadowed
+    // variables in case of errors in uninitializedVariables().
     if (debuggerCore()->boolSetting(UseCodeModel)) {
         QStringList uninitializedVariables;
         getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(),
                                   frame.function, frame.file, frame.line, &uninitializedVariables);
         if (!uninitializedVariables.isEmpty()) {
-            str << blankSeparator << "-u ";
+            str << blankSeparator << "-u \"";
             int i = 0;
             foreach(const QString &u, uninitializedVariables) {
                 if (i++)
                     str << ',';
                 str << localsPrefixC << u;
             }
+            str << '"';
         }
     }
     // Perform watches synchronization
@@ -1452,41 +1553,176 @@ void CdbEngine::selectThread(int index)
     postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack);
 }
 
+// Default address range for showing disassembly.
+enum { DisassemblerRange = 512 };
+
+/* Try to emulate gdb's behaviour: When passed an address, display
+ * the disassembled function. CDB's 'u' (disassemble) command takes a symbol,
+ * but does not display the whole function, only 10 lines per default.
+ * So, to ensure the agent's
+ * address is in that range, resolve the function symbol, cache it and
+ * request the disassembly for a range that contains the agent's address. */
+
 void CdbEngine::fetchDisassembler(DisassemblerAgent *agent)
 {
     QTC_ASSERT(m_accessible, return;)
+    const QString function = agent->location().functionName();
+    const QString module = agent->location().from();
+    const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
+    if (function.isEmpty() || module.isEmpty()) {
+        // No function, display a default range.
+        postDisassemblerCommand(agent->address(), cookie);
+    } else {
+        postResolveSymbol(module, function, cookie);
+    }
+}
+
+void CdbEngine::postDisassemblerCommand(quint64 address, const QVariant &cookie)
+{
+    postDisassemblerCommand(address - DisassemblerRange / 2,
+                            address + DisassemblerRange / 2, cookie);
+}
+
+void CdbEngine::postDisassemblerCommand(quint64 address, quint64 endAddress,
+                                        const QVariant &cookie)
+{
     QByteArray cmd;
     ByteArrayInputStream str(cmd);
-    str <<  "u " << hex << hexPrefixOn << agent->address() << " L40";
-    const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
+    str <<  "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
     postBuiltinCommand(cmd, 0, &CdbEngine::handleDisassembler, 0, cookie);
 }
 
+void CdbEngine::postResolveSymbol(const QString &module, const QString &function,
+                                  const QVariant &cookie)
+{
+    const QString symbol = module + QLatin1Char('!') + function;
+    const QList<quint64> addresses = m_symbolAddressCache.values(symbol);
+    if (addresses.isEmpty()) {
+        QVariantList cookieList;
+        cookieList << QVariant(symbol) << cookie;
+        showMessage(QLatin1String("Resolving symbol: ") + symbol, LogMisc);
+        postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(), 0,
+                           &CdbEngine::handleResolveSymbol, 0,
+                           QVariant(cookieList));
+    } else {
+        showMessage(QString::fromLatin1("Using cached addresses for %1.").
+                    arg(symbol), LogMisc);
+        handleResolveSymbol(addresses, cookie);
+    }
+}
+
+// Parse address from 'x' response.
+// "00000001`3f7ebe80 module!foo (void)"
+static inline quint64 resolvedAddress(const QByteArray &line)
+{
+    const int blankPos = line.indexOf(' ');
+    if (blankPos >= 0) {
+        QByteArray addressBA = line.left(blankPos);
+        if (addressBA.size() > 9 && addressBA.at(8) == '`')
+            addressBA.remove(8, 1);
+        bool ok;
+        const quint64 address = addressBA.toULongLong(&ok, 16);
+        if (ok)
+            return address;
+    }
+    return 0;
+}
+
+void CdbEngine::handleResolveSymbol(const CdbBuiltinCommandPtr &command)
+{
+    QTC_ASSERT(command->cookie.type() == QVariant::List, return; );
+    const QVariantList cookieList = command->cookie.toList();
+    const QString symbol = cookieList.front().toString();
+    // Insert all matches of (potentially) ambiguous symbols
+    if (const int size = command->reply.size()) {
+        for (int i = 0; i < size; i++) {
+            if (const quint64 address = resolvedAddress(command->reply.at(i))) {
+                m_symbolAddressCache.insert(symbol, address);
+                showMessage(QString::fromLatin1("Obtained 0x%1 for %2 (#%3)").
+                            arg(address, 0, 16).arg(symbol).arg(i + 1), LogMisc);
+            }
+        }
+    } else {
+        showMessage(QLatin1String("Symbol resolution failed: ")
+                    + QString::fromLatin1(command->joinedReply()),
+                    LogError);
+    }
+    handleResolveSymbol(m_symbolAddressCache.values(symbol), cookieList.back());
+}
+
+// Find the function address matching needle in a list of function
+// addresses obtained from the 'x' command. Check for the
+// mimimum POSITIVE offset (needle >= function address.)
+static inline quint64 findClosestFunctionAddress(const QList<quint64> &addresses,
+                                                 quint64 needle)
+{
+    const int size = addresses.size();
+    if (!size)
+        return 0;
+    if (size == 1)
+       return addresses.front();
+    int closestIndex = 0;
+    quint64 closestOffset = 0xFFFFFFFF;
+    for (int i = 0; i < size; i++) {
+        if (addresses.at(i) <= needle) {
+            const quint64 offset = needle - addresses.at(i);
+            if (offset < closestOffset) {
+                closestOffset = offset;
+                closestIndex = i;
+            }
+        }
+    }
+    return addresses.at(closestIndex);
+}
+
+void CdbEngine::handleResolveSymbol(const QList<quint64> &addresses, const QVariant &cookie)
+{
+    // Disassembly mode: Determine suitable range containing the
+    // agent's address within the function to display.
+    if (qVariantCanConvert<DisassemblerAgent*>(cookie)) {
+        DisassemblerAgent *agent = cookie.value<DisassemblerAgent *>();
+        const quint64 agentAddress = agent->address();
+        const quint64 functionAddress
+                = findClosestFunctionAddress(addresses, agentAddress);
+        if (functionAddress > 0 && functionAddress <= agentAddress) {
+            quint64 endAddress = agentAddress + DisassemblerRange / 2;
+            if (const quint64 remainder = endAddress % 8)
+                endAddress += 8 - remainder;
+            postDisassemblerCommand(functionAddress, endAddress, cookie);
+        } else {
+            postDisassemblerCommand(agentAddress, cookie);
+        }
+        return;
+    }
+}
+
 // Parse: "00000000`77606060 cc              int     3"
 void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command)
 {
     QTC_ASSERT(qVariantCanConvert<DisassemblerAgent*>(command->cookie), return;)
     DisassemblerAgent *agent = qvariant_cast<DisassemblerAgent*>(command->cookie);
-    DisassemblerLines disassemblerLines;
-    foreach(const QByteArray &line, command->reply)
-        disassemblerLines.appendLine(DisassemblerLine(QString::fromLatin1(line)));
-    agent->setContents(disassemblerLines);
+    agent->setContents(parseCdbDisassembler(command->reply));
 }
 
 void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length)
 {
-    if (!m_accessible) {
-        qWarning("Internal error: Attempt to read memory from inaccessible session: %s", Q_FUNC_INFO);
-        return;
-    }
     if (debug)
         qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr);
+    const MemoryViewCookie cookie(agent, editor, addr, length);
+    if (m_accessible) {
+        postFetchMemory(cookie);
+    } else {
+        doInterruptInferiorCustomSpecialStop(qVariantFromValue(cookie));
+    }
+}
 
+void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie)
+{
     QByteArray args;
     ByteArrayInputStream str(args);
-    str << addr << ' ' << length;
-    const QVariant cookie = qVariantFromValue<MemoryViewCookie>(MemoryViewCookie(agent, editor, addr, length));
-    postExtensionCommand("memory", args, 0, &CdbEngine::handleMemory, 0, cookie);
+    str << cookie.address << ' ' << cookie.length;
+    postExtensionCommand("memory", args, 0, &CdbEngine::handleMemory, 0,
+                         qVariantFromValue(cookie));
 }
 
 void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data)
@@ -1510,7 +1746,7 @@ void CdbEngine::handleMemory(const CdbExtensionCommandPtr &command)
             memViewCookie.agent->addLazyData(memViewCookie.editorToken,
                                              memViewCookie.address, data);
     } else {
-        showMessage(QString::fromLocal8Bit(command->errorMessage), LogError);
+        showMessage(QString::fromLocal8Bit(command->errorMessage), LogWarning);
     }
 }
 
@@ -1550,9 +1786,10 @@ void CdbEngine::reloadFullStack()
 
 void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply)
 {
-    if (reply->success) {
-        m_inferiorPid = reply->reply.toUInt();
-        showMessage(QString::fromLatin1("Inferior pid: %1.").arg(m_inferiorPid), LogMisc);
+    // Fails for core dumps.
+    if (reply->success)
+        notifyInferiorPid(reply->reply.toULongLong());
+    if (reply->success || startParameters().startMode == AttachCore) {
         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk")
         notifyInferiorSetupOk();
     }  else {
@@ -1563,8 +1800,8 @@ void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply)
     }
 }
 
-// Parse CDB gdbmi register syntax
-static inline Register parseRegister(const GdbMi &gdbmiReg)
+// Parse CDB gdbmi register syntax.
+static Register parseRegister(const GdbMi &gdbmiReg)
 {
     Register reg;
     reg.name = gdbmiReg.findChild("name").data();
@@ -1574,7 +1811,7 @@ static inline Register parseRegister(const GdbMi &gdbmiReg)
         reg.name += description.data();
         reg.name += ')';
     }
-    reg.value = QString::fromAscii(gdbmiReg.findChild("value").data());
+    reg.value = gdbmiReg.findChild("value").data();
     return reg;
 }
 
@@ -1619,7 +1856,7 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
             registers.reserve(value.childCount());
             foreach (const GdbMi &gdbmiReg, value.children())
                 registers.push_back(parseRegister(gdbmiReg));
-            registerHandler()->setRegisters(registers);
+            registerHandler()->setAndMarkRegisters(registers);
         } else {
             showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
             qWarning("Parse error in registers response:\n%s", reply->reply.constData());
@@ -1660,7 +1897,7 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
         if (forNewStackFrame)
             emit stackFrameCompleted();
     } else {
-        showMessage(QString::fromLatin1(reply->errorMessage), LogError);
+        showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);
     }
 }
 
@@ -1732,9 +1969,25 @@ enum StopActionFlags
     StopShutdownInProgress = 0x80 // Shutdown in progress
 };
 
+static inline QString msgTracePointTriggered(BreakpointModelId id, const int number,
+                                             const QString &threadId)
+{
+    return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
+            .arg(id.toString()).arg(number).arg(threadId);
+}
+
+static inline QString msgCheckingConditionalBreakPoint(BreakpointModelId id, const int number,
+                                                       const QByteArray &condition,
+                                                       const QString &threadId)
+{
+    return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression '%4'.")
+            .arg(id.toString()).arg(number).arg(threadId, QString::fromAscii(condition));
+}
+
 unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
                                       QString *message,
-                                      QString *exceptionBoxMessage)
+                                      QString *exceptionBoxMessage,
+                                      bool conditionalBreakPointTriggered)
 {
     // Report stop reason (GDBMI)
     unsigned rc  = 0;
@@ -1758,18 +2011,44 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
     const int threadId = stopReason.findChild("threadId").data().toInt();
     if (reason == "breakpoint") {
         // Note: Internal breakpoints (run to line) are reported with id=0.
-        BreakpointId id = 0;
+        // Step out creates temporary breakpoints with id 10000.
+        BreakpointModelId id;
         int number = 0;
         const GdbMi breakpointIdG = stopReason.findChild("breakpointId");
         if (breakpointIdG.isValid()) {
-            id = breakpointIdG.data().toULongLong();
-            if (id)
-                number = breakHandler()->response(id).number;
+            id = BreakpointModelId(breakpointIdG.data().toInt());
+            if (id && breakHandler()->engineBreakpointIds(this).contains(id)) {
+                const BreakpointResponse parameters =  breakHandler()->response(id);
+                if (!parameters.message.isEmpty()) {
+                    showMessage(parameters.message + QLatin1Char('\n'), AppOutput);
+                    showMessage(parameters.message, LogMisc);
+                }
+                // Trace point? Just report.
+                number = parameters.id.majorPart();
+                if (parameters.tracepoint) {
+                    *message = msgTracePointTriggered(id, number, QString::number(threadId));
+                    return StopReportLog|StopIgnoreContinue;
+                }
+                // Trigger evaluation of BP expression unless we are already in the response.
+                if (!conditionalBreakPointTriggered && !parameters.condition.isEmpty()) {
+                    *message = msgCheckingConditionalBreakPoint(id, number, parameters.condition,
+                                                                QString::number(threadId));
+                    ConditionalBreakPointCookie cookie(id);
+                    cookie.stopReason = stopReason;
+                    evaluateExpression(parameters.condition, qVariantFromValue(cookie));
+                    return StopReportLog;
+                }
+            } else {
+                id = BreakpointModelId();
+            }
         }
-        if (id && breakHandler()->type(id) == Watchpoint) {
-            *message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
+        QString tid = QString::number(threadId);
+        if (id && breakHandler()->type(id) == WatchpointAtAddress) {
+            *message = msgWatchpointByAddressTriggered(id, number, breakHandler()->address(id), tid);
+        } else if (id && breakHandler()->type(id) == WatchpointAtExpression) {
+            *message = msgWatchpointByExpressionTriggered(id, number, breakHandler()->expression(id), tid);
         } else {
-            *message = msgBreakpointTriggered(id, number, QString::number(threadId));
+            *message = msgBreakpointTriggered(id, number, tid);
         }
         rc |= StopReportStatusMessage|StopNotifyStop;
         return rc;
@@ -1779,9 +2058,10 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
         exception.fromGdbMI(stopReason);
         QString description = exception.toString();
 #ifdef Q_OS_WIN
-        // It is possible to hit on a startup trap while stepping (if something
+        // It is possible to hit on a startup trap or WOW86 exception while stepping (if something
         // pulls DLLs. Avoid showing a 'stopped' Message box.
-        if (exception.exceptionCode == winExceptionStartupCompleteTrap)
+        if (exception.exceptionCode == winExceptionStartupCompleteTrap
+            || exception.exceptionCode == winExceptionWX86Breakpoint)
             return StopNotifyStop;
         if (exception.exceptionCode == winExceptionCtrlPressed) {
             // Detect interruption by pressing Ctrl in a console and force a switch to thread 0.
@@ -1849,16 +2129,27 @@ void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
     if (state() == EngineSetupRequested) { // Temporary stop at beginning
         STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
         notifyEngineSetupOk();
+        // Store stop reason to be handled in runEngine().
+        if (startParameters().startMode == AttachCore) {
+            m_coreStopReason.reset(new GdbMi);
+            m_coreStopReason->fromString(messageBA);
+        }
         return;
     }
 
+    GdbMi stopReason;
+    stopReason.fromString(messageBA);
+    processStop(stopReason, false);
+}
+
+void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointTriggered)
+{
     // Further examine stop and report to user
     QString message;
     QString exceptionBoxMessage;
-    GdbMi stopReason;
-    stopReason.fromString(messageBA);
     int forcedThreadId = -1;
-    const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage);
+    const unsigned stopFlags = examineStopReason(stopReason, &message, &exceptionBoxMessage,
+                                                 conditionalBreakPointTriggered);
     // Do the non-blocking log reporting
     if (stopFlags & StopReportLog)
         showMessage(message, LogMisc);
@@ -1866,19 +2157,21 @@ void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
         showStatusMessage(message);
     if (stopFlags & StopReportParseError)
         showMessage(message, LogError);
-    // Ignore things like WOW64
+    // Ignore things like WOW64, report tracepoints.
     if (stopFlags & StopIgnoreContinue) {
         postCommand("g", 0);
         return;
     }
     // Notify about state and send off command sequence to get stack, etc.
     if (stopFlags & StopNotifyStop) {
-        if (state() == InferiorStopRequested) {
-            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
-            notifyInferiorStopOk();
-        } else {
-            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSpontaneousStop")
-            notifyInferiorSpontaneousStop();
+        if (startParameters().startMode != AttachCore) {
+            if (state() == InferiorStopRequested) {
+                STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorStopOk")
+                        notifyInferiorStopOk();
+            } else {
+                STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSpontaneousStop")
+                        notifyInferiorSpontaneousStop();
+            }
         }
         // Prevent further commands from being sent if shutdown is in progress
         if (stopFlags & StopShutdownInProgress) {
@@ -2247,26 +2540,104 @@ bool CdbEngine::stateAcceptsBreakpointChanges() const
     return false;
 }
 
-bool CdbEngine::acceptsBreakpoint(BreakpointId id) const
+bool CdbEngine::acceptsBreakpoint(BreakpointModelId id) const
+{
+    const BreakpointParameters &data = breakHandler()->breakpointData(id);
+    if (!DebuggerEngine::isCppBreakpoint(data))
+        return false;
+    switch (data.type) {
+    case UnknownType:
+    case BreakpointAtFork:
+    case WatchpointAtExpression:
+    case BreakpointAtSysCall:
+    case BreakpointOnQmlSignalHandler:
+    case BreakpointAtJavaScriptThrow:
+        return false;
+    case WatchpointAtAddress:
+    case BreakpointByFileAndLine:
+    case BreakpointByFunction:
+    case BreakpointByAddress:
+    case BreakpointAtThrow:
+    case BreakpointAtCatch:
+    case BreakpointAtMain:
+    case BreakpointAtExec:
+        break;
+    }
+    return true;
+}
+
+// Context for fixing file/line-type breakpoints, for delayed creation.
+class BreakpointCorrectionContext
+{
+public:
+    explicit BreakpointCorrectionContext(const CPlusPlus::Snapshot &s,
+                                         const CPlusPlus::CppModelManagerInterface::WorkingCopy &workingCopy) :
+        m_snapshot(s), m_workingCopy(workingCopy) {}
+
+    unsigned fixLineNumber(const QString &fileName, unsigned lineNumber) const;
+
+private:
+    const CPlusPlus::Snapshot m_snapshot;
+    CPlusPlus::CppModelManagerInterface::WorkingCopy m_workingCopy;
+};
+
+static CPlusPlus::Document::Ptr getParsedDocument(const QString &fileName,
+                                                  const CPlusPlus::CppModelManagerInterface::WorkingCopy &workingCopy,
+                                                  const CPlusPlus::Snapshot &snapshot)
+{
+    QString src;
+    if (workingCopy.contains(fileName)) {
+        src = workingCopy.source(fileName);
+    } else {
+        Utils::FileReader reader;
+        if (reader.fetch(fileName)) // ### FIXME error reporting
+            src = QString::fromLocal8Bit(reader.data()); // ### FIXME encoding
+    }
+
+    QByteArray source = snapshot.preprocessedCode(src, fileName);
+
+    CPlusPlus::Document::Ptr doc = snapshot.documentFromSource(source, fileName);
+    doc->parse();
+    return doc;
+}
+
+unsigned BreakpointCorrectionContext::fixLineNumber(const QString &fileName,
+                                                    unsigned lineNumber) const
 {
-    return DebuggerEngine::isCppBreakpoint(breakHandler()->breakpointData(id));
+    CPlusPlus::Document::Ptr doc = m_snapshot.document(fileName);
+    if (!doc || !doc->translationUnit()->ast())
+        doc = getParsedDocument(fileName, m_workingCopy, m_snapshot);
+
+    CPlusPlus::FindCdbBreakpoint findVisitor(doc->translationUnit());
+    const unsigned correctedLine = findVisitor(lineNumber);
+    if (!correctedLine) {
+        qWarning("Unable to find breakpoint location for %s:%d",
+                 qPrintable(QDir::toNativeSeparators(fileName)), lineNumber);
+        return lineNumber;
+    }
+    if (debug)
+        qDebug("Code model: Breakpoint line %u -> %u in %s",
+               lineNumber, correctedLine, qPrintable(fileName));
+    return correctedLine;
 }
 
 void CdbEngine::attemptBreakpointSynchronization()
 {
+
+
     if (debug)
         qDebug("attemptBreakpointSynchronization in %s", stateName(state()));
     // Check if there is anything to be done at all.
     BreakHandler *handler = breakHandler();
     // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
-    foreach (BreakpointId id, handler->unclaimedBreakpointIds())
+    foreach (BreakpointModelId id, handler->unclaimedBreakpointIds())
         if (acceptsBreakpoint(id))
             handler->setEngine(id, this);
 
     // Quick check: is there a need to change something? - Populate module cache
     bool changed = false;
-    const BreakpointIds ids = handler->engineBreakpointIds(this);
-    foreach (BreakpointId id, ids) {
+    const BreakpointModelIds ids = handler->engineBreakpointIds(this);
+    foreach (BreakpointModelId id, ids) {
         switch (handler->state(id)) {
         case BreakpointInsertRequested:
         case BreakpointRemoveRequested:
@@ -2302,10 +2673,12 @@ void CdbEngine::attemptBreakpointSynchronization()
     // Breakhandler::setResponse() on pending breakpoints clears the pending flag.
     // handleBreakPoints will the complete that information and set it on the break handler.
     bool addedChanged = false;
-    foreach (BreakpointId id, ids) {
+    QScopedPointer<BreakpointCorrectionContext> lineCorrection;
+    foreach (BreakpointModelId id, ids) {
         BreakpointParameters parameters = handler->breakpointData(id);
         BreakpointResponse response;
         response.fromParameters(parameters);
+        response.id = BreakpointResponseId(id.majorPart(), id.minorPart());
         // If we encountered that file and have a module for it: Add it.
         if (parameters.type == BreakpointByFileAndLine && parameters.module.isEmpty()) {
             const QHash<QString, QString>::const_iterator it = m_fileNameModuleHash.constFind(parameters.fileName);
@@ -2314,37 +2687,52 @@ void CdbEngine::attemptBreakpointSynchronization()
         }
         switch (handler->state(id)) {
         case BreakpointInsertRequested:
-            postCommand(cdbAddBreakpointCommand(parameters, id, false), 0);
+            if (parameters.type == BreakpointByFileAndLine
+                && m_options->breakpointCorrection) {
+                if (lineCorrection.isNull())
+                    lineCorrection.reset(new BreakpointCorrectionContext(debuggerCore()->cppCodeModelSnapshot(),
+                                                                         CPlusPlus::CppModelManagerInterface::instance()->workingCopy()));
+                response.lineNumber = lineCorrection->fixLineNumber(parameters.fileName, parameters.lineNumber);
+                postCommand(cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false), 0);
+            } else {
+                postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
+            }
             if (!parameters.enabled)
-                postCommand("bd " + QByteArray::number(id), 0);
+                postCommand("bd " + QByteArray::number(id.majorPart()), 0);
             handler->notifyBreakpointInsertProceeding(id);
             handler->notifyBreakpointInsertOk(id);
             m_pendingBreakpointMap.insert(id, response);
             addedChanged = true;
+            // Ensure enabled/disabled is correct in handler and line number is there.
+            handler->setResponse(id, response);
             if (debugBreakpoints)
-                qDebug("Adding %llu %s\n", id, qPrintable(response.toString()));
+                qDebug("Adding %d %s\n", id.toInternalId(),
+                    qPrintable(response.toString()));
             break;
         case BreakpointChangeRequested:
             handler->notifyBreakpointChangeProceeding(id);
+            if (debugBreakpoints)
+                qDebug("Changing %d:\n    %s\nTo %s\n", id.toInternalId(),
+                    qPrintable(handler->response(id).toString()),
+                    qPrintable(parameters.toString()));
             if (parameters.enabled != handler->response(id).enabled) {
                 // Change enabled/disabled breakpoints without triggering update.
-                postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(id), 0);
+                postCommand((parameters.enabled ? "be " : "bd ")
+                    + QByteArray::number(id.majorPart()), 0);
                 response.pending = false;
                 response.enabled = parameters.enabled;
                 handler->setResponse(id, response);
             } else {
                 // Delete and re-add, triggering update
                 addedChanged = true;
-                postCommand("bc " + QByteArray::number(id), 0);
-                postCommand(cdbAddBreakpointCommand(parameters, id, false), 0);
+                postCommand("bc " + QByteArray::number(id.majorPart()), 0);
+                postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
                 m_pendingBreakpointMap.insert(id, response);
             }
             handler->notifyBreakpointChangeOk(id);
-            if (debugBreakpoints)
-                qDebug("Changing %llu %s\n", id, qPrintable(response.toString()));
             break;
         case BreakpointRemoveRequested:
-            postCommand("bc " + QByteArray::number(id), 0);
+            postCommand("bc " + QByteArray::number(id.majorPart()), 0);
             handler->notifyBreakpointRemoveProceeding(id);
             handler->notifyBreakpointRemoveOk(id);
             m_pendingBreakpointMap.remove(id);
@@ -2358,24 +2746,39 @@ void CdbEngine::attemptBreakpointSynchronization()
         postCommandSequence(CommandListBreakPoints);
 }
 
-QString CdbEngine::normalizeFileName(const QString &f)
+// Pass a file name through source mapping and normalize upper/lower case (for the editor
+// manager to correctly process it) and convert to clean path.
+CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDebugger(const QString &f)
 {
-    QMap<QString, QString>::const_iterator it = m_normalizedFileCache.constFind(f);
+    // 1) Check cache.
+    QMap<QString, NormalizedSourceFileName>::const_iterator it = m_normalizedFileCache.constFind(f);
     if (it != m_normalizedFileCache.constEnd())
         return it.value();
-    const QString winF = QDir::toNativeSeparators(f);
+    if (debugSourceMapping)
+        qDebug(">sourceMapNormalizeFileNameFromDebugger %s", qPrintable(f));
+    // Do we have source path mappings? ->Apply.
+    const QString fileName = cdbSourcePathMapping(QDir::toNativeSeparators(f), m_sourcePathMappings,
+                                                  DebuggerToSource);
+    // Up/lower case normalization according to Windows.
 #ifdef Q_OS_WIN
-    QString normalized = winNormalizeFileName(winF);
+    QString normalized = Utils::normalizePathName(fileName);
 #else
-    QString normalized = winF;
+    QString normalized = fileName;
 #endif
-    if (normalized.isEmpty()) { // At least upper case drive letter
-        normalized = winF;
-        if (normalized.size() > 2 && normalized.at(1) == QLatin1Char(':'))
-            normalized[0] = normalized.at(0).toUpper();
-    }
-    m_normalizedFileCache.insert(f, normalized);
-    return normalized;
+    if (debugSourceMapping)
+        qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized));
+    // Check if it really exists, that is normalize worked and QFileInfo confirms it.
+    const bool exists = !normalized.isEmpty() && QFileInfo(normalized).isFile();
+    NormalizedSourceFileName result(QDir::cleanPath(normalized.isEmpty() ? fileName : normalized), exists);
+    if (!exists) {
+        // At least upper case drive letter if failed.
+        if (result.fileName.size() > 2 && result.fileName.at(1) == QLatin1Char(':'))
+            result.fileName[0] = result.fileName.at(0).toUpper();
+    }
+    m_normalizedFileCache.insert(f, result);
+    if (debugSourceMapping)
+        qDebug("<sourceMapNormalizeFileNameFromDebugger %s %d", qPrintable(result.fileName), result.exists);
+    return result;
 }
 
 // Parse frame from GDBMI. Duplicate of the gdb code, but that
@@ -2393,7 +2796,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi)
         if (fullName.isValid()) {
             frame.file = QFile::decodeName(fullName.data());
             frame.line = frameMi.findChild("line").data().toInt();
-            frame.usable = QFileInfo(frame.file).isFile();
+            frame.usable = false; // To be decided after source path mapping.
         }
         frame.function = QLatin1String(frameMi.findChild("func").data());
         frame.from = QLatin1String(frameMi.findChild("from").data());
@@ -2421,7 +2824,9 @@ unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
             return ParseStackStepInto;
         }
         if (hasFile) {
-            frames[i].file = QDir::cleanPath(normalizeFileName(frames.at(i).file));
+            const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file);
+            frames[i].file = fileName.fileName;
+            frames[i].usable = fileName.exists;
             if (current == -1 && frames[i].usable)
                 current = i;
         }
@@ -2446,6 +2851,41 @@ void CdbEngine::handleStackTrace(const CdbExtensionCommandPtr &command)
     }
 }
 
+void CdbEngine::handleExpression(const CdbExtensionCommandPtr &command)
+{
+    int value = 0;
+    if (command->success) {
+        value = command->reply.toInt();
+    } else {
+        showMessage(command->errorMessage, LogError);
+    }
+    // Is this a conditional breakpoint?
+    if (command->cookie.isValid() && qVariantCanConvert<ConditionalBreakPointCookie>(command->cookie)) {
+        const ConditionalBreakPointCookie cookie = qvariant_cast<ConditionalBreakPointCookie>(command->cookie);
+        const QString message = value ?
+            tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
+            arg(value).arg(cookie.id.toString()) :
+            tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
+            arg(cookie.id.toString());
+        showMessage(message, LogMisc);
+        // Stop if evaluation is true, else continue
+        if (value) {
+            processStop(cookie.stopReason, true);
+        } else {
+            postCommand("g", 0);
+        }
+    }
+}
+
+void CdbEngine::evaluateExpression(QByteArray exp, const QVariant &cookie)
+{
+    if (exp.contains(' ') && !exp.startsWith('"')) {
+        exp.prepend('"');
+        exp.append('"');
+    }
+    postExtensionCommand("expression", exp, 0, &CdbEngine::handleExpression, 0, cookie);
+}
+
 void CdbEngine::dummyHandler(const CdbBuiltinCommandPtr &command)
 {
     postCommandSequence(command->commandSequence);
@@ -2515,10 +2955,10 @@ void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
     m_watchPointX = m_watchPointY = 0;
 }
 
-static inline void formatCdbBreakPointResponse(BreakpointId id, const BreakpointResponse &r,
+static inline void formatCdbBreakPointResponse(BreakpointModelId id, const BreakpointResponse &r,
                                                   QTextStream &str)
 {
-    str << "Obtained breakpoint " << id << " (#" << r.number << ')';
+    str << "Obtained breakpoint " << id << " (#" << r.id.majorPart() << ')';
     if (r.pending) {
         str << ", pending";
     } else {
@@ -2561,23 +3001,28 @@ void CdbEngine::handleBreakPoints(const GdbMi &value)
     BreakHandler *handler = breakHandler();
     foreach (const GdbMi &breakPointG, value.children()) {
         BreakpointResponse reportedResponse;
-        const BreakpointId id = parseBreakPoint(breakPointG, &reportedResponse);
+        parseBreakPoint(breakPointG, &reportedResponse);
         if (debugBreakpoints)
-            qDebug("  Parsed %llu: pending=%d %s\n", id, reportedResponse.pending,
-                   qPrintable(reportedResponse.toString()));
-
-        if (!reportedResponse.pending) {
-            const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(id);
+            qDebug("  Parsed %d: pending=%d %s\n", reportedResponse.id.majorPart(),
+                reportedResponse.pending,
+                qPrintable(reportedResponse.toString()));
+        if (reportedResponse.id.isValid() && !reportedResponse.pending) {
+            const BreakpointModelId mid = handler->findBreakpointByResponseId(reportedResponse.id);
+            QTC_ASSERT(mid.isValid(), continue; )
+            const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(mid);
             if (it != m_pendingBreakpointMap.end()) {
                 // Complete the response and set on handler.
                 BreakpointResponse &currentResponse = it.value();
-                currentResponse.number = reportedResponse.number;
+                currentResponse.id = reportedResponse.id;
                 currentResponse.address = reportedResponse.address;
                 currentResponse.module = reportedResponse.module;
                 currentResponse.pending = reportedResponse.pending;
                 currentResponse.enabled = reportedResponse.enabled;
-                formatCdbBreakPointResponse(id, currentResponse, str);
-                handler->setResponse(id, currentResponse);
+                formatCdbBreakPointResponse(mid, currentResponse, str);
+                if (debugBreakpoints)
+                    qDebug("  Setting for %d: %s\n", currentResponse.id.majorPart(),
+                        qPrintable(currentResponse.toString()));
+                handler->setResponse(mid, currentResponse);
                 m_pendingBreakpointMap.erase(it);
             }
         } // not pending reported
@@ -2627,6 +3072,10 @@ void CdbEngine::handleCustomSpecialStop(const QVariant &v)
         postCommand(cdbWriteMemoryCommand(changeData.address, changeData.data), 0);
         return;
     }
+    if (qVariantCanConvert<MemoryViewCookie>(v)) {
+        postFetchMemory(qVariantValue<MemoryViewCookie>(v));
+        return;
+    }
 }
 
 } // namespace Internal