forked from qt-creator/qt-creator
Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
bindir=$(dirname $(readlink -nf $0))
|
bindir=$(dirname "$(readlink -nf $0)")
|
||||||
if test "$(uname -m)" = "x86_64" ; then
|
if test "$(uname -m)" = "x86_64" ; then
|
||||||
libdir=$(cd ${bindir}/../lib64 ; pwd)
|
libdir=$(cd "${bindir}/../lib64" ; pwd)
|
||||||
else
|
else
|
||||||
libdir=$(cd ${bindir}/../lib ; pwd)
|
libdir=$(cd "${bindir}/../lib" ; pwd)
|
||||||
fi
|
fi
|
||||||
LD_LIBRARY_PATH="${libdir}/qtcreator:${LD_LIBRARY_PATH}" exec "${bindir}/qtcreator.bin" ${1+"$@"}
|
LD_LIBRARY_PATH="${libdir}/qtcreator:${LD_LIBRARY_PATH}" exec "${bindir}/qtcreator.bin" ${1+"$@"}
|
||||||
|
@@ -84,16 +84,17 @@ void BreakWindow::resizeEvent(QResizeEvent *ev)
|
|||||||
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
{
|
{
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
QModelIndex index = indexAt(ev->pos());
|
const QModelIndex index = indexAt(ev->pos());
|
||||||
|
const bool indexIsValid = index.isValid();
|
||||||
QAction *act0 = new QAction(tr("Delete breakpoint"), &menu);
|
QAction *act0 = new QAction(tr("Delete breakpoint"), &menu);
|
||||||
act0->setEnabled(index.isValid());
|
act0->setEnabled(indexIsValid);
|
||||||
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
|
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
|
||||||
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
|
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
|
||||||
act2->setCheckable(true);
|
act2->setCheckable(true);
|
||||||
act2->setChecked(m_alwaysResizeColumnsToContents);
|
act2->setChecked(m_alwaysResizeColumnsToContents);
|
||||||
QAction *act3 = new QAction(tr("Edit condition..."), &menu);
|
QAction *act3 = new QAction(tr("Edit condition..."), &menu);
|
||||||
act0->setEnabled(index.isValid());
|
act3->setEnabled(indexIsValid);
|
||||||
QAction *act4 = new QAction(tr("Syncronize breakpoints"), &menu);
|
QAction *act4 = new QAction(tr("Synchronize breakpoints"), &menu);
|
||||||
|
|
||||||
menu.addAction(act0);
|
menu.addAction(act0);
|
||||||
menu.addAction(act3);
|
menu.addAction(act3);
|
||||||
|
@@ -6,6 +6,10 @@ contains(QMAKE_CXX, cl) {
|
|||||||
|
|
||||||
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
|
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
|
||||||
|
|
||||||
|
!exists ($$CDB_PATH) {
|
||||||
|
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
|
||||||
|
}
|
||||||
|
|
||||||
exists ($$CDB_PATH) {
|
exists ($$CDB_PATH) {
|
||||||
message("Experimental: Adding support for $$CDB_PATH")
|
message("Experimental: Adding support for $$CDB_PATH")
|
||||||
|
|
||||||
@@ -25,7 +29,9 @@ HEADERS += \
|
|||||||
$$PWD/cdbdebugoutput.h \
|
$$PWD/cdbdebugoutput.h \
|
||||||
$$PWD/cdbsymbolgroupcontext.h \
|
$$PWD/cdbsymbolgroupcontext.h \
|
||||||
$$PWD/cdbstacktracecontext.h \
|
$$PWD/cdbstacktracecontext.h \
|
||||||
$$PWD/cdbbreakpoint.h
|
$$PWD/cdbbreakpoint.h \
|
||||||
|
$$PWD/cdbmodules.h \
|
||||||
|
$$PWD/cdbassembler.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/cdbdebugengine.cpp \
|
$$PWD/cdbdebugengine.cpp \
|
||||||
@@ -33,7 +39,9 @@ SOURCES += \
|
|||||||
$$PWD/cdbdebugoutput.cpp \
|
$$PWD/cdbdebugoutput.cpp \
|
||||||
$$PWD/cdbsymbolgroupcontext.cpp \
|
$$PWD/cdbsymbolgroupcontext.cpp \
|
||||||
$$PWD/cdbstacktracecontext.cpp \
|
$$PWD/cdbstacktracecontext.cpp \
|
||||||
$$PWD/cdbbreakpoint.cpp
|
$$PWD/cdbbreakpoint.cpp \
|
||||||
|
$$PWD/cdbmodules.cpp \
|
||||||
|
$$PWD/cdbassembler.cpp
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
|
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
|
||||||
|
234
src/plugins/debugger/cdb/cdbassembler.cpp
Normal file
234
src/plugins/debugger/cdb/cdbassembler.cpp
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Qt Software Information (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 qt-sales@nokia.com.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include "cdbassembler.h"
|
||||||
|
#include "cdbdebugoutput.h"
|
||||||
|
#include "cdbdebugengine_p.h"
|
||||||
|
#include "cdbsymbolgroupcontext.h"
|
||||||
|
|
||||||
|
#include "disassemblerhandler.h"
|
||||||
|
#include "registerhandler.h"
|
||||||
|
|
||||||
|
#include <QtCore/QVector>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
typedef QList<DisassemblerLine> DisassemblerLineList;
|
||||||
|
|
||||||
|
bool getRegisters(IDebugControl4 *ctl,
|
||||||
|
IDebugRegisters2 *ireg,
|
||||||
|
QList<Register> *registers,
|
||||||
|
QString *errorMessage, int base)
|
||||||
|
{
|
||||||
|
registers->clear();
|
||||||
|
ULONG count;
|
||||||
|
HRESULT hr = ireg->GetNumberRegisters(&count);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("GetNumberRegisters", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!count)
|
||||||
|
return true;
|
||||||
|
// Retrieve names
|
||||||
|
WCHAR wszBuf[MAX_PATH];
|
||||||
|
for (ULONG r = 0; r < count; r++) {
|
||||||
|
hr = ireg->GetDescriptionWide(r, wszBuf, MAX_PATH - 1, 0, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("GetDescriptionWide", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Register reg;
|
||||||
|
reg.name = QString::fromUtf16(wszBuf);
|
||||||
|
registers->push_back(reg);
|
||||||
|
}
|
||||||
|
// get values
|
||||||
|
QVector<DEBUG_VALUE> values(count);
|
||||||
|
DEBUG_VALUE *valuesPtr = &(*values.begin());
|
||||||
|
memset(valuesPtr, 0, count * sizeof(DEBUG_VALUE));
|
||||||
|
hr = ireg->GetValues(count, 0, 0, valuesPtr);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("GetValues", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (base < 2)
|
||||||
|
base = 10;
|
||||||
|
for (ULONG r = 0; r < count; r++)
|
||||||
|
(*registers)[r].value = CdbSymbolGroupContext::debugValueToString(values.at(r), ctl, 0, base);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output parser for disassembler lines.
|
||||||
|
// It uses the source file lines as symbol until it encounters
|
||||||
|
// a C++ symbol (function entered), from which then on
|
||||||
|
// it uses that symbol.
|
||||||
|
class DisassemblerOutputParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DisassemblerOutputParser(DisassemblerLineList *list);
|
||||||
|
|
||||||
|
void parse(const QStringList &l);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum ParseResult { ParseOk, ParseIgnore, ParseFailed };
|
||||||
|
ParseResult parseDisassembled(const QString &in, DisassemblerLine* l);
|
||||||
|
|
||||||
|
DisassemblerLineList *m_list;
|
||||||
|
QString m_sourceSymbol;
|
||||||
|
int m_sourceSymbolOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
DisassemblerOutputParser::DisassemblerOutputParser(DisassemblerLineList *list) :
|
||||||
|
m_list(list),
|
||||||
|
m_sourceSymbolOffset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a disassembler line:
|
||||||
|
// module!class::foo:
|
||||||
|
// 004017cf cc int 3
|
||||||
|
// 77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58]
|
||||||
|
DisassemblerOutputParser::ParseResult
|
||||||
|
DisassemblerOutputParser::parseDisassembled(const QString &in, DisassemblerLine* l)
|
||||||
|
{
|
||||||
|
l->clear();
|
||||||
|
|
||||||
|
// Check if there is a source file
|
||||||
|
if (in.size() < 7)
|
||||||
|
return ParseIgnore;
|
||||||
|
const bool hasSourceFile = !in.at(6).isSpace();
|
||||||
|
|
||||||
|
// Sometimes, empty lines occur
|
||||||
|
const QString simplified = in.simplified();
|
||||||
|
if (simplified.isEmpty())
|
||||||
|
return ParseIgnore;
|
||||||
|
|
||||||
|
QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||||
|
// Check for symbols as 'module!class::foo:' (start of function encountered)
|
||||||
|
if (tokens.size() == 1) {
|
||||||
|
QString symbol = tokens.front();
|
||||||
|
if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) {
|
||||||
|
symbol.truncate(symbol.size() - 1);
|
||||||
|
m_sourceSymbol = symbol;
|
||||||
|
m_sourceSymbolOffset = 0;
|
||||||
|
}
|
||||||
|
return ParseIgnore;
|
||||||
|
}
|
||||||
|
if (tokens.size() < 2)
|
||||||
|
return ParseIgnore;
|
||||||
|
// Symbol display: Do we know a symbol?
|
||||||
|
if (!m_sourceSymbol.isEmpty()) {
|
||||||
|
l->symbol = QString(QLatin1Char('<'));
|
||||||
|
l->symbol += m_sourceSymbol;
|
||||||
|
if (m_sourceSymbolOffset) {
|
||||||
|
l->symbol += QLatin1Char('+');
|
||||||
|
l->symbol += QString::number(m_sourceSymbolOffset);
|
||||||
|
}
|
||||||
|
l->symbol += QLatin1Char('>');
|
||||||
|
m_sourceSymbolOffset++;
|
||||||
|
}
|
||||||
|
// Read source file information: If we don't know a symbol yet,
|
||||||
|
// use the source file.
|
||||||
|
if (hasSourceFile) {
|
||||||
|
if (l->symbol.isEmpty()) {
|
||||||
|
l->symbol = tokens.at(1);
|
||||||
|
l->symbol += QLatin1Char('+');
|
||||||
|
l->symbol += tokens.front();
|
||||||
|
}
|
||||||
|
tokens.pop_front();
|
||||||
|
tokens.pop_front();
|
||||||
|
}
|
||||||
|
l->symbolDisplay = l->symbol;
|
||||||
|
// Get offset address and instruction
|
||||||
|
if (tokens.size() < 3)
|
||||||
|
return ParseFailed;
|
||||||
|
l->addressDisplay = l->address = tokens.front();
|
||||||
|
tokens.pop_front();
|
||||||
|
// The rest is effective address & instructions
|
||||||
|
if (tokens.size() > 1)
|
||||||
|
tokens.pop_front();
|
||||||
|
l->mnemonic = tokens.join(QString(QLatin1Char(' ')));
|
||||||
|
return ParseOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisassemblerOutputParser::parse(const QStringList &l)
|
||||||
|
{
|
||||||
|
DisassemblerLine dLine;
|
||||||
|
foreach(const QString &line, l) {
|
||||||
|
switch (parseDisassembled(line, &dLine)) {
|
||||||
|
case ParseOk:
|
||||||
|
m_list->push_back(dLine);
|
||||||
|
break;
|
||||||
|
case ParseIgnore:
|
||||||
|
break;
|
||||||
|
case ParseFailed:
|
||||||
|
qWarning("Failed to parse '%s'\n", qPrintable(line));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dissassemble(IDebugClient5 *client,
|
||||||
|
IDebugControl4 *ctl,
|
||||||
|
ULONG64 offset,
|
||||||
|
unsigned long beforeLines,
|
||||||
|
unsigned long afterLines,
|
||||||
|
QList<DisassemblerLine> *lines,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << offset;
|
||||||
|
lines->clear();
|
||||||
|
const ULONG flags = DEBUG_DISASM_MATCHING_SYMBOLS|DEBUG_DISASM_SOURCE_LINE_NUMBER|DEBUG_DISASM_SOURCE_FILE_NAME;
|
||||||
|
// Catch the output by temporarily setting another handler.
|
||||||
|
// We use the method that outputs to the output handler as it
|
||||||
|
// conveniently provides the 'beforeLines' context (stepping back
|
||||||
|
// in assembler code). We build a complete string first as line breaks
|
||||||
|
// may occur in-between messages.
|
||||||
|
StringOutputHandler stringHandler;
|
||||||
|
IDebugOutputCallbacksWide *oldHandler = CdbDebugOutputBase::getOutputCallback(client);
|
||||||
|
client->SetOutputCallbacksWide(&stringHandler);
|
||||||
|
// For some reason, we need to output to "all clients"
|
||||||
|
const HRESULT hr = ctl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS,
|
||||||
|
beforeLines, beforeLines + afterLines,
|
||||||
|
offset, flags, 0, 0, 0, 0);
|
||||||
|
client->SetOutputCallbacksWide(oldHandler);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
|
||||||
|
arg(QString::number(offset, 16), msgComFailed("OutputDisassemblyLines", hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DisassemblerOutputParser parser(lines);
|
||||||
|
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
64
src/plugins/debugger/cdb/cdbassembler.h
Normal file
64
src/plugins/debugger/cdb/cdbassembler.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Qt Software Information (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 qt-sales@nokia.com.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CDBASSEMBLER_H
|
||||||
|
#define CDBASSEMBLER_H
|
||||||
|
|
||||||
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QString>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <inc/dbgeng.h>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class DisassemblerLine;
|
||||||
|
|
||||||
|
// Utilities related to assembler code.
|
||||||
|
class Register;
|
||||||
|
|
||||||
|
bool getRegisters(IDebugControl4 *ctl,
|
||||||
|
IDebugRegisters2 *ireg,
|
||||||
|
QList<Register> *registers,
|
||||||
|
QString *errorMessage,
|
||||||
|
int base = 10 /* 16 for hex, etc */);
|
||||||
|
|
||||||
|
bool dissassemble(IDebugClient5 *client,
|
||||||
|
IDebugControl4 *ctl,
|
||||||
|
ULONG64 offset,
|
||||||
|
unsigned long beforeLines,
|
||||||
|
unsigned long afterLines,
|
||||||
|
QList<DisassemblerLine> *lines,
|
||||||
|
QString *errorMessage);
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
|
#endif // CDBASSEMBLER_H
|
@@ -28,6 +28,7 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include "cdbbreakpoint.h"
|
#include "cdbbreakpoint.h"
|
||||||
|
#include "cdbmodules.h"
|
||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "cdbdebugengine_p.h"
|
#include "cdbdebugengine_p.h"
|
||||||
|
|
||||||
@@ -279,20 +280,48 @@ bool CDBBreakPoint::getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
|
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
|
||||||
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
|
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
|
||||||
|
IDebugSymbols3 *syms,
|
||||||
BreakHandler *handler,
|
BreakHandler *handler,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
|
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
|
||||||
BreakPointIndexMap breakPointIndexMap;
|
|
||||||
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
|
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
BreakPointIndexMap breakPointIndexMap;
|
||||||
|
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
|
||||||
|
// Ignore invalid functions (that could not be found) as they make
|
||||||
|
// the debugger hang.
|
||||||
const int handlerCount = handler->size();
|
const int handlerCount = handler->size();
|
||||||
for (int i=0; i < handlerCount; ++i)
|
const QChar moduleDelimiter = QLatin1Char('!');
|
||||||
breakPointIndexMap.insert(CDBBreakPoint(*handler->at(i)), i);
|
for (int i=0; i < handlerCount; ++i) {
|
||||||
|
BreakpointData *bd = handler->at(i);
|
||||||
|
// Function breakpoints: Are the module names specified?
|
||||||
|
bool breakPointOk = false;
|
||||||
|
if (bd->funcName.isEmpty()) {
|
||||||
|
breakPointOk = true;
|
||||||
|
} else {
|
||||||
|
switch (resolveSymbol(syms, &bd->funcName, errorMessage)) {
|
||||||
|
case ResolveSymbolOk:
|
||||||
|
breakPointOk = true;
|
||||||
|
break;
|
||||||
|
case ResolveSymbolAmbiguous:
|
||||||
|
qWarning("Warning: %s\n", qPrintable(*errorMessage));
|
||||||
|
breakPointOk = true;
|
||||||
|
break;
|
||||||
|
case ResolveSymbolNotFound:
|
||||||
|
case ResolveSymbolError:
|
||||||
|
qWarning("Warning: %s\n", qPrintable(*errorMessage));
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
} // function breakpoint
|
||||||
|
if (breakPointOk)
|
||||||
|
breakPointIndexMap.insert(CDBBreakPoint(*bd), i);
|
||||||
|
}
|
||||||
|
errorMessage->clear();
|
||||||
// get number of engine breakpoints
|
// get number of engine breakpoints
|
||||||
ULONG engineCount;
|
ULONG engineCount;
|
||||||
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
|
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
|
||||||
@@ -356,5 +385,5 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
@@ -49,7 +49,8 @@ class BreakpointData;
|
|||||||
/* CDB Break point data structure with utilities to
|
/* CDB Break point data structure with utilities to
|
||||||
* apply to engine and to retrieve them from the engine and comparison. */
|
* apply to engine and to retrieve them from the engine and comparison. */
|
||||||
|
|
||||||
struct CDBBreakPoint {
|
struct CDBBreakPoint
|
||||||
|
{
|
||||||
CDBBreakPoint();
|
CDBBreakPoint();
|
||||||
CDBBreakPoint(const BreakpointData &bpd);
|
CDBBreakPoint(const BreakpointData &bpd);
|
||||||
|
|
||||||
@@ -72,7 +73,8 @@ struct CDBBreakPoint {
|
|||||||
static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0);
|
static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0);
|
||||||
static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
|
static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
|
||||||
// Synchronize (halted) engine with BreakHandler.
|
// Synchronize (halted) engine with BreakHandler.
|
||||||
static bool synchronizeBreakPoints(IDebugControl4* ctl, BreakHandler *bh, QString *errorMessage);
|
static bool synchronizeBreakPoints(IDebugControl4* ctl, IDebugSymbols3 *syms,
|
||||||
|
BreakHandler *bh, QString *errorMessage);
|
||||||
|
|
||||||
// Return a 'canonical' file (using '/' and capitalized drive letter)
|
// Return a 'canonical' file (using '/' and capitalized drive letter)
|
||||||
static QString canonicalSourceFile(const QString &f);
|
static QString canonicalSourceFile(const QString &f);
|
||||||
@@ -93,7 +95,7 @@ inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
|||||||
inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
||||||
{ return b1.compare(b2) < 0; }
|
{ return b1.compare(b2) < 0; }
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
|
||||||
#endif // CDBBREAKPOINTS_H
|
#endif // CDBBREAKPOINTS_H
|
||||||
|
@@ -32,11 +32,17 @@
|
|||||||
#include "cdbsymbolgroupcontext.h"
|
#include "cdbsymbolgroupcontext.h"
|
||||||
#include "cdbstacktracecontext.h"
|
#include "cdbstacktracecontext.h"
|
||||||
#include "cdbbreakpoint.h"
|
#include "cdbbreakpoint.h"
|
||||||
|
#include "cdbmodules.h"
|
||||||
|
#include "cdbassembler.h"
|
||||||
|
|
||||||
|
#include "debuggeractions.h"
|
||||||
#include "debuggermanager.h"
|
#include "debuggermanager.h"
|
||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
|
#include "registerhandler.h"
|
||||||
|
#include "moduleshandler.h"
|
||||||
|
#include "disassemblerhandler.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -51,6 +57,7 @@
|
|||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtGui/QMessageBox>
|
#include <QtGui/QMessageBox>
|
||||||
#include <QtGui/QMainWindow>
|
#include <QtGui/QMainWindow>
|
||||||
|
#include <QtGui/QApplication>
|
||||||
|
|
||||||
#define DBGHELP_TRANSLATE_TCHAR
|
#define DBGHELP_TRANSLATE_TCHAR
|
||||||
#include <inc/Dbghelp.h>
|
#include <inc/Dbghelp.h>
|
||||||
@@ -190,7 +197,6 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
|
|||||||
m_breakEventMode(BreakEventHandle),
|
m_breakEventMode(BreakEventHandle),
|
||||||
m_watchTimer(-1),
|
m_watchTimer(-1),
|
||||||
m_debugEventCallBack(engine),
|
m_debugEventCallBack(engine),
|
||||||
m_debugOutputCallBack(engine),
|
|
||||||
m_pDebugClient(0),
|
m_pDebugClient(0),
|
||||||
m_pDebugControl(0),
|
m_pDebugControl(0),
|
||||||
m_pDebugSystemObjects(0),
|
m_pDebugSystemObjects(0),
|
||||||
@@ -220,7 +226,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack);
|
m_pDebugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
|
||||||
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
|
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
|
||||||
|
|
||||||
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
|
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
|
||||||
@@ -308,6 +314,14 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
|
|||||||
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
|
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
|
||||||
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
|
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
|
||||||
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
|
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
|
||||||
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(QString,QString)),
|
||||||
|
m_d->m_debuggerManager, SLOT(showDebuggerOutput(QString,QString)));
|
||||||
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(QString,QString)),
|
||||||
|
m_d->m_debuggerManager, SLOT(showDebuggerInput(QString,QString)));
|
||||||
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
|
||||||
|
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
|
||||||
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
|
||||||
|
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CdbDebugEngine::~CdbDebugEngine()
|
CdbDebugEngine::~CdbDebugEngine()
|
||||||
@@ -344,8 +358,16 @@ void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CdbDebugEnginePrivate::clearDisplay()
|
||||||
|
{
|
||||||
|
m_debuggerManagerAccess->threadsHandler()->removeAll();
|
||||||
|
m_debuggerManagerAccess->modulesHandler()->removeAll();
|
||||||
|
m_debuggerManagerAccess->registerHandler()->removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
bool CdbDebugEngine::startDebugger()
|
bool CdbDebugEngine::startDebugger()
|
||||||
{
|
{
|
||||||
|
m_d->clearDisplay();
|
||||||
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
@@ -1010,6 +1032,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl,
|
return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl,
|
||||||
|
m_pDebugSymbols,
|
||||||
m_debuggerManagerAccess->breakHandler(),
|
m_debuggerManagerAccess->breakHandler(),
|
||||||
errorMessage);
|
errorMessage);
|
||||||
}
|
}
|
||||||
@@ -1024,6 +1047,30 @@ void CdbDebugEngine::saveSessionData()
|
|||||||
|
|
||||||
void CdbDebugEngine::reloadDisassembler()
|
void CdbDebugEngine::reloadDisassembler()
|
||||||
{
|
{
|
||||||
|
enum { ContextLines = 40 };
|
||||||
|
// Do we have a top stack frame?
|
||||||
|
const ULONG64 offset = m_d->m_currentStackTrace ? m_d->m_currentStackTrace->instructionOffset() : ULONG64(0);
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << offset;
|
||||||
|
|
||||||
|
DisassemblerHandler *dh = m_d->m_debuggerManagerAccess->disassemblerHandler();
|
||||||
|
if (offset) {
|
||||||
|
QList<DisassemblerLine> lines;
|
||||||
|
QString errorMessage;
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
const bool drc = dissassemble(m_d->m_pDebugClient, m_d->m_pDebugControl, offset,
|
||||||
|
ContextLines, ContextLines, &lines, &errorMessage);
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
if (drc) {
|
||||||
|
dh->setLines(lines);
|
||||||
|
if (lines.size() > ContextLines)
|
||||||
|
dh->setCurrentLine(ContextLines);
|
||||||
|
} else {
|
||||||
|
qWarning("reloadDisassembler: %s\n", qPrintable(errorMessage));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dh->setLines(QList<DisassemblerLine>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::reloadModules()
|
void CdbDebugEngine::reloadModules()
|
||||||
@@ -1042,8 +1089,54 @@ void CdbDebugEngine::loadAllSymbols()
|
|||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
|
||||||
|
{
|
||||||
|
QList<Symbol> rc;
|
||||||
|
QString errorMessage;
|
||||||
|
bool success = false;
|
||||||
|
do {
|
||||||
|
if (m_d->isDebuggeeRunning()) {
|
||||||
|
errorMessage = tr("Cannot retrieve symbols while the debuggee is running.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!getModuleSymbols(m_d->m_pDebugSymbols, moduleName, &rc, &errorMessage))
|
||||||
|
break;
|
||||||
|
success = true;
|
||||||
|
} while (false);
|
||||||
|
if (!success)
|
||||||
|
qWarning("%s\n", qPrintable(errorMessage));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int registerFormatBase()
|
||||||
|
{
|
||||||
|
switch(checkedRegisterFormatAction()) {
|
||||||
|
case FormatHexadecimal:
|
||||||
|
return 16;
|
||||||
|
case FormatDecimal:
|
||||||
|
return 10;
|
||||||
|
case FormatOctal:
|
||||||
|
return 8;
|
||||||
|
case FormatBinary:
|
||||||
|
return 2;
|
||||||
|
break;
|
||||||
|
case FormatRaw:
|
||||||
|
case FormatNatural:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::reloadRegisters()
|
void CdbDebugEngine::reloadRegisters()
|
||||||
{
|
{
|
||||||
|
const int intBase = registerFormatBase();
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << intBase;
|
||||||
|
QList<Register> registers;
|
||||||
|
QString errorMessage;
|
||||||
|
if (!getRegisters(m_d->m_pDebugControl, m_d->m_pDebugRegisters, ®isters, &errorMessage, intBase))
|
||||||
|
qWarning("reloadRegisters() failed: %s\n", qPrintable(errorMessage));
|
||||||
|
m_d->m_debuggerManagerAccess->registerHandler()->setRegisters(registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
||||||
@@ -1142,21 +1235,34 @@ void CdbDebugEnginePrivate::updateThreadList()
|
|||||||
|
|
||||||
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
|
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
|
||||||
QList<ThreadData> threads;
|
QList<ThreadData> threads;
|
||||||
|
bool success = false;
|
||||||
|
QString errorMessage;
|
||||||
|
do {
|
||||||
|
ULONG numberOfThreads;
|
||||||
|
HRESULT hr= m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
errorMessage= msgComFailed("GetNumberThreads", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const ULONG maxThreadIds = 256;
|
||||||
|
ULONG threadIds[maxThreadIds];
|
||||||
|
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
|
||||||
|
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
|
||||||
|
ThreadData thread;
|
||||||
|
thread.id = threadId;
|
||||||
|
threads.append(thread);
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT hr;
|
th->setThreads(threads);
|
||||||
ULONG numberOfThreads;
|
success = true;
|
||||||
hr = m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
|
} while (false);
|
||||||
const ULONG maxThreadIds = 256;
|
if (!success)
|
||||||
ULONG threadIds[maxThreadIds];
|
qWarning("updateThreadList() failed: %s\n", qPrintable(errorMessage));
|
||||||
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
|
|
||||||
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
|
|
||||||
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
|
|
||||||
ThreadData thread;
|
|
||||||
thread.id = threadId;
|
|
||||||
threads.append(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
th->setThreads(threads);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::updateStackTrace()
|
void CdbDebugEnginePrivate::updateStackTrace()
|
||||||
@@ -1166,6 +1272,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
// Create a new context
|
// Create a new context
|
||||||
clearForRun();
|
clearForRun();
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
|
m_engine->reloadRegisters();
|
||||||
m_currentStackTrace =
|
m_currentStackTrace =
|
||||||
CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
|
CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
|
||||||
m_pDebugSymbols, m_currentThreadId, &errorMessage);
|
m_pDebugSymbols, m_currentThreadId, &errorMessage);
|
||||||
@@ -1173,6 +1280,10 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Disassembling slows things down a bit. Assembler is still available via menu.
|
||||||
|
#if 0
|
||||||
|
m_engine->reloadDisassembler(); // requires stack trace
|
||||||
|
#endif
|
||||||
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
|
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
|
||||||
// find the first usable frame and select it
|
// find the first usable frame and select it
|
||||||
int current = -1;
|
int current = -1;
|
||||||
@@ -1191,11 +1302,14 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString)
|
|
||||||
|
void CdbDebugEnginePrivate::updateModules()
|
||||||
{
|
{
|
||||||
if (debugCDB && strstr(szOutputString, "ModLoad:") == 0)
|
QList<Module> modules;
|
||||||
qDebug() << Q_FUNC_INFO << szOutputString;
|
QString errorMessage;
|
||||||
m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString));
|
if (!getModuleList(m_pDebugSymbols, &modules, &errorMessage))
|
||||||
|
qWarning("updateModules() failed: %s\n", qPrintable(errorMessage));
|
||||||
|
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)
|
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)
|
||||||
|
@@ -87,6 +87,7 @@ public:
|
|||||||
virtual void reloadModules();
|
virtual void reloadModules();
|
||||||
virtual void loadSymbols(const QString &moduleName);
|
virtual void loadSymbols(const QString &moduleName);
|
||||||
virtual void loadAllSymbols();
|
virtual void loadAllSymbols();
|
||||||
|
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
|
||||||
|
|
||||||
virtual void reloadRegisters();
|
virtual void reloadRegisters();
|
||||||
virtual void reloadSourceFiles();
|
virtual void reloadSourceFiles();
|
||||||
|
@@ -48,7 +48,8 @@ class CdbStackTraceContext;
|
|||||||
// Thin wrapper around the 'DBEng' debugger engine shared library
|
// Thin wrapper around the 'DBEng' debugger engine shared library
|
||||||
// which is loaded at runtime.
|
// which is loaded at runtime.
|
||||||
|
|
||||||
class DebuggerEngineLibrary {
|
class DebuggerEngineLibrary
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
DebuggerEngineLibrary();
|
DebuggerEngineLibrary();
|
||||||
bool init(QString *errorMessage);
|
bool init(QString *errorMessage);
|
||||||
@@ -82,11 +83,13 @@ struct CdbDebugEnginePrivate
|
|||||||
void updateThreadList();
|
void updateThreadList();
|
||||||
void updateStackTrace();
|
void updateStackTrace();
|
||||||
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
|
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
|
||||||
void handleDebugOutput(const char* szOutputString);
|
void updateModules();
|
||||||
|
|
||||||
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
|
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
|
||||||
void cleanStackTrace();
|
void cleanStackTrace();
|
||||||
void clearForRun();
|
void clearForRun();
|
||||||
CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const;
|
CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const;
|
||||||
|
void clearDisplay();
|
||||||
|
|
||||||
bool interruptInterferiorProcess(QString *errorMessage);
|
bool interruptInterferiorProcess(QString *errorMessage);
|
||||||
|
|
||||||
|
@@ -76,8 +76,9 @@ STDMETHODIMP_(ULONG) CdbDebugEventCallback::Release(THIS)
|
|||||||
|
|
||||||
STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
|
STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
|
||||||
{
|
{
|
||||||
*mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
|
*mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
|
||||||
//| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
|
| DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE
|
||||||
|
| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
|
||||||
| DEBUG_EVENT_BREAKPOINT
|
| DEBUG_EVENT_BREAKPOINT
|
||||||
| DEBUG_EVENT_EXCEPTION
|
| DEBUG_EVENT_EXCEPTION
|
||||||
;
|
;
|
||||||
@@ -125,13 +126,9 @@ STDMETHODIMP CdbDebugEventCallback::CreateThread(
|
|||||||
Q_UNUSED(Handle)
|
Q_UNUSED(Handle)
|
||||||
Q_UNUSED(DataOffset)
|
Q_UNUSED(DataOffset)
|
||||||
Q_UNUSED(StartOffset)
|
Q_UNUSED(StartOffset)
|
||||||
|
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
//Debugger::ThreadInfo ti;
|
m_pEngine->m_d->updateThreadList();
|
||||||
//ti.handle = Handle;
|
|
||||||
//ti.dataOffset = DataOffset;
|
|
||||||
//ti.startOffset = StartOffset;
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +139,8 @@ STDMETHODIMP CdbDebugEventCallback::ExitThread(
|
|||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << ExitCode;
|
qDebug() << Q_FUNC_INFO << ExitCode;
|
||||||
|
// @TODO: It seems the terminated thread is still in the list...
|
||||||
|
m_pEngine->m_d->updateThreadList();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,14 +209,14 @@ STDMETHODIMP CdbDebugEventCallback::LoadModule(
|
|||||||
{
|
{
|
||||||
Q_UNUSED(ImageFileHandle)
|
Q_UNUSED(ImageFileHandle)
|
||||||
Q_UNUSED(BaseOffset)
|
Q_UNUSED(BaseOffset)
|
||||||
Q_UNUSED(ModuleSize)
|
|
||||||
Q_UNUSED(ModuleName)
|
Q_UNUSED(ModuleName)
|
||||||
|
Q_UNUSED(ModuleSize)
|
||||||
Q_UNUSED(ImageName)
|
Q_UNUSED(ImageName)
|
||||||
Q_UNUSED(CheckSum)
|
Q_UNUSED(CheckSum)
|
||||||
Q_UNUSED(TimeDateStamp)
|
Q_UNUSED(TimeDateStamp)
|
||||||
if (debugCDB)
|
if (debugCDB > 1)
|
||||||
qDebug() << Q_FUNC_INFO << ModuleName;
|
qDebug() << Q_FUNC_INFO << ModuleName;
|
||||||
|
m_pEngine->m_d->updateModules();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,9 +228,9 @@ STDMETHODIMP CdbDebugEventCallback::UnloadModule(
|
|||||||
{
|
{
|
||||||
Q_UNUSED(ImageBaseName)
|
Q_UNUSED(ImageBaseName)
|
||||||
Q_UNUSED(BaseOffset)
|
Q_UNUSED(BaseOffset)
|
||||||
if (debugCDB)
|
if (debugCDB > 1)
|
||||||
qDebug() << Q_FUNC_INFO << ImageBaseName;
|
qDebug() << Q_FUNC_INFO << ImageBaseName;
|
||||||
|
m_pEngine->m_d->updateModules();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@
|
|||||||
**
|
**
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include "cdbdebugoutput.h"
|
#include "cdbdebugoutput.h"
|
||||||
#include "cdbdebugengine.h"
|
#include "cdbdebugengine.h"
|
||||||
#include "cdbdebugengine_p.h"
|
#include "cdbdebugengine_p.h"
|
||||||
@@ -38,12 +37,11 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
CdbDebugOutput::CdbDebugOutput(CdbDebugEngine* engine) :
|
CdbDebugOutputBase::CdbDebugOutputBase()
|
||||||
m_pEngine(engine)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
STDMETHODIMP CdbDebugOutput::QueryInterface(
|
STDMETHODIMP CdbDebugOutputBase::QueryInterface(
|
||||||
THIS_
|
THIS_
|
||||||
IN REFIID InterfaceId,
|
IN REFIID InterfaceId,
|
||||||
OUT PVOID* Interface
|
OUT PVOID* Interface
|
||||||
@@ -52,9 +50,9 @@ STDMETHODIMP CdbDebugOutput::QueryInterface(
|
|||||||
*Interface = NULL;
|
*Interface = NULL;
|
||||||
|
|
||||||
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
|
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
|
||||||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
|
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide)))
|
||||||
{
|
{
|
||||||
*Interface = (IDebugOutputCallbacks *)this;
|
*Interface = (IDebugOutputCallbacksWide*)this;
|
||||||
AddRef();
|
AddRef();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
} else {
|
} else {
|
||||||
@@ -62,30 +60,100 @@ STDMETHODIMP CdbDebugOutput::QueryInterface(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STDMETHODIMP_(ULONG) CdbDebugOutput::AddRef(THIS)
|
STDMETHODIMP_(ULONG) CdbDebugOutputBase::AddRef(THIS)
|
||||||
{
|
{
|
||||||
// This class is designed to be static so
|
// This class is designed to be static so
|
||||||
// there's no true refcount.
|
// there's no true refcount.
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
STDMETHODIMP_(ULONG) CdbDebugOutput::Release(THIS)
|
STDMETHODIMP_(ULONG) CdbDebugOutputBase::Release(THIS)
|
||||||
{
|
{
|
||||||
// This class is designed to be static so
|
// This class is designed to be static so
|
||||||
// there's no true refcount.
|
// there's no true refcount.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
STDMETHODIMP CdbDebugOutput::Output(
|
STDMETHODIMP CdbDebugOutputBase::Output(
|
||||||
THIS_
|
THIS_
|
||||||
IN ULONG mask,
|
IN ULONG mask,
|
||||||
IN PCSTR text
|
IN PCWSTR text
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(mask);
|
output(mask, QString::fromUtf16(text));
|
||||||
m_pEngine->m_d->handleDebugOutput(text);
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IDebugOutputCallbacksWide *CdbDebugOutputBase::getOutputCallback(IDebugClient5 *client)
|
||||||
|
{
|
||||||
|
IDebugOutputCallbacksWide *rc;
|
||||||
|
if (FAILED(client->GetOutputCallbacksWide(&rc)))
|
||||||
|
return 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------- CdbDebugOutput
|
||||||
|
|
||||||
|
// Return a prefix for debugger messages
|
||||||
|
static QString prefix(ULONG mask)
|
||||||
|
{
|
||||||
|
if (mask & (DEBUG_OUTPUT_PROMPT_REGISTERS)) {
|
||||||
|
static const QString p = QLatin1String("registers:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (mask & (DEBUG_OUTPUT_EXTENSION_WARNING|DEBUG_OUTPUT_WARNING)) {
|
||||||
|
static const QString p = QLatin1String("warning:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (mask & (DEBUG_OUTPUT_ERROR)) {
|
||||||
|
static const QString p = QLatin1String("error:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (mask & DEBUG_OUTPUT_SYMBOLS) {
|
||||||
|
static const QString p = QLatin1String("symbols:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
static const QString commonPrefix = QLatin1String("cdb:");
|
||||||
|
return commonPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OutputKind { DebuggerOutput, DebuggerPromptOutput, DebuggeeOutput, DebuggeePromptOutput };
|
||||||
|
|
||||||
|
static inline OutputKind outputKind(ULONG mask)
|
||||||
|
{
|
||||||
|
if (mask & DEBUG_OUTPUT_DEBUGGEE)
|
||||||
|
return DebuggeeOutput;
|
||||||
|
if (mask & DEBUG_OUTPUT_DEBUGGEE_PROMPT)
|
||||||
|
return DebuggeePromptOutput;
|
||||||
|
if (mask & DEBUG_OUTPUT_PROMPT)
|
||||||
|
return DebuggerPromptOutput;
|
||||||
|
return DebuggerOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdbDebugOutput::CdbDebugOutput()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CdbDebugOutput::output(ULONG mask, const QString &msg)
|
||||||
|
{
|
||||||
|
if (debugCDB > 1)
|
||||||
|
qDebug() << Q_FUNC_INFO << "\n " << msg;
|
||||||
|
|
||||||
|
switch (outputKind(mask)) {
|
||||||
|
case DebuggerOutput:
|
||||||
|
debuggerOutput(prefix(mask), msg);
|
||||||
|
break;
|
||||||
|
case DebuggerPromptOutput:
|
||||||
|
emit debuggerInputPrompt(prefix(mask), msg);
|
||||||
|
break;
|
||||||
|
case DebuggeeOutput:
|
||||||
|
emit debuggeeOutput(msg);
|
||||||
|
break;
|
||||||
|
case DebuggeePromptOutput:
|
||||||
|
emit debuggeeInputPrompt(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
@@ -33,16 +33,17 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <inc/dbgeng.h>
|
#include <inc/dbgeng.h>
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class CdbDebugEngine;
|
// CdbDebugOutputBase is a base class for output handlers
|
||||||
|
// that takes care of the Active X magic and conversion to QString.
|
||||||
|
|
||||||
class CdbDebugOutput : public IDebugOutputCallbacks
|
class CdbDebugOutputBase : public IDebugOutputCallbacksWide
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CdbDebugOutput(CdbDebugEngine* engine);
|
|
||||||
|
|
||||||
// IUnknown.
|
// IUnknown.
|
||||||
STDMETHOD(QueryInterface)(
|
STDMETHOD(QueryInterface)(
|
||||||
THIS_
|
THIS_
|
||||||
@@ -60,11 +61,48 @@ public:
|
|||||||
STDMETHOD(Output)(
|
STDMETHOD(Output)(
|
||||||
THIS_
|
THIS_
|
||||||
IN ULONG mask,
|
IN ULONG mask,
|
||||||
IN PCSTR text
|
IN PCWSTR text
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Helpers to retrieve the output callbacks IF
|
||||||
|
static IDebugOutputCallbacksWide *getOutputCallback(IDebugClient5 *client);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CdbDebugOutputBase();
|
||||||
|
virtual void output(ULONG mask, const QString &message) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Standard CDB output handler
|
||||||
|
class CdbDebugOutput : public QObject, public CdbDebugOutputBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
CdbDebugOutput();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void output(ULONG mask, const QString &message);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void debuggerOutput(const QString &prefix, const QString &message);
|
||||||
|
void debuggerInputPrompt(const QString &prefix, const QString &message);
|
||||||
|
void debuggeeOutput(const QString &message);
|
||||||
|
void debuggeeInputPrompt(const QString &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
// An output handler that adds lines to a string (to be
|
||||||
|
// used for cases in which linebreaks occur in-between calls
|
||||||
|
// to output).
|
||||||
|
class StringOutputHandler : public CdbDebugOutputBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringOutputHandler() {}
|
||||||
|
QString result() const { return m_result; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void output(ULONG, const QString &message) { m_result += message; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CdbDebugEngine* m_pEngine;
|
QString m_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
163
src/plugins/debugger/cdb/cdbmodules.cpp
Normal file
163
src/plugins/debugger/cdb/cdbmodules.cpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Qt Software Information (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 qt-sales@nokia.com.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include "cdbmodules.h"
|
||||||
|
#include "moduleshandler.h"
|
||||||
|
#include "cdbdebugengine_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/QFileInfo>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage)
|
||||||
|
{
|
||||||
|
modules->clear();
|
||||||
|
ULONG loadedCount, unloadedCount;
|
||||||
|
HRESULT hr = syms->GetNumberModules(&loadedCount, &unloadedCount);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("GetNumberModules", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// retrieve array of parameters
|
||||||
|
const ULONG count = loadedCount + unloadedCount;
|
||||||
|
QVector<DEBUG_MODULE_PARAMETERS> parameters(count);
|
||||||
|
DEBUG_MODULE_PARAMETERS *parmPtr = &(*parameters.begin());
|
||||||
|
memset(parmPtr, 0, sizeof(DEBUG_MODULE_PARAMETERS) * count);
|
||||||
|
hr = syms->GetModuleParameters(count, 0, 0u, parmPtr);
|
||||||
|
// E_INVALIDARG indicates 'Partial results' according to docu
|
||||||
|
if (FAILED(hr) && hr != E_INVALIDARG) {
|
||||||
|
*errorMessage= msgComFailed("GetModuleParameters", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// fill array
|
||||||
|
const QString hexPrefix = QLatin1String("0x");
|
||||||
|
WCHAR wszBuf[MAX_PATH];
|
||||||
|
for (ULONG m = 0; m < count; m++) {
|
||||||
|
const DEBUG_MODULE_PARAMETERS &p = parameters.at(m);
|
||||||
|
if (p.Base != DEBUG_INVALID_OFFSET) { // Partial results?
|
||||||
|
Module module;
|
||||||
|
module.symbolsRead = (p.Flags & DEBUG_MODULE_USER_MODE)
|
||||||
|
&& (p.SymbolType != DEBUG_SYMTYPE_NONE);
|
||||||
|
module.startAddress = hexPrefix + QString::number(p.Base, 16);
|
||||||
|
module.endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
|
||||||
|
hr = syms ->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0);
|
||||||
|
if (FAILED(hr) && hr != E_INVALIDARG) {
|
||||||
|
*errorMessage= msgComFailed("GetModuleNameStringWide", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
module.moduleName = QString::fromUtf16(wszBuf);
|
||||||
|
modules->push_back(module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search symbols matching a pattern
|
||||||
|
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
|
||||||
|
QStringList *matches, QString *errorMessage)
|
||||||
|
{
|
||||||
|
matches->clear();
|
||||||
|
ULONG64 handle = 0;
|
||||||
|
// E_NOINTERFACE means "no match". Apparently, it does not always
|
||||||
|
// set handle.
|
||||||
|
HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
|
||||||
|
if (hr == E_NOINTERFACE) {
|
||||||
|
if (handle)
|
||||||
|
syms->EndSymbolMatch(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("StartSymbolMatchWide", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WCHAR wszBuf[MAX_PATH];
|
||||||
|
while (true) {
|
||||||
|
hr = syms->GetNextSymbolMatchWide(handle, wszBuf, MAX_PATH - 1, 0, 0);
|
||||||
|
if (hr == E_NOINTERFACE)
|
||||||
|
break;
|
||||||
|
if (hr == S_OK)
|
||||||
|
matches->push_back(QString::fromUtf16(wszBuf));
|
||||||
|
}
|
||||||
|
syms->EndSymbolMatch(handle);
|
||||||
|
if (matches->empty())
|
||||||
|
*errorMessage = QString::fromLatin1("No symbol matches '%1'.").arg(pattern);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing the module specifier: "main" -> "project!main"
|
||||||
|
|
||||||
|
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
// Is it an incomplete symbol?
|
||||||
|
if (symbol->contains(QLatin1Char('!')))
|
||||||
|
return ResolveSymbolOk;
|
||||||
|
// 'main' is a #define for gdb, but not for VS
|
||||||
|
if (*symbol == QLatin1String("qMain"))
|
||||||
|
*symbol = QLatin1String("main");
|
||||||
|
// resolve
|
||||||
|
QStringList matches;
|
||||||
|
if (!searchSymbols(syms, *symbol, &matches, errorMessage))
|
||||||
|
return ResolveSymbolError;
|
||||||
|
if (matches.empty())
|
||||||
|
return ResolveSymbolNotFound;
|
||||||
|
*symbol = matches.front();
|
||||||
|
if (matches.size() > 1) {
|
||||||
|
*errorMessage = QString::fromLatin1("Ambiguous symbol '%1': %2").
|
||||||
|
arg(*symbol, matches.join(QString(QLatin1Char(' '))));
|
||||||
|
return ResolveSymbolAmbiguous;
|
||||||
|
}
|
||||||
|
return ResolveSymbolOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List symbols of a module
|
||||||
|
bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
|
||||||
|
QList<Symbol> *symbols, QString *errorMessage)
|
||||||
|
{
|
||||||
|
// Search all symbols and retrieve addresses
|
||||||
|
symbols->clear();
|
||||||
|
QStringList matches;
|
||||||
|
const QString pattern = QFileInfo(moduleName).baseName() + QLatin1String("!*");
|
||||||
|
if (!searchSymbols(syms, pattern, &matches, errorMessage))
|
||||||
|
return false;
|
||||||
|
const QString hexPrefix = QLatin1String("0x");
|
||||||
|
foreach (const QString &name, matches) {
|
||||||
|
Symbol symbol;
|
||||||
|
symbol.name = name;
|
||||||
|
ULONG64 offset = 0;
|
||||||
|
if (SUCCEEDED(syms->GetOffsetByNameWide(name.utf16(), &offset)))
|
||||||
|
symbol.address = hexPrefix + QString::number(offset, 16);
|
||||||
|
symbols->push_back(symbol);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
65
src/plugins/debugger/cdb/cdbmodules.h
Normal file
65
src/plugins/debugger/cdb/cdbmodules.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Qt Software Information (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 qt-sales@nokia.com.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CDBMODULES_H
|
||||||
|
#define CDBMODULES_H
|
||||||
|
|
||||||
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QString>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <inc/dbgeng.h>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class Module;
|
||||||
|
class Symbol;
|
||||||
|
|
||||||
|
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
|
||||||
|
// Search symbols matching a pattern
|
||||||
|
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
|
||||||
|
QStringList *matches, QString *errorMessage);
|
||||||
|
|
||||||
|
// ResolveSymbol: For symbols that are missing the module specifier,
|
||||||
|
// find the module and expand: "main" -> "project!main".
|
||||||
|
|
||||||
|
enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
|
||||||
|
ResolveSymbolNotFound, ResolveSymbolError };
|
||||||
|
|
||||||
|
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage);
|
||||||
|
|
||||||
|
// List symbols of a module
|
||||||
|
bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
|
||||||
|
QList<Symbol> *symbols, QString *errorMessage);
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
|
#endif // CDBMODULES_H
|
@@ -40,7 +40,8 @@ namespace Internal {
|
|||||||
CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
|
CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
|
||||||
IDebugSymbols3* pDebugSymbols) :
|
IDebugSymbols3* pDebugSymbols) :
|
||||||
m_pDebugSystemObjects(pDebugSystemObjects),
|
m_pDebugSystemObjects(pDebugSystemObjects),
|
||||||
m_pDebugSymbols(pDebugSymbols)
|
m_pDebugSymbols(pDebugSymbols),
|
||||||
|
m_instructionOffset(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +96,8 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
|
|||||||
for (ULONG i=0; i < frameCount; ++i) {
|
for (ULONG i=0; i < frameCount; ++i) {
|
||||||
StackFrame frame(i);
|
StackFrame frame(i);
|
||||||
const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
|
const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
|
||||||
|
if (i == 0)
|
||||||
|
m_instructionOffset = instructionOffset;
|
||||||
frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
|
frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
|
||||||
|
|
||||||
m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
|
m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
|
||||||
@@ -163,5 +166,5 @@ IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString *
|
|||||||
return sg;
|
return sg;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
@@ -66,6 +66,9 @@ public:
|
|||||||
QList<StackFrame> frames() const { return m_frames; }
|
QList<StackFrame> frames() const { return m_frames; }
|
||||||
inline int frameCount() const { return m_frames.size(); }
|
inline int frameCount() const { return m_frames.size(); }
|
||||||
|
|
||||||
|
// Top-Level instruction offset for disassembler
|
||||||
|
ULONG64 instructionOffset() const { return m_instructionOffset; }
|
||||||
|
|
||||||
CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
|
CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -78,9 +81,10 @@ private:
|
|||||||
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
|
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
|
||||||
QVector <CdbSymbolGroupContext*> m_symbolContexts;
|
QVector <CdbSymbolGroupContext*> m_symbolContexts;
|
||||||
QList<StackFrame> m_frames;
|
QList<StackFrame> m_frames;
|
||||||
|
ULONG64 m_instructionOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
|
||||||
#endif // CDBSTACKTRACECONTEXT_H
|
#endif // CDBSTACKTRACECONTEXT_H
|
||||||
|
@@ -58,13 +58,13 @@ static inline void debugSymbolFlags(unsigned long f, QTextStream &str)
|
|||||||
str << "|DEBUG_SYMBOL_IS_LOCAL";
|
str << "|DEBUG_SYMBOL_IS_LOCAL";
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS& p)
|
QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p)
|
||||||
{
|
{
|
||||||
str << " Type=" << p.TypeId << " parent=";
|
str << " Type=" << p.TypeId << " parent=";
|
||||||
if (isTopLevelSymbol(p)) {
|
if (isTopLevelSymbol(p)) {
|
||||||
str << "<ROOT>";
|
str << "<ROOT>";
|
||||||
} else {
|
} else {
|
||||||
str << p.ParentSymbol;
|
str << p.ParentSymbol;
|
||||||
}
|
}
|
||||||
str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/';
|
str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/';
|
||||||
debugSymbolFlags(p.Flags, str);
|
debugSymbolFlags(p.Flags, str);
|
||||||
@@ -403,45 +403,67 @@ bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &val
|
|||||||
|
|
||||||
// format an array of integers as "0x323, 0x2322, ..."
|
// format an array of integers as "0x323, 0x2322, ..."
|
||||||
template <class Integer>
|
template <class Integer>
|
||||||
static QString hexFormatArrayHelper(const Integer *array, int size)
|
static QString formatArrayHelper(const Integer *array, int size, int base = 10)
|
||||||
{
|
{
|
||||||
QString rc;
|
QString rc;
|
||||||
const QString hexPrefix = QLatin1String("0x");
|
const QString hexPrefix = QLatin1String("0x");
|
||||||
const QString separator= QLatin1String(", ");
|
const QString separator= QLatin1String(", ");
|
||||||
|
const bool hex = base == 16;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if (i)
|
if (i)
|
||||||
rc += separator;
|
rc += separator;
|
||||||
rc += hexPrefix;
|
if (hex)
|
||||||
rc += QString::number(array[i], 16);
|
rc += hexPrefix;
|
||||||
|
rc += QString::number(array[i], base);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CdbSymbolGroupContext::hexFormatArray(const unsigned short *array, int size)
|
QString CdbSymbolGroupContext::hexFormatArray(const unsigned short *array, int size)
|
||||||
{
|
{
|
||||||
return hexFormatArrayHelper(array, size);
|
return formatArrayHelper(array, size, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type)
|
// Helper to format an integer with
|
||||||
|
// a hex prefix in case base = 16
|
||||||
|
template <class Integer>
|
||||||
|
inline QString formatInteger(Integer value, int base)
|
||||||
|
{
|
||||||
|
QString rc;
|
||||||
|
if (base == 16)
|
||||||
|
rc = QLatin1String("0x");
|
||||||
|
rc += QString::number(value, base);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl,
|
||||||
|
QString *qType,
|
||||||
|
int integerBase)
|
||||||
{
|
{
|
||||||
switch (dv.Type) {
|
switch (dv.Type) {
|
||||||
case DEBUG_VALUE_INT8:
|
case DEBUG_VALUE_INT8:
|
||||||
*type = QLatin1String("char");
|
if (qType)
|
||||||
return QString::number(dv.I8);
|
*qType = QLatin1String("char");
|
||||||
|
return formatInteger(dv.I8, integerBase);
|
||||||
case DEBUG_VALUE_INT16:
|
case DEBUG_VALUE_INT16:
|
||||||
*type = QLatin1String("short");
|
if (qType)
|
||||||
return QString::number(static_cast<short>(dv.I16));
|
*qType = QLatin1String("short");
|
||||||
|
return formatInteger(static_cast<short>(dv.I16), integerBase);
|
||||||
case DEBUG_VALUE_INT32:
|
case DEBUG_VALUE_INT32:
|
||||||
*type = QLatin1String("long");
|
if (qType)
|
||||||
return QString::number(static_cast<long>(dv.I32));
|
*qType = QLatin1String("long");
|
||||||
|
return formatInteger(static_cast<long>(dv.I32), integerBase);
|
||||||
case DEBUG_VALUE_INT64:
|
case DEBUG_VALUE_INT64:
|
||||||
*type = QLatin1String("long long");
|
if (qType)
|
||||||
return QString::number(static_cast<long long>(dv.I64));
|
*qType = QLatin1String("long long");
|
||||||
|
return formatInteger(static_cast<long long>(dv.I64), integerBase);
|
||||||
case DEBUG_VALUE_FLOAT32:
|
case DEBUG_VALUE_FLOAT32:
|
||||||
*type = QLatin1String("float");
|
if (qType)
|
||||||
|
*qType = QLatin1String("float");
|
||||||
return QString::number(dv.F32);
|
return QString::number(dv.F32);
|
||||||
case DEBUG_VALUE_FLOAT64:
|
case DEBUG_VALUE_FLOAT64:
|
||||||
*type = QLatin1String("double");
|
if (qType)
|
||||||
|
*qType = QLatin1String("double");
|
||||||
return QString::number(dv.F64);
|
return QString::number(dv.F64);
|
||||||
case DEBUG_VALUE_FLOAT80:
|
case DEBUG_VALUE_FLOAT80:
|
||||||
case DEBUG_VALUE_FLOAT128: { // Convert to double
|
case DEBUG_VALUE_FLOAT128: { // Convert to double
|
||||||
@@ -449,28 +471,32 @@ QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugC
|
|||||||
double d = 0.0;
|
double d = 0.0;
|
||||||
if (SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue)))
|
if (SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue)))
|
||||||
d = dv.F64;
|
d = dv.F64;
|
||||||
*type = dv.Type == DEBUG_VALUE_FLOAT80 ? QLatin1String("80bit-float") : QLatin1String("128bit-float");
|
if (qType)
|
||||||
|
*qType = QLatin1String(dv.Type == DEBUG_VALUE_FLOAT80 ? "80bit-float" : "128bit-float");
|
||||||
return QString::number(d);
|
return QString::number(d);
|
||||||
}
|
}
|
||||||
case DEBUG_VALUE_VECTOR64: {
|
case DEBUG_VALUE_VECTOR64: {
|
||||||
*type = QLatin1String("64bit-vector");
|
if (qType)
|
||||||
QString rc = QLatin1String("bytes: ");
|
*qType = QLatin1String("64bit-vector");
|
||||||
rc += hexFormatArrayHelper(dv.VI8, 8);
|
QString rc = QLatin1String("bytes: ");
|
||||||
rc += QLatin1String(" long: ");
|
rc += formatArrayHelper(dv.VI8, 8, integerBase);
|
||||||
rc += hexFormatArrayHelper(dv.VI32, 2);
|
rc += QLatin1String(" long: ");
|
||||||
return rc;
|
rc += formatArrayHelper(dv.VI32, 2, integerBase);
|
||||||
}
|
return rc;
|
||||||
|
}
|
||||||
case DEBUG_VALUE_VECTOR128: {
|
case DEBUG_VALUE_VECTOR128: {
|
||||||
*type = QLatin1String("128bit-vector");
|
if (qType)
|
||||||
QString rc = QLatin1String("bytes: ");
|
*qType = QLatin1String("128bit-vector");
|
||||||
rc += hexFormatArrayHelper(dv.VI8, 16);
|
QString rc = QLatin1String("bytes: ");
|
||||||
rc += QLatin1String(" long long: ");
|
rc += formatArrayHelper(dv.VI8, 16, integerBase);
|
||||||
rc += hexFormatArrayHelper(dv.VI64, 2);
|
rc += QLatin1String(" long long: ");
|
||||||
return rc;
|
rc += formatArrayHelper(dv.VI64, 2, integerBase);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (qType)
|
||||||
*type = QString::fromLatin1("Unknown type #%1:").arg(dv.Type);
|
*qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type);
|
||||||
return hexFormatArrayHelper(dv.RawBytes, 24);
|
return formatArrayHelper(dv.RawBytes, 24, integerBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Watch model functions
|
// - Watch model functions
|
||||||
@@ -613,5 +639,5 @@ bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class WatchData;
|
class WatchData;
|
||||||
class WatchHandler;
|
class WatchHandler;
|
||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
|
inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
|
||||||
|
|
||||||
// Helper to convert a DEBUG_VALUE structure to a string representation
|
// Helper to convert a DEBUG_VALUE structure to a string representation
|
||||||
static QString debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type);
|
static QString debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type = 0, int integerBase = 10);
|
||||||
|
|
||||||
// format an array of unsigned longs as "0x323, 0x2322, ..."
|
// format an array of unsigned longs as "0x323, 0x2322, ..."
|
||||||
static QString hexFormatArray(const unsigned short *array, int size);
|
static QString hexFormatArray(const unsigned short *array, int size);
|
||||||
@@ -145,6 +145,7 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
}
|
} // namespace Debugger
|
||||||
|
|
||||||
#endif // CDBSYMBOLGROUPCONTEXT_H
|
#endif // CDBSYMBOLGROUPCONTEXT_H
|
||||||
|
@@ -54,7 +54,7 @@ namespace Internal {
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
DebuggerSettings::DebuggerSettings(QObject *parent)
|
DebuggerSettings::DebuggerSettings(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent), m_registerFormatGroup(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DebuggerSettings::~DebuggerSettings()
|
DebuggerSettings::~DebuggerSettings()
|
||||||
@@ -74,25 +74,25 @@ void DebuggerSettings::readSettings(QSettings *settings)
|
|||||||
item->readSettings(settings);
|
item->readSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerSettings::writeSettings(QSettings *settings)
|
void DebuggerSettings::writeSettings(QSettings *settings) const
|
||||||
{
|
{
|
||||||
foreach (SavedAction *item, m_items)
|
foreach (SavedAction *item, m_items)
|
||||||
item->writeSettings(settings);
|
item->writeSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
SavedAction *DebuggerSettings::item(int code)
|
SavedAction *DebuggerSettings::item(int code) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_items.value(code, 0), return 0);
|
QTC_ASSERT(m_items.value(code, 0), return 0);
|
||||||
return m_items.value(code, 0);
|
return m_items.value(code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DebuggerSettings::dump()
|
QString DebuggerSettings::dump() const
|
||||||
{
|
{
|
||||||
QString out;
|
QString out;
|
||||||
QTextStream ts(&out);
|
QTextStream ts(&out);
|
||||||
ts << "Debugger settings: ";
|
ts << "Debugger settings: ";
|
||||||
foreach (SavedAction *item, m_items)
|
foreach (SavedAction *item, m_items)
|
||||||
ts << "\n" << item->value().toString();
|
ts << '\n' << item->value().toString();
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,27 +153,27 @@ DebuggerSettings *DebuggerSettings::instance()
|
|||||||
|
|
||||||
//
|
//
|
||||||
// DebuggingHelper
|
// DebuggingHelper
|
||||||
//
|
const QString debugModeGroup = QLatin1String("DebugMode");
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
instance->insertItem(UseDebuggingHelpers, item);
|
instance->insertItem(UseDebuggingHelpers, item);
|
||||||
item->setDefaultValue(true);
|
item->setDefaultValue(true);
|
||||||
item->setSettingsKey("DebugMode", "UseDebuggingHelper");
|
item->setSettingsKey(debugModeGroup, QLatin1String("UseDebuggingHelper"));
|
||||||
item->setText(tr("Use Debugging Helper"));
|
item->setText(tr("Use Debugging Helper"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setDefaultValue(true);
|
item->setDefaultValue(true);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
instance->insertItem(UseCustomDebuggingHelperLocation, item);
|
instance->insertItem(UseCustomDebuggingHelperLocation, item);
|
||||||
item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation");
|
item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
instance->insertItem(CustomDebuggingHelperLocation, item);
|
instance->insertItem(CustomDebuggingHelperLocation, item);
|
||||||
item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation");
|
item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation"));
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
instance->insertItem(DebugDebuggingHelpers, item);
|
instance->insertItem(DebugDebuggingHelpers, item);
|
||||||
item->setSettingsKey("DebugMode", "DebugDebuggingHelpers");
|
item->setSettingsKey(debugModeGroup, QLatin1String("DebugDebuggingHelpers"));
|
||||||
item->setText(tr("Debug debugging helper"));
|
item->setText(tr("Debug debugging helper"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
|
|
||||||
@@ -193,115 +193,120 @@ DebuggerSettings *DebuggerSettings::instance()
|
|||||||
// Registers
|
// Registers
|
||||||
//
|
//
|
||||||
|
|
||||||
QActionGroup *registerFormatGroup = new QActionGroup(instance);
|
instance->m_registerFormatGroup = new QActionGroup(instance);
|
||||||
registerFormatGroup->setExclusive(true);
|
instance->m_registerFormatGroup->setExclusive(true);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Hexadecimal"));
|
item->setText(tr("Hexadecimal"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatHexadecimal");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatHexadecimal"));
|
||||||
item->setChecked(true);
|
item->setChecked(true);
|
||||||
|
item->setData(FormatHexadecimal);
|
||||||
instance->insertItem(FormatHexadecimal, item);
|
instance->insertItem(FormatHexadecimal, item);
|
||||||
registerFormatGroup->addAction(item);
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Decimal"));
|
item->setText(tr("Decimal"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatDecimal");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatDecimal"));
|
||||||
|
item->setData(FormatDecimal);
|
||||||
instance->insertItem(FormatDecimal, item);
|
instance->insertItem(FormatDecimal, item);
|
||||||
registerFormatGroup->addAction(item);
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Octal"));
|
item->setText(tr("Octal"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatOctal");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatOctal"));
|
||||||
|
item->setData(FormatOctal);
|
||||||
instance->insertItem(FormatOctal, item);
|
instance->insertItem(FormatOctal, item);
|
||||||
registerFormatGroup->addAction(item);
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Binary"));
|
item->setText(tr("Binary"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatBinary");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatBinary"));
|
||||||
|
item->setData(FormatBinary);
|
||||||
instance->insertItem(FormatBinary, item);
|
instance->insertItem(FormatBinary, item);
|
||||||
registerFormatGroup->addAction(item);
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Raw"));
|
item->setText(tr("Raw"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatRaw");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatRaw"));
|
||||||
instance->insertItem(FormatRaw, item);
|
instance->insertItem(FormatRaw, item);
|
||||||
registerFormatGroup->addAction(item);
|
item->setData(FormatRaw);
|
||||||
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setText(tr("Natural"));
|
item->setText(tr("Natural"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setSettingsKey("DebugMode", "FormatNatural");
|
item->setSettingsKey(debugModeGroup, QLatin1String("FormatNatural"));
|
||||||
|
item->setData(FormatNatural);
|
||||||
instance->insertItem(FormatNatural, item);
|
instance->insertItem(FormatNatural, item);
|
||||||
registerFormatGroup->addAction(item);
|
instance->m_registerFormatGroup->addAction(item);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Settings
|
// Settings
|
||||||
//
|
//
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "Location");
|
item->setSettingsKey(debugModeGroup, QLatin1String("Location"));
|
||||||
instance->insertItem(GdbLocation, item);
|
instance->insertItem(GdbLocation, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "Environment");
|
item->setSettingsKey(debugModeGroup, QLatin1String("Environment"));
|
||||||
instance->insertItem(GdbEnvironment, item);
|
instance->insertItem(GdbEnvironment, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "ScriptFile");
|
item->setSettingsKey(debugModeGroup, QLatin1String("ScriptFile"));
|
||||||
instance->insertItem(GdbScriptFile, item);
|
instance->insertItem(GdbScriptFile, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "AutoQuit");
|
item->setSettingsKey(debugModeGroup, QLatin1String("AutoQuit"));
|
||||||
item->setText(tr("Automatically quit debugger"));
|
item->setText(tr("Automatically quit debugger"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
instance->insertItem(AutoQuit, item);
|
instance->insertItem(AutoQuit, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "UseToolTips");
|
item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTips"));
|
||||||
item->setText(tr("Use tooltips when debugging"));
|
item->setText(tr("Use tooltips when debugging"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
instance->insertItem(UseToolTips, item);
|
instance->insertItem(UseToolTips, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setDefaultValue("xterm");
|
item->setDefaultValue(QLatin1String("xterm"));
|
||||||
item->setSettingsKey("DebugMode", "Terminal");
|
item->setSettingsKey(debugModeGroup, QLatin1String("Terminal"));
|
||||||
instance->insertItem(TerminalApplication, item);
|
instance->insertItem(TerminalApplication, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "ListSourceFiles");
|
item->setSettingsKey(debugModeGroup, QLatin1String("ListSourceFiles"));
|
||||||
item->setText(tr("List source files"));
|
item->setText(tr("List source files"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
instance->insertItem(ListSourceFiles, item);
|
instance->insertItem(ListSourceFiles, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "SkipKnownFrames");
|
item->setSettingsKey(debugModeGroup, QLatin1String("SkipKnownFrames"));
|
||||||
item->setText(tr("Skip known frames"));
|
item->setText(tr("Skip known frames"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
instance->insertItem(SkipKnownFrames, item);
|
instance->insertItem(SkipKnownFrames, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "AllPluginBreakpoints");
|
item->setSettingsKey(debugModeGroup, QLatin1String("AllPluginBreakpoints"));
|
||||||
instance->insertItem(AllPluginBreakpoints, item);
|
instance->insertItem(AllPluginBreakpoints, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "SelectedPluginBreakpoints");
|
item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpoints"));
|
||||||
instance->insertItem(SelectedPluginBreakpoints, item);
|
instance->insertItem(SelectedPluginBreakpoints, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "NoPluginBreakpoints");
|
item->setSettingsKey(debugModeGroup, QLatin1String("NoPluginBreakpoints"));
|
||||||
instance->insertItem(NoPluginBreakpoints, item);
|
instance->insertItem(NoPluginBreakpoints, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "SelectedPluginBreakpointsPattern");
|
item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpointsPattern"));
|
||||||
instance->insertItem(SelectedPluginBreakpointsPattern, item);
|
instance->insertItem(SelectedPluginBreakpointsPattern, item);
|
||||||
|
|
||||||
item = new SavedAction(instance);
|
item = new SavedAction(instance);
|
||||||
item->setSettingsKey("DebugMode", "MaximalStackDepth");
|
item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStackDepth"));
|
||||||
item->setDefaultValue(20);
|
item->setDefaultValue(20);
|
||||||
instance->insertItem(MaximalStackDepth, item);
|
instance->insertItem(MaximalStackDepth, item);
|
||||||
|
|
||||||
@@ -316,6 +321,11 @@ DebuggerSettings *DebuggerSettings::instance()
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DebuggerSettings::checkedRegisterFormatAction() const
|
||||||
|
{
|
||||||
|
return m_registerFormatGroup->checkedAction()->data().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// DebuggerActions
|
// DebuggerActions
|
||||||
@@ -327,6 +337,11 @@ SavedAction *theDebuggerAction(int code)
|
|||||||
return DebuggerSettings::instance()->item(code);
|
return DebuggerSettings::instance()->item(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int checkedRegisterFormatAction()
|
||||||
|
{
|
||||||
|
return DebuggerSettings::instance()->checkedRegisterFormatAction();
|
||||||
|
}
|
||||||
|
|
||||||
bool theDebuggerBoolSetting(int code)
|
bool theDebuggerBoolSetting(int code)
|
||||||
{
|
{
|
||||||
return DebuggerSettings::instance()->item(code)->value().toBool();
|
return DebuggerSettings::instance()->item(code)->value().toBool();
|
||||||
|
@@ -34,6 +34,9 @@
|
|||||||
|
|
||||||
#include <utils/savedaction.h>
|
#include <utils/savedaction.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QActionGroup;
|
||||||
|
QT_END_NAMESPACE
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -46,18 +49,22 @@ public:
|
|||||||
~DebuggerSettings();
|
~DebuggerSettings();
|
||||||
|
|
||||||
void insertItem(int code, Core::Utils::SavedAction *item);
|
void insertItem(int code, Core::Utils::SavedAction *item);
|
||||||
Core::Utils::SavedAction *item(int code);
|
Core::Utils::SavedAction *item(int code) const;
|
||||||
|
|
||||||
QString dump();
|
QString dump() const;
|
||||||
|
|
||||||
static DebuggerSettings *instance();
|
static DebuggerSettings *instance();
|
||||||
|
|
||||||
|
// Return one of FormatHexadecimal, FormatDecimal,...
|
||||||
|
int checkedRegisterFormatAction() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void readSettings(QSettings *settings);
|
void readSettings(QSettings *settings);
|
||||||
void writeSettings(QSettings *settings);
|
void writeSettings(QSettings *settings) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<int, Core::Utils::SavedAction *> m_items;
|
QHash<int, Core::Utils::SavedAction *> m_items;
|
||||||
|
QActionGroup *m_registerFormatGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -125,7 +132,10 @@ enum DebuggerActionCode
|
|||||||
// singleton access
|
// singleton access
|
||||||
Core::Utils::SavedAction *theDebuggerAction(int code);
|
Core::Utils::SavedAction *theDebuggerAction(int code);
|
||||||
|
|
||||||
// convienience
|
// Return one of FormatHexadecimal, FormatDecimal,...
|
||||||
|
int checkedRegisterFormatAction();
|
||||||
|
|
||||||
|
// convenience
|
||||||
bool theDebuggerBoolSetting(int code);
|
bool theDebuggerBoolSetting(int code);
|
||||||
QString theDebuggerStringSetting(int code);
|
QString theDebuggerStringSetting(int code);
|
||||||
|
|
||||||
|
@@ -175,7 +175,7 @@ void DebuggerManager::init()
|
|||||||
m_statusLabel = new QLabel;
|
m_statusLabel = new QLabel;
|
||||||
m_breakWindow = new BreakWindow;
|
m_breakWindow = new BreakWindow;
|
||||||
m_disassemblerWindow = new DisassemblerWindow;
|
m_disassemblerWindow = new DisassemblerWindow;
|
||||||
m_modulesWindow = new ModulesWindow;
|
m_modulesWindow = new ModulesWindow(this);
|
||||||
m_outputWindow = new DebuggerOutputWindow;
|
m_outputWindow = new DebuggerOutputWindow;
|
||||||
m_registerWindow = new RegisterWindow;
|
m_registerWindow = new RegisterWindow;
|
||||||
m_stackWindow = new StackWindow;
|
m_stackWindow = new StackWindow;
|
||||||
@@ -213,6 +213,8 @@ void DebuggerManager::init()
|
|||||||
QAbstractItemView *disassemblerView =
|
QAbstractItemView *disassemblerView =
|
||||||
qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
|
qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
|
||||||
disassemblerView->setModel(m_disassemblerHandler->model());
|
disassemblerView->setModel(m_disassemblerHandler->model());
|
||||||
|
connect(m_disassemblerWindow, SIGNAL(reloadDisassemblerRequested()),
|
||||||
|
this, SLOT(reloadDisassembler()));
|
||||||
|
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
m_breakHandler = new BreakHandler;
|
m_breakHandler = new BreakHandler;
|
||||||
@@ -996,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module)
|
|||||||
m_engine->loadSymbols(module);
|
m_engine->loadSymbols(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_engine, return QList<Symbol>());
|
||||||
|
return m_engine->moduleSymbols(moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
void DebuggerManager::stepExec()
|
void DebuggerManager::stepExec()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_engine, return);
|
QTC_ASSERT(m_engine, return);
|
||||||
|
@@ -65,7 +65,7 @@ class WatchHandler;
|
|||||||
class SourceFilesWindow;
|
class SourceFilesWindow;
|
||||||
class WatchData;
|
class WatchData;
|
||||||
class BreakpointData;
|
class BreakpointData;
|
||||||
|
class Symbol;
|
||||||
|
|
||||||
// Note: the Debugger process itself is referred to as 'Debugger',
|
// Note: the Debugger process itself is referred to as 'Debugger',
|
||||||
// whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
|
// whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
|
||||||
@@ -309,6 +309,8 @@ public:
|
|||||||
int status() const { return m_status; }
|
int status() const { return m_status; }
|
||||||
DebuggerStartMode startMode() const { return m_startMode; }
|
DebuggerStartMode startMode() const { return m_startMode; }
|
||||||
|
|
||||||
|
QList<Symbol> moduleSymbols(const QString &moduleName);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void debuggingFinished();
|
void debuggingFinished();
|
||||||
void inferiorPidChanged(qint64 pid);
|
void inferiorPidChanged(qint64 pid);
|
||||||
|
@@ -650,6 +650,19 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
|
|||||||
connect(resetToSimpleAction, SIGNAL(triggered()),
|
connect(resetToSimpleAction, SIGNAL(triggered()),
|
||||||
m_manager, SLOT(setSimpleDockWidgetArrangement()));
|
m_manager, SLOT(setSimpleDockWidgetArrangement()));
|
||||||
|
|
||||||
|
connect(theDebuggerAction(FormatHexadecimal), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
connect(theDebuggerAction(FormatDecimal), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
connect(theDebuggerAction(FormatOctal), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
connect(theDebuggerAction(FormatBinary), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
connect(theDebuggerAction(FormatRaw), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
connect(theDebuggerAction(FormatNatural), SIGNAL(triggered()),
|
||||||
|
m_manager, SLOT(reloadRegisters()));
|
||||||
|
|
||||||
// FIXME:
|
// FIXME:
|
||||||
m_generalOptionPage = new GdbOptionPage;
|
m_generalOptionPage = new GdbOptionPage;
|
||||||
addObject(m_generalOptionPage);
|
addObject(m_generalOptionPage);
|
||||||
|
@@ -39,6 +39,14 @@
|
|||||||
using namespace Debugger;
|
using namespace Debugger;
|
||||||
using namespace Debugger::Internal;
|
using namespace Debugger::Internal;
|
||||||
|
|
||||||
|
void DisassemblerLine::clear()
|
||||||
|
{
|
||||||
|
address.clear();
|
||||||
|
symbol.clear();
|
||||||
|
addressDisplay.clear();
|
||||||
|
symbolDisplay.clear();
|
||||||
|
mnemonic.clear();
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@@ -41,6 +41,8 @@ namespace Internal {
|
|||||||
class DisassemblerLine
|
class DisassemblerLine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void clear();
|
||||||
|
|
||||||
QString address;
|
QString address;
|
||||||
QString symbol;
|
QString symbol;
|
||||||
QString addressDisplay;
|
QString addressDisplay;
|
||||||
|
@@ -221,19 +221,6 @@ void GdbEngine::initializeConnections()
|
|||||||
connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()),
|
connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()),
|
||||||
this, SLOT(recheckDebuggingHelperAvailability()));
|
this, SLOT(recheckDebuggingHelperAvailability()));
|
||||||
|
|
||||||
connect(theDebuggerAction(FormatHexadecimal), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
connect(theDebuggerAction(FormatDecimal), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
connect(theDebuggerAction(FormatOctal), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
connect(theDebuggerAction(FormatBinary), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
connect(theDebuggerAction(FormatRaw), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
connect(theDebuggerAction(FormatNatural), SIGNAL(triggered()),
|
|
||||||
this, SLOT(reloadRegisters()));
|
|
||||||
|
|
||||||
connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()),
|
connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()),
|
||||||
this, SLOT(reloadFullStack()));
|
this, SLOT(reloadFullStack()));
|
||||||
connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()),
|
connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()),
|
||||||
@@ -2402,6 +2389,40 @@ void GdbEngine::loadAllSymbols()
|
|||||||
reloadModules();
|
reloadModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
|
||||||
|
{
|
||||||
|
QList<Symbol> rc;
|
||||||
|
bool success = false;
|
||||||
|
QString errorMessage;
|
||||||
|
do {
|
||||||
|
const QString nmBinary = QLatin1String("nm");
|
||||||
|
QProcess proc;
|
||||||
|
proc.start(nmBinary, QStringList() << QLatin1String("-D") << moduleName);
|
||||||
|
if (!proc.waitForFinished()) {
|
||||||
|
errorMessage = tr("Unable to run '%1': %2").arg(nmBinary, proc.errorString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
|
||||||
|
const QRegExp re(QLatin1String("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"));
|
||||||
|
Q_ASSERT(re.isValid());
|
||||||
|
foreach (const QString &line, contents.split(QLatin1Char('\n'))) {
|
||||||
|
if (re.indexIn(line) != -1) {
|
||||||
|
Symbol symbol;
|
||||||
|
symbol.address = re.cap(1);
|
||||||
|
symbol.state = re.cap(2);
|
||||||
|
symbol.name = re.cap(3);
|
||||||
|
rc.push_back(symbol);
|
||||||
|
} else {
|
||||||
|
qWarning("moduleSymbols: unhandled: %s", qPrintable(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
} while (false);
|
||||||
|
if (!success)
|
||||||
|
qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void GdbEngine::reloadModules()
|
void GdbEngine::reloadModules()
|
||||||
{
|
{
|
||||||
sendCommand("info shared", ModulesList, QVariant());
|
sendCommand("info shared", ModulesList, QVariant());
|
||||||
@@ -2619,22 +2640,28 @@ void GdbEngine::handleStackListThreads(const GdbResultRecord &record, int id)
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline char registerFormatChar()
|
||||||
|
{
|
||||||
|
switch(checkedRegisterFormatAction()) {
|
||||||
|
case FormatHexadecimal:
|
||||||
|
return 'x';
|
||||||
|
case FormatDecimal:
|
||||||
|
return 'd';
|
||||||
|
case FormatOctal:
|
||||||
|
return 'o';
|
||||||
|
case FormatBinary:
|
||||||
|
return 't';
|
||||||
|
case FormatRaw:
|
||||||
|
return 'r';
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 'N';
|
||||||
|
}
|
||||||
|
|
||||||
void GdbEngine::reloadRegisters()
|
void GdbEngine::reloadRegisters()
|
||||||
{
|
{
|
||||||
QString format;
|
sendCommand(QLatin1String("-data-list-register-values ") + QLatin1Char(registerFormatChar()), RegisterListValues);
|
||||||
if (theDebuggerAction(FormatHexadecimal)->isChecked())
|
|
||||||
format = "x";
|
|
||||||
else if (theDebuggerAction(FormatDecimal)->isChecked())
|
|
||||||
format = "d";
|
|
||||||
else if (theDebuggerAction(FormatOctal)->isChecked())
|
|
||||||
format = "o";
|
|
||||||
else if (theDebuggerAction(FormatBinary)->isChecked())
|
|
||||||
format = "t";
|
|
||||||
else if (theDebuggerAction(FormatRaw)->isChecked())
|
|
||||||
format = "r";
|
|
||||||
else
|
|
||||||
format = "N";
|
|
||||||
sendCommand("-data-list-register-values " + format, RegisterListValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleRegisterListNames(const GdbResultRecord &record)
|
void GdbEngine::handleRegisterListNames(const GdbResultRecord &record)
|
||||||
|
@@ -129,6 +129,7 @@ private:
|
|||||||
|
|
||||||
void loadSymbols(const QString &moduleName);
|
void loadSymbols(const QString &moduleName);
|
||||||
void loadAllSymbols();
|
void loadAllSymbols();
|
||||||
|
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
|
||||||
|
|
||||||
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
|
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
|
||||||
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#define DEBUGGER_IDEBUGGERENGINE_H
|
#define DEBUGGER_IDEBUGGERENGINE_H
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QList>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QPoint;
|
class QPoint;
|
||||||
@@ -40,6 +41,8 @@ QT_END_NAMESPACE
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class Symbol;
|
||||||
|
|
||||||
class IDebuggerEngine : public QObject
|
class IDebuggerEngine : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -79,6 +82,7 @@ public:
|
|||||||
virtual void reloadModules() = 0;
|
virtual void reloadModules() = 0;
|
||||||
virtual void loadSymbols(const QString &moduleName) = 0;
|
virtual void loadSymbols(const QString &moduleName) = 0;
|
||||||
virtual void loadAllSymbols() = 0;
|
virtual void loadAllSymbols() = 0;
|
||||||
|
virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
|
||||||
|
|
||||||
virtual void reloadRegisters() = 0;
|
virtual void reloadRegisters() = 0;
|
||||||
|
|
||||||
|
@@ -51,6 +51,19 @@ enum ModulesModelRoles
|
|||||||
LoadAllSymbolsRole
|
LoadAllSymbolsRole
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Symbol
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class Symbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString address;
|
||||||
|
QString state;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "moduleswindow.h"
|
#include "moduleswindow.h"
|
||||||
#include "moduleshandler.h" // for model roles
|
#include "moduleshandler.h" // for model roles
|
||||||
|
#include "debuggermanager.h"
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
#include <QtGui/QResizeEvent>
|
#include <QtGui/QResizeEvent>
|
||||||
#include <QtGui/QToolButton>
|
#include <QtGui/QToolButton>
|
||||||
#include <QtGui/QTreeWidget>
|
#include <QtGui/QTreeWidget>
|
||||||
|
#include <QtGui/QApplication>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -48,10 +49,14 @@
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
using Debugger::Internal::ModulesWindow;
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
ModulesWindow::ModulesWindow(QWidget *parent)
|
ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager,
|
||||||
: QTreeView(parent), m_alwaysResizeColumnsToContents(false)
|
QWidget *parent) :
|
||||||
|
QTreeView(parent),
|
||||||
|
m_alwaysResizeColumnsToContents(false),
|
||||||
|
m_debuggerManager(debuggerManager)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Modules"));
|
setWindowTitle(tr("Modules"));
|
||||||
setSortingEnabled(true);
|
setSortingEnabled(true);
|
||||||
@@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event)
|
|||||||
|
|
||||||
void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
|
void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
{
|
{
|
||||||
|
QString name;
|
||||||
QModelIndex index = indexAt(ev->pos());
|
QModelIndex index = indexAt(ev->pos());
|
||||||
index = index.sibling(index.row(), 0);
|
if (index.isValid())
|
||||||
QString name = model()->data(index).toString();
|
index = index.sibling(index.row(), 0);
|
||||||
|
if (index.isValid())
|
||||||
|
name = model()->data(index).toString();
|
||||||
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
QAction *act0 = new QAction(tr("Update module list"), &menu);
|
QAction *act0 = new QAction(tr("Update module list"), &menu);
|
||||||
@@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
act5->setDisabled(name.isEmpty());
|
act5->setDisabled(name.isEmpty());
|
||||||
act6->setDisabled(name.isEmpty());
|
act6->setDisabled(name.isEmpty());
|
||||||
act7->setDisabled(name.isEmpty());
|
act7->setDisabled(name.isEmpty());
|
||||||
#ifndef Q_OS_LINUX
|
|
||||||
act7->setDisabled(true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
menu.addAction(act0);
|
menu.addAction(act0);
|
||||||
menu.addAction(act4);
|
menu.addAction(act4);
|
||||||
@@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name)
|
|||||||
{
|
{
|
||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
return;
|
return;
|
||||||
QProcess proc;
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
proc.start("nm", QStringList() << "-D" << name);
|
const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
|
||||||
proc.waitForFinished();
|
QApplication::restoreOverrideCursor();
|
||||||
|
if (symbols.empty())
|
||||||
|
return;
|
||||||
QTreeWidget *w = new QTreeWidget;
|
QTreeWidget *w = new QTreeWidget;
|
||||||
w->setColumnCount(3);
|
w->setColumnCount(3);
|
||||||
w->setRootIsDecorated(false);
|
w->setRootIsDecorated(false);
|
||||||
w->setAlternatingRowColors(true);
|
w->setAlternatingRowColors(true);
|
||||||
//w->header()->hide();
|
|
||||||
w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
|
w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
|
||||||
w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
|
w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
|
||||||
QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
|
foreach (const Symbol &s, symbols) {
|
||||||
QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)");
|
QTreeWidgetItem *it = new QTreeWidgetItem;
|
||||||
foreach (QString line, contents.split('\n')) {
|
it->setData(0, Qt::DisplayRole, s.address);
|
||||||
if (re.indexIn(line) != -1) {
|
it->setData(1, Qt::DisplayRole, s.state);
|
||||||
QTreeWidgetItem *it = new QTreeWidgetItem;
|
it->setData(2, Qt::DisplayRole, s.name);
|
||||||
it->setData(0, Qt::DisplayRole, re.cap(1));
|
w->addTopLevelItem(it);
|
||||||
it->setData(1, Qt::DisplayRole, re.cap(2));
|
|
||||||
it->setData(2, Qt::DisplayRole, re.cap(3));
|
|
||||||
w->addTopLevelItem(it);
|
|
||||||
} else {
|
|
||||||
qDebug() << "UNHANDLED LINE" << line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
emit newDockRequested(w);
|
emit newDockRequested(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -35,12 +35,14 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class DebuggerManager;
|
||||||
|
|
||||||
class ModulesWindow : public QTreeView
|
class ModulesWindow : public QTreeView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ModulesWindow(QWidget *parent = 0);
|
explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void reloadModulesRequested();
|
void reloadModulesRequested();
|
||||||
@@ -62,6 +64,7 @@ private:
|
|||||||
void setModel(QAbstractItemModel *model);
|
void setModel(QAbstractItemModel *model);
|
||||||
|
|
||||||
bool m_alwaysResizeColumnsToContents;
|
bool m_alwaysResizeColumnsToContents;
|
||||||
|
DebuggerManager *m_debuggerManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
#include "registerhandler.h"
|
#include "registerhandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
|
#include "moduleshandler.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
@@ -405,6 +406,10 @@ void ScriptEngine::reloadModules()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
|
||||||
|
{
|
||||||
|
return QList<Symbol>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -102,6 +102,7 @@ private:
|
|||||||
|
|
||||||
void loadSymbols(const QString &moduleName);
|
void loadSymbols(const QString &moduleName);
|
||||||
void loadAllSymbols();
|
void loadAllSymbols();
|
||||||
|
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
|
||||||
void reloadDisassembler();
|
void reloadDisassembler();
|
||||||
void reloadModules();
|
void reloadModules();
|
||||||
void reloadRegisters() {}
|
void reloadRegisters() {}
|
||||||
|
@@ -96,15 +96,16 @@ namespace Internal {
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define StartOfLine QTextCursor::StartOfLine
|
#define StartOfLine QTextCursor::StartOfLine
|
||||||
#define EndOfLine QTextCursor::EndOfLine
|
#define EndOfLine QTextCursor::EndOfLine
|
||||||
#define MoveAnchor QTextCursor::MoveAnchor
|
#define MoveAnchor QTextCursor::MoveAnchor
|
||||||
#define KeepAnchor QTextCursor::KeepAnchor
|
#define KeepAnchor QTextCursor::KeepAnchor
|
||||||
#define Up QTextCursor::Up
|
#define Up QTextCursor::Up
|
||||||
#define Down QTextCursor::Down
|
#define Down QTextCursor::Down
|
||||||
#define Right QTextCursor::Right
|
#define Right QTextCursor::Right
|
||||||
#define Left QTextCursor::Left
|
#define Left QTextCursor::Left
|
||||||
#define EndOfDocument QTextCursor::End
|
#define EndOfDocument QTextCursor::End
|
||||||
|
#define StartOfDocument QTextCursor::Start
|
||||||
|
|
||||||
#define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
|
#define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
|
||||||
|
|
||||||
@@ -274,8 +275,6 @@ public:
|
|||||||
void moveToWordBoundary(bool simple, bool forward);
|
void moveToWordBoundary(bool simple, bool forward);
|
||||||
|
|
||||||
// to reduce line noise
|
// to reduce line noise
|
||||||
typedef QTextCursor::MoveOperation MoveOperation;
|
|
||||||
typedef QTextCursor::MoveMode MoveMode;
|
|
||||||
void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
|
void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
|
||||||
void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); }
|
void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); }
|
||||||
void moveToEndOfLine();
|
void moveToEndOfLine();
|
||||||
@@ -1701,6 +1700,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
|
|||||||
static QRegExp reNormal("^norm(al)?( (.*))?$");
|
static QRegExp reNormal("^norm(al)?( (.*))?$");
|
||||||
static QRegExp reSet("^set?( (.*))?$");
|
static QRegExp reSet("^set?( (.*))?$");
|
||||||
static QRegExp reWrite("^w!?( (.*))?$");
|
static QRegExp reWrite("^w!?( (.*))?$");
|
||||||
|
static QRegExp reSubstitute("^s(.)(.*)\\1(.*)\\1([gi]*)");
|
||||||
|
|
||||||
if (cmd.isEmpty()) {
|
if (cmd.isEmpty()) {
|
||||||
setPosition(firstPositionInLine(beginLine));
|
setPosition(firstPositionInLine(beginLine));
|
||||||
@@ -1805,6 +1805,47 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
|
|||||||
enterCommandMode();
|
enterCommandMode();
|
||||||
//qDebug() << "REPLAY: " << reNormal.cap(3);
|
//qDebug() << "REPLAY: " << reNormal.cap(3);
|
||||||
replay(reNormal.cap(3), 1);
|
replay(reNormal.cap(3), 1);
|
||||||
|
} else if (reSubstitute.indexIn(cmd) != -1) { // :substitute
|
||||||
|
QString needle = reSubstitute.cap(2);
|
||||||
|
const QString replacement = reSubstitute.cap(3);
|
||||||
|
QString flags = reSubstitute.cap(4);
|
||||||
|
const bool startOfLineOnly = needle.startsWith('^');
|
||||||
|
if (startOfLineOnly)
|
||||||
|
needle.remove(0, 1);
|
||||||
|
needle.replace('$', '\n');
|
||||||
|
needle.replace("\\\n", "\\$");
|
||||||
|
QRegExp pattern(needle);
|
||||||
|
if (flags.contains('i'))
|
||||||
|
pattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
const bool global = flags.contains('g');
|
||||||
|
m_tc.beginEditBlock();
|
||||||
|
for (int line = beginLine; line <= endLine; ++line) {
|
||||||
|
const int start = firstPositionInLine(line);
|
||||||
|
const int end = lastPositionInLine(line);
|
||||||
|
for (int position = start; position <= end && position >= start; ) {
|
||||||
|
position = pattern.indexIn(m_tc.document()->toPlainText(), position);
|
||||||
|
if (startOfLineOnly && position != start)
|
||||||
|
break;
|
||||||
|
if (position != -1) {
|
||||||
|
m_tc.setPosition(position);
|
||||||
|
m_tc.movePosition(QTextCursor::NextCharacter,
|
||||||
|
KeepAnchor, pattern.matchedLength());
|
||||||
|
QString text = m_tc.selectedText();
|
||||||
|
if (text.endsWith(ParagraphSeparator)) {
|
||||||
|
text = replacement + "\n";
|
||||||
|
} else {
|
||||||
|
text.replace(ParagraphSeparator, "\n");
|
||||||
|
text.replace(pattern, replacement);
|
||||||
|
}
|
||||||
|
m_tc.removeSelectedText();
|
||||||
|
m_tc.insertText(text);
|
||||||
|
}
|
||||||
|
if (!global)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_tc.endEditBlock();
|
||||||
|
enterCommandMode();
|
||||||
} else if (reSet.indexIn(cmd) != -1) { // :set
|
} else if (reSet.indexIn(cmd) != -1) { // :set
|
||||||
showBlackMessage(QString());
|
showBlackMessage(QString());
|
||||||
QString arg = reSet.cap(2);
|
QString arg = reSet.cap(2);
|
||||||
@@ -1927,7 +1968,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
|
|||||||
|
|
||||||
if (!needle0.isEmpty()) {
|
if (!needle0.isEmpty()) {
|
||||||
QTextCursor tc = m_tc;
|
QTextCursor tc = m_tc;
|
||||||
tc.movePosition(QTextCursor::Start, MoveAnchor);
|
tc.movePosition(StartOfDocument, MoveAnchor);
|
||||||
|
|
||||||
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
|
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
|
||||||
QString needle = needle0;
|
QString needle = needle0;
|
||||||
@@ -2330,11 +2371,13 @@ void FakeVimHandler::Private::recordJump()
|
|||||||
UNDO_DEBUG("jumps: " << m_jumpListUndo);
|
UNDO_DEBUG("jumps: " << m_jumpListUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UndoBreaker : public QAbstractUndoItem
|
class UndoBreaker : public QAbstractUndoItem
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
UndoBreaker(FakeVimHandler::Private *doc) : m_doc(doc) {}
|
UndoBreaker(FakeVimHandler::Private *doc) : m_doc(doc) {}
|
||||||
void undo() { m_doc->m_needMoreUndo = true; }
|
void undo() { m_doc->m_needMoreUndo = true; }
|
||||||
void redo() { m_doc->m_needMoreUndo = true; }
|
void redo() { m_doc->m_needMoreUndo = true; }
|
||||||
|
private:
|
||||||
FakeVimHandler::Private *m_doc;
|
FakeVimHandler::Private *m_doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user