-
Christian Kandeler authored
A lot of our build system files specify unneeded include paths. These roughly fall into the following categories: a) Paths that are already set in more general files such as qtcreator.pri. b) Paths that serve no purpose at all, possibly left over from earlier versions of the project. c) Paths that act as workarounds for wrong include statements of the form '#include "xyz.h"', where xyz.h is not in the same directory as the including file. This patch removes such path specifications and fixes the offending include statements from case c). Tested on Linux, Windows and OSX with qmake and qbs. Change-Id: I039a8449f8a65df0d616b4c08081145c18ae4b15 Reviewed-by:
Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by:
Joerg Bornemann <joerg.bornemann@digia.com>
Christian Kandeler authoredA lot of our build system files specify unneeded include paths. These roughly fall into the following categories: a) Paths that are already set in more general files such as qtcreator.pri. b) Paths that serve no purpose at all, possibly left over from earlier versions of the project. c) Paths that act as workarounds for wrong include statements of the form '#include "xyz.h"', where xyz.h is not in the same directory as the including file. This patch removes such path specifications and fixes the offending include statements from case c). Tested on Linux, Windows and OSX with qmake and qbs. Change-Id: I039a8449f8a65df0d616b4c08081145c18ae4b15 Reviewed-by:
Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by:
Joerg Bornemann <joerg.bornemann@digia.com>
remotegdbserveradapter.cpp 18.68 KiB
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** 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
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "remotegdbserveradapter.h"
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerstringutils.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QFileInfo>
#include <QMessageBox>
namespace Debugger {
namespace Internal {
#define CB(callback) \
static_cast<GdbEngine::GdbCommandCallback>(&GdbRemoteServerEngine::callback), \
STRINGIFY(callback)
///////////////////////////////////////////////////////////////////////
//
// RemoteGdbAdapter
//
///////////////////////////////////////////////////////////////////////
GdbRemoteServerEngine::GdbRemoteServerEngine(const DebuggerStartParameters &startParameters)
: GdbEngine(startParameters)
{
m_isMulti = false;
m_targetPid = -1;
#ifdef Q_OS_WIN
m_gdbProc.setUseCtrlCStub(!startParameters.remoteExecutable.isEmpty()); // This is only set for QNX
#endif
connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
SLOT(uploadProcError(QProcess::ProcessError)));
connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()),
SLOT(readUploadStandardOutput()));
connect(&m_uploadProc, SIGNAL(readyReadStandardError()),
SLOT(readUploadStandardError()));
connect(&m_uploadProc, SIGNAL(finished(int)),
SLOT(uploadProcFinished()));
}
GdbEngine::DumperHandling GdbRemoteServerEngine::dumperHandling() const
{
using namespace ProjectExplorer;
const Abi abi = startParameters().toolChainAbi;
if (abi.os() == Abi::WindowsOS
|| abi.binaryFormat() == Abi::ElfFormat)
return DumperLoadedByGdb;
return DumperLoadedByGdbPreload;
}
void GdbRemoteServerEngine::setupEngine()
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER"));
if (!startParameters().serverStartScript.isEmpty()) {
// Provide script information about the environment
QString arglist;
Utils::QtcProcess::addArg(&arglist, startParameters().serverStartScript);
Utils::QtcProcess::addArg(&arglist, startParameters().executable);
Utils::QtcProcess::addArg(&arglist, startParameters().remoteChannel);
m_uploadProc.start(_("/bin/sh ") + arglist);
m_uploadProc.waitForStarted();
}
if (!startParameters().workingDirectory.isEmpty())
m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
if (startParameters().environment.size())
m_gdbProc.setEnvironment(startParameters().environment.toStringList());
if (startParameters().remoteSetupNeeded)
notifyEngineRequestRemoteSetup();
else
startGdb();
}
void GdbRemoteServerEngine::uploadProcError(QProcess::ProcessError error)
{
QString msg;
switch (error) {
case QProcess::FailedToStart:
msg = tr("The upload process failed to start. Shell missing?");
break;
case QProcess::Crashed:
msg = tr("The upload process crashed some time after starting "
"successfully.");
break;
case QProcess::Timedout:
msg = tr("The last waitFor...() function timed out. "
"The state of QProcess is unchanged, and you can try calling "
"waitFor...() again.");
break;
case QProcess::WriteError:
msg = tr("An error occurred when attempting to write "
"to the upload process. For example, the process may not be running, "
"or it may have closed its input channel.");
break;
case QProcess::ReadError:
msg = tr("An error occurred when attempting to read from "
"the upload process. For example, the process may not be running.");
break;
default:
msg = tr("An unknown error in the upload process occurred. "
"This is the default return value of error().");
}
showMessage(msg, StatusBar);
showMessageBox(QMessageBox::Critical, tr("Error"), msg);
}
void GdbRemoteServerEngine::readUploadStandardOutput()
{
const QByteArray ba = m_uploadProc.readAllStandardOutput();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
showMessage(msg, LogOutput);
showMessage(msg, AppOutput);
}
void GdbRemoteServerEngine::readUploadStandardError()
{
const QByteArray ba = m_uploadProc.readAllStandardError();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
showMessage(msg, LogOutput);
showMessage(msg, AppError);
}
void GdbRemoteServerEngine::uploadProcFinished()
{
if (m_uploadProc.exitStatus() == QProcess::NormalExit
&& m_uploadProc.exitCode() == 0)
startGdb();
else
notifyEngineRemoteSetupFailed(m_uploadProc.errorString());
}
void GdbRemoteServerEngine::setupInferior()
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
const DebuggerStartParameters &sp = startParameters();
QString executableFileName;
if (!sp.executable.isEmpty()) {
QFileInfo fi(sp.executable);
executableFileName = fi.absoluteFilePath();
}
QString symbolFileName;
if (!sp.symbolFileName.isEmpty()) {
QFileInfo fi(sp.symbolFileName);
symbolFileName = fi.absoluteFilePath();
}
//const QByteArray sysroot = sp.sysroot.toLocal8Bit();
//const QByteArray remoteArch = sp.remoteArchitecture.toLatin1();
const QString args = sp.processArgs;
// if (!remoteArch.isEmpty())
// postCommand("set architecture " + remoteArch);
const QString solibSearchPath
= sp.solibSearchPath.join(QString(Utils::HostOsInfo::pathListSeparator()));
if (!solibSearchPath.isEmpty())
postCommand("set solib-search-path " + solibSearchPath.toLocal8Bit());
if (!args.isEmpty())
postCommand("-exec-arguments " + args.toLocal8Bit());
// This has to be issued before 'target remote'. On pre-7.0 the
// command is not present and will result in ' No symbol table is
// loaded. Use the "file" command.' as gdb tries to set the
// value of a variable with name 'target-async'.
//
// Testing with -list-target-features which was introduced at
// the same time would not work either, as this need an existing
// target.
//
// Using it even without a target and having it fail might still
// be better as:
// Some external comment: '[but] "set target-async on" with a native
// windows gdb will work, but then fail when you actually do
// "run"/"attach", I think..
// gdb/mi/mi-main.c:1958: internal-error:
// mi_execute_async_cli_command: Assertion `is_running (inferior_ptid)'
// failed.\nA problem internal to GDB has been detected,[...]
if (debuggerCore()->boolSetting(TargetAsync))
postCommand("set target-async on", CB(handleSetTargetAsync));
if (executableFileName.isEmpty() && symbolFileName.isEmpty()) {
showMessage(tr("No symbol file given."), StatusBar);
callTargetRemote();
return;
}
if (!symbolFileName.isEmpty()) {
postCommand("-file-symbol-file \""
+ symbolFileName.toLocal8Bit() + '"',
CB(handleFileExecAndSymbols));
}
if (!executableFileName.isEmpty()) {
postCommand("-file-exec-and-symbols \"" + executableFileName.toLocal8Bit() + '"',
CB(handleFileExecAndSymbols));
}
}
void GdbRemoteServerEngine::handleSetTargetAsync(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultError)
qDebug() << "Adapter too old: does not support asynchronous mode.";
}
void GdbRemoteServerEngine::handleFileExecAndSymbols(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
callTargetRemote();
} else {
QByteArray reason = response.data["msg"].data();
QString msg = tr("Reading debug information failed:\n");
msg += QString::fromLocal8Bit(reason);
if (reason.endsWith("No such file or directory.")) {
showMessage(_("INFERIOR STARTUP: BINARY NOT FOUND"));
showMessage(msg, StatusBar);
callTargetRemote(); // Proceed nevertheless.
} else {
notifyInferiorSetupFailed(msg);
}
}
}
void GdbRemoteServerEngine::callTargetRemote()
{
QByteArray rawChannel = startParameters().remoteChannel.toLatin1();
QByteArray channel = rawChannel;
// Don't touch channels with explicitly set protocols.
if (!channel.startsWith("tcp:") && !channel.startsWith("udp:")
&& !channel.startsWith("file:") && channel.contains(':'))
{
// "Fix" the IPv6 case with host names without '['...']'
if (!channel.startsWith('[') && channel.count(':') >= 2) {
channel.insert(0, '[');
channel.insert(channel.lastIndexOf(':'), ']');
}
channel = "tcp:" + channel;
}
if (m_isQnxGdb)
postCommand("target qnx " + channel, CB(handleTargetQnx));
else if (m_isMulti)
postCommand("target extended-remote " + m_serverChannel, CB(handleTargetExtendedRemote));
else
postCommand("target remote " + channel, CB(handleTargetRemote), 10);
}
void GdbRemoteServerEngine::handleTargetRemote(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
// gdb server will stop the remote application itself.
showMessage(_("INFERIOR STARTED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
QString postAttachCommands = debuggerCore()->stringSetting(GdbPostAttachCommands);
if (!postAttachCommands.isEmpty()) {
foreach (const QString &cmd, postAttachCommands.split(QLatin1Char('\n')))
postCommand(cmd.toLatin1());
}
handleInferiorPrepared();
} else {
// 16^error,msg="hd:5555: Connection timed out."
QString msg = msgConnectRemoteServerFailed(
QString::fromLocal8Bit(response.data["msg"].data()));
notifyInferiorSetupFailed(msg);
}
}
void GdbRemoteServerEngine::handleTargetExtendedRemote(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
// gdb server will stop the remote application itself.
showMessage(_("ATTACHED TO GDB SERVER STARTED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
QString postAttachCommands = debuggerCore()->stringSetting(GdbPostAttachCommands);
if (!postAttachCommands.isEmpty()) {
foreach (const QString &cmd, postAttachCommands.split(QLatin1Char('\n')))
postCommand(cmd.toLatin1());
}
postCommand("attach " + QByteArray::number(m_targetPid), CB(handleTargetExtendedAttach));
} else {
QString msg = msgConnectRemoteServerFailed(
QString::fromLocal8Bit(response.data["msg"].data()));
notifyInferiorSetupFailed(msg);
}
}
void GdbRemoteServerEngine::handleTargetExtendedAttach(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
// gdb server will stop the remote application itself.
handleInferiorPrepared();
} else {
QString msg = msgConnectRemoteServerFailed(
QString::fromLocal8Bit(response.data["msg"].data()));
notifyInferiorSetupFailed(msg);
}
}
void GdbRemoteServerEngine::notifyInferiorSetupOk()
{
emit aboutToNotifyInferiorSetupOk();
GdbEngine::notifyInferiorSetupOk();
}
void GdbRemoteServerEngine::handleTargetQnx(const GdbResponse &response)
{
QTC_ASSERT(m_isQnxGdb, qDebug() << m_isQnxGdb);
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
// gdb server will stop the remote application itself.
showMessage(_("INFERIOR STARTED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
const qint64 pid = isMasterEngine() ? startParameters().attachPID : masterEngine()->startParameters().attachPID;
if (pid > -1)
postCommand("attach " + QByteArray::number(pid), CB(handleAttach));
else
handleInferiorPrepared();
} else {
// 16^error,msg="hd:5555: Connection timed out."
QString msg = msgConnectRemoteServerFailed(
QString::fromLocal8Bit(response.data["msg"].data()));
notifyInferiorSetupFailed(msg);
}
}
void GdbRemoteServerEngine::handleAttach(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
switch (response.resultClass) {
case GdbResultDone:
case GdbResultRunning: {
showMessage(_("INFERIOR ATTACHED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
handleInferiorPrepared();
break;
}
case GdbResultError:
if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
notifyInferiorSetupFailed(DumperHelper::msgPtraceError(startParameters().startMode));
break;
}
// if msg != "ptrace: ..." fall through
default:
QString msg = QString::fromLocal8Bit(response.data["msg"].data());
notifyInferiorSetupFailed(msg);
}
}
void GdbRemoteServerEngine::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
const QString remoteExecutable = startParameters().remoteExecutable;
if (!remoteExecutable.isEmpty()) {
// Cannot use -exec-run for QNX gdb 7.4 as it does not support path parameter for the MI call
const bool useRun = m_isQnxGdb && m_gdbVersion > 70300;
QByteArray command = useRun ? "run" : "-exec-run";
command += " " + remoteExecutable.toLocal8Bit();
const QByteArray arguments = isMasterEngine() ? startParameters().processArgs.toLocal8Bit() : masterEngine()->startParameters().processArgs.toLocal8Bit();
command += " " + arguments;
postCommand(command, GdbEngine::RunRequest, CB(handleExecRun));
} else {
notifyEngineRunAndInferiorStopOk();
continueInferiorInternal();
}
}
void GdbRemoteServerEngine::handleExecRun(const GdbResponse &response)
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) {
notifyEngineRunAndInferiorRunOk();
showMessage(_("INFERIOR STARTED"));
showMessage(msgInferiorSetupOk(), StatusBar);
} else {
QString msg = QString::fromLocal8Bit(response.data["msg"].data());
showMessage(msg);
notifyEngineRunFailed();
}
}
void GdbRemoteServerEngine::interruptInferior2()
{
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
if (debuggerCore()->boolSetting(TargetAsync)) {
postCommand("-exec-interrupt", GdbEngine::Immediate,
CB(handleInterruptInferior));
#ifdef Q_OS_WIN
} else if (m_isQnxGdb) {
m_gdbProc.winInterruptByCtrlC();
#endif
} else {
bool ok = m_gdbProc.interrupt();
if (!ok) {
// FIXME: Extra state needed?
showMessage(_("NOTE: INFERIOR STOP NOT POSSIBLE"));
showStatusMessage(tr("Interrupting not possible"));
notifyInferiorRunOk();
}
}
}
void GdbRemoteServerEngine::handleInterruptInferior(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
// The gdb server will trigger extra output that we will pick up
// to do a proper state transition.
} else {
// FIXME: On some gdb versions like git 170ffa5d7dd this produces
// >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
notifyInferiorStopOk();
}
}
void GdbRemoteServerEngine::shutdownEngine()
{
notifyAdapterShutdownOk();
}
void GdbRemoteServerEngine::notifyEngineRemoteServerRunning
(const QByteArray &serverChannel, int inferiorPid)
{
showMessage(_("NOTE: REMOTE SERVER RUNNING IN MULTIMODE"));
m_isMulti = true;
m_targetPid = inferiorPid;
m_serverChannel = serverChannel;
startGdb();
}
void GdbRemoteServerEngine::notifyEngineRemoteSetupDone(int gdbServerPort, int qmlPort)
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
DebuggerEngine::notifyEngineRemoteSetupDone(gdbServerPort, qmlPort);
if (m_isMulti) {
// Has been done in notifyEngineRemoteServerRunning
} else {
if (qmlPort != -1)
startParameters().qmlServerPort = qmlPort;
if (gdbServerPort != -1) {
QString &rc = startParameters().remoteChannel;
const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
if (sepIndex != -1) {
rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
QString::number(gdbServerPort));
}
}
startGdb();
}
}
void GdbRemoteServerEngine::notifyEngineRemoteSetupFailed(const QString &reason)
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
DebuggerEngine::notifyEngineRemoteSetupFailed(reason);
handleAdapterStartFailed(reason);
}
} // namespace Internal
} // namespace Debugger