Commit 8477c7bc authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Add new CDB-engine.

Rubber-stamped-by: hjk
parent 9c0eacf8
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "bytearrayinputstream.h"
namespace Debugger {
namespace Cdb {
ByteArrayInputStream::ByteArrayInputStream(QByteArray &ba) :
m_target(ba), m_integerBase(10), m_hexPrefix(false), m_width(0)
{
}
void hexPrefixOn(ByteArrayInputStream &bs)
{
bs.setHexPrefix(true);
}
void hexPrefixOff(ByteArrayInputStream &bs)
{
bs.setHexPrefix(false);
}
void hex(ByteArrayInputStream &bs)
{
bs.setIntegerBase(16);
}
void dec(ByteArrayInputStream &bs)
{
bs.setIntegerBase(10);
}
QByteArray trimFront(QByteArray in)
{
if (in.isEmpty())
return in;
const int size = in.size();
int pos = 0;
for ( ; pos < size && isspace(in.at(pos)); pos++) ;
if (pos)
in.remove(0, pos);
return in;
}
QByteArray trimBack(QByteArray in)
{
if (in.isEmpty())
return in;
const int size = in.size();
int pos = size - 1;
for ( ; pos >= 0 && isspace(in.at(pos)); pos--) ;
if (pos != size - 1)
in.truncate(pos + 1);
return in;
}
// Simplify: replace tabs, find all occurrences
// of 2 blanks, check further up for blanks and remove that bit.
QByteArray simplify(const QByteArray &inIn)
{
if (inIn.isEmpty())
return inIn;
QByteArray in = trimFront(trimBack(inIn));
in.replace('\t', ' ');
in.replace('\n', ' ');
in.replace('\r', ' ');
const QByteArray twoBlanks = " ";
while (true) {
const int pos = in.indexOf(twoBlanks);
if (pos != -1) {
const int size = in.size();
int endPos = pos + twoBlanks.size();
for ( ; endPos < size && in.at(endPos) == ' '; endPos++) ;
in.remove(pos + 1, endPos - pos - 1);
} else {
break;
}
}
return in;
}
} // namespace Cdb
} // namespace Debugger
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef BYTEARRAYINPUTSTREAM_H
#define BYTEARRAYINPUTSTREAM_H
#include <QtCore/QByteArray>
#include <QtCore/QString>
namespace Debugger {
namespace Cdb {
class ByteArrayInputStream
{
Q_DISABLE_COPY(ByteArrayInputStream)
public:
typedef void (ModifierFunc)(ByteArrayInputStream &s);
explicit ByteArrayInputStream(QByteArray &ba);
ByteArrayInputStream &operator<<(char a) { m_target.append(a); return *this; }
ByteArrayInputStream &operator<<(const QByteArray &a) { m_target.append(a); return *this; }
ByteArrayInputStream &operator<<(const char *a) { m_target.append(a); return *this; }
ByteArrayInputStream &operator<<(const QString &a) { m_target.append(a.toLatin1()); return *this; }
ByteArrayInputStream &operator<<(int i) { appendInt(i); return *this; }
ByteArrayInputStream &operator<<(unsigned i) { appendInt(i); return *this; }
ByteArrayInputStream &operator<<(quint64 i) { appendInt(i); return *this; }
ByteArrayInputStream &operator<<(qint64 i) { appendInt(i); return *this; }
// Stream a modifier by invoking it
ByteArrayInputStream &operator<<(ModifierFunc mf) { mf(*this); return *this; }
void setHexPrefix(bool hp) { m_hexPrefix = hp; }
bool hexPrefix() const { return m_hexPrefix; }
void setIntegerBase(int b) { m_integerBase = b; }
int integerBase() const { return m_integerBase; }
private:
template <class IntType> void appendInt(IntType i);
QByteArray &m_target;
int m_integerBase;
bool m_hexPrefix;
int m_width;
};
template <class IntType>
void ByteArrayInputStream::appendInt(IntType i)
{
const bool hexPrefix = m_integerBase == 16 && m_hexPrefix;
if (hexPrefix)
m_target.append("0x");
const QByteArray n = QByteArray::number(i, m_integerBase);
if (m_width > 0) {
int pad = m_width - n.size();
if (hexPrefix)
pad -= 2;
if (pad > 0)
m_target.append(QByteArray(pad, '0'));
}
m_target.append(n);
}
// Streamable modifiers for ByteArrayInputStream
void hexPrefixOn(ByteArrayInputStream &bs);
void hexPrefixOff(ByteArrayInputStream &bs);
void hex(ByteArrayInputStream &bs);
void dec(ByteArrayInputStream &bs);
// Bytearray parse helpers
QByteArray trimFront(QByteArray in);
QByteArray trimBack(QByteArray in);
QByteArray simplify(const QByteArray &inIn);
} // namespace Cdb
} // namespace Debugger
#endif // BYTEARRAYINPUTSTREAM_H
HEADERS += $$PWD/cdbengine2.h \
cdb2/bytearrayinputstream.h \
cdb2/cdbparsehelpers.h \
cdb2/cdboptions2.h \
cdb2/cdboptionspage2.h
SOURCES += $$PWD/cdbengine2.cpp \
cdb2/bytearrayinputstream.cpp \
cdb2/cdbparsehelpers.cpp \
cdb2/cdboptions2.cpp \
cdb2/cdboptionspage2.cpp
FORMS += cdb2/cdboptionspagewidget2.ui
INCLUDEPATH*=$$PWD
DEPENDPATH*=$$PWD
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef DEBUGGER_CDBENGINE_H
#define DEBUGGER_CDBENGINE_H
#include "debuggerengine.h"
#include <QtCore/QSharedPointer>
#include <QtCore/QProcess>
#include <QtCore/QVariant>
#include <QtCore/QMap>
#include <QtCore/QTime>
namespace Debugger {
namespace Cdb {
class DisassemblerViewAgent;
struct CdbBuiltinCommand;
struct CdbExtensionCommand;
struct CdbOptions;
class CdbEngine : public Debugger::DebuggerEngine
{
Q_OBJECT
public:
typedef QSharedPointer<CdbOptions> OptionsPtr;
enum CommandFlags { QuietCommand = 0x1 };
// Flag bits for a sequence of commands
enum CommandSequenceFlags {
CommandListStack = 0x1,
CommandListThreads = 0x2,
CommandListRegisters = 0x4,
CommandListModules = 0x8
};
typedef QSharedPointer<CdbBuiltinCommand> CdbBuiltinCommandPtr;
typedef QSharedPointer<CdbExtensionCommand> CdbExtensionCommandPtr;
typedef void (CdbEngine::*BuiltinCommandHandler)(const CdbBuiltinCommandPtr &);
typedef void (CdbEngine::*ExtensionCommandHandler)(const CdbExtensionCommandPtr &);
explicit CdbEngine(const DebuggerStartParameters &sp, const OptionsPtr &options);
virtual ~CdbEngine();
// Factory function that returns 0 if the debug engine library cannot be found.
virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
virtual void setupEngine();
virtual void setupInferior();
virtual void runEngine();
virtual void shutdownInferior();
virtual void shutdownEngine();
virtual void detachDebugger();
virtual void updateWatchData(const Debugger::Internal::WatchData &data,
const Debugger::Internal::WatchUpdateFlags & flags = Debugger::Internal::WatchUpdateFlags());
virtual unsigned debuggerCapabilities() const;
virtual void setRegisterValue(int regnr, const QString &value);
virtual void executeStep();
virtual void executeStepOut();
virtual void executeNext();
virtual void executeStepI();
virtual void executeNextI();
virtual void continueInferior();
virtual void interruptInferior();
virtual void executeRunToLine(const QString &fileName, int lineNumber);
virtual void executeRunToFunction(const QString &functionName);
virtual void executeJumpToLine(const QString &fileName, int lineNumber);
virtual void assignValueInDebugger(const Debugger::Internal::WatchData *w, const QString &expr, const QVariant &value);
virtual void executeDebuggerCommand(const QString &command);
virtual void activateFrame(int index);
virtual void selectThread(int index);
virtual void attemptBreakpointSynchronization();
virtual void fetchDisassembler(Debugger::Internal::DisassemblerViewAgent *agent);
virtual void fetchMemory(Debugger::Internal::MemoryViewAgent *, QObject *, quint64 addr, quint64 length);
virtual void reloadModules();
virtual void loadSymbols(const QString &moduleName);
virtual void loadAllSymbols();
virtual void requestModuleSymbols(const QString &moduleName);
virtual void reloadRegisters();
virtual void reloadSourceFiles();
virtual void reloadFullStack();
//virtual bool isSynchronous() const { return true; }
private slots:
void readyReadStandardOut();
void readyReadStandardError();
void processError();
void processFinished();
void postCommand(const QByteArray &cmd, unsigned flags);
void postBuiltinCommand(const QByteArray &cmd,
unsigned flags,
BuiltinCommandHandler handler,
unsigned nextCommandFlag = 0,
const QVariant &cookie = QVariant());
void postExtensionCommand(const QByteArray &cmd,
const QByteArray &arguments,
unsigned flags,
ExtensionCommandHandler handler,
unsigned nextCommandFlag = 0,
const QVariant &cookie = QVariant());
void postCommandSequence(unsigned mask);
void operateByInstructionTriggered(bool);
private:
enum SpecialStopMode { NoSpecialStop, SpecialStopSynchronizeBreakpoints };
void handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message);
bool doSetupEngine(QString *errorMessage);
void handleSessionAccessible(unsigned long cdbExState);
void handleSessionInaccessible(unsigned long cdbExState);
void handleSessionIdle(const QByteArray &message);
void doInterruptInferior(SpecialStopMode sm);
void doContinueInferior();
inline void parseOutputLine(QByteArray line);
inline bool isCdbProcessRunning() const { return m_process.state() != QProcess::NotRunning; }
// Builtin commands
void dummyHandler(const CdbBuiltinCommandPtr &);
void handleStackTrace(const CdbBuiltinCommandPtr &);
void handleRegisters(const CdbBuiltinCommandPtr &);
void handleDisassembler(const CdbBuiltinCommandPtr &);
void handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &);
// Extension commands
void handleThreads(const CdbExtensionCommandPtr &);
void handlePid(const CdbExtensionCommandPtr &reply);
void handleLocals(const CdbExtensionCommandPtr &reply);
void handleExpandLocals(const CdbExtensionCommandPtr &reply);
void handleRegisters(const CdbExtensionCommandPtr &reply);
void handleModules(const CdbExtensionCommandPtr &reply);
void handleMemory(const CdbExtensionCommandPtr &);
QString normalizeFileName(const QString &f);
void updateLocalVariable(const QByteArray &iname);
int elapsedLogTime() const;
const QByteArray m_creatorExtPrefix;
const QByteArray m_tokenPrefix;
const OptionsPtr m_options;
QProcess m_process;
QByteArray m_outputBuffer;
unsigned long m_inferiorPid;
// Debugger accessible (expecting commands)
bool m_accessible;
SpecialStopMode m_specialStopMode;
int m_nextCommandToken;
int m_nextBreakpointNumber;
QList<CdbBuiltinCommandPtr> m_builtinCommandQueue;
int m_currentBuiltinCommandIndex; // Current command whose output is recorded.
QList<CdbExtensionCommandPtr> m_extensionCommandQueue;
QMap<QString, QString> m_normalizedFileCache;
const QByteArray m_extensionCommandPrefixBA; // Library name used as prefix
bool m_operateByInstructionPending; // Creator operate by instruction action changed.
bool m_operateByInstruction;
bool m_notifyEngineShutdownOnTermination;
bool m_hasDebuggee;
QTime m_logTime;
mutable int m_elapsedLogTime;
};
} // namespace Cdb
} // namespace Debugger
#endif // DEBUGGER_CDBENGINE_H
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "cdboptions2.h"
#ifdef Q_OS_WIN
# include <utils/winutils.h>
#endif
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
static const char settingsGroupC[] = "CDB2";
static const char enabledKeyC[] = "Enabled";
static const char pathKeyC[] = "Path";
static const char symbolPathsKeyC[] = "SymbolPaths";
static const char sourcePathsKeyC[] = "SourcePaths";
static const char is64bitKeyC[] = "64bit";
namespace Debugger {
namespace Cdb {
CdbOptions::CdbOptions() :
enabled(false), is64bit(false)
{
}
QString CdbOptions::settingsGroup()
{
return QLatin1String(settingsGroupC);
}
void CdbOptions::clear()
{
is64bit = enabled = false;
executable.clear();
symbolPaths.clear();
sourcePaths.clear();
}
void CdbOptions::fromSettings(const QSettings *s)
{
clear();
// Is this the first time we are called ->
// try to find automatically
const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/');
const QString enabledKey = keyRoot + QLatin1String(enabledKeyC);
#if 0 // TODO: Enable autodetection after deprecating the old CDB engine only.
const bool firstTime = !s->contains(enabledKey);
if (firstTime)
CdbOptions::autoDetectExecutable(&executable, &is64bit);
#endif
enabled = s->value(enabledKey, false).toBool();
is64bit = s->value(keyRoot + QLatin1String(is64bitKeyC), is64bit).toBool();
executable = s->value(keyRoot + QLatin1String(pathKeyC), executable).toString();
symbolPaths = s->value(keyRoot + QLatin1String(symbolPathsKeyC), QStringList()).toStringList();
sourcePaths = s->value(keyRoot + QLatin1String(sourcePathsKeyC), QStringList()).toStringList();
}
void CdbOptions::toSettings(QSettings *s) const
{
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(enabledKeyC), enabled);
s->setValue(QLatin1String(pathKeyC), executable);
s->setValue(QLatin1String(is64bitKeyC), is64bit);
s->setValue(QLatin1String(symbolPathsKeyC), symbolPaths);
s->setValue(QLatin1String(sourcePathsKeyC), sourcePaths);
s->endGroup();
}
bool CdbOptions::equals(const CdbOptions &rhs) const
{
return enabled == rhs.enabled && is64bit == rhs.is64bit
&& executable == rhs.executable
&& symbolPaths == rhs.symbolPaths
&& sourcePaths == rhs.sourcePaths;
}
bool CdbOptions::autoDetectExecutable(QString *outPath, bool *is64bitIn /* = 0 */,
QStringList *checkedDirectories /* = 0 */)
{
// Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>/cdb.exe" and its
// " (x86)", " (x64)" variations.
static const char *postFixes[] = {" (x64)", " 64-bit", " (x86)", " (x32)" };
enum { first32bitIndex = 2 };
if (checkedDirectories)
checkedDirectories->clear();
outPath->clear();
const QByteArray programDirB = qgetenv("ProgramFiles");
if (programDirB.isEmpty())
return false;
const QString programDir = QString::fromLocal8Bit(programDirB) + QLatin1Char('/');
const QString installDir = QLatin1String("Debugging Tools For Windows");
const QString executable = QLatin1String("/cdb.exe");
QString path = programDir + installDir;
if (checkedDirectories)
checkedDirectories->push_back(path);
const QFileInfo fi(path + executable);
// Plain system installation
if (fi.isFile() && fi.isExecutable()) {
*outPath = fi.absoluteFilePath();
if (is64bitIn)
#ifdef Q_OS_WIN
*is64bitIn = Utils::winIs64BitSystem();
#else
*is64bitIn = false;
#endif
return true;
}
// Try the post fixes
const int rootLength = path.size();
for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
path.truncate(rootLength);
path += QLatin1String(postFixes[i]);
if (checkedDirectories)
checkedDirectories->push_back(path);
const QFileInfo fi2(path + executable);
if (fi2.isFile() && fi2.isExecutable()) {
if (is64bitIn)
*is64bitIn = i < first32bitIndex;
*outPath = fi2.absoluteFilePath();
return true;
}
}
return false;
}
} // namespace Internal