summaryrefslogtreecommitdiff
path: root/src/plugins/debugger/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/debugger/gdb')
-rw-r--r--src/plugins/debugger/gdb/abstractplaingdbadapter.cpp6
-rw-r--r--src/plugins/debugger/gdb/attachgdbadapter.cpp8
-rw-r--r--src/plugins/debugger/gdb/classicgdbengine.cpp24
-rw-r--r--src/plugins/debugger/gdb/coregdbadapter.cpp9
-rw-r--r--src/plugins/debugger/gdb/gdb.pri2
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp279
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h19
-rw-r--r--src/plugins/debugger/gdb/gdbmi.cpp433
-rw-r--r--src/plugins/debugger/gdb/gdbmi.h180
-rw-r--r--src/plugins/debugger/gdb/gdboptionspage.cpp55
-rw-r--r--src/plugins/debugger/gdb/localplaingdbadapter.cpp8
-rw-r--r--src/plugins/debugger/gdb/pythongdbengine.cpp3
-rw-r--r--src/plugins/debugger/gdb/remotegdbserveradapter.cpp38
-rw-r--r--src/plugins/debugger/gdb/termgdbadapter.cpp55
14 files changed, 334 insertions, 785 deletions
diff --git a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
index 0c1de8b3d7..305d68d71a 100644
--- a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
+++ b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
@@ -28,11 +28,11 @@
****************************************************************************/
#include "abstractplaingdbadapter.h"
-#include "gdbmi.h"
-#include "gdbengine.h"
-#include "debuggerstartparameters.h"
+
#include "debuggeractions.h"
#include "debuggercore.h"
+#include "debuggerprotocol.h"
+#include "debuggerstartparameters.h"
#include "debuggerstringutils.h"
#include <QDir>
diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp
index 4b71ba73fa..9467471bd9 100644
--- a/src/plugins/debugger/gdb/attachgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp
@@ -28,12 +28,11 @@
****************************************************************************/
#include "attachgdbadapter.h"
-#include "gdbmi.h"
-#include "debuggerstartparameters.h"
-#include "gdbengine.h"
-#include "procinterrupt.h"
+#include "debuggerprotocol.h"
#include "debuggerstringutils.h"
+#include "debuggerstartparameters.h"
+#include "procinterrupt.h"
#include <utils/qtcassert.h>
@@ -88,6 +87,7 @@ void GdbAttachEngine::handleAttach(const GdbResponse &response)
case GdbResultRunning:
showMessage(_("INFERIOR ATTACHED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
+ tryLoadPythonDumpers();
handleInferiorPrepared();
break;
case GdbResultError:
diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp
index c96735eeab..897ead3f3f 100644
--- a/src/plugins/debugger/gdb/classicgdbengine.cpp
+++ b/src/plugins/debugger/gdb/classicgdbengine.cpp
@@ -28,13 +28,13 @@
****************************************************************************/
#include "gdbengine.h"
-#include "gdbmi.h"
-#include "debuggerstartparameters.h"
#include "debuggeractions.h"
#include "debuggercore.h"
+#include "debuggerprotocol.h"
+#include "debuggerstartparameters.h"
#include "debuggerstringutils.h"
-
+#include "sourceutils.h"
#include "stackhandler.h"
#include "watchhandler.h"
@@ -552,11 +552,10 @@ void DumperHelper::evaluationParameters(const WatchData &data,
// in rare cases we need more or less:
switch (td.type) {
case QAbstractItemType:
- if (data.dumperFlags.isEmpty()) {
+ if (data.dumperFlags.isEmpty())
qWarning("Internal error: empty dumper state '%s'.", data.iname.constData());
- } else {
+ else
inner = data.dumperFlags.mid(1);
- }
break;
case QObjectSlotType:
case QObjectSignalType: {
@@ -1068,11 +1067,10 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
data1.type = data.type.left(data.type.size() - 4);
data1.iname = data.iname + '.' + QByteArray::number(i);
const QByteArray &addressSpec = list.at(i);
- if (addressSpec.startsWith("0x")) {
+ if (addressSpec.startsWith("0x"))
data.setHexAddress(addressSpec);
- } else {
+ else
data.dumperFlags = addressSpec; // Item model dumpers pull tricks
- }
data1.exp = "((" + gdbQuoteTypes(data1.type) + "*)" + addressSpec + ')';
data1.setHasChildren(false);
data1.setValueNeeded();
@@ -1230,8 +1228,8 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
QStringList uninitializedVariables;
if (debuggerCore()->action(UseCodeModel)->isChecked()) {
const StackFrame frame =
- qVariantCanConvert<Debugger::Internal::StackFrame>(response.cookie)
- ? qVariantValue<Debugger::Internal::StackFrame>(response.cookie)
+ response.cookie.canConvert<Debugger::Internal::StackFrame>()
+ ? qvariant_cast<Debugger::Internal::StackFrame>(response.cookie)
: stackHandler()->currentFrame();
if (frame.isUsable())
getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(),
@@ -1284,8 +1282,8 @@ static void showQtDumperLibraryWarning(const QString &details)
dialog.exec();
if (dialog.clickedButton() == qtPref) {
Core::ICore::showOptionsDialog(
- _(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY),
- _(QtSupport::Constants::QTVERSION_SETTINGS_PAGE_ID));
+ ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY,
+ QtSupport::Constants::QTVERSION_SETTINGS_PAGE_ID);
} else if (dialog.clickedButton() == helperOff) {
debuggerCore()->action(UseDebuggingHelpers)->setValue(qVariantFromValue(false), false);
}
diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp
index fc782d8c64..71f3f4657c 100644
--- a/src/plugins/debugger/gdb/coregdbadapter.cpp
+++ b/src/plugins/debugger/gdb/coregdbadapter.cpp
@@ -29,12 +29,11 @@
#include "coregdbadapter.h"
-#include "debuggerstartparameters.h"
-#include "debuggercore.h"
#include "debuggeractions.h"
+#include "debuggercore.h"
+#include "debuggerprotocol.h"
+#include "debuggerstartparameters.h"
#include "debuggerstringutils.h"
-#include "gdbmi.h"
-#include "gdbengine.h"
#include <utils/consoleprocess.h>
#include <utils/elfreader.h>
@@ -185,7 +184,7 @@ void GdbCoreEngine::handleTargetCore(const GdbResponse &response)
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
// HACK: The namespace is not accessible in the initial run.
- loadPythonDumpers();
+ tryLoadPythonDumpers();
showMessage(tr("Attached to core."), StatusBar);
handleInferiorPrepared();
// Due to the auto-solib-add off setting, we don't have any
diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri
index b371e63e73..7a100e6851 100644
--- a/src/plugins/debugger/gdb/gdb.pri
+++ b/src/plugins/debugger/gdb/gdb.pri
@@ -1,5 +1,4 @@
HEADERS += \
- $$PWD/gdbmi.h \
$$PWD/gdbengine.h \
$$PWD/gdboptionspage.h \
$$PWD/attachgdbadapter.h \
@@ -15,7 +14,6 @@ HEADERS += \
$$PWD/startgdbserverdialog.h
SOURCES += \
- $$PWD/gdbmi.cpp \
$$PWD/gdbengine.cpp \
$$PWD/classicgdbengine.cpp \
$$PWD/pythongdbengine.cpp \
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index f472cf96e7..f939934234 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -44,13 +44,14 @@
#include "debuggerconstants.h"
#include "debuggercore.h"
#include "debuggerplugin.h"
+#include "debuggerprotocol.h"
#include "debuggerrunner.h"
#include "debuggerstringutils.h"
#include "debuggertooltipmanager.h"
#include "disassembleragent.h"
-#include "gdbmi.h"
#include "gdboptionspage.h"
#include "memoryagent.h"
+#include "sourceutils.h"
#include "watchutils.h"
#include "breakhandler.h"
@@ -75,6 +76,7 @@
#include <projectexplorer/itaskhandler.h>
#include <texteditor/itexteditor.h>
#include <utils/elfreader.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/savedaction.h>
@@ -261,6 +263,7 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters)
m_terminalTrap = startParameters.useTerminal;
m_fullStartDone = false;
m_forceAsyncModel = false;
+ m_pythonAttemptedToLoad = false;
invalidateSourcesList();
@@ -278,6 +281,8 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters)
SLOT(reloadLocals()));
connect(debuggerCore()->action(UseDynamicType), SIGNAL(valueChanged(QVariant)),
SLOT(reloadLocals()));
+ connect(debuggerCore()->action(IntelFlavor), SIGNAL(valueChanged(QVariant)),
+ SLOT(reloadDisassembly()));
}
GdbEngine::~GdbEngine()
@@ -343,24 +348,23 @@ static void dump(const char *first, const char *middle, const QString & to)
// Parse "~:gdb: unknown target exception 0xc0000139 at 0x77bef04e\n"
// and return an exception message
-static inline QString msgWinException(const QByteArray &data)
+static inline QString msgWinException(const QByteArray &data, unsigned *exCodeIn = 0)
{
+ if (exCodeIn)
+ *exCodeIn = 0;
const int exCodePos = data.indexOf("0x");
const int blankPos = exCodePos != -1 ? data.indexOf(' ', exCodePos + 1) : -1;
const int addressPos = blankPos != -1 ? data.indexOf("0x", blankPos + 1) : -1;
if (addressPos < 0)
return GdbEngine::tr("An exception was triggered.");
const unsigned exCode = data.mid(exCodePos, blankPos - exCodePos).toUInt(0, 0);
+ if (exCodeIn)
+ *exCodeIn = exCode;
const quint64 address = data.mid(addressPos).trimmed().toULongLong(0, 0);
QString rc;
QTextStream str(&rc);
str << GdbEngine::tr("An exception was triggered: ");
-#ifdef Q_OS_WIN
formatWindowsException(exCode, address, 0, 0, 0, str);
-#else
- Q_UNUSED(exCode)
- Q_UNUSED(address)
-#endif
str << '.';
return rc;
}
@@ -466,6 +470,8 @@ void GdbEngine::handleResponse(const QByteArray &buff)
m_pendingLogStreamOutput.clear();
m_pendingConsoleStreamOutput.clear();
} else if (asyncClass == "running") {
+ GdbMi threads = result.findChild("thread-id");
+ threadsHandler()->notifyRunning(threads.data());
if (state() == InferiorRunOk || state() == InferiorSetupRequested) {
// We get multiple *running after thread creation and in Windows terminals.
showMessage(QString::fromLatin1("NOTE: INFERIOR STILL RUNNING IN STATE %1.").
@@ -526,6 +532,10 @@ void GdbEngine::handleResponse(const QByteArray &buff)
//"{id="1",group-id="28902"}"
QByteArray id = result.findChild("id").data();
showStatusMessage(tr("Thread %1 created").arg(_(id)), 1000);
+ ThreadData thread;
+ thread.id = ThreadId(id.toLong());
+ thread.groupId = result.findChild("group-id").data();
+ threadsHandler()->updateThread(thread);
} else if (asyncClass == "thread-group-exited") {
// Archer has "{id="28902"}"
QByteArray id = result.findChild("id").data();
@@ -537,6 +547,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
QByteArray groupid = result.findChild("group-id").data();
showStatusMessage(tr("Thread %1 in group %2 exited")
.arg(_(id)).arg(_(groupid)), 1000);
+ threadsHandler()->removeThread(ThreadId(id.toLong()));
} else if (asyncClass == "thread-selected") {
QByteArray id = result.findChild("id").data();
showStatusMessage(tr("Thread %1 selected").arg(_(id)), 1000);
@@ -689,8 +700,13 @@ void GdbEngine::handleResponse(const QByteArray &buff)
// [Windows, most likely some DLL/Entry point not found]:
// "gdb: unknown target exception 0xc0000139 at 0x77bef04e"
// This may be fatal and cause the target to exit later
- m_lastWinException = msgWinException(data);
+ unsigned exCode;
+ m_lastWinException = msgWinException(data, &exCode);
showMessage(m_lastWinException, LogMisc);
+ const Task::TaskType type = isFatalWinException(exCode) ? Task::Error : Task::Warning;
+ const Task task(type, m_lastWinException, Utils::FileName(), 0,
+ Core::Id(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME));
+ taskHub()->addTask(task);
}
if (data.startsWith("QMLBP:")) {
@@ -732,7 +748,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
Task task(Task::Warning,
tr("Missing debug information for %1\nTry: %2")
.arg(m_lastMissingDebugInfo).arg(cmd),
- FileName(), 0, Core::Id("Debuginfo"));
+ FileName(), 0, Core::Id(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO));
taskHub()->addTask(task);
@@ -754,19 +770,18 @@ void GdbEngine::handleResponse(const QByteArray &buff)
break;
QByteArray resultClass = QByteArray::fromRawData(from, inner - from);
- if (resultClass == "done") {
+ if (resultClass == "done")
response.resultClass = GdbResultDone;
- } else if (resultClass == "running") {
+ else if (resultClass == "running")
response.resultClass = GdbResultRunning;
- } else if (resultClass == "connected") {
+ else if (resultClass == "connected")
response.resultClass = GdbResultConnected;
- } else if (resultClass == "error") {
+ else if (resultClass == "error")
response.resultClass = GdbResultError;
- } else if (resultClass == "exit") {
+ else if (resultClass == "exit")
response.resultClass = GdbResultExit;
- } else {
+ else
response.resultClass = GdbResultUnknown;
- }
from = inner;
if (from != to) {
@@ -944,9 +959,8 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
showMessage(_("QUEUING COMMAND " + cmd.command));
m_commandsToRunOnTemporaryBreak.append(cmd);
if (state() == InferiorStopRequested) {
- if (cmd.flags & LosesChild) {
+ if (cmd.flags & LosesChild)
notifyInferiorIll();
- }
showMessage(_("CHILD ALREADY BEING INTERRUPTED. STILL HOPING."));
// Calling shutdown() here breaks all situations where two
// NeedsStop commands are issued in quick succession.
@@ -1396,6 +1410,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
return;
}
+ GdbMi threads = data.findChild("stopped-thread");
+ threadsHandler()->notifyStopped(threads.data());
+
const QByteArray reason = data.findChild("reason").data();
if (isExitedReason(reason)) {
@@ -1418,11 +1435,12 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
return;
}
+ tryLoadPythonDumpers();
+
bool gotoHandleStop1 = true;
if (!m_fullStartDone) {
m_fullStartDone = true;
postCommand("sharedlibrary .*");
- loadPythonDumpers();
postCommand("p 3", CB(handleStop1));
gotoHandleStop1 = false;
}
@@ -1747,10 +1765,6 @@ void GdbEngine::handleStop2(const GdbMi &data)
// Let the event loop run before deciding whether to update the stack.
m_stackNeeded = true; // setTokenBarrier() might reset this.
- if (isStopperThread)
- m_currentThreadId = 0;
- else
- m_currentThreadId = data.findChild("thread-id").data().toInt();
QTimer::singleShot(0, this, SLOT(handleStop2()));
}
@@ -1760,8 +1774,6 @@ void GdbEngine::handleStop2()
if (!m_stackNeeded)
return;
- reloadStack(false); // Will trigger register reload.
-
if (supportsThreads()) {
if (m_isMacGdb || m_gdbVersion < 70100) {
postCommand("-thread-list-ids", Discardable, CB(handleThreadListIds));
@@ -1770,7 +1782,6 @@ void GdbEngine::handleStop2()
postCommand("-thread-info", Discardable, CB(handleThreadInfo));
}
}
-
}
void GdbEngine::handleInfoProc(const GdbResponse &response)
@@ -1831,6 +1842,14 @@ void GdbEngine::handleListFeatures(const GdbResponse &response)
void GdbEngine::handleHasPython(const GdbResponse &response)
{
+ if (response.resultClass == GdbResultDone)
+ m_hasPython = true;
+ else
+ pythonDumpersFailed();
+}
+
+void GdbEngine::handlePythonSetup(const GdbResponse &response)
+{
if (response.resultClass == GdbResultDone) {
m_hasPython = true;
GdbMi data;
@@ -1852,8 +1871,6 @@ void GdbEngine::handleHasPython(const GdbResponse &response)
}
const GdbMi hasInferiorThreadList = data.findChild("hasInferiorThreadList");
m_hasInferiorThreadList = (hasInferiorThreadList.data().toInt() != 0);
- } else {
- pythonDumpersFailed();
}
}
@@ -2120,9 +2137,11 @@ bool GdbEngine::hasCapability(unsigned cap) const
| AddWatcherCapability
| WatchWidgetsCapability
| ShowModuleSymbolsCapability
+ | ShowModuleSectionsCapability
| CatchCapability
| OperateByInstructionCapability
| RunToLineCapability
+ | WatchComplexExpressionsCapability
| MemoryAddressCapability))
return true;
@@ -2166,11 +2185,10 @@ void GdbEngine::executeStep()
setTokenBarrier();
notifyInferiorRunRequested();
showStatusMessage(tr("Step requested..."), 5000);
- if (isReverseDebugging()) {
+ if (isReverseDebugging())
postCommand("reverse-step", RunRequest, CB(handleExecuteStep));
- } else {
+ else
postCommand("-exec-step", RunRequest, CB(handleExecuteStep));
- }
}
void GdbEngine::handleExecuteStep(const GdbResponse &response)
@@ -3317,7 +3335,7 @@ void GdbEngine::handleShowModuleSymbols(const GdbResponse &response)
const QString modulePath = cookie.section(QLatin1Char('@'), 0, 0);
const QString fileName = cookie.section(QLatin1Char('@'), 1, 1);
if (response.resultClass == GdbResultDone) {
- Symbols rc;
+ Symbols symbols;
QFile file(fileName);
file.open(QIODevice::ReadOnly);
// Object file /opt/dev/qt/lib/libQtNetworkMyns.so.4:
@@ -3361,17 +3379,62 @@ void GdbEngine::handleShowModuleSymbols(const GdbResponse &response)
symbol.name = _(line.mid(posName, lenName));
symbol.section = _(line.mid(posSection, lenSection));
symbol.demangled = _(line.mid(posDemangled, lenDemangled));
- rc.push_back(symbol);
+ symbols.push_back(symbol);
}
file.close();
file.remove();
- debuggerCore()->showModuleSymbols(modulePath, rc);
+ debuggerCore()->showModuleSymbols(modulePath, symbols);
} else {
showMessageBox(QMessageBox::Critical, tr("Cannot Read Symbols"),
tr("Cannot read symbols for module \"%1\".").arg(fileName));
}
}
+void GdbEngine::requestModuleSections(const QString &moduleName)
+{
+ // There seems to be no way to get the symbols from a single .so.
+ postCommand("maint info section ALLOBJ",
+ NeedsStop, CB(handleShowModuleSections), moduleName);
+}
+
+void GdbEngine::handleShowModuleSections(const GdbResponse &response)
+{
+ // ~" Object file: /usr/lib/i386-linux-gnu/libffi.so.6\n"
+ // ~" 0xb44a6114->0xb44a6138 at 0x00000114: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS\n"
+ if (response.resultClass == GdbResultDone) {
+ const QString moduleName = response.cookie.toString();
+ const QStringList lines = QString::fromLocal8Bit(response.consoleStreamOutput).split(QLatin1Char('\n'));
+ const QString prefix = QLatin1String(" Object file: ");
+ const QString needle = prefix + moduleName;
+ Sections sections;
+ bool active = false;
+ foreach (const QString &line, lines) {
+ if (line.startsWith(prefix)) {
+ if (active)
+ break;
+ if (line == needle)
+ active = true;
+ } else {
+ if (active) {
+ QStringList items = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ QString fromTo = items.value(0, QString());
+ const int pos = fromTo.indexOf(QLatin1Char('-'));
+ QTC_ASSERT(pos >= 0, continue);
+ Section section;
+ section.from = fromTo.left(pos);
+ section.to = fromTo.mid(pos + 2);
+ section.address = items.value(2, QString());
+ section.name = items.value(3, QString());
+ section.flags = items.value(4, QString());
+ sections.append(section);
+ }
+ }
+ }
+ if (!sections.isEmpty())
+ debuggerCore()->showModuleSections(moduleName, sections);
+ }
+}
+
void GdbEngine::reloadModules()
{
if (state() == InferiorRunOk || state() == InferiorStopOk)
@@ -3488,15 +3551,12 @@ void GdbEngine::reloadSourceFilesInternal()
//
//////////////////////////////////////////////////////////////////////
-void GdbEngine::selectThread(int index)
+void GdbEngine::selectThread(ThreadId threadId)
{
- threadsHandler()->setCurrentThread(index);
- Threads threads = threadsHandler()->threads();
- QTC_ASSERT(index < threads.size(), return);
- const int id = threads.at(index).id;
+ threadsHandler()->setCurrentThread(threadId);
showStatusMessage(tr("Retrieving data for stack view thread 0x%1...")
- .arg(id, 0, 16), 10000);
- postCommand("-thread-select " + QByteArray::number(id), Discardable,
+ .arg(threadId.raw(), 0, 16), 10000);
+ postCommand("-thread-select " + QByteArray::number(threadId.raw()), Discardable,
CB(handleStackSelectThread));
}
@@ -3640,17 +3700,21 @@ void GdbEngine::handleStackSelectFrame(const GdbResponse &response)
void GdbEngine::handleThreadInfo(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
- int currentThreadId;
- const Threads threads =
- ThreadsHandler::parseGdbmiThreads(response.data, &currentThreadId);
- threadsHandler()->setThreads(threads);
- threadsHandler()->setCurrentThreadId(currentThreadId);
+ ThreadsHandler *handler = threadsHandler();
+ handler->updateThreads(response.data);
+ // This is necessary as the current thread might not be in the list.
+ if (!handler->currentThread().isValid()) {
+ ThreadId other = handler->threadAt(0);
+ if (other.isValid())
+ selectThread(other);
+ }
updateViews(); // Adjust Threads combobox.
if (m_hasInferiorThreadList && debuggerCore()->boolSetting(ShowThreadNames)) {
postCommand("threadnames " +
debuggerCore()->action(MaximalStackDepth)->value().toByteArray(),
Discardable, CB(handleThreadNames));
}
+ reloadStack(false); // Will trigger register reload.
} else {
// Fall back for older versions: Try to get at least a list
// of running threads.
@@ -3662,37 +3726,29 @@ void GdbEngine::handleThreadListIds(const GdbResponse &response)
{
// "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
// In gdb 7.1+ additionally: current-thread-id="1"
+ ThreadsHandler *handler = threadsHandler();
const QList<GdbMi> items = response.data.findChild("thread-ids").children();
- Threads threads;
for (int index = 0, n = items.size(); index != n; ++index) {
ThreadData thread;
- thread.id = items.at(index).data().toInt();
- threads.append(thread);
+ thread.id = ThreadId(items.at(index).data().toInt());
+ handler->updateThread(thread);
}
- threadsHandler()->setThreads(threads);
- threadsHandler()->setCurrentThreadId(m_currentThreadId);
+ reloadStack(false); // Will trigger register reload.
}
void GdbEngine::handleThreadNames(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
+ ThreadsHandler *handler = threadsHandler();
GdbMi names;
names.fromString(response.consoleStreamOutput);
-
- Threads threads = threadsHandler()->threads();
-
foreach (const GdbMi &name, names.children()) {
- int id = name.findChild("id").data().toInt();
- for (int index = 0, n = threads.size(); index != n; ++index) {
- ThreadData &thread = threads[index];
- if (thread.id == quint64(id)) {
- thread.name = decodeData(name.findChild("value").data(),
- name.findChild("valueencoded").data().toInt());
- break;
- }
- }
+ ThreadData thread;
+ thread.id = ThreadId(name.findChild("id").data().toInt());
+ thread.name = decodeData(name.findChild("value").data(),
+ name.findChild("valueencoded").data().toInt());
+ handler->updateThread(thread);
}
- threadsHandler()->setThreads(threads);
updateViews();
}
}
@@ -4539,6 +4595,12 @@ DisassemblerLines GdbEngine::parseDisassembler(const GdbResponse &response)
return parseCliDisassembler(response.consoleStreamOutput);
}
+void GdbEngine::reloadDisassembly()
+{
+ setTokenBarrier();
+ updateLocals();
+}
+
void GdbEngine::handleDisassemblerCheck(const GdbResponse &response)
{
m_disassembleUsesComma = response.resultClass != GdbResultDone;
@@ -4649,7 +4711,7 @@ void GdbEngine::startGdb(const QStringList &args)
handleGdbStartFailed();
handleAdapterStartFailed(
msgNoGdbBinaryForToolChain(sp.toolChainAbi),
- _(Constants::DEBUGGER_COMMON_SETTINGS_ID));
+ Constants::DEBUGGER_COMMON_SETTINGS_ID);
return;
}
QStringList gdbArgs;
@@ -4730,10 +4792,10 @@ void GdbEngine::startGdb(const QStringList &args)
postCommand("set width 0");
postCommand("set height 0");
- postCommand("set breakpoint always-inserted on", ConsoleCommand);
+ //postCommand("set breakpoint always-inserted on", ConsoleCommand);
// displaced-stepping does not work in Thumb mode.
//postCommand("set displaced-stepping on");
- postCommand("set trust-readonly-sections on", ConsoleCommand);
+ //postCommand("set trust-readonly-sections on", ConsoleCommand);
postCommand("set remotecache on", ConsoleCommand);
//postCommand("set non-stop on", ConsoleCommand);
@@ -4793,10 +4855,18 @@ void GdbEngine::startGdb(const QStringList &args)
} else {
m_fullStartDone = true;
postCommand("set auto-solib-add on", ConsoleCommand);
- loadPythonDumpers();
}
+ if (debuggerCore()->boolSetting(MultiInferior)) {
+ //postCommand("set follow-exec-mode new");
+ postCommand("set detach-on-fork off");
+ }
+
+ // Quick check whether we have python.
+ postCommand("python print 43", ConsoleCommand, CB(handleHasPython));
+
// Dummy command to guarantee a roundtrip before the adapter proceed.
+ // Make sure this stays the last command in startGdb().
postCommand("pwd", ConsoleCommand, CB(reportEngineSetupOk));
}
@@ -4834,10 +4904,15 @@ void GdbEngine::loadInitScript()
}
}
-void GdbEngine::loadPythonDumpers()
+void GdbEngine::tryLoadPythonDumpers()
{
if (m_forceAsyncModel)
return;
+ if (!m_hasPython)
+ return;
+ if (m_pythonAttemptedToLoad)
+ return;
+ m_pythonAttemptedToLoad = true;
const QByteArray dumperSourcePath =
Core::ICore::resourcePath().toLocal8Bit() + "/dumper/";
@@ -4849,9 +4924,22 @@ void GdbEngine::loadPythonDumpers()
postCommand("python execfile('" + dumperSourcePath + "qttypes.py')",
ConsoleCommand|NonCriticalResponse);
+ postCommand("python qqStringCutOff = "
+ + debuggerCore()->action(MaximalStringLength)->value().toByteArray(),
+ ConsoleCommand|NonCriticalResponse);
+
loadInitScript();
- postCommand("bbsetup", ConsoleCommand, CB(handleHasPython));
+ postCommand("bbsetup", ConsoleCommand, CB(handlePythonSetup));
+}
+
+void GdbEngine::reloadDebuggingHelpers()
+{
+ // Only supported for python.
+ if (m_hasPython) {
+ m_pythonAttemptedToLoad = false;
+ tryLoadPythonDumpers();
+ }
}
void GdbEngine::handleGdbError(QProcess::ProcessError error)
@@ -4921,17 +5009,17 @@ void GdbEngine::abortDebugger()
}
void GdbEngine::handleAdapterStartFailed(const QString &msg,
- const QString &settingsIdHint)
+ Core::Id settingsIdHint)
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty()) {
const QString title = tr("Adapter start failed");
- if (settingsIdHint.isEmpty()) {
+ if (!settingsIdHint.isValid()) {
Core::ICore::showWarningWithOptions(title, msg);
} else {
Core::ICore::showWarningWithOptions(title, msg, QString(),
- _(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
+ Constants::DEBUGGER_SETTINGS_CATEGORY, settingsIdHint);
}
}
notifyEngineSetupFailed();
@@ -4951,6 +5039,11 @@ void GdbEngine::handleInferiorPrepared()
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
+ if (debuggerCore()->boolSetting(IntelFlavor)) {
+ //postCommand("set follow-exec-mode new");
+ postCommand("set disassembly-flavor intel");
+ }
+
if (sp.breakOnMain) {
QByteArray cmd = "tbreak ";
cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
@@ -4988,19 +5081,17 @@ void GdbEngine::finishInferiorSetup()
void GdbEngine::handleDebugInfoLocation(const GdbResponse &response)
{
-#ifdef Q_OS_WIN
- const char pathSep = ';';
-#else
- const char pathSep = ':';
-#endif
if (response.resultClass == GdbResultDone) {
const QByteArray debugInfoLocation = startParameters().debugInfoLocation.toLocal8Bit();
if (QFile::exists(QString::fromLocal8Bit(debugInfoLocation))) {
const QByteArray curDebugInfoLocations = response.consoleStreamOutput.split('"').value(1);
- if (curDebugInfoLocations.isEmpty())
+ if (curDebugInfoLocations.isEmpty()) {
postCommand("set debug-file-directory " + debugInfoLocation);
- else
- postCommand("set debug-file-directory " + debugInfoLocation + pathSep + curDebugInfoLocations);
+ } else {
+ postCommand("set debug-file-directory " + debugInfoLocation
+ + HostOsInfo::pathListSeparator().toLatin1()
+ + curDebugInfoLocations);
+ }
}
}
}
@@ -5033,13 +5124,18 @@ void GdbEngine::handleNamespaceExtraction(const GdbResponse &response)
} else {
if (debuggerCore()->boolSetting(BreakOnAbort))
postCommand("-break-insert -f abort");
- if (debuggerCore()->boolSetting(BreakOnWarning))
+ if (debuggerCore()->boolSetting(BreakOnWarning)) {
postCommand("-break-insert -f '" + qtNamespace() + "qWarning'");
- if (debuggerCore()->boolSetting(BreakOnFatal))
+ postCommand("-break-insert -f '" + qtNamespace() + "QMessageLogger::warning'");
+ }
+ if (debuggerCore()->boolSetting(BreakOnFatal)) {
postCommand("-break-insert -f '" + qtNamespace() + "qFatal'",
- CB(handleBreakOnQFatal));
- else
+ CB(handleBreakOnQFatal), QVariant(false));
+ postCommand("-break-insert -f '" + qtNamespace() + "QMessageLogger::fatal'",
+ CB(handleBreakOnQFatal), QVariant(true));
+ } else {
notifyInferiorSetupOk();
+ }
}
}
@@ -5056,7 +5152,8 @@ void GdbEngine::handleBreakOnQFatal(const GdbResponse &response)
}
// Continue setup.
- notifyInferiorSetupOk();
+ if (response.cookie.toBool())
+ notifyInferiorSetupOk();
}
void GdbEngine::notifyInferiorSetupFailed(const QString &msg)
@@ -5309,7 +5406,7 @@ bool GdbEngine::prepareCommand()
// perr == BadQuoting is never returned on Windows
// FIXME? QTCREATORBUG-2809
handleAdapterStartFailed(QCoreApplication::translate("DebuggerEngine", // Same message in CdbEngine
- "Debugging complex command lines is currently not supported on Windows."), QString());
+ "Debugging complex command lines is currently not supported on Windows."), Core::Id());
return false;
}
#endif
@@ -5362,6 +5459,14 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
}
}
+QByteArray GdbEngine::dotEscape(QByteArray str)
+{
+ str.replace(' ', '.');
+ str.replace('\\', '.');
+ str.replace('/', '.');
+ return str;
+}
+
//
// Factory
//
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 689c133e00..b70d9e4756 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -35,6 +35,9 @@
#include "stackframe.h"
#include "watchhandler.h"
#include "watchutils.h"
+#include "threaddata.h"
+
+#include <coreplugin/id.h>
#include <QByteArray>
#include <QProcess>
@@ -227,18 +230,19 @@ protected: ////////// Gdb Process Management //////////
void startGdb(const QStringList &args = QStringList());
void reportEngineSetupOk(const GdbResponse &response);
+ void handleCheckForPython(const GdbResponse &response);
void handleInferiorShutdown(const GdbResponse &response);
void handleGdbExit(const GdbResponse &response);
void handleNamespaceExtraction(const GdbResponse &response);
void loadInitScript();
- void loadPythonDumpers();
+ void tryLoadPythonDumpers();
void pythonDumpersFailed();
// Something went wrong with the adapter *before* adapterStarted() was emitted.
// Make sure to clean up everything before emitting this signal.
void handleAdapterStartFailed(const QString &msg,
- const QString &settingsIdHint = QString());
+ Core::Id settingsIdHint = Core::Id());
// This triggers the initial breakpoint synchronization and causes
// finishInferiorSetup() being called once done.
@@ -387,6 +391,7 @@ protected:
void handleShowVersion(const GdbResponse &response);
void handleListFeatures(const GdbResponse &response);
void handleHasPython(const GdbResponse &response);
+ void handlePythonSetup(const GdbResponse &response);
int m_gdbVersion; // 6.8.0 is 60800
int m_gdbBuildVersion; // MAC only?
@@ -437,7 +442,7 @@ private: ////////// Inferior Management //////////
private: ////////// View & Data Stuff //////////
protected:
- void selectThread(int index);
+ void selectThread(ThreadId threadId);
void activateFrame(int index);
void resetLocation();
@@ -475,11 +480,13 @@ private: ////////// View & Data Stuff //////////
Q_SLOT void loadAllSymbols();
void loadSymbolsForStack();
void requestModuleSymbols(const QString &moduleName);
+ void requestModuleSections(const QString &moduleName);
void reloadModules();
void examineModules();
void reloadModulesInternal();
void handleModulesList(const GdbResponse &response);
void handleShowModuleSymbols(const GdbResponse &response);
+ void handleShowModuleSections(const GdbResponse &response);
//
// Snapshot specific stuff
@@ -523,6 +530,7 @@ private: ////////// View & Data Stuff //////////
DisassemblerLines parseDisassembler(const GdbResponse &response);
DisassemblerLines parseCliDisassembler(const QByteArray &response);
DisassemblerLines parseMiDisassembler(const GdbMi &response);
+ Q_SLOT void reloadDisassembly();
bool m_disassembleUsesComma;
@@ -645,6 +653,7 @@ protected:
bool checkDebuggingHelpersClassic();
void setDebuggingHelperStateClassic(DebuggingHelperState);
void tryLoadDebuggingHelpersClassic();
+ void reloadDebuggingHelpers();
DebuggingHelperState m_debuggingHelperState;
DumperHelper m_dumperHelper;
@@ -661,10 +670,8 @@ protected:
QString tooltipExpression() const;
QScopedPointer<GdbToolTipContext> m_toolTipContext;
-
// For short-circuiting stack and thread list evaluation.
bool m_stackNeeded;
- int m_currentThreadId;
//
// Qml
@@ -701,6 +708,7 @@ protected:
// debug information.
bool attemptQuickStart() const;
bool m_fullStartDone;
+ bool m_pythonAttemptedToLoad;
// Test
bool m_forceAsyncModel;
@@ -713,6 +721,7 @@ protected:
static QString msgInferiorSetupOk();
static QString msgInferiorRunOk();
static QString msgConnectRemoteServerFailed(const QString &why);
+ static QByteArray dotEscape(QByteArray str);
protected:
enum DumperHandling
diff --git a/src/plugins/debugger/gdb/gdbmi.cpp b/src/plugins/debugger/gdb/gdbmi.cpp
deleted file mode 100644
index 609b50a874..0000000000
--- a/src/plugins/debugger/gdb/gdbmi.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/****************************************************************************
-**
-** 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 "gdbmi.h"
-
-#include <utils/qtcassert.h>
-
-#include <QByteArray>
-#include <QDebug>
-#include <QRegExp>
-#include <QTextStream>
-
-#include <ctype.h>
-
-namespace Debugger {
-namespace Internal {
-
-void skipCommas(const char *&from, const char *to)
-{
- while (*from == ',' && from != to)
- ++from;
-}
-
-QTextStream &operator<<(QTextStream &os, const GdbMi &mi)
-{
- return os << mi.toString();
-}
-
-void GdbMi::parseResultOrValue(const char *&from, const char *to)
-{
- while (from != to && isspace(*from))
- ++from;
-
- //qDebug() << "parseResultOrValue: " << QByteArray(from, to - from);
- parseValue(from, to);
- if (isValid()) {
- //qDebug() << "no valid result in " << QByteArray(from, to - from);
- return;
- }
- if (from == to || *from == '(')
- return;
- const char *ptr = from;
- while (ptr < to && *ptr != '=') {
- //qDebug() << "adding" << QChar(*ptr) << "to name";
- ++ptr;
- }
- m_name = QByteArray(from, ptr - from);
- from = ptr;
- if (from < to && *from == '=') {
- ++from;
- parseValue(from, to);
- }
-}
-
-QByteArray GdbMi::parseCString(const char *&from, const char *to)
-{
- QByteArray result;
- //qDebug() << "parseCString: " << QByteArray(from, to - from);
- if (*from != '"') {
- qDebug() << "MI Parse Error, double quote expected";
- ++from; // So we don't hang
- return QByteArray();
- }
- const char *ptr = from;
- ++ptr;
- while (ptr < to) {
- if (*ptr == '"') {
- ++ptr;
- result = QByteArray(from + 1, ptr - from - 2);
- break;
- }
- if (*ptr == '\\') {
- ++ptr;
- if (ptr == to) {
- qDebug() << "MI Parse Error, unterminated backslash escape";
- from = ptr; // So we don't hang
- return QByteArray();
- }
- }
- ++ptr;
- }
- from = ptr;
-
- int idx = result.indexOf('\\');
- if (idx >= 0) {
- char *dst = result.data() + idx;
- const char *src = dst + 1, *end = result.data() + result.length();
- do {
- char c = *src++;
- switch (c) {
- case 'a': *dst++ = '\a'; break;
- case 'b': *dst++ = '\b'; break;
- case 'f': *dst++ = '\f'; break;
- case 'n': *dst++ = '\n'; break;
- case 'r': *dst++ = '\r'; break;
- case 't': *dst++ = '\t'; break;
- case 'v': *dst++ = '\v'; break;
- case '"': *dst++ = '"'; break;
- case '\\': *dst++ = '\\'; break;
- default:
- {
- int chars = 0;
- uchar prod = 0;
- forever {
- if (c < '0' || c > '7') {
- --src;
- break;
- }
- prod = prod * 8 + c - '0';
- if (++chars == 3 || src == end)
- break;
- c = *src++;
- }
- if (!chars) {
- qDebug() << "MI Parse Error, unrecognized backslash escape";
- return QByteArray();
- }
- *dst++ = prod;
- }
- }
- while (src != end) {
- char c = *src++;
- if (c == '\\')
- break;
- *dst++ = c;
- }
- } while (src != end);
- *dst = 0;
- result.truncate(dst - result.data());
- }
-
- return result;
-}
-
-void GdbMi::parseValue(const char *&from, const char *to)
-{
- //qDebug() << "parseValue: " << QByteArray(from, to - from);
- switch (*from) {
- case '{':
- parseTuple(from, to);
- break;
- case '[':
- parseList(from, to);
- break;
- case '"':
- m_type = Const;
- m_data = parseCString(from, to);
- break;
- default:
- break;
- }
-}
-
-
-void GdbMi::parseTuple(const char *&from, const char *to)
-{
- //qDebug() << "parseTuple: " << QByteArray(from, to - from);
- QTC_CHECK(*from == '{');
- ++from;
- parseTuple_helper(from, to);
-}
-
-void GdbMi::parseTuple_helper(const char *&from, const char *to)
-{
- skipCommas(from, to);
- //qDebug() << "parseTuple_helper: " << QByteArray(from, to - from);
- m_type = Tuple;
- while (from < to) {
- if (*from == '}') {
- ++from;
- break;
- }
- GdbMi child;
- child.parseResultOrValue(from, to);
- //qDebug() << "\n=======\n" << qPrintable(child.toString()) << "\n========\n";
- if (!child.isValid())
- return;
- m_children += child;
- skipCommas(from, to);
- }
-}
-
-void GdbMi::parseList(const char *&from, const char *to)
-{
- //qDebug() << "parseList: " << QByteArray(from, to - from);
- QTC_CHECK(*from == '[');
- ++from;
- m_type = List;
- skipCommas(from, to);
- while (from < to) {
- if (*from == ']') {
- ++from;
- break;
- }
- GdbMi child;
- child.parseResultOrValue(from, to);
- if (child.isValid())
- m_children += child;
- skipCommas(from, to);
- }
-}
-
-static QByteArray ind(int indent)
-{
- return QByteArray(2 * indent, ' ');
-}
-
-void GdbMi::dumpChildren(QByteArray * str, bool multiline, int indent) const
-{
- for (int i = 0; i < m_children.size(); ++i) {
- if (i != 0) {
- *str += ',';
- if (multiline)
- *str += '\n';
- }
- if (multiline)
- *str += ind(indent);
- *str += m_children.at(i).toString(multiline, indent);
- }
-}
-
-QByteArray GdbMi::escapeCString(const QByteArray &ba)
-{
- QByteArray ret;
- ret.reserve(ba.length() * 2);
- for (int i = 0; i < ba.length(); ++i) {
- const uchar c = ba.at(i);
- switch (c) {
- case '\\': ret += "\\\\"; break;
- case '\a': ret += "\\a"; break;
- case '\b': ret += "\\b"; break;
- case '\f': ret += "\\f"; break;
- case '\n': ret += "\\n"; break;
- case '\r': ret += "\\r"; break;
- case '\t': ret += "\\t"; break;
- case '\v': ret += "\\v"; break;
- case '"': ret += "\\\""; break;
- default:
- if (c < 32 || c == 127) {
- ret += '\\';
- ret += ('0' + (c >> 6));
- ret += ('0' + ((c >> 3) & 7));
- ret += ('0' + (c & 7));
- } else {
- ret += c;
- }
- }
- }
- return ret;
-}
-
-QByteArray GdbMi::toString(bool multiline, int indent) const
-{
- QByteArray result;
- switch (m_type) {
- case Invalid:
- if (multiline)
- result += ind(indent) + "Invalid\n";
- else
- result += "Invalid";
- break;
- case Const:
- if (!m_name.isEmpty())
- result += m_name + '=';
- result += '"' + escapeCString(m_data) + '"';
- break;
- case Tuple:
- if (!m_name.isEmpty())
- result += m_name + '=';
- if (multiline) {
- result += "{\n";
- dumpChildren(&result, multiline, indent + 1);
- result += '\n' + ind(indent) + '}';
- } else {
- result += '{';
- dumpChildren(&result, multiline, indent + 1);
- result += '}';
- }
- break;
- case List:
- if (!m_name.isEmpty())
- result += m_name + '=';
- if (multiline) {
- result += "[\n";
- dumpChildren(&result, multiline, indent + 1);
- result += '\n' + ind(indent) + ']';
- } else {
- result += '[';
- dumpChildren(&result, multiline, indent + 1);
- result += ']';
- }
- break;
- }
- return result;
-}
-
-void GdbMi::fromString(const QByteArray &ba)
-{
- const char *from = ba.constBegin();
- const char *to = ba.constEnd();
- parseResultOrValue(from, to);
-}
-
-void GdbMi::fromStringMultiple(const QByteArray &ba)
-{
- const char *from = ba.constBegin();
- const char *to = ba.constEnd();
- parseTuple_helper(from, to);
-}
-
-GdbMi GdbMi::findChild(const char *name) const
-{
- for (int i = 0; i < m_children.size(); ++i)
- if (m_children.at(i).m_name == name)
- return m_children.at(i);
- return GdbMi();
-}
-
-qulonglong GdbMi::toAddress() const
-{
- QByteArray ba = m_data;
- if (ba.endsWith('L'))
- ba.chop(1);
- if (ba.startsWith('*') || ba.startsWith('@'))
- ba = ba.mid(1);
- return ba.toULongLong(0, 0);
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-//
-// GdbResponse
-//
-//////////////////////////////////////////////////////////////////////////////////
-
-QByteArray GdbResponse::stringFromResultClass(GdbResultClass resultClass)
-{
- switch (resultClass) {
- case GdbResultDone: return "done";
- case GdbResultRunning: return "running";
- case GdbResultConnected: return "connected";
- case GdbResultError: return "error";
- case GdbResultExit: return "exit";
- default: return "unknown";
- }
-}
-
-QByteArray GdbResponse::toString() const
-{
- QByteArray result;
- if (token != -1)
- result = QByteArray::number(token);
- result += '^';
- result += stringFromResultClass(resultClass);
- if (data.isValid())
- result += ',' + data.toString();
- result += '\n';
- return result;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////
-//
-// GdbResponse
-//
-//////////////////////////////////////////////////////////////////////////////////
-
-void extractGdbVersion(const QString &msg,
- int *gdbVersion, int *gdbBuildVersion, bool *isMacGdb, bool *isQnxGdb)
-{
- const QChar dot(QLatin1Char('.'));
-
- QString cleaned;
- QString build;
- bool inClean = true;
- foreach (QChar c, msg) {
- if (inClean && !cleaned.isEmpty() && c != dot && (c.isPunct() || c.isSpace()))
- inClean = false;
- if (inClean) {
- if (c.isDigit())
- cleaned.append(c);
- else if (!cleaned.isEmpty() && !cleaned.endsWith(dot))
- cleaned.append(dot);
- } else {
- if (c.isDigit())
- build.append(c);
- else if (!build.isEmpty() && !build.endsWith(dot))
- build.append(dot);
- }
- }
-
- *isMacGdb = msg.contains(QLatin1String("Apple version"));
- *isQnxGdb = msg.contains(QLatin1String("qnx"));
-
- *gdbVersion = 10000 * cleaned.section(dot, 0, 0).toInt()
- + 100 * cleaned.section(dot, 1, 1).toInt()
- + 1 * cleaned.section(dot, 2, 2).toInt();
- if (cleaned.count(dot) >= 3)
- *gdbBuildVersion = cleaned.section(dot, 3, 3).toInt();
- else
- *gdbBuildVersion = build.section(dot, 0, 0).toInt();
-
- if (*isMacGdb)
- *gdbBuildVersion = build.section(dot, 1, 1).toInt();
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/gdbmi.h b/src/plugins/debugger/gdb/gdbmi.h
deleted file mode 100644
index b9d3e39ae3..0000000000
--- a/src/plugins/debugger/gdb/gdbmi.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** 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.
-**
-****************************************************************************/
-
-#ifndef DEBUGGER_GDBMI_H
-#define DEBUGGER_GDBMI_H
-
-#include <QByteArray>
-#include <QList>
-#include <QVariant>
-
-namespace Debugger {
-namespace Internal {
-
-/*
-
-output ==>
- ( out-of-band-record )* [ result-record ] "(gdb)" nl
-result-record ==>
- [ token ] "^" result-class ( "," result )* nl
-out-of-band-record ==>
- async-record | stream-record
-async-record ==>
- exec-async-output | status-async-output | notify-async-output
-exec-async-output ==>
- [ token ] "*" async-output
-status-async-output ==>
- [ token ] "+" async-output
-notify-async-output ==>
- [ token ] "=" async-output
-async-output ==>
- async-class ( "," result )* nl
-result-class ==>
- "done" | "running" | "connected" | "error" | "exit"
-async-class ==>
- "stopped" | others (where others will be added depending on the needs--this is still in development).
-result ==>
- variable "=" value
-variable ==>
- string
-value ==>
- const | tuple | list
-const ==>
- c-string
-tuple ==>
- "{}" | "{" result ( "," result )* "}"
-list ==>
- "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
-stream-record ==>
- console-stream-output | target-stream-output | log-stream-output
-console-stream-output ==>
- "~" c-string
-target-stream-output ==>
- "@" c-string
-log-stream-output ==>
- "&" c-string
-nl ==>
- CR | CR-LF
-token ==>
- any sequence of digits.
-
- */
-
-// FIXME: rename into GdbMiValue
-class GdbMi
-{
-public:
- GdbMi() : m_type(Invalid) {}
-
- QByteArray m_name;
- QByteArray m_data;
- QList<GdbMi> m_children;
-
- enum Type {
- Invalid,
- Const,
- Tuple,
- List
- };
-
- Type m_type;
-
- inline Type type() const { return m_type; }
- inline QByteArray name() const { return m_name; }
- inline bool hasName(const char *name) const { return m_name == name; }
-
- inline bool isValid() const { return m_type != Invalid; }
- inline bool isConst() const { return m_type == Const; }
- inline bool isTuple() const { return m_type == Tuple; }
- inline bool isList() const { return m_type == List; }
-
-
- inline QByteArray data() const { return m_data; }
- inline const QList<GdbMi> &children() const { return m_children; }
- inline int childCount() const { return m_children.size(); }
-
- const GdbMi &childAt(int index) const { return m_children[index]; }
- GdbMi &childAt(int index) { return m_children[index]; }
- GdbMi findChild(const char *name) const;
-
- QByteArray toString(bool multiline = false, int indent = 0) const;
- qulonglong toAddress() const;
- void fromString(const QByteArray &str);
- void fromStringMultiple(const QByteArray &str);
-
-private:
- friend class GdbResponse;
- friend class GdbEngine;
-
- static QByteArray parseCString(const char *&from, const char *to);
- static QByteArray escapeCString(const QByteArray &ba);
- void parseResultOrValue(const char *&from, const char *to);
- void parseValue(const char *&from, const char *to);
- void parseTuple(const char *&from, const char *to);
- void parseTuple_helper(const char *&from, const char *to);
- void parseList(const char *&from, const char *to);
-
- void dumpChildren(QByteArray *str, bool multiline, int indent) const;
-};
-
-enum GdbResultClass
-{
- // "done" | "running" | "connected" | "error" | "exit"
- GdbResultUnknown,
- GdbResultDone,
- GdbResultRunning,
- GdbResultConnected,
- GdbResultError,
- GdbResultExit
-};
-
-class GdbResponse
-{
-public:
- GdbResponse() : token(-1), resultClass(GdbResultUnknown) {}
- QByteArray toString() const;
- static QByteArray stringFromResultClass(GdbResultClass resultClass);
-
- int token;
- GdbResultClass resultClass;
- GdbMi data;
- QVariant cookie;
- QByteArray logStreamOutput;
- QByteArray consoleStreamOutput;
-};
-
-void extractGdbVersion(const QString &msg,
- int *gdbVersion, int *gdbBuildVersion, bool *isMacGdb, bool *isQnxGdb);
-
-} // namespace Internal
-} // namespace Debugger
-
-//Q_DECLARE_METATYPE(GdbDebugger::Internal::GdbMi)
-
-#endif // DEBUGGER_GDBMI_H
diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp
index 0d023f1c09..014db0cf01 100644
--- a/src/plugins/debugger/gdb/gdboptionspage.cpp
+++ b/src/plugins/debugger/gdb/gdboptionspage.cpp
@@ -76,9 +76,13 @@ public:
QCheckBox *checkBoxBreakOnAbort;
QCheckBox *checkBoxEnableReverseDebugging;
QCheckBox *checkBoxAttemptQuickStart;
+ QCheckBox *checkBoxMultiInferior;
+ QCheckBox *checkBoxIntelFlavor;
QGroupBox *groupBoxStartupCommands;
QTextEdit *textEditStartupCommands;
+ QGroupBox *groupBoxPostAttachCommands;
+ QTextEdit *textEditPostAttachCommands;
//QGroupBox *groupBoxPluginDebugging;
//QRadioButton *radioButtonAllPluginBreakpoints;
@@ -183,6 +187,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
"of debug information such as <i>/usr/src/debug</i> "
"when starting GDB.</body></html>"));
+ // #fixme: 2.7 Move to common settings page.
checkBoxBreakOnWarning = new QCheckBox(groupBoxGeneral);
checkBoxBreakOnWarning->setText(CommonOptionsPage::msgSetBreakpointAtFunction("qWarning"));
checkBoxBreakOnWarning->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qWarning"));
@@ -210,13 +215,30 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
"This can result in faster startup times at the price of not being able to "
"set breakpoints by file and number.</body></html>"));
+ checkBoxMultiInferior = new QCheckBox(groupBoxGeneral);
+ checkBoxMultiInferior->setText(GdbOptionsPage::tr("Debug all children"));
+ checkBoxMultiInferior->setToolTip(GdbOptionsPage::tr(
+ "<html><head/><body>Keep debugging all children after a fork."
+ "</body></html>"));
+
+ checkBoxIntelFlavor = new QCheckBox(groupBoxGeneral);
+ checkBoxIntelFlavor->setText(GdbOptionsPage::tr("Use Intel style disassembly"));
+ checkBoxIntelFlavor->setToolTip(GdbOptionsPage::tr(
+ "<html><head/><body>GDB shows by default AT&&T style disassembly."
+ "</body></html>"));
+
groupBoxStartupCommands = new QGroupBox(this);
groupBoxStartupCommands->setTitle(GdbOptionsPage::tr("Additional Startup Commands"));
groupBoxStartupCommands->setToolTip(GdbOptionsPage::tr(
"<html><head/><body><p>GDB commands entered here will be executed after "
"GDB has been started and the debugging helpers have been initialized.</p>"
"<p>You can add commands to load further debugging helpers here, or "
- "modify existing ones.</p><p>To execute arbitrary Python scripts, "
+ "modify existing ones.</p>"
+ "<p>To execute simple Python commands, prefix them with \"python\".</p>"
+ "<p>To execute sequences of Python commands spanning multiple lines "
+ "prepend the block with \"python\" on a separate line, and append "
+ "\"end\" on a separate line.</p>"
+ "<p>To execute arbitrary Python scripts, "
"use <i>python execfile('/path/to/script.py')</i>.</p>"
"</body></html>"));
@@ -224,6 +246,19 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
textEditStartupCommands->setAcceptRichText(false);
textEditStartupCommands->setToolTip(groupBoxStartupCommands->toolTip());
+ groupBoxPostAttachCommands = new QGroupBox(this);
+ groupBoxPostAttachCommands->setTitle(GdbOptionsPage::tr("Additional Attach Commands"));
+ groupBoxPostAttachCommands->setToolTip(GdbOptionsPage::tr(
+ "<html><head/><body><p>GDB commands entered here will be executed after "
+ "GDB has successfully attached to remote targets.</p>"
+ "<p>You can add commands to further set up the target here, "
+ "such as \"monitor reset\" or \"load\"."
+ "</body></html>"));
+
+ textEditPostAttachCommands = new QTextEdit(groupBoxPostAttachCommands);
+ textEditPostAttachCommands->setAcceptRichText(false);
+ textEditPostAttachCommands->setToolTip(groupBoxPostAttachCommands->toolTip());
+
/*
groupBoxPluginDebugging = new QGroupBox(q);
groupBoxPluginDebugging->setTitle(GdbOptionsPage::tr(
@@ -258,6 +293,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
formLayout->addRow(checkBoxUseDynamicType);
formLayout->addRow(checkBoxLoadGdbInit);
formLayout->addRow(checkBoxWarnOnReleaseBuilds);
+ formLayout->addRow(checkBoxIntelFlavor);
formLayout->addRow(labelDangerous);
formLayout->addRow(checkBoxTargetAsync);
formLayout->addRow(checkBoxAutoEnrichParameters);
@@ -266,18 +302,23 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
formLayout->addRow(checkBoxBreakOnAbort);
formLayout->addRow(checkBoxEnableReverseDebugging);
formLayout->addRow(checkBoxAttemptQuickStart);
+ formLayout->addRow(checkBoxMultiInferior);
QGridLayout *startLayout = new QGridLayout(groupBoxStartupCommands);
startLayout->addWidget(textEditStartupCommands, 0, 0, 1, 1);
+ QGridLayout *postAttachLayout = new QGridLayout(groupBoxPostAttachCommands);
+ postAttachLayout->addWidget(textEditPostAttachCommands, 0, 0, 1, 1);
+
//QHBoxLayout *horizontalLayout = new QHBoxLayout();
//horizontalLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Preferred, QSizePolicy::Minimum));
//horizontalLayout->addWidget(labelSelectedPluginBreakpoints);
//horizontalLayout->addWidget(lineEditSelectedPluginBreakpointsPattern);
QGridLayout *gridLayout = new QGridLayout(this);
- gridLayout->addWidget(groupBoxGeneral, 0, 0);
- gridLayout->addWidget(groupBoxStartupCommands, 0, 1);
+ gridLayout->addWidget(groupBoxGeneral, 0, 0, 2, 1);
+ gridLayout->addWidget(groupBoxStartupCommands, 0, 1, 1, 1);
+ gridLayout->addWidget(groupBoxPostAttachCommands, 1, 1, 1, 1);
//gridLayout->addWidget(groupBoxStartupCommands, 0, 1, 1, 1);
//gridLayout->addWidget(radioButtonAllPluginBreakpoints, 0, 0, 1, 1);
@@ -289,6 +330,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
DebuggerCore *dc = debuggerCore();
group.insert(dc->action(GdbStartupCommands), textEditStartupCommands);
+ group.insert(dc->action(GdbPostAttachCommands), textEditPostAttachCommands);
group.insert(dc->action(LoadGdbInit), checkBoxLoadGdbInit);
group.insert(dc->action(AutoEnrichParameters), checkBoxAutoEnrichParameters);
group.insert(dc->action(UseDynamicType), checkBoxUseDynamicType);
@@ -300,6 +342,8 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
group.insert(dc->action(BreakOnAbort), checkBoxBreakOnAbort);
group.insert(dc->action(GdbWatchdogTimeout), spinBoxGdbWatchdogTimeout);
group.insert(dc->action(AttemptQuickStart), checkBoxAttemptQuickStart);
+ group.insert(dc->action(MultiInferior), checkBoxMultiInferior);
+ group.insert(dc->action(IntelFlavor), checkBoxIntelFlavor);
group.insert(dc->action(UseMessageBoxForSignals), checkBoxUseMessageBoxForSignals);
group.insert(dc->action(SkipKnownFrames), checkBoxSkipKnownFrames);
@@ -324,6 +368,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
<< sep << checkBoxUseMessageBoxForSignals->text()
<< sep << checkBoxAdjustBreakpointLocations->text()
<< sep << checkBoxAttemptQuickStart->text()
+ << sep << checkBoxMultiInferior->text()
// << sep << groupBoxPluginDebugging->title()
// << sep << radioButtonAllPluginBreakpoints->text()
// << sep << radioButtonSelectedPluginBreakpoints->text()
@@ -335,9 +380,9 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent)
GdbOptionsPage::GdbOptionsPage()
{
- setId(QLatin1String("M.Gdb"));
+ setId("M.Gdb");
setDisplayName(tr("GDB"));
- setCategory(QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY));
+ setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
setDisplayCategory(QCoreApplication::translate("Debugger", Constants::DEBUGGER_SETTINGS_TR_CATEGORY));
setCategoryIcon(QLatin1String(Constants::DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON));
}
diff --git a/src/plugins/debugger/gdb/localplaingdbadapter.cpp b/src/plugins/debugger/gdb/localplaingdbadapter.cpp
index 5d5ce71407..366b20860a 100644
--- a/src/plugins/debugger/gdb/localplaingdbadapter.cpp
+++ b/src/plugins/debugger/gdb/localplaingdbadapter.cpp
@@ -37,6 +37,7 @@
#include <projectexplorer/abi.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
@@ -61,11 +62,8 @@ GdbLocalPlainEngine::GdbLocalPlainEngine(const DebuggerStartParameters &startPar
GdbEngine::DumperHandling GdbLocalPlainEngine::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
+ return Utils::HostOsInfo::isWindowsHost() || Utils::HostOsInfo::isMacHost()
+ ? DumperLoadedByGdb : DumperLoadedByGdbPreload;
}
void GdbLocalPlainEngine::setupEngine()
diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp
index 623c0318da..9b8ed82ea4 100644
--- a/src/plugins/debugger/gdb/pythongdbengine.cpp
+++ b/src/plugins/debugger/gdb/pythongdbengine.cpp
@@ -28,7 +28,8 @@
****************************************************************************/
#include "gdbengine.h"
-#include "gdbmi.h"
+
+#include "debuggerprotocol.h"
#include "debuggeractions.h"
#include "debuggercore.h"
#include "debuggerstringutils.h"
diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp
index f9a583003f..733e7b5a9e 100644
--- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp
+++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp
@@ -30,15 +30,16 @@
#include "remotegdbserveradapter.h"
#include "debuggeractions.h"
-#include "debuggerstartparameters.h"
#include "debuggercore.h"
+#include "debuggerprotocol.h"
+#include "debuggerstartparameters.h"
#include "debuggerstringutils.h"
-#include "gdbengine.h"
-#include "gdbmi.h"
-#include <utils/qtcassert.h>
-#include <utils/fancymainwindow.h>
#include <projectexplorer/abi.h>
+#include <utils/fancymainwindow.h>
+#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QFileInfo>
#include <QMessageBox>
@@ -84,7 +85,14 @@ void GdbRemoteServerEngine::setupEngine()
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER"));
if (!startParameters().serverStartScript.isEmpty()) {
- m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
+
+ // 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().remoteSetupNeeded)
@@ -156,11 +164,6 @@ void GdbRemoteServerEngine::setupInferior()
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
const DebuggerStartParameters &sp = startParameters();
-#ifdef Q_OS_WIN
- #define PATHSEP ";"
-#else
- #define PATHSEP ":"
-#endif
QString executableFileName;
if (!sp.executable.isEmpty()) {
QFileInfo fi(sp.executable);
@@ -178,7 +181,8 @@ void GdbRemoteServerEngine::setupInferior()
// if (!remoteArch.isEmpty())
// postCommand("set architecture " + remoteArch);
- const QString solibSearchPath = sp.solibSearchPath.join(QLatin1String(PATHSEP));
+ const QString solibSearchPath
+ = sp.solibSearchPath.join(QString(Utils::HostOsInfo::pathListSeparator()));
if (!solibSearchPath.isEmpty())
postCommand("set solib-search-path " + solibSearchPath.toLocal8Bit());
@@ -285,6 +289,11 @@ void GdbRemoteServerEngine::handleTargetRemote(const GdbResponse &record)
// 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."
@@ -304,11 +313,10 @@ void GdbRemoteServerEngine::handleTargetQnx(const GdbResponse &response)
showMessage(msgAttachedToStoppedInferior(), StatusBar);
const qint64 pid = isMasterEngine() ? startParameters().attachPID : masterEngine()->startParameters().attachPID;
- if (pid > -1) {
+ if (pid > -1)
postCommand("attach " + QByteArray::number(pid), CB(handleAttach));
- } else {
+ else
handleInferiorPrepared();
- }
} else {
// 16^error,msg="hd:5555: Connection timed out."
QString msg = msgConnectRemoteServerFailed(
diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp
index 8ede54051a..d0f19cd2a6 100644
--- a/src/plugins/debugger/gdb/termgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/termgdbadapter.cpp
@@ -29,14 +29,14 @@
#include "termgdbadapter.h"
+#include "debuggercore.h"
+#include "debuggerprotocol.h"
#include "debuggerstartparameters.h"
-#include "gdbmi.h"
-#include "gdbengine.h"
-#include "procinterrupt.h"
#include "debuggerstringutils.h"
-#include "debuggercore.h"
+#include "procinterrupt.h"
#include "shared/hostutils.h"
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
@@ -60,11 +60,10 @@ GdbTermEngine::GdbTermEngine(const DebuggerStartParameters &startParameters)
{
#ifdef Q_OS_WIN
// Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) {
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
m_stubProc.setMode(Utils::ConsoleProcess::Suspend);
- } else {
+ else
m_stubProc.setMode(Utils::ConsoleProcess::Debug);
- }
#else
m_stubProc.setMode(Utils::ConsoleProcess::Debug);
m_stubProc.setSettings(Core::ICore::settings());
@@ -79,11 +78,9 @@ GdbTermEngine::~GdbTermEngine()
GdbEngine::DumperHandling GdbTermEngine::dumperHandling() const
{
// LD_PRELOAD fails for System-Qt on Mac.
-#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
- return DumperLoadedByGdb;
-#else
- return DumperLoadedByAdapter; // Handles loading itself via LD_PRELOAD
-#endif
+ return Utils::HostOsInfo::isWindowsHost() || Utils::HostOsInfo::isMacHost()
+ ? DumperLoadedByGdb
+ : DumperLoadedByAdapter; // Handles loading itself via LD_PRELOAD
}
void GdbTermEngine::setupEngine()
@@ -106,7 +103,7 @@ void GdbTermEngine::setupEngine()
connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString)));
connect(&m_stubProc, SIGNAL(processStarted()), SLOT(stubStarted()));
- connect(&m_stubProc, SIGNAL(wrapperStopped()), SLOT(stubExited()));
+ connect(&m_stubProc, SIGNAL(stubStopped()), SLOT(stubExited()));
// FIXME: Starting the stub implies starting the inferior. This is
// fairly unclean as far as the state machine and error reporting go.
@@ -146,25 +143,29 @@ void GdbTermEngine::setupInferior()
void GdbTermEngine::handleStubAttached(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
-#ifdef Q_OS_WIN
- QString errorMessage;
-#endif // Q_OS_WIN
+
switch (response.resultClass) {
case GdbResultDone:
case GdbResultRunning:
-#ifdef Q_OS_WIN
- // Resume thread that was suspended by console stub process (see stub code).
- if (winResumeThread(m_stubProc.applicationMainThreadID(), &errorMessage)) {
- showMessage(QString::fromLatin1("Inferior attached, thread %1 resumed").
- arg(m_stubProc.applicationMainThreadID()), LogMisc);
+ if (startParameters().toolChainAbi.os() != ProjectExplorer::Abi::WindowsOS) {
+ showMessage(_("INFERIOR ATTACHED"));
} else {
- showMessage(QString::fromLatin1("Inferior attached, unable to resume thread %1: %2").
- arg(m_stubProc.applicationMainThreadID()).arg(errorMessage),
- LogWarning);
- }
+ QString errorMessage;
+ // Resume thread that was suspended by console stub process (see stub code).
+#ifdef Q_OS_WIN
+ const qint64 mainThreadId = m_stubProc.applicationMainThreadID();
#else
- showMessage(_("INFERIOR ATTACHED"));
-#endif // Q_OS_WIN
+ const qint64 mainThreadId = -1;
+#endif
+ if (winResumeThread(mainThreadId, &errorMessage)) {
+ showMessage(QString::fromLatin1("Inferior attached, thread %1 resumed").
+ arg(mainThreadId), LogMisc);
+ } else {
+ showMessage(QString::fromLatin1("Inferior attached, unable to resume thread %1: %2").
+ arg(mainThreadId).arg(errorMessage),
+ LogWarning);
+ }
+ }
handleInferiorPrepared();
break;
case GdbResultError: