localplaingdbadapter.cpp 5.88 KB
Newer Older
ck's avatar
ck committed
1 2 3 4 5 6 7 8
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
ck's avatar
ck committed
10
**
con's avatar
con committed
11 12 13 14
** 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.
ck's avatar
ck committed
15 16 17 18 19 20 21 22 23 24
**
** 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.
**
con's avatar
con committed
25 26 27 28 29 30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
ck's avatar
ck committed
31 32 33 34 35 36
**
**************************************************************************/

#include "localplaingdbadapter.h"

#include "gdbengine.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
37
#include "debuggerstartparameters.h"
ck's avatar
ck committed
38
#include "procinterrupt.h"
hjk's avatar
hjk committed
39
#include "debuggercore.h"
ck's avatar
ck committed
40 41 42 43 44
#include "debuggerstringutils.h"

#include <utils/qtcassert.h>

#include <QtCore/QFileInfo>
45 46
#include <QtCore/QProcess>
#include <QtGui/QMessageBox>
ck's avatar
ck committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// PlainGdbAdapter
//
///////////////////////////////////////////////////////////////////////

LocalPlainGdbAdapter::LocalPlainGdbAdapter(GdbEngine *engine, QObject *parent)
    : AbstractPlainGdbAdapter(engine, parent)
{
    // Output
    connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
        engine, SLOT(readDebugeeOutput(QByteArray)));
}

AbstractGdbAdapter::DumperHandling LocalPlainGdbAdapter::dumperHandling() const
{
    // LD_PRELOAD fails for System-Qt on Mac.
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
    return DumperLoadedByGdb;
#else
    return DumperLoadedByGdbPreload;
#endif
}

void LocalPlainGdbAdapter::startAdapter()
{
hjk's avatar
hjk committed
77
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
78
    showMessage(_("TRYING TO START ADAPTER"));
ck's avatar
ck committed
79

80 81 82 83 84
#ifdef Q_OS_WIN
    if (!prepareWinCommand())
        return;
#endif

ck's avatar
ck committed
85 86 87
    QStringList gdbArgs;

    if (!m_outputCollector.listen()) {
88
        m_engine->handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
ck's avatar
ck committed
89 90 91 92 93
                .arg(m_outputCollector.errorString()), QString());
        return;
    }
    gdbArgs.append(_("--tty=") + m_outputCollector.serverName());

94 95
    if (!startParameters().workingDirectory.isEmpty())
        m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
96 97
    if (startParameters().environment.size())
        m_gdbProc.setEnvironment(startParameters().environment.toStringList());
ck's avatar
ck committed
98 99 100 101 102 103

    if (!m_engine->startGdb(gdbArgs)) {
        m_outputCollector.shutdown();
        return;
    }

104
    checkForReleaseBuild();
hjk's avatar
hjk committed
105
    m_engine->handleAdapterStarted();
106 107
}

hjk's avatar
hjk committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
void LocalPlainGdbAdapter::setupInferior()
{
    AbstractPlainGdbAdapter::setupInferior();
}

void LocalPlainGdbAdapter::runEngine()
{
    AbstractPlainGdbAdapter::runEngine();
}

void LocalPlainGdbAdapter::shutdownInferior()
{
    m_engine->defaultInferiorShutdown("kill");
}

void LocalPlainGdbAdapter::shutdownAdapter()
{
    showMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
    m_outputCollector.shutdown();
    m_engine->notifyAdapterShutdownOk();
}

130 131 132 133 134 135 136 137 138 139 140
void LocalPlainGdbAdapter::checkForReleaseBuild()
{
    // Quick check for a "release" build
    QProcess proc;
    QStringList args;
    args.append(_("-h"));
    args.append(_("-j"));
    args.append(_(".debug_info"));
    args.append(startParameters().executable);
    proc.start(_("objdump"), args);
    proc.closeWriteChannel();
141 142 143 144 145
    if (!proc.waitForStarted()) {
        showMessage(_("OBJDUMP PROCESS COULD NOT BE STARTED. "
            "RELEASE BUILD CHECK WILL FAIL"));
        return;
    }
146 147 148 149 150 151 152 153
    proc.waitForFinished();
    QByteArray ba = proc.readAllStandardOutput();
    // This should yield something like
    // "debuggertest:     file format elf32-i386\n\n"
    // "Sections:\nIdx Name          Size      VMA       LMA       File off  Algn\n"
    // "30 .debug_info   00087d36  00000000  00000000  0006bbd5  2**0\n"
    // " CONTENTS, READONLY, DEBUGGING"
    if (ba.contains("Sections:") && !ba.contains(".debug_info")) {
hjk's avatar
hjk committed
154
        showMessageBox(QMessageBox::Information, "Warning",
155 156 157
           tr("This does not seem to be a \"Debug\" build.\n"
              "Setting breakpoints by file name and line number may fail."));
    }
ck's avatar
ck committed
158 159 160 161
}

void LocalPlainGdbAdapter::interruptInferior()
{
162
    const qint64 attachedPID = m_engine->inferiorPid();
ck's avatar
ck committed
163
    if (attachedPID <= 0) {
164
        showMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
ck's avatar
ck committed
165 166 167
        return;
    }

168 169 170
    if (interruptProcess(attachedPID)) {
        showMessage(_("INTERRUPTED %1").arg(attachedPID));
    } else {
171
        showMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
hjk's avatar
hjk committed
172 173
        m_engine->notifyInferiorStopFailed();
    }
ck's avatar
ck committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
}

QByteArray LocalPlainGdbAdapter::execFilePath() const
{
    return QFileInfo(startParameters().executable)
            .absoluteFilePath().toLocal8Bit();
}

bool LocalPlainGdbAdapter::infoTargetNecessary() const
{
#ifdef Q_OS_LINUX
    return true;
#else
    return false;
#endif
}

QByteArray LocalPlainGdbAdapter::toLocalEncoding(const QString &s) const
{
    return s.toLocal8Bit();
}

QString LocalPlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const
{
    return QString::fromLocal8Bit(b);
}

} // namespace Internal
} // namespace Debugger