termgdbadapter.cpp 7.05 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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
12
13
14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16
17
18
19
20
21
22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
25
26

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

28
29
30
31
#include <debugger/debuggercore.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/shared/hostutils.h>
32

33
#include <utils/hostosinfo.h>
34
35
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
36
#include <coreplugin/messagebox.h>
37

38
39
using namespace Utils;

40
41
42
43
44
45
46
47
48
namespace Debugger {
namespace Internal {

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

49
GdbTermEngine::GdbTermEngine(const DebuggerRunParameters &startParameters)
50
    : GdbEngine(startParameters)
51
{
52
53
54
55
56
57
58
    if (HostOsInfo::isWindowsHost()) {
        // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
        if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
            m_stubProc.setMode(ConsoleProcess::Suspend);
        else
            m_stubProc.setMode(ConsoleProcess::Debug);
    } else {
59
        m_stubProc.setMode(ConsoleProcess::Debug);
60
61
        m_stubProc.setSettings(Core::ICore::settings());
    }
62
63
}

64
GdbTermEngine::~GdbTermEngine()
65
66
67
68
{
    m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
}

69
void GdbTermEngine::setupEngine()
70
{
hjk's avatar
hjk committed
71
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
72
    showMessage("TRYING TO START ADAPTER");
73
74
75
76
77
78
79

// 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
80
    if (!prepareCommand())
81
82
        return;

83
    m_stubProc.setWorkingDirectory(runParameters().inferior.workingDirectory);
84
    // Set environment + dumper preload.
85
    m_stubProc.setEnvironment(runParameters().stubEnvironment);
86

87
    connect(&m_stubProc, &ConsoleProcess::processError,
Montel Laurent's avatar
Montel Laurent committed
88
            this, &GdbTermEngine::stubError);
89
    connect(&m_stubProc, &ConsoleProcess::processStarted,
Montel Laurent's avatar
Montel Laurent committed
90
            this, &GdbTermEngine::stubStarted);
91
    connect(&m_stubProc, &ConsoleProcess::stubStopped,
Montel Laurent's avatar
Montel Laurent committed
92
            this, &GdbTermEngine::stubExited);
93
94
    // FIXME: Starting the stub implies starting the inferior. This is
    // fairly unclean as far as the state machine and error reporting go.
95

96
97
    if (!m_stubProc.start(runParameters().inferior.executable,
                         runParameters().inferior.commandLineArguments)) {
98
        // Error message for user is delivered via a signal.
99
        handleAdapterStartFailed(QString());
100
101
        return;
    }
102
103
}

104
void GdbTermEngine::stubStarted()
105
{
106
    startGdb();
107
108
}

109
void GdbTermEngine::handleGdbStartFailed()
110
111
{
    m_stubProc.stop();
112
113
}

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

void GdbTermEngine::runEngine()
{
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    const qint64 attachedPID = m_stubProc.applicationPID();
131
    runCommand({"attach " + QString::number(attachedPID),
132
                [this](const DebuggerResponse &r) { handleStubAttached(r); }});
133
134
}

135
void GdbTermEngine::handleStubAttached(const DebuggerResponse &response)
136
{
137
138
139
140
    // InferiorStopOk can happen if the "*stopped" in response to the
    // 'attach' comes in before its '^done'
    QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk,
               qDebug() << state());
141

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

181
void GdbTermEngine::interruptInferior2()
182
{
183
    interruptLocalInferior(inferiorPid());
184
185
}

186
void GdbTermEngine::stubError(const QString &msg)
187
{
188
    Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
189
    notifyEngineIll();
190
191
}

192
void GdbTermEngine::stubExited()
193
{
hjk's avatar
hjk committed
194
    if (state() == EngineShutdownRequested || state() == DebuggerFinished) {
hjk's avatar
hjk committed
195
        showMessage("STUB EXITED EXPECTEDLY");
hjk's avatar
hjk committed
196
197
        return;
    }
hjk's avatar
hjk committed
198
    showMessage("STUB EXITED");
199
    notifyEngineIll();
hjk's avatar
hjk committed
200
201
}

202
void GdbTermEngine::shutdownEngine()
hjk's avatar
hjk committed
203
{
204
    notifyAdapterShutdownOk();
205
206
207
208
}

} // namespace Internal
} // namespace Debugger