2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
#include "gdbengine.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/debuggerinternalconstants.h>
|
2014-10-17 13:40:04 +02:00
|
|
|
#include <debugger/debuggerruncontrol.h>
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/disassemblerlines.h>
|
|
|
|
|
|
|
|
|
|
#include <debugger/debuggeractions.h>
|
|
|
|
|
#include <debugger/debuggercore.h>
|
|
|
|
|
#include <debugger/debuggermainwindow.h>
|
|
|
|
|
#include <debugger/debuggerplugin.h>
|
|
|
|
|
#include <debugger/debuggerprotocol.h>
|
|
|
|
|
#include <debugger/debuggertooltipmanager.h>
|
|
|
|
|
#include <debugger/disassembleragent.h>
|
|
|
|
|
#include <debugger/memoryagent.h>
|
|
|
|
|
#include <debugger/sourceutils.h>
|
2015-01-26 11:47:51 +01:00
|
|
|
#include <debugger/terminal.h>
|
2013-08-29 16:36:42 +02:00
|
|
|
|
|
|
|
|
#include <debugger/breakhandler.h>
|
|
|
|
|
#include <debugger/moduleshandler.h>
|
|
|
|
|
#include <debugger/registerhandler.h>
|
|
|
|
|
#include <debugger/sourcefileshandler.h>
|
|
|
|
|
#include <debugger/stackhandler.h>
|
|
|
|
|
#include <debugger/threadshandler.h>
|
|
|
|
|
#include <debugger/debuggersourcepathmappingwidget.h>
|
|
|
|
|
#include <debugger/logwindow.h>
|
|
|
|
|
#include <debugger/procinterrupt.h>
|
|
|
|
|
#include <debugger/shared/hostutils.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-04-08 17:25:28 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2014-11-25 13:08:18 +01:00
|
|
|
#include <coreplugin/messagebox.h>
|
2015-03-06 13:36:42 +01:00
|
|
|
|
2013-11-04 09:47:34 +01:00
|
|
|
#include <projectexplorer/devicesupport/deviceprocess.h>
|
2017-04-11 13:45:37 +02:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
2013-11-04 09:47:34 +01:00
|
|
|
#include <projectexplorer/taskhub.h>
|
2014-10-13 18:49:44 +02:00
|
|
|
|
2017-08-29 11:48:48 +02:00
|
|
|
#include <app/app_version.h>
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2012-08-23 15:53:58 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2012-06-13 10:15:56 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
2012-08-13 17:39:29 +02:00
|
|
|
#include <utils/savedaction.h>
|
2017-09-08 08:53:15 +02:00
|
|
|
#include <utils/synchronousprocess.h>
|
2017-01-19 16:44:22 +01:00
|
|
|
#include <utils/temporaryfile.h>
|
2008-12-09 16:18:28 +01:00
|
|
|
|
2012-03-23 17:53:30 +01:00
|
|
|
#include <QDirIterator>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QMessageBox>
|
2015-06-08 12:10:11 +02:00
|
|
|
#include <QProcess>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QPushButton>
|
2018-08-03 15:49:06 +03:00
|
|
|
#include <QRegularExpression>
|
2015-09-14 13:40:35 +02:00
|
|
|
#include <QJsonArray>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-06-05 14:15:54 +02:00
|
|
|
using namespace Core;
|
2011-02-23 16:47:08 +01:00
|
|
|
using namespace ProjectExplorer;
|
2012-06-04 18:06:59 +02:00
|
|
|
using namespace Utils;
|
2011-02-23 16:47:08 +01:00
|
|
|
|
2009-08-18 08:34:48 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-01-25 10:59:45 +01:00
|
|
|
enum { debugPending = 0 };
|
|
|
|
|
|
|
|
|
|
#define PENDING_DEBUG(s) do { if (debugPending) qDebug() << s; } while (0)
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-02-05 22:46:09 +01:00
|
|
|
#define CB(callback) [this](const DebuggerResponse &r) { callback(r); }
|
2013-11-27 16:10:14 +01:00
|
|
|
|
2015-09-11 16:51:11 +02:00
|
|
|
#define CHECK_STATE(s) do { checkState(s, __FILE__, __LINE__); } while (0)
|
2015-02-24 15:30:42 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
static int ¤tToken()
|
|
|
|
|
{
|
|
|
|
|
static int token = 0;
|
|
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-13 11:22:28 +02:00
|
|
|
static bool isMostlyHarmlessMessage(const QStringRef &msg)
|
2015-03-05 12:50:57 +01:00
|
|
|
{
|
|
|
|
|
return msg == "warning: GDB: Failed to set controlling terminal: "
|
|
|
|
|
"Inappropriate ioctl for device\\n"
|
2016-06-13 11:22:28 +02:00
|
|
|
|| msg == "warning: GDB: Failed to set controlling terminal: "
|
|
|
|
|
"Invalid argument\\n";
|
2015-03-05 12:50:57 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// GdbEngine
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2017-09-26 15:22:14 +02:00
|
|
|
GdbEngine::GdbEngine()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
setObjectName("GdbEngine");
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
setDebuggerName("GDB");
|
2010-07-21 11:05:40 +02:00
|
|
|
|
2016-06-13 11:22:28 +02:00
|
|
|
m_gdbOutputCodec = QTextCodec::codecForLocale();
|
|
|
|
|
m_inferiorOutputCodec = QTextCodec::codecForLocale();
|
2011-02-10 13:43:02 +01:00
|
|
|
|
2010-11-16 12:52:02 +01:00
|
|
|
m_commandTimer.setSingleShot(true);
|
2015-02-12 13:50:54 +01:00
|
|
|
connect(&m_commandTimer, &QTimer::timeout,
|
|
|
|
|
this, &GdbEngine::commandTimeout);
|
|
|
|
|
|
|
|
|
|
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
|
|
|
|
|
this, &GdbEngine::reloadLocals);
|
|
|
|
|
connect(action(CreateFullBacktrace), &QAction::triggered,
|
|
|
|
|
this, &GdbEngine::createFullBacktrace);
|
|
|
|
|
connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
|
|
|
|
|
this, &GdbEngine::reloadLocals);
|
|
|
|
|
connect(action(UseDynamicType), &SavedAction::valueChanged,
|
|
|
|
|
this, &GdbEngine::reloadLocals);
|
2017-09-08 08:53:15 +02:00
|
|
|
|
2017-10-27 13:31:57 +02:00
|
|
|
connect(&m_gdbProc, &QProcess::errorOccurred,
|
|
|
|
|
this, &GdbEngine::handleGdbError);
|
2019-02-26 09:40:49 +01:00
|
|
|
connect(&m_gdbProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
2017-10-27 13:31:57 +02:00
|
|
|
this, &GdbEngine::handleGdbFinished);
|
|
|
|
|
connect(&m_gdbProc, &QtcProcess::readyReadStandardOutput,
|
|
|
|
|
this, &GdbEngine::readGdbStandardOutput);
|
|
|
|
|
connect(&m_gdbProc, &QtcProcess::readyReadStandardError,
|
|
|
|
|
this, &GdbEngine::readGdbStandardError);
|
|
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
// Output
|
|
|
|
|
connect(&m_outputCollector, &OutputCollector::byteDelivery,
|
|
|
|
|
this, &GdbEngine::readDebuggeeOutput);
|
2010-05-05 12:49:08 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
GdbEngine::~GdbEngine()
|
|
|
|
|
{
|
2010-03-11 11:07:16 +01:00
|
|
|
// Prevent sending error messages afterwards.
|
2012-06-13 10:15:56 +02:00
|
|
|
disconnect();
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 15:55:15 +02:00
|
|
|
QString GdbEngine::failedToStartMessage()
|
|
|
|
|
{
|
|
|
|
|
return tr("The gdb process failed to start.");
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-21 16:42:57 +01:00
|
|
|
// Parse "~:gdb: unknown target exception 0xc0000139 at 0x77bef04e\n"
|
|
|
|
|
// and return an exception message
|
2018-02-01 10:59:24 +01:00
|
|
|
static QString msgWinException(const QString &data, unsigned *exCodeIn = nullptr)
|
2011-01-21 16:42:57 +01:00
|
|
|
{
|
2012-11-02 16:14:43 +01:00
|
|
|
if (exCodeIn)
|
|
|
|
|
*exCodeIn = 0;
|
2011-01-21 16:42:57 +01:00
|
|
|
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.");
|
2019-01-17 01:38:54 +01:00
|
|
|
const unsigned exCode = data.midRef(exCodePos, blankPos - exCodePos).toUInt(nullptr, 0);
|
2012-11-02 16:14:43 +01:00
|
|
|
if (exCodeIn)
|
|
|
|
|
*exCodeIn = exCode;
|
2018-07-23 22:28:49 +02:00
|
|
|
const quint64 address = data.mid(addressPos).trimmed().toULongLong(nullptr, 0);
|
2011-01-21 16:42:57 +01:00
|
|
|
QString rc;
|
|
|
|
|
QTextStream str(&rc);
|
2013-10-17 14:52:10 +02:00
|
|
|
str << GdbEngine::tr("An exception was triggered:") << ' ';
|
2011-01-21 16:42:57 +01:00
|
|
|
formatWindowsException(exCode, address, 0, 0, 0, str);
|
|
|
|
|
str << '.';
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static bool isNameChar(int c)
|
2011-04-08 15:38:50 +02:00
|
|
|
{
|
|
|
|
|
// could be 'stopped' or 'shlibs-added'
|
|
|
|
|
return (c >= 'a' && c <= 'z') || c == '-';
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static bool contains(const QString &message, const QString &pattern, int size)
|
2012-05-30 12:12:29 +02:00
|
|
|
{
|
|
|
|
|
const int s = message.size();
|
|
|
|
|
if (s < size)
|
|
|
|
|
return false;
|
|
|
|
|
const int pos = message.indexOf(pattern);
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
return false;
|
2012-06-13 10:15:56 +02:00
|
|
|
const bool beginFits = pos == 0 || message.at(pos - 1) == '\n';
|
|
|
|
|
const bool endFits = pos + size == s || message.at(pos + size) == '\n';
|
|
|
|
|
return beginFits && endFits;
|
2012-05-30 12:12:29 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static bool isGdbConnectionError(const QString &message)
|
2012-05-07 14:29:22 +02:00
|
|
|
{
|
|
|
|
|
// Handle messages gdb client produces when the target exits (gdbserver)
|
|
|
|
|
//
|
|
|
|
|
// we get this as response either to a specific command, e.g.
|
|
|
|
|
// 31^error,msg="Remote connection closed"
|
|
|
|
|
// or as informative output:
|
|
|
|
|
// &Remote connection closed
|
2012-05-30 12:12:29 +02:00
|
|
|
|
|
|
|
|
const char msg1[] = "Remote connection closed";
|
|
|
|
|
const char msg2[] = "Remote communication error. Target disconnected.: No error.";
|
|
|
|
|
const char msg3[] = "Quit";
|
|
|
|
|
|
|
|
|
|
return contains(message, msg1, sizeof(msg1) - 1)
|
|
|
|
|
|| contains(message, msg2, sizeof(msg2) - 1)
|
|
|
|
|
|| contains(message, msg3, sizeof(msg3) - 1);
|
2012-05-07 14:29:22 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void GdbEngine::handleResponse(const QString &buff)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(buff, LogOutput);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
if (buff.isEmpty() || buff == "(gdb) ")
|
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const QChar *from = buff.constData();
|
|
|
|
|
const QChar *to = from + buff.size();
|
|
|
|
|
const QChar *inner;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
int token = -1;
|
2011-06-06 18:17:51 +02:00
|
|
|
// Token is a sequence of numbers.
|
2009-02-24 20:34:30 +01:00
|
|
|
for (inner = from; inner != to; ++inner)
|
|
|
|
|
if (*inner < '0' || *inner > '9')
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
2009-02-24 20:34:30 +01:00
|
|
|
if (from != inner) {
|
2016-06-07 17:04:53 +02:00
|
|
|
token = QString(from, inner - from).toInt();
|
2009-02-24 20:34:30 +01:00
|
|
|
from = inner;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-06-06 18:17:51 +02:00
|
|
|
// Next char decides kind of response.
|
2016-06-07 17:04:53 +02:00
|
|
|
const QChar c = *from++;
|
|
|
|
|
switch (c.unicode()) {
|
2009-02-24 20:34:30 +01:00
|
|
|
case '*':
|
|
|
|
|
case '+':
|
|
|
|
|
case '=': {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString asyncClass;
|
2009-02-24 20:34:30 +01:00
|
|
|
for (; from != to; ++from) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QChar c = *from;
|
|
|
|
|
if (!isNameChar(c.unicode()))
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
|
|
|
|
asyncClass += *from;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-09-24 11:16:00 +02:00
|
|
|
GdbMi result;
|
2009-02-24 20:34:30 +01:00
|
|
|
while (from != to) {
|
|
|
|
|
GdbMi data;
|
2009-04-07 14:14:43 +02:00
|
|
|
if (*from != ',') {
|
2010-01-29 21:33:57 +01:00
|
|
|
// happens on archer where we get
|
|
|
|
|
// 23^running <NL> *running,thread-id="all" <NL> (gdb)
|
2009-09-24 11:16:00 +02:00
|
|
|
result.m_type = GdbMi::Tuple;
|
2009-04-07 14:14:43 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++from; // skip ','
|
|
|
|
|
data.parseResultOrValue(from, to);
|
|
|
|
|
if (data.isValid()) {
|
2009-09-24 11:16:00 +02:00
|
|
|
//qDebug() << "parsed result:" << data.toString();
|
2018-09-25 18:48:29 +02:00
|
|
|
result.addChild(data);
|
2009-09-24 11:16:00 +02:00
|
|
|
result.m_type = GdbMi::Tuple;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-14 13:26:22 +02:00
|
|
|
handleAsyncOutput(asyncClass, result);
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2009-02-12 13:31:19 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
case '~': {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString data = GdbMi::parseCString(from, to);
|
2015-10-08 16:19:57 +02:00
|
|
|
if (data.startsWith("bridgemessage={")) {
|
2015-10-14 13:26:22 +02:00
|
|
|
// It's already logged.
|
2015-10-08 16:19:57 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-10-14 13:26:22 +02:00
|
|
|
if (data.startsWith("interpreterresult={")) {
|
|
|
|
|
GdbMi allData;
|
|
|
|
|
allData.fromStringMultiple(data);
|
2015-10-08 16:19:57 +02:00
|
|
|
DebuggerResponse response;
|
|
|
|
|
response.resultClass = ResultDone;
|
2015-10-14 13:26:22 +02:00
|
|
|
response.data = allData["interpreterresult"];
|
|
|
|
|
response.token = allData["token"].toInt();
|
2015-10-08 16:19:57 +02:00
|
|
|
handleResultRecord(&response);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-10-14 13:26:22 +02:00
|
|
|
if (data.startsWith("interpreterasync={")) {
|
|
|
|
|
GdbMi allData;
|
|
|
|
|
allData.fromStringMultiple(data);
|
2016-06-07 17:04:53 +02:00
|
|
|
QString asyncClass = allData["asyncclass"].data();
|
2015-10-14 13:26:22 +02:00
|
|
|
if (asyncClass == "breakpointmodified")
|
|
|
|
|
handleInterpreterBreakpointModified(allData["interpreterasync"]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-03-03 09:31:13 +01:00
|
|
|
m_pendingConsoleStreamOutput += data;
|
2009-09-23 12:12:36 +02:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
// Fragile, but it's all we have.
|
|
|
|
|
if (data.contains("\nNo more reverse-execution history.\n"))
|
|
|
|
|
handleBeginOfRecordingReached();
|
|
|
|
|
|
2009-09-23 12:12:36 +02:00
|
|
|
// Show some messages to give the impression something happens.
|
2009-10-22 20:04:59 +02:00
|
|
|
if (data.startsWith("Reading symbols from ")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showStatusMessage(tr("Reading %1...").arg(data.mid(21)), 1000);
|
2010-07-22 12:02:09 +02:00
|
|
|
progressPing();
|
2009-10-22 20:04:59 +02:00
|
|
|
} else if (data.startsWith("[New ") || data.startsWith("[Thread ")) {
|
|
|
|
|
if (data.endsWith('\n'))
|
|
|
|
|
data.chop(1);
|
2010-07-22 12:02:09 +02:00
|
|
|
progressPing();
|
2016-06-07 17:04:53 +02:00
|
|
|
showStatusMessage(data, 1000);
|
2011-01-21 16:42:57 +01:00
|
|
|
} else if (data.startsWith("gdb: unknown target exception 0x")) {
|
|
|
|
|
// [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
|
2012-11-02 16:14:43 +01:00
|
|
|
unsigned exCode;
|
|
|
|
|
m_lastWinException = msgWinException(data, &exCode);
|
2011-01-21 16:42:57 +01:00
|
|
|
showMessage(m_lastWinException, LogMisc);
|
2012-11-02 16:14:43 +01:00
|
|
|
const Task::TaskType type = isFatalWinException(exCode) ? Task::Error : Task::Warning;
|
2013-08-29 18:25:59 +02:00
|
|
|
TaskHub::addTask(type, m_lastWinException, Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
|
2009-10-22 20:04:59 +02:00
|
|
|
}
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2009-02-12 13:31:19 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
case '@': {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString data = GdbMi::parseCString(from, to);
|
2017-07-03 17:17:08 +10:00
|
|
|
QString msg = data.left(data.size() - 1);
|
2016-06-13 11:22:28 +02:00
|
|
|
showMessage(msg, AppOutput);
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
case '&': {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString data = GdbMi::parseCString(from, to);
|
2009-02-24 20:34:30 +01:00
|
|
|
// On Windows, the contents seem to depend on the debugger
|
|
|
|
|
// version and/or OS version used.
|
2016-06-13 11:22:28 +02:00
|
|
|
if (data.startsWith("warning:"))
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(data.mid(9), AppStuff); // Cut "warning: "
|
2015-03-05 12:50:57 +01:00
|
|
|
|
|
|
|
|
m_pendingLogStreamOutput += data;
|
2012-03-21 16:13:01 +01:00
|
|
|
|
2012-05-07 14:29:22 +02:00
|
|
|
if (isGdbConnectionError(data)) {
|
2012-03-21 16:13:01 +01:00
|
|
|
notifyInferiorExited();
|
2012-05-07 14:29:22 +02:00
|
|
|
break;
|
2012-03-21 16:13:01 +01:00
|
|
|
}
|
2012-03-30 17:36:44 +02:00
|
|
|
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(IdentifyDebugInfoPackages)) {
|
2013-03-21 18:00:18 +01:00
|
|
|
// From SuSE's gdb: >&"Missing separate debuginfo for ...\n"
|
|
|
|
|
// ">&"Try: zypper install -C \"debuginfo(build-id)=c084ee5876ed1ac12730181c9f07c3e027d8e943\"\n"
|
|
|
|
|
if (data.startsWith("Missing separate debuginfo for ")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
m_lastMissingDebugInfo = data.mid(32);
|
2013-03-21 18:00:18 +01:00
|
|
|
} else if (data.startsWith("Try: zypper")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString cmd = data.mid(4);
|
2013-03-21 18:00:18 +01:00
|
|
|
|
|
|
|
|
Task task(Task::Warning,
|
|
|
|
|
tr("Missing debug information for %1\nTry: %2")
|
|
|
|
|
.arg(m_lastMissingDebugInfo).arg(cmd),
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath(), 0, Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
|
2013-03-21 18:00:18 +01:00
|
|
|
|
2013-08-19 12:04:51 +02:00
|
|
|
TaskHub::addTask(task);
|
2018-03-07 15:31:08 +01:00
|
|
|
Internal::addDebugInfoTask(task.taskId, cmd);
|
2013-03-21 18:00:18 +01:00
|
|
|
}
|
2012-03-30 17:36:44 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
case '^': {
|
2015-02-05 15:47:07 +01:00
|
|
|
DebuggerResponse response;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-09-24 11:16:00 +02:00
|
|
|
response.token = token;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
for (inner = from; inner != to; ++inner)
|
|
|
|
|
if (*inner < 'a' || *inner > 'z')
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
QString resultClass = QString::fromRawData(from, inner - from);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (resultClass == "done")
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultDone;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (resultClass == "running")
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultRunning;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (resultClass == "connected")
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultConnected;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (resultClass == "error")
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultError;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (resultClass == "exit")
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultExit;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2015-02-05 15:47:07 +01:00
|
|
|
response.resultClass = ResultUnknown;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
from = inner;
|
|
|
|
|
if (from != to) {
|
2009-04-07 09:51:21 +02:00
|
|
|
if (*from == ',') {
|
|
|
|
|
++from;
|
2009-09-24 11:16:00 +02:00
|
|
|
response.data.parseTuple_helper(from, to);
|
|
|
|
|
response.data.m_type = GdbMi::Tuple;
|
|
|
|
|
response.data.m_name = "data";
|
2009-04-07 09:51:21 +02:00
|
|
|
} else {
|
2010-11-30 12:47:53 +01:00
|
|
|
// Archer has this.
|
2009-09-24 11:16:00 +02:00
|
|
|
response.data.m_type = GdbMi::Tuple;
|
|
|
|
|
response.data.m_name = "data";
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2009-02-24 20:34:30 +01:00
|
|
|
|
2011-07-05 17:57:57 +02:00
|
|
|
response.logStreamOutput = m_pendingLogStreamOutput;
|
|
|
|
|
response.consoleStreamOutput = m_pendingConsoleStreamOutput;
|
2009-02-24 20:34:30 +01:00
|
|
|
m_pendingLogStreamOutput.clear();
|
|
|
|
|
m_pendingConsoleStreamOutput.clear();
|
|
|
|
|
|
2016-12-15 18:28:58 +01:00
|
|
|
if (response.data.data().isEmpty())
|
|
|
|
|
response.data.fromString(response.consoleStreamOutput);
|
|
|
|
|
|
2009-10-23 21:32:08 +02:00
|
|
|
handleResultRecord(&response);
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
2012-02-07 14:07:21 +01:00
|
|
|
qDebug() << "UNKNOWN RESPONSE TYPE '" << c << "'. REST: " << from;
|
2009-02-24 20:34:30 +01:00
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result)
|
2015-10-14 13:26:22 +02:00
|
|
|
{
|
|
|
|
|
if (asyncClass == "stopped") {
|
|
|
|
|
if (m_inUpdateLocals) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("UNEXPECTED *stopped NOTIFICATION IGNORED", LogWarning);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else {
|
|
|
|
|
handleStopResponse(result);
|
|
|
|
|
m_pendingLogStreamOutput.clear();
|
|
|
|
|
m_pendingConsoleStreamOutput.clear();
|
|
|
|
|
}
|
|
|
|
|
} else if (asyncClass == "running") {
|
|
|
|
|
if (m_inUpdateLocals) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("UNEXPECTED *running NOTIFICATION IGNORED", LogWarning);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else {
|
|
|
|
|
GdbMi threads = result["thread-id"];
|
|
|
|
|
threadsHandler()->notifyRunning(threads.data());
|
2015-12-06 11:25:06 +02:00
|
|
|
if (runParameters().toolChainAbi.os() == Abi::WindowsOS) {
|
|
|
|
|
// NOTE: Each created thread spits out a *running message. We completely ignore them
|
|
|
|
|
// on Windows, and handle only numbered responses
|
|
|
|
|
|
2015-10-14 13:26:22 +02:00
|
|
|
// FIXME: Breakpoints on Windows are exceptions which are thrown in newly
|
|
|
|
|
// created threads so we have to filter out the running threads messages when
|
|
|
|
|
// we request a stop.
|
2017-11-15 17:12:03 +01:00
|
|
|
} else if (state() == InferiorRunOk || state() == EngineSetupRequested) {
|
2015-12-06 11:25:06 +02:00
|
|
|
// We get multiple *running after thread creation and in Windows terminals.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("NOTE: INFERIOR STILL RUNNING IN STATE %1.").
|
|
|
|
|
arg(DebuggerEngine::stateName(state())));
|
2015-10-14 13:26:22 +02:00
|
|
|
} else {
|
|
|
|
|
notifyInferiorRunOk();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (asyncClass == "library-loaded") {
|
|
|
|
|
// Archer has 'id="/usr/lib/libdrm.so.2",
|
|
|
|
|
// target-name="/usr/lib/libdrm.so.2",
|
|
|
|
|
// host-name="/usr/lib/libdrm.so.2",
|
|
|
|
|
// symbols-loaded="0"
|
|
|
|
|
|
|
|
|
|
// id="/lib/i386-linux-gnu/libc.so.6"
|
|
|
|
|
// target-name="/lib/i386-linux-gnu/libc.so.6"
|
|
|
|
|
// host-name="/lib/i386-linux-gnu/libc.so.6"
|
|
|
|
|
// symbols-loaded="0",thread-group="i1"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2015-10-14 13:26:22 +02:00
|
|
|
if (!id.isEmpty())
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Library %1 loaded.").arg(id), 1000);
|
2015-10-14 13:26:22 +02:00
|
|
|
progressPing();
|
|
|
|
|
Module module;
|
|
|
|
|
module.startAddress = 0;
|
|
|
|
|
module.endAddress = 0;
|
2016-06-07 17:04:53 +02:00
|
|
|
module.hostPath = result["host-name"].data();
|
|
|
|
|
module.modulePath = result["target-name"].data();
|
2015-10-14 13:26:22 +02:00
|
|
|
module.moduleName = QFileInfo(module.hostPath).baseName();
|
|
|
|
|
modulesHandler()->updateModule(module);
|
|
|
|
|
} else if (asyncClass == "library-unloaded") {
|
|
|
|
|
// Archer has 'id="/usr/lib/libdrm.so.2",
|
|
|
|
|
// target-name="/usr/lib/libdrm.so.2",
|
|
|
|
|
// host-name="/usr/lib/libdrm.so.2"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2018-08-24 12:48:20 +02:00
|
|
|
modulesHandler()->removeModule(result["target-name"].data());
|
2015-10-14 13:26:22 +02:00
|
|
|
progressPing();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Library %1 unloaded.").arg(id), 1000);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else if (asyncClass == "thread-group-added") {
|
|
|
|
|
// 7.1-symbianelf has "{id="i1"}"
|
2017-02-27 17:19:00 +01:00
|
|
|
} else if (asyncClass == "thread-group-started") {
|
2015-10-14 13:26:22 +02:00
|
|
|
// Archer had only "{id="28902"}" at some point of 6.8.x.
|
|
|
|
|
// *-started seems to be standard in 7.1, but in early
|
|
|
|
|
// 7.0.x, there was a *-created instead.
|
|
|
|
|
progressPing();
|
|
|
|
|
// 7.1.50 has thread-group-started,id="i1",pid="3529"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Thread group %1 created.").arg(id), 1000);
|
2017-03-01 09:35:28 +01:00
|
|
|
notifyInferiorPid(result["pid"].toProcessHandle());
|
2015-10-14 13:26:22 +02:00
|
|
|
handleThreadGroupCreated(result);
|
|
|
|
|
} else if (asyncClass == "thread-created") {
|
|
|
|
|
//"{id="1",group-id="28902"}"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Thread %1 created.").arg(id), 1000);
|
2015-10-14 13:26:22 +02:00
|
|
|
ThreadData thread;
|
2018-08-15 17:28:00 +02:00
|
|
|
thread.id = id;
|
2015-10-14 13:26:22 +02:00
|
|
|
thread.groupId = result["group-id"].data();
|
|
|
|
|
threadsHandler()->updateThread(thread);
|
|
|
|
|
} else if (asyncClass == "thread-group-exited") {
|
|
|
|
|
// Archer has "{id="28902"}"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Thread group %1 exited.").arg(id), 1000);
|
2015-10-14 13:26:22 +02:00
|
|
|
handleThreadGroupExited(result);
|
|
|
|
|
} else if (asyncClass == "thread-exited") {
|
|
|
|
|
//"{id="1",group-id="28902"}"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
|
|
|
|
QString groupid = result["group-id"].data();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Thread %1 in group %2 exited.")
|
2016-06-07 17:04:53 +02:00
|
|
|
.arg(id).arg(groupid), 1000);
|
2018-08-15 17:28:00 +02:00
|
|
|
threadsHandler()->removeThread(id);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else if (asyncClass == "thread-selected") {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString id = result["id"].data();
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Thread %1 selected.").arg(id), 1000);
|
2015-10-14 13:26:22 +02:00
|
|
|
//"{id="2"}"
|
|
|
|
|
} else if (asyncClass == "breakpoint-modified") {
|
|
|
|
|
// New in FSF gdb since 2011-04-27.
|
|
|
|
|
// "{bkpt={number="3",type="breakpoint",disp="keep",
|
|
|
|
|
// enabled="y",addr="<MULTIPLE>",times="1",
|
|
|
|
|
// original-location="\\",simple_gdbtest_app.cpp\\":135"},
|
|
|
|
|
// {number="3.1",enabled="y",addr="0x0805ff68",
|
|
|
|
|
// func="Vector<int>::Vector(int)",
|
|
|
|
|
// file="simple_gdbtest_app.cpp",
|
|
|
|
|
// fullname="/data/...line="135"},{number="3.2"...}}.."
|
|
|
|
|
|
|
|
|
|
// Note the leading comma in original-location. Filter it out.
|
|
|
|
|
// We don't need the field anyway.
|
2016-06-07 17:04:53 +02:00
|
|
|
QString ba = result.toString();
|
2015-10-14 13:26:22 +02:00
|
|
|
ba = '[' + ba.mid(6, ba.size() - 7) + ']';
|
|
|
|
|
const int pos1 = ba.indexOf(",original-location");
|
|
|
|
|
const int pos2 = ba.indexOf("\":", pos1 + 2);
|
|
|
|
|
const int pos3 = ba.indexOf('"', pos2 + 2);
|
|
|
|
|
ba.remove(pos1, pos3 - pos1 + 1);
|
|
|
|
|
GdbMi res;
|
|
|
|
|
res.fromString(ba);
|
|
|
|
|
BreakHandler *handler = breakHandler();
|
|
|
|
|
Breakpoint bp;
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &bkpt : res) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString nr = bkpt["number"].data();
|
2015-11-02 16:01:43 +01:00
|
|
|
if (nr.contains('.')) {
|
|
|
|
|
// A sub-breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, continue);
|
|
|
|
|
SubBreakpoint loc = bp->findOrCreateSubBreakpoint(nr);
|
|
|
|
|
loc->params.updateFromGdbOutput(bkpt);
|
|
|
|
|
loc->params.type = bp->type();
|
2015-11-02 16:01:43 +01:00
|
|
|
} else {
|
|
|
|
|
// A primary breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp = handler->findBreakpointByResponseId(nr);
|
|
|
|
|
if (bp)
|
|
|
|
|
bp->updateFromGdbOutput(bkpt);
|
2015-10-14 13:26:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (bp)
|
|
|
|
|
bp->adjustMarker();
|
2015-10-14 13:26:22 +02:00
|
|
|
} else if (asyncClass == "breakpoint-created") {
|
|
|
|
|
// "{bkpt={number="1",type="breakpoint",disp="del",enabled="y",
|
|
|
|
|
// addr="<PENDING>",pending="main",times="0",
|
|
|
|
|
// original-location="main"}}" -- or --
|
|
|
|
|
// {bkpt={number="2",type="hw watchpoint",disp="keep",enabled="y",
|
|
|
|
|
// what="*0xbfffed48",times="0",original-location="*0xbfffed48"}}
|
|
|
|
|
BreakHandler *handler = breakHandler();
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &bkpt : result) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString nr = bkpt["number"].data();
|
|
|
|
|
BreakpointParameters br;
|
2015-10-14 13:26:22 +02:00
|
|
|
br.type = BreakpointByFileAndLine;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
br.updateFromGdbOutput(bkpt);
|
|
|
|
|
handler->handleAlienBreakpoint(nr, br);
|
2015-10-14 13:26:22 +02:00
|
|
|
}
|
|
|
|
|
} else if (asyncClass == "breakpoint-deleted") {
|
|
|
|
|
// "breakpoint-deleted" "{id="1"}"
|
|
|
|
|
// New in FSF gdb since 2011-04-27.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString nr = result["id"].data();
|
|
|
|
|
// This also triggers when a temporary breakpoint is hit.
|
|
|
|
|
// We do not really want that, as this loses all information.
|
|
|
|
|
// FIXME: Use a special marker for this case?
|
|
|
|
|
// if (!bp.isOneShot()) ... is not sufficient.
|
|
|
|
|
// It keeps temporary "Jump" breakpoints alive.
|
|
|
|
|
breakHandler()->removeAlienBreakpoint(nr);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else if (asyncClass == "cmd-param-changed") {
|
|
|
|
|
// New since 2012-08-09
|
|
|
|
|
// "{param="debug remote",value="1"}"
|
|
|
|
|
} else if (asyncClass == "memory-changed") {
|
|
|
|
|
// New since 2013
|
|
|
|
|
// "{thread-group="i1",addr="0x0918a7a8",len="0x10"}"
|
|
|
|
|
} else if (asyncClass == "tsv-created") {
|
|
|
|
|
// New since 2013-02-06
|
|
|
|
|
} else if (asyncClass == "tsv-modified") {
|
|
|
|
|
// New since 2013-02-06
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "IGNORED ASYNC OUTPUT"
|
|
|
|
|
<< asyncClass << result.toString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void GdbEngine::readGdbStandardError()
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString err = QString::fromUtf8(m_gdbProc.readAllStandardError());
|
|
|
|
|
showMessage("UNEXPECTED GDB STDERR: " + err);
|
2009-10-30 18:18:21 +01:00
|
|
|
if (err == "Undefined command: \"bb\". Try \"help\".\n")
|
|
|
|
|
return;
|
2010-03-29 16:45:34 +02:00
|
|
|
if (err.startsWith("BFD: reopening"))
|
|
|
|
|
return;
|
2011-03-30 15:58:58 +02:00
|
|
|
qWarning() << "Unexpected GDB stderr:" << err;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void GdbEngine::readDebuggeeOutput(const QByteArray &ba)
|
|
|
|
|
{
|
2016-06-13 11:22:28 +02:00
|
|
|
const QString msg = m_inferiorOutputCodec->toUnicode(ba.constData(), ba.size(),
|
|
|
|
|
&m_inferiorOutputCodecState);
|
|
|
|
|
|
|
|
|
|
if (msg.startsWith("&\"") && isMostlyHarmlessMessage(msg.midRef(2, msg.size() - 4)))
|
|
|
|
|
showMessage("Mostly harmless terminal warning suppressed.", LogWarning);
|
|
|
|
|
else
|
|
|
|
|
showMessage(msg, AppStuff);
|
2016-06-07 17:04:53 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void GdbEngine::readGdbStandardOutput()
|
|
|
|
|
{
|
2010-11-16 12:42:57 +01:00
|
|
|
m_commandTimer.start(); // Restart timer.
|
2009-11-03 14:56:27 +01:00
|
|
|
|
2009-02-24 22:36:36 +01:00
|
|
|
int newstart = 0;
|
|
|
|
|
int scan = m_inbuffer.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-06-08 12:10:11 +02:00
|
|
|
QByteArray out = m_gdbProc.readAllStandardOutput();
|
2012-05-18 02:28:41 +02:00
|
|
|
m_inbuffer.append(out);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-11-16 12:42:57 +01:00
|
|
|
// This can trigger when a dialog starts a nested event loop.
|
2009-10-27 12:05:03 +01:00
|
|
|
if (m_busy)
|
|
|
|
|
return;
|
|
|
|
|
|
2009-02-24 20:34:30 +01:00
|
|
|
while (newstart < m_inbuffer.size()) {
|
|
|
|
|
int start = newstart;
|
2009-02-24 22:36:36 +01:00
|
|
|
int end = m_inbuffer.indexOf('\n', scan);
|
2009-02-24 20:34:30 +01:00
|
|
|
if (end < 0) {
|
|
|
|
|
m_inbuffer.remove(0, start);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
newstart = end + 1;
|
2009-02-24 22:36:36 +01:00
|
|
|
scan = newstart;
|
2009-02-24 20:34:30 +01:00
|
|
|
if (end == start)
|
|
|
|
|
continue;
|
|
|
|
|
if (m_inbuffer.at(end - 1) == '\r') {
|
|
|
|
|
--end;
|
|
|
|
|
if (end == start)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2009-10-27 12:05:03 +01:00
|
|
|
m_busy = true;
|
2016-06-07 17:04:53 +02:00
|
|
|
|
2016-06-13 11:22:28 +02:00
|
|
|
QString msg = m_gdbOutputCodec->toUnicode(m_inbuffer.constData() + start, end - start,
|
|
|
|
|
&m_gdbOutputCodecState);
|
2016-06-07 17:04:53 +02:00
|
|
|
|
|
|
|
|
handleResponse(msg);
|
2009-10-27 12:05:03 +01:00
|
|
|
m_busy = false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-02-24 21:50:20 +01:00
|
|
|
m_inbuffer.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::interruptInferior()
|
|
|
|
|
{
|
2017-09-08 08:53:15 +02:00
|
|
|
// A core never runs, so this cannot be called.
|
|
|
|
|
QTC_ASSERT(!isCoreEngine(), return);
|
|
|
|
|
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopRequested);
|
2011-02-03 16:49:28 +01:00
|
|
|
|
2012-03-09 15:04:59 +01:00
|
|
|
if (usesExecInterrupt()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"-exec-interrupt"});
|
2011-02-03 16:49:28 +01:00
|
|
|
} else {
|
|
|
|
|
showStatusMessage(tr("Stop requested..."), 5000);
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("TRYING TO INTERRUPT INFERIOR");
|
2014-06-05 14:15:54 +02:00
|
|
|
if (HostOsInfo::isWindowsHost() && !m_isQnxGdb) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
IDevice::ConstPtr dev = device();
|
|
|
|
|
QTC_ASSERT(dev, notifyInferiorStopFailed(); return);
|
|
|
|
|
DeviceProcessSignalOperation::Ptr signalOperation = dev->signalOperation();
|
2017-08-17 10:37:05 +02:00
|
|
|
QTC_ASSERT(signalOperation, notifyInferiorStopFailed(); return);
|
|
|
|
|
connect(signalOperation.data(), &DeviceProcessSignalOperation::finished,
|
|
|
|
|
this, [this, signalOperation](const QString &error) {
|
|
|
|
|
if (error.isEmpty()) {
|
|
|
|
|
showMessage("Interrupted " + QString::number(inferiorPid()));
|
|
|
|
|
notifyInferiorStopOk();
|
|
|
|
|
} else {
|
|
|
|
|
showMessage(error, LogError);
|
|
|
|
|
notifyInferiorStopFailed();
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-06-20 17:19:12 +02:00
|
|
|
signalOperation->setDebuggerCommand(runParameters().debugger.executable.toString());
|
2017-08-17 10:37:05 +02:00
|
|
|
signalOperation->interruptProcess(inferiorPid());
|
2013-11-04 09:47:34 +01:00
|
|
|
} else {
|
|
|
|
|
interruptInferior2();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-06 23:08:57 +03:00
|
|
|
void GdbEngine::runCommand(const DebuggerCommand &command)
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2015-10-14 13:26:22 +02:00
|
|
|
const int token = ++currentToken();
|
|
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
DebuggerCommand cmd = command;
|
2009-09-21 11:09:38 +02:00
|
|
|
|
2017-01-31 12:59:52 +01:00
|
|
|
if (cmd.function.isEmpty()) {
|
|
|
|
|
showMessage(QString("EMPTY FUNCTION RUN, TOKEN: %1 ARGS: %2")
|
|
|
|
|
.arg(token).arg(cmd.args.toString()));
|
|
|
|
|
QTC_ASSERT(false, return);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 13:12:51 +01:00
|
|
|
if (m_gdbProc.state() != QProcess::Running) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
|
|
|
|
|
.arg(cmd.function).arg(state()));
|
2019-01-08 13:12:51 +01:00
|
|
|
if (cmd.callback) {
|
|
|
|
|
DebuggerResponse response;
|
|
|
|
|
response.resultClass = ResultError;
|
|
|
|
|
cmd.callback(response);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-13 09:46:51 +01:00
|
|
|
if (cmd.flags & (NeedsTemporaryStop|NeedsFullStop)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("RUNNING NEEDS-STOP COMMAND " + cmd.function);
|
2016-12-13 09:46:51 +01:00
|
|
|
const bool wantContinue = bool(cmd.flags & NeedsTemporaryStop);
|
|
|
|
|
cmd.flags &= ~(NeedsTemporaryStop|NeedsFullStop);
|
2015-08-14 17:15:32 +02:00
|
|
|
if (state() == InferiorStopRequested) {
|
2016-12-13 09:46:51 +01:00
|
|
|
if (cmd.flags & LosesChild) {
|
2015-08-14 17:15:32 +02:00
|
|
|
notifyInferiorIll();
|
|
|
|
|
return;
|
2009-10-23 21:54:27 +02:00
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("CHILD ALREADY BEING INTERRUPTED. STILL HOPING.");
|
2015-08-14 17:15:32 +02:00
|
|
|
// Calling shutdown() here breaks all situations where two
|
|
|
|
|
// NeedsStop commands are issued in quick succession.
|
2016-12-13 09:46:51 +01:00
|
|
|
m_onStop.append(cmd, wantContinue);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (state() == InferiorRunOk) {
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Stopping temporarily."), 1000);
|
2016-12-13 09:46:51 +01:00
|
|
|
m_onStop.append(cmd, wantContinue);
|
2018-11-30 14:05:18 +01:00
|
|
|
setState(InferiorStopRequested);
|
2018-05-23 14:57:22 +02:00
|
|
|
interruptInferior();
|
2016-12-13 09:46:51 +01:00
|
|
|
return;
|
2009-09-25 08:35:31 +02:00
|
|
|
}
|
2018-03-21 18:01:33 +01:00
|
|
|
if (state() != InferiorStopOk)
|
|
|
|
|
showMessage("UNSAFE STATE FOR QUEUED COMMAND. EXECUTING IMMEDIATELY");
|
2016-12-13 09:46:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(cmd.flags & Discardable))
|
|
|
|
|
++m_nonDiscardableCount;
|
|
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
bool isPythonCommand = true;
|
2017-01-20 10:05:31 +01:00
|
|
|
if ((cmd.flags & NativeCommand) || cmd.function.contains('-') || cmd.function.contains(' '))
|
2016-12-13 13:37:05 +01:00
|
|
|
isPythonCommand = false;
|
|
|
|
|
if (isPythonCommand) {
|
2016-12-13 09:46:51 +01:00
|
|
|
cmd.arg("token", token);
|
|
|
|
|
cmd.function = "python theDumper." + cmd.function + "(" + cmd.argsToPython() + ")";
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 12:10:11 +02:00
|
|
|
QTC_ASSERT(m_gdbProc.state() == QProcess::Running, return);
|
2010-09-07 10:59:40 +02:00
|
|
|
|
2015-02-17 17:44:54 +01:00
|
|
|
cmd.postTime = QTime::currentTime().msecsSinceStartOfDay();
|
2015-02-06 10:30:25 +01:00
|
|
|
m_commandForToken[token] = cmd;
|
2016-12-13 09:46:51 +01:00
|
|
|
m_flagsForToken[token] = cmd.flags;
|
|
|
|
|
if (cmd.flags & ConsoleCommand)
|
2015-02-06 10:30:25 +01:00
|
|
|
cmd.function = "-interpreter-exec console \"" + cmd.function + '"';
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.function = QString::number(token) + cmd.function;
|
|
|
|
|
showMessage(cmd.function, LogInput);
|
2009-09-15 12:16:21 +02:00
|
|
|
|
2011-06-06 18:17:51 +02:00
|
|
|
if (m_scheduledTestResponses.contains(token)) {
|
|
|
|
|
// Fake response for test cases.
|
2016-06-07 17:04:53 +02:00
|
|
|
QString buffer = m_scheduledTestResponses.value(token);
|
|
|
|
|
buffer.replace("@TOKEN@", QString::number(token));
|
2011-06-06 18:17:51 +02:00
|
|
|
m_scheduledTestResponses.remove(token);
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("FAKING TEST RESPONSE (TOKEN: %2, RESPONSE: %3)")
|
|
|
|
|
.arg(token).arg(buffer));
|
2011-06-06 18:17:51 +02:00
|
|
|
QMetaObject::invokeMethod(this, "handleResponse",
|
2016-06-07 17:04:53 +02:00
|
|
|
Q_ARG(QString, buffer));
|
2011-06-06 18:17:51 +02:00
|
|
|
} else {
|
2017-02-06 17:13:49 +01:00
|
|
|
m_gdbProc.write(cmd.function.toUtf8() + "\r\n");
|
2016-11-17 11:36:45 +01:00
|
|
|
if (command.flags & NeedsFlush)
|
2017-02-06 17:13:49 +01:00
|
|
|
m_gdbProc.write("p 0\r\n");
|
2009-11-02 16:59:57 +01:00
|
|
|
|
2011-06-06 18:17:51 +02:00
|
|
|
// Start Watchdog.
|
|
|
|
|
if (m_commandTimer.interval() <= 20000)
|
|
|
|
|
m_commandTimer.setInterval(commandTimeoutTime());
|
|
|
|
|
// The process can die for external reason between the "-gdb-exit" was
|
|
|
|
|
// sent and a response could be retrieved. We don't want the watchdog
|
|
|
|
|
// to bark in that case since the only possible outcome is a dead
|
|
|
|
|
// process anyway.
|
2015-02-06 10:30:25 +01:00
|
|
|
if (!cmd.function.endsWith("-gdb-exit"))
|
2011-06-06 18:17:51 +02:00
|
|
|
m_commandTimer.start();
|
2009-11-03 14:56:27 +01:00
|
|
|
|
2011-06-06 18:17:51 +02:00
|
|
|
//if (cmd.flags & LosesChild)
|
|
|
|
|
// notifyInferiorIll();
|
|
|
|
|
}
|
2009-05-04 18:30:22 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-11 16:59:34 +01:00
|
|
|
int GdbEngine::commandTimeoutTime() const
|
|
|
|
|
{
|
2014-07-28 14:23:52 +02:00
|
|
|
int time = action(GdbWatchdogTimeout)->value().toInt();
|
2011-01-05 09:55:01 +01:00
|
|
|
return 1000 * qMax(40, time);
|
2009-12-11 16:59:34 +01:00
|
|
|
}
|
|
|
|
|
|
2009-11-03 14:56:27 +01:00
|
|
|
void GdbEngine::commandTimeout()
|
|
|
|
|
{
|
2015-02-06 10:30:25 +01:00
|
|
|
QList<int> keys = m_commandForToken.keys();
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(keys);
|
2009-12-11 16:59:34 +01:00
|
|
|
bool killIt = false;
|
2009-11-03 14:56:27 +01:00
|
|
|
foreach (int key, keys) {
|
2015-02-06 10:30:25 +01:00
|
|
|
const DebuggerCommand &cmd = m_commandForToken.value(key);
|
2015-09-11 11:28:55 +02:00
|
|
|
killIt = true;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString::number(key) + ": " + cmd.function);
|
2009-11-03 14:56:27 +01:00
|
|
|
}
|
2015-12-06 11:36:01 +02:00
|
|
|
QStringList commands;
|
|
|
|
|
foreach (const DebuggerCommand &cmd, m_commandForToken)
|
2016-06-07 17:04:53 +02:00
|
|
|
commands << QString("\"%1\"").arg(cmd.function);
|
2009-12-11 16:59:34 +01:00
|
|
|
if (killIt) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("TIMED OUT WAITING FOR GDB REPLY. "
|
|
|
|
|
"COMMANDS STILL IN PROGRESS: ") + commands.join(", "));
|
2010-11-16 12:42:57 +01:00
|
|
|
int timeOut = m_commandTimer.interval();
|
|
|
|
|
//m_commandTimer.stop();
|
2010-01-08 11:32:53 +01:00
|
|
|
const QString msg = tr("The gdb process has not responded "
|
2017-10-19 09:10:57 +02:00
|
|
|
"to a command within %n seconds. This could mean it is stuck "
|
2009-12-11 16:59:34 +01:00
|
|
|
"in an endless loop or taking longer than expected to perform "
|
2010-01-08 11:32:53 +01:00
|
|
|
"the operation.\nYou can choose between waiting "
|
2018-07-23 22:28:49 +02:00
|
|
|
"longer or aborting debugging.", nullptr, timeOut / 1000);
|
2009-12-11 16:59:34 +01:00
|
|
|
QMessageBox *mb = showMessageBox(QMessageBox::Critical,
|
2017-10-19 09:10:57 +02:00
|
|
|
tr("GDB Not Responding"), msg,
|
2009-12-11 16:59:34 +01:00
|
|
|
QMessageBox::Ok | QMessageBox::Cancel);
|
2017-10-19 09:10:57 +02:00
|
|
|
mb->button(QMessageBox::Cancel)->setText(tr("Give GDB More Time"));
|
|
|
|
|
mb->button(QMessageBox::Ok)->setText(tr("Stop Debugging"));
|
2009-12-11 16:59:34 +01:00
|
|
|
if (mb->exec() == QMessageBox::Ok) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("KILLING DEBUGGER AS REQUESTED BY USER");
|
2009-12-11 16:59:34 +01:00
|
|
|
// This is an undefined state, so we just pull the emergency brake.
|
2015-06-08 12:10:11 +02:00
|
|
|
m_gdbProc.kill();
|
2017-12-14 09:11:16 +01:00
|
|
|
notifyEngineShutdownFinished();
|
2009-12-11 16:59:34 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("CONTINUE DEBUGGER AS REQUESTED BY USER");
|
2009-12-11 16:59:34 +01:00
|
|
|
}
|
2010-01-12 13:49:56 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("\nNON-CRITICAL TIMEOUT\nCOMMANDS STILL IN PROGRESS: ")
|
|
|
|
|
+ commands.join(", "));
|
2009-12-11 16:59:34 +01:00
|
|
|
}
|
2009-11-03 14:56:27 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleResultRecord(DebuggerResponse *response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2011-06-06 18:17:51 +02:00
|
|
|
//qDebug() << "TOKEN:" << response->token
|
2009-05-06 20:55:21 +02:00
|
|
|
// << " ACCEPTABLE:" << m_oldestAcceptableToken;
|
2011-06-06 18:17:51 +02:00
|
|
|
//qDebug() << "\nRESULT" << response->token << response->toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-10-23 21:32:08 +02:00
|
|
|
int token = response->token;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (token == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-06 10:30:25 +01:00
|
|
|
if (!m_commandForToken.contains(token)) {
|
2009-10-05 08:56:02 +02:00
|
|
|
// In theory this should not happen (rather the error should be
|
|
|
|
|
// reported in the "first" response to the command) in practice it
|
|
|
|
|
// does. We try to handle a few situations we are aware of gracefully.
|
|
|
|
|
// Ideally, this code should not be present at all.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("COOKIE FOR TOKEN %1 ALREADY EATEN (%2). "
|
|
|
|
|
"TWO RESPONSES FOR ONE COMMAND?").arg(token).
|
|
|
|
|
arg(stateName(state())));
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response->resultClass == ResultError) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response->data["msg"].data();
|
2009-10-05 08:56:02 +02:00
|
|
|
if (msg == "Cannot find new threads: generic error") {
|
|
|
|
|
// Handle a case known to occur on Linux/gdb 6.8 when debugging moc
|
|
|
|
|
// with helpers enabled. In this case we get a second response with
|
|
|
|
|
// msg="Cannot find new threads: generic error"
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("APPLYING WORKAROUND #1");
|
2017-10-19 09:10:57 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Executable Failed"), msg);
|
|
|
|
|
showStatusMessage(tr("Process failed to start."));
|
2010-07-09 17:07:59 +02:00
|
|
|
//shutdown();
|
|
|
|
|
notifyInferiorIll();
|
2010-01-29 21:33:57 +01:00
|
|
|
} else if (msg == "\"finish\" not meaningful in the outermost frame.") {
|
2011-03-30 15:58:58 +02:00
|
|
|
// Handle a case known to appear on GDB 6.4 symbianelf when
|
2009-10-05 08:56:02 +02:00
|
|
|
// the stack is cut due to access to protected memory.
|
2016-06-07 17:04:53 +02:00
|
|
|
//showMessage("APPLYING WORKAROUND #2");
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorStopOk();
|
2009-10-05 08:56:02 +02:00
|
|
|
} else if (msg.startsWith("Cannot find bounds of current function")) {
|
|
|
|
|
// Happens when running "-exec-next" in a function for which
|
|
|
|
|
// there is no debug information. Divert to "-exec-next-step"
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("APPLYING WORKAROUND #3");
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorStopOk();
|
2018-10-02 12:53:07 +02:00
|
|
|
executeStepOver(true);
|
2009-10-29 18:31:45 +01:00
|
|
|
} else if (msg.startsWith("Couldn't get registers: No such process.")) {
|
|
|
|
|
// Happens on archer-tromey-python 6.8.50.20090910-cvs
|
|
|
|
|
// There might to be a race between a process shutting down
|
|
|
|
|
// and library load messages.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("APPLYING WORKAROUND #4");
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorStopOk();
|
2010-10-27 15:39:25 +02:00
|
|
|
//notifyInferiorIll();
|
2016-06-07 17:04:53 +02:00
|
|
|
//showStatusMessage(tr("Executable failed: %1").arg(msg));
|
2010-07-09 17:07:59 +02:00
|
|
|
//shutdown();
|
2017-10-19 09:10:57 +02:00
|
|
|
//AsynchronousMessageBox::critical(tr("Executable Failed"), msg);
|
2010-11-24 15:55:09 +01:00
|
|
|
} else if (msg.contains("Cannot insert breakpoint")) {
|
|
|
|
|
// For breakpoints set by address to non-existent addresses we
|
|
|
|
|
// might get something like "6^error,msg="Warning:\nCannot insert
|
|
|
|
|
// breakpoint 3.\nError accessing memory address 0x34592327:
|
|
|
|
|
// Input/output error.\nCannot insert breakpoint 4.\nError
|
|
|
|
|
// accessing memory address 0x34592335: Input/output error.\n".
|
|
|
|
|
// This should not stop us from proceeding.
|
|
|
|
|
// Most notably, that happens after a "6^running" and "*running"
|
|
|
|
|
// We are probably sitting at _start and can't proceed as
|
|
|
|
|
// long as the breakpoints are enabled.
|
|
|
|
|
// FIXME: Should we silently disable the offending breakpoints?
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("APPLYING WORKAROUND #5");
|
2017-10-19 09:10:57 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Setting Breakpoints Failed"), msg);
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(state() == InferiorRunOk);
|
2010-11-24 15:55:09 +01:00
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
notifyEngineIll();
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (msg.startsWith("Process record: failed to record execution log.")) {
|
|
|
|
|
// Reverse execution recording failed. Full message is something like
|
|
|
|
|
// ~"Process record does not support instruction 0xfae64 at address 0x7ffff7dec6f8.\n"
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
handleRecordingFailed();
|
|
|
|
|
} else if (msg.startsWith("Target multi-thread does not support this command.")) {
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
handleRecordingFailed();
|
2012-05-07 14:29:22 +02:00
|
|
|
} else if (isGdbConnectionError(msg)) {
|
|
|
|
|
notifyInferiorExited();
|
2009-10-05 08:56:02 +02:00
|
|
|
} else {
|
2011-01-21 16:42:57 +01:00
|
|
|
// Windows: Some DLL or some function not found. Report
|
|
|
|
|
// the exception now in a box.
|
|
|
|
|
if (msg.startsWith("During startup program exited with"))
|
|
|
|
|
notifyInferiorExited();
|
2016-11-17 11:36:45 +01:00
|
|
|
else if (msg.contains("Command aborted."))
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
2011-01-21 16:42:57 +01:00
|
|
|
QString logMsg;
|
|
|
|
|
if (!m_lastWinException.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
logMsg = m_lastWinException + '\n';
|
|
|
|
|
logMsg += msg;
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Executable Failed"), logMsg);
|
2011-01-21 16:42:57 +01:00
|
|
|
showStatusMessage(tr("Executable failed: %1").arg(logMsg));
|
2009-09-28 09:18:24 +02:00
|
|
|
}
|
2009-08-13 09:42:34 +02:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 10:30:25 +01:00
|
|
|
DebuggerCommand cmd = m_commandForToken.take(token);
|
2015-09-11 11:28:55 +02:00
|
|
|
const int flags = m_flagsForToken.take(token);
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(LogTimeStamps)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("Response time: %1: %2 s")
|
|
|
|
|
.arg(cmd.function)
|
2015-02-17 17:44:54 +01:00
|
|
|
.arg(QTime::fromMSecsSinceStartOfDay(cmd.postTime).msecsTo(QTime::currentTime()) / 1000.),
|
2010-06-14 17:23:25 +02:00
|
|
|
LogTime);
|
2009-07-06 11:37:21 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
if (response->token < m_oldestAcceptableToken && (flags & Discardable)) {
|
2010-06-14 18:19:02 +02:00
|
|
|
//showMessage(_("### SKIPPING OLD RESULT") + response.toString());
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-30 14:18:47 +02:00
|
|
|
bool isExpectedResult =
|
2015-02-05 15:47:07 +01:00
|
|
|
(response->resultClass == ResultError) // Can always happen.
|
2015-09-11 11:28:55 +02:00
|
|
|
|| (response->resultClass == ResultRunning && (flags & RunRequest))
|
|
|
|
|
|| (response->resultClass == ResultExit && (flags & ExitRequest))
|
2015-02-05 15:47:07 +01:00
|
|
|
|| (response->resultClass == ResultDone);
|
|
|
|
|
// ResultDone can almost "always" happen. Known examples are:
|
2015-02-06 10:30:25 +01:00
|
|
|
// (response->resultClass == ResultDone && cmd.function == "continue")
|
2010-06-30 14:39:41 +02:00
|
|
|
// Happens with some incarnations of gdb 6.8 for "jump to line"
|
2015-02-06 10:30:25 +01:00
|
|
|
// (response->resultClass == ResultDone && cmd.function.startsWith("jump"))
|
|
|
|
|
// (response->resultClass == ResultDone && cmd.function.startsWith("detach"))
|
2011-07-04 14:53:37 +02:00
|
|
|
// Happens when stepping finishes very quickly and issues *stopped and ^done
|
|
|
|
|
// instead of ^running and *stopped
|
2015-02-05 15:47:07 +01:00
|
|
|
// (response->resultClass == ResultDone && (cmd.flags & RunRequest));
|
2010-06-30 14:18:47 +02:00
|
|
|
|
2010-06-30 14:39:41 +02:00
|
|
|
if (!isExpectedResult) {
|
2015-05-27 13:59:56 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
Abi abi = rp.toolChainAbi;
|
2012-06-28 10:00:04 +02:00
|
|
|
if (abi.os() == Abi::WindowsOS
|
2015-02-06 10:30:25 +01:00
|
|
|
&& cmd.function.startsWith("attach")
|
2017-09-27 08:22:02 +02:00
|
|
|
&& (rp.startMode == AttachExternal || terminal()))
|
2011-03-24 14:21:52 +01:00
|
|
|
{
|
|
|
|
|
// Ignore spurious 'running' responses to 'attach'.
|
|
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString rsp = DebuggerResponse::stringFromResultClass(response->resultClass);
|
2015-02-06 10:30:25 +01:00
|
|
|
rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.function + "'";
|
2016-06-07 17:04:53 +02:00
|
|
|
qWarning("%s", qPrintable(rsp));
|
|
|
|
|
showMessage(rsp);
|
2010-04-09 12:49:21 +02:00
|
|
|
}
|
2009-10-12 12:00:07 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
if (!(flags & Discardable))
|
2011-12-13 15:40:31 +01:00
|
|
|
--m_nonDiscardableCount;
|
|
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
m_inUpdateLocals = (flags & InUpdateLocals);
|
2015-07-17 13:30:51 +02:00
|
|
|
|
2010-06-30 14:39:41 +02:00
|
|
|
if (cmd.callback)
|
2015-02-05 15:47:07 +01:00
|
|
|
cmd.callback(*response);
|
2010-06-30 14:39:41 +02:00
|
|
|
|
2009-09-15 12:16:21 +02:00
|
|
|
// Continue only if there are no commands wire anymore, so this will
|
2010-08-30 07:52:41 +02:00
|
|
|
// be fully synchronous.
|
2009-05-07 12:18:45 +02:00
|
|
|
// This is somewhat inefficient, as it makes the last command synchronous.
|
|
|
|
|
// 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.
|
2015-02-06 10:30:25 +01:00
|
|
|
if (m_commandsDoneCallback && m_commandForToken.isEmpty()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ALL COMMANDS DONE; INVOKING CALLBACK");
|
2009-10-08 12:38:01 +02:00
|
|
|
CommandsDoneCallback cont = m_commandsDoneCallback;
|
2018-07-23 22:28:49 +02:00
|
|
|
m_commandsDoneCallback = nullptr;
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response->resultClass != ResultRunning) //only start if the thing is not already running
|
2014-06-05 17:22:51 +02:00
|
|
|
(this->*cont)();
|
2009-09-21 11:09:38 +02:00
|
|
|
} else {
|
2015-02-06 10:30:25 +01:00
|
|
|
PENDING_DEBUG("MISSING TOKENS: " << m_commandForToken.keys());
|
2009-05-07 12:18:45 +02:00
|
|
|
}
|
2009-11-03 14:56:27 +01:00
|
|
|
|
2015-02-06 10:30:25 +01:00
|
|
|
if (m_commandForToken.isEmpty())
|
2010-11-16 12:42:57 +01:00
|
|
|
m_commandTimer.stop();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-16 12:41:06 +01:00
|
|
|
bool GdbEngine::acceptsDebuggerCommands() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-02-27 15:12:36 +01:00
|
|
|
return true;
|
2017-03-07 12:47:35 +01:00
|
|
|
// return state() == InferiorStopOk
|
|
|
|
|
// || state() == InferiorUnrunnable;
|
2011-02-16 12:41:06 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::executeDebuggerCommand(const QString &command)
|
2011-02-16 12:41:06 +01:00
|
|
|
{
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(acceptsDebuggerCommands());
|
2017-04-03 13:00:07 +03:00
|
|
|
runCommand({command, NativeCommand});
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:04:02 +01:00
|
|
|
// This is triggered when switching snapshots.
|
2009-09-23 15:28:50 +02:00
|
|
|
void GdbEngine::updateAll()
|
2009-03-02 15:14:12 +01:00
|
|
|
{
|
2013-11-27 16:10:14 +01:00
|
|
|
//PENDING_DEBUG("UPDATING ALL\n");
|
|
|
|
|
QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk);
|
2015-09-11 11:28:55 +02:00
|
|
|
DebuggerCommand cmd(stackCommand(action(MaximalStackDepth)->value().toInt()));
|
2015-02-11 16:05:55 +01:00
|
|
|
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); };
|
|
|
|
|
runCommand(cmd);
|
2013-11-27 16:10:14 +01:00
|
|
|
stackHandler()->setCurrentIndex(0);
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"-thread-info", CB(handleThreadInfo)});
|
2013-11-27 16:10:14 +01:00
|
|
|
reloadRegisters();
|
|
|
|
|
updateLocals();
|
2009-09-30 12:27:03 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleQuerySources(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-09 11:13:20 +01:00
|
|
|
m_sourcesListUpdating = false;
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2009-02-17 14:08:49 +01:00
|
|
|
QMap<QString, QString> oldShortToFull = m_shortToFullName;
|
2008-12-02 12:01:29 +01:00
|
|
|
m_shortToFullName.clear();
|
|
|
|
|
m_fullToShortName.clear();
|
2011-06-28 18:00:38 +02:00
|
|
|
// "^done,files=[{file="../../../../bin/dumper/dumper.cpp",
|
|
|
|
|
// fullname="/data5/dev/ide/main/bin/dumper/dumper.cpp"},
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data["files"]) {
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi fileName = item["file"];
|
2012-03-23 17:53:30 +01:00
|
|
|
if (fileName.data().endsWith("<built-in>"))
|
|
|
|
|
continue;
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi fullName = item["fullname"];
|
2016-06-07 17:04:53 +02:00
|
|
|
QString file = fileName.data();
|
2012-03-23 17:53:30 +01:00
|
|
|
QString full;
|
2009-10-22 20:04:59 +02:00
|
|
|
if (fullName.isValid()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
full = cleanupFullName(fullName.data());
|
2010-03-05 18:24:32 +01:00
|
|
|
m_fullToShortName[full] = file;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-03-23 17:53:30 +01:00
|
|
|
m_shortToFullName[file] = full;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-02-17 14:08:49 +01:00
|
|
|
if (m_shortToFullName != oldShortToFull)
|
2010-06-16 11:08:54 +02:00
|
|
|
sourceFilesHandler()->setSourceFiles(m_shortToFullName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteJumpToLine(const DebuggerResponse &response)
|
2010-06-30 14:18:47 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultRunning) {
|
2012-08-21 11:30:59 +02:00
|
|
|
// All is fine. Waiting for a *running
|
|
|
|
|
// and the temporary breakpoint to be hit.
|
|
|
|
|
notifyInferiorRunOk(); // Only needed for gdb < 7.0.
|
2015-02-05 15:47:07 +01:00
|
|
|
} else if (response.resultClass == ResultError) {
|
2014-11-27 14:31:02 +01:00
|
|
|
// Could be "Unreasonable jump request" or similar.
|
2017-10-19 09:10:57 +02:00
|
|
|
QString out = tr("Cannot jump. Stopped.");
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2014-11-27 14:31:02 +01:00
|
|
|
if (!msg.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
out += ". " + msg;
|
2014-11-27 14:31:02 +01:00
|
|
|
showStatusMessage(out);
|
|
|
|
|
notifyInferiorRunFailed();
|
2015-02-05 15:47:07 +01:00
|
|
|
} else if (response.resultClass == ResultDone) {
|
2010-06-30 14:18:47 +02:00
|
|
|
// This happens on old gdb. Trigger the effect of a '*stopped'.
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Jumped. Stopped."));
|
2010-07-12 15:39:22 +02:00
|
|
|
notifyInferiorSpontaneousStop();
|
2015-02-06 01:26:47 +01:00
|
|
|
handleStop2(response.data);
|
2009-04-30 15:21:37 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteRunToLine(const DebuggerResponse &response)
|
2010-06-30 14:39:41 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultRunning) {
|
2012-08-21 11:30:59 +02:00
|
|
|
// All is fine. Waiting for a *running
|
|
|
|
|
// and the temporary breakpoint to be hit.
|
2015-02-05 15:47:07 +01:00
|
|
|
} else if (response.resultClass == ResultDone) {
|
2011-05-03 18:14:18 +02:00
|
|
|
// This happens on old gdb (Mac). gdb is not stopped yet,
|
|
|
|
|
// but merely accepted the continue.
|
2010-06-30 14:39:41 +02:00
|
|
|
// >&"continue\n"
|
|
|
|
|
// >~"Continuing.\n"
|
|
|
|
|
//>~"testArray () at ../simple/app.cpp:241\n"
|
|
|
|
|
//>~"241\t s[1] = \"b\";\n"
|
|
|
|
|
//>122^done
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Target line hit, and therefore stopped."));
|
2011-05-03 18:14:18 +02:00
|
|
|
notifyInferiorRunOk();
|
2010-06-30 14:39:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static bool isExitedReason(const QString &reason)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-04-30 15:21:37 +02:00
|
|
|
return reason == "exited-normally" // inferior exited normally
|
|
|
|
|
|| reason == "exited-signalled" // inferior exited because of a signal
|
|
|
|
|
//|| reason == "signal-received" // inferior received signal
|
|
|
|
|
|| reason == "exited"; // inferior exited
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-10-09 10:20:42 +02:00
|
|
|
void GdbEngine::handleStopResponse(const GdbMi &data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-08-29 11:42:28 +02:00
|
|
|
// Ignore trap on Windows terminals, which results in
|
|
|
|
|
// spurious "* stopped" message.
|
2017-09-27 08:22:02 +02:00
|
|
|
if (m_expectTerminalTrap) {
|
|
|
|
|
m_expectTerminalTrap = false;
|
|
|
|
|
if ((!data.isValid() || !data["reason"].isValid())
|
|
|
|
|
&& Abi::hostAbi().os() == Abi::WindowsOS) {
|
|
|
|
|
showMessage("IGNORING TERMINAL SIGTRAP", LogMisc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-08-29 11:42:28 +02:00
|
|
|
}
|
2009-10-30 17:40:29 +01:00
|
|
|
|
2010-07-13 08:41:27 +02:00
|
|
|
if (isDying()) {
|
|
|
|
|
notifyInferiorStopOk();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi threads = data["stopped-thread"];
|
2012-10-19 16:37:57 +02:00
|
|
|
threadsHandler()->notifyStopped(threads.data());
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString reason = data["reason"].data();
|
2009-02-17 16:25:48 +01:00
|
|
|
if (isExitedReason(reason)) {
|
2010-07-09 17:07:59 +02:00
|
|
|
// // The user triggered a stop, but meanwhile the app simply exited ...
|
|
|
|
|
// QTC_ASSERT(state() == InferiorStopRequested
|
|
|
|
|
// /*|| state() == InferiorStopRequested_Kill*/,
|
|
|
|
|
// qDebug() << state());
|
2009-04-30 15:21:37 +02:00
|
|
|
QString msg;
|
2009-02-17 16:25:48 +01:00
|
|
|
if (reason == "exited") {
|
2010-03-23 14:49:02 +01:00
|
|
|
msg = tr("Application exited with exit code %1")
|
2016-06-07 17:04:53 +02:00
|
|
|
.arg(data["exit-code"].toString());
|
2009-04-30 22:22:37 +02:00
|
|
|
} else if (reason == "exited-signalled" || reason == "signal-received") {
|
2010-03-23 14:49:02 +01:00
|
|
|
msg = tr("Application exited after receiving signal %1")
|
2016-06-07 17:04:53 +02:00
|
|
|
.arg(data["signal-name"].toString());
|
2009-04-30 15:21:37 +02:00
|
|
|
} else {
|
2017-10-19 09:10:57 +02:00
|
|
|
msg = tr("Application exited normally.");
|
2009-02-17 16:25:48 +01:00
|
|
|
}
|
2015-06-12 15:17:14 +02:00
|
|
|
// Only show the message. Ramp-down will be triggered by -thread-group-exited.
|
2009-09-14 11:02:36 +02:00
|
|
|
showStatusMessage(msg);
|
2009-02-17 16:25:48 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 15:30:42 +01:00
|
|
|
// Ignore signals from the process stub.
|
2015-06-12 15:17:14 +02:00
|
|
|
const GdbMi frame = data["frame"];
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString func = frame["from"].data();
|
2017-09-27 08:22:02 +02:00
|
|
|
if (terminal()
|
2015-02-24 15:30:42 +01:00
|
|
|
&& data["reason"].data() == "signal-received"
|
|
|
|
|
&& data["signal-name"].data() == "SIGSTOP"
|
|
|
|
|
&& (func.endsWith("/ld-linux.so.2")
|
|
|
|
|
|| func.endsWith("/ld-linux-x86-64.so.2")))
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("INTERNAL CONTINUE AFTER SIGSTOP FROM STUB", LogMisc);
|
2015-02-24 15:30:42 +01:00
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
continueInferiorInternal();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-13 09:46:51 +01:00
|
|
|
if (!m_onStop.isEmpty()) {
|
2015-08-14 17:15:32 +02:00
|
|
|
notifyInferiorStopOk();
|
2016-12-13 09:46:51 +01:00
|
|
|
showMessage("HANDLING QUEUED COMMANDS AFTER TEMPORARY STOP", LogMisc);
|
|
|
|
|
DebuggerCommandSequence seq = m_onStop;
|
|
|
|
|
m_onStop = DebuggerCommandSequence();
|
|
|
|
|
for (const DebuggerCommand &cmd : seq.commands())
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
if (seq.wantContinue())
|
|
|
|
|
continueInferiorInternal();
|
2015-08-14 17:15:32 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString nr = data["bkptno"].data();
|
2012-08-29 11:42:28 +02:00
|
|
|
int lineNumber = 0;
|
|
|
|
|
QString fullName;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString function;
|
|
|
|
|
QString language;
|
2012-08-29 11:42:28 +02:00
|
|
|
if (frame.isValid()) {
|
2013-05-03 18:26:10 +02:00
|
|
|
const GdbMi lineNumberG = frame["line"];
|
2015-10-08 16:19:57 +02:00
|
|
|
function = frame["function"].data(); // V4 protocol
|
|
|
|
|
if (function.isEmpty())
|
|
|
|
|
function = frame["func"].data(); // GDB's *stopped messages
|
|
|
|
|
language = frame["language"].data();
|
2012-08-29 11:42:28 +02:00
|
|
|
if (lineNumberG.isValid()) {
|
2013-05-07 12:09:54 +02:00
|
|
|
lineNumber = lineNumberG.toInt();
|
2016-06-07 17:04:53 +02:00
|
|
|
fullName = cleanupFullName(frame["fullname"].data());
|
2012-08-29 11:42:28 +02:00
|
|
|
if (fullName.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
fullName = frame["file"].data();
|
2012-08-29 11:42:28 +02:00
|
|
|
} // found line number
|
|
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("INVALID STOPPED REASON", LogWarning);
|
2012-08-29 11:42:28 +02:00
|
|
|
}
|
2010-11-23 15:54:57 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (!nr.isEmpty() && frame.isValid()) {
|
2010-11-23 15:54:57 +01:00
|
|
|
// Use opportunity to update the breakpoint marker position.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (Breakpoint bp = breakHandler()->findBreakpointByResponseId(nr)) {
|
|
|
|
|
QString fileName = bp->fileName();
|
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
fileName = fullName;
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
|
bp->setMarkerFileAndLine(fileName, lineNumber);
|
|
|
|
|
}
|
2010-11-18 12:30:56 +01:00
|
|
|
}
|
|
|
|
|
|
2011-06-24 16:25:30 +02:00
|
|
|
//qDebug() << "BP " << rid << data.toString();
|
2010-11-23 15:54:57 +01:00
|
|
|
// Quickly set the location marker.
|
2018-10-05 12:03:19 +02:00
|
|
|
if (lineNumber && !operatesByInstruction()
|
2014-10-24 10:28:28 +02:00
|
|
|
&& QFileInfo::exists(fullName)
|
2015-10-08 16:19:57 +02:00
|
|
|
&& function != "qt_v4TriggeredBreakpointHook"
|
2015-10-14 13:26:22 +02:00
|
|
|
&& function != "qt_qmlDebugMessageAvailable"
|
2015-10-08 16:19:57 +02:00
|
|
|
&& language != "js")
|
2010-12-16 19:06:33 +01:00
|
|
|
gotoLocation(Location(fullName, lineNumber));
|
2010-11-23 15:54:57 +01:00
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
if (state() == InferiorRunOk) {
|
2009-10-09 10:54:03 +02:00
|
|
|
// Stop triggered by a breakpoint or otherwise not directly
|
|
|
|
|
// initiated by the user.
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
} else if (state() == InferiorRunRequested) {
|
2010-10-12 11:52:11 +02:00
|
|
|
// Stop triggered by something like "-exec-step\n"
|
2011-06-06 16:19:56 +02:00
|
|
|
// "&"Cannot access memory at address 0xbfffedd4\n"
|
|
|
|
|
// or, on S40,
|
|
|
|
|
// "*running,thread-id="30""
|
|
|
|
|
// "&"Warning:\n""
|
|
|
|
|
// "&"Cannot insert breakpoint -33.\n"
|
|
|
|
|
// "&"Error accessing memory address 0x11673fc: Input/output error.\n""
|
2010-07-09 17:07:59 +02:00
|
|
|
// In this case a proper response 94^error,msg="" will follow and
|
|
|
|
|
// be handled in the result handler.
|
2010-10-12 11:52:11 +02:00
|
|
|
// -- or --
|
|
|
|
|
// *stopped arriving earlier than ^done response to an -exec-step
|
2018-02-12 16:07:15 +01:00
|
|
|
notifyInferiorRunOk();
|
2010-10-12 11:52:11 +02:00
|
|
|
notifyInferiorSpontaneousStop();
|
2012-08-21 10:29:54 +02:00
|
|
|
} else if (state() == InferiorStopOk) {
|
2011-01-24 13:37:07 +01:00
|
|
|
// That's expected.
|
2015-02-24 15:30:42 +01:00
|
|
|
} else if (state() == InferiorStopRequested) {
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorStopOk();
|
2015-02-24 15:30:42 +01:00
|
|
|
} else if (state() == EngineRunRequested) {
|
|
|
|
|
// This is gdb 7+'s initial *stopped in response to attach that
|
2017-10-19 08:29:20 +02:00
|
|
|
// appears before the ^done is seen for local setups.
|
2015-02-24 15:30:42 +01:00
|
|
|
notifyEngineRunAndInferiorStopOk();
|
2017-10-19 08:29:20 +02:00
|
|
|
if (terminal()) {
|
2015-03-02 13:02:15 +01:00
|
|
|
continueInferiorInternal();
|
2017-10-19 08:29:20 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-02-24 15:30:42 +01:00
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
2009-10-09 10:54:03 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2012-08-21 10:29:54 +02:00
|
|
|
|
2017-02-06 12:10:02 +01:00
|
|
|
handleStop1(data);
|
2010-11-23 12:31:47 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static QString stopSignal(const Abi &abi)
|
2011-03-24 14:21:52 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
return QLatin1String(abi.os() == Abi::WindowsOS ? "SIGTRAP" : "SIGINT");
|
2011-03-24 14:21:52 +01:00
|
|
|
}
|
|
|
|
|
|
2012-04-17 10:00:40 +02:00
|
|
|
void GdbEngine::handleStop1(const GdbMi &data)
|
|
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2012-08-21 10:29:54 +02:00
|
|
|
QTC_ASSERT(!isDying(), return);
|
2013-05-03 18:26:10 +02:00
|
|
|
const GdbMi frame = data["frame"];
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString reason = data["reason"].data();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-05-19 12:00:01 +02:00
|
|
|
// This was seen on XP after removing a breakpoint while running
|
2009-06-19 12:04:21 +02:00
|
|
|
// >945*stopped,reason="signal-received",signal-name="SIGTRAP",
|
2009-02-13 16:55:24 +01:00
|
|
|
// signal-meaning="Trace/breakpoint trap",thread-id="2",
|
|
|
|
|
// frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
|
|
|
|
|
// args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"}
|
2009-12-18 16:25:59 +01:00
|
|
|
// also seen on gdb 6.8-symbianelf without qXfer:libraries:read+;
|
|
|
|
|
// FIXME: remote.c parses "loaded" reply. It should be turning
|
|
|
|
|
// that into a TARGET_WAITKIND_LOADED. Does it?
|
|
|
|
|
// The bandaid here has the problem that it breaks for 'next' over a
|
|
|
|
|
// statement that indirectly loads shared libraries
|
2010-01-06 14:16:35 +01:00
|
|
|
// 6.1.2010: Breaks interrupting inferiors, disabled:
|
|
|
|
|
// if (reason == "signal-received"
|
|
|
|
|
// && data.findChild("signal-name").data() == "SIGTRAP") {
|
|
|
|
|
// continueInferiorInternal();
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
2009-02-13 16:55:24 +01:00
|
|
|
|
2010-03-11 11:07:16 +01:00
|
|
|
// Jump over well-known frames.
|
2008-12-02 12:01:29 +01:00
|
|
|
static int stepCounter = 0;
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(SkipKnownFrames)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (reason == "end-stepping-range" || reason == "function-finished") {
|
2010-06-14 18:19:02 +02:00
|
|
|
//showMessage(frame.toString());
|
2016-06-07 17:04:53 +02:00
|
|
|
QString funcName = frame["function"].data();
|
|
|
|
|
QString fileName = frame["file"].data();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (isLeavableFunction(funcName, fileName)) {
|
2010-06-14 18:19:02 +02:00
|
|
|
//showMessage(_("LEAVING ") + funcName);
|
2008-12-02 12:01:29 +01:00
|
|
|
++stepCounter;
|
2010-11-08 15:41:44 +01:00
|
|
|
executeStepOut();
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (isSkippableFunction(funcName, fileName)) {
|
2010-06-14 18:19:02 +02:00
|
|
|
//showMessage(_("SKIPPING ") + funcName);
|
2008-12-02 12:01:29 +01:00
|
|
|
++stepCounter;
|
2018-10-02 12:53:07 +02:00
|
|
|
executeStepIn(false);
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//if (stepCounter)
|
|
|
|
|
// qDebug() << "STEPCOUNTER:" << stepCounter;
|
|
|
|
|
stepCounter = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-19 12:00:01 +02:00
|
|
|
// Show return value if possible, usually with reason "function-finished".
|
|
|
|
|
// *stopped,reason="function-finished",frame={addr="0x080556da",
|
|
|
|
|
// func="testReturnValue",args=[],file="/../app.cpp",
|
|
|
|
|
// fullname="/../app.cpp",line="1611"},gdb-result-var="$1",
|
|
|
|
|
// return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all",
|
|
|
|
|
// core="1"
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi resultVar = data["gdb-result-var"];
|
2010-05-19 12:00:01 +02:00
|
|
|
if (resultVar.isValid())
|
|
|
|
|
m_resultVarName = resultVar.data();
|
|
|
|
|
else
|
|
|
|
|
m_resultVarName.clear();
|
|
|
|
|
|
2013-03-21 17:32:34 +01:00
|
|
|
if (!m_systemDumpersLoaded) {
|
|
|
|
|
m_systemDumpersLoaded = true;
|
2014-07-28 14:23:52 +02:00
|
|
|
if (m_gdbVersion >= 70400 && boolSetting(LoadGdbDumpers))
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"importPlainDumpers on"});
|
2015-01-25 01:36:08 +01:00
|
|
|
else
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"importPlainDumpers off"});
|
2013-03-21 17:32:34 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-27 16:10:14 +01:00
|
|
|
handleStop2(data);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-04-17 10:00:40 +02:00
|
|
|
void GdbEngine::handleStop2(const GdbMi &data)
|
2009-10-09 10:59:56 +02:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2012-08-21 10:29:54 +02:00
|
|
|
QTC_ASSERT(!isDying(), return);
|
2010-07-13 08:41:27 +02:00
|
|
|
|
2011-05-24 12:38:54 +02:00
|
|
|
// A user initiated stop looks like the following. Note that there is
|
|
|
|
|
// this extra "stopper thread" created and "properly" reported by gdb.
|
|
|
|
|
//
|
|
|
|
|
// dNOTE: INFERIOR RUN OK
|
|
|
|
|
// dState changed from InferiorRunRequested(10) to InferiorRunOk(11).
|
|
|
|
|
// >*running,thread-id="all"
|
|
|
|
|
// >=thread-exited,id="11",group-id="i1"
|
|
|
|
|
// sThread 11 in group i1 exited
|
|
|
|
|
// dState changed from InferiorRunOk(11) to InferiorStopRequested(13).
|
|
|
|
|
// dCALL: INTERRUPT INFERIOR
|
|
|
|
|
// sStop requested...
|
|
|
|
|
// dTRYING TO INTERRUPT INFERIOR
|
|
|
|
|
// >=thread-created,id="12",group-id="i1"
|
|
|
|
|
// sThread 12 created
|
|
|
|
|
// >~"[New Thread 8576.0x1154]\n"
|
|
|
|
|
// s[New Thread 8576.0x1154]
|
|
|
|
|
// >*running,thread-id="all"
|
|
|
|
|
// >~"[Switching to Thread 8576.0x1154]\n"
|
|
|
|
|
// >*stopped,reason="signal-received",signal-name="SIGTRAP",
|
|
|
|
|
// signal-meaning="Trace/breakpointtrap",frame={addr="0x7c90120f",func=
|
|
|
|
|
// "ntdll!DbgUiConnectToDbg",args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"},
|
|
|
|
|
// thread-id="12",stopped-threads="all"
|
|
|
|
|
// dNOTE: INFERIOR STOP OK
|
|
|
|
|
// dState changed from InferiorStopRequested(13) to InferiorStopOk(14).
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString reason = data["reason"].data();
|
2015-05-27 13:59:56 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
2010-01-13 10:31:03 +01:00
|
|
|
|
2011-05-24 12:38:54 +02:00
|
|
|
bool isStopperThread = false;
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
if (rp.toolChainAbi.os() == Abi::WindowsOS
|
2017-09-27 08:22:02 +02:00
|
|
|
&& terminal()
|
2011-03-24 14:21:52 +01:00
|
|
|
&& reason == "signal-received"
|
2013-05-03 18:26:10 +02:00
|
|
|
&& data["signal-name"].data() == "SIGTRAP")
|
2011-03-24 14:21:52 +01:00
|
|
|
{
|
2011-05-24 12:38:54 +02:00
|
|
|
// This is the stopper thread. That also means that the
|
|
|
|
|
// reported thread is not the one we'd like to expose
|
|
|
|
|
// to the user.
|
|
|
|
|
isStopperThread = true;
|
2010-01-13 10:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 15:16:31 +02:00
|
|
|
if (reason == "watchpoint-trigger") {
|
|
|
|
|
// *stopped,reason="watchpoint-trigger",wpt={number="2",exp="*0xbfffed40"},
|
|
|
|
|
// value={old="1",new="0"},frame={addr="0x00451e1b",
|
|
|
|
|
// func="QScopedPointer",args=[{name="this",value="0xbfffed40"},
|
|
|
|
|
// {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
|
2010-06-15 11:14:44 +02:00
|
|
|
// thread-id="1",stopped-threads="all",core="2"
|
2013-05-03 18:26:10 +02:00
|
|
|
const GdbMi wpt = data["wpt"];
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString rid = wpt["number"].data();
|
2015-01-10 01:07:01 +01:00
|
|
|
const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
|
2019-01-17 01:38:54 +01:00
|
|
|
const quint64 bpAddress = wpt["exp"].data().midRef(1).toULongLong(nullptr, 0);
|
2011-05-09 08:35:58 +02:00
|
|
|
QString msg;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (bp) {
|
|
|
|
|
if (bp->type() == WatchpointAtExpression)
|
|
|
|
|
msg = bp->msgWatchpointByExpressionTriggered(bp->expression());
|
|
|
|
|
if (bp->type() == WatchpointAtAddress)
|
|
|
|
|
msg = bp->msgWatchpointByAddressTriggered(bpAddress);
|
|
|
|
|
}
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi value = data["value"];
|
|
|
|
|
GdbMi oldValue = value["old"];
|
|
|
|
|
GdbMi newValue = value["new"];
|
2011-03-04 19:49:03 +01:00
|
|
|
if (oldValue.isValid() && newValue.isValid()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
msg += ' ';
|
2011-03-04 19:49:03 +01:00
|
|
|
msg += tr("Value changed from %1 to %2.")
|
2016-06-07 17:04:53 +02:00
|
|
|
.arg(oldValue.data()).arg(newValue.data());
|
2011-03-04 19:49:03 +01:00
|
|
|
}
|
|
|
|
|
showStatusMessage(msg);
|
2010-11-23 16:14:19 +01:00
|
|
|
} else if (reason == "breakpoint-hit") {
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi gNumber = data["bkptno"]; // 'number' or 'bkptno'?
|
2010-11-17 17:16:34 +01:00
|
|
|
if (!gNumber.isValid())
|
2013-05-03 18:26:10 +02:00
|
|
|
gNumber = data["number"];
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString rid = gNumber.data();
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString threadId = data["thread-id"].data();
|
2010-12-20 16:28:26 +01:00
|
|
|
m_currentThread = threadId;
|
2018-08-03 15:49:06 +03:00
|
|
|
if (const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid)) {
|
|
|
|
|
showStatusMessage(bp->msgBreakpointTriggered(threadId));
|
|
|
|
|
const QString commands = bp->command().trimmed();
|
|
|
|
|
// Can be either c or cont[inue]
|
|
|
|
|
const QRegularExpression contExp("(^|\\n)\\s*c(ont(i(n(ue?)?)?)?)?$");
|
|
|
|
|
QTC_CHECK(contExp.isValid());
|
|
|
|
|
if (contExp.match(commands).hasMatch()) {
|
|
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-21 11:09:38 +02:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString reasontr = msgStopped(reason);
|
2011-02-23 11:28:20 +01:00
|
|
|
if (reason == "signal-received") {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString name = data["signal-name"].data();
|
|
|
|
|
QString meaning = data["signal-meaning"].data();
|
2009-10-16 15:47:54 +02:00
|
|
|
// Ignore these as they are showing up regularly when
|
2009-09-21 11:09:38 +02:00
|
|
|
// stopping debugging.
|
2015-05-27 13:59:56 +02:00
|
|
|
if (name == stopSignal(rp.toolChainAbi) || rp.expectedSignals.contains(name)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(name + " CONSIDERED HARMLESS. CONTINUING.");
|
2018-11-09 10:55:50 +01:00
|
|
|
} else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") {
|
|
|
|
|
showMessage("SIGNAL 0 CONSIDERED BOGUS.");
|
2010-11-26 14:35:36 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("HANDLING SIGNAL " + name);
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(UseMessageBoxForSignals) && !isStopperThread)
|
2016-12-14 09:59:49 +01:00
|
|
|
if (!showStoppedBySignalMessageBox(meaning, name)) {
|
|
|
|
|
showMessage("SIGNAL RECEIVED WHILE SHOWING SIGNAL MESSAGE");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-03-10 10:32:58 +01:00
|
|
|
if (!name.isEmpty() && !meaning.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
reasontr = msgStoppedBySignal(meaning, name);
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (reason.isEmpty())
|
2010-11-17 17:16:34 +01:00
|
|
|
showStatusMessage(msgStopped());
|
2009-09-21 11:09:38 +02:00
|
|
|
else
|
2010-03-10 10:32:58 +01:00
|
|
|
showStatusMessage(reasontr);
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2010-12-17 13:07:17 +01:00
|
|
|
// Let the event loop run before deciding whether to update the stack.
|
|
|
|
|
m_stackNeeded = true; // setTokenBarrier() might reset this.
|
2016-04-19 22:49:23 +02:00
|
|
|
QTimer::singleShot(0, this, &GdbEngine::handleStop3);
|
2010-12-17 13:07:17 +01:00
|
|
|
}
|
|
|
|
|
|
2016-04-19 22:49:23 +02:00
|
|
|
void GdbEngine::handleStop3()
|
2010-12-17 13:07:17 +01:00
|
|
|
{
|
2015-10-06 23:08:57 +03:00
|
|
|
DebuggerCommand cmd("-thread-info", Discardable);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = CB(handleThreadInfo);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleShowVersion(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("PARSING VERSION: " + response.toString());
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2013-11-27 16:10:14 +01:00
|
|
|
bool isMacGdb = false;
|
|
|
|
|
int gdbBuildVersion = -1;
|
2008-12-02 12:01:29 +01:00
|
|
|
m_gdbVersion = 100;
|
2012-02-10 07:42:44 +01:00
|
|
|
m_isQnxGdb = false;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.consoleStreamOutput;
|
2010-05-27 15:41:52 +02:00
|
|
|
extractGdbVersion(msg,
|
2013-11-27 16:10:14 +01:00
|
|
|
&m_gdbVersion, &gdbBuildVersion, &isMacGdb, &m_isQnxGdb);
|
2011-12-16 14:14:15 +01:00
|
|
|
|
2014-01-28 11:21:57 +01:00
|
|
|
// On Mac, FSF GDB does not work sufficiently well,
|
|
|
|
|
// and on Linux and Windows we require at least 7.4.1,
|
|
|
|
|
// on Android 7.3.1.
|
|
|
|
|
bool isSupported = m_gdbVersion >= 70300;
|
2011-12-16 14:14:15 +01:00
|
|
|
if (isSupported)
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("SUPPORTED GDB VERSION " + msg);
|
2010-05-27 15:41:52 +02:00
|
|
|
else
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("UNSUPPORTED GDB VERSION " + msg);
|
2010-01-21 16:34:59 +01:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("USING GDB VERSION: %1, BUILD: %2%3").arg(m_gdbVersion)
|
|
|
|
|
.arg(gdbBuildVersion).arg(QLatin1String(isMacGdb ? " (APPLE)" : "")));
|
2011-06-07 17:28:45 +02:00
|
|
|
|
2013-11-27 16:10:14 +01:00
|
|
|
if (usesExecInterrupt())
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set target-async on", ConsoleCommand});
|
2013-11-27 16:10:14 +01:00
|
|
|
else
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set target-async off", ConsoleCommand});
|
2012-03-28 09:37:02 +02:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set build-id-verbose 2", ConsoleCommand);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleListFeatures(const DebuggerResponse &response)
|
2011-06-15 14:02:26 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("FEATURES: " + response.toString());
|
2011-06-15 14:02:26 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handlePythonSetup(const DebuggerResponse &response)
|
2009-10-14 09:41:14 +02:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2016-12-15 18:28:58 +01:00
|
|
|
GdbMi data = response.data;
|
2015-01-23 19:09:08 +01:00
|
|
|
watchHandler()->addDumpers(data["dumpers"]);
|
2015-09-17 09:47:36 +02:00
|
|
|
m_pythonVersion = data["python"].toInt();
|
|
|
|
|
if (m_pythonVersion < 20700) {
|
|
|
|
|
int pythonMajor = m_pythonVersion / 10000;
|
|
|
|
|
int pythonMinor = (m_pythonVersion / 100) % 100;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString out = "<p>"
|
2015-09-17 09:47:36 +02:00
|
|
|
+ tr("The selected build of GDB supports Python scripting, "
|
|
|
|
|
"but the used version %1.%2 is not sufficient for "
|
2017-08-29 11:48:48 +02:00
|
|
|
"%3. Supported versions are Python 2.7 and 3.x.")
|
|
|
|
|
.arg(pythonMajor).arg(pythonMinor)
|
|
|
|
|
.arg(Core::Constants::IDE_DISPLAY_NAME);
|
2015-09-17 09:47:36 +02:00
|
|
|
showStatusMessage(out);
|
|
|
|
|
AsynchronousMessageBox::critical(tr("Execution Error"), out);
|
|
|
|
|
}
|
2014-01-28 11:27:13 +01:00
|
|
|
loadInitScript();
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ENGINE SUCCESSFULLY STARTED");
|
2017-11-15 17:12:03 +01:00
|
|
|
setupInferior();
|
2014-01-28 11:27:13 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2014-04-02 15:08:50 +02:00
|
|
|
if (msg.contains("Python scripting is not supported in this copy of GDB.")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString out1 = "The selected build of GDB does not support Python scripting.";
|
2017-08-29 11:48:48 +02:00
|
|
|
QString out2 = QStringLiteral("It cannot be used in %1.")
|
|
|
|
|
.arg(Core::Constants::IDE_DISPLAY_NAME);
|
2016-06-07 17:04:53 +02:00
|
|
|
showStatusMessage(out1 + ' ' + out2);
|
|
|
|
|
AsynchronousMessageBox::critical(tr("Execution Error"), out1 + "<br>" + out2);
|
2014-04-02 15:08:50 +02:00
|
|
|
}
|
2014-01-28 11:27:13 +01:00
|
|
|
notifyEngineSetupFailed();
|
2010-09-23 14:58:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void GdbEngine::showExecutionError(const QString &message)
|
|
|
|
|
{
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Execution Error"),
|
2016-06-07 17:04:53 +02:00
|
|
|
tr("Cannot continue debugged process:") + '\n' + message);
|
2010-07-09 17:07:59 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteContinue(const DebuggerResponse &response)
|
2009-07-21 14:37:31 +02:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorRunRequested);
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultRunning) {
|
2012-08-21 11:30:59 +02:00
|
|
|
// All is fine. Waiting for a *running.
|
|
|
|
|
notifyInferiorRunOk(); // Only needed for gdb < 7.0.
|
2010-07-09 17:07:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2011-04-06 17:34:08 +02:00
|
|
|
if (msg.startsWith("Cannot find bounds of current function")) {
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
if (isDying())
|
2009-11-02 16:59:57 +01:00
|
|
|
return;
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2010-07-09 17:07:59 +02:00
|
|
|
showStatusMessage(tr("Stopped."), 5000);
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack();
|
2011-09-07 15:20:04 +02:00
|
|
|
} else if (msg.startsWith("Cannot access memory at address")) {
|
|
|
|
|
// Happens on single step on ARM prolog and epilogs.
|
2011-04-06 17:34:08 +02:00
|
|
|
} else if (msg.startsWith("\"finish\" not meaningful in the outermost frame")) {
|
|
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
if (isDying())
|
|
|
|
|
return;
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2011-04-06 17:34:08 +02:00
|
|
|
// FIXME: Fix translation in master.
|
2016-06-07 17:04:53 +02:00
|
|
|
showStatusMessage(msg, 5000);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
gotoCurrentLocation();
|
2012-03-03 01:48:43 +01:00
|
|
|
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showExecutionError(msg);
|
2012-03-03 01:48:43 +01:00
|
|
|
notifyInferiorRunFailed() ;
|
2010-07-09 17:07:59 +02:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showExecutionError(msg);
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorIll();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::fullName(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
return QString();
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(!m_sourcesListUpdating, /* */);
|
2009-10-28 11:59:57 +01:00
|
|
|
return m_shortToFullName.value(fileName, QString());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-10-28 11:59:57 +01:00
|
|
|
QString GdbEngine::cleanupFullName(const QString &fileName)
|
|
|
|
|
{
|
2010-08-09 15:27:21 +02:00
|
|
|
QString cleanFilePath = fileName;
|
2011-03-24 14:21:52 +01:00
|
|
|
|
2011-04-28 11:10:01 +02:00
|
|
|
// Gdb running on windows often delivers "fullnames" which
|
|
|
|
|
// (a) have no drive letter and (b) are not normalized.
|
|
|
|
|
if (Abi::hostAbi().os() == Abi::WindowsOS) {
|
2015-06-22 12:29:40 +03:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
return QString();
|
2011-03-24 14:21:52 +01:00
|
|
|
QFileInfo fi(fileName);
|
|
|
|
|
if (fi.isReadable())
|
|
|
|
|
cleanFilePath = QDir::cleanPath(fi.absoluteFilePath());
|
|
|
|
|
}
|
2012-03-23 17:53:30 +01:00
|
|
|
|
2014-07-28 14:23:52 +02:00
|
|
|
if (!boolSetting(AutoEnrichParameters))
|
2012-03-23 17:53:30 +01:00
|
|
|
return cleanFilePath;
|
|
|
|
|
|
2018-08-21 17:46:47 +02:00
|
|
|
const QString sysroot = runParameters().sysRoot.toString();
|
2012-03-23 17:53:30 +01:00
|
|
|
if (QFileInfo(cleanFilePath).isReadable())
|
|
|
|
|
return cleanFilePath;
|
2016-06-07 17:04:53 +02:00
|
|
|
if (!sysroot.isEmpty() && fileName.startsWith('/')) {
|
2012-03-23 17:53:30 +01:00
|
|
|
cleanFilePath = sysroot + fileName;
|
|
|
|
|
if (QFileInfo(cleanFilePath).isReadable())
|
|
|
|
|
return cleanFilePath;
|
|
|
|
|
}
|
|
|
|
|
if (m_baseNameToFullName.isEmpty()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString debugSource = sysroot + "/usr/src/debug";
|
2012-03-23 17:53:30 +01:00
|
|
|
if (QFileInfo(debugSource).isDir()) {
|
|
|
|
|
QDirIterator it(debugSource, QDirIterator::Subdirectories);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
QString name = it.fileName();
|
2016-06-07 17:04:53 +02:00
|
|
|
if (!name.startsWith('.')) {
|
2012-03-23 17:53:30 +01:00
|
|
|
QString path = it.filePath();
|
|
|
|
|
m_baseNameToFullName.insert(name, path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cleanFilePath.clear();
|
2019-05-28 13:49:26 +02:00
|
|
|
const QString base = FilePath::fromString(fileName).fileName();
|
2012-03-23 17:53:30 +01:00
|
|
|
|
2015-04-01 11:19:32 +02:00
|
|
|
QMap<QString, QString>::const_iterator jt = m_baseNameToFullName.constFind(base);
|
|
|
|
|
while (jt != m_baseNameToFullName.constEnd() && jt.key() == base) {
|
2012-03-23 17:53:30 +01:00
|
|
|
// FIXME: Use some heuristics to find the "best" match.
|
|
|
|
|
return jt.value();
|
|
|
|
|
//++jt;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-09 15:27:21 +02:00
|
|
|
return cleanFilePath;
|
|
|
|
|
}
|
2009-10-28 11:59:57 +01:00
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void GdbEngine::shutdownInferior()
|
|
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorShutdownRequested);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (runParameters().startMode == AttachCore) {
|
|
|
|
|
notifyInferiorShutdownFinished();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-09-11 11:28:55 +02:00
|
|
|
DebuggerCommand cmd;
|
2016-12-13 13:37:05 +01:00
|
|
|
cmd.function = QLatin1String(runParameters().closeMode == DetachAtClose ? "detach " : "kill ");
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = CB(handleInferiorShutdown);
|
2016-12-13 09:46:51 +01:00
|
|
|
cmd.flags = NeedsTemporaryStop|LosesChild;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-07-09 17:07:59 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleInferiorShutdown(const DebuggerResponse &response)
|
2010-07-09 17:07:59 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2015-06-16 15:01:46 +02:00
|
|
|
// We'll get async thread-group-exited responses to which we react.
|
|
|
|
|
// Nothing to do here.
|
2017-12-14 09:36:41 +01:00
|
|
|
// notifyInferiorShutdownFinished();
|
2010-07-09 17:07:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2019-01-08 13:12:51 +01:00
|
|
|
// "kill" got stuck, gdb was kill -9'd, or similar.
|
2015-06-16 15:01:46 +02:00
|
|
|
CHECK_STATE(InferiorShutdownRequested);
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
|
|
|
|
if (msg.contains(": No such file or directory.")) {
|
2010-07-09 17:07:59 +02:00
|
|
|
// This happens when someone removed the binary behind our back.
|
|
|
|
|
// It is not really an error from a user's point of view.
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("NOTE: " + msg);
|
2019-01-08 13:12:51 +01:00
|
|
|
} else if (m_gdbProc.state() == QProcess::Running) {
|
2017-12-14 09:36:41 +01:00
|
|
|
AsynchronousMessageBox::critical(tr("Failed to Shut Down Application"),
|
|
|
|
|
msgInferiorStopFailed(msg));
|
2010-07-09 17:07:59 +02:00
|
|
|
}
|
2017-12-14 09:36:41 +01:00
|
|
|
notifyInferiorShutdownFinished();
|
2010-07-09 17:07:59 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleGdbExit(const DebuggerResponse &response)
|
2010-07-09 17:07:59 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultExit) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("GDB CLAIMS EXIT; WAITING");
|
2010-07-09 17:07:59 +02:00
|
|
|
// Don't set state here, this will be handled in handleGdbFinished()
|
|
|
|
|
//notifyEngineShutdownOk();
|
|
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = msgGdbStopFailed(response.data["msg"].data());
|
|
|
|
|
qDebug() << QString("GDB WON'T EXIT (%1); KILLING IT").arg(msg);
|
|
|
|
|
showMessage(QString("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
|
2015-06-08 12:10:11 +02:00
|
|
|
m_gdbProc.kill();
|
2017-12-14 09:11:16 +01:00
|
|
|
notifyEngineShutdownFinished();
|
2010-07-09 17:07:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-07 12:34:19 +03:00
|
|
|
void GdbEngine::setLinuxOsAbi()
|
|
|
|
|
{
|
|
|
|
|
// In case GDB has multiple supported targets, the default osabi can be Cygwin.
|
2017-06-11 16:19:09 +03:00
|
|
|
if (!HostOsInfo::isWindowsHost())
|
|
|
|
|
return;
|
|
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
bool isElf = (rp.toolChainAbi.binaryFormat() == Abi::ElfFormat);
|
|
|
|
|
if (!isElf && !rp.inferior.executable.isEmpty()) {
|
2019-06-20 17:19:12 +02:00
|
|
|
isElf = Utils::anyOf(Abi::abisOfBinary(rp.inferior.executable), [](const Abi &abi) {
|
2017-06-11 16:19:09 +03:00
|
|
|
return abi.binaryFormat() == Abi::ElfFormat;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (isElf)
|
2016-04-07 12:34:19 +03:00
|
|
|
runCommand({"set osabi GNU/Linux"});
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-07 15:20:44 +02:00
|
|
|
void GdbEngine::detachDebugger()
|
|
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2017-10-16 14:56:35 +02:00
|
|
|
QTC_CHECK(runParameters().startMode != AttachCore);
|
2019-01-31 12:31:08 +01:00
|
|
|
DebuggerCommand cmd("detach", NativeCommand | ExitRequest);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &) {
|
|
|
|
|
CHECK_STATE(InferiorStopOk);
|
|
|
|
|
notifyInferiorExited();
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-07-02 12:20:26 +02:00
|
|
|
}
|
|
|
|
|
|
2012-03-28 09:37:02 +02:00
|
|
|
void GdbEngine::handleThreadGroupCreated(const GdbMi &result)
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString groupId = result["id"].data();
|
|
|
|
|
QString pid = result["pid"].data();
|
2015-06-12 15:17:14 +02:00
|
|
|
threadsHandler()->notifyGroupCreated(groupId, pid);
|
2012-03-28 09:37:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleThreadGroupExited(const GdbMi &result)
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString groupId = result["id"].data();
|
2015-07-07 15:13:10 +02:00
|
|
|
if (threadsHandler()->notifyGroupExited(groupId)) {
|
|
|
|
|
if (m_rerunPending)
|
|
|
|
|
m_rerunPending = false;
|
|
|
|
|
else
|
|
|
|
|
notifyInferiorExited();
|
|
|
|
|
}
|
2012-03-28 09:37:02 +02:00
|
|
|
}
|
|
|
|
|
|
2012-06-28 10:00:04 +02:00
|
|
|
static QString msgNoGdbBinaryForToolChain(const Abi &tc)
|
2010-04-09 08:43:26 +02:00
|
|
|
{
|
2017-10-19 09:10:57 +02:00
|
|
|
return GdbEngine::tr("There is no GDB binary available for binaries in format \"%1\".")
|
2011-02-01 18:36:00 +01:00
|
|
|
.arg(tc.toString());
|
2009-10-08 17:23:27 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-12 20:28:17 +01:00
|
|
|
bool GdbEngine::hasCapability(unsigned cap) const
|
2010-02-05 10:23:55 +01:00
|
|
|
{
|
2018-11-18 20:12:40 +02:00
|
|
|
if (cap & (AutoDerefPointersCapability
|
|
|
|
|
| DisassemblerCapability
|
|
|
|
|
| RegisterCapability
|
|
|
|
|
| ShowMemoryCapability
|
|
|
|
|
| CreateFullBacktraceCapability
|
|
|
|
|
| AddWatcherCapability
|
|
|
|
|
| ShowModuleSymbolsCapability
|
|
|
|
|
| ShowModuleSectionsCapability
|
|
|
|
|
| OperateByInstructionCapability
|
|
|
|
|
| WatchComplexExpressionsCapability
|
|
|
|
|
| MemoryAddressCapability
|
|
|
|
|
| AdditionalQmlStackCapability)) {
|
|
|
|
|
return true;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-18 20:12:40 +02:00
|
|
|
if (runParameters().startMode == AttachCore)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return cap & (JumpToLineCapability
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
| ReloadModuleCapability
|
|
|
|
|
| ReloadModuleSymbolsCapability
|
|
|
|
|
| BreakOnThrowAndCatchCapability
|
|
|
|
|
| BreakConditionCapability
|
|
|
|
|
| BreakIndividualLocationsCapability
|
|
|
|
|
| TracePointCapability
|
|
|
|
|
| ReturnFromFunctionCapability
|
|
|
|
|
| WatchpointByAddressCapability
|
|
|
|
|
| WatchpointByExpressionCapability
|
|
|
|
|
| AddWatcherWhileRunningCapability
|
|
|
|
|
| WatchWidgetsCapability
|
|
|
|
|
| CatchCapability
|
|
|
|
|
| RunToLineCapability
|
|
|
|
|
| MemoryAddressCapability
|
|
|
|
|
| AdditionalQmlStackCapability
|
|
|
|
|
| ResetInferiorCapability
|
|
|
|
|
| SnapshotCapability
|
|
|
|
|
| ReverseSteppingCapability);
|
2010-02-05 10:23:55 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-28 10:58:21 +01:00
|
|
|
|
2009-10-08 13:47:56 +02:00
|
|
|
void GdbEngine::continueInferiorInternal()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2010-07-20 12:14:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
showStatusMessage(tr("Running requested..."), 5000);
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorRunRequested);
|
2015-10-08 16:19:57 +02:00
|
|
|
if (isNativeMixedActiveFrame()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("executeContinue", RunRequest);
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.callback = CB(handleExecuteContinue);
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
} else {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("-exec-continue");
|
|
|
|
|
cmd.flags = RunRequest | NeedsFlush;
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.callback = CB(handleExecuteContinue);
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-10-08 13:47:56 +02:00
|
|
|
void GdbEngine::continueInferior()
|
|
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2009-10-20 14:08:59 +02:00
|
|
|
setTokenBarrier();
|
2009-10-08 13:47:56 +02:00
|
|
|
continueInferiorInternal();
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-02 12:53:07 +02:00
|
|
|
void GdbEngine::executeStepIn(bool byInstruction)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2008-12-02 12:01:29 +01:00
|
|
|
setTokenBarrier();
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2009-09-25 08:35:31 +02:00
|
|
|
showStatusMessage(tr("Step requested..."), 5000);
|
2018-10-02 12:53:07 +02:00
|
|
|
|
|
|
|
|
DebuggerCommand cmd;
|
2015-10-08 16:19:57 +02:00
|
|
|
if (isNativeMixedActiveFrame()) {
|
2018-10-02 12:53:07 +02:00
|
|
|
cmd.flags = RunRequest;
|
|
|
|
|
cmd.function = "executeStep";
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.callback = CB(handleExecuteStep);
|
2018-10-02 12:53:07 +02:00
|
|
|
} else if (byInstruction) {
|
|
|
|
|
cmd.flags = RunRequest|NeedsFlush;
|
|
|
|
|
cmd.function = "-exec-step-instruction";
|
|
|
|
|
if (isReverseDebugging())
|
|
|
|
|
cmd.function += "--reverse";
|
|
|
|
|
cmd.callback = CB(handleExecuteContinue);
|
2015-09-11 11:28:55 +02:00
|
|
|
} else {
|
2016-11-17 11:36:45 +01:00
|
|
|
cmd.flags = RunRequest|NeedsFlush;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
cmd.function = "-exec-step";
|
|
|
|
|
if (isReverseDebugging())
|
|
|
|
|
cmd.function += " --reverse";
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = CB(handleExecuteStep);
|
2015-01-22 12:05:00 +01:00
|
|
|
}
|
2018-10-02 12:53:07 +02:00
|
|
|
runCommand(cmd);
|
2010-02-01 16:14:57 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteStep(const DebuggerResponse &response)
|
2010-02-01 16:14:57 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2010-10-12 11:52:11 +02:00
|
|
|
// Step was finishing too quick, and a '*stopped' messages should
|
2011-02-23 15:15:04 +01:00
|
|
|
// have preceded it, so just ignore this result.
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(state() == InferiorStopOk);
|
2010-10-12 11:52:11 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorRunRequested);
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultRunning) {
|
2012-08-21 11:30:59 +02:00
|
|
|
// All is fine. Waiting for a *running.
|
|
|
|
|
notifyInferiorRunOk(); // Only needed for gdb < 7.0.
|
2010-07-09 17:07:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2011-06-06 16:19:56 +02:00
|
|
|
if (msg.startsWith("Cannot find bounds of current function")
|
2011-09-07 15:20:04 +02:00
|
|
|
|| msg.contains("Error accessing memory address")
|
|
|
|
|
|| msg.startsWith("Cannot access memory at address")) {
|
2011-06-06 16:19:56 +02:00
|
|
|
// On S40: "40^error,msg="Warning:\nCannot insert breakpoint -39.\n"
|
|
|
|
|
//" Error accessing memory address 0x11673fc: Input/output error.\n"
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
if (isDying())
|
2010-02-01 16:14:57 +01:00
|
|
|
return;
|
2018-10-02 12:53:07 +02:00
|
|
|
executeStepIn(true); // Fall back to instruction-wise stepping.
|
2012-03-05 19:22:07 +01:00
|
|
|
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showExecutionError(msg);
|
2012-03-05 19:22:07 +01:00
|
|
|
notifyInferiorRunFailed();
|
2012-04-13 18:23:44 +02:00
|
|
|
} else if (msg.startsWith("warning: SuspendThread failed")) {
|
|
|
|
|
// On Win: would lead to "PC register is not available" or "\312"
|
|
|
|
|
continueInferiorInternal();
|
2010-07-09 17:07:59 +02:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showExecutionError(msg);
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorIll();
|
2010-02-01 16:14:57 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-10 16:17:40 +01:00
|
|
|
void GdbEngine::executeStepOut()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"-stack-select-frame 0", Discardable});
|
2008-12-02 12:01:29 +01:00
|
|
|
setTokenBarrier();
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2009-09-25 08:35:31 +02:00
|
|
|
showStatusMessage(tr("Finish function requested..."), 5000);
|
2015-10-08 16:19:57 +02:00
|
|
|
if (isNativeMixedActiveFrame()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"executeStepOut", RunRequest});
|
2015-10-08 16:19:57 +02:00
|
|
|
} else {
|
|
|
|
|
// -exec-finish in 'main' results (correctly) in
|
|
|
|
|
// 40^error,msg="\"finish\" not meaningful in the outermost frame."
|
|
|
|
|
// However, this message does not seem to get flushed before
|
|
|
|
|
// anything else happen - i.e. "never". Force some extra output.
|
2016-11-17 11:36:45 +01:00
|
|
|
runCommand({"-exec-finish", RunRequest|NeedsFlush, CB(handleExecuteContinue)});
|
2015-10-08 16:19:57 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-02 12:53:07 +02:00
|
|
|
void GdbEngine::executeStepOver(bool byInstruction)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2008-12-02 12:01:29 +01:00
|
|
|
setTokenBarrier();
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2009-09-25 08:35:31 +02:00
|
|
|
showStatusMessage(tr("Step next requested..."), 5000);
|
2018-10-02 12:53:07 +02:00
|
|
|
|
|
|
|
|
DebuggerCommand cmd;
|
|
|
|
|
cmd.flags = RunRequest;
|
2015-10-08 16:19:57 +02:00
|
|
|
if (isNativeMixedActiveFrame()) {
|
2018-10-02 12:53:07 +02:00
|
|
|
cmd.function = "executeNext";
|
|
|
|
|
} else if (byInstruction) {
|
|
|
|
|
cmd.function = "-exec-next-instruction";
|
|
|
|
|
if (isReverseDebugging())
|
|
|
|
|
cmd.function += " --reverse";
|
|
|
|
|
cmd.callback = CB(handleExecuteContinue);
|
2011-06-06 18:17:51 +02:00
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
cmd.function = "-exec-next";
|
|
|
|
|
if (isReverseDebugging())
|
|
|
|
|
cmd.function += " --reverse";
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = CB(handleExecuteNext);
|
2011-06-06 18:17:51 +02:00
|
|
|
}
|
2018-10-02 12:53:07 +02:00
|
|
|
runCommand(cmd);
|
2010-02-01 16:14:57 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
|
2010-02-01 16:14:57 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2010-10-12 11:52:11 +02:00
|
|
|
// Step was finishing too quick, and a '*stopped' messages should
|
2011-02-23 15:15:04 +01:00
|
|
|
// have preceded it, so just ignore this result.
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2010-10-12 11:52:11 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorRunRequested);
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultRunning) {
|
2012-08-21 11:30:59 +02:00
|
|
|
// All is fine. Waiting for a *running.
|
|
|
|
|
notifyInferiorRunOk(); // Only needed for gdb < 7.0.
|
2010-07-09 17:07:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2011-06-21 16:45:23 +02:00
|
|
|
if (msg.startsWith("Cannot find bounds of current function")
|
2011-06-06 18:17:51 +02:00
|
|
|
|| msg.contains("Error accessing memory address ")) {
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
if (!isDying())
|
2018-10-02 12:53:07 +02:00
|
|
|
executeStepOver(true); // Fall back to instruction-wise stepping.
|
2012-03-05 19:22:07 +01:00
|
|
|
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showExecutionError(msg);
|
2012-03-05 19:22:07 +01:00
|
|
|
notifyInferiorRunFailed();
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (msg.startsWith("Target multi-thread does not support this command.")) {
|
|
|
|
|
notifyInferiorRunFailed();
|
|
|
|
|
handleRecordingFailed();
|
2010-07-09 17:07:59 +02:00
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
AsynchronousMessageBox::warning(tr("Execution Error"),
|
2016-06-07 17:04:53 +02:00
|
|
|
tr("Cannot continue debugged process:") + '\n' + msg);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
//notifyInferiorIll();
|
2010-02-01 16:14:57 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static QString addressSpec(quint64 address)
|
2011-02-23 10:16:11 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
return "*0x" + QString::number(address, 16);
|
2011-02-23 10:16:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::executeRunToLine(const ContextData &data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2008-12-02 12:01:29 +01:00
|
|
|
setTokenBarrier();
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2011-02-23 10:16:11 +01:00
|
|
|
showStatusMessage(tr("Run to line %1 requested...").arg(data.lineNumber), 5000);
|
2010-03-29 15:58:52 +02:00
|
|
|
#if 1
|
2016-06-07 17:04:53 +02:00
|
|
|
QString loc;
|
2013-11-27 16:10:14 +01:00
|
|
|
if (data.address)
|
|
|
|
|
loc = addressSpec(data.address);
|
|
|
|
|
else
|
2016-06-07 17:04:53 +02:00
|
|
|
loc = '"' + breakLocation(data.fileName) + '"' + ':' + QString::number(data.lineNumber);
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"tbreak " + loc});
|
2015-09-11 11:28:55 +02:00
|
|
|
|
2017-01-31 12:59:52 +01:00
|
|
|
runCommand({"continue", NativeCommand|RunRequest, CB(handleExecuteRunToLine)});
|
2010-03-29 15:58:52 +02:00
|
|
|
#else
|
|
|
|
|
// Seems to jump to unpredicatable places. Observed in the manual
|
|
|
|
|
// tests in the Foo::Foo() constructor with both gdb 6.8 and 7.1.
|
2016-06-07 17:04:53 +02:00
|
|
|
QString args = '"' + breakLocation(fileName) + '"' + ':' + QString::number(lineNumber);
|
2015-09-11 11:28:55 +02:00
|
|
|
runCommand("-exec-until " + args, RunRequest, CB(handleExecuteContinue));
|
2010-03-29 15:58:52 +02:00
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-10 16:17:40 +01:00
|
|
|
void GdbEngine::executeRunToFunction(const QString &functionName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2008-12-02 12:01:29 +01:00
|
|
|
setTokenBarrier();
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"-break-insert -t " + functionName});
|
2010-07-09 17:07:59 +02:00
|
|
|
showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000);
|
2009-10-20 14:08:59 +02:00
|
|
|
continueInferiorInternal();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-23 10:16:11 +01:00
|
|
|
void GdbEngine::executeJumpToLine(const ContextData &data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2016-06-07 17:04:53 +02:00
|
|
|
QString loc;
|
2011-02-23 10:16:11 +01:00
|
|
|
if (data.address)
|
|
|
|
|
loc = addressSpec(data.address);
|
|
|
|
|
else
|
2016-06-07 17:04:53 +02:00
|
|
|
loc = '"' + breakLocation(data.fileName) + '"' + ':' + QString::number(data.lineNumber);
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"tbreak " + loc});
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2015-09-11 11:28:55 +02:00
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"jump " + loc, RunRequest, CB(handleExecuteJumpToLine)});
|
2008-12-02 12:01:29 +01:00
|
|
|
// will produce something like
|
2009-10-22 22:54:30 +02:00
|
|
|
// &"jump \"/home/apoenitz/dev/work/test1/test1.cpp\":242"
|
2008-12-02 12:01:29 +01:00
|
|
|
// ~"Continuing at 0x4058f3."
|
|
|
|
|
// ~"run1 (argc=1, argv=0x7fffbf1f5538) at test1.cpp:242"
|
|
|
|
|
// ~"242\t x *= 2;"
|
|
|
|
|
// 23^done"
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-10 16:17:40 +01:00
|
|
|
void GdbEngine::executeReturn()
|
2010-02-15 16:02:41 +01:00
|
|
|
{
|
2015-02-24 15:30:42 +01:00
|
|
|
CHECK_STATE(InferiorStopOk);
|
2010-02-15 16:02:41 +01:00
|
|
|
setTokenBarrier();
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunRequested();
|
2010-02-15 16:02:41 +01:00
|
|
|
showStatusMessage(tr("Immediate return from function requested..."), 5000);
|
2016-04-15 16:35:45 +02:00
|
|
|
runCommand({"-exec-return", RunRequest, CB(handleExecuteReturn)});
|
2010-02-15 16:02:41 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::executeRecordReverse(bool record)
|
|
|
|
|
{
|
|
|
|
|
if (record)
|
|
|
|
|
runCommand({"record full"});
|
|
|
|
|
else
|
|
|
|
|
runCommand({"record stop"});
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleExecuteReturn(const DebuggerResponse &response)
|
2010-02-15 16:02:41 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorStopOk();
|
2010-02-15 16:02:41 +01:00
|
|
|
updateAll();
|
2010-07-09 17:07:59 +02:00
|
|
|
return;
|
2010-02-15 16:02:41 +01:00
|
|
|
}
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyInferiorRunFailed();
|
2010-02-15 16:02:41 +01:00
|
|
|
}
|
2010-07-09 17:07:59 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-06 17:16:18 +02:00
|
|
|
Discards the results of all pending watch-updating commands.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-10-07 13:34:40 +02:00
|
|
|
This function is called at the beginning of all step, next, finish, and so on,
|
2008-12-02 12:01:29 +01:00
|
|
|
debugger functions.
|
2009-02-18 13:50:55 +01:00
|
|
|
If non-watch-updating commands with call-backs are still in the pipe,
|
|
|
|
|
it will complain.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
void GdbEngine::setTokenBarrier()
|
|
|
|
|
{
|
2012-03-01 11:23:47 +01:00
|
|
|
//QTC_ASSERT(m_nonDiscardableCount == 0, /**/);
|
2011-12-13 15:40:31 +01:00
|
|
|
bool good = true;
|
2015-02-06 10:30:25 +01:00
|
|
|
QHashIterator<int, DebuggerCommand> it(m_commandForToken);
|
2011-12-14 15:32:48 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2015-09-11 11:28:55 +02:00
|
|
|
if (!(m_flagsForToken.value(it.key()) & Discardable)) {
|
|
|
|
|
qDebug() << "TOKEN: " << it.key() << "CMD:" << it.value().function;
|
2011-12-13 15:40:31 +01:00
|
|
|
good = false;
|
|
|
|
|
}
|
2009-04-14 12:14:01 +02:00
|
|
|
}
|
2011-12-13 15:40:31 +01:00
|
|
|
QTC_ASSERT(good, return);
|
2009-03-04 10:11:42 +01:00
|
|
|
PENDING_DEBUG("\n--- token barrier ---\n");
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("--- token barrier ---", LogMiscInput);
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(LogTimeStamps))
|
2010-09-22 16:20:08 +02:00
|
|
|
showMessage(LogWindow::logTimeStamp(), LogMiscInput);
|
2008-12-02 12:01:29 +01:00
|
|
|
m_oldestAcceptableToken = currentToken();
|
2010-12-17 13:07:17 +01:00
|
|
|
m_stackNeeded = false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Breakpoint specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-10-22 22:54:30 +02:00
|
|
|
QString GdbEngine::breakLocation(const QString &file) const
|
|
|
|
|
{
|
|
|
|
|
QString where = m_fullToShortName.value(file);
|
|
|
|
|
if (where.isEmpty())
|
2019-05-28 13:49:26 +02:00
|
|
|
return FilePath::fromString(file).fileName();
|
2009-10-22 22:54:30 +02:00
|
|
|
return where;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QTC_ASSERT(data.type != UnknownBreakpointType, return QString());
|
2010-11-16 10:23:20 +01:00
|
|
|
// FIXME: Non-GCC-runtime
|
2010-11-16 11:06:09 +01:00
|
|
|
if (data.type == BreakpointAtThrow)
|
2016-06-07 17:04:53 +02:00
|
|
|
return QLatin1String("__cxa_throw");
|
2010-11-16 11:06:09 +01:00
|
|
|
if (data.type == BreakpointAtCatch)
|
2016-06-07 17:04:53 +02:00
|
|
|
return QLatin1String("__cxa_begin_catch");
|
2017-04-03 10:33:57 +03:00
|
|
|
if (data.type == BreakpointAtMain)
|
2017-09-27 08:22:02 +02:00
|
|
|
return mainFunction();
|
2010-11-25 14:33:13 +01:00
|
|
|
if (data.type == BreakpointByFunction)
|
2016-06-07 17:04:53 +02:00
|
|
|
return '"' + data.functionName + '"';
|
2010-11-25 14:33:13 +01:00
|
|
|
if (data.type == BreakpointByAddress)
|
|
|
|
|
return addressSpec(data.address);
|
|
|
|
|
|
2013-04-10 09:27:07 +02:00
|
|
|
BreakpointPathUsage usage = data.pathUsage;
|
|
|
|
|
if (usage == BreakpointPathUsageEngineDefault)
|
2013-05-24 12:40:06 +02:00
|
|
|
usage = BreakpointUseShortPath;
|
2013-04-10 09:27:07 +02:00
|
|
|
|
|
|
|
|
const QString fileName = usage == BreakpointUseFullPath
|
2010-11-16 12:17:00 +01:00
|
|
|
? data.fileName : breakLocation(data.fileName);
|
2010-03-04 15:42:09 +01:00
|
|
|
// The argument is simply a C-quoted version of the argument to the
|
|
|
|
|
// non-MI "break" command, including the "original" quoting it wants.
|
2016-06-07 17:04:53 +02:00
|
|
|
return "\"\\\"" + GdbMi::escapeCString(fileName) + "\\\":"
|
|
|
|
|
+ QString::number(data.lineNumber) + '"';
|
2010-03-04 15:42:09 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
QString GdbEngine::breakpointLocation2(const BreakpointParameters &data)
|
2011-03-04 18:08:56 +01:00
|
|
|
{
|
2013-04-10 09:27:07 +02:00
|
|
|
BreakpointPathUsage usage = data.pathUsage;
|
|
|
|
|
if (usage == BreakpointPathUsageEngineDefault)
|
2013-05-24 12:40:06 +02:00
|
|
|
usage = BreakpointUseShortPath;
|
2013-04-10 09:27:07 +02:00
|
|
|
|
|
|
|
|
const QString fileName = usage == BreakpointUseFullPath
|
2011-03-04 18:08:56 +01:00
|
|
|
? data.fileName : breakLocation(data.fileName);
|
2016-06-07 17:04:53 +02:00
|
|
|
return GdbMi::escapeCString(fileName) + ':' + QString::number(data.lineNumber);
|
2011-03-04 18:08:56 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleInsertInterpreterBreakpoint(const DebuggerResponse &response,
|
|
|
|
|
const Breakpoint &bp)
|
2015-10-14 13:26:22 +02:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
const bool pending = response.data["pending"].toInt();
|
2015-10-14 13:26:22 +02:00
|
|
|
if (pending) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointInsertOk(bp);
|
2015-10-14 13:26:22 +02:00
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setResponseId(response.data["number"].data());
|
|
|
|
|
bp->updateFromGdbOutput(response.data);
|
|
|
|
|
notifyBreakpointInsertOk(bp);
|
2015-10-14 13:26:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleInterpreterBreakpointModified(const GdbMi &data)
|
|
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
int modelId = data["modelid"].toInt();
|
|
|
|
|
Breakpoint bp = breakHandler()->findBreakpointByModelId(modelId);
|
|
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
bp->updateFromGdbOutput(data);
|
2015-10-14 13:26:22 +02:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-05-07 15:16:31 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (bp && response.resultClass == ResultDone) {
|
2010-05-07 15:16:31 +02:00
|
|
|
// "Hardware watchpoint 2: *0xbfffed40\n"
|
2016-06-07 17:04:53 +02:00
|
|
|
QString ba = response.consoleStreamOutput;
|
2013-05-03 18:26:10 +02:00
|
|
|
GdbMi wpt = response.data["wpt"];
|
2011-05-06 14:10:44 +02:00
|
|
|
if (wpt.isValid()) {
|
|
|
|
|
// Mac yields:
|
|
|
|
|
//>32^done,wpt={number="4",exp="*4355182176"}
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setResponseId(wpt["number"].data());
|
2016-06-07 17:04:53 +02:00
|
|
|
QString exp = wpt["exp"].data();
|
2011-05-11 15:24:50 +02:00
|
|
|
if (exp.startsWith('*'))
|
2019-01-17 01:38:54 +01:00
|
|
|
bp->setAddress(exp.midRef(1).toULongLong(nullptr, 0));
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_CHECK(!bp->needsChange());
|
|
|
|
|
notifyBreakpointInsertOk(bp);
|
2011-05-06 14:10:44 +02:00
|
|
|
} else if (ba.startsWith("Hardware watchpoint ")
|
2010-11-26 12:30:05 +01:00
|
|
|
|| ba.startsWith("Watchpoint ")) {
|
2011-05-06 14:10:44 +02:00
|
|
|
// Non-Mac: "Hardware watchpoint 2: *0xbfffed40\n"
|
2010-11-26 12:30:05 +01:00
|
|
|
const int end = ba.indexOf(':');
|
|
|
|
|
const int begin = ba.lastIndexOf(' ', end) + 1;
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString address = ba.mid(end + 2).trimmed();
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setResponseId(ba.mid(begin, end - begin));
|
2011-05-11 15:24:50 +02:00
|
|
|
if (address.startsWith('*'))
|
2019-01-17 01:38:54 +01:00
|
|
|
bp->setAddress(address.midRef(1).toULongLong(nullptr, 0));
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_CHECK(!bp->needsChange());
|
|
|
|
|
notifyBreakpointInsertOk(bp);
|
2010-05-07 15:16:31 +02:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("CANNOT PARSE WATCHPOINT FROM " + ba);
|
2010-05-07 15:16:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleCatchInsert(const DebuggerResponse &response, const Breakpoint &bp)
|
2011-03-04 19:26:11 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (response.resultClass == ResultDone)
|
|
|
|
|
notifyBreakpointInsertOk(bp);
|
2011-03-04 19:26:11 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
|
2013-03-07 23:11:42 +01:00
|
|
|
{
|
2015-01-10 01:07:01 +01:00
|
|
|
QTC_ASSERT(bp, return);
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString nr = bkpt["number"].data();
|
2013-03-07 23:11:42 +01:00
|
|
|
if (nr.contains('.')) {
|
|
|
|
|
// A sub-breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
SubBreakpoint sub = bp->findOrCreateSubBreakpoint(nr);
|
|
|
|
|
QTC_ASSERT(sub, return);
|
|
|
|
|
sub->params.updateFromGdbOutput(bkpt);
|
|
|
|
|
sub->params.type = bp->type();
|
2013-03-07 23:11:42 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The MI output format might change, see
|
|
|
|
|
// http://permalink.gmane.org/gmane.comp.gdb.patches/83936
|
2013-05-03 18:26:10 +02:00
|
|
|
const GdbMi locations = bkpt["locations"];
|
2013-03-07 23:11:42 +01:00
|
|
|
if (locations.isValid()) {
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &location : locations) {
|
2013-03-07 23:11:42 +01:00
|
|
|
// A sub-breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString subnr = location["number"].data();
|
|
|
|
|
SubBreakpoint sub = bp->findOrCreateSubBreakpoint(subnr);
|
|
|
|
|
QTC_ASSERT(sub, return);
|
|
|
|
|
sub->params.updateFromGdbOutput(location);
|
|
|
|
|
sub->params.type = bp->type();
|
2013-03-07 23:11:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A (the?) primary breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setResponseId(nr);
|
|
|
|
|
bp->updateFromGdbOutput(bkpt);
|
2013-03-07 23:11:42 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-03-04 15:42:09 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
if (bp->state() == BreakpointRemoveRequested) {
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2014-03-04 00:12:11 +01:00
|
|
|
// This delete was deferred. Act now.
|
2013-05-03 18:26:10 +02:00
|
|
|
const GdbMi mainbkpt = response.data["bkpt"];
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointRemoveProceeding(bp);
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("-break-delete " + mainbkpt["number"].data());
|
2018-03-21 18:01:33 +01:00
|
|
|
cmd.flags = NeedsTemporaryStop;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointRemoveOk(bp);
|
2011-10-28 12:26:00 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2011-07-04 13:37:01 +02:00
|
|
|
// The result is a list with the first entry marked "bkpt"
|
|
|
|
|
// and "unmarked" rest. The "bkpt" one seems to always be
|
|
|
|
|
// the "main" entry. Use the "main" entry to retrieve the
|
|
|
|
|
// already known data from the BreakpointManager, and then
|
|
|
|
|
// iterate over all items to update main- and sub-data.
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &bkpt : response.data)
|
2015-11-02 16:01:43 +01:00
|
|
|
handleBkpt(bkpt, bp);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (bp->needsChange()) {
|
|
|
|
|
bp->gotoState(BreakpointUpdateRequested, BreakpointInsertionProceeding);
|
|
|
|
|
updateBreakpoint(bp);
|
2015-11-02 16:01:43 +01:00
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointInsertOk(bp);
|
2010-11-30 12:47:53 +01:00
|
|
|
}
|
2013-05-03 18:26:10 +02:00
|
|
|
} else if (response.data["msg"].data().contains("Unknown option")) {
|
2010-12-16 17:58:43 +01:00
|
|
|
// Older version of gdb don't know the -a option to set tracepoints
|
|
|
|
|
// ^error,msg="mi_cmd_break_insert: Unknown option ``a''"
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const QString fileName = bp->fileName();
|
|
|
|
|
const int lineNumber = bp->lineNumber();
|
2016-06-07 17:04:53 +02:00
|
|
|
DebuggerCommand cmd("trace \"" + GdbMi::escapeCString(fileName) + "\":"
|
2016-06-09 11:42:37 +02:00
|
|
|
+ QString::number(lineNumber),
|
2018-03-21 18:01:33 +01:00
|
|
|
NeedsTemporaryStop);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-03-04 15:42:09 +01:00
|
|
|
} else {
|
|
|
|
|
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
|
2010-06-15 11:14:44 +02:00
|
|
|
// know how to do pending breakpoints using CLI but not MI. So try
|
2010-03-04 15:42:09 +01:00
|
|
|
// again with MI.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
DebuggerCommand cmd("break " + breakpointLocation2(bp->requestedParameters()),
|
2018-03-21 18:01:33 +01:00
|
|
|
NeedsTemporaryStop);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert2(r, bp); };
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-03-04 15:42:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakInsert2(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-03-04 15:42:09 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointInsertOk(bp);
|
2011-03-04 18:08:56 +01:00
|
|
|
} else {
|
|
|
|
|
// Note: gdb < 60800 doesn't "do" pending breakpoints.
|
|
|
|
|
// Not much we can do about it except implementing the
|
|
|
|
|
// logic on top of shared library events, and that's not
|
|
|
|
|
// worth the effort.
|
2010-03-04 15:42:09 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakDisable(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-03-25 13:33:38 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
// This should only be the requested state.
|
|
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
bp->setEnabled(false);
|
|
|
|
|
// GDB does *not* touch the subbreakpoints in that case
|
|
|
|
|
// bp->forFirstLevelChildren([&](const SubBreakpoint &l) { l->params.enabled = false; });
|
|
|
|
|
updateBreakpoint(bp); // Maybe there's more to do.
|
|
|
|
|
}
|
2010-11-15 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakEnable(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-11-15 16:22:51 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
// This should only be the requested state.
|
|
|
|
|
bp->setEnabled(true);
|
|
|
|
|
// GDB does *not* touch the subbreakpoints in that case
|
|
|
|
|
//bp->forFirstLevelChildren([&](const SubBreakpoint &l) { l->params.enabled = true; });
|
|
|
|
|
updateBreakpoint(bp); // Maybe there's more to do.
|
|
|
|
|
}
|
2010-11-30 12:47:53 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp)
|
2010-11-30 12:47:53 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
QTC_CHECK(response.resultClass == ResultDone);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
// Parsing is fragile. Assume we got what we asked for instead.
|
|
|
|
|
bp->setThreadSpec(bp->requestedParameters().threadSpec);
|
|
|
|
|
notifyBreakpointNeedsReinsertion(bp);
|
2015-01-10 01:07:01 +01:00
|
|
|
insertBreakpoint(bp);
|
2010-03-25 13:33:38 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp)
|
2011-11-04 14:03:48 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
QTC_CHECK(response.resultClass == ResultDone);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
notifyBreakpointNeedsReinsertion(bp);
|
2015-01-10 01:07:01 +01:00
|
|
|
insertBreakpoint(bp);
|
2011-11-04 14:03:48 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakIgnore(const DebuggerResponse &response, const Breakpoint &bp)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
// gdb 6.8:
|
|
|
|
|
// ignore 2 0:
|
|
|
|
|
// ~"Will stop next time breakpoint 2 is reached.\n"
|
|
|
|
|
// 28^done
|
|
|
|
|
// ignore 2 12:
|
|
|
|
|
// &"ignore 2 12\n"
|
|
|
|
|
// ~"Will ignore next 12 crossings of breakpoint 2.\n"
|
|
|
|
|
// 29^done
|
|
|
|
|
//
|
|
|
|
|
// gdb 6.3 does not produce any console output
|
2015-02-05 15:47:07 +01:00
|
|
|
QTC_CHECK(response.resultClass == ResultDone);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
2011-07-05 17:57:57 +02:00
|
|
|
//QString msg = _(response.consoleStreamOutput);
|
2010-11-15 16:22:51 +01:00
|
|
|
//if (msg.contains(__("Will stop next time breakpoint")))
|
2010-11-18 16:07:42 +01:00
|
|
|
// response.ignoreCount = _("0");
|
2010-11-15 16:22:51 +01:00
|
|
|
//else if (msg.contains(__("Will ignore next")))
|
2010-11-18 16:07:42 +01:00
|
|
|
// response.ignoreCount = data->ignoreCount;
|
2010-11-15 16:22:51 +01:00
|
|
|
// FIXME: this assumes it is doing the right thing...
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setIgnoreCount(bp->requestedParameters().ignoreCount);
|
|
|
|
|
bp->setCommand(bp->requestedParameters().command);
|
|
|
|
|
updateBreakpoint(bp); // Maybe there's more to do.
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::handleBreakCondition(const DebuggerResponse &, const Breakpoint &bp)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
2010-11-30 12:47:53 +01:00
|
|
|
// Can happen at invalid condition strings.
|
2015-02-05 15:47:07 +01:00
|
|
|
//QTC_CHECK(response.resultClass == ResultDone)
|
2010-11-15 16:22:51 +01:00
|
|
|
// We just assume it was successful. Otherwise we had to parse
|
|
|
|
|
// the output stream data.
|
|
|
|
|
// The following happens on Mac:
|
|
|
|
|
// QByteArray msg = response.data.findChild("msg").data();
|
2013-11-27 16:10:14 +01:00
|
|
|
// if (msg.startsWith("Error parsing breakpoint condition. "
|
|
|
|
|
// " Will try again when we hit the breakpoint."))
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->setCondition(bp->requestedParameters().condition);
|
|
|
|
|
updateBreakpoint(bp); // Maybe there's more to do.
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
bool GdbEngine::stateAcceptsBreakpointChanges() const
|
|
|
|
|
{
|
|
|
|
|
switch (state()) {
|
2017-11-15 17:12:03 +01:00
|
|
|
case EngineSetupRequested:
|
2010-11-10 16:33:11 +01:00
|
|
|
case InferiorRunRequested:
|
|
|
|
|
case InferiorRunOk:
|
|
|
|
|
case InferiorStopRequested:
|
|
|
|
|
case InferiorStopOk:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bool GdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
|
2010-10-05 11:01:14 +02:00
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
if (runParameters().startMode == AttachCore)
|
2014-12-12 08:26:55 +01:00
|
|
|
return false;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (bp.isCppBreakpoint())
|
2014-12-12 08:26:55 +01:00
|
|
|
return true;
|
2015-10-08 16:19:57 +02:00
|
|
|
return isNativeMixedEnabled();
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::insertBreakpoint(const Breakpoint &bp)
|
2010-11-10 16:33:11 +01:00
|
|
|
{
|
|
|
|
|
// Set up fallback in case of pending breakpoints which aren't handled
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
// by the MI interface.A
|
|
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
QTC_CHECK(bp->state() == BreakpointInsertionRequested);
|
|
|
|
|
notifyBreakpointInsertProceeding(bp);
|
2015-01-10 01:07:01 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const BreakpointParameters &requested = bp->requestedParameters();
|
2014-12-12 08:26:55 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (!requested.isCppBreakpoint()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("insertInterpreterBreakpoint", NeedsTemporaryStop);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->addToCommand(&cmd);
|
2015-10-14 13:26:22 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleInsertInterpreterBreakpoint(r, bp); };
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2014-12-12 08:26:55 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
const auto handleWatch = [this, bp](const DebuggerResponse &r) { handleWatchInsert(r, bp); };
|
|
|
|
|
const auto handleCatch = [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); };
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
BreakpointType type = requested.type;
|
2010-11-10 16:33:11 +01:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
DebuggerCommand cmd;
|
|
|
|
|
if (type == WatchpointAtAddress) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
cmd.function = "watch " + addressSpec(requested.address);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = handleWatch;
|
|
|
|
|
} else if (type == WatchpointAtExpression) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
cmd.function = "watch " + requested.expression;
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = handleWatch;
|
|
|
|
|
} else if (type == BreakpointAtFork) {
|
|
|
|
|
cmd.function = "catch fork";
|
|
|
|
|
cmd.callback = handleCatch;
|
2018-03-21 18:01:33 +01:00
|
|
|
cmd.flags = NeedsTemporaryStop;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2015-09-11 11:28:55 +02:00
|
|
|
// Another one...
|
|
|
|
|
cmd.function = "catch vfork";
|
|
|
|
|
} else if (type == BreakpointAtExec) {
|
|
|
|
|
cmd.function = "catch exec";
|
|
|
|
|
cmd.callback = handleCatch;
|
|
|
|
|
} else if (type == BreakpointAtSysCall) {
|
|
|
|
|
cmd.function = "catch syscall";
|
|
|
|
|
cmd.callback = handleCatch;
|
2013-11-27 16:10:14 +01:00
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (requested.isTracepoint()) {
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function = "-break-insert -a -f ";
|
|
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
int spec = requested.threadSpec;
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function = "-break-insert ";
|
|
|
|
|
if (spec >= 0)
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.function += "-p " + QString::number(spec);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function += " -f ";
|
|
|
|
|
}
|
2012-08-21 14:16:07 +02:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (requested.oneShot)
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function += "-t ";
|
2012-08-21 14:16:07 +02:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (!requested.enabled)
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function += "-d ";
|
2013-02-26 13:54:45 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (int ignoreCount = requested.ignoreCount)
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.function += "-i " + QString::number(ignoreCount) + ' ';
|
2013-02-26 11:59:40 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QString condition = requested.condition;
|
2015-09-11 11:28:55 +02:00
|
|
|
if (!condition.isEmpty())
|
2016-04-06 18:49:51 +02:00
|
|
|
cmd.function += " -c \"" + condition.replace('"', "\\\"") + "\" ";
|
2013-02-14 15:30:31 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
cmd.function += breakpointLocation(requested);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); };
|
|
|
|
|
}
|
2018-03-21 18:01:33 +01:00
|
|
|
cmd.flags = NeedsTemporaryStop;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::updateBreakpoint(const Breakpoint &bp)
|
2010-11-10 16:33:11 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
const BreakpointParameters &requested = bp->requestedParameters();
|
|
|
|
|
QTC_ASSERT(requested.type != UnknownBreakpointType, return);
|
|
|
|
|
QTC_ASSERT(!bp->responseId().isEmpty(), return);
|
|
|
|
|
const QString bpnr = bp->responseId();
|
|
|
|
|
const BreakpointState state = bp->state();
|
|
|
|
|
if (state == BreakpointUpdateRequested)
|
|
|
|
|
notifyBreakpointChangeProceeding(bp);
|
|
|
|
|
const BreakpointState state2 = bp->state();
|
|
|
|
|
QTC_ASSERT(state2 == BreakpointUpdateProceeding, qDebug() << state2);
|
2010-11-30 12:47:53 +01:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
DebuggerCommand cmd;
|
2018-12-10 21:08:38 -08:00
|
|
|
// FIXME: See QTCREATORBUG-21611, QTCREATORBUG-21616
|
|
|
|
|
// if (!bp->isPending() && requested.threadSpec != bp->threadSpec()) {
|
|
|
|
|
// // The only way to change this seems to be to re-set the bp completely.
|
|
|
|
|
// cmd.function = "-break-delete " + bpnr;
|
|
|
|
|
// cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakThreadSpec(r, bp); };
|
|
|
|
|
// } else if (!bp->isPending() && requested.lineNumber != bp->lineNumber()) {
|
|
|
|
|
// // The only way to change this seems to be to re-set the bp completely.
|
|
|
|
|
// cmd.function = "-break-delete " + bpnr;
|
|
|
|
|
// cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakLineNumber(r, bp); };
|
|
|
|
|
// } else if
|
|
|
|
|
if (requested.command != bp->command()) {
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function = "-break-commands " + bpnr;
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
for (QString command : requested.command.split('\n')) {
|
2018-08-02 22:07:26 +03:00
|
|
|
if (!command.isEmpty()) {
|
|
|
|
|
// escape backslashes and quotes
|
|
|
|
|
command.replace('\\', "\\\\");
|
|
|
|
|
command.replace('"', "\\\"");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.function += " \"" + command + '"';
|
2018-08-02 22:07:26 +03:00
|
|
|
}
|
2011-02-04 11:33:45 +01:00
|
|
|
}
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); };
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (!requested.conditionsMatch(bp->condition())) {
|
|
|
|
|
cmd.function = "condition " + bpnr + ' ' + requested.condition;
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakCondition(r, bp); };
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (requested.ignoreCount != bp->ignoreCount()) {
|
|
|
|
|
cmd.function = "ignore " + bpnr + ' ' + QString::number(requested.ignoreCount);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); };
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (!requested.enabled && bp->isEnabled()) {
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function = "-break-disable " + bpnr;
|
|
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakDisable(r, bp); };
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
} else if (requested.enabled && !bp->isEnabled()) {
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.function = "-break-enable " + bpnr;
|
|
|
|
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakEnable(r, bp); };
|
|
|
|
|
} else {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointChangeOk(bp);
|
2010-11-30 12:47:53 +01:00
|
|
|
return;
|
2010-11-15 16:22:51 +01:00
|
|
|
}
|
2018-03-21 18:01:33 +01:00
|
|
|
cmd.flags = NeedsTemporaryStop;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::enableSubBreakpoint(const SubBreakpoint &sbp, bool on)
|
2018-01-31 10:46:57 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(sbp, return);
|
|
|
|
|
DebuggerCommand cmd((on ? "-break-enable " : "-break-disable ") + sbp->responseId);
|
2018-01-31 10:46:57 +01:00
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
void GdbEngine::removeBreakpoint(const Breakpoint &bp)
|
2010-11-10 16:33:11 +01:00
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
QTC_ASSERT(bp, return);
|
|
|
|
|
QTC_CHECK(bp->state() == BreakpointRemoveRequested);
|
2015-01-22 12:05:00 +01:00
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const BreakpointParameters &requested = bp->requestedParameters();
|
|
|
|
|
if (!requested.isCppBreakpoint()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("removeInterpreterBreakpoint");
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
bp->addToCommand(&cmd);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointRemoveOk(bp);
|
2015-01-22 12:05:00 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (!bp->responseId().isEmpty()) {
|
2011-10-28 12:26:00 +02:00
|
|
|
// We already have a fully inserted breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointRemoveProceeding(bp);
|
|
|
|
|
showMessage(QString("DELETING BP %1 IN %2").arg(bp->responseId()).arg(bp->fileName()));
|
|
|
|
|
DebuggerCommand cmd("-break-delete " + bp->responseId(), NeedsTemporaryStop);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2015-02-23 14:30:14 +01:00
|
|
|
|
|
|
|
|
// Pretend it succeeds without waiting for response. Feels better.
|
|
|
|
|
// Otherwise, clicking in the gutter leaves the breakpoint visible
|
|
|
|
|
// for quite some time, so the user assumes a mis-click and clicks
|
|
|
|
|
// again, effectivly re-introducing the breakpoint.
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
notifyBreakpointRemoveOk(bp);
|
2015-02-23 14:30:14 +01:00
|
|
|
|
2011-10-28 12:26:00 +02:00
|
|
|
} else {
|
|
|
|
|
// Breakpoint was scheduled to be inserted, but we haven't had
|
|
|
|
|
// an answer so far. Postpone activity by doing nothing.
|
|
|
|
|
}
|
2010-10-05 11:01:14 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Modules specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static QString dotEscape(QString str)
|
|
|
|
|
{
|
|
|
|
|
str.replace(' ', '.');
|
|
|
|
|
str.replace('\\', '.');
|
|
|
|
|
str.replace('/', '.');
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-16 13:34:00 +01:00
|
|
|
void GdbEngine::loadSymbols(const QString &modulePath)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
// FIXME: gdb does not understand quoted names here (tested with 6.8)
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"sharedlibrary " + dotEscape(modulePath)});
|
2009-10-28 22:08:58 +01:00
|
|
|
reloadModulesInternal();
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack();
|
2010-12-21 12:41:34 +01:00
|
|
|
updateLocals();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::loadAllSymbols()
|
|
|
|
|
{
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"sharedlibrary .*"});
|
2009-10-28 22:08:58 +01:00
|
|
|
reloadModulesInternal();
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack();
|
2010-12-21 12:41:34 +01:00
|
|
|
updateLocals();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-12-21 13:34:59 +01:00
|
|
|
void GdbEngine::loadSymbolsForStack()
|
|
|
|
|
{
|
|
|
|
|
bool needUpdate = false;
|
|
|
|
|
const Modules &modules = modulesHandler()->modules();
|
2019-06-24 14:54:47 +02:00
|
|
|
stackHandler()->forItemsAtLevel<2>([modules, &needUpdate, this](StackFrameItem *frameItem) {
|
2019-06-24 12:28:07 +02:00
|
|
|
const StackFrame &frame = frameItem->frame;
|
2016-06-07 17:04:53 +02:00
|
|
|
if (frame.function == "??") {
|
2010-12-21 14:41:17 +01:00
|
|
|
//qDebug() << "LOAD FOR " << frame.address;
|
2018-05-30 15:42:51 +02:00
|
|
|
for (const Module &module : modules) {
|
2010-12-21 13:34:59 +01:00
|
|
|
if (module.startAddress <= frame.address
|
|
|
|
|
&& frame.address < module.endAddress) {
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"sharedlibrary " + dotEscape(module.modulePath)});
|
2010-12-21 13:34:59 +01:00
|
|
|
needUpdate = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-24 12:28:07 +02:00
|
|
|
});
|
2010-12-21 13:34:59 +01:00
|
|
|
if (needUpdate) {
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack();
|
2010-12-21 13:34:59 +01:00
|
|
|
updateLocals();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
static void handleShowModuleSymbols(const DebuggerResponse &response,
|
|
|
|
|
const QString &modulePath, const QString &fileName)
|
2010-11-26 09:58:34 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2012-11-07 18:31:17 +01:00
|
|
|
Symbols symbols;
|
2010-11-26 09:58:34 +01:00
|
|
|
QFile file(fileName);
|
|
|
|
|
file.open(QIODevice::ReadOnly);
|
2010-12-16 11:25:28 +01:00
|
|
|
// Object file /opt/dev/qt/lib/libQtNetworkMyns.so.4:
|
2010-11-26 09:58:34 +01:00
|
|
|
// [ 0] A 0x16bd64 _DYNAMIC moc_qudpsocket.cpp
|
2010-12-16 11:25:28 +01:00
|
|
|
// [12] S 0xe94680 _ZN4myns5QFileC1Ev section .plt myns::QFile::QFile()
|
2016-06-07 17:04:53 +02:00
|
|
|
foreach (const QString &line, QString::fromLocal8Bit(file.readAll()).split('\n')) {
|
2010-11-26 09:58:34 +01:00
|
|
|
if (line.isEmpty())
|
|
|
|
|
continue;
|
2010-11-26 13:06:03 +01:00
|
|
|
if (line.at(0) != '[')
|
2010-11-26 09:58:34 +01:00
|
|
|
continue;
|
|
|
|
|
int posCode = line.indexOf(']') + 2;
|
|
|
|
|
int posAddress = line.indexOf("0x", posCode);
|
|
|
|
|
if (posAddress == -1)
|
|
|
|
|
continue;
|
|
|
|
|
int posName = line.indexOf(" ", posAddress);
|
2012-06-13 13:13:26 +02:00
|
|
|
int lenAddress = posName - posAddress;
|
2010-11-26 09:58:34 +01:00
|
|
|
int posSection = line.indexOf(" section ");
|
|
|
|
|
int lenName = 0;
|
|
|
|
|
int lenSection = 0;
|
|
|
|
|
int posDemangled = 0;
|
|
|
|
|
if (posSection == -1) {
|
|
|
|
|
lenName = line.size() - posName;
|
|
|
|
|
posDemangled = posName;
|
2009-04-15 12:01:58 +02:00
|
|
|
} else {
|
2010-11-26 09:58:34 +01:00
|
|
|
lenName = posSection - posName;
|
|
|
|
|
posSection += 10;
|
|
|
|
|
posDemangled = line.indexOf(' ', posSection + 1);
|
|
|
|
|
if (posDemangled == -1) {
|
|
|
|
|
lenSection = line.size() - posSection;
|
|
|
|
|
} else {
|
|
|
|
|
lenSection = posDemangled - posSection;
|
|
|
|
|
posDemangled += 1;
|
|
|
|
|
}
|
2009-04-15 12:01:58 +02:00
|
|
|
}
|
2010-11-26 09:58:34 +01:00
|
|
|
int lenDemangled = 0;
|
|
|
|
|
if (posDemangled != -1)
|
|
|
|
|
lenDemangled = line.size() - posDemangled;
|
|
|
|
|
Symbol symbol;
|
2016-06-07 17:04:53 +02:00
|
|
|
symbol.state = line.mid(posCode, 1);
|
|
|
|
|
symbol.address = line.mid(posAddress, lenAddress);
|
|
|
|
|
symbol.name = line.mid(posName, lenName);
|
|
|
|
|
symbol.section = line.mid(posSection, lenSection);
|
|
|
|
|
symbol.demangled = line.mid(posDemangled, lenDemangled);
|
2012-11-07 18:31:17 +01:00
|
|
|
symbols.push_back(symbol);
|
2009-04-15 12:01:58 +02:00
|
|
|
}
|
2010-11-26 09:58:34 +01:00
|
|
|
file.close();
|
|
|
|
|
file.remove();
|
2014-10-22 13:04:47 +02:00
|
|
|
Internal::showModuleSymbols(modulePath, symbols);
|
2010-11-26 09:58:34 +01:00
|
|
|
} else {
|
2015-02-06 01:26:47 +01:00
|
|
|
AsynchronousMessageBox::critical(GdbEngine::tr("Cannot Read Symbols"),
|
|
|
|
|
GdbEngine::tr("Cannot read symbols for module \"%1\".").arg(fileName));
|
2010-11-26 09:58:34 +01:00
|
|
|
}
|
2009-04-15 12:01:58 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::requestModuleSymbols(const QString &modulePath)
|
|
|
|
|
{
|
2017-01-19 16:44:22 +01:00
|
|
|
Utils::TemporaryFile tf("gdbsymbols");
|
2015-02-06 01:26:47 +01:00
|
|
|
if (!tf.open())
|
|
|
|
|
return;
|
|
|
|
|
QString fileName = tf.fileName();
|
|
|
|
|
tf.close();
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("maint print msymbols \"" + fileName + "\" " + modulePath, NeedsTemporaryStop);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [modulePath, fileName](const DebuggerResponse &r) {
|
|
|
|
|
handleShowModuleSymbols(r, modulePath, fileName);
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2015-02-06 01:26:47 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-07 18:31:17 +01:00
|
|
|
void GdbEngine::requestModuleSections(const QString &moduleName)
|
|
|
|
|
{
|
|
|
|
|
// There seems to be no way to get the symbols from a single .so.
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("maint info section ALLOBJ", NeedsTemporaryStop);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, moduleName](const DebuggerResponse &r) {
|
|
|
|
|
handleShowModuleSections(r, moduleName);
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2012-11-07 18:31:17 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::handleShowModuleSections(const DebuggerResponse &response,
|
|
|
|
|
const QString &moduleName)
|
2012-11-07 18:31:17 +01:00
|
|
|
{
|
|
|
|
|
// ~" 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"
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QStringList lines = response.consoleStreamOutput.split('\n');
|
2018-10-07 22:38:47 +03:00
|
|
|
const QString prefix = " Object file: ";
|
2012-11-07 18:31:17 +01:00
|
|
|
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) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QStringList items = line.split(' ', QString::SkipEmptyParts);
|
2012-11-07 18:31:17 +01:00
|
|
|
QString fromTo = items.value(0, QString());
|
2016-06-07 17:04:53 +02:00
|
|
|
const int pos = fromTo.indexOf('-');
|
2012-11-07 18:31:17 +01:00
|
|
|
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())
|
2014-10-22 13:04:47 +02:00
|
|
|
Internal::showModuleSections(moduleName, sections);
|
2012-11-07 18:31:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void GdbEngine::reloadModules()
|
2009-10-28 22:08:58 +01:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
if (state() == InferiorRunOk || state() == InferiorStopOk)
|
2009-10-28 22:08:58 +01:00
|
|
|
reloadModulesInternal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::reloadModulesInternal()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-12-13 09:46:51 +01:00
|
|
|
runCommand({"info shared", NeedsTemporaryStop, CB(handleModulesList)});
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-03-16 13:34:00 +01:00
|
|
|
static QString nameFromPath(const QString &path)
|
|
|
|
|
{
|
|
|
|
|
return QFileInfo(path).baseName();
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleModulesList(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2012-06-02 03:30:21 +02:00
|
|
|
ModulesHandler *handler = modulesHandler();
|
|
|
|
|
Module module;
|
2009-10-02 13:24:41 +02:00
|
|
|
// That's console-based output, likely Linux or Windows,
|
2011-03-24 14:21:52 +01:00
|
|
|
// but we can avoid the target dependency here.
|
2016-06-07 17:04:53 +02:00
|
|
|
QString data = response.consoleStreamOutput;
|
2008-12-02 12:01:29 +01:00
|
|
|
QTextStream ts(&data, QIODevice::ReadOnly);
|
2012-06-02 03:30:21 +02:00
|
|
|
bool found = false;
|
2008-12-02 12:01:29 +01:00
|
|
|
while (!ts.atEnd()) {
|
|
|
|
|
QString line = ts.readLine();
|
|
|
|
|
QString symbolsRead;
|
|
|
|
|
QTextStream ts(&line, QIODevice::ReadOnly);
|
2016-06-07 17:04:53 +02:00
|
|
|
if (line.startsWith("0x")) {
|
2009-10-23 15:46:39 +02:00
|
|
|
ts >> module.startAddress >> module.endAddress >> symbolsRead;
|
2012-03-16 13:34:00 +01:00
|
|
|
module.modulePath = ts.readLine().trimmed();
|
|
|
|
|
module.moduleName = nameFromPath(module.modulePath);
|
2010-07-22 16:15:50 +02:00
|
|
|
module.symbolsRead =
|
2016-06-07 17:04:53 +02:00
|
|
|
(symbolsRead == "Yes" ? Module::ReadOk : Module::ReadFailed);
|
2012-06-02 03:30:21 +02:00
|
|
|
handler->updateModule(module);
|
|
|
|
|
found = true;
|
2016-06-07 17:04:53 +02:00
|
|
|
} else if (line.trimmed().startsWith("No")) {
|
2009-10-23 15:46:39 +02:00
|
|
|
// gdb 6.4 symbianelf
|
|
|
|
|
ts >> symbolsRead;
|
2016-06-07 17:04:53 +02:00
|
|
|
QTC_ASSERT(symbolsRead == "No", continue);
|
2011-01-06 09:34:45 +01:00
|
|
|
module.startAddress = 0;
|
|
|
|
|
module.endAddress = 0;
|
2012-03-16 13:34:00 +01:00
|
|
|
module.modulePath = ts.readLine().trimmed();
|
|
|
|
|
module.moduleName = nameFromPath(module.modulePath);
|
2012-06-02 03:30:21 +02:00
|
|
|
handler->updateModule(module);
|
|
|
|
|
found = true;
|
2009-10-23 15:46:39 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-06-02 03:30:21 +02:00
|
|
|
if (!found) {
|
2009-03-12 12:00:53 +01:00
|
|
|
// Mac has^done,shlib-info={num="1",name="dyld",kind="-",
|
|
|
|
|
// dyld-addr="0x8fe00000",reason="dyld",requested-state="Y",
|
|
|
|
|
// state="Y",path="/usr/lib/dyld",description="/usr/lib/dyld",
|
|
|
|
|
// loaded_addr="0x8fe00000",slide="0x0",prefix="__dyld_"},
|
|
|
|
|
// shlib-info={...}...
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data) {
|
2016-06-07 17:04:53 +02:00
|
|
|
module.modulePath = item["path"].data();
|
2012-03-16 13:34:00 +01:00
|
|
|
module.moduleName = nameFromPath(module.modulePath);
|
2013-05-03 18:26:10 +02:00
|
|
|
module.symbolsRead = (item["state"].data() == "Y")
|
2010-07-22 16:15:50 +02:00
|
|
|
? Module::ReadOk : Module::ReadFailed;
|
2010-12-21 13:34:59 +01:00
|
|
|
module.startAddress =
|
2018-07-23 22:28:49 +02:00
|
|
|
item["loaded_addr"].data().toULongLong(nullptr, 0);
|
2010-12-21 13:34:59 +01:00
|
|
|
module.endAddress = 0; // FIXME: End address not easily available.
|
2012-06-02 03:30:21 +02:00
|
|
|
handler->updateModule(module);
|
2009-03-12 12:00:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-06-02 03:30:21 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-22 16:53:01 +02:00
|
|
|
void GdbEngine::examineModules()
|
|
|
|
|
{
|
2012-06-01 19:01:37 +02:00
|
|
|
ModulesHandler *handler = modulesHandler();
|
2018-05-30 15:42:51 +02:00
|
|
|
for (const Module &module : handler->modules()) {
|
2012-06-06 16:08:59 +02:00
|
|
|
if (module.elfData.symbolsType == UnknownSymbols)
|
2012-06-04 18:06:59 +02:00
|
|
|
handler->updateModule(module);
|
2010-07-22 16:53:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-17 14:08:49 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Source files specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void GdbEngine::reloadSourceFiles()
|
2009-10-28 22:08:58 +01:00
|
|
|
{
|
2015-09-11 11:28:55 +02:00
|
|
|
if ((state() == InferiorRunOk || state() == InferiorStopOk) && !m_sourcesListUpdating) {
|
|
|
|
|
m_sourcesListUpdating = true;
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("-file-list-exec-source-files", NeedsTemporaryStop);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &response) {
|
|
|
|
|
m_sourcesListUpdating = false;
|
|
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
QMap<QString, QString> oldShortToFull = m_shortToFullName;
|
|
|
|
|
m_shortToFullName.clear();
|
|
|
|
|
m_fullToShortName.clear();
|
|
|
|
|
// "^done,files=[{file="../../../../bin/dumper/dumper.cpp",
|
|
|
|
|
// fullname="/data5/dev/ide/main/bin/dumper/dumper.cpp"},
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data["files"]) {
|
2015-09-11 11:28:55 +02:00
|
|
|
GdbMi fileName = item["file"];
|
|
|
|
|
if (fileName.data().endsWith("<built-in>"))
|
|
|
|
|
continue;
|
|
|
|
|
GdbMi fullName = item["fullname"];
|
2016-06-07 17:04:53 +02:00
|
|
|
QString file = fileName.data();
|
2015-09-11 11:28:55 +02:00
|
|
|
QString full;
|
|
|
|
|
if (fullName.isValid()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
full = cleanupFullName(fullName.data());
|
2015-09-11 11:28:55 +02:00
|
|
|
m_fullToShortName[full] = file;
|
|
|
|
|
}
|
|
|
|
|
m_shortToFullName[file] = full;
|
|
|
|
|
}
|
|
|
|
|
if (m_shortToFullName != oldShortToFull)
|
|
|
|
|
sourceFilesHandler()->setSourceFiles(m_shortToFullName);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2015-09-11 11:28:55 +02:00
|
|
|
}
|
2009-02-17 14:08:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Stack specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-08-15 17:28:00 +02:00
|
|
|
void GdbEngine::selectThread(const Thread &thread)
|
2009-10-05 12:00:47 +02:00
|
|
|
{
|
2018-08-15 17:28:00 +02:00
|
|
|
showStatusMessage(tr("Retrieving data for stack view thread %1...")
|
|
|
|
|
.arg(thread->id()), 10000);
|
|
|
|
|
DebuggerCommand cmd("-thread-select " + thread->id(), Discardable);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this](const DebuggerResponse &) {
|
|
|
|
|
QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk);
|
|
|
|
|
showStatusMessage(tr("Retrieving data for stack view..."), 3000);
|
|
|
|
|
reloadStack(); // Will reload registers.
|
|
|
|
|
updateLocals();
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-10-05 12:00:47 +02:00
|
|
|
void GdbEngine::reloadFullStack()
|
|
|
|
|
{
|
2010-01-14 15:25:53 +01:00
|
|
|
PENDING_DEBUG("RELOAD FULL STACK");
|
2013-11-17 21:36:37 +01:00
|
|
|
resetLocation();
|
2015-02-11 16:05:55 +01:00
|
|
|
DebuggerCommand cmd = stackCommand(-1);
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, true); };
|
2016-12-13 13:37:05 +01:00
|
|
|
cmd.flags = Discardable;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2009-10-05 12:00:47 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
void GdbEngine::loadAdditionalQmlStack()
|
2014-02-07 18:10:02 +01:00
|
|
|
{
|
2016-10-11 14:58:55 +02:00
|
|
|
DebuggerCommand cmd = stackCommand(-1);
|
|
|
|
|
cmd.arg("extraqml", "1");
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, true); };
|
2016-12-13 13:37:05 +01:00
|
|
|
cmd.flags = Discardable;
|
2015-09-11 11:28:55 +02:00
|
|
|
runCommand(cmd);
|
2014-02-07 18:10:02 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-11 16:05:55 +01:00
|
|
|
DebuggerCommand GdbEngine::stackCommand(int depth)
|
2014-12-12 09:22:57 +01:00
|
|
|
{
|
2015-10-27 16:13:04 +01:00
|
|
|
DebuggerCommand cmd("fetchStack");
|
2015-02-11 16:05:55 +01:00
|
|
|
cmd.arg("limit", depth);
|
2015-10-08 16:19:57 +02:00
|
|
|
cmd.arg("nativemixed", isNativeMixedActive());
|
2014-12-12 09:22:57 +01:00
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::reloadStack()
|
2009-10-05 12:00:47 +02:00
|
|
|
{
|
2010-01-14 15:25:53 +01:00
|
|
|
PENDING_DEBUG("RELOAD STACK");
|
2015-02-11 16:05:55 +01:00
|
|
|
DebuggerCommand cmd = stackCommand(action(MaximalStackDepth)->value().toInt());
|
|
|
|
|
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); };
|
2016-12-13 13:37:05 +01:00
|
|
|
cmd.flags = Discardable;
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2009-10-05 12:00:47 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isFull)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass != ResultDone) {
|
2009-10-05 12:00:47 +02:00
|
|
|
// That always happens on symbian gdb with
|
|
|
|
|
// ^error,data={msg="Previous frame identical to this frame (corrupt stack?)"
|
2011-07-05 17:57:57 +02:00
|
|
|
// logStreamOutput: "Previous frame identical to this frame (corrupt stack?)\n"
|
2009-10-05 12:00:47 +02:00
|
|
|
//qDebug() << "LISTING STACK FAILED: " << response.toString();
|
2010-11-24 11:44:43 +01:00
|
|
|
reloadRegisters();
|
2009-10-05 12:00:47 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-12-15 18:28:58 +01:00
|
|
|
GdbMi stack = response.data["stack"]; // C++
|
|
|
|
|
//if (!frames.isValid() || frames.childCount() == 0) // Mixed.
|
|
|
|
|
GdbMi frames = stack["frames"];
|
|
|
|
|
if (!frames.isValid())
|
|
|
|
|
isFull = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-10-09 15:00:20 +02:00
|
|
|
stackHandler()->setFramesAndCurrentIndex(frames, isFull);
|
|
|
|
|
activateFrame(stackHandler()->currentIndex());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::activateFrame(int frameIndex)
|
|
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
|
2010-06-15 11:42:49 +02:00
|
|
|
StackHandler *handler = stackHandler();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2019-06-24 12:28:07 +02:00
|
|
|
if (handler->isSpecialFrame(frameIndex)) {
|
2009-04-06 17:27:15 +02:00
|
|
|
reloadFullStack();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-10-02 12:31:19 +02:00
|
|
|
|
2010-06-15 11:42:49 +02:00
|
|
|
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
2010-11-22 17:12:02 +01:00
|
|
|
handler->setCurrentIndex(frameIndex);
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
gotoCurrentLocation();
|
2014-12-12 09:22:57 +01:00
|
|
|
|
|
|
|
|
if (handler->frameAt(frameIndex).language != QmlLanguage) {
|
|
|
|
|
// Assuming the command always succeeds this saves a roundtrip.
|
|
|
|
|
// Otherwise the lines below would need to get triggered
|
|
|
|
|
// after a response to this -stack-select-frame here.
|
|
|
|
|
//if (!m_currentThread.isEmpty())
|
|
|
|
|
// cmd += " --thread " + m_currentThread;
|
2016-06-07 17:04:53 +02:00
|
|
|
runCommand({"-stack-select-frame " + QString::number(frameIndex), Discardable});
|
2014-12-12 09:22:57 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-22 17:12:02 +01:00
|
|
|
updateLocals();
|
|
|
|
|
reloadRegisters();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleThreadInfo(const DebuggerResponse &response)
|
2010-05-17 17:38:31 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2012-10-24 16:48:09 +02:00
|
|
|
ThreadsHandler *handler = threadsHandler();
|
2018-08-30 11:52:37 +02:00
|
|
|
handler->setThreads(response.data);
|
2019-03-22 07:35:48 +01:00
|
|
|
updateState(); // Adjust Threads combobox.
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(ShowThreadNames)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
runCommand({"threadnames " + action(MaximalStackDepth)->value().toString(),
|
2015-11-03 12:01:57 +01:00
|
|
|
Discardable, CB(handleThreadNames)});
|
2010-10-27 14:21:33 +02:00
|
|
|
}
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack(); // Will trigger register reload.
|
2010-05-17 17:38:31 +02:00
|
|
|
} else {
|
|
|
|
|
// Fall back for older versions: Try to get at least a list
|
|
|
|
|
// of running threads.
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"-thread-list-ids", Discardable, CB(handleThreadListIds)});
|
2010-05-17 17:38:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleThreadListIds(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
// "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
|
2010-05-17 17:38:31 +02:00
|
|
|
// In gdb 7.1+ additionally: current-thread-id="1"
|
2012-10-19 16:37:57 +02:00
|
|
|
ThreadsHandler *handler = threadsHandler();
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data["thread-ids"]) {
|
2008-12-02 12:01:29 +01:00
|
|
|
ThreadData thread;
|
2018-08-15 17:28:00 +02:00
|
|
|
thread.id = item.data();
|
2012-10-19 16:37:57 +02:00
|
|
|
handler->updateThread(thread);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2015-02-06 01:26:47 +01:00
|
|
|
reloadStack(); // Will trigger register reload.
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleThreadNames(const DebuggerResponse &response)
|
2010-09-13 12:37:30 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2012-10-19 16:37:57 +02:00
|
|
|
ThreadsHandler *handler = threadsHandler();
|
2010-09-13 12:37:30 +02:00
|
|
|
GdbMi names;
|
2011-07-05 17:57:57 +02:00
|
|
|
names.fromString(response.consoleStreamOutput);
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &name : names) {
|
2012-10-19 16:37:57 +02:00
|
|
|
ThreadData thread;
|
2018-08-15 17:28:00 +02:00
|
|
|
thread.id = name["id"].data();
|
2018-09-16 12:38:29 +03:00
|
|
|
// Core is unavailable in core dump. Allow the user to provide it.
|
|
|
|
|
thread.core = name["core"].data();
|
2015-12-11 13:28:21 +01:00
|
|
|
thread.name = decodeData(name["value"].data(), name["valueencoded"].data());
|
2012-10-19 16:37:57 +02:00
|
|
|
handler->updateThread(thread);
|
2010-09-13 12:37:30 +02:00
|
|
|
}
|
2019-03-22 07:35:48 +01:00
|
|
|
updateState();
|
2010-09-13 12:37:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-02 17:25:14 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Snapshot specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-07-21 09:42:33 +02:00
|
|
|
void GdbEngine::createSnapshot()
|
2010-02-02 17:25:14 +01:00
|
|
|
{
|
|
|
|
|
QString fileName;
|
2017-01-19 16:44:22 +01:00
|
|
|
Utils::TemporaryFile tf("gdbsnapshot");
|
2010-02-02 17:25:14 +01:00
|
|
|
if (tf.open()) {
|
|
|
|
|
fileName = tf.fileName();
|
|
|
|
|
tf.close();
|
2014-05-27 17:51:55 +02:00
|
|
|
// This must not be quoted, it doesn't work otherwise.
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("gcore " + fileName, NeedsTemporaryStop | ConsoleCommand);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, fileName](const DebuggerResponse &r) { handleMakeSnapshot(r, fileName); };
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-02-02 17:25:14 +01:00
|
|
|
} else {
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Snapshot Creation Error"),
|
2010-02-02 17:25:14 +01:00
|
|
|
tr("Cannot create snapshot file."));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile)
|
2010-02-02 17:25:14 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
emit attachToCoreRequested(coreFile);
|
2010-02-02 17:25:14 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Snapshot Creation Error"),
|
2016-06-07 17:04:53 +02:00
|
|
|
tr("Cannot create snapshot:") + '\n' + msg);
|
2010-02-02 17:25:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Register specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void GdbEngine::reloadRegisters()
|
|
|
|
|
{
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
if (!isRegistersWindowVisible())
|
2010-06-28 09:10:20 +02:00
|
|
|
return;
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
2009-11-30 16:45:15 +01:00
|
|
|
return;
|
2014-12-17 13:14:29 +01:00
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
|
if (!m_registerNamesListed) {
|
2015-07-21 12:52:18 +02:00
|
|
|
// The MI version does not give register size.
|
2015-09-11 11:28:55 +02:00
|
|
|
// runCommand("-data-list-register-names", CB(handleRegisterListNames));
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"maintenance print raw-registers",
|
2015-11-03 12:01:57 +01:00
|
|
|
CB(handleRegisterListing)});
|
2014-12-17 13:14:29 +01:00
|
|
|
m_registerNamesListed = true;
|
|
|
|
|
}
|
|
|
|
|
// Can cause i386-linux-nat.c:571: internal-error: Got request
|
|
|
|
|
// for bad register number 41.\nA problem internal to GDB has been detected.
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"-data-list-register-values r", Discardable,
|
|
|
|
|
CB(handleRegisterListValues)});
|
2014-12-17 13:14:29 +01:00
|
|
|
} else {
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"maintenance print cooked-registers",
|
2015-11-03 12:01:57 +01:00
|
|
|
CB(handleMaintPrintRegisters)});
|
2009-10-30 16:42:33 +01:00
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
2009-10-30 16:42:33 +01:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static QString readWord(const QString &ba, int *pos)
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
|
|
|
|
const int n = ba.size();
|
|
|
|
|
while (*pos < n && ba.at(*pos) == ' ')
|
|
|
|
|
++*pos;
|
|
|
|
|
const int start = *pos;
|
|
|
|
|
while (*pos < n && ba.at(*pos) != ' ' && ba.at(*pos) != '\n')
|
|
|
|
|
++*pos;
|
|
|
|
|
return ba.mid(start, *pos - start);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleMaintPrintRegisters(const DebuggerResponse &response)
|
2009-08-18 08:34:48 +02:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass != ResultDone)
|
2014-12-17 13:14:29 +01:00
|
|
|
return;
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString &ba = response.consoleStreamOutput;
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterHandler *handler = registerHandler();
|
|
|
|
|
//0 1 2 3 4 5 6
|
|
|
|
|
//0123456789012345678901234567890123456789012345678901234567890
|
|
|
|
|
// Name Nr Rel Offset Size Type Raw value
|
|
|
|
|
// rax 0 0 0 8 int64_t 0x0000000000000000
|
|
|
|
|
// rip 16 16 128 8 *1 0x0000000000400dc9
|
|
|
|
|
// eflags 17 17 136 4 i386_eflags 0x00000246
|
|
|
|
|
// cs 18 18 140 4 int32_t 0x00000033
|
|
|
|
|
// xmm15 55 55 516 16 vec128 0x00000000000000000000000000000000
|
|
|
|
|
// mxcsr 56 56 532 4 i386_mxcsr 0x00001fa0
|
|
|
|
|
// ''
|
|
|
|
|
// st6 30 30 224 10 _i387_ext 0x00000000000000000000
|
|
|
|
|
// st7 31 31 234 10 _i387_ext 0x00000000000000000000
|
|
|
|
|
// fctrl 32 32 244 4 int 0x0000037f
|
|
|
|
|
|
|
|
|
|
const int n = ba.size();
|
|
|
|
|
int pos = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
// Skip first line, and until '\n' after each line finished.
|
|
|
|
|
while (pos < n && ba.at(pos) != '\n')
|
|
|
|
|
++pos;
|
|
|
|
|
if (pos >= n)
|
|
|
|
|
break;
|
|
|
|
|
++pos; // skip \n
|
|
|
|
|
Register reg;
|
|
|
|
|
reg.name = readWord(ba, &pos);
|
|
|
|
|
if (reg.name == "''" || reg.name == "*1:" || reg.name.isEmpty())
|
|
|
|
|
continue;
|
|
|
|
|
readWord(ba, &pos); // Nr
|
|
|
|
|
readWord(ba, &pos); // Rel
|
|
|
|
|
readWord(ba, &pos); // Offset
|
|
|
|
|
reg.size = readWord(ba, &pos).toInt();
|
|
|
|
|
reg.reportedType = readWord(ba, &pos);
|
2016-06-07 17:04:53 +02:00
|
|
|
reg.value.fromString(readWord(ba, &pos), HexadecimalFormat);
|
2014-12-17 13:14:29 +01:00
|
|
|
handler->updateRegister(reg);
|
|
|
|
|
}
|
|
|
|
|
handler->commitUpdates();
|
|
|
|
|
}
|
2015-08-25 13:48:55 +02:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void GdbEngine::setRegisterValue(const QString &name, const QString &value)
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString fullName = name;
|
2015-08-25 13:48:55 +02:00
|
|
|
if (name.startsWith("xmm"))
|
|
|
|
|
fullName += ".uint128";
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"set $" + fullName + "=" + value});
|
2009-08-18 08:34:48 +02:00
|
|
|
reloadRegisters();
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleRegisterListNames(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass != ResultDone) {
|
2009-10-30 16:42:33 +01:00
|
|
|
m_registerNamesListed = false;
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2009-10-30 16:42:33 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-07-21 12:52:18 +02:00
|
|
|
m_registers.clear();
|
2014-12-17 13:14:29 +01:00
|
|
|
int gdbRegisterNumber = 0;
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data["register-names"]) {
|
2015-07-21 12:52:18 +02:00
|
|
|
if (!item.data().isEmpty()) {
|
|
|
|
|
Register reg;
|
|
|
|
|
reg.name = item.data();
|
|
|
|
|
m_registers[gdbRegisterNumber] = reg;
|
|
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
++gdbRegisterNumber;
|
2012-08-28 12:39:57 -05:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-21 12:52:18 +02:00
|
|
|
void GdbEngine::handleRegisterListing(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
if (response.resultClass != ResultDone) {
|
|
|
|
|
m_registerNamesListed = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// &"maintenance print raw-registers\n"
|
|
|
|
|
// >~" Name Nr Rel Offset Size Type Raw value\n"
|
|
|
|
|
// >~" rax 0 0 0 8 int64_t 0x0000000000000005\n"
|
|
|
|
|
// >~" rip 16 16 128 8 *1 0x000000000040232a\n"
|
|
|
|
|
// >~" '' 145 145 536 0 int0_t <invalid>\n"
|
|
|
|
|
|
|
|
|
|
m_registers.clear();
|
2016-06-07 17:04:53 +02:00
|
|
|
QStringList lines = response.consoleStreamOutput.split('\n');
|
2015-07-21 12:52:18 +02:00
|
|
|
for (int i = 1; i < lines.size(); ++i) {
|
2016-11-28 09:04:07 +01:00
|
|
|
const QVector<QStringRef> parts = lines.at(i).splitRef(' ', QString::SkipEmptyParts);
|
2015-07-21 12:52:18 +02:00
|
|
|
if (parts.size() < 7)
|
|
|
|
|
continue;
|
|
|
|
|
int gdbRegisterNumber = parts.at(1).toInt();
|
|
|
|
|
Register reg;
|
2016-11-23 10:10:55 +01:00
|
|
|
reg.name = parts.at(0).toString();
|
2015-07-21 12:52:18 +02:00
|
|
|
reg.size = parts.at(4).toInt();
|
2016-11-23 10:10:55 +01:00
|
|
|
reg.reportedType = parts.at(5).toString();
|
2015-07-21 12:52:18 +02:00
|
|
|
m_registers[gdbRegisterNumber] = reg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass != ResultDone)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterHandler *handler = registerHandler();
|
2008-12-02 12:01:29 +01:00
|
|
|
// 24^done,register-values=[{number="0",value="0xf423f"},...]
|
2018-09-25 18:48:29 +02:00
|
|
|
for (const GdbMi &item : response.data["register-values"]) {
|
2013-05-07 12:09:54 +02:00
|
|
|
const int number = item["number"].toInt();
|
2015-07-21 12:52:18 +02:00
|
|
|
Register reg = m_registers[number];
|
2016-06-07 17:04:53 +02:00
|
|
|
QString data = item["value"].data();
|
2014-12-17 13:14:29 +01:00
|
|
|
if (data.startsWith("0x")) {
|
2016-06-07 17:04:53 +02:00
|
|
|
reg.value.fromString(data, HexadecimalFormat);
|
2015-03-03 17:10:50 +01:00
|
|
|
} else if (data == "<error reading variable>") {
|
|
|
|
|
// Nothing. See QTCREATORBUG-14029.
|
2014-12-17 13:14:29 +01:00
|
|
|
} else {
|
|
|
|
|
// This is what GDB considers machine readable output:
|
|
|
|
|
// value="{v4_float = {0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
|
|
|
|
// v2_double = {0x0000000000000000, 0x0000000000000000},
|
|
|
|
|
// v16_int8 = {0x00 <repeats 16 times>},
|
|
|
|
|
// v8_int16 = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
|
|
|
|
|
// v4_int32 = {0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
|
|
|
|
// v2_int64 = {0x0000000000000000, 0x0000000000000000},
|
|
|
|
|
// uint128 = <error reading variable>}"}
|
2016-03-14 17:50:08 +01:00
|
|
|
// Try to make sense of it using the int32 chunks.
|
|
|
|
|
// Android gdb 7.10 has u32 = {0x00000000, 0x40340000}.
|
|
|
|
|
// Use that if available.
|
2016-06-07 17:04:53 +02:00
|
|
|
QString result;
|
2016-03-14 17:50:08 +01:00
|
|
|
int pos1 = data.indexOf("_int32");
|
|
|
|
|
if (pos1 == -1)
|
|
|
|
|
pos1 = data.indexOf("u32");
|
2014-12-17 13:14:29 +01:00
|
|
|
const int pos2 = data.indexOf('{', pos1) + 1;
|
|
|
|
|
const int pos3 = data.indexOf('}', pos2);
|
2016-06-07 17:04:53 +02:00
|
|
|
QString inner = data.mid(pos2, pos3 - pos2);
|
|
|
|
|
QStringList list = inner.split(',');
|
2014-12-17 13:14:29 +01:00
|
|
|
for (int i = list.size(); --i >= 0; ) {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString chunk = list.at(i);
|
2014-12-17 13:14:29 +01:00
|
|
|
if (chunk.startsWith(' '))
|
|
|
|
|
chunk.remove(0, 1);
|
2017-07-05 18:17:36 +03:00
|
|
|
if (chunk.startsWith('<') || chunk.startsWith('{')) // <unavailable>, {v4_float=...
|
|
|
|
|
continue;
|
2014-12-17 13:14:29 +01:00
|
|
|
if (chunk.startsWith("0x"))
|
|
|
|
|
chunk.remove(0, 2);
|
|
|
|
|
QTC_ASSERT(chunk.size() == 8, continue);
|
|
|
|
|
result.append(chunk);
|
|
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
reg.value.fromString(result, HexadecimalFormat);
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
handler->updateRegister(reg);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
handler->commitUpdates();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Watch specific stuff
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-09-23 11:15:56 +02:00
|
|
|
void GdbEngine::reloadLocals()
|
2009-10-06 10:54:08 +02:00
|
|
|
{
|
|
|
|
|
setTokenBarrier();
|
|
|
|
|
updateLocals();
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleVarAssign(const DebuggerResponse &)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-10-05 12:00:47 +02:00
|
|
|
// Everything might have changed, force re-evaluation.
|
2009-02-18 13:50:55 +01:00
|
|
|
setTokenBarrier();
|
2008-12-02 12:01:29 +01:00
|
|
|
updateLocals();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
void GdbEngine::assignValueInDebugger(WatchItem *item,
|
2010-11-10 16:33:11 +01:00
|
|
|
const QString &expression, const QVariant &value)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("assignValue");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("type", toHex(item->type));
|
|
|
|
|
cmd.arg("expr", toHex(expression));
|
|
|
|
|
cmd.arg("value", toHex(value.toString()));
|
2015-03-19 12:42:53 +01:00
|
|
|
cmd.arg("simpleType", isIntOrFloatType(item->type));
|
2015-02-10 13:40:26 +01:00
|
|
|
cmd.callback = CB(handleVarAssign);
|
|
|
|
|
runCommand(cmd);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-05-24 11:55:09 +02:00
|
|
|
class MemoryAgentCookie
|
2009-08-14 13:04:05 +02:00
|
|
|
{
|
2011-05-24 11:55:09 +02:00
|
|
|
public:
|
2018-07-23 22:28:49 +02:00
|
|
|
MemoryAgentCookie() = default;
|
2011-05-24 11:55:09 +02:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
QByteArray *accumulator = nullptr; // Shared between split request. Last one cleans up.
|
|
|
|
|
uint *pendingRequests = nullptr; // Shared between split request. Last one cleans up.
|
2013-11-05 18:47:03 +01:00
|
|
|
|
2010-12-14 12:29:32 +01:00
|
|
|
QPointer<MemoryAgent> agent;
|
2016-07-14 10:00:15 +02:00
|
|
|
quint64 base = 0; // base address.
|
|
|
|
|
uint offset = 0; // offset to base, and in accumulator
|
|
|
|
|
uint length = 0; //
|
2009-08-18 08:34:48 +02:00
|
|
|
};
|
2009-08-14 13:04:05 +02:00
|
|
|
|
2013-11-05 18:47:03 +01:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void GdbEngine::changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data)
|
2011-02-25 13:21:54 +01:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
Q_UNUSED(agent)
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("-data-write-memory 0x" + QString::number(addr, 16) + " d 1", NeedsTemporaryStop);
|
2018-05-30 15:42:51 +02:00
|
|
|
for (unsigned char c : data)
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.function += ' ' + QString::number(uint(c));
|
2016-07-14 10:00:15 +02:00
|
|
|
cmd.callback = CB(handleVarAssign);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2011-02-25 13:21:54 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void GdbEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
|
2009-08-14 13:04:05 +02:00
|
|
|
{
|
2013-11-05 18:47:03 +01:00
|
|
|
MemoryAgentCookie ac;
|
|
|
|
|
ac.accumulator = new QByteArray(length, char());
|
|
|
|
|
ac.pendingRequests = new uint(1);
|
|
|
|
|
ac.agent = agent;
|
|
|
|
|
ac.base = addr;
|
|
|
|
|
ac.length = length;
|
|
|
|
|
fetchMemoryHelper(ac);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::fetchMemoryHelper(const MemoryAgentCookie &ac)
|
|
|
|
|
{
|
2015-10-06 23:08:57 +03:00
|
|
|
DebuggerCommand cmd("-data-read-memory 0x"
|
2016-06-07 17:04:53 +02:00
|
|
|
+ QString::number(ac.base + ac.offset, 16) + " x 1 1 "
|
|
|
|
|
+ QString::number(ac.length),
|
2016-12-13 09:46:51 +01:00
|
|
|
NeedsTemporaryStop);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, ac](const DebuggerResponse &r) { handleFetchMemory(r, ac); };
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2009-08-14 13:04:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac)
|
2009-08-12 10:51:25 +02:00
|
|
|
{
|
|
|
|
|
// ^done,addr="0x08910c88",nr-bytes="16",total-bytes="16",
|
|
|
|
|
// next-row="0x08910c98",prev-row="0x08910c78",next-page="0x08910c98",
|
|
|
|
|
// prev-page="0x08910c78",memory=[{addr="0x08910c88",
|
|
|
|
|
// data=["1","0","0","0","5","0","0","0","0","0","0","0","0","0","0","0"]}]
|
2013-11-05 18:47:03 +01:00
|
|
|
--*ac.pendingRequests;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("PENDING: %1").arg(*ac.pendingRequests));
|
2009-08-18 08:34:48 +02:00
|
|
|
QTC_ASSERT(ac.agent, return);
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2013-11-05 18:47:03 +01:00
|
|
|
GdbMi memory = response.data["memory"];
|
2018-09-25 18:48:29 +02:00
|
|
|
QTC_ASSERT(memory.childCount() <= 1, return);
|
|
|
|
|
if (memory.childCount() == 0)
|
2013-11-05 18:47:03 +01:00
|
|
|
return;
|
2018-09-25 18:48:29 +02:00
|
|
|
GdbMi memory0 = memory.childAt(0); // we asked for only one 'row'
|
2013-11-05 18:47:03 +01:00
|
|
|
GdbMi data = memory0["data"];
|
2018-09-25 18:48:29 +02:00
|
|
|
int i = 0;
|
|
|
|
|
for (const GdbMi &child : data) {
|
2013-11-05 18:47:03 +01:00
|
|
|
bool ok = true;
|
|
|
|
|
unsigned char c = '?';
|
|
|
|
|
c = child.data().toUInt(&ok, 0);
|
|
|
|
|
QTC_ASSERT(ok, return);
|
2018-09-25 18:48:29 +02:00
|
|
|
(*ac.accumulator)[ac.offset + i++] = c;
|
2013-11-05 18:47:03 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// We have an error
|
|
|
|
|
if (ac.length > 1) {
|
|
|
|
|
// ... and size > 1, split the load and re-try.
|
|
|
|
|
*ac.pendingRequests += 2;
|
|
|
|
|
uint hunk = ac.length / 2;
|
|
|
|
|
MemoryAgentCookie ac1 = ac;
|
|
|
|
|
ac1.length = hunk;
|
|
|
|
|
ac1.offset = ac.offset;
|
|
|
|
|
MemoryAgentCookie ac2 = ac;
|
|
|
|
|
ac2.length = ac.length - hunk;
|
|
|
|
|
ac2.offset = ac.offset + hunk;
|
|
|
|
|
fetchMemoryHelper(ac1);
|
|
|
|
|
fetchMemoryHelper(ac2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*ac.pendingRequests <= 0) {
|
2016-07-14 10:00:15 +02:00
|
|
|
ac.agent->addData(ac.base, *ac.accumulator);
|
2013-11-05 18:47:03 +01:00
|
|
|
delete ac.pendingRequests;
|
|
|
|
|
delete ac.accumulator;
|
|
|
|
|
}
|
2009-08-12 10:51:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-12 12:01:40 +02:00
|
|
|
class DisassemblerAgentCookie
|
2009-08-18 08:34:48 +02:00
|
|
|
{
|
2010-04-12 12:01:40 +02:00
|
|
|
public:
|
2018-07-23 22:28:49 +02:00
|
|
|
DisassemblerAgentCookie() : agent(nullptr) {}
|
2011-02-10 13:43:02 +01:00
|
|
|
DisassemblerAgentCookie(DisassemblerAgent *agent_) : agent(agent_) {}
|
2010-04-12 12:01:40 +02:00
|
|
|
|
|
|
|
|
public:
|
2010-12-14 12:29:32 +01:00
|
|
|
QPointer<DisassemblerAgent> agent;
|
2009-08-18 08:34:48 +02:00
|
|
|
};
|
|
|
|
|
|
2010-12-14 12:29:32 +01:00
|
|
|
void GdbEngine::fetchDisassembler(DisassemblerAgent *agent)
|
2009-08-12 10:51:25 +02:00
|
|
|
{
|
2014-07-28 14:23:52 +02:00
|
|
|
if (boolSetting(IntelFlavor))
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set disassembly-flavor intel"});
|
2014-05-26 15:24:27 +02:00
|
|
|
else
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set disassembly-flavor att"});
|
2014-05-26 15:24:27 +02:00
|
|
|
|
2014-04-11 18:35:37 +02:00
|
|
|
fetchDisassemblerByCliPointMixed(agent);
|
2009-08-14 13:04:05 +02:00
|
|
|
}
|
2011-02-10 13:43:02 +01:00
|
|
|
|
2018-07-19 19:48:44 +03:00
|
|
|
static inline QString disassemblerCommand(const Location &location, bool mixed, QChar mixedFlag)
|
2012-02-01 17:44:07 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString command = "disassemble /r";
|
2012-02-01 17:44:07 +01:00
|
|
|
if (mixed)
|
2018-07-19 19:48:44 +03:00
|
|
|
command += mixedFlag;
|
2014-05-02 17:01:39 +02:00
|
|
|
command += ' ';
|
2012-02-01 17:44:07 +01:00
|
|
|
if (const quint64 address = location.address()) {
|
|
|
|
|
command += "0x";
|
2016-06-07 17:04:53 +02:00
|
|
|
command += QString::number(address, 16);
|
2012-02-01 17:44:07 +01:00
|
|
|
} else if (!location.functionName().isEmpty()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
command += location.functionName();
|
2012-02-01 17:44:07 +01:00
|
|
|
} else {
|
2016-06-07 17:04:53 +02:00
|
|
|
QTC_ASSERT(false, return QString(); );
|
2012-02-01 17:44:07 +01:00
|
|
|
}
|
|
|
|
|
return command;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac)
|
2011-02-10 13:43:02 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(ac.agent, return);
|
2018-07-19 19:48:44 +03:00
|
|
|
DebuggerCommand cmd(disassemblerCommand(ac.agent->location(), true, mixedDisasmFlag()),
|
|
|
|
|
Discardable | ConsoleCommand);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, ac](const DebuggerResponse &response) {
|
|
|
|
|
if (response.resultClass == ResultDone)
|
|
|
|
|
if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent))
|
|
|
|
|
return;
|
|
|
|
|
// 'point, plain' can take far too long.
|
|
|
|
|
// Skip this feature and immediately fall back to the 'range' version:
|
|
|
|
|
fetchDisassemblerByCliRangeMixed(ac);
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2011-02-10 13:43:02 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-06 01:26:47 +01:00
|
|
|
void GdbEngine::fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac)
|
2011-02-10 13:43:02 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(ac.agent, return);
|
|
|
|
|
const quint64 address = ac.agent->address();
|
2016-06-07 17:04:53 +02:00
|
|
|
QString start = QString::number(address - 20, 16);
|
|
|
|
|
QString end = QString::number(address + 100, 16);
|
2018-07-19 19:48:44 +03:00
|
|
|
DebuggerCommand cmd("disassemble /r" + mixedDisasmFlag() + " 0x" + start + ",0x" + end,
|
|
|
|
|
Discardable | ConsoleCommand);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, ac](const DebuggerResponse &response) {
|
|
|
|
|
if (response.resultClass == ResultDone)
|
|
|
|
|
if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent))
|
|
|
|
|
return;
|
|
|
|
|
fetchDisassemblerByCliRangePlain(ac);
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-02-09 15:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-10 13:43:02 +01:00
|
|
|
void GdbEngine::fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac0)
|
2010-02-09 15:02:55 +01:00
|
|
|
{
|
2010-04-12 12:01:40 +02:00
|
|
|
DisassemblerAgentCookie ac = ac0;
|
|
|
|
|
QTC_ASSERT(ac.agent, return);
|
2010-09-21 15:12:33 +02:00
|
|
|
const quint64 address = ac.agent->address();
|
2016-06-07 17:04:53 +02:00
|
|
|
QString start = QString::number(address - 20, 16);
|
|
|
|
|
QString end = QString::number(address + 100, 16);
|
2015-10-06 23:08:57 +03:00
|
|
|
DebuggerCommand cmd("disassemble /r 0x" + start + ",0x" + end, Discardable);
|
2015-09-11 11:28:55 +02:00
|
|
|
cmd.callback = [this, ac](const DebuggerResponse &response) {
|
|
|
|
|
if (response.resultClass == ResultDone)
|
|
|
|
|
if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent))
|
|
|
|
|
return;
|
|
|
|
|
// Finally, give up.
|
|
|
|
|
//76^error,msg="No function contains program counter for selected..."
|
|
|
|
|
//76^error,msg="No function contains specified address."
|
|
|
|
|
//>568^error,msg="Line number 0 out of range;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString msg = response.data["msg"].data();
|
|
|
|
|
showStatusMessage(tr("Disassembler failed: %1").arg(msg), 5000);
|
2015-09-11 11:28:55 +02:00
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-02-09 15:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
2014-04-11 18:35:37 +02:00
|
|
|
struct LineData
|
2009-08-14 13:04:05 +02:00
|
|
|
{
|
2018-07-23 22:28:49 +02:00
|
|
|
LineData() = default;
|
2014-04-11 18:35:37 +02:00
|
|
|
LineData(int i, int f) : index(i), function(f) {}
|
|
|
|
|
int index;
|
|
|
|
|
int function;
|
|
|
|
|
};
|
2009-08-12 10:51:25 +02:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
bool GdbEngine::handleCliDisassemblerResult(const QString &output, DisassemblerAgent *agent)
|
2011-02-10 13:43:02 +01:00
|
|
|
{
|
2015-02-06 01:26:47 +01:00
|
|
|
QTC_ASSERT(agent, return true);
|
2011-02-10 13:43:02 +01:00
|
|
|
// First line is something like
|
|
|
|
|
// "Dump of assembler code from 0xb7ff598f to 0xb7ff5a07:"
|
|
|
|
|
DisassemblerLines dlines;
|
2016-06-07 17:04:53 +02:00
|
|
|
foreach (const QString &line, output.split('\n'))
|
|
|
|
|
dlines.appendUnparsed(line);
|
2011-02-10 13:43:02 +01:00
|
|
|
|
2014-04-11 18:35:37 +02:00
|
|
|
QVector<DisassemblerLine> lines = dlines.data();
|
|
|
|
|
|
2018-07-23 22:28:49 +02:00
|
|
|
using LineMap = QMap<quint64, LineData>;
|
2014-04-11 18:35:37 +02:00
|
|
|
LineMap lineMap;
|
|
|
|
|
int currentFunction = -1;
|
|
|
|
|
for (int i = 0, n = lines.size(); i != n; ++i) {
|
|
|
|
|
const DisassemblerLine &line = lines.at(i);
|
|
|
|
|
if (line.address)
|
|
|
|
|
lineMap.insert(line.address, LineData(i, currentFunction));
|
|
|
|
|
else
|
|
|
|
|
currentFunction = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentFunction = -1;
|
|
|
|
|
DisassemblerLines result;
|
2014-04-30 14:56:51 +02:00
|
|
|
result.setBytesLength(dlines.bytesLength());
|
2015-04-01 11:19:32 +02:00
|
|
|
for (LineMap::const_iterator it = lineMap.constBegin(), et = lineMap.constEnd(); it != et; ++it) {
|
2014-04-11 18:35:37 +02:00
|
|
|
LineData d = *it;
|
|
|
|
|
if (d.function != currentFunction) {
|
|
|
|
|
if (d.function != -1) {
|
|
|
|
|
DisassemblerLine &line = lines[d.function];
|
|
|
|
|
++line.hunk;
|
|
|
|
|
result.appendLine(line);
|
|
|
|
|
currentFunction = d.function;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result.appendLine(lines.at(d.index));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result.coversAddress(agent->address())) {
|
|
|
|
|
agent->setContents(result);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2011-02-10 13:43:02 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParameters &sp,
|
2014-09-11 22:22:51 +03:00
|
|
|
const SourcePathMap &in)
|
2013-02-06 16:17:30 +01:00
|
|
|
{
|
|
|
|
|
// Do not overwrite user settings.
|
2014-09-11 22:22:51 +03:00
|
|
|
SourcePathMap rc = sp.sourcePathMap;
|
|
|
|
|
for (auto it = in.constBegin(), end = in.constEnd(); it != end; ++it)
|
2013-02-06 16:17:30 +01:00
|
|
|
rc.insert(it.key(), it.value());
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-21 11:09:38 +02:00
|
|
|
//
|
|
|
|
|
// Starting up & shutting down
|
|
|
|
|
//
|
|
|
|
|
|
2017-09-27 16:48:32 +02:00
|
|
|
void GdbEngine::setupEngine()
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2017-09-27 16:48:32 +02:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
|
|
|
|
showMessage("TRYING TO START ADAPTER");
|
|
|
|
|
|
|
|
|
|
if (isRemoteEngine() && HostOsInfo::isWindowsHost())
|
|
|
|
|
m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
|
|
|
|
|
|
2019-06-04 15:44:59 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
2019-06-20 17:19:12 +02:00
|
|
|
CommandLine gdbCommand{rp.debugger.executable};
|
2019-06-04 15:44:59 +02:00
|
|
|
|
2017-09-27 16:48:32 +02:00
|
|
|
if (isPlainEngine()) {
|
|
|
|
|
if (!m_outputCollector.listen()) {
|
|
|
|
|
handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
|
|
|
|
|
.arg(m_outputCollector.errorString()));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-06-04 15:44:59 +02:00
|
|
|
gdbCommand.addArg("--tty=" + m_outputCollector.serverName());
|
2017-09-27 16:48:32 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString tests = QString::fromLocal8Bit(qgetenv("QTC_DEBUGGER_TESTS"));
|
2018-10-07 22:38:47 +03:00
|
|
|
foreach (const QStringRef &test, tests.splitRef(','))
|
2011-06-06 18:17:51 +02:00
|
|
|
m_testCases.insert(test.toInt());
|
|
|
|
|
foreach (int test, m_testCases)
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ENABLING TEST CASE: " + QString::number(test));
|
2011-06-06 18:17:51 +02:00
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
m_expectTerminalTrap = terminal();
|
2009-10-20 11:02:16 +02:00
|
|
|
|
2016-07-29 15:55:15 +02:00
|
|
|
if (rp.debugger.executable.isEmpty()) {
|
2012-06-13 10:15:56 +02:00
|
|
|
handleGdbStartFailed();
|
2010-06-16 11:08:54 +02:00
|
|
|
handleAdapterStartFailed(
|
2015-05-27 13:59:56 +02:00
|
|
|
msgNoGdbBinaryForToolChain(rp.toolChainAbi),
|
2012-12-29 01:31:08 +01:00
|
|
|
Constants::DEBUGGER_COMMON_SETTINGS_ID);
|
2012-06-05 11:05:58 +02:00
|
|
|
return;
|
2010-04-08 16:55:25 +02:00
|
|
|
}
|
2016-07-29 15:55:15 +02:00
|
|
|
|
2019-06-05 15:35:15 +02:00
|
|
|
gdbCommand.addArgs({"-i", "mi"});
|
2014-07-28 14:23:52 +02:00
|
|
|
if (!boolSetting(LoadGdbInit))
|
2019-06-04 15:44:59 +02:00
|
|
|
gdbCommand.addArg("-n");
|
2010-12-02 17:43:14 +01:00
|
|
|
|
2019-06-04 15:44:59 +02:00
|
|
|
showMessage("STARTING " + gdbCommand.toUserOutput());
|
|
|
|
|
m_gdbProc.setCommand(gdbCommand);
|
2016-07-29 15:55:15 +02:00
|
|
|
if (QFileInfo(rp.debugger.workingDirectory).isDir())
|
|
|
|
|
m_gdbProc.setWorkingDirectory(rp.debugger.workingDirectory);
|
|
|
|
|
m_gdbProc.setEnvironment(rp.debugger.environment);
|
2015-06-08 12:10:11 +02:00
|
|
|
m_gdbProc.start();
|
2010-03-10 15:51:31 +01:00
|
|
|
|
2015-06-08 12:10:11 +02:00
|
|
|
if (!m_gdbProc.waitForStarted()) {
|
2012-06-13 10:15:56 +02:00
|
|
|
handleGdbStartFailed();
|
2016-07-29 15:55:15 +02:00
|
|
|
QString msg;
|
|
|
|
|
QString wd = m_gdbProc.workingDirectory();
|
|
|
|
|
if (!QFileInfo(wd).isDir())
|
2017-04-24 15:17:40 +02:00
|
|
|
msg = failedToStartMessage() + ' ' + tr("The working directory \"%1\" is not usable.").arg(wd);
|
2016-07-29 15:55:15 +02:00
|
|
|
else
|
2017-07-05 15:17:38 +02:00
|
|
|
msg = RunWorker::userMessageForProcessError(QProcess::FailedToStart, rp.debugger.executable);
|
2012-06-05 19:55:32 +02:00
|
|
|
handleAdapterStartFailed(msg);
|
2012-06-05 11:05:58 +02:00
|
|
|
return;
|
2010-03-10 15:51:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("GDB STARTED, INITIALIZING IT");
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"show version", CB(handleShowVersion)});
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("-list-features", CB(handleListFeatures));
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"show debug-file-directory", CB(handleDebugInfoLocation)});
|
2015-09-11 11:28:55 +02:00
|
|
|
|
|
|
|
|
//runCommand("-enable-timings");
|
|
|
|
|
//rurun print static-members off"); // Seemingly doesn't work.
|
|
|
|
|
//runCommand("set debug infrun 1");
|
|
|
|
|
//runCommand("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend");
|
|
|
|
|
//runCommand("define hook-stop\nprint 4\nend");
|
|
|
|
|
//runCommand("define hookpost-stop\nprint 5\nend");
|
|
|
|
|
//runCommand("define hook-call\nprint 6\nend");
|
|
|
|
|
//runCommand("define hookpost-call\nprint 7\nend");
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set print object on"});
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set step-mode on"); // we can't work with that yes
|
|
|
|
|
//runCommand("set exec-done-display on");
|
|
|
|
|
//runCommand("set print pretty on");
|
|
|
|
|
//runCommand("set confirm off");
|
|
|
|
|
//runCommand("set pagination off");
|
2009-10-05 12:06:29 +02:00
|
|
|
|
|
|
|
|
// The following does not work with 6.3.50-20050815 (Apple version gdb-1344)
|
|
|
|
|
// (Mac OS 10.6), but does so for gdb-966 (10.5):
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set print inferior-events 1");
|
2009-10-05 12:06:29 +02:00
|
|
|
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set breakpoint pending on"});
|
|
|
|
|
runCommand({"set print elements 10000"});
|
2012-04-17 10:00:40 +02:00
|
|
|
|
2010-01-12 13:49:56 +01:00
|
|
|
// Produces a few messages during symtab loading
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set verbose on");
|
2009-09-21 11:09:38 +02:00
|
|
|
|
|
|
|
|
// 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>'()
|
2013-10-22 18:58:19 +02:00
|
|
|
// /build/buildd/gdb-6.8/gdb/valops.c:2069: internal-error
|
|
|
|
|
// This seems to be fixed, however, with 'on' it seems to _require_
|
|
|
|
|
// explicit casting of function pointers:
|
|
|
|
|
// GNU gdb (GDB) 7.5.91.20130417-cvs-ubuntu
|
|
|
|
|
// (gdb) p &Myns::QMetaType::typeName -> $1 = (const char *(*)(int)) 0xb7cf73b0 <Myns::QMetaType::typeName(int)>
|
|
|
|
|
// (gdb) p Myns::QMetaType::typeName(1024) -> 31^error,msg="Couldn't find method Myns::QMetaType::typeName"
|
|
|
|
|
// But we can work around on the dumper side. So let's use the default (i.e. 'on')
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set overload-resolution off");
|
2013-10-22 18:58:19 +02:00
|
|
|
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand(_("set demangle-style none"));
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set unwindonsignal on"});
|
|
|
|
|
runCommand({"set width 0"});
|
|
|
|
|
runCommand({"set height 0"});
|
2012-01-24 20:03:50 +01:00
|
|
|
|
2013-08-30 14:27:00 +02:00
|
|
|
// FIXME: Provide proper Gui settings for these:
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set breakpoint always-inserted on", ConsoleCommand);
|
2012-01-24 20:03:50 +01:00
|
|
|
// displaced-stepping does not work in Thumb mode.
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set displaced-stepping on");
|
|
|
|
|
//runCommand("set trust-readonly-sections on", ConsoleCommand);
|
|
|
|
|
//runCommand("set remotecache on", ConsoleCommand);
|
|
|
|
|
//runCommand("set non-stop on", ConsoleCommand);
|
2011-02-03 16:49:28 +01:00
|
|
|
|
2012-06-13 10:15:56 +02:00
|
|
|
showStatusMessage(tr("Setting up inferior..."));
|
|
|
|
|
|
|
|
|
|
// Addint executable to modules list.
|
|
|
|
|
Module module;
|
|
|
|
|
module.startAddress = 0;
|
|
|
|
|
module.endAddress = 0;
|
2019-06-20 17:19:12 +02:00
|
|
|
module.modulePath = rp.inferior.executable.toString();
|
2016-06-07 17:04:53 +02:00
|
|
|
module.moduleName = "<executable>";
|
2012-06-13 10:15:56 +02:00
|
|
|
modulesHandler()->updateModule(module);
|
|
|
|
|
|
|
|
|
|
// Apply source path mappings from global options.
|
2012-08-09 04:25:13 +02:00
|
|
|
//showMessage(_("Assuming Qt is installed at %1").arg(qtInstallPath));
|
2012-06-13 10:15:56 +02:00
|
|
|
const SourcePathMap sourcePathMap =
|
2015-05-27 13:59:56 +02:00
|
|
|
DebuggerSourcePathMappingWidget::mergePlatformQtPath(rp,
|
2014-10-22 13:04:47 +02:00
|
|
|
Internal::globalDebuggerOptions()->sourcePathMap);
|
2013-02-06 16:17:30 +01:00
|
|
|
const SourcePathMap completeSourcePathMap =
|
2015-05-27 13:59:56 +02:00
|
|
|
mergeStartParametersSourcePathMap(rp, sourcePathMap);
|
2014-09-11 22:22:51 +03:00
|
|
|
for (auto it = completeSourcePathMap.constBegin(), cend = completeSourcePathMap.constEnd();
|
|
|
|
|
it != cend;
|
|
|
|
|
++it) {
|
2019-03-31 15:33:46 +03:00
|
|
|
runCommand({"set substitute-path " + it.key() + " " + expand(it.value())});
|
2014-09-11 22:22:51 +03:00
|
|
|
}
|
2012-06-13 10:15:56 +02:00
|
|
|
|
|
|
|
|
// Spaces just will not work.
|
2018-05-30 15:42:51 +02:00
|
|
|
for (const QString &src : rp.debugSourceLocation) {
|
2013-04-19 15:01:55 +02:00
|
|
|
if (QDir(src).exists())
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"directory " + src});
|
2013-04-19 15:01:55 +02:00
|
|
|
else
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("# directory does not exist: " + src, LogInput);
|
2013-04-19 15:01:55 +02:00
|
|
|
}
|
2012-06-13 10:15:56 +02:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
if (!rp.sysRoot.isEmpty()) {
|
2018-08-21 17:46:47 +02:00
|
|
|
runCommand({"set sysroot " + rp.sysRoot.toString()});
|
2012-06-13 10:15:56 +02:00
|
|
|
// sysroot is not enough to correctly locate the sources, so explicitly
|
|
|
|
|
// relocate the most likely place for the debug source
|
2018-08-21 17:46:47 +02:00
|
|
|
runCommand({"set substitute-path /usr/src " + rp.sysRoot.toString() + "/usr/src"});
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//QByteArray ba = QFileInfo(sp.dumperLibrary).path().toLocal8Bit();
|
|
|
|
|
//if (!ba.isEmpty())
|
2015-09-11 11:28:55 +02:00
|
|
|
// runCommand("set solib-search-path " + ba);
|
2009-09-21 11:09:38 +02:00
|
|
|
|
2016-11-15 08:38:04 +01:00
|
|
|
if (boolSetting(MultiInferior) || runParameters().multiProcess) {
|
2015-09-11 11:28:55 +02:00
|
|
|
//runCommand("set follow-exec-mode new");
|
2015-11-03 12:01:57 +01:00
|
|
|
runCommand({"set detach-on-fork off"});
|
2012-11-06 15:21:42 +01:00
|
|
|
}
|
2013-01-09 14:51:49 +01:00
|
|
|
|
2014-01-28 11:27:13 +01:00
|
|
|
// Finally, set up Python.
|
|
|
|
|
// We need to guarantee a roundtrip before the adapter proceeds.
|
2013-01-09 14:51:49 +01:00
|
|
|
// Make sure this stays the last command in startGdb().
|
2013-05-28 12:12:42 +02:00
|
|
|
// Don't use ConsoleCommand, otherwise Mac won't markup the output.
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString dumperSourcePath = ICore::resourcePath() + "/debugger/";
|
2012-06-05 11:05:58 +02:00
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
//if (terminal()->isUsable())
|
|
|
|
|
// runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())});
|
2015-01-14 16:58:10 +01:00
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
const QFileInfo gdbBinaryFile = rp.debugger.executable.toFileInfo();
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString uninstalledData = gdbBinaryFile.absolutePath() + "/data-directory/python";
|
2014-01-28 11:27:13 +01:00
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"python sys.path.insert(1, '" + dumperSourcePath + "')"});
|
|
|
|
|
runCommand({"python sys.path.append('" + uninstalledData + "')"});
|
|
|
|
|
runCommand({"python from gdbbridge import *"});
|
2015-01-20 20:19:55 +01:00
|
|
|
|
|
|
|
|
const QString path = stringSetting(ExtraDumperFile);
|
2015-06-22 08:00:47 +03:00
|
|
|
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("addDumperModule");
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd.arg("path", path);
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2015-02-11 12:20:21 +01:00
|
|
|
}
|
2015-01-20 20:19:55 +01:00
|
|
|
|
|
|
|
|
const QString commands = stringSetting(ExtraDumperCommands);
|
|
|
|
|
if (!commands.isEmpty())
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({commands});
|
2015-01-20 20:19:55 +01:00
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"loadDumpers", CB(handlePythonSetup)});
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleGdbStartFailed()
|
|
|
|
|
{
|
2017-09-27 08:22:02 +02:00
|
|
|
if (isPlainEngine())
|
2017-09-08 08:53:15 +02:00
|
|
|
m_outputCollector.shutdown();
|
2011-12-05 08:53:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::loadInitScript()
|
|
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
const QString script = runParameters().overrideStartScript;
|
2011-11-01 17:56:32 +01:00
|
|
|
if (!script.isEmpty()) {
|
|
|
|
|
if (QFileInfo(script).isReadable()) {
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"source " + script});
|
2009-09-21 11:09:38 +02:00
|
|
|
} else {
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::warning(
|
2017-10-19 09:10:57 +02:00
|
|
|
tr("Cannot Find Debugger Initialization Script"),
|
|
|
|
|
tr("The debugger settings point to a script file at \"%1\", "
|
2009-09-21 11:09:38 +02:00
|
|
|
"which is not accessible. If a script file is not needed, "
|
2017-09-08 14:20:43 +02:00
|
|
|
"consider clearing that entry to avoid this warning."
|
2011-11-01 17:56:32 +01:00
|
|
|
).arg(script));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2017-02-14 16:50:54 +01:00
|
|
|
const QString commands = nativeStartupCommands().trimmed();
|
2011-12-05 08:53:51 +02:00
|
|
|
if (!commands.isEmpty())
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({commands});
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
2010-07-15 13:23:44 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-15 10:38:15 +03:00
|
|
|
void GdbEngine::setEnvironmentVariables()
|
|
|
|
|
{
|
2018-01-03 10:59:50 +01:00
|
|
|
auto isWindowsPath = [this](const QString &str){
|
|
|
|
|
return HostOsInfo::isWindowsHost()
|
|
|
|
|
&& !isRemoteEngine()
|
|
|
|
|
&& str.compare("path", Qt::CaseInsensitive) == 0;
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-16 11:12:43 +02:00
|
|
|
Environment sysEnv = Environment::systemEnvironment();
|
2016-01-28 10:31:24 +01:00
|
|
|
Environment runEnv = runParameters().inferior.environment;
|
2015-07-16 11:12:43 +02:00
|
|
|
foreach (const EnvironmentItem &item, sysEnv.diff(runEnv)) {
|
2018-01-03 10:59:50 +01:00
|
|
|
// imitate the weird windows gdb behavior of setting the case of the path environment
|
|
|
|
|
// variable name to an all uppercase PATH
|
|
|
|
|
const QString name = isWindowsPath(item.name) ? "PATH" : item.name;
|
2017-06-23 16:54:45 +02:00
|
|
|
if (item.operation == EnvironmentItem::Unset)
|
2018-01-03 10:59:50 +01:00
|
|
|
runCommand({"unset environment " + name});
|
2015-07-16 11:12:43 +02:00
|
|
|
else
|
2018-01-03 10:59:50 +01:00
|
|
|
runCommand({"-gdb-set environment " + name + '=' + item.value});
|
2015-07-15 10:38:15 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-10 12:40:50 +01:00
|
|
|
void GdbEngine::reloadDebuggingHelpers()
|
|
|
|
|
{
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({"reloadDumpers"});
|
2015-01-22 13:06:38 +01:00
|
|
|
reloadLocals();
|
2013-01-10 12:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
2009-10-20 11:02:16 +02:00
|
|
|
void GdbEngine::handleGdbError(QProcess::ProcessError error)
|
|
|
|
|
{
|
2019-06-20 17:19:12 +02:00
|
|
|
QString msg = RunWorker::userMessageForProcessError(error, runParameters().debugger.executable);
|
2017-07-05 15:17:38 +02:00
|
|
|
QString errorString = m_gdbProc.errorString();
|
|
|
|
|
if (!errorString.isEmpty())
|
|
|
|
|
msg += '\n' + errorString;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("HANDLE GDB ERROR: " + msg);
|
2010-10-30 21:54:23 +02:00
|
|
|
// Show a message box for asynchronously reported issues.
|
2009-10-20 11:02:16 +02:00
|
|
|
switch (error) {
|
2010-09-06 14:26:19 +02:00
|
|
|
case QProcess::FailedToStart:
|
|
|
|
|
// This should be handled by the code trying to start the process.
|
|
|
|
|
break;
|
2009-10-20 11:02:16 +02:00
|
|
|
case QProcess::Crashed:
|
2019-01-08 13:12:51 +01:00
|
|
|
// At this time, m_gdbProc.state() can still return Running.
|
|
|
|
|
// Wait for finished() instead.
|
2010-09-06 14:26:19 +02:00
|
|
|
break;
|
2009-10-20 11:02:16 +02:00
|
|
|
case QProcess::ReadError:
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
default:
|
2013-10-26 21:57:20 +03:00
|
|
|
//m_gdbProc->kill();
|
2010-10-27 15:39:25 +02:00
|
|
|
//notifyEngineIll();
|
2015-02-03 23:58:49 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("GDB I/O Error"), msg);
|
2009-10-20 11:02:16 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-05 11:11:32 +01:00
|
|
|
void GdbEngine::handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2010-11-16 12:42:57 +01:00
|
|
|
if (m_commandTimer.isActive())
|
|
|
|
|
m_commandTimer.stop();
|
2010-11-16 12:38:50 +01:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
notifyDebuggerProcessFinished(exitCode, exitStatus, "GDB");
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-19 12:31:19 +02:00
|
|
|
void GdbEngine::abortDebuggerProcess()
|
2011-10-31 16:15:48 +01:00
|
|
|
{
|
2017-09-19 12:31:19 +02:00
|
|
|
m_gdbProc.kill();
|
2011-10-31 16:15:48 +01:00
|
|
|
}
|
|
|
|
|
|
2014-06-05 17:22:51 +02:00
|
|
|
void GdbEngine::resetInferior()
|
|
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
if (!runParameters().commandsForReset.isEmpty()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString commands = expand(runParameters().commandsForReset);
|
|
|
|
|
foreach (QString command, commands.split('\n')) {
|
2014-06-05 17:22:51 +02:00
|
|
|
command = command.trimmed();
|
2015-08-14 17:15:32 +02:00
|
|
|
if (!command.isEmpty())
|
2017-01-20 10:05:31 +01:00
|
|
|
runCommand({command, ConsoleCommand | NeedsTemporaryStop | NativeCommand});
|
2014-06-05 17:22:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-07-07 15:13:10 +02:00
|
|
|
m_rerunPending = true;
|
2014-06-05 17:22:51 +02:00
|
|
|
requestInterruptInferior();
|
|
|
|
|
runEngine();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 14:15:54 +02:00
|
|
|
void GdbEngine::handleAdapterStartFailed(const QString &msg, Id settingsIdHint)
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("ADAPTER START FAILED");
|
2016-03-09 19:16:14 +01:00
|
|
|
if (!msg.isEmpty() && !Internal::isTestRun()) {
|
2017-10-19 09:10:57 +02:00
|
|
|
const QString title = tr("Adapter Start Failed");
|
2018-08-30 09:10:24 +02:00
|
|
|
ICore::showWarningWithOptions(title, msg, QString(), settingsIdHint);
|
2009-10-26 11:55:02 +01:00
|
|
|
}
|
2010-07-09 17:07:59 +02:00
|
|
|
notifyEngineSetupFailed();
|
2009-09-21 11:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-27 13:57:21 +02:00
|
|
|
void GdbEngine::prepareForRestart()
|
|
|
|
|
{
|
|
|
|
|
m_rerunPending = false;
|
2018-07-23 22:28:49 +02:00
|
|
|
m_commandsDoneCallback = nullptr;
|
2016-05-27 13:57:21 +02:00
|
|
|
m_commandForToken.clear();
|
|
|
|
|
m_flagsForToken.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-19 19:04:01 +02:00
|
|
|
void GdbEngine::handleInferiorPrepared()
|
2009-09-21 11:09:38 +02:00
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
2011-03-18 10:02:07 +01:00
|
|
|
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2011-03-04 16:21:57 +01:00
|
|
|
|
2015-05-27 13:59:56 +02:00
|
|
|
if (!rp.commandsAfterConnect.isEmpty()) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString commands = expand(rp.commandsAfterConnect);
|
2016-12-13 13:37:05 +01:00
|
|
|
for (const QString &command : commands.split('\n'))
|
2017-01-20 10:05:31 +01:00
|
|
|
runCommand({command, NativeCommand});
|
2013-09-12 18:46:35 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-06 10:30:25 +01:00
|
|
|
if (m_commandForToken.isEmpty()) {
|
2010-07-08 18:10:50 +02:00
|
|
|
finishInferiorSetup();
|
2009-10-20 11:02:16 +02:00
|
|
|
} else {
|
2018-07-23 22:28:49 +02:00
|
|
|
QTC_CHECK(m_commandsDoneCallback == nullptr);
|
2010-07-08 18:10:50 +02:00
|
|
|
m_commandsDoneCallback = &GdbEngine::finishInferiorSetup;
|
2009-10-20 11:02:16 +02:00
|
|
|
}
|
2009-09-24 10:08:17 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void GdbEngine::finishInferiorSetup()
|
2009-09-24 10:08:17 +02:00
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2011-04-18 14:30:52 +02:00
|
|
|
|
2015-11-02 16:01:43 +01:00
|
|
|
if (runParameters().startMode != AttachCore) { // No breakpoints in core files.
|
|
|
|
|
const bool onAbort = boolSetting(BreakOnAbort);
|
|
|
|
|
const bool onWarning = boolSetting(BreakOnWarning);
|
|
|
|
|
const bool onFatal = boolSetting(BreakOnFatal);
|
|
|
|
|
if (onAbort || onWarning || onFatal) {
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("createSpecialBreakpoints");
|
2015-11-02 16:01:43 +01:00
|
|
|
cmd.arg("breakonabort", onAbort);
|
|
|
|
|
cmd.arg("breakonwarning", onWarning);
|
|
|
|
|
cmd.arg("breakonfatal", onFatal);
|
|
|
|
|
runCommand(cmd);
|
2012-12-20 15:26:51 +01:00
|
|
|
}
|
2011-05-30 16:01:50 +02:00
|
|
|
}
|
2015-11-02 16:01:43 +01:00
|
|
|
|
|
|
|
|
// It is ok to cut corners here and not wait for createSpecialBreakpoints()'s
|
|
|
|
|
// response, as the command is synchronous from Creator's point of view,
|
|
|
|
|
// and even if it fails (e.g. due to stripped binaries), continuing with
|
|
|
|
|
// the start up is the best we can do.
|
2017-11-15 17:12:03 +01:00
|
|
|
notifyEngineSetupOk();
|
2011-03-21 15:04:31 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 15:47:07 +01:00
|
|
|
void GdbEngine::handleDebugInfoLocation(const DebuggerResponse &response)
|
2014-02-27 12:54:20 +01:00
|
|
|
{
|
2015-02-05 15:47:07 +01:00
|
|
|
if (response.resultClass == ResultDone) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString debugInfoLocation = runParameters().debugInfoLocation;
|
2018-06-05 08:01:03 +02:00
|
|
|
if (!debugInfoLocation.isEmpty() && QFile::exists(debugInfoLocation)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
const QString curDebugInfoLocations = response.consoleStreamOutput.split('"').value(1);
|
|
|
|
|
QString cmd = "set debug-file-directory " + debugInfoLocation;
|
2015-11-03 12:01:57 +01:00
|
|
|
if (!curDebugInfoLocations.isEmpty())
|
2016-06-07 17:04:53 +02:00
|
|
|
cmd += HostOsInfo::pathListSeparator() + curDebugInfoLocations;
|
2016-12-13 13:37:05 +01:00
|
|
|
runCommand({cmd});
|
2014-02-27 12:54:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-12 10:33:59 +02:00
|
|
|
void GdbEngine::notifyInferiorSetupFailedHelper(const QString &msg)
|
2009-09-21 17:35:19 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
showStatusMessage(tr("Failed to start application:") + ' ' + msg);
|
2010-07-09 08:48:33 +02:00
|
|
|
if (state() == EngineSetupFailed) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("INFERIOR START FAILED, BUT ADAPTER DIED ALREADY");
|
2009-10-29 11:20:21 +01:00
|
|
|
return; // Adapter crashed meanwhile, so this notification is meaningless.
|
2010-03-10 15:51:31 +01:00
|
|
|
}
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("INFERIOR START FAILED");
|
2017-10-19 09:10:57 +02:00
|
|
|
AsynchronousMessageBox::critical(tr("Failed to Start Application"), msg);
|
2017-11-15 17:12:03 +01:00
|
|
|
notifyEngineSetupFailed();
|
2009-09-21 17:35:19 +02:00
|
|
|
}
|
|
|
|
|
|
2010-03-29 18:44:02 +02:00
|
|
|
void GdbEngine::createFullBacktrace()
|
|
|
|
|
{
|
2016-12-13 09:46:51 +01:00
|
|
|
DebuggerCommand cmd("thread apply all bt full", NeedsTemporaryStop | ConsoleCommand);
|
2017-09-07 17:05:47 +02:00
|
|
|
cmd.callback = [](const DebuggerResponse &response) {
|
2015-09-11 11:28:55 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
2016-06-07 17:04:53 +02:00
|
|
|
Internal::openTextEditor("Backtrace $",
|
|
|
|
|
response.consoleStreamOutput + response.logStreamOutput);
|
2015-09-11 11:28:55 +02:00
|
|
|
}
|
|
|
|
|
};
|
2015-10-06 23:08:57 +03:00
|
|
|
runCommand(cmd);
|
2010-03-29 18:44:02 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-11 09:46:39 +02:00
|
|
|
void GdbEngine::resetCommandQueue()
|
|
|
|
|
{
|
2010-11-16 12:42:57 +01:00
|
|
|
m_commandTimer.stop();
|
2015-02-06 10:30:25 +01:00
|
|
|
if (!m_commandForToken.isEmpty()) {
|
2010-08-11 09:46:39 +02:00
|
|
|
QString msg;
|
|
|
|
|
QTextStream ts(&msg);
|
|
|
|
|
ts << "RESETING COMMAND QUEUE. LEFT OVER TOKENS: ";
|
2015-02-06 10:30:25 +01:00
|
|
|
foreach (const DebuggerCommand &cmd, m_commandForToken)
|
|
|
|
|
ts << "CMD:" << cmd.function;
|
|
|
|
|
m_commandForToken.clear();
|
2015-09-11 11:28:55 +02:00
|
|
|
m_flagsForToken.clear();
|
2010-08-11 09:46:39 +02:00
|
|
|
showMessage(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-29 18:44:02 +02:00
|
|
|
|
2012-03-09 15:04:59 +01:00
|
|
|
bool GdbEngine::usesExecInterrupt() const
|
|
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
DebuggerStartMode mode = runParameters().startMode;
|
2012-06-05 10:25:48 +02:00
|
|
|
return (mode == AttachToRemoteServer || mode == AttachToRemoteProcess)
|
2016-04-19 14:01:44 +02:00
|
|
|
&& usesTargetAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbEngine::usesTargetAsync() const
|
|
|
|
|
{
|
|
|
|
|
return runParameters().useTargetAsync || boolSetting(TargetAsync);
|
2012-03-09 15:04:59 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void GdbEngine::scheduleTestResponse(int testCase, const QString &response)
|
2011-06-06 18:17:51 +02:00
|
|
|
{
|
2015-05-27 13:59:56 +02:00
|
|
|
if (!m_testCases.contains(testCase) && runParameters().testCase != testCase)
|
2011-06-06 18:17:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int token = currentToken() + 1;
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage(QString("SCHEDULING TEST RESPONSE (CASE: %1, TOKEN: %2, RESPONSE: %3)")
|
|
|
|
|
.arg(testCase).arg(token).arg(response));
|
2011-06-06 18:17:51 +02:00
|
|
|
m_scheduledTestResponses[token] = response;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-13 10:15:56 +02:00
|
|
|
QString GdbEngine::msgGdbStopFailed(const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return tr("The gdb process could not be stopped:\n%1").arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgInferiorStopFailed(const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return tr("Application process could not be stopped:\n%1").arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgInferiorSetupOk()
|
|
|
|
|
{
|
2017-10-19 09:10:57 +02:00
|
|
|
return tr("Application started.");
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgInferiorRunOk()
|
|
|
|
|
{
|
2017-10-19 09:10:57 +02:00
|
|
|
return tr("Application running.");
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgAttachedToStoppedInferior()
|
|
|
|
|
{
|
2017-10-19 09:10:57 +02:00
|
|
|
return tr("Attached to stopped application.");
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgConnectRemoteServerFailed(const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return tr("Connecting to remote server failed:\n%1").arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::interruptLocalInferior(qint64 pid)
|
|
|
|
|
{
|
2017-09-08 08:53:15 +02:00
|
|
|
CHECK_STATE(InferiorStopRequested);
|
2012-06-13 10:15:56 +02:00
|
|
|
if (pid <= 0) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError);
|
2012-06-13 10:15:56 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (interruptProcess(pid, GdbEngineType, &errorMessage)) {
|
2016-06-07 17:04:53 +02:00
|
|
|
showMessage("Interrupted " + QString::number(pid));
|
2012-06-13 10:15:56 +02:00
|
|
|
} else {
|
|
|
|
|
showMessage(errorMessage, LogError);
|
|
|
|
|
notifyInferiorStopFailed();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-04 01:34:51 +01:00
|
|
|
void GdbEngine::debugLastCommand()
|
|
|
|
|
{
|
2015-02-11 17:51:15 +01:00
|
|
|
runCommand(m_lastDebuggableCommand);
|
2014-01-04 01:34:51 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
bool GdbEngine::isPlainEngine() const
|
|
|
|
|
{
|
2017-09-27 08:22:02 +02:00
|
|
|
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && !terminal();
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbEngine::isCoreEngine() const
|
|
|
|
|
{
|
2017-10-16 14:56:35 +02:00
|
|
|
return runParameters().startMode == AttachCore;
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
2009-09-23 09:54:21 +02:00
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
bool GdbEngine::isRemoteEngine() const
|
2010-06-16 11:08:54 +02:00
|
|
|
{
|
2017-10-16 14:56:35 +02:00
|
|
|
DebuggerStartMode startMode = runParameters().startMode;
|
|
|
|
|
return startMode == StartRemoteProcess || startMode == AttachToRemoteServer;
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbEngine::isAttachEngine() const
|
|
|
|
|
{
|
2017-10-16 14:56:35 +02:00
|
|
|
return runParameters().startMode == AttachExternal;
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbEngine::isTermEngine() const
|
|
|
|
|
{
|
2017-09-27 08:22:02 +02:00
|
|
|
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && terminal();
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::setupInferior()
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
|
2017-09-27 15:30:02 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
|
2017-11-15 17:12:03 +01:00
|
|
|
//runCommand("set follow-exec-mode new");
|
|
|
|
|
if (rp.breakOnMain)
|
|
|
|
|
runCommand({"tbreak " + mainFunction()});
|
|
|
|
|
|
|
|
|
|
// Initial attempt to set breakpoints.
|
|
|
|
|
if (rp.startMode != AttachCore) {
|
|
|
|
|
showStatusMessage(tr("Setting breakpoints..."));
|
|
|
|
|
showMessage(tr("Setting breakpoints..."));
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
BreakpointManager::claimBreakpointsForEngine(this);
|
2017-11-15 17:12:03 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-19 08:29:20 +02:00
|
|
|
if (rp.startMode == AttachToRemoteProcess) {
|
|
|
|
|
|
2017-11-15 17:12:03 +01:00
|
|
|
notifyEngineSetupOk();
|
2017-10-19 08:29:20 +02:00
|
|
|
|
|
|
|
|
} else if (isAttachEngine()) {
|
2017-09-08 08:53:15 +02:00
|
|
|
// Task 254674 does not want to remove them
|
|
|
|
|
//qq->breakHandler()->removeAllBreakpoints();
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
|
|
|
|
|
} else if (isRemoteEngine()) {
|
|
|
|
|
|
|
|
|
|
setLinuxOsAbi();
|
|
|
|
|
QString symbolFile;
|
2019-06-20 17:19:12 +02:00
|
|
|
if (!rp.symbolFile.isEmpty())
|
|
|
|
|
symbolFile = rp.symbolFile.toFileInfo().absoluteFilePath();
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
//const QByteArray sysroot = sp.sysroot.toLocal8Bit();
|
|
|
|
|
//const QByteArray remoteArch = sp.remoteArchitecture.toLatin1();
|
|
|
|
|
const QString args = runParameters().inferior.commandLineArguments;
|
|
|
|
|
|
|
|
|
|
// if (!remoteArch.isEmpty())
|
|
|
|
|
// postCommand("set architecture " + remoteArch);
|
2017-09-19 12:00:16 +02:00
|
|
|
if (!rp.solibSearchPath.isEmpty()) {
|
|
|
|
|
DebuggerCommand cmd("appendSolibSearchPath");
|
|
|
|
|
cmd.arg("path", rp.solibSearchPath);
|
|
|
|
|
cmd.arg("separator", HostOsInfo::pathListSeparator());
|
|
|
|
|
runCommand(cmd);
|
|
|
|
|
}
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
if (!args.isEmpty())
|
|
|
|
|
runCommand({"-exec-arguments " + args});
|
|
|
|
|
|
|
|
|
|
setEnvironmentVariables();
|
|
|
|
|
|
|
|
|
|
// This has to be issued before 'target remote'. On pre-7.0 the
|
|
|
|
|
// command is not present and will result in ' No symbol table is
|
|
|
|
|
// loaded. Use the "file" command.' as gdb tries to set the
|
|
|
|
|
// value of a variable with name 'target-async'.
|
|
|
|
|
//
|
|
|
|
|
// Testing with -list-target-features which was introduced at
|
|
|
|
|
// the same time would not work either, as this need an existing
|
|
|
|
|
// target.
|
|
|
|
|
//
|
|
|
|
|
// Using it even without a target and having it fail might still
|
|
|
|
|
// be better as:
|
|
|
|
|
// Some external comment: '[but] "set target-async on" with a native
|
|
|
|
|
// windows gdb will work, but then fail when you actually do
|
|
|
|
|
// "run"/"attach", I think..
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gdb/mi/mi-main.c:1958: internal-error:
|
|
|
|
|
// mi_execute_async_cli_command: Assertion `is_running (inferior_ptid)'
|
|
|
|
|
// failed.\nA problem internal to GDB has been detected,[...]
|
|
|
|
|
if (usesTargetAsync())
|
|
|
|
|
runCommand({"set target-async on", CB(handleSetTargetAsync)});
|
|
|
|
|
|
|
|
|
|
if (symbolFile.isEmpty()) {
|
|
|
|
|
showMessage(tr("No symbol file given."), StatusBar);
|
|
|
|
|
callTargetRemote();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!symbolFile.isEmpty()) {
|
|
|
|
|
runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
|
|
|
|
|
CB(handleFileExecAndSymbols)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (isCoreEngine()) {
|
|
|
|
|
|
|
|
|
|
setLinuxOsAbi();
|
2017-09-27 15:30:02 +02:00
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
FilePath executable = rp.inferior.executable;
|
2017-09-27 15:30:02 +02:00
|
|
|
|
|
|
|
|
if (executable.isEmpty()) {
|
|
|
|
|
CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(rp.debugger, rp.coreFile);
|
|
|
|
|
|
|
|
|
|
if (!cinfo.isCore) {
|
|
|
|
|
AsynchronousMessageBox::warning(tr("Error Loading Core File"),
|
|
|
|
|
tr("The specified file does not appear to be a core file."));
|
2017-11-15 17:12:03 +01:00
|
|
|
notifyEngineSetupFailed();
|
2017-09-27 15:30:02 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
executable = FilePath::fromString(cinfo.foundExecutableName);
|
2017-09-27 15:30:02 +02:00
|
|
|
if (executable.isEmpty()) {
|
|
|
|
|
AsynchronousMessageBox::warning(tr("Error Loading Symbols"),
|
|
|
|
|
tr("No executable to load symbols from specified core."));
|
2017-11-15 17:12:03 +01:00
|
|
|
notifyEngineSetupFailed();
|
2017-09-27 15:30:02 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
// Do that first, otherwise no symbols are loaded.
|
2019-06-20 17:19:12 +02:00
|
|
|
QFileInfo fi = executable.toFileInfo();
|
2017-09-08 08:53:15 +02:00
|
|
|
QString path = fi.absoluteFilePath();
|
|
|
|
|
runCommand({"-file-exec-and-symbols \"" + path + '"',
|
|
|
|
|
CB(handleFileExecAndSymbols)});
|
|
|
|
|
|
|
|
|
|
} else if (isTermEngine()) {
|
|
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
const qint64 attachedPID = terminal()->applicationPid();
|
|
|
|
|
const qint64 attachedMainThreadID = terminal()->applicationMainThreadId();
|
2017-09-08 08:53:15 +02:00
|
|
|
notifyInferiorPid(ProcessHandle(attachedPID));
|
|
|
|
|
const QString msg = (attachedMainThreadID != -1)
|
|
|
|
|
? QString("Going to attach to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
|
|
|
|
|
: QString("Going to attach to %1").arg(attachedPID);
|
|
|
|
|
showMessage(msg, LogMisc);
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
|
|
|
|
|
} else if (isPlainEngine()) {
|
|
|
|
|
|
|
|
|
|
setEnvironmentVariables();
|
|
|
|
|
if (!rp.inferior.workingDirectory.isEmpty())
|
|
|
|
|
runCommand({"cd " + rp.inferior.workingDirectory});
|
|
|
|
|
if (!rp.inferior.commandLineArguments.isEmpty()) {
|
|
|
|
|
QString args = rp.inferior.commandLineArguments;
|
|
|
|
|
runCommand({"-exec-arguments " + args});
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
QString executable = runParameters().inferior.executable.toFileInfo().absoluteFilePath();
|
2017-09-08 08:53:15 +02:00
|
|
|
runCommand({"-file-exec-and-symbols \"" + executable + '"',
|
|
|
|
|
CB(handleFileExecAndSymbols)});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::runEngine()
|
|
|
|
|
{
|
|
|
|
|
CHECK_STATE(EngineRunRequested);
|
|
|
|
|
|
2017-10-19 08:29:20 +02:00
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
|
|
|
|
|
if (rp.startMode == AttachToRemoteProcess) {
|
|
|
|
|
|
|
|
|
|
notifyEngineRunAndInferiorStopOk();
|
2017-09-08 08:53:15 +02:00
|
|
|
|
2017-10-19 08:29:20 +02:00
|
|
|
QString channel = rp.remoteChannel;
|
|
|
|
|
runCommand({"target remote " + channel});
|
|
|
|
|
|
|
|
|
|
} else if (isAttachEngine()) {
|
|
|
|
|
|
|
|
|
|
const qint64 pid = rp.attachPID.pid();
|
2017-09-08 08:53:15 +02:00
|
|
|
showStatusMessage(tr("Attaching to process %1.").arg(pid));
|
|
|
|
|
runCommand({"attach " + QString::number(pid),
|
|
|
|
|
[this](const DebuggerResponse &r) { handleAttach(r); }});
|
|
|
|
|
// In some cases we get only output like
|
|
|
|
|
// "Could not attach to process. If your uid matches the uid of the target\n"
|
|
|
|
|
// "process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try\n"
|
|
|
|
|
// " again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf\n"
|
|
|
|
|
// " ptrace: Operation not permitted.\n"
|
|
|
|
|
// but no(!) ^ response. Use a second command to force *some* output
|
|
|
|
|
runCommand({"print 24"});
|
|
|
|
|
|
|
|
|
|
} else if (isRemoteEngine()) {
|
|
|
|
|
|
|
|
|
|
if (runParameters().useContinueInsteadOfRun) {
|
|
|
|
|
notifyEngineRunAndInferiorStopOk();
|
|
|
|
|
continueInferiorInternal();
|
|
|
|
|
} else {
|
|
|
|
|
runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (isCoreEngine()) {
|
|
|
|
|
|
2017-09-27 15:30:02 +02:00
|
|
|
runCommand({"target core " + runParameters().coreFile, CB(handleTargetCore)});
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
} else if (isTermEngine()) {
|
|
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
const qint64 attachedPID = terminal()->applicationPid();
|
|
|
|
|
const qint64 mainThreadId = terminal()->applicationMainThreadId();
|
2017-09-08 08:53:15 +02:00
|
|
|
runCommand({"attach " + QString::number(attachedPID),
|
2017-09-27 08:22:02 +02:00
|
|
|
[this, mainThreadId](const DebuggerResponse &r) {
|
|
|
|
|
handleStubAttached(r, mainThreadId);
|
|
|
|
|
}});
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
} else if (isPlainEngine()) {
|
|
|
|
|
|
|
|
|
|
if (runParameters().useContinueInsteadOfRun)
|
|
|
|
|
runCommand({"-exec-continue", DebuggerCommand::RunRequest, CB(handleExecuteContinue)});
|
|
|
|
|
else
|
|
|
|
|
runCommand({"-exec-run", DebuggerCommand::RunRequest, CB(handleExecRun)});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleAttach(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
if (isAttachEngine()) {
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk, qDebug() << state());
|
|
|
|
|
switch (response.resultClass) {
|
|
|
|
|
case ResultDone:
|
|
|
|
|
case ResultRunning:
|
|
|
|
|
showMessage("INFERIOR ATTACHED");
|
|
|
|
|
if (state() == EngineRunRequested) {
|
|
|
|
|
// Happens e.g. for "Attach to unstarted application"
|
|
|
|
|
// We will get a '*stopped' later that we'll interpret as 'spontaneous'
|
|
|
|
|
// So acknowledge the current state and put a delayed 'continue' in the pipe.
|
2017-10-19 09:10:57 +02:00
|
|
|
showMessage(tr("Attached to running application."), StatusBar);
|
2017-09-08 08:53:15 +02:00
|
|
|
notifyEngineRunAndInferiorRunOk();
|
|
|
|
|
} else {
|
|
|
|
|
// InferiorStopOk, e.g. for "Attach to running application".
|
|
|
|
|
// The *stopped came in between sending the 'attach' and
|
|
|
|
|
// receiving its '^done'.
|
2017-10-19 08:29:20 +02:00
|
|
|
notifyEngineRunAndInferiorStopOk();
|
2017-09-08 08:53:15 +02:00
|
|
|
if (runParameters().continueAfterAttach)
|
|
|
|
|
continueInferiorInternal();
|
2019-04-09 08:20:38 +02:00
|
|
|
else
|
|
|
|
|
updateAll();
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ResultError:
|
|
|
|
|
if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
|
|
|
|
|
QString msg = msgPtraceError(runParameters().startMode);
|
|
|
|
|
showStatusMessage(tr("Failed to attach to application: %1").arg(msg));
|
|
|
|
|
AsynchronousMessageBox::warning(tr("Debugger Error"), msg);
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
showStatusMessage(tr("Failed to attach to application: %1")
|
|
|
|
|
.arg(QString(response.data["msg"].data())));
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
showStatusMessage(tr("Failed to attach to application: %1")
|
|
|
|
|
.arg(QString(response.data["msg"].data())));
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (isRemoteEngine()) {
|
|
|
|
|
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
switch (response.resultClass) {
|
|
|
|
|
case ResultDone:
|
|
|
|
|
case ResultRunning: {
|
|
|
|
|
showMessage("INFERIOR ATTACHED");
|
|
|
|
|
showMessage(msgAttachedToStoppedInferior(), StatusBar);
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ResultError:
|
|
|
|
|
if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msgPtraceError(runParameters().startMode));
|
2017-09-08 08:53:15 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(response.data["msg"].data());
|
2017-09-08 08:53:15 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(response.data["msg"].data());
|
2017-09-08 08:53:15 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::interruptInferior2()
|
|
|
|
|
{
|
|
|
|
|
if (isAttachEngine()) {
|
|
|
|
|
|
|
|
|
|
interruptLocalInferior(runParameters().attachPID.pid());
|
|
|
|
|
|
2017-10-20 13:08:37 +02:00
|
|
|
} else if (isRemoteEngine() || runParameters().startMode == AttachToRemoteProcess) {
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
CHECK_STATE(InferiorStopRequested);
|
|
|
|
|
if (usesTargetAsync()) {
|
|
|
|
|
runCommand({"-exec-interrupt", CB(handleInterruptInferior)});
|
|
|
|
|
} else if (m_isQnxGdb && HostOsInfo::isWindowsHost()) {
|
|
|
|
|
m_gdbProc.interrupt();
|
|
|
|
|
} else {
|
|
|
|
|
qint64 pid = m_gdbProc.processId();
|
|
|
|
|
bool ok = interruptProcess(pid, GdbEngineType, &m_errorString);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
// FIXME: Extra state needed?
|
|
|
|
|
showMessage("NOTE: INFERIOR STOP NOT POSSIBLE");
|
2017-10-19 09:10:57 +02:00
|
|
|
showStatusMessage(tr("Interrupting not possible."));
|
2017-09-08 08:53:15 +02:00
|
|
|
notifyInferiorRunOk();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (isTermEngine() || isPlainEngine()) {
|
|
|
|
|
|
|
|
|
|
interruptLocalInferior(inferiorPid());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-19 19:48:44 +03:00
|
|
|
QChar GdbEngine::mixedDisasmFlag() const
|
|
|
|
|
{
|
|
|
|
|
// /m is deprecated since 7.11, and was replaced by /s which works better with optimizations
|
|
|
|
|
return m_gdbVersion >= 71100 ? 's' : 'm';
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
void GdbEngine::shutdownEngine()
|
|
|
|
|
{
|
|
|
|
|
if (isPlainEngine()) {
|
|
|
|
|
showMessage(QString("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
|
|
|
|
|
m_outputCollector.shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-27 16:53:57 +02:00
|
|
|
CHECK_STATE(EngineShutdownRequested);
|
2017-10-06 13:11:29 +02:00
|
|
|
showMessage(QString("INITIATE GDBENGINE SHUTDOWN, PROC STATE: %1").arg(m_gdbProc.state()));
|
2018-07-23 22:28:49 +02:00
|
|
|
m_commandsDoneCallback = nullptr;
|
2017-09-27 16:53:57 +02:00
|
|
|
switch (m_gdbProc.state()) {
|
|
|
|
|
case QProcess::Running: {
|
|
|
|
|
if (runParameters().closeMode == KillAndExitMonitorAtClose)
|
|
|
|
|
runCommand({"monitor exit"});
|
|
|
|
|
runCommand({"exitGdb", ExitRequest, CB(handleGdbExit)});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case QProcess::NotRunning:
|
|
|
|
|
// Cannot find executable.
|
2017-12-14 09:11:16 +01:00
|
|
|
notifyEngineShutdownFinished();
|
2017-09-27 16:53:57 +02:00
|
|
|
break;
|
|
|
|
|
case QProcess::Starting:
|
|
|
|
|
showMessage("GDB NOT REALLY RUNNING; KILLING IT");
|
|
|
|
|
m_gdbProc.kill();
|
2017-12-14 09:11:16 +01:00
|
|
|
notifyEngineShutdownFinished();
|
2017-09-27 16:53:57 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
if (isRemoteEngine()) {
|
2018-07-12 12:04:18 +02:00
|
|
|
if (response.resultClass != ResultDone) {
|
|
|
|
|
QString msg = response.data["msg"].data();
|
|
|
|
|
if (!msg.isEmpty()) {
|
|
|
|
|
showMessage(msg);
|
2017-09-08 08:53:15 +02:00
|
|
|
showMessage(msg, StatusBar);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-12 12:04:18 +02:00
|
|
|
callTargetRemote(); // Proceed nevertheless.
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
} else if (isCoreEngine()) {
|
|
|
|
|
|
2017-09-27 15:30:02 +02:00
|
|
|
QString core = runParameters().coreFile;
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
showMessage(tr("Symbols found."), StatusBar);
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
} else {
|
2017-10-19 09:10:57 +02:00
|
|
|
QString msg = tr("No symbols found in the core file \"%1\".").arg(core)
|
2017-09-08 08:53:15 +02:00
|
|
|
+ ' ' + tr("This can be caused by a path length limitation "
|
|
|
|
|
"in the core file.")
|
2017-10-19 09:10:57 +02:00
|
|
|
+ ' ' + tr("Try to specify the binary in "
|
2017-12-27 13:56:54 +01:00
|
|
|
"Debug > Start Debugging > Load Core File.");
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msg);
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (isPlainEngine()) {
|
|
|
|
|
|
|
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
} else {
|
|
|
|
|
QString msg = response.data["msg"].data();
|
|
|
|
|
// Extend the message a bit in unknown cases.
|
|
|
|
|
if (!msg.endsWith("File format not recognized"))
|
|
|
|
|
msg = tr("Starting executable failed:") + '\n' + msg;
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msg);
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleExecRun(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
CHECK_STATE(EngineRunRequested);
|
|
|
|
|
|
2018-08-17 16:34:43 +02:00
|
|
|
if (response.resultClass == ResultRunning) {
|
|
|
|
|
notifyEngineRunAndInferiorRunOk();
|
|
|
|
|
showMessage("INFERIOR STARTED");
|
|
|
|
|
showMessage(msgInferiorSetupOk(), StatusBar);
|
|
|
|
|
} else {
|
|
|
|
|
showMessage(response.data["msg"].data());
|
|
|
|
|
notifyEngineRunFailed();
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleSetTargetAsync(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultError)
|
|
|
|
|
qDebug() << "Adapter too old: does not support asynchronous mode.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::callTargetRemote()
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
QString channel = runParameters().remoteChannel;
|
|
|
|
|
|
|
|
|
|
// Don't touch channels with explicitly set protocols.
|
|
|
|
|
if (!channel.startsWith("tcp:") && !channel.startsWith("udp:")
|
|
|
|
|
&& !channel.startsWith("file:") && channel.contains(':')
|
|
|
|
|
&& !channel.startsWith('|'))
|
|
|
|
|
{
|
|
|
|
|
// "Fix" the IPv6 case with host names without '['...']'
|
|
|
|
|
if (!channel.startsWith('[') && channel.count(':') >= 2) {
|
|
|
|
|
channel.insert(0, '[');
|
|
|
|
|
channel.insert(channel.lastIndexOf(':'), ']');
|
|
|
|
|
}
|
|
|
|
|
channel = "tcp:" + channel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_isQnxGdb)
|
|
|
|
|
runCommand({"target qnx " + channel, CB(handleTargetQnx)});
|
|
|
|
|
else if (runParameters().useExtendedRemote)
|
|
|
|
|
runCommand({"target extended-remote " + channel, CB(handleTargetExtendedRemote)});
|
|
|
|
|
else
|
|
|
|
|
runCommand({"target remote " + channel, CB(handleTargetRemote)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleTargetRemote(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
// gdb server will stop the remote application itself.
|
|
|
|
|
showMessage("INFERIOR STARTED");
|
|
|
|
|
showMessage(msgAttachedToStoppedInferior(), StatusBar);
|
|
|
|
|
QString commands = expand(stringSetting(GdbPostAttachCommands));
|
|
|
|
|
if (!commands.isEmpty())
|
|
|
|
|
runCommand({commands, NativeCommand});
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
} else {
|
|
|
|
|
// 16^error,msg="hd:5555: Connection timed out."
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msgConnectRemoteServerFailed(response.data["msg"].data()));
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleTargetExtendedRemote(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
showMessage("ATTACHED TO GDB SERVER STARTED");
|
|
|
|
|
showMessage(msgAttachedToStoppedInferior(), StatusBar);
|
|
|
|
|
QString commands = expand(stringSetting(GdbPostAttachCommands));
|
|
|
|
|
if (!commands.isEmpty())
|
|
|
|
|
runCommand({commands, NativeCommand});
|
|
|
|
|
if (runParameters().attachPID.isValid()) { // attach to pid if valid
|
|
|
|
|
// gdb server will stop the remote application itself.
|
|
|
|
|
runCommand({"attach " + QString::number(runParameters().attachPID.pid()),
|
|
|
|
|
CB(handleTargetExtendedAttach)});
|
|
|
|
|
} else if (!runParameters().inferior.executable.isEmpty()) {
|
2019-06-20 17:19:12 +02:00
|
|
|
runCommand({"-gdb-set remote exec-file " + runParameters().inferior.executable.toString(),
|
2017-09-08 08:53:15 +02:00
|
|
|
CB(handleTargetExtendedAttach)});
|
|
|
|
|
} else {
|
|
|
|
|
const QString title = tr("No Remote Executable or Process ID Specified");
|
|
|
|
|
const QString msg = tr(
|
|
|
|
|
"No remote executable could be determined from your build system files.<p>"
|
|
|
|
|
"In case you use qmake, consider adding<p>"
|
|
|
|
|
" target.path = /tmp/your_executable # path on device<br>"
|
|
|
|
|
" INSTALLS += target</p>"
|
|
|
|
|
"to your .pro file.");
|
|
|
|
|
QMessageBox *mb = showMessageBox(QMessageBox::Critical, title, msg,
|
|
|
|
|
QMessageBox::Ok | QMessageBox::Cancel);
|
|
|
|
|
mb->button(QMessageBox::Cancel)->setText(tr("Continue Debugging"));
|
|
|
|
|
mb->button(QMessageBox::Ok)->setText(tr("Stop Debugging"));
|
|
|
|
|
if (mb->exec() == QMessageBox::Ok) {
|
|
|
|
|
showMessage("KILLING DEBUGGER AS REQUESTED BY USER");
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(title);
|
2017-09-08 08:53:15 +02:00
|
|
|
} else {
|
|
|
|
|
showMessage("CONTINUE DEBUGGER AS REQUESTED BY USER");
|
|
|
|
|
handleInferiorPrepared(); // This will likely fail.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msgConnectRemoteServerFailed(response.data["msg"].data()));
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleTargetExtendedAttach(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
// gdb server will stop the remote application itself.
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
} else {
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(msgConnectRemoteServerFailed(response.data["msg"].data()));
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleTargetQnx(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
// gdb server will stop the remote application itself.
|
|
|
|
|
showMessage("INFERIOR STARTED");
|
|
|
|
|
showMessage(msgAttachedToStoppedInferior(), StatusBar);
|
|
|
|
|
|
|
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
if (rp.attachPID.isValid())
|
|
|
|
|
runCommand({"attach " + QString::number(rp.attachPID.pid()), CB(handleAttach)});
|
2019-06-20 17:19:12 +02:00
|
|
|
else if (!rp.inferior.executable.isEmpty())
|
|
|
|
|
runCommand({"set nto-executable " + rp.inferior.executable.toString(),
|
|
|
|
|
CB(handleSetNtoExecutable)});
|
2017-09-08 08:53:15 +02:00
|
|
|
else
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
} else {
|
|
|
|
|
// 16^error,msg="hd:5555: Connection timed out."
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(response.data["msg"].data());
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleSetNtoExecutable(const DebuggerResponse &response)
|
|
|
|
|
{
|
2017-11-15 17:12:03 +01:00
|
|
|
CHECK_STATE(EngineSetupRequested);
|
2017-09-08 08:53:15 +02:00
|
|
|
switch (response.resultClass) {
|
|
|
|
|
case ResultDone:
|
|
|
|
|
case ResultRunning: {
|
|
|
|
|
showMessage("EXECUTABLE SET");
|
|
|
|
|
showMessage(msgAttachedToStoppedInferior(), StatusBar);
|
|
|
|
|
handleInferiorPrepared();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ResultError:
|
2012-06-13 10:15:56 +02:00
|
|
|
default:
|
2017-09-12 10:33:59 +02:00
|
|
|
notifyInferiorSetupFailedHelper(response.data["msg"].data());
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleInterruptInferior(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
if (response.resultClass == ResultDone) {
|
|
|
|
|
// The gdb server will trigger extra output that we will pick up
|
|
|
|
|
// to do a proper state transition.
|
|
|
|
|
} else {
|
|
|
|
|
// FIXME: On some gdb versions like git 170ffa5d7dd this produces
|
|
|
|
|
// >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
|
|
|
|
|
notifyInferiorStopOk();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
void GdbEngine::handleStubAttached(const DebuggerResponse &response, qint64 mainThreadId)
|
2017-09-08 08:53:15 +02:00
|
|
|
{
|
|
|
|
|
// InferiorStopOk can happen if the "*stopped" in response to the
|
|
|
|
|
// 'attach' comes in before its '^done'
|
|
|
|
|
QTC_ASSERT(state() == EngineRunRequested || state() == InferiorStopOk, qDebug() << state());
|
|
|
|
|
|
|
|
|
|
switch (response.resultClass) {
|
|
|
|
|
case ResultDone:
|
|
|
|
|
case ResultRunning:
|
|
|
|
|
if (runParameters().toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS) {
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
// Resume thread that was suspended by console stub process (see stub code).
|
|
|
|
|
if (winResumeThread(mainThreadId, &errorMessage)) {
|
|
|
|
|
showMessage(QString("Inferior attached, thread %1 resumed").
|
|
|
|
|
arg(mainThreadId), LogMisc);
|
|
|
|
|
} else {
|
|
|
|
|
showMessage(QString("Inferior attached, unable to resume thread %1: %2").
|
|
|
|
|
arg(mainThreadId).arg(errorMessage),
|
|
|
|
|
LogWarning);
|
|
|
|
|
}
|
|
|
|
|
notifyEngineRunAndInferiorStopOk();
|
|
|
|
|
continueInferiorInternal();
|
|
|
|
|
} else {
|
|
|
|
|
showMessage("INFERIOR ATTACHED AND RUNNING");
|
|
|
|
|
//notifyEngineRunAndInferiorRunOk();
|
|
|
|
|
// Wait for the upcoming *stopped and handle it there.
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ResultError:
|
|
|
|
|
if (response.data["msg"].data() == "ptrace: Operation not permitted.") {
|
|
|
|
|
showMessage(msgPtraceError(runParameters().startMode));
|
|
|
|
|
notifyEngineRunFailed();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
showMessage(response.data["msg"].data());
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
showMessage(QString("Invalid response %1").arg(response.resultClass));
|
|
|
|
|
notifyEngineIll();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString findExecutableFromName(const QString &fileNameFromCore, const QString &coreFile)
|
|
|
|
|
{
|
|
|
|
|
if (fileNameFromCore.isEmpty())
|
|
|
|
|
return fileNameFromCore;
|
|
|
|
|
QFileInfo fi(fileNameFromCore);
|
|
|
|
|
if (fi.isFile())
|
|
|
|
|
return fileNameFromCore;
|
|
|
|
|
|
|
|
|
|
// turn the filename into an absolute path, using the location of the core as a hint
|
|
|
|
|
QString absPath;
|
|
|
|
|
if (fi.isAbsolute()) {
|
|
|
|
|
absPath = fileNameFromCore;
|
|
|
|
|
} else {
|
|
|
|
|
QFileInfo coreInfo(coreFile);
|
|
|
|
|
QDir coreDir = coreInfo.dir();
|
|
|
|
|
absPath = FileUtils::resolvePath(coreDir.absolutePath(), fileNameFromCore);
|
|
|
|
|
}
|
|
|
|
|
if (QFileInfo(absPath).isFile() || absPath.isEmpty())
|
|
|
|
|
return absPath;
|
|
|
|
|
|
|
|
|
|
// remove possible trailing arguments
|
2018-10-07 22:38:47 +03:00
|
|
|
QChar sep(' ');
|
2017-09-08 08:53:15 +02:00
|
|
|
QStringList pathFragments = absPath.split(sep);
|
|
|
|
|
while (pathFragments.size() > 0) {
|
|
|
|
|
QString joined_path = pathFragments.join(sep);
|
|
|
|
|
if (QFileInfo(joined_path).isFile()) {
|
|
|
|
|
return joined_path;
|
|
|
|
|
}
|
|
|
|
|
pathFragments.pop_back();
|
2012-06-13 10:15:56 +02:00
|
|
|
}
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 15:42:03 +02:00
|
|
|
CoreInfo CoreInfo::readExecutableNameFromCore(const Runnable &debugger, const QString &coreFile)
|
2017-09-08 08:53:15 +02:00
|
|
|
{
|
|
|
|
|
CoreInfo cinfo;
|
|
|
|
|
#if 0
|
|
|
|
|
ElfReader reader(coreFile);
|
|
|
|
|
cinfo.rawStringFromCore = QString::fromLocal8Bit(reader.readCoreName(&cinfo.isCore));
|
|
|
|
|
cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
|
|
|
|
|
#else
|
2017-10-01 10:20:25 +03:00
|
|
|
QStringList args = {"-nx", "-batch"};
|
|
|
|
|
// Multiarch GDB on Windows crashes if osabi is cygwin (the default) when opening a core dump.
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
|
args += {"-ex", "set osabi GNU/Linux"};
|
|
|
|
|
args += {"-ex", "core " + coreFile};
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
SynchronousProcess proc;
|
|
|
|
|
QStringList envLang = QProcess::systemEnvironment();
|
|
|
|
|
Utils::Environment::setupEnglishOutput(&envLang);
|
|
|
|
|
proc.setEnvironment(envLang);
|
2019-06-20 17:19:12 +02:00
|
|
|
SynchronousProcessResponse response = proc.runBlocking({debugger.executable, args});
|
2017-09-08 08:53:15 +02:00
|
|
|
|
|
|
|
|
if (response.result == SynchronousProcessResponse::Finished) {
|
|
|
|
|
QString output = response.stdOut();
|
|
|
|
|
// Core was generated by `/data/dev/creator-2.6/bin/qtcreator'.
|
|
|
|
|
// Program terminated with signal 11, Segmentation fault.
|
|
|
|
|
int pos1 = output.indexOf("Core was generated by");
|
|
|
|
|
if (pos1 != -1) {
|
|
|
|
|
pos1 += 23;
|
|
|
|
|
int pos2 = output.indexOf('\'', pos1);
|
|
|
|
|
if (pos2 != -1) {
|
|
|
|
|
cinfo.isCore = true;
|
|
|
|
|
cinfo.rawStringFromCore = output.mid(pos1, pos2 - pos1);
|
|
|
|
|
cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return cinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleTargetCore(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
CHECK_STATE(EngineRunRequested);
|
|
|
|
|
notifyEngineRunOkAndInferiorUnrunnable();
|
|
|
|
|
showMessage(tr("Attached to core."), StatusBar);
|
|
|
|
|
if (response.resultClass == ResultError) {
|
|
|
|
|
// We'll accept any kind of error e.g. &"Cannot access memory at address 0x2abc2a24\n"
|
|
|
|
|
// Even without the stack, the user can find interesting stuff by exploring
|
|
|
|
|
// the memory, globals etc.
|
|
|
|
|
showStatusMessage(tr("Attach to core \"%1\" failed:").arg(runParameters().coreFile)
|
|
|
|
|
+ '\n' + response.data["msg"].data()
|
|
|
|
|
+ '\n' + tr("Continuing nevertheless."));
|
|
|
|
|
}
|
|
|
|
|
// Due to the auto-solib-add off setting, we don't have any
|
|
|
|
|
// symbols yet. Load them in order of importance.
|
|
|
|
|
reloadStack();
|
|
|
|
|
reloadModulesInternal();
|
|
|
|
|
runCommand({"p 5", CB(handleCoreRoundTrip)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbEngine::handleCoreRoundTrip(const DebuggerResponse &response)
|
|
|
|
|
{
|
|
|
|
|
CHECK_STATE(InferiorUnrunnable);
|
|
|
|
|
Q_UNUSED(response);
|
|
|
|
|
loadSymbolsForStack();
|
|
|
|
|
handleStop3();
|
|
|
|
|
QTimer::singleShot(1000, this, &GdbEngine::loadAllSymbols);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 13:03:38 +01:00
|
|
|
void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
2013-11-27 16:10:14 +01:00
|
|
|
{
|
2016-11-03 13:28:28 +01:00
|
|
|
watchHandler()->notifyUpdateStarted(params);
|
2015-06-16 16:38:14 +02:00
|
|
|
|
2016-12-13 13:37:05 +01:00
|
|
|
DebuggerCommand cmd("fetchVariables", Discardable|InUpdateLocals);
|
2015-02-12 11:31:02 +01:00
|
|
|
watchHandler()->appendFormatRequests(&cmd);
|
2015-09-14 12:53:35 +02:00
|
|
|
watchHandler()->appendWatchersAndTooltipRequests(&cmd);
|
2015-02-11 17:51:15 +01:00
|
|
|
|
2017-04-14 09:48:25 +02:00
|
|
|
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd.arg("passexceptions", alwaysVerbose);
|
2015-02-11 17:51:15 +01:00
|
|
|
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
|
|
|
|
|
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
|
|
|
|
|
cmd.arg("dyntype", boolSetting(UseDynamicType));
|
2015-12-16 14:13:44 +01:00
|
|
|
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
|
2019-04-09 08:23:24 +02:00
|
|
|
cmd.arg("timestamps", boolSetting(LogTimeStamps));
|
2015-02-11 17:51:15 +01:00
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
StackFrame frame = stackHandler()->currentFrame();
|
|
|
|
|
cmd.arg("context", frame.context);
|
2016-09-20 08:39:26 +02:00
|
|
|
cmd.arg("nativemixed", isNativeMixedActive());
|
|
|
|
|
|
|
|
|
|
cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
|
|
|
|
|
cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
|
2015-01-22 12:05:00 +01:00
|
|
|
|
2015-02-11 17:51:15 +01:00
|
|
|
cmd.arg("resultvarname", m_resultVarName);
|
2015-10-27 15:50:41 +01:00
|
|
|
cmd.arg("partialvar", params.partialVariable);
|
2014-01-07 16:15:08 +01:00
|
|
|
|
2015-02-11 17:51:15 +01:00
|
|
|
m_lastDebuggableCommand = cmd;
|
2016-09-20 08:39:26 +02:00
|
|
|
m_lastDebuggableCommand.arg("passexceptions", "1");
|
|
|
|
|
|
|
|
|
|
cmd.callback = CB(handleFetchVariables);
|
|
|
|
|
|
|
|
|
|
runCommand(cmd);
|
2013-11-27 16:10:14 +01:00
|
|
|
}
|
|
|
|
|
|
2015-10-08 16:19:57 +02:00
|
|
|
void GdbEngine::handleFetchVariables(const DebuggerResponse &response)
|
2013-11-27 16:10:14 +01:00
|
|
|
{
|
2015-07-17 13:30:51 +02:00
|
|
|
m_inUpdateLocals = false;
|
2016-12-16 09:28:40 +01:00
|
|
|
updateLocalsView(response.data);
|
2015-07-06 09:46:08 +02:00
|
|
|
watchHandler()->notifyUpdateFinished();
|
2013-11-27 16:10:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
|
|
|
|
|
{
|
|
|
|
|
if (sm == StartInternal) {
|
|
|
|
|
return QCoreApplication::translate("QtDumperHelper",
|
|
|
|
|
"ptrace: Operation not permitted.\n\n"
|
|
|
|
|
"Could not attach to the process. "
|
|
|
|
|
"Make sure no other debugger traces this process.\n"
|
|
|
|
|
"Check the settings of\n"
|
|
|
|
|
"/proc/sys/kernel/yama/ptrace_scope\n"
|
|
|
|
|
"For more details, see /etc/sysctl.d/10-ptrace.conf\n");
|
|
|
|
|
}
|
|
|
|
|
return QCoreApplication::translate("QtDumperHelper",
|
|
|
|
|
"ptrace: Operation not permitted.\n\n"
|
|
|
|
|
"Could not attach to the process. "
|
|
|
|
|
"Make sure no other debugger traces this process.\n"
|
|
|
|
|
"If your uid matches the uid\n"
|
|
|
|
|
"of the target process, check the settings of\n"
|
|
|
|
|
"/proc/sys/kernel/yama/ptrace_scope\n"
|
|
|
|
|
"For more details, see /etc/sysctl.d/10-ptrace.conf\n");
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-27 08:22:02 +02:00
|
|
|
QString GdbEngine::mainFunction() const
|
|
|
|
|
{
|
|
|
|
|
const DebuggerRunParameters &rp = runParameters();
|
|
|
|
|
return QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS && !terminal() ? "qMain" : "main");
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 08:53:15 +02:00
|
|
|
//
|
|
|
|
|
// Factory
|
|
|
|
|
//
|
|
|
|
|
|
2017-09-26 15:22:14 +02:00
|
|
|
DebuggerEngine *createGdbEngine()
|
2017-09-08 08:53:15 +02:00
|
|
|
{
|
2017-09-26 15:22:14 +02:00
|
|
|
return new GdbEngine;
|
2017-09-08 08:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
2009-08-18 08:34:48 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|
|
|
|
|
|
2010-12-16 11:25:28 +01:00
|
|
|
Q_DECLARE_METATYPE(Debugger::Internal::GdbMi)
|