Skip to content
Snippets Groups Projects
  • Christian Kandeler's avatar
    72d17382
    Remove superfluous include paths from project files. · 72d17382
    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: default avatarOswald Buddenhagen <oswald.buddenhagen@digia.com>
    Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@digia.com>
    72d17382
    History
    Remove superfluous include paths from project files.
    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: default avatarOswald Buddenhagen <oswald.buddenhagen@digia.com>
    Reviewed-by: default avatarJoerg 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