debugger: rework startup logic

This commit is contained in:
hjk
2009-09-21 11:09:38 +02:00
parent ae2cfdaa53
commit 1d64e169b0
9 changed files with 923 additions and 466 deletions

View File

@@ -33,6 +33,7 @@
#include "gdboptionspage.h"
#include "trkoptions.h"
#include "trkoptionspage.h"
#include "plaingdbadapter.h"
#include "trkgdbadapter.h"
#include "watchutils.h"
@@ -82,6 +83,9 @@
#endif
#include <ctype.h>
static QString lastFile;
static int lastLine;
namespace Debugger {
namespace Internal {
using namespace Debugger::Constants;
@@ -141,44 +145,13 @@ static QByteArray parsePlainConsoleStream(const GdbResultRecord &record)
return out.mid(pos + 3);
}
///////////////////////////////////////////////////////////////////////
//
// PlainGdbAdapter
//
///////////////////////////////////////////////////////////////////////
void PlainGdbAdapter::attach()
{
QFileInfo fi(m_engine->startParameters().executable);
m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()),
&GdbEngine::handleFileExecAndSymbols, "handleFileExecAndSymbols");
}
void PlainGdbAdapter::interruptInferior()
{
if (m_engine->startMode() == StartRemote) {
m_engine->postCommand(_("-exec-interrupt"));
return;
}
const qint64 attachedPID = m_engine->inferiorPid();
if (attachedPID <= 0) {
m_engine->debugMessage(
_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
return;
}
if (!interruptProcess(attachedPID))
m_engine->debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}
///////////////////////////////////////////////////////////////////////
//
// GdbEngine
//
///////////////////////////////////////////////////////////////////////
GdbEngine::GdbEngine(DebuggerManager *parent, AbstractGdbAdapter *gdbAdapter) :
GdbEngine::GdbEngine(DebuggerManager *parent) :
#ifdef Q_OS_WIN // Do injection loading with MinGW (call loading does not work with 64bit)
m_dumperInjectionLoad(true),
#else
@@ -187,21 +160,24 @@ GdbEngine::GdbEngine(DebuggerManager *parent, AbstractGdbAdapter *gdbAdapter) :
m_manager(parent),
qq(parent->engineInterface())
{
m_gdbAdapter = gdbAdapter;
m_gdbAdapter->setEngine(this);
m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug);
#ifdef Q_OS_UNIX
m_stubProc.setSettings(Core::ICore::instance()->settings());
#endif
initializeVariables();
initializeConnections();
m_gdbAdapter = 0;
}
GdbEngine::~GdbEngine()
{
// prevent sending error messages afterwards
m_gdbAdapter->disconnect(this);
delete m_gdbAdapter;
if (m_gdbAdapter) {
m_gdbAdapter->disconnect(this);
delete m_gdbAdapter;
m_gdbAdapter = 0;
}
}
void GdbEngine::setGdbAdapter(AbstractGdbAdapter *gdbAdapter)
{
m_gdbAdapter = gdbAdapter;
initializeVariables();
initializeConnections();
}
void GdbEngine::initializeConnections()
@@ -213,16 +189,31 @@ void GdbEngine::initializeConnections()
this, SLOT(readGdbStandardOutput()));
connect(m_gdbAdapter, SIGNAL(readyReadStandardError()),
this, SLOT(readGdbStandardError()));
connect(m_gdbAdapter, SIGNAL(finished(int, QProcess::ExitStatus)),
m_manager, SLOT(exitDebugger()));
connect(m_gdbAdapter, SIGNAL(started()),
this, SLOT(startDebugger2()));
connect(&m_stubProc, SIGNAL(processError(QString)),
this, SLOT(stubError(QString)));
connect(&m_stubProc, SIGNAL(processStarted()),
this, SLOT(stubStarted()));
connect(&m_stubProc, SIGNAL(wrapperStopped()),
connect(m_gdbAdapter, SIGNAL(adapterStarted()),
this, SLOT(handleAdapterStarted()));
connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString)),
this, SLOT(handleAdapterStartFailed(QString)));
connect(m_gdbAdapter, SIGNAL(adapterShutDown()),
this, SLOT(handleAdapterShutDown()));
connect(m_gdbAdapter, SIGNAL(adapterShutdownFailed(QString)),
this, SLOT(handleAdapterShutdownFailed(QString)));
connect(m_gdbAdapter, SIGNAL(inferiorPrepared()),
this, SLOT(handleInferiorPrepared()));
connect(m_gdbAdapter, SIGNAL(inferiorPreparationFailed(QString)),
this, SLOT(handleInferiorPreparationFailed(QString)));
connect(m_gdbAdapter, SIGNAL(inferiorStarted()),
this, SLOT(handleInferiorStarted()));
connect(m_gdbAdapter, SIGNAL(inferiorStartFailed(QString)),
this, SLOT(handleInferiorStartFailed(QString)));
connect(m_gdbAdapter, SIGNAL(inferiorShutDown()),
this, SLOT(handleInferiorShutDown()));
connect(m_gdbAdapter, SIGNAL(inferiorShutdownFailed(QString)),
this, SLOT(handleInferiorShutdownFailed(QString)));
connect(m_gdbAdapter, SIGNAL(adapterCrashed()),
m_manager, SLOT(exitDebugger()));
connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
@@ -269,7 +260,7 @@ void GdbEngine::initializeVariables()
m_oldestAcceptableToken = -1;
m_outputCodec = QTextCodec::codecForLocale();
m_pendingRequests = 0;
m_autoContinue = false;
m_continuationAfterDone = 0;
m_waitingForFirstBreakpointToBeHit = false;
m_commandsToRunOnTemporaryBreak.clear();
m_cookieForToken.clear();
@@ -287,10 +278,8 @@ void GdbEngine::initializeVariables()
// FIXME: unhandled:
//m_outputCodecState = QTextCodec::ConverterState();
//OutputCollector m_outputCollector;
//QProcess m_gdbAdapter;
//QProcess m_uploadProc;
//Core::Utils::ConsoleProcess m_stubProc;
}
void GdbEngine::gdbProcError(QProcess::ProcessError error)
@@ -544,11 +533,13 @@ void GdbEngine::handleResponse(const QByteArray &buff)
}
case '~': {
static QRegExp re(_("New .hread 0x[0-9a-f]* \\(LWP ([0-9]*)\\)"));
QByteArray data = GdbMi::parseCString(from, to);
m_pendingConsoleStreamOutput += data;
if (data.startsWith("Reading symbols from ")) {
if (re.indexIn(_(data)) != -1)
maybeHandleInferiorPidChanged(re.cap(1));
if (data.startsWith("Reading symbols from "))
showStatusMessage(tr("Reading %1...").arg(_(data.mid(21))));
}
break;
}
@@ -633,25 +624,6 @@ void GdbEngine::handleResponse(const QByteArray &buff)
}
}
void GdbEngine::handleStubAttached(const GdbResultRecord &, const QVariant &)
{
qq->notifyInferiorStopped();
handleAqcuiredInferior();
m_autoContinue = true;
}
void GdbEngine::stubStarted()
{
const qint64 attachedPID = m_stubProc.applicationPID();
qq->notifyInferiorPidChanged(attachedPID);
postCommand(_("attach %1").arg(attachedPID), CB(handleStubAttached));
}
void GdbEngine::stubError(const QString &msg)
{
QMessageBox::critical(mainWindow(), tr("Debugger Error"), msg);
}
void GdbEngine::readGdbStandardError()
{
qWarning() << "Unexpected gdb stderr:" << m_gdbAdapter->readAllStandardError();
@@ -717,6 +689,18 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
tryLoadDebuggingHelpers();
}
void GdbEngine::postCommand(const QString &command, AdapterCallback callback,
const char *callbackName, const QVariant &cookie)
{
GdbCommand cmd;
cmd.command = command;
//cmd.flags = flags;
cmd.adapterCallback = callback;
cmd.callbackName = callbackName;
cmd.cookie = cookie;
postCommandHelper(cmd);
}
void GdbEngine::postCommand(const QString &command, GdbCommandCallback callback,
const char *callbackName, const QVariant &cookie)
{
@@ -727,28 +711,32 @@ void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags,
GdbCommandCallback callback, const char *callbackName,
const QVariant &cookie)
{
if (m_gdbAdapter->state() == QProcess::NotRunning) {
debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + command);
return;
}
if (flags & RebuildModel) {
++m_pendingRequests;
PENDING_DEBUG(" CALLBACK" << callbackName << "INCREMENTS PENDING TO:"
<< m_pendingRequests << command);
} else {
PENDING_DEBUG(" UNKNOWN CALLBACK" << callbackName << "LEAVES PENDING AT:"
<< m_pendingRequests << command);
}
GdbCommand cmd;
cmd.command = command;
cmd.flags = flags;
cmd.callback = callback;
cmd.callbackName = callbackName;
cmd.cookie = cookie;
postCommandHelper(cmd);
}
if ((flags & NeedsStop) && status() != DebuggerInferiorStopped
void GdbEngine::postCommandHelper(const GdbCommand &cmd)
{
if (m_gdbAdapter->state() == QProcess::NotRunning) {
debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + cmd.command);
return;
}
if (cmd.flags & RebuildModel) {
++m_pendingRequests;
PENDING_DEBUG(" CALLBACK" << cmd.callbackName
<< "INCREMENTS PENDING TO:" << m_pendingRequests << cmd.command);
} else {
PENDING_DEBUG(" UNKNOWN CALLBACK" << cmd.callbackName
<< "LEAVES PENDING AT:" << m_pendingRequests << cmd.command);
}
if ((cmd.flags & NeedsStop) && status() != DebuggerInferiorStopped
&& status() != DebuggerProcessStartingUp) {
// queue the commands that we cannot send at once
QTC_ASSERT(status() == DebuggerInferiorRunning,
@@ -757,13 +745,14 @@ void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags,
debugMessage(_("QUEUING COMMAND ") + cmd.command);
m_commandsToRunOnTemporaryBreak.append(cmd);
interruptInferior();
} else if (!command.isEmpty()) {
} else if (!cmd.command.isEmpty()) {
flushCommand(cmd);
}
}
void GdbEngine::flushCommand(GdbCommand &cmd)
void GdbEngine::flushCommand(const GdbCommand &cmd0)
{
GdbCommand cmd = cmd0;
if (m_gdbAdapter->state() != QProcess::Running) {
emit gdbInputAvailable(LogInput, cmd.command);
debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + cmd.command);
@@ -834,7 +823,9 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
// << "\n data: " << record.data.toString(true);
if (cmd.callback)
(this->*(cmd.callback))(record, cmd.cookie);
(this->*cmd.callback)(record, cmd.cookie);
if (cmd.adapterCallback)
(m_gdbAdapter->*cmd.adapterCallback)(record, cmd.cookie);
if (cmd.flags & RebuildModel) {
--m_pendingRequests;
@@ -855,10 +846,13 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
// An optimization would be requesting the continue immediately when the
// event loop is entered, and let individual commands have a flag to suppress
// that behavior.
if (m_cookieForToken.isEmpty() && m_autoContinue) {
m_autoContinue = false;
continueInferior();
showStatusMessage(tr("Continuing after temporary stop."));
if (m_continuationAfterDone && m_cookieForToken.isEmpty()) {
Continuation cont = m_continuationAfterDone;
m_continuationAfterDone = 0;
(this->*cont)();
//showStatusMessage(tr("Continuing after temporary stop."));
} else {
PENDING_DEBUG("MISSING TOKENS: " << m_cookieForToken.keys());
}
}
@@ -1077,7 +1071,7 @@ void GdbEngine::handleAqcuiredInferior()
void GdbEngine::handleAsyncOutput(const GdbMi &data)
{
const QByteArray &reason = data.findChild("reason").data();
const QByteArray reason = data.findChild("reason").data();
if (isExitedReason(reason)) {
qq->notifyInferiorExited();
@@ -1107,7 +1101,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
qq->notifyInferiorStopped();
handleAqcuiredInferior();
m_autoContinue = true;
// FIXME: m_continuationAfterDone = true;
return;
}
@@ -1123,7 +1117,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
flushCommand(cmd);
}
showStatusMessage(tr("Processing queued commands."));
m_autoContinue = true;
// FIXME: m_continuationAfterDone = true;
return;
}
@@ -1185,64 +1179,12 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
}
if (isStoppedReason(reason) || reason.isEmpty()) {
if (m_modulesListOutdated) {
reloadModules();
m_modulesListOutdated = false;
}
// Need another round trip
if (reason == "breakpoint-hit") {
showStatusMessage(tr("Stopped at breakpoint."));
GdbMi frame = data.findChild("frame");
//debugMessage(_("HIT BREAKPOINT: " + frame.toString()));
m_currentFrame = _(frame.findChild("addr").data() + '%' +
frame.findChild("func").data() + '%');
if (theDebuggerAction(ListSourceFiles)->value().toBool())
reloadSourceFiles();
postCommand(_("-break-list"), CB(handleBreakList));
QVariant var = QVariant::fromValue<GdbMi>(data);
postCommand(_("p 0"), CB(handleAsyncOutput2), var); // dummy
QVariant var = QVariant::fromValue<GdbMi>(data);
if (m_debuggingHelperState == DebuggingHelperUninitialized) {
tryLoadDebuggingHelpers();
postCommand(_("p 4"), CB(handleStop1), var); // dummy
} else {
#ifdef Q_OS_LINUX
// For some reason, attaching to a stopped process causes *two* stops
// when trying to continue (kernel 2.6.24-23-ubuntu).
// Interestingly enough, on MacOSX no signal is delivered at all.
if (reason == "signal-received"
&& data.findChild("signal-name").data() == "SIGSTOP") {
GdbMi frameData = data.findChild("frame");
if (frameData.findChild("func").data() == "_start"
&& frameData.findChild("from").data() == "/lib/ld-linux.so.2") {
postCommand(_("-exec-continue"), CB(handleExecContinue));
return;
}
}
#endif
if (reason == "signal-received"
&& theDebuggerBoolSetting(UseMessageBoxForSignals)) {
QByteArray name = data.findChild("signal-name").data();
// Ignore SIGTRAP as they are showing up regularily when
// stopping debugging.
if (name != "SIGTRAP") {
QByteArray meaning = data.findChild("signal-meaning").data();
QString msg = tr("<p>The inferior stopped because it received a "
"signal from the Operating System.<p>"
"<table><tr><td>Signal name : </td><td>%1</td></tr>"
"<tr><td>Signal meaning : </td><td>%2</td></tr></table>")
.arg(name.isEmpty() ? tr(" <Unknown> ") : _(name))
.arg(meaning.isEmpty() ? tr(" <Unknown> ") : _(meaning));
QMessageBox *mb = new QMessageBox(QMessageBox::Information,
tr("Signal received"), msg, QMessageBox::NoButton,
mainWindow());
mb->setAttribute(Qt::WA_DeleteOnClose);
mb->show();
}
}
if (reason.isEmpty())
showStatusMessage(tr("Stopped."));
else
showStatusMessage(tr("Stopped: \"%1\"").arg(_(reason)));
handleAsyncOutput2(data);
handleStop1(GdbResultRecord(), var);
}
return;
}
@@ -1296,12 +1238,77 @@ void GdbEngine::reloadStack()
postCommand(cmd, WatchUpdate, CB(handleStackListFrames), false);
}
void GdbEngine::handleAsyncOutput2(const GdbResultRecord &, const QVariant &cookie)
void GdbEngine::handleStop1(const GdbResultRecord &, const QVariant &cookie)
{
handleAsyncOutput2(cookie.value<GdbMi>());
GdbMi data = cookie.value<GdbMi>();
QByteArray reason = data.findChild("reason").data();
if (m_modulesListOutdated) {
reloadModules();
m_modulesListOutdated = false;
}
// Need another round trip
if (reason == "breakpoint-hit") {
showStatusMessage(tr("Stopped at breakpoint."));
GdbMi frame = data.findChild("frame");
//debugMessage(_("HIT BREAKPOINT: " + frame.toString()));
m_currentFrame = _(frame.findChild("addr").data() + '%' +
frame.findChild("func").data() + '%');
if (theDebuggerAction(ListSourceFiles)->value().toBool())
reloadSourceFiles();
postCommand(_("-break-list"), CB(handleBreakList));
QVariant var = QVariant::fromValue<GdbMi>(data);
postCommand(_("p 0"), CB(handleStop2), var); // dummy
} else {
#ifdef Q_OS_LINUX
// For some reason, attaching to a stopped process causes *two* stops
// when trying to continue (kernel 2.6.24-23-ubuntu).
// Interestingly enough, on MacOSX no signal is delivered at all.
if (reason == "signal-received"
&& data.findChild("signal-name").data() == "SIGSTOP") {
GdbMi frameData = data.findChild("frame");
if (frameData.findChild("func").data() == "_start"
&& frameData.findChild("from").data() == "/lib/ld-linux.so.2") {
postCommand(_("-exec-continue"), CB(handleExecContinue));
return;
}
}
#endif
if (reason == "signal-received"
&& theDebuggerBoolSetting(UseMessageBoxForSignals)) {
QByteArray name = data.findChild("signal-name").data();
// Ignore SIGTRAP as they are showing up regularily when
// stopping debugging.
if (name != "SIGTRAP") {
QByteArray meaning = data.findChild("signal-meaning").data();
QString msg = tr("<p>The inferior stopped because it received a "
"signal from the Operating System.<p>"
"<table><tr><td>Signal name : </td><td>%1</td></tr>"
"<tr><td>Signal meaning : </td><td>%2</td></tr></table>")
.arg(name.isEmpty() ? tr(" <Unknown> ") : _(name))
.arg(meaning.isEmpty() ? tr(" <Unknown> ") : _(meaning));
QMessageBox *mb = new QMessageBox(QMessageBox::Information,
tr("Signal received"), msg, QMessageBox::NoButton,
mainWindow());
mb->setAttribute(Qt::WA_DeleteOnClose);
mb->show();
}
}
if (reason.isEmpty())
showStatusMessage(tr("Stopped."));
else
showStatusMessage(tr("Stopped: \"%1\"").arg(_(reason)));
handleStop2(data);
}
}
void GdbEngine::handleAsyncOutput2(const GdbMi &data)
void GdbEngine::handleStop2(const GdbResultRecord &, const QVariant &cookie)
{
handleStop2(cookie.value<GdbMi>());
}
void GdbEngine::handleStop2(const GdbMi &data)
{
qq->notifyInferiorStopped();
@@ -1399,6 +1406,7 @@ void GdbEngine::handleFileExecAndSymbols(const GdbResultRecord &response, const
}
}
#if 0
void GdbEngine::handleExecRun(const GdbResultRecord &response, const QVariant &)
{
if (response.resultClass == GdbResultRunning) {
@@ -1413,6 +1421,7 @@ void GdbEngine::handleExecRun(const GdbResultRecord &response, const QVariant &)
qq->notifyInferiorExited();
}
}
#endif
void GdbEngine::handleExecContinue(const GdbResultRecord &response, const QVariant &)
{
@@ -1519,6 +1528,7 @@ void GdbEngine::handleExitHelper(const GdbResultRecord &, const QVariant &)
void GdbEngine::exitDebugger2()
{
/*
postCommand(_("-gdb-exit"), CB(handleExit));
// 20s can easily happen when loading webkit debug information
if (!m_gdbAdapter->waitForFinished(20000)) {
@@ -1533,6 +1543,7 @@ void GdbEngine::exitDebugger2()
.arg(m_gdbAdapter->state()));
m_gdbAdapter->kill();
}
*/
m_outputCollector.shutdown();
initializeVariables();
@@ -1548,6 +1559,8 @@ int GdbEngine::currentFrame() const
void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
{
m_startParameters = sp;
m_gdbAdapter->startAdapter(sp);
/*
// This should be set by the constructor or in exitDebugger().
QTC_ASSERT(m_debuggingHelperState == DebuggingHelperUninitialized,
initializeVariables());
@@ -1619,154 +1632,7 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
QString loc = theDebuggerStringSetting(GdbLocation);
showStatusMessage(tr("Starting Debugger: ") + loc + _c(' ') + gdbArgs.join(_(" ")));
m_gdbAdapter->start(loc, gdbArgs);
}
void GdbEngine::emitStartFailed()
{
// QMessageBox::critical(mainWindow(), tr("Debugger Startup Failure"),
// tr("Cannot start debugger: %1").arg(m_gdbAdapter->errorString()));
m_outputCollector.shutdown();
m_stubProc.blockSignals(true);
m_stubProc.stop();
m_stubProc.blockSignals(false);
emit startFailed();
}
void GdbEngine::startDebugger2()
{
debugMessage(_("STARTUP, PHASE 2"));
showStatusMessage(tr("Gdb Running..."));
postCommand(_("show version"), CB(handleShowVersion));
//postCommand(_("-enable-timings");
postCommand(_("set print static-members off")); // Seemingly doesn't work.
//postCommand(_("set debug infrun 1"));
//postCommand(_("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend"));
//postCommand(_("define hook-stop\nprint 4\nend"));
//postCommand(_("define hookpost-stop\nprint 5\nend"));
//postCommand(_("define hook-call\nprint 6\nend"));
//postCommand(_("define hookpost-call\nprint 7\nend"));
//postCommand(_("set print object on")); // works with CLI, but not MI
//postCommand(_("set step-mode on")); // we can't work with that yes
//postCommand(_("set exec-done-display on"));
//postCommand(_("set print pretty on"));
//postCommand(_("set confirm off"));
//postCommand(_("set pagination off"));
postCommand(_("set print inferior-events 1"));
postCommand(_("set breakpoint pending on"));
postCommand(_("set print elements 10000"));
postCommand(_("-data-list-register-names"), CB(handleRegisterListNames));
//postCommand(_("set substitute-path /var/tmp/qt-x11-src-4.5.0 "
// "/home/sandbox/qtsdk-2009.01/qt"));
// one of the following is needed to prevent crashes in gdb on code like:
// template <class T> T foo() { return T(0); }
// int main() { return foo<int>(); }
// (gdb) call 'int foo<int>'()
// /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error:
postCommand(_("set overload-resolution off"));
//postCommand(_("set demangle-style none"));
// From the docs:
// Stop means reenter debugger if this signal happens (implies print).
// Print means print a message if this signal happens.
// Pass means let program see this signal;
// otherwise program doesn't know.
// Pass and Stop may be combined.
// We need "print" as otherwise we would get no feedback whatsoever
// Custom DebuggingHelper crashs which happen regularily for when accessing
// uninitialized variables.
postCommand(_("handle SIGSEGV nopass stop print"));
// This is useful to kill the inferior whenever gdb dies.
//postCommand(_("handle SIGTERM pass nostop print"));
postCommand(_("set unwindonsignal on"));
//postCommand(_("pwd"));
postCommand(_("set width 0"));
postCommand(_("set height 0"));
#ifdef Q_OS_MAC
postCommand(_("-gdb-set inferior-auto-start-cfm off"));
postCommand(_("-gdb-set sharedLibrary load-rules "
"dyld \".*libSystem.*\" all "
"dyld \".*libauto.*\" all "
"dyld \".*AppKit.*\" all "
"dyld \".*PBGDBIntrospectionSupport.*\" all "
"dyld \".*Foundation.*\" all "
"dyld \".*CFDataFormatters.*\" all "
"dyld \".*libobjc.*\" all "
"dyld \".*CarbonDataFormatters.*\" all"));
#endif
QString scriptFileName = theDebuggerStringSetting(GdbScriptFile);
if (!scriptFileName.isEmpty()) {
if (QFileInfo(scriptFileName).isReadable()) {
postCommand(_("source ") + scriptFileName);
} else {
QMessageBox::warning(mainWindow(),
tr("Cannot find debugger initialization script"),
tr("The debugger settings point to a script file at '%1' "
"which is not accessible. If a script file is not needed, "
"consider clearing that entry to avoid this warning. "
).arg(scriptFileName));
}
}
if (startMode() == AttachExternal || startMode() == AttachCrashedExternal) {
postCommand(_("attach %1").arg(m_startParameters->attachPID), CB(handleAttach));
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
} else if (startMode() == AttachCore) {
QFileInfo fi(m_startParameters->executable);
QString fileName = _c('"') + fi.absoluteFilePath() + _c('"');
QFileInfo fi2(m_startParameters->coreFile);
// quoting core name below fails in gdb 6.8-debian
QString coreName = fi2.absoluteFilePath();
postCommand(_("-file-exec-and-symbols ") + fileName, CB(handleFileExecAndSymbols));
postCommand(_("target core ") + coreName, CB(handleTargetCore));
qq->breakHandler()->removeAllBreakpoints();
} else if (startMode() == StartRemote) {
postCommand(_("set architecture %1").arg(m_startParameters->remoteArchitecture));
qq->breakHandler()->setAllPending();
//QFileInfo fi(m_startParameters->executable);
//QString fileName = fi.absoluteFileName();
QString fileName = m_startParameters->executable;
postCommand(_("-file-exec-and-symbols \"%1\"").arg(fileName), CB(handleFileExecAndSymbols));
// works only for > 6.8
postCommand(_("set target-async on"), CB(handleSetTargetAsync));
} else if (m_startParameters->useTerminal) {
qq->breakHandler()->setAllPending();
} else if (startMode() == StartInternal || startMode() == StartExternal) {
qq->breakHandler()->setAllPending();
m_gdbAdapter->attach();
if (m_gdbAdapter->isAdapter()) {
m_autoContinue = true;
qq->notifyInferiorStopped();
attemptBreakpointSynchronization();
qq->notifyInferiorRunningRequested();
} else {
#ifdef Q_OS_MAC
postCommand(_("sharedlibrary apply-load-rules all"));
#endif
if (!m_startParameters->processArgs.isEmpty())
postCommand(_("-exec-arguments ") + m_startParameters->processArgs.join(_(" ")));
#ifdef Q_OS_MAC
// On MacOS, breaking in at the entry point wreaks havoc.
postCommand(_("tbreak main"));
m_waitingForFirstBreakpointToBeHit = true;
qq->notifyInferiorRunningRequested();
postCommand(_("-exec-run"), CB(handleExecRun));
#else
if (!m_dumperInjectionLoad)
postCommand(_("set auto-solib-add off"));
postCommand(_("info target"), CB(handleStart));
#endif
}
}
emit startSuccessful();
*/
}
void GdbEngine::continueInferior()
@@ -1777,32 +1643,6 @@ void GdbEngine::continueInferior()
postCommand(_("-exec-continue"), CB(handleExecContinue));
}
void GdbEngine::handleStart(const GdbResultRecord &response, const QVariant &)
{
#if defined(Q_OS_MAC)
Q_UNUSED(response)
#else
if (response.resultClass == GdbResultDone) {
// [some leading stdout here]
// >&" Entry point: 0x80831f0 0x08048134 - 0x08048147 is .interp\n"
// [some trailing stdout here]
QString msg = _(response.data.findChild("consolestreamoutput").data());
QRegExp needle(_("\\bEntry point: (0x[0-9a-f]+)\\b"));
if (needle.indexIn(msg) != -1) {
//debugMessage(_("STREAM: ") + msg + " " + needle.cap(1));
postCommand(_("tbreak *") + needle.cap(1));
m_waitingForFirstBreakpointToBeHit = true;
qq->notifyInferiorRunningRequested();
postCommand(_("-exec-run"), CB(handleExecRun));
} else {
debugMessage(_("PARSING START ADDRESS FAILED: ") + msg);
}
} else if (response.resultClass == GdbResultError) {
debugMessage(_("FETCHING START ADDRESS FAILED: " + response.toString()));
}
#endif
}
void GdbEngine::handleAttach(const GdbResultRecord &, const QVariant &)
{
qq->notifyInferiorStopped();
@@ -1850,7 +1690,7 @@ void GdbEngine::handleTargetRemote(const GdbResultRecord &record, const QVariant
if (record.resultClass == GdbResultDone) {
//postCommand(_("-exec-continue"), CB(handleExecContinue));
handleAqcuiredInferior();
m_autoContinue = true;
// FIXME m_continuationAfterDone = true;
} else if (record.resultClass == GdbResultError) {
// 16^error,msg="hd:5555: Connection timed out."
QString msg = __(record.data.findChild("msg").data());
@@ -1899,8 +1739,15 @@ void GdbEngine::nextExec()
qq->notifyInferiorRunningRequested();
if (qq->isReverseDebugging())
postCommand(_("-reverse-next"), CB(handleExecContinue));
else
else {
#if 0
postCommand(_("-exec-next"), CB(handleExecContinue));
#else
postCommand(_("tbreak %1:%2").arg(QFileInfo(lastFile).fileName())
.arg(lastLine + 1));
postCommand(_("-exec-continue"), CB(handleExecContinue));
#endif
}
}
void GdbEngine::nextIExec()
@@ -3478,7 +3325,7 @@ void GdbEngine::handleDebuggingHelperValue1(const GdbResultRecord &record,
&& msg.startsWith(__("The program being debugged stopped while"))
&& msg.contains(__("qDumpObjectData440"))) {
// Fake full stop
postCommand(_("p 0"), CB(handleAsyncOutput2)); // dummy
postCommand(_("p 0"), CB(handleStop2)); // dummy
return;
}
#endif
@@ -4287,14 +4134,209 @@ void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResultRecord &record,
void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker)
{
lastFile = frame.file;
lastLine = frame.line;
m_manager->gotoLocation(frame, setMarker);
}
//
// Starting up & shutting down
//
void GdbEngine::handleAdapterStartFailed(const QString &msg)
{
debugMessage(_("ADAPTER START FAILED"));
m_outputCollector.shutdown();
QMessageBox::critical(mainWindow(), tr("Error"), msg);
QTC_ASSERT(status() == DebuggerInferiorRunning, /**/);
//interruptInferior();
}
void GdbEngine::handleAdapterStarted()
{
debugMessage(_("ADAPTER SUCCESSFULLY STARTED, PREPARING INFERIOR"));
m_gdbAdapter->prepareInferior();
}
void GdbEngine::handleInferiorPreparationFailed(const QString &msg)
{
debugMessage(_("INFERIOR PREPARATION FAILD"));
m_outputCollector.shutdown();
QMessageBox::critical(mainWindow(), tr("Error"),
tr("Inferior start preparation failed:\n") + msg);
}
void GdbEngine::handleInferiorPrepared()
{
// FIXME: Check that inferior is in "stopped" state
qq->notifyInferiorStopped();
showStatusMessage(tr("Inferior prepared for startup."));
postCommand(_("show version"), CB(handleShowVersion));
//postCommand(_("-enable-timings");
postCommand(_("set print static-members off")); // Seemingly doesn't work.
//postCommand(_("set debug infrun 1"));
//postCommand(_("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend"));
//postCommand(_("define hook-stop\nprint 4\nend"));
//postCommand(_("define hookpost-stop\nprint 5\nend"));
//postCommand(_("define hook-call\nprint 6\nend"));
//postCommand(_("define hookpost-call\nprint 7\nend"));
//postCommand(_("set print object on")); // works with CLI, but not MI
//postCommand(_("set step-mode on")); // we can't work with that yes
//postCommand(_("set exec-done-display on"));
//postCommand(_("set print pretty on"));
//postCommand(_("set confirm off"));
//postCommand(_("set pagination off"));
postCommand(_("set print inferior-events 1"));
postCommand(_("set breakpoint pending on"));
postCommand(_("set print elements 10000"));
postCommand(_("-data-list-register-names"), CB(handleRegisterListNames));
//postCommand(_("set substitute-path /var/tmp/qt-x11-src-4.5.0 "
// "/home/sandbox/qtsdk-2009.01/qt"));
// one of the following is needed to prevent crashes in gdb on code like:
// template <class T> T foo() { return T(0); }
// int main() { return foo<int>(); }
// (gdb) call 'int foo<int>'()
// /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error:
postCommand(_("set overload-resolution off"));
//postCommand(_("set demangle-style none"));
// From the docs:
// Stop means reenter debugger if this signal happens (implies print).
// Print means print a message if this signal happens.
// Pass means let program see this signal;
// otherwise program doesn't know.
// Pass and Stop may be combined.
// We need "print" as otherwise we would get no feedback whatsoever
// Custom DebuggingHelper crashs which happen regularily for when accessing
// uninitialized variables.
postCommand(_("handle SIGSEGV nopass stop print"));
// This is useful to kill the inferior whenever gdb dies.
//postCommand(_("handle SIGTERM pass nostop print"));
postCommand(_("set unwindonsignal on"));
//postCommand(_("pwd"));
postCommand(_("set width 0"));
postCommand(_("set height 0"));
#ifdef Q_OS_MAC
postCommand(_("-gdb-set inferior-auto-start-cfm off"));
postCommand(_("-gdb-set sharedLibrary load-rules "
"dyld \".*libSystem.*\" all "
"dyld \".*libauto.*\" all "
"dyld \".*AppKit.*\" all "
"dyld \".*PBGDBIntrospectionSupport.*\" all "
"dyld \".*Foundation.*\" all "
"dyld \".*CFDataFormatters.*\" all "
"dyld \".*libobjc.*\" all "
"dyld \".*CarbonDataFormatters.*\" all"));
#endif
QString scriptFileName = theDebuggerStringSetting(GdbScriptFile);
if (!scriptFileName.isEmpty()) {
if (QFileInfo(scriptFileName).isReadable()) {
postCommand(_("source ") + scriptFileName);
} else {
QMessageBox::warning(mainWindow(),
tr("Cannot find debugger initialization script"),
tr("The debugger settings point to a script file at '%1' "
"which is not accessible. If a script file is not needed, "
"consider clearing that entry to avoid this warning. "
).arg(scriptFileName));
}
}
/*
if (startMode() == AttachExternal || startMode() == AttachCrashedExternal) {
postCommand(_("attach %1").arg(m_startParameters->attachPID), CB(handleAttach));
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
} else if (startMode() == AttachCore) {
QFileInfo fi(m_startParameters->executable);
QString fileName = _c('"') + fi.absoluteFilePath() + _c('"');
QFileInfo fi2(m_startParameters->coreFile);
// quoting core name below fails in gdb 6.8-debian
QString coreName = fi2.absoluteFilePath();
postCommand(_("-file-exec-and-symbols ") + fileName, CB(handleFileExecAndSymbols));
postCommand(_("target core ") + coreName, CB(handleTargetCore));
qq->breakHandler()->removeAllBreakpoints();
} else if (startMode() == StartRemote) {
postCommand(_("set architecture %1").arg(m_startParameters->remoteArchitecture));
qq->breakHandler()->setAllPending();
//QFileInfo fi(m_startParameters->executable);
//QString fileName = fi.absoluteFileName();
QString fileName = m_startParameters->executable;
postCommand(_("-file-exec-and-symbols \"%1\"").arg(fileName), CB(handleFileExecAndSymbols));
// works only for > 6.8
postCommand(_("set target-async on"), CB(handleSetTargetAsync));
} else if (m_startParameters->useTerminal) {
qq->breakHandler()->setAllPending();
} else if (startMode() == StartInternal || startMode() == StartExternal) {
qq->breakHandler()->setAllPending();
m_gdbAdapter->attach();
if (m_gdbAdapter->isAdapter()) {
m_continuationAfterDone = true;
qq->notifyInferiorStopped();
attemptBreakpointSynchronization();
qq->notifyInferiorRunningRequested();
} [...]
}
*/
// initial attempt to set breakpoints
QTC_ASSERT(m_continuationAfterDone == 0, /**/);
showStatusMessage(tr("Start initial breakpoint setting."));
m_continuationAfterDone = &GdbEngine::handleInitialBreakpointsSet;
attemptBreakpointSynchronization();
}
void GdbEngine::handleInitialBreakpointsSet()
{
showStatusMessage(tr("Finishing initial breakpoint setting."));
qq->notifyInferiorRunningRequested();
m_gdbAdapter->startInferior();
}
void GdbEngine::handleInferiorStartFailed(const QString &msg)
{
debugMessage(_("INFERIOR START FAILED"));
QMessageBox::critical(mainWindow(), tr("Error"),
tr("Inferior start failed:\n") + msg);
qq->notifyInferiorExited();
}
void GdbEngine::handleInferiorStarted()
{
qq->notifyInferiorRunning();
}
void GdbEngine::handleInferiorShutDown()
{
debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
}
void GdbEngine::handleInferiorShutdownFailed(const QString &msg)
{
debugMessage(_("INFERIOR SHUTDOWN FAILED"));
QMessageBox::critical(mainWindow(), tr("Error"),
tr("Inferior shutdown failed:\n") + msg);
}
//
// Factory
//
IDebuggerEngine *createGdbEngine(DebuggerManager *parent,
QList<Core::IOptionsPage*> *opts)
{
opts->push_back(new GdbOptionsPage);
return new GdbEngine(parent, new PlainGdbAdapter);
GdbEngine *engine = new GdbEngine(parent);
PlainGdbAdapter *adapter = new PlainGdbAdapter(engine);
engine->setGdbAdapter(adapter);
return engine;
}
IDebuggerEngine *createSymbianEngine(DebuggerManager *parent,
@@ -4305,8 +4347,9 @@ IDebuggerEngine *createSymbianEngine(DebuggerManager *parent,
if (!qgetenv("QTCREATOR_WITH_S60").isEmpty())
opts->push_back(new TrkOptionsPage(options));
TrkGdbAdapter *adapter = new TrkGdbAdapter(options);
GdbEngine *engine = new GdbEngine(parent, adapter);
GdbEngine *engine = new GdbEngine(parent);
TrkGdbAdapter *adapter = new TrkGdbAdapter(engine, options);
engine->setGdbAdapter(adapter);
QObject::connect(adapter, SIGNAL(output(QString)),
parent, SLOT(showDebuggerOutput(QString)));
return engine;