termgdbadapter.cpp 7.39 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30 31

#include "termgdbadapter.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
32

33 34 35 36 37
#include <debugger/debuggercore.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/shared/hostutils.h>
38

39
#include <utils/hostosinfo.h>
40 41
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
42
#include <coreplugin/messagebox.h>
43

44 45
using namespace Utils;

46 47 48 49 50 51 52 53 54
namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// TermGdbAdapter
//
///////////////////////////////////////////////////////////////////////

55
GdbTermEngine::GdbTermEngine(const DebuggerRunParameters &startParameters)
56
    : GdbEngine(startParameters)
57
{
58 59
#ifdef Q_OS_WIN
    // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
60
    if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
61
        m_stubProc.setMode(ConsoleProcess::Suspend);
62
    else
63
        m_stubProc.setMode(ConsoleProcess::Debug);
64
#else
65
    m_stubProc.setMode(ConsoleProcess::Debug);
hjk's avatar
hjk committed
66
    m_stubProc.setSettings(Core::ICore::settings());
67 68 69
#endif
}

70
GdbTermEngine::~GdbTermEngine()
71 72 73 74
{
    m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
}

75
void GdbTermEngine::setupEngine()
76
{
hjk's avatar
hjk committed
77
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
78
    showMessage(_("TRYING TO START ADAPTER"));
79 80 81 82 83 84 85

// Currently, adapters are not re-used
//    // We leave the console open, so recycle it now.
//    m_stubProc.blockSignals(true);
//    m_stubProc.stop();
//    m_stubProc.blockSignals(false);

hjk's avatar
hjk committed
86
    if (!prepareCommand())
87 88
        return;

89
    m_stubProc.setWorkingDirectory(runParameters().workingDirectory);
90
    // Set environment + dumper preload.
91
    m_stubProc.setEnvironment(runParameters().stubEnvironment);
92

93
    connect(&m_stubProc, &ConsoleProcess::processError,
Montel Laurent's avatar
Montel Laurent committed
94
            this, &GdbTermEngine::stubError);
95
    connect(&m_stubProc, &ConsoleProcess::processStarted,
Montel Laurent's avatar
Montel Laurent committed
96
            this, &GdbTermEngine::stubStarted);
97
    connect(&m_stubProc, &ConsoleProcess::stubStopped,
Montel Laurent's avatar
Montel Laurent committed
98
            this, &GdbTermEngine::stubExited);
99 100
    // FIXME: Starting the stub implies starting the inferior. This is
    // fairly unclean as far as the state machine and error reporting go.
101

102 103
    if (!m_stubProc.start(runParameters().executable,
                         runParameters().processArgs)) {
104
        // Error message for user is delivered via a signal.
105
        handleAdapterStartFailed(QString());
106 107
        return;
    }
108 109
}

110
void GdbTermEngine::stubStarted()
111
{
112
    startGdb();
113 114
}

115
void GdbTermEngine::handleGdbStartFailed()
116 117
{
    m_stubProc.stop();
118 119
}

120
void GdbTermEngine::setupInferior()
121
{
hjk's avatar
hjk committed
122
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
123
    const qint64 attachedPID = m_stubProc.applicationPID();
124
    const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID();
125
    notifyInferiorPid(attachedPID);
126
    const QString msg = (attachedMainThreadID != -1)
127 128
            ? QString::fromLatin1("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
            : QString::fromLatin1("Going to attach to %1").arg(attachedPID);
129
    showMessage(msg, LogMisc);
130 131 132 133 134 135 136
    handleInferiorPrepared();
}

void GdbTermEngine::runEngine()
{
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    const qint64 attachedPID = m_stubProc.applicationPID();
137 138
    runCommand({"attach " + QByteArray::number(attachedPID), NoFlags,
                [this](const DebuggerResponse &r) { handleStubAttached(r); }});
139 140
}

141
void GdbTermEngine::handleStubAttached(const DebuggerResponse &response)
142
{
143 144 145 146
    // InferiorStopOk can happen if the "*stopped" in response to the
    // 'attach' comes in before its '^done'
    QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk,
               qDebug() << state());
147

148
    switch (response.resultClass) {
149
    case ResultDone:
hjk's avatar
hjk committed
150
    case ResultRunning:
151
        if (runParameters().toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS) {
152 153 154 155 156 157 158 159 160 161 162
            QString errorMessage;
            // Resume thread that was suspended by console stub process (see stub code).
            const qint64 mainThreadId = m_stubProc.applicationMainThreadID();
            if (winResumeThread(mainThreadId, &errorMessage)) {
                showMessage(QString::fromLatin1("Inferior attached, thread %1 resumed").
                            arg(mainThreadId), LogMisc);
            } else {
                showMessage(QString::fromLatin1("Inferior attached, unable to resume thread %1: %2").
                            arg(mainThreadId).arg(errorMessage),
                            LogWarning);
            }
hjk's avatar
hjk committed
163
            notifyEngineRunAndInferiorStopOk();
164
            continueInferiorInternal();
hjk's avatar
hjk committed
165 166 167 168
        } else {
            showMessage(_("INFERIOR ATTACHED AND RUNNING"));
            //notifyEngineRunAndInferiorRunOk();
            // Wait for the upcoming *stopped and handle it there.
169 170
        }
        break;
171
    case ResultError:
172
        if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
173
            showMessage(msgPtraceError(runParameters().startMode));
174
            notifyEngineRunFailed();
175 176
            break;
        }
177
        showMessage(QString::fromLocal8Bit(response.data["msg"].data()));
178
        notifyEngineIll();
179 180
        break;
    default:
181
        showMessage(QString::fromLatin1("Invalid response %1").arg(response.resultClass));
182
        notifyEngineIll();
183
        break;
184 185 186
    }
}

187
void GdbTermEngine::interruptInferior2()
188
{
189
    interruptLocalInferior(inferiorPid());
190 191
}

192
void GdbTermEngine::stubError(const QString &msg)
193
{
194
    Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
195 196
}

197
void GdbTermEngine::stubExited()
198
{
hjk's avatar
hjk committed
199 200 201 202
    if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
        showMessage(_("STUB EXITED EXPECTEDLY"));
        return;
    }
203
    showMessage(_("STUB EXITED"));
204
    notifyEngineIll();
hjk's avatar
hjk committed
205 206
}

207
void GdbTermEngine::shutdownEngine()
hjk's avatar
hjk committed
208
{
209
    notifyAdapterShutdownOk();
210 211 212 213
}

} // namespace Internal
} // namespace Debugger