diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri deleted file mode 100644 index 59652c3856a60598fdd30005c47c4dc3f6bbae35..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdb.pri +++ /dev/null @@ -1,97 +0,0 @@ -include(cdbcore.pri) - -!isEmpty(CDB_PATH) { - -HEADERS += \ - $$PWD/cdbengine.h \ - $$PWD/cdbengine_p.h \ - $$PWD/cdbdebugeventcallback.h \ - $$PWD/cdbdebugoutput.h \ - $$PWD/cdbsymbolgroupcontext.h \ - $$PWD/cdbsymbolgroupcontext_tpl.h \ - $$PWD/cdbstacktracecontext.h \ - $$PWD/cdbbreakpoint.h \ - $$PWD/cdbmodules.h \ - $$PWD/cdbassembler.h \ - $$PWD/cdboptions.h \ - $$PWD/cdboptionspage.h \ - $$PWD/cdbdumperhelper.h \ - $$PWD/cdbexceptionutils.h - -SOURCES += \ - $$PWD/cdbengine.cpp \ - $$PWD/cdbdebugeventcallback.cpp \ - $$PWD/cdbdebugoutput.cpp \ - $$PWD/cdbsymbolgroupcontext.cpp \ - $$PWD/cdbstacktracecontext.cpp \ - $$PWD/cdbbreakpoint.cpp \ - $$PWD/cdbmodules.cpp \ - $$PWD/cdbassembler.cpp \ - $$PWD/cdboptions.cpp \ - $$PWD/cdboptionspage.cpp \ - $$PWD/cdbdumperhelper.cpp \ - $$PWD/cdbexceptionutils.cpp - -FORMS += $$PWD/cdboptionspagewidget.ui -} - - -# Compile test on non-Windows platforms -isEmpty(CDB_PATH) { -false { - -HEADERS += \ - $$PWD/cdbcom.h \ - $$PWD/coreengine.h \ - $$PWD/debugoutputbase.h \ - $$PWD/debugeventcallbackbase.h \ - $$PWD/symbolgroupcontext.h \ - $$PWD/stacktracecontext.h \ - $$PWD/corebreakpoint.h - -HEADERS += \ - $$PWD/cdbengine.h \ - $$PWD/cdbengine_p.h \ - $$PWD/cdbdebugeventcallback.h \ - $$PWD/cdbdebugoutput.h \ - $$PWD/cdbsymbolgroupcontext.h \ - $$PWD/cdbsymbolgroupcontext_tpl.h \ - $$PWD/cdbstacktracecontext.h \ - $$PWD/cdbbreakpoint.h \ - $$PWD/cdbmodules.h \ - $$PWD/cdbassembler.h \ - $$PWD/cdboptions.h \ - $$PWD/cdboptionspage.h \ - $$PWD/cdbdumperhelper.h \ - $$PWD/cdbsymbolpathlisteditor.h \ - $$PWD/cdbexceptionutils.h - -SOURCES += \ -# $$PWD/coreengine.cpp \ -# $$PWD/debugoutputbase.cpp \ -# $$PWD/debugeventcallbackbase.cpp \ -# $$PWD/symbolgroupcontext.cpp \ -# $$PWD/stacktracecontext.cpp \ -# $$PWD/corebreakpoint.cpp - -SOURCES += \ -# $$PWD/cdbengine.cpp \ -# $$PWD/cdbdebugeventcallback.cpp \ - $$PWD/cdbdebugoutput.cpp \ -# $$PWD/cdbsymbolgroupcontext.cpp \ - $$PWD/cdbstacktracecontext.cpp \ - $$PWD/cdbbreakpoint.cpp \ -# $$PWD/cdbmodules.cpp \ - $$PWD/cdbassembler.cpp \ - $$PWD/cdboptions.cpp \ - $$PWD/cdboptionspage.cpp \ -# $$PWD/cdbdumperhelper.cpp \ - $$PWD/cdbsymbolpathlisteditor.cpp \ -# $$PWD/cdbexceptionutils.cpp - -FORMS += $$PWD/cdboptionspagewidget.ui -INCLUDEPATH*=$$PWD -DEPENDPATH*=$$PWD -} -} - diff --git a/src/plugins/debugger/cdb/cdbassembler.cpp b/src/plugins/debugger/cdb/cdbassembler.cpp deleted file mode 100644 index 61d3a15029888e966eb4e85d19bb3092a359cf2a..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbassembler.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbassembler.h" -#include "cdbdebugoutput.h" -#include "cdbengine_p.h" -#include "cdbsymbolgroupcontext.h" - -#include "registerhandler.h" - -#include <QtCore/QVector> - -namespace Debugger { -namespace Internal { - -Registers getRegisters(CIDebugControl *ctl, - CIDebugRegisters *ireg, - QString *errorMessage, int base) -{ - - ULONG count; - HRESULT hr = ireg->GetNumberRegisters(&count); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("GetNumberRegisters", hr); - return Registers(); - } - if (!count) - return Registers(); - Registers registers(count); - // Retrieve names - char buf[MAX_PATH]; - for (ULONG r = 0; r < count; r++) { - hr = ireg->GetDescription(r, buf, MAX_PATH - 1, 0, 0); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("GetDescription", hr); - return Registers(); - } - registers[r].name = QByteArray(buf); - } - // 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= CdbCore::msgComFailed("GetValues", hr); - return Registers(); - } - if (base < 2) - base = 10; - for (ULONG r = 0; r < count; r++) - registers[r].value = CdbCore::debugValueToString(values.at(r), 0, base, ctl); - return registers; -} - -bool setRegisterValueU64(CIDebugRegisters *ireg, unsigned index, quint64 value, QString *errorMessage) -{ - DEBUG_VALUE debugValueSet; - debugValueSet.Type = DEBUG_VALUE_INT64; - debugValueSet.I64 = value; - const HRESULT hr = ireg->SetValue(index, &debugValueSet); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("SetValue", hr); - false; - } - return true; -} - -bool setRegisterValueU64(CIDebugControl *ctl, - CIDebugRegisters *ireg, - const QString &name, quint64 value, - QString *errorMessage) -{ - // Look up register by name - const Registers registers = getRegisters(ctl, ireg, errorMessage); - const int regCount = registers.size(); - for (int r = 0; r < regCount; r++) - if (registers.at(r).name == name) - return setRegisterValueU64(ireg, r, value, errorMessage); - *errorMessage = QString::fromLatin1("Unable to set register '%1' to %2: No such register") - .arg(name).arg(value); - return false; -} - -/* Output parser for disassembler lines: Parse a disassembler line: - * \code -module!class::foo: - 004017cf cc int 3 -77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58] -\endcode - * and reformat to something like: - * \code -00000001400043c9 mainwindow.cpp+296 90 nop -00000001400043ca mainwindow.cpp+296 488d8c24d8020000 lea rcx,[rsp+2D8h] -00000001400043d2 mainwindow.cpp+296 ff1500640300 call qword ptr [gitgui!_imp_??1QStringQEAAXZ (00000001`4003a7d8)] -\endcode - * Reformatting brings address to the front for disassembler agent's extracting - * the address for location marker to work. - * Moves symbol information to the 2nd column, using the source file lines as - * symbol until it encounters a C++ symbol (function entered), from which then on - * it uses that symbol, indicating the offset. - */ - -class DisassemblerOutputParser -{ - Q_DISABLE_COPY(DisassemblerOutputParser) -public: - explicit DisassemblerOutputParser(QTextStream &str, int addressFieldWidth = 0); - - void parse(const QStringList &l); - -private: - enum ParseResult { ParseOk, ParseIgnore, ParseFailed }; - ParseResult parseDisassembled(const QString &in); - - const int m_addressFieldWidth; - QTextStream &m_str; - QString m_sourceSymbol; - int m_sourceSymbolOffset; -}; - -DisassemblerOutputParser::DisassemblerOutputParser(QTextStream &str, int addressFieldWidth) : - m_addressFieldWidth(addressFieldWidth), - m_str(str), - m_sourceSymbolOffset(0) -{ -} - -DisassemblerOutputParser::ParseResult - DisassemblerOutputParser::parseDisassembled(const QString &in) -{ - // 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; - - const QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts); - const int tokenCount = tokens.size(); - // Check for symbols as 'module!class::foo:' (start of function encountered) - // and store as state. - if (tokenCount == 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 (tokenCount < 2) - return ParseIgnore; - if (tokenCount < 3) - return ParseFailed; - // Format line. Start with address which is important for setting the marker. - // Fix CDB word separator for location marker hex conversion to work. - const int addressTokenPos = hasSourceFile ? 2 : 0; - QString addressToken = tokens.at(addressTokenPos); - if (addressToken.size() > 9 && addressToken.at(8) == QLatin1Char('`')) - addressToken.remove(8, 1); - m_str << addressToken << ' '; - // Symbol display: Do we know a symbol? -> Display with offset. - // Else default to source file information. - if (m_sourceSymbol.isEmpty()) { - if (hasSourceFile) - m_str << tokens.at(1) << '+' << tokens.front(); - } else { - m_str << '<' << m_sourceSymbol; - if (m_sourceSymbolOffset) - m_str << '+' << m_sourceSymbolOffset; - m_str << '>'; - m_sourceSymbolOffset++; - } - for (int i = addressTokenPos + 1; i < tokenCount; i++) - m_str << ' ' << tokens.at(i); - m_str << '\n'; - return ParseOk; -} - -void DisassemblerOutputParser::parse(const QStringList &l) -{ - foreach(const QString &line, l) { - switch (parseDisassembled(line)) { - case ParseOk: - case ParseIgnore: - break; - case ParseFailed: - qWarning("Failed to parse '%s'\n", qPrintable(line)); - break; - } - } -} - -bool disassemble(CdbCore::CoreEngine *engine, - ULONG64 offset, - unsigned long beforeLines, - unsigned long afterLines, - QTextStream &str, - QString *errorMessage) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << offset; - QString lines; - if (!engine->disassemble(offset, beforeLines, afterLines, &lines, errorMessage)) - return false; - DisassemblerOutputParser parser(str); - parser.parse(lines.split(QLatin1Char('\n'))); - return true; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbassembler.h b/src/plugins/debugger/cdb/cdbassembler.h deleted file mode 100644 index 2e8ee5db419780dd3ecb167f9631f3cd4d0a8c23..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbassembler.h +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBASSEMBLER_H -#define CDBASSEMBLER_H - -#include <QtCore/QList> -#include <QtCore/QString> - -#include "cdbcom.h" -#include "registerhandler.h" - -QT_BEGIN_NAMESPACE -class QTextStream; -QT_END_NAMESPACE - -namespace CdbCore { - class CoreEngine; -} - -namespace Debugger { -namespace Internal { - -// Utilities related to assembler code. - -Registers getRegisters(CIDebugControl *ctl, - CIDebugRegisters *ireg, - QString *errorMessage, - int base = 10 /* 16 for hex, etc */); - -bool setRegisterValueU64(CIDebugRegisters *ireg, unsigned index, quint64 value, - QString *errorMessage); - -bool setRegisterValueU64(CIDebugControl *ctl, CIDebugRegisters *ireg, const QString &name, - quint64 value, QString *errorMessage); - -bool disassemble(CdbCore::CoreEngine *engine, - ULONG64 offset, - unsigned long beforeLines, - unsigned long afterLines, - QTextStream &str, - QString *errorMessage); - -} // namespace Internal -} // namespace Debugger - -#endif // CDBASSEMBLER_H diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp deleted file mode 100644 index fbf6518a1331ff51d3de463a849bd4cdf89f1104..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbbreakpoint.h" -#include "cdbengine_p.h" -#include "corebreakpoint.h" -#include "cdbmodules.h" -#include "breakhandler.h" -#include "shared/dbgwinutils.h" - -#include <QtCore/QDebug> -#include <QtCore/QDir> - -namespace Debugger { -namespace Internal { - -// Convert breakpoint structs -static CdbCore::BreakPoint breakPointFromBreakPointData(const BreakpointParameters &bpd, const QString &functionName) -{ - CdbCore::BreakPoint rc; - rc.type = bpd.type == Watchpoint ? - CdbCore::BreakPoint::Data : - CdbCore::BreakPoint::Code ; - - rc.address = bpd.address; - rc.threadId = bpd.threadSpec; - rc.fileName = QDir::toNativeSeparators(bpd.fileName); - rc.condition = bpd.condition; - rc.funcName = functionName.isEmpty() ? bpd.functionName : functionName; - rc.ignoreCount = bpd.ignoreCount; - rc.lineNumber = bpd.lineNumber; - rc.oneShot = false; - rc.enabled = bpd.enabled; - return rc; -} - -static inline QString msgCannotSetBreakAtFunction(const QString &func, const QString &why) -{ - return QString::fromLatin1("Cannot set a breakpoint at '%1': %2").arg(func, why); -} - -bool addCdbBreakpoint(CIDebugControl* debugControl, - CIDebugSymbols *syms, - const BreakpointParameters &bpIn, - BreakpointResponse *response, - QString *errorMessage) -{ - const BreakpointParameters bp = fixWinMSVCBreakpoint(bpIn); - errorMessage->clear(); - // Function breakpoints: Are the module names specified? - QString resolvedFunction; - if (bp.type == BreakpointByFunction) { - resolvedFunction = bp.functionName; - switch (resolveSymbol(syms, &resolvedFunction, errorMessage)) { - case ResolveSymbolOk: - break; - case ResolveSymbolAmbiguous: - break; - case ResolveSymbolNotFound: - case ResolveSymbolError: - *errorMessage = msgCannotSetBreakAtFunction(bp.functionName, *errorMessage); - return false; - } - if (debugBreakpoints) - qDebug() << bp.functionName << " resolved to " << resolvedFunction; - } // function breakpoint - // Now add... - quint64 address; - unsigned long id; - const CdbCore::BreakPoint ncdbbp = breakPointFromBreakPointData(bp, resolvedFunction); - if (!ncdbbp.add(debugControl, errorMessage, &id, &address)) - return false; - if (debugBreakpoints) - qDebug("Added %lu at 0x%lx %s", id, address, qPrintable(ncdbbp.toString())); - - response->fromParameters(bp); - response->number = id; - response->address = address; - response->functionName = resolvedFunction; - return true; -} - -// Delete all breakpoints -bool deleteCdbBreakpoints(CIDebugControl* debugControl, - QString *errorMessage) -{ - errorMessage->clear(); - // Do an initial check whether we are in a state that allows - // for modifying breakPoints - ULONG engineCount; - if (!CdbCore::BreakPoint::getBreakPointCount(debugControl, &engineCount, errorMessage)) { - *errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage); - return false; - } - if (debugBreakpoints) - qDebug("Deleting breakpoints 0..%lu", engineCount); - - if (engineCount) { - for (int b = engineCount - 1; b >= 0 ; b--) - if (!CdbCore::BreakPoint::removeBreakPointById(debugControl, b, errorMessage)) - return false; - } - return true; -} - -void debugCdbBreakpoints(CIDebugControl* debugControl) -{ - QString errorMessage; - QList<CdbCore::BreakPoint> bps; - CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, &errorMessage); - QDebug nsp = qDebug().nospace(); - const int count = bps.size(); - nsp <<"### Breakpoints in engine: " << count << '\n'; - for (int i = 0; i < count; i++) - nsp << " #" << i << ' ' << bps.at(i) << '\n'; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h deleted file mode 100644 index fc8aba3ac6609af3053e32d33c7fe6c078fb9b15..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbbreakpoint.h +++ /dev/null @@ -1,64 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBBREAKPOINTS_H -#define CDBBREAKPOINTS_H - -#include "cdbcom.h" - -#include <QtCore/QString> - -QT_BEGIN_NAMESPACE -class QDebug; -QT_END_NAMESPACE - -namespace Debugger { -namespace Internal { -class BreakpointParameters; -class BreakpointResponse; - -// Convert breakpoint structs -bool addCdbBreakpoint(CIDebugControl* debugControl, - CIDebugSymbols *syms, - const BreakpointParameters &bp, - BreakpointResponse *response, - QString *errorMessage); - -bool deleteCdbBreakpoints(CIDebugControl* debugControl, QString *errorMessage); - -void debugCdbBreakpoints(CIDebugControl* debugControl); - -} // namespace Internal -} // namespace Debugger - -#endif // CDBBREAKPOINTS_H diff --git a/src/plugins/debugger/cdb/cdbcom.h b/src/plugins/debugger/cdb/cdbcom.h deleted file mode 100644 index 1d951ee13c39ed25d902b1012ed63af30a017445..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbcom.h +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBCOM_H -#define CDBCOM_H - -#include <QtCore/QtGlobal> - -#ifdef Q_OS_WIN - -#include <windows.h> -#include <inc/dbgeng.h> - -// typedef out the version numbers -typedef IDebugClient5 CIDebugClient; -typedef IDebugControl4 CIDebugControl; -typedef IDebugSystemObjects4 CIDebugSystemObjects; -typedef IDebugSymbols3 CIDebugSymbols; -typedef IDebugRegisters2 CIDebugRegisters; -typedef IDebugDataSpaces4 CIDebugDataSpaces; - -typedef IDebugSymbolGroup2 CIDebugSymbolGroup; -typedef IDebugBreakpoint2 CIDebugBreakpoint; -typedef IDebugAdvanced2 CIDebugAdvanced; - -#else - -#include "cdbcomstub.h" - -#endif // Q_OS_WIN - -#endif // CDBCOM_H diff --git a/src/plugins/debugger/cdb/cdbcomstub.h b/src/plugins/debugger/cdb/cdbcomstub.h deleted file mode 100644 index 571fb3a410ee3b879c9b85cc1fa6a346f9bee6cb..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbcomstub.h +++ /dev/null @@ -1,137 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBCOMSTUB_H -#define CDBCOMSTUB_H - -// Stubs to make it partially compile for test purposes on non-Windows. - -// FIXME: Make everything more Windows-like instead of choosing arbitrary -// values to make it compile. - -typedef unsigned long ULONG; -typedef unsigned long long ULONG64; -typedef void *PVOID; -typedef unsigned short *PCWSTR; -typedef void *HANDLE; -typedef int HRESULT; -typedef int DEBUG_VALUE; -typedef int PDEBUG_BREAKPOINT2; -const int MAX_PATH = 1024; - -inline bool FAILED(HRESULT) { return false; } - -enum -{ - DEBUG_OUTPUT_PROMPT_REGISTERS = 1, - DEBUG_OUTPUT_EXTENSION_WARNING = 2, - DEBUG_OUTPUT_WARNING = 4, - DEBUG_OUTPUT_ERROR = 8, - DEBUG_OUTPUT_DEBUGGEE = 16, - DEBUG_OUTPUT_DEBUGGEE_PROMPT = 32, - DEBUG_OUTPUT_PROMPT = 64, -}; - -#define IN -#define OUT -#define THIS -#define THIS_ -#define REFIID void * -#define THIS_ -#define STDMETHOD(x) HRESULT x -#define STDMETHOD_(x, y) x y - -struct IUnknown -{ - virtual ~IUnknown(); - virtual STDMETHOD_(ULONG, AddRef)(THIS) { return 1; } - virtual STDMETHOD_(ULONG, Release)(THIS) { return 1; } -}; - -struct IDebugOutputCallbacksWide : IUnknown -{ -}; - -struct CIDebugClient : IUnknown -{ -}; - -struct CIDebugControl : IUnknown -{ -}; - -struct CIDebugSystemObjects : IUnknown -{ -}; - -struct CIDebugSymbols : IUnknown -{ -}; - -struct CIDebugRegisters : IUnknown -{ - HRESULT GetNumberRegisters(ULONG *) const { return 0; } - HRESULT GetDescription(ULONG, char *, int, int, int) const { return 0; } - HRESULT GetValues(ULONG, int, int, DEBUG_VALUE *) const { return 0; } -}; - -struct CIDebugDataSpaces : IUnknown -{ -}; - -struct CIDebugSymbolGroup : IUnknown -{ -}; - -struct CIDebugBreakpoint : IUnknown -{ -}; - -enum DebugSymbolFlags -{ - DEBUG_SYMBOL_IS_LOCAL = 1, - DEBUG_SYMBOL_IS_ARGUMENT = 2, - DEBUG_SYMBOL_READ_ONLY = 4 -}; - -struct DEBUG_SYMBOL_PARAMETERS -{ - DebugSymbolFlags Flags; - unsigned long ParentSymbol; -}; - -struct DEBUG_STACK_FRAME -{ -}; - -#endif // Q_OS_WIN diff --git a/src/plugins/debugger/cdb/cdbcore.pri b/src/plugins/debugger/cdb/cdbcore.pri deleted file mode 100644 index c1439de63dcdf3353360ed7b5abdd66a5bdfc1a6..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbcore.pri +++ /dev/null @@ -1,54 +0,0 @@ -# Detect presence of "Debugging Tools For Windows" -# in case VS compilers are used. - -# FIXME -CDB_PATH="" -win32 { -contains(QMAKE_CXX, cl) { - -CDB_PATH="$$(CDB_PATH)" -isEmpty(CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk" - -!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk" -!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x64)/sdk" -!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows 64-bit/sdk" - -exists($$CDB_PATH) { - -message("Adding support for $$CDB_PATH") - -DEFINES+=CDB_ENABLED - -CDB_PLATFORM=i386 - -INCLUDEPATH*=$$CDB_PATH -CDB_LIBPATH=$$CDB_PATH/lib/$$CDB_PLATFORM - -HEADERS += \ - $$PWD/cdbcom.h \ - $$PWD/coreengine.h \ - $$PWD/debugoutputbase.h \ - $$PWD/debugeventcallbackbase.h \ - $$PWD/symbolgroupcontext.h \ - $$PWD/stacktracecontext.h \ - $$PWD/corebreakpoint.h - -SOURCES += \ - $$PWD/coreengine.cpp \ - $$PWD/debugoutputbase.cpp \ - $$PWD/debugeventcallbackbase.cpp \ - $$PWD/symbolgroupcontext.cpp \ - $$PWD/stacktracecontext.cpp \ - $$PWD/corebreakpoint.cpp - -INCLUDEPATH*=$$PWD -DEPENDPATH*=$$PWD - -LIBS+=-lpsapi - -} else { - message("Debugging Tools for Windows could not be found in $$CDB_PATH") - CDB_PATH="" -} # exists($$CDB_PATH) -} # (QMAKE_CXX, cl) -} # win32 diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp deleted file mode 100644 index 82ea855440f7d93534174d697400cb1cf3b9255b..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbdebugeventcallback.h" -#include "cdbengine.h" -#include "cdbexceptionutils.h" -#include "cdbengine_p.h" -#include "dbgwinutils.h" - -#include <QtCore/QDebug> -#include <QtCore/QTextStream> -#include <QtCore/QCoreApplication> - -namespace Debugger { -namespace Internal { - -// ---------- CdbDebugEventCallback - -CdbDebugEventCallback::CdbDebugEventCallback(CdbEngine *dbg) : - m_pEngine(dbg) -{ -} - -STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask) -{ - *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS - | DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD - | DEBUG_EVENT_BREAKPOINT - | DEBUG_EVENT_EXCEPTION | baseInterestMask(); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2 Bp) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO; - m_pEngine->m_d->handleBreakpointEvent(Bp); - return S_OK; -} - - -STDMETHODIMP CdbDebugEventCallback::Exception( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG /* FirstChance */ - ) -{ - QString msg; - { - QTextStream str(&msg); - formatException(Exception, &m_pEngine->m_d->interfaces(), str); - } - const bool fatal = isFatalWinException(Exception->ExceptionCode); - if (debugCDB) - qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg; - m_pEngine->showMessage(msg, AppError); - m_pEngine->showMessage(msg, LogMisc); - m_pEngine->m_d->notifyException(Exception->ExceptionCode, fatal, msg); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::CreateThread( - THIS_ - __in ULONG64 Handle, - __in ULONG64 DataOffset, - __in ULONG64 StartOffset - ) -{ - Q_UNUSED(Handle) - Q_UNUSED(DataOffset) - Q_UNUSED(StartOffset) - if (debugCDB) - qDebug() << Q_FUNC_INFO; - m_pEngine->m_d->updateThreadList(); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::ExitThread( - THIS_ - __in ULONG ExitCode - ) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << ExitCode; - // @TODO: It seems the terminated thread is still in the list... - m_pEngine->m_d->updateThreadList(); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::CreateProcess( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 Handle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp, - __in ULONG64 InitialThreadHandle, - __in ULONG64 ThreadDataOffset, - __in ULONG64 StartOffset - ) -{ - Q_UNUSED(ImageFileHandle) - Q_UNUSED(BaseOffset) - Q_UNUSED(ModuleSize) - Q_UNUSED(ModuleName) - Q_UNUSED(ImageName) - Q_UNUSED(CheckSum) - Q_UNUSED(TimeDateStamp) - Q_UNUSED(ThreadDataOffset) - Q_UNUSED(StartOffset) - if (debugCDB) - qDebug() << Q_FUNC_INFO << ModuleName; - m_pEngine->m_d->processCreatedAttached(Handle, InitialThreadHandle); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::ExitProcess( - THIS_ - __in ULONG ExitCode - ) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << ExitCode; - m_pEngine->processTerminated(ExitCode); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::LoadModule( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp - ) -{ - Q_UNUSED(ImageFileHandle) - Q_UNUSED(BaseOffset) - Q_UNUSED(ModuleSize) - Q_UNUSED(ImageName) - Q_UNUSED(CheckSum) - Q_UNUSED(TimeDateStamp) - if (debugCDB > 1) - qDebug() << Q_FUNC_INFO << ModuleName; - handleModuleLoad(); - m_pEngine->m_d->handleModuleLoad(BaseOffset, QString::fromUtf16(reinterpret_cast<const ushort *>(ModuleName))); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::UnloadModule( - THIS_ - __in_opt PCWSTR ImageBaseName, - __in ULONG64 BaseOffset - ) -{ - Q_UNUSED(BaseOffset) - if (debugCDB > 1) - qDebug() << Q_FUNC_INFO << ImageBaseName; - if (!ImageBaseName) - return S_OK; - m_pEngine->m_d->handleModuleUnload(QString::fromUtf16(reinterpret_cast<const ushort *>(ImageBaseName))); - handleModuleUnload(); - m_pEngine->m_d->updateModules(); - return S_OK; -} - -STDMETHODIMP CdbDebugEventCallback::SystemError( - THIS_ - __in ULONG Error, - __in ULONG Level - ) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << Error << Level; - return S_OK; -} - -// -----------ExceptionLoggerEventCallback -CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, - bool skipNonFatalExceptions, CdbEngine *engine) : - m_logChannel(logChannel), - m_skipNonFatalExceptions(skipNonFatalExceptions), - m_engine(engine) -{ -} - -STDMETHODIMP CdbExceptionLoggerEventCallback::GetInterestMask(THIS_ __out PULONG mask) -{ - *mask = DEBUG_EVENT_EXCEPTION | baseInterestMask(); - return S_OK; -} - -STDMETHODIMP CdbExceptionLoggerEventCallback::Exception( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG /* FirstChance */ - ) -{ - const bool recordException = !m_skipNonFatalExceptions || isFatalWinException(Exception->ExceptionCode); - QString msg; - formatException(Exception, QTextStream(&msg)); - if (recordException) { - m_exceptionCodes.push_back(Exception->ExceptionCode); - m_exceptionMessages.push_back(msg); - } - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << msg; - m_engine->showMessage(msg, m_logChannel); - if (recordException) - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - return S_OK; -} - -// -----------IgnoreDebugEventCallback -IgnoreDebugEventCallback::IgnoreDebugEventCallback() -{ -} - -STDMETHODIMP IgnoreDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask) -{ - *mask = 0; - return S_OK; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h deleted file mode 100644 index 5ba270732b4472a2e0ccc863206196ec331fa7ba..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h +++ /dev/null @@ -1,174 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGGER_CDBDEBUGEVENTCALLBACK_H -#define DEBUGGER_CDBDEBUGEVENTCALLBACK_H - -#include "debugeventcallbackbase.h" - -#include <QtCore/QStringList> - -namespace Debugger { -namespace Internal { - -class CdbEngine; - -class CdbDebugEventCallback : public CdbCore::DebugEventCallbackBase -{ -public: - explicit CdbDebugEventCallback(CdbEngine* dbg); - - // IDebugEventCallbacks. - - STDMETHOD(GetInterestMask)( - THIS_ - __out PULONG mask - ); - - STDMETHOD(Breakpoint)( - THIS_ - __in PDEBUG_BREAKPOINT2 Bp - ); - - STDMETHOD(Exception)( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG FirstChance - ); - - STDMETHOD(CreateThread)( - THIS_ - __in ULONG64 Handle, - __in ULONG64 DataOffset, - __in ULONG64 StartOffset - ); - STDMETHOD(ExitThread)( - THIS_ - __in ULONG ExitCode - ); - - STDMETHOD(CreateProcess)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 Handle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp, - __in ULONG64 InitialThreadHandle, - __in ULONG64 ThreadDataOffset, - __in ULONG64 StartOffset - ); - - STDMETHOD(ExitProcess)( - THIS_ - __in ULONG ExitCode - ); - - STDMETHOD(LoadModule)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp - ); - - STDMETHOD(UnloadModule)( - THIS_ - __in_opt PCWSTR ImageBaseName, - __in ULONG64 BaseOffset - ); - - STDMETHOD(SystemError)( - THIS_ - __in ULONG Error, - __in ULONG Level - ); - -private: - CdbEngine *m_pEngine; -}; - -// Event handler logs exceptions to the debugger window -// and ignores the rest. To be used for running dumper calls. -class CdbExceptionLoggerEventCallback : public CdbCore::DebugEventCallbackBase -{ -public: - CdbExceptionLoggerEventCallback(int logChannel, - bool skipNonFatalExceptions, - CdbEngine *engine); - - STDMETHOD(GetInterestMask)( - THIS_ - __out PULONG mask - ); - - STDMETHOD(Exception)( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG FirstChance - ); - - int exceptionCount() const { return m_exceptionMessages.size(); } - QStringList exceptionMessages() const { return m_exceptionMessages; } - QList<ULONG> exceptionCodes() const { return m_exceptionCodes; } - -private: - const int m_logChannel; - const bool m_skipNonFatalExceptions; - CdbEngine *m_engine; - QList<ULONG> m_exceptionCodes; - QStringList m_exceptionMessages; -}; - -// Event handler that ignores everything -class IgnoreDebugEventCallback : public CdbCore::DebugEventCallbackBase -{ -public: - explicit IgnoreDebugEventCallback(); - - STDMETHOD(GetInterestMask)( - THIS_ - __out PULONG mask - ); -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_CDBDEBUGEVENTCALLBACK_H diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.cpp b/src/plugins/debugger/cdb/cdbdebugoutput.cpp deleted file mode 100644 index 9c6c392d53c907873bc5ed19b7c9628ed6cdfb91..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdebugoutput.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbdebugoutput.h" -#include "debuggerrunner.h" -#include "cdbengine_p.h" -#include "cdbcom.h" - -#include <QtCore/QDebug> - -namespace Debugger { -namespace Internal { - -// ------------------------- CdbDebugOutput - -// Return a prefix for debugger messages -static int logChannel(ULONG mask) -{ - if (mask & (DEBUG_OUTPUT_PROMPT_REGISTERS)) - return LogMisc; - if (mask & (DEBUG_OUTPUT_EXTENSION_WARNING|DEBUG_OUTPUT_WARNING)) - return LogWarning; - if (mask & (DEBUG_OUTPUT_ERROR)) - return LogError; - if (mask & DEBUG_OUTPUT_DEBUGGEE) - //return DebuggeeOutput; - return AppOutput; - if (mask & DEBUG_OUTPUT_DEBUGGEE_PROMPT) - //return DebuggeePromptOutput; - return AppError; - if (mask & DEBUG_OUTPUT_PROMPT) - //return DebuggerPromptOutput; - return AppError; - return LogMisc; -} - -CdbDebugOutput::CdbDebugOutput() -{ -} - -void CdbDebugOutput::output(ULONG mask, const QString &msg) -{ - if (debugCDB > 1) - qDebug() << Q_FUNC_INFO << "\n " << msg; - emit showMessage(msg, logChannel(mask), -1); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.h b/src/plugins/debugger/cdb/cdbdebugoutput.h deleted file mode 100644 index 2f8d39375b22e85a5560fff85e22c872036f17f2..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdebugoutput.h +++ /dev/null @@ -1,61 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGGER_CDBOUTPUT_H -#define DEBUGGER_CDBOUTPUT_H - -#include "debugoutputbase.h" - -#include <QtCore/QObject> - -namespace Debugger { -namespace Internal { - -// Standard CDB output handler -class CdbDebugOutput : public QObject, public CdbCore::DebugOutputBase -{ - Q_OBJECT -public: - CdbDebugOutput(); - -signals: - void showMessage(const QString &output, int channel, int timeout); - -protected: - virtual void output(ULONG mask, const QString &message); -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_CDBOUTPUT_H diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp deleted file mode 100644 index eb8e0e51a1e616c0cbc71e2e6f6c202c30897dc3..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ /dev/null @@ -1,801 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbdumperhelper.h" -#include "cdbmodules.h" -#include "cdbengine.h" -#include "cdbengine_p.h" -#include "cdbdebugoutput.h" -#include "cdbdebugeventcallback.h" -#include "cdbsymbolgroupcontext.h" -#include "watchhandler.h" -#include "cdbexceptionutils.h" - -#include "shared/sharedlibraryinjector.h" - -#include <QtCore/QRegExp> -#include <QtCore/QCoreApplication> -#include <QtCore/QTextStream> -#include <QtCore/QTime> -#include <QtCore/QThread> -#include <QtCore/QEventLoop> -#include <QtGui/QApplication> - -enum { loadDebug = 0 }; -enum { dumpDebug = 0 }; - -static const char *dumperModuleNameC = "gdbmacros"; -static const char *qtCoreModuleNameC = "QtCore"; -static const ULONG waitTimeOutMS = 30000; -static const char *dumperPrefixC = "dumper:"; - -/* Loading the dumpers is 2 step process: - * 1) The library must be loaded into the debuggee, for which there are - * 2 approaches: - * - Injection loading using the SharedLibraryInjector which - * launches a remote thread in the debuggee which loads the - * library. Drawbacks: - * * The remote thread must not starve. - * * It is not possible to wait loading and loading occurs late, - * after entering main() - * - Debugger Call loading, which has the debuggee execute - * a LoadLibrary call via debugger commands. Drawbacks: - * * Slow - * * Requires presence of a symbol of the same prototype as - * LoadLibraryA as the original prototype is not sufficient. - * 2) Call a query function (protocol 1 of the dumper) to obtain a list - * of handled types and a map of known sizes. - * - * The class currently launches injection loading from the module - * load hook as soon as it sees a Qt module. - * The dumpType() function performs the rest of the [delayed] initialization. - * If the load has not finished, it attempts call loading and - * executes the initial query protocol. - * - * Note: The main technique here is having the debuggee call functions - * using the .call command (which takes a function with a known - * prototype and simple, integer parameters). - * This does not work from an IDebugEvent callback, as it will cause - * WaitForEvent() to fail with unknown errors. - * It mostly works from breakpoints, with the addditional restriction - * that complex functions only work from 'well-defined' breakpoints - * (such as main()) and otherwise cause access violation exceptions - * (for example LoadLibrary). - * Exceptions occurring in the functions to be called must be handled - * by __try/__except (they show up in the debugger and must acknowledged - * by gN (go not handled). */ - -namespace Debugger { -namespace Internal { - -// ------- Call load helpers - - // Load a library into the debuggee. Currently requires -// the QtCored4.pdb file to be present as we need "qstrdup" -// as dummy symbol. This is ok ATM since dumpers only -// make sense for Qt apps. -static bool debuggeeLoadLibrary(CdbEngine *cdbEngine, - CdbCore::CoreEngine *engine, - unsigned long threadId, - const QString &moduleName, - QString *errorMessage) -{ - if (loadDebug > 1) - qDebug() << Q_FUNC_INFO << moduleName; - // Try to ignore the breakpoints, skip stray startup-complete trap exceptions - QSharedPointer<CdbExceptionLoggerEventCallback> - exLogger(new CdbExceptionLoggerEventCallback(LogWarning, true, cdbEngine)); - CdbCore::EventCallbackRedirector eventRedir(engine, exLogger); - Q_UNUSED(eventRedir) - // Make a call to LoadLibraryA. First, reserve memory in debugger - // and copy name over. - ULONG64 nameAddress; - if (!engine->createDebuggeeAscIIString(moduleName, &nameAddress, errorMessage)) - return false; - // We want to call "HMODULE LoadLibraryA(LPCTSTR lpFileName)" - // (void* LoadLibraryA(char*)). However, despite providing a symbol - // server, the debugger refuses to recognize it as a function. - // Call with a prototype of 'qstrdup', as it is the same - // Prepare call: Locate 'qstrdup' in the (potentially namespaced) corelib. For some - // reason, the symbol is present in QtGui as well without type information. - QString dummyFunc = QLatin1String("*qstrdup"); - if (resolveSymbol(engine->interfaces().debugSymbols, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk) - return false; - - QString callCmd; { - QTextStream str(&callCmd); - str.setIntegerBase(16); - str << ".call /s " << dummyFunc << " Kernel32!LoadLibraryA(0x" << nameAddress << ')'; - } - if (loadDebug) - qDebug() << "Calling" << callCmd; - - if (!engine->executeDebuggerCommand(callCmd, errorMessage)) - return false; - // Execute current thread. This will hit a breakpoint. - QString goCmd; - QTextStream(&goCmd) << '~' << threadId << " g"; - if (!engine->executeDebuggerCommand(goCmd, errorMessage)) - return false; - const HRESULT hr = engine->waitForEvent(waitTimeOutMS); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("WaitForEvent", hr); - return false; - } - return true; -} - -// Format a "go" in a thread -static inline QString goCommand(unsigned long threadId) -{ - QString rc; - QTextStream(&rc) << '~' << threadId << " g"; - return rc; -} - -// ---- Load messages -static inline QString msgMethod(bool injectOrCall) -{ - return injectOrCall ? - QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "injection") : - QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "debugger call"); -} - -static QString msgLoading(const QString &library, bool injectOrCall) -{ - return QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", - "Loading the custom dumper library '%1' (%2) ..."). - arg(library, msgMethod(injectOrCall)); -} - -static QString msgLoadFailed(const QString &library, bool injectOrCall, const QString &why) -{ - return QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", - "Loading of the custom dumper library '%1' (%2) failed: %3"). - arg(library, msgMethod(injectOrCall), why); -} - -static QString msgLoadSucceeded(const QString &library, bool injectOrCall) -{ - return QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", - "Loaded the custom dumper library '%1' (%2)."). - arg(library, msgMethod(injectOrCall)); -} - -// Dumper initialization as a background thread. -// Befriends CdbDumperHelper and calls its methods -class CdbDumperInitThread : public QThread { - Q_OBJECT -public: - static inline bool ensureDumperInitialized(CdbDumperHelper &h, QString *errorMessage); - - virtual void run(); - -signals: - void logMessage(const QString &m, int channel); - void statusMessage(const QString &m, int timeOut); - -private: - explicit CdbDumperInitThread(CdbDumperHelper &h, QString *errorMessage); - - CdbDumperHelper &m_helper; - bool m_ok; - QString *m_errorMessage; -}; - -CdbDumperInitThread::CdbDumperInitThread(CdbDumperHelper &h, QString *errorMessage) : - m_helper(h), - m_ok(false), - m_errorMessage(errorMessage) -{ -} - -bool CdbDumperInitThread::ensureDumperInitialized(CdbDumperHelper &h, QString *errorMessage) -{ - // Quick state check - switch (h.state()) { - case CdbDumperHelper::Disabled: - *errorMessage = QLatin1String("Internal error, attempt to call disabled dumper"); - return false; - case CdbDumperHelper::Initialized: - return true; - default: - break; - } - // Need a thread to do initialization work. Typically - // takes several seconds depending on debuggee size. - QApplication::setOverrideCursor(Qt::BusyCursor); - CdbDumperInitThread thread(h, errorMessage); - connect(&thread, SIGNAL(statusMessage(QString,int)), - h.m_engine, SLOT(showStatusMessage(QString,int)), - Qt::QueuedConnection); - connect(&thread, SIGNAL(logMessage(QString,int)), - h.m_engine, SLOT(showMessage(QString,int)), - Qt::QueuedConnection); - QEventLoop eventLoop; - connect(&thread, SIGNAL(finished()), &eventLoop, SLOT(quit()), Qt::QueuedConnection); - thread.start(); - if (thread.isRunning()) - eventLoop.exec(QEventLoop::ExcludeUserInputEvents); - QApplication::restoreOverrideCursor(); - if (thread.m_ok) { - h.m_engine->showStatusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Stopped / Custom dumper library initialized."), messageTimeOut); - h.m_engine->showMessage(h.m_helper.toString()); - h.m_state = CdbDumperHelper::Initialized; - } else { - h.m_state = CdbDumperHelper::Disabled; // No message here - *errorMessage = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage); - h.m_engine->showStatusMessage(*errorMessage, messageTimeOut); - h.m_engine->showQtDumperLibraryWarning(*errorMessage); - } - if (loadDebug) - qDebug() << Q_FUNC_INFO << '\n' << thread.m_ok; - return thread.m_ok; -} - -void CdbDumperInitThread ::run() -{ - switch (m_helper.state()) { - // Injection load failed or disabled: Try a call load. - case CdbDumperHelper::NotLoaded: - case CdbDumperHelper::InjectLoading: - case CdbDumperHelper::InjectLoadFailed: - // Also shows up in the log window. - emit statusMessage(msgLoading(m_helper.m_library, false), -1); - switch (m_helper.initCallLoad(m_errorMessage)) { - case CdbDumperHelper::CallLoadOk: - case CdbDumperHelper::CallLoadAlreadyLoaded: - emit logMessage(msgLoadSucceeded(m_helper.m_library, false), LogMisc); - m_helper.m_state = CdbDumperHelper::Loaded; - break; - case CdbDumperHelper::CallLoadError: - *m_errorMessage = msgLoadFailed(m_helper.m_library, false, *m_errorMessage); - m_ok = false; - return; - case CdbDumperHelper::CallLoadNoQtApp: - emit logMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The debuggee does not appear to be Qt application."), LogMisc); - m_helper.m_state = CdbDumperHelper::Disabled; // No message here - m_ok = true; - return; - } - break; - case CdbDumperHelper::Loaded: // Injection load succeeded, ideally - break; - } - // Perform remaining initialization - emit statusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Initializing dumpers..."), 60000); - m_ok = m_helper.initResolveSymbols(m_errorMessage) && m_helper.initKnownTypes(m_errorMessage); -} - -// ------------------- CdbDumperHelper - -CdbDumperHelper::CdbDumperHelper(CdbEngine *engine, - CdbCore::CoreEngine *coreEngine) : - m_tryInjectLoad(true), - m_msgDisabled(QLatin1String("Dumpers are disabled")), - m_msgNotInScope(QLatin1String("Data not in scope")), - m_state(NotLoaded), - m_engine(engine), - m_coreEngine(coreEngine), - m_inBufferAddress(0), - m_inBufferSize(0), - m_outBufferAddress(0), - m_outBufferSize(0), - m_buffer(0), - m_dumperCallThread(0), - m_goCommand(goCommand(m_dumperCallThread)), - m_fastSymbolResolution(true) -{ -} - -CdbDumperHelper::~CdbDumperHelper() -{ - clearBuffer(); -} - -void CdbDumperHelper::disable() -{ - if (loadDebug) - qDebug() << Q_FUNC_INFO; - m_engine->showMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Disabling dumpers due to debuggee crash...")); - m_state = Disabled; -} - -void CdbDumperHelper::clearBuffer() -{ - if (m_buffer) { - delete [] m_buffer; - m_buffer = 0; - } -} - -void CdbDumperHelper::reset(const QString &library, bool enabled) -{ - if (loadDebug) - qDebug() << Q_FUNC_INFO << '\n' << library << enabled; - m_library = library; - m_state = enabled ? NotLoaded : Disabled; - m_dumpObjectSymbol = QLatin1String("qDumpObjectData440"); - m_helper.clear(); - m_inBufferAddress = m_outBufferAddress = 0; - m_inBufferSize = m_outBufferSize = 0; - m_failedTypes.clear(); - clearBuffer(); -} - -void CdbDumperHelper::moduleLoadHook(const QString &module, HANDLE debuggeeHandle) -{ - if (loadDebug > 1) - qDebug() << "moduleLoadHook" << module << m_state << debuggeeHandle; - switch (m_state) { - case Disabled: - case Initialized: - break; - case NotLoaded: - // Try an inject load as soon as a Qt lib is loaded. - // for the thread to finish as this would lock up. - if (m_tryInjectLoad && module.contains(QLatin1String("Qt"), Qt::CaseInsensitive)) { - // Also shows up in the log window. - m_engine->showMessage(msgLoading(m_library, true), StatusBar, messageTimeOut); - QString errorMessage; - SharedLibraryInjector sh(GetProcessId(debuggeeHandle)); - if (sh.remoteInject(m_library, false, &errorMessage)) { - m_state = InjectLoading; - } else { - m_state = InjectLoadFailed; - // Ok, try call loading... - m_engine->showMessage(msgLoadFailed(m_library, true, errorMessage)); - } - } - break; - case InjectLoading: - // check if gdbmacros.dll loaded - if (module.contains(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive)) { - m_state = Loaded; - m_engine->showMessage(msgLoadSucceeded(m_library, true)); - } - break; - } -} - -// Try to load dumpers by triggering calls using the debugger -CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMessage) -{ - if (loadDebug) - qDebug() << Q_FUNC_INFO; - // Do we have Qt and are we already loaded by accident? - QStringList modules; - if (!getModuleNameList(m_coreEngine->interfaces().debugSymbols, &modules, errorMessage)) - return CallLoadError; - // Are we already loaded by some accident? - if (!modules.filter(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive).isEmpty()) - return CallLoadAlreadyLoaded; - // Is that Qt application at all? - if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty()) - return CallLoadNoQtApp; - // Try to load - if (!debuggeeLoadLibrary(m_engine, m_coreEngine, m_dumperCallThread, m_library, errorMessage)) - return CallLoadError; - return CallLoadOk; -} - -// Retrieve address and optionally size of a symbol. -static inline bool getSymbolAddress(CIDebugSymbols *sg, - const QString &name, - quint64 *address, - ULONG *size /* = 0*/, - QString *errorMessage) -{ - // Get address - HRESULT hr = sg->GetOffsetByNameWide(reinterpret_cast<PCWSTR>(name.utf16()), address); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetOffsetByNameWide", hr); - return false; - } - // Get size. Even works for arrays - if (size) { - ULONG64 moduleAddress; - ULONG type; - hr = sg->GetOffsetTypeId(*address, &type, &moduleAddress); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetOffsetTypeId", hr); - return false; - } - hr = sg->GetTypeSize(moduleAddress, type, size); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetTypeSize", hr); - return false; - } - } // size desired - return true; -} - -bool CdbDumperHelper::initResolveSymbols(QString *errorMessage) -{ - // Resolve the symbols we need. - // There is a 'qDumpInBuffer' in QtCore as well. - if (loadDebug) - qDebug() << Q_FUNC_INFO; - const QString dumperModuleName = QLatin1String(dumperModuleNameC); - QString inBufferSymbol, outBufferSymbol; - bool rc; - if (m_fastSymbolResolution) { - // Symbols in the debugging helpers are never namespaced. - m_dumpObjectSymbol = dumperModuleName + QLatin1String("!qDumpObjectData440"); - inBufferSymbol = dumperModuleName + QLatin1String("!qDumpInBuffer"); - outBufferSymbol = dumperModuleName + QLatin1String("!qDumpOutBuffer"); - } else { - // Classical approach of loading the dumper symbols. Takes some time though. - m_dumpObjectSymbol = QLatin1String("*qDumpObjectData440"); - inBufferSymbol = QLatin1String("*qDumpInBuffer"); - outBufferSymbol = QLatin1String("*qDumpOutBuffer"); - - rc = resolveSymbol(m_coreEngine->interfaces().debugSymbols, &m_dumpObjectSymbol, errorMessage) == ResolveSymbolOk - && resolveSymbol(m_coreEngine->interfaces().debugSymbols, dumperModuleName, &inBufferSymbol, errorMessage) == ResolveSymbolOk - && resolveSymbol(m_coreEngine->interfaces().debugSymbols, dumperModuleName, &outBufferSymbol, errorMessage) == ResolveSymbolOk; - if (!rc) - return false; - } - // Determine buffer addresses, sizes and alloc buffer - rc = getSymbolAddress(m_coreEngine->interfaces().debugSymbols, inBufferSymbol, &m_inBufferAddress, &m_inBufferSize, errorMessage) - && getSymbolAddress(m_coreEngine->interfaces().debugSymbols, outBufferSymbol, &m_outBufferAddress, &m_outBufferSize, errorMessage); - if (!rc) - return false; - m_buffer = new char[qMax(m_inBufferSize, m_outBufferSize)]; - if (loadDebug) - qDebug().nospace() << Q_FUNC_INFO << '\n' << rc << m_dumpObjectSymbol - << " buffers at 0x" << QString::number(m_inBufferAddress, 16) << ',' - << m_inBufferSize << "; 0x" - << QString::number(m_outBufferAddress, 16) << ',' << m_outBufferSize << '\n'; - return true; -} - -// Call query protocol to retrieve known types and sizes -bool CdbDumperHelper::initKnownTypes(QString *errorMessage) -{ - if (loadDebug) - qDebug() << Q_FUNC_INFO; - const double dumperVersionRequired = 1.3; - QByteArray output; - QString callCmd; - QTextStream(&callCmd) << ".call " << m_dumpObjectSymbol << "(1,0,0,0,0,0,0,0)"; - const char *outData; - if (callDumper(callCmd, QByteArray(), &outData, false, errorMessage) != CallOk) { - return false; - } - if (!m_helper.parseQuery(outData)) { - *errorMessage = QString::fromLatin1("Unable to parse the dumper output: '%1'").arg(QString::fromAscii(output)); - } - if (m_helper.dumperVersion() < dumperVersionRequired) { - *errorMessage = QtDumperHelper::msgDumperOutdated(dumperVersionRequired, m_helper.dumperVersion()); - return false; - } - if (loadDebug || dumpDebug) - qDebug() << Q_FUNC_INFO << '\n' << m_helper.toString(true); - return true; -} - -CdbDumperHelper::CallResult - CdbDumperHelper::callDumper(const QString &callCmd, const QByteArray &inBuffer, const char **outDataPtr, - bool ignoreAccessViolation, QString *errorMessage) -{ - *outDataPtr = 0; - // Skip stray startup-complete trap exceptions. - QSharedPointer<CdbExceptionLoggerEventCallback> exLogger(new -CdbExceptionLoggerEventCallback(LogWarning, true, m_engine)); - CdbCore::EventCallbackRedirector eventRedir(m_coreEngine, exLogger); - Q_UNUSED(eventRedir) - // write input buffer - if (!inBuffer.isEmpty()) { - if (!m_coreEngine->writeToDebuggee(inBuffer, m_inBufferAddress, errorMessage)) - return CallFailed; - } - if (!m_coreEngine->executeDebuggerCommand(callCmd, errorMessage)) { - // Clear the outstanding call in case we triggered a debug library assert with a message box - QString clearError; - if (!m_coreEngine->executeDebuggerCommand(QLatin1String(".call /c"), &clearError)) { - *errorMessage += QString::fromLatin1("/Unable to clear call %1").arg(clearError); - } - return CallSyntaxError; - } - // Set up call and a temporary breakpoint after it. - // Try to skip debuggee crash exceptions and dumper exceptions - // by using 'gN' (go not handled -> pass handling to dumper __try/__catch block) - for (int i = 0; i < 10; i++) { - const int oldExceptionCount = exLogger->exceptionCount(); - // Go in current thread. If an exception occurs in loop 2, - // let the dumper handle it. - QString goCmd = m_goCommand; - if (i) - goCmd = QLatin1Char('N'); - if (!m_coreEngine->executeDebuggerCommand(goCmd, errorMessage)) - return CallFailed; - HRESULT hr = m_coreEngine->waitForEvent(waitTimeOutMS); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("WaitForEvent", hr); - return CallFailed; - } - const int newExceptionCount = exLogger->exceptionCount(); - // no new exceptions? -> break - if (oldExceptionCount == newExceptionCount) - break; - // If we are to ignore EXCEPTION_ACCESS_VIOLATION, check if anything - // else occurred. - if (ignoreAccessViolation) { - const QList<ULONG> newExceptionCodes = exLogger->exceptionCodes().mid(oldExceptionCount); - if (newExceptionCodes.count(EXCEPTION_ACCESS_VIOLATION) == newExceptionCodes.size()) - break; - } - } - if (exLogger->exceptionCount()) { - const QString exMsgs = exLogger->exceptionMessages().join(QString(QLatin1Char(','))); - *errorMessage = QString::fromLatin1("Exceptions occurred during the dumper call: %1").arg(exMsgs); - return CallFailed; - } - // Read output - const HRESULT hr = m_coreEngine->interfaces().debugDataSpaces->ReadVirtual(m_outBufferAddress, m_buffer, m_outBufferSize, 0); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("ReadVirtual", hr); - return CallFailed; - } - // see QDumper implementation - const char result = m_buffer[0]; - switch (result) { - case 't': - break; - case '+': - *errorMessage = QString::fromLatin1("Dumper call '%1' resulted in output overflow.").arg(callCmd); - return CallFailed; - case 'f': - *errorMessage = QString::fromLatin1("Dumper call '%1' failed.").arg(callCmd); - return CallFailed; - default: - *errorMessage = QString::fromLatin1("Dumper call '%1' failed ('%2').").arg(callCmd).arg(QLatin1Char(result)); - return CallFailed; - } - *outDataPtr = m_buffer + 1; - return CallOk; -} - -static inline QString msgDumpFailed(const WatchData &wd, const QString *why) -{ - return QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(QString::fromLatin1(wd.iname), wd.type, *why); -} - -static inline QString msgNotHandled(const QString &type) -{ - return QString::fromLatin1("The type '%1' is not handled.").arg(type); -} - -CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage) -{ - if (dumpDebug || debugCDBExecution) - qDebug() << ">dumpType() thread: " << m_dumperCallThread << " state: " << m_state - << wd.iname << wd.type << QTime::currentTime().toString(); - const CdbDumperHelper::DumpResult rc = dumpTypeI(wd, dumpChildren, result, errorMessage); - if (dumpDebug) - qDebug() << "<dumpType() state: " << m_state << wd.iname - << wd.type << " returns " << rc << *errorMessage << QTime::currentTime().toString(); - return rc; -} - -CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage) -{ - errorMessage->clear(); - // Check failure cache and supported types - if (m_state == Disabled) { - *errorMessage =m_msgDisabled; - return DumpNotHandled; - } - if (wd.error) { - *errorMessage =m_msgNotInScope; - return DumpNotHandled; - } - if (m_failedTypes.contains(wd.type)) { - *errorMessage = msgNotHandled(wd.type); - return DumpNotHandled; - } - if (wd.address == 0) { - *errorMessage = QString::fromLatin1("Address is missing for '%1' (%2).") - .arg(QString::fromUtf8(wd.exp)).arg(QString::fromUtf8(wd.type)); - return DumpNotHandled; - } - - // Do we have a thread - if (m_dumperCallThread == InvalidDumperCallThread) { - *errorMessage = QString::fromLatin1("No thread to call."); - if (loadDebug) - qDebug() << *errorMessage; - return DumpNotHandled; - } - - // Delay initialization as much as possible - if (isIntOrFloatType(wd.type)) { - *errorMessage = QString::fromLatin1("Unhandled POD: " ) + wd.type; - return DumpNotHandled; - } - - // Ensure types are parsed and known. - if (!CdbDumperInitThread::ensureDumperInitialized(*this, errorMessage)) { - *errorMessage = msgDumpFailed(wd, errorMessage); - m_engine->showMessage(*errorMessage, LogError); - return DumpError; - } - - // Known type? - const QtDumperHelper::TypeData td = m_helper.typeData(wd.type); - if (loadDebug) - qDebug() << "dumpType" << wd.type << td; - if (td.type == QtDumperHelper::UnknownType) { - *errorMessage = msgNotHandled(wd.type); - return DumpNotHandled; - } - - // Now evaluate - const QString message = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", - "Querying dumpers for '%1'/'%2' (%3)"). - arg(QString::fromLatin1(wd.iname), wd.exp, wd.type); - m_engine->showMessage(message); - - const DumpExecuteResult der = executeDump(wd, td, dumpChildren, result, errorMessage); - if (der == DumpExecuteOk) - return DumpOk; - if (der == CallSyntaxError) { - m_failedTypes.push_back(wd.type); - if (dumpDebug) - qDebug() << "Caching failing type/expression evaluation failed for " << wd.type; - } - // log error - *errorMessage = msgDumpFailed(wd, errorMessage); - m_engine->showMessage(*errorMessage, LogWarning); - return DumpError; -} - -CdbDumperHelper::DumpExecuteResult - CdbDumperHelper::executeDump(const WatchData &wd, - const QtDumperHelper::TypeData& td, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage) -{ - QByteArray inBuffer; - QList<QByteArray> extraParameters; - // Build parameter list. - m_helper.evaluationParameters(wd, td, QtDumperHelper::CdbDebugger, &inBuffer, &extraParameters); - QString callCmd; - QTextStream str(&callCmd); - str << ".call " << m_dumpObjectSymbol << "(2,0," << wd.hexAddress() << ',' << (dumpChildren ? 1 : 0); - foreach(const QByteArray &e, extraParameters) - str << ',' << QString::fromUtf8(e); - str << ')'; - if (dumpDebug) - qDebug() << "Query: " << wd.toString() << "\nwith: " << callCmd << '\n'; - const char *outputData; - // Completely ignore EXCEPTION_ACCESS_VIOLATION crashes in the dumpers. - ExceptionBlocker eb(m_coreEngine->interfaces().debugControl, EXCEPTION_ACCESS_VIOLATION, ExceptionBlocker::IgnoreException); - if (!eb) { - *errorMessage = eb.errorString(); - return DumpExecuteCallFailed; - } - switch (callDumper(callCmd, inBuffer, &outputData, true, errorMessage)) { - case CallFailed: - return DumpExecuteCallFailed; - case CallSyntaxError: - return DumpExpressionFailed; - case CallOk: - break; - } - if (!QtDumperHelper::parseValue(outputData, result)) { - *errorMessage = QLatin1String("Parsing of value query output failed."); - return DumpExecuteCallFailed; - } - return DumpExecuteOk; -} - -// Simplify some types for sizeof expressions -static void simplifySizeExpression(QByteArray *typeName) -{ - typeName->replace("std::basic_string<char,std::char_traits<char>,std::allocator<char>>", - "std::string"); -} - -bool CdbDumperHelper::getTypeSize(const QByteArray &typeNameIn, int *size, QString *errorMessage) -{ - if (loadDebug > 1) - qDebug() << Q_FUNC_INFO << typeNameIn; - // Look up cache - QByteArray typeName = typeNameIn; - simplifySizeExpression(&typeName); - // "std::" types sometimes only work without namespace. - // If it fails, try again with stripped namespace - *size = 0; - bool success = false; - do { - if (runTypeSizeQuery(typeName, size, errorMessage)) { - success = true; - break; - } - if (!typeName.contains("std::")) - break; - typeName.replace("std::", ""); - errorMessage->clear(); - if (!runTypeSizeQuery(typeName, size, errorMessage)) - break; - success = true; - } while (false); - // Cache in dumper helper - if (success) - m_helper.addSize(typeName, *size); - return success; -} - -bool CdbDumperHelper::runTypeSizeQuery - (const QByteArray &typeName, int *size, QString *errorMessage) -{ - // Retrieve by C++ expression. If we knew the module, we could make use - // of the TypeId query mechanism provided by the IDebugSymbolGroup. - DEBUG_VALUE sizeValue; - QByteArray expression = "sizeof(" + typeName + ')'; - if (!m_coreEngine->evaluateExpression(expression, &sizeValue, errorMessage)) - return false; - qint64 size64; - if (!CdbCore::debugValueToInteger(sizeValue, &size64)) { - *errorMessage = QLatin1String("Expression result is not an integer"); - return false; - } - *size = static_cast<int>(size64); - return true; -} - -unsigned long CdbDumperHelper::dumperCallThread() -{ - return m_dumperCallThread; -} - -void CdbDumperHelper::setDumperCallThread(unsigned long t) -{ - if (m_dumperCallThread != t) { - m_dumperCallThread = t; - m_goCommand = goCommand(m_dumperCallThread); - } -} - -const CdbCore::ComInterfaces *CdbDumperHelper::comInterfaces() const -{ - return &m_coreEngine->interfaces(); -} - -} // namespace Internal -} // namespace Debugger - -#include "cdbdumperhelper.moc" diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h deleted file mode 100644 index aa55f00c02a4115dd4915f3fd6f32cd6cff1b262..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbdumperhelper.h +++ /dev/null @@ -1,171 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBDUMPERHELPER_H -#define CDBDUMPERHELPER_H - -#include "watchutils.h" -#include "cdbcom.h" - -#include <QtCore/QStringList> -#include <QtCore/QMap> - -namespace CdbCore { - class CoreEngine; - struct ComInterfaces; -} - -namespace Debugger { -namespace Internal { - -class CdbDumperInitThread; -class CdbEngine; - -/* For code clarity, all the stuff related to custom dumpers goes here. - * "Custom dumper" is a library compiled against the current - * Qt containing functions to evaluate values of Qt classes - * (such as QString), taking pointers to their addresses. - * The dumper functions produce formatted string output which is - * converted into WatchData items with the help of QtDumperHelper. - * - * Usage: When launching the debugger, call reset() with path to dumpers - * and enabled flag. From the module load event callback, call - * moduleLoadHook() to initialize. - * dumpType() is the main query function to obtain a list of WatchData from - * WatchData item produced by the smbol context. - * Call disable(), should the debuggee crash (as performing debuggee - * calls is no longer possible, then). - * - * dumperCallThread specifies the thread to use when making the calls. - * As of Debugging Tools v 6.11.1.404 (6.10.2009), calls cannot be executed - * when the current thread is in some WaitFor...() function. The call will - * then hang (regardless whether that thread or some other, non-blocking thread - * is used), and the debuggee will be in running state afterwards (causing errors - * from ReadVirtual, etc). - * The current thread can be used when stepping or a breakpoint was - * hit. When interrupting the inferior, an artifical thread is created, - * that is not usable, either. */ - -class CdbDumperHelper -{ - Q_DISABLE_COPY(CdbDumperHelper) -public: - enum State { - Disabled, // Disabled or failed - NotLoaded, - InjectLoadFailed, - InjectLoading, - Loaded, - Initialized, // List of types, etc. retrieved - }; - - explicit CdbDumperHelper(CdbEngine *engine, - CdbCore::CoreEngine *coreEngine); - ~CdbDumperHelper(); - - State state() const { return m_state; } - bool isEnabled() const { return m_state != Disabled; } - - void setFastSymbolResolution(bool b) { m_fastSymbolResolution = b; } - - // Disable in case of a debuggee crash. - void disable(); - - // Call before starting the debugger - void reset(const QString &library, bool enabled); - - // Call from the module load callback to perform initialization. - void moduleLoadHook(const QString &module, HANDLE debuggeeHandle); - - // Dump a WatchData item. - enum DumpResult { DumpNotHandled, DumpOk, DumpError }; - DumpResult dumpType(const WatchData &d, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage); - - const CdbCore::ComInterfaces *comInterfaces() const; - - enum { InvalidDumperCallThread = 0xFFFFFFFF }; - unsigned long dumperCallThread(); - void setDumperCallThread(unsigned long t); - -private: - friend class CdbDumperInitThread; - enum CallLoadResult { CallLoadOk, CallLoadError, CallLoadNoQtApp, CallLoadAlreadyLoaded }; - - void clearBuffer(); - CallLoadResult initCallLoad(QString *errorMessage); - bool initResolveSymbols(QString *errorMessage); - bool initKnownTypes(QString *errorMessage); - - inline DumpResult dumpTypeI(const WatchData &d, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage); - - bool getTypeSize(const QByteArray &typeName, int *size, QString *errorMessage); - bool runTypeSizeQuery(const QByteArray &typeName, int *size, QString *errorMessage); - enum CallResult { CallOk, CallSyntaxError, CallFailed }; - CallResult callDumper(const QString &call, const QByteArray &inBuffer, const char **outputPtr, - bool ignoreAccessViolation, QString *errorMessage); - - enum DumpExecuteResult { DumpExecuteOk, DumpExpressionFailed, DumpExecuteCallFailed }; - DumpExecuteResult executeDump(const WatchData &wd, - const QtDumperHelper::TypeData& td, bool dumpChildren, - QList<WatchData> *result, QString *errorMessage); - - const bool m_tryInjectLoad; - const QString m_msgDisabled; - const QString m_msgNotInScope; - State m_state; - CdbEngine *m_engine; - CdbCore::CoreEngine *m_coreEngine; - - QString m_library; - QString m_dumpObjectSymbol; - - quint64 m_inBufferAddress; - unsigned long m_inBufferSize; - quint64 m_outBufferAddress; - unsigned long m_outBufferSize; - char *m_buffer; - - QStringList m_failedTypes; - - QtDumperHelper m_helper; - unsigned long m_dumperCallThread; - QString m_goCommand; - bool m_fastSymbolResolution; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // CDBDUMPERHELPER_H diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp deleted file mode 100644 index d8afdc938753ec2b5d7bec988a09b2ec434c1e0f..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ /dev/null @@ -1,1905 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbengine.h" -#include "cdbengine_p.h" -#include "cdbdebugoutput.h" -#include "cdbdebugeventcallback.h" -#include "cdbstacktracecontext.h" -#include "cdbsymbolgroupcontext.h" -#include "cdbbreakpoint.h" -#include "cdbmodules.h" -#include "cdbassembler.h" -#include "cdboptionspage.h" -#include "cdboptions.h" -#include "cdbexceptionutils.h" -#include "cdbsymbolpathlisteditor.h" -#include "dbgwinutils.h" -#include "debuggercore.h" -#include "disassembleragent.h" -#include "memoryagent.h" - -#include "debuggeractions.h" -#include "breakhandler.h" -#include "stackhandler.h" -#include "watchhandler.h" -#include "threadshandler.h" -#include "registerhandler.h" -#include "moduleshandler.h" -#include "watchutils.h" -#include "corebreakpoint.h" - -#include <coreplugin/icore.h> -#include <utils/qtcassert.h> -#include <utils/qtcprocess.h> -#include <utils/winutils.h> -#include <utils/consoleprocess.h> -#include <utils/fancymainwindow.h> -#include <texteditor/itexteditor.h> -#include <utils/savedaction.h> -#include <utils/checkablemessagebox.h> -#include <projectexplorer/toolchain.h> - -#include <QtCore/QDebug> -#include <QtCore/QTimer> -#include <QtCore/QTimerEvent> -#include <QtCore/QFileInfo> -#include <QtCore/QDir> -#include <QtCore/QLibrary> -#include <QtCore/QCoreApplication> -#include <QtGui/QMessageBox> -#include <QtGui/QMainWindow> -#include <QtGui/QApplication> -#include <QtGui/QToolTip> - -#define DBGHELP_TRANSLATE_TCHAR -#include <inc/Dbghelp.h> - -static const char localSymbolRootC[] = "local"; - -#if 0 -# define STATE_DEBUG(func, line, notifyFunc) qDebug("%s at %s:%d", notifyFunc, func, line); -#else -# define STATE_DEBUG(func, line, notifyFunc) -#endif - -namespace Debugger { -namespace Internal { - -CdbOptionsPage *theOptionsPage = 0; -typedef QList<WatchData> WatchList; - -// ----- Message helpers - -static QString msgStackIndexOutOfRange(int idx, int size) -{ - return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size); -} - -QString msgDebuggerCommandFailed(const QString &command, HRESULT hr) -{ - return QString::fromLatin1("Unable to execute '%1': %2").arg(command, CdbCore::msgDebugEngineComResult(hr)); -} - -static const char *msgNoStackTraceC = "Internal error: no stack trace present."; - -// Format function failure message. Pass in Q_FUNC_INFO -static QString msgFunctionFailed(const char *func, const QString &why) -{ - // Strip a "cdecl_ int namespace1::class::foo(int bar)" as - // returned by Q_FUNC_INFO down to "foo" - QString function = QLatin1String(func); - const int firstParentPos = function.indexOf(QLatin1Char('(')); - if (firstParentPos != -1) - function.truncate(firstParentPos); - const int classSepPos = function.lastIndexOf(QLatin1String("::")); - if (classSepPos != -1) - function.remove(0, classSepPos + 2); - //: Function call failed - return CdbEngine::tr("The function \"%1()\" failed: %2").arg(function, why); -} - -// ----- Engine helpers - -// --- CdbEnginePrivate - -CdbEnginePrivate::CdbEnginePrivate(CdbEngine *engine) : - m_options(theOptionsPage->options()), - m_hDebuggeeProcess(0), - m_hDebuggeeThread(0), - m_breakEventMode(BreakEventHandle), - m_dumper(new CdbDumperHelper(engine, this)), - m_currentThreadId(-1), - m_eventThreadId(-1), - m_interruptArticifialThreadId(-1), - m_ignoreInitialBreakPoint(false), - m_interrupted(false), - m_engine(engine), - m_currentStackTrace(0), - m_firstActivatedFrame(true), - m_inferiorStartupComplete(false), - m_mode(AttachCore), - m_stoppedReason(StoppedOther) -{ - connect(this, SIGNAL(watchTimerDebugEvent()), this, SLOT(handleDebugEvent())); - connect(this, SIGNAL(modulesLoaded()), this, SLOT(slotModulesLoaded())); -} - -bool CdbEnginePrivate::init(QString *errorMessage) -{ - enum { bufLen = 10240 }; - - if (!CdbCore::CoreEngine::init(m_options->path, errorMessage)) - return false; - CdbDebugOutput *output = new CdbDebugOutput; - connect(output, SIGNAL(showMessage(QString,int,int)), - m_engine, SLOT(showMessage(QString,int,int)), - Qt::QueuedConnection); // Multithread invocation when loading dumpers. - setDebugOutput(DebugOutputBasePtr(output)); - setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine))); - updateCodeLevel(); - - return true; -} - -DebuggerEngine *CdbEngine::create(const DebuggerStartParameters &sp, - QString *errorMessage) -{ - if (!CdbCore::CoreEngine::interfacesAvailable()) { - *errorMessage = CdbEngine::tr("An instance of the CDB engine is still running; cannot create an a new instance."); - return 0; - } - CdbEngine *rc = new CdbEngine(sp); - if (rc->m_d->init(errorMessage)) { - rc->syncDebuggerPaths(); - return rc; - } - delete rc; - return 0; -} - -void CdbEnginePrivate::updateCodeLevel() -{ - const CdbCore::CoreEngine::CodeLevel cl = debuggerCore()->boolSetting(OperateByInstruction) ? - CdbCore::CoreEngine::CodeLevelAssembly : CdbCore::CoreEngine::CodeLevelSource; - setCodeLevel(cl); -} - -CdbEnginePrivate::~CdbEnginePrivate() -{ - cleanStackTrace(); -} - -void CdbEnginePrivate::clearForRun() -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO; - - m_breakEventMode = BreakEventHandle; - m_eventThreadId = m_interruptArticifialThreadId = -1; - m_interrupted = false; - cleanStackTrace(); - m_stoppedReason = StoppedOther; - m_stoppedMessage.clear(); - m_engine->threadsHandler()->notifyRunning(); -} - -void CdbEnginePrivate::cleanStackTrace() -{ - if (m_currentStackTrace) { - delete m_currentStackTrace; - m_currentStackTrace = 0; - } - m_firstActivatedFrame = false; - m_editorToolTipCache.clear(); -} - -CdbEngine::CdbEngine(const DebuggerStartParameters &startParameters) : - DebuggerEngine(startParameters), - m_d(new CdbEnginePrivate(this)) -{ - setObjectName(QLatin1String("CdbEngine")); - m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend); - connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)), - this, SLOT(slotConsoleStubMessage(QString, bool))); - connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), - this, SLOT(slotConsoleStubStarted())); - connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), - this, SLOT(slotConsoleStubTerminated())); -} - -CdbEngine::~CdbEngine() -{ - delete m_d; -} - -void CdbEngine::shutdownInferior() -{ - QString errorMessage; - if (!m_d->endInferior(false, &errorMessage)) - showMessage(errorMessage, LogError); -} - -void CdbEngine::shutdownEngine() -{ - m_d->endDebugging(); -} - -QString CdbEngine::editorToolTip(const QString &exp, const QString &function) -{ - // Figure the editor tooltip. Ask the frame context of the - // function if it is a local variable it knows. If that is not - // the case, try to evaluate via debugger - QString errorMessage; - QString rc; - // Find the frame of the function if there is any - CdbSymbolGroupContext *frame = 0; - if (m_d->m_currentStackTrace && !function.isEmpty()) { - const int frameIndex = m_d->m_currentStackTrace->indexOf(function); - if (debugToolTips) - qDebug() << "CdbEngine::editorToolTip" << exp << function << frameIndex; - if (frameIndex != -1) - frame = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage); - } - if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage)) - return rc; - // No function/symbol context found, try to evaluate in current context. - // Do not append type as this will mostly be 'long long' for integers, etc. - QString type; - if (debugToolTips) - qDebug() << "Defaulting to expression"; - if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage)) - return QString(); - return rc; -} - -void CdbEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos) -{ - typedef CdbEnginePrivate::EditorToolTipCache EditorToolTipCache; - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << cursorPos; - // Need a stopped debuggee and a cpp file - if (!m_d->m_hDebuggeeProcess || m_d->isDebuggeeRunning()) - return; - if (!isCppEditor(editor)) - return; - // Determine expression and function - QString toolTip; - do { - int line; - int column; - QString function; - const QString exp = cppExpressionAt(editor, cursorPos, &line, &column, &function); - if (function.isEmpty() || exp.isEmpty()) - break; - // Check cache (key containing function) or try to figure out expression - QString cacheKey = function; - cacheKey += QLatin1Char('@'); - cacheKey += exp; - const EditorToolTipCache::const_iterator cit = m_d->m_editorToolTipCache.constFind(cacheKey); - if (cit != m_d->m_editorToolTipCache.constEnd()) { - toolTip = cit.value(); - } else { - toolTip = editorToolTip(exp, function); - if (!toolTip.isEmpty()) - m_d->m_editorToolTipCache.insert(cacheKey, toolTip); - } - } while (false); - // Display - QToolTip::hideText(); - if (!toolTip.isEmpty()) - QToolTip::showText(mousePos, toolTip); -} - -void CdbEnginePrivate::clearDisplay() -{ - m_engine->threadsHandler()->removeAll(); - m_engine->modulesHandler()->removeAll(); - m_engine->registerHandler()->removeAll(); -} - -void CdbEnginePrivate::checkVersion() -{ - static bool versionNotChecked = true; - // Check for version 6.11 (extended expression syntax) - if (versionNotChecked) { - versionNotChecked = false; - // Get engine DLL version - QString errorMessage; - const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage); - if (version.isEmpty()) { - qWarning("%s\n", qPrintable(errorMessage)); - return; - } - // Compare - const double minVersion = 6.11; - m_engine->showMessage(CdbEngine::tr("Version: %1").arg(version)); - if (version.toDouble() < minVersion) { - const QString msg = CdbEngine::tr( - "<html>The installed version of the <i>Debugging Tools for Windows</i> (%1) " - "is rather old. Upgrading to version %2 is recommended " - "for the proper display of Qt's data types.</html>").arg(version).arg(minVersion); - Core::ICore::instance()->showWarningWithOptions(CdbEngine::tr("Debugger"), msg, QString(), - QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY), - CdbOptionsPage::settingsId()); - } - } -} - -void CdbEngine::setupEngine() -{ - QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); - const DebuggerStartParameters &sp = startParameters(); - if (debugCDBExecution) - qDebug("setupEngine"); - CdbCore::BreakPoint::clearNormalizeFileNameCache(); - // Nag to add symbol server - if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(), - &(m_d->m_options->symbolPaths))) { - m_d->m_options->toSettings(Core::ICore::instance()->settings()); - syncDebuggerPaths(); - } - m_d->checkVersion(); - if (m_d->m_hDebuggeeProcess) { - warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged.")); - notifyEngineSetupFailed(); - return; - } - switch (sp.startMode) { - case AttachCore: - case AttachToRemote: - warning(QLatin1String("Internal error: Mode not supported.")); - notifyEngineSetupFailed(); - return; - default: - break; - } - m_d->m_mode = sp.startMode; - m_d->clearDisplay(); - m_d->m_inferiorStartupComplete = false; - // Options - QString errorMessage; - if (!m_d->setBreakOnThrow(m_d->m_options->breakOnException, &errorMessage)) - showMessage(errorMessage, LogWarning); - m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading); - // Figure out dumper. @TODO: same in gdb... - const QString dumperLibName = QDir::toNativeSeparators(qtDumperLibraryName()); - bool dumperEnabled = m_d->m_mode != AttachCore - && m_d->m_mode != AttachCrashedExternal - && qtDumperLibraryEnabled(); - if (dumperEnabled) { - const QFileInfo fi(dumperLibName); - if (!fi.isFile()) { - const QStringList &locations = qtDumperLibraryLocations(); - const QString loc = locations.join(QLatin1String(", ")); - const QString msg = tr("The dumper library was not found at %1.").arg(loc); - showQtDumperLibraryWarning(msg); - dumperEnabled = false; - } - } - m_d->m_dumper->reset(dumperLibName, dumperEnabled); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk"); - notifyEngineSetupOk(); -} - -void CdbEngine::setupInferior() -{ - QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk"); - notifyInferiorSetupOk(); -} - -void CdbEngine::runEngine() -{ - if (debugCDBExecution) - qDebug("runEngine"); - QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - - const DebuggerStartParameters &sp = startParameters(); - bool rc = false; - bool needWatchTimer = false; - QString errorMessage; - m_d->clearForRun(); - m_d->updateCodeLevel(); - m_d->m_ignoreInitialBreakPoint = false; - switch (m_d->m_mode) { - case AttachExternal: - case AttachCrashedExternal: - rc = startAttachDebugger(sp.attachPID, m_d->m_mode, &errorMessage); - needWatchTimer = true; // Fetch away module load, etc. even if crashed - break; - case StartInternal: - case StartExternal: { - Utils::QtcProcess::SplitError perr; - QString pargs = Utils::QtcProcess::prepareArgs(sp.processArgs, &perr, - &sp.environment, &sp.workingDirectory); - if (perr != Utils::QtcProcess::SplitOk) { - // perr == BadQuoting is never returned on Windows - // FIXME? QTCREATORBUG-2809 - errorMessage = QApplication::translate("DebuggerEngine", // Same message in GdbEngine - "Debugging complex command lines is currently not supported under Windows"); - break; - } - if (sp.useTerminal) { - // Attaching to console processes triggers an initial breakpoint, which we do not want - m_d->m_ignoreInitialBreakPoint = true; - // Launch console stub and wait for its startup - m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now. - m_d->m_consoleStubProc.setWorkingDirectory(sp.workingDirectory); - m_d->m_consoleStubProc.setEnvironment(sp.environment); - rc = m_d->m_consoleStubProc.start(sp.executable, pargs); - if (!rc) - errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp.executable); - // continues in slotConsoleStubStarted()... - } else { - needWatchTimer = true; - rc = m_d->startDebuggerWithExecutable(sp.workingDirectory, - sp.executable, - pargs, - sp.environment.toStringList(), - &errorMessage); - } - break; } - case AttachCore: - errorMessage = tr("Attaching to core files is not supported."); - break; - } - if (rc) { - if (needWatchTimer) - m_d->startWatchTimer(); - // Continues processCreatedAttached(). - } else { - warning(errorMessage); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyEngineRunFailed"); - notifyEngineRunFailed(); - } -} - -bool CdbEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage) -{ - // Need to attach invasively, otherwise, no notification signals - // for for CreateProcess/ExitProcess occur. - // Initial breakpoint occur: - // 1) Desired: When attaching to a crashed process - // 2) Undesired: When starting up a console process, in conjunction - // with the 32bit Wow-engine - // As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed - // by lookup at the state of the application (startup trap). However, - // there is no startup trap when attaching to a process that has been - // running for a while. (see notifyException). - const bool suppressInitialBreakPoint = sm != AttachCrashedExternal; - return m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage); -} - -void CdbEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle) -{ - if (debugCDBExecution) - qDebug(">processCreatedAttached"); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyEngineRunAndInferiorStopOk"); - m_engine->notifyEngineRunAndInferiorStopOk(); - setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle)); - ULONG currentThreadId; - if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, ¤tThreadId))) { - m_currentThreadId = currentThreadId; - } else { - m_currentThreadId = 0; - } - // Clear any saved breakpoints and set initial breakpoints - m_engine->executeDebuggerCommand(QLatin1String("bc")); - m_engine->attemptBreakpointSynchronization(); - // Attaching to crashed: This handshake (signalling an event) is required for - // the exception to be delivered to the debugger - // Also, see special handling in slotModulesLoaded(). - if (m_mode == AttachCrashedExternal) { - const QString crashParameter = m_engine->startParameters().crashParameter; - if (!crashParameter.isEmpty()) { - ULONG64 evtNr = crashParameter.toULongLong(); - const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr); - if (FAILED(hr)) - m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr))); - } - } - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested()/notifyInferiorRunOk()"); - m_engine->notifyInferiorRunRequested(); - m_engine->notifyInferiorRunOk(); - if (debugCDBExecution) - qDebug("<processCreatedAttached"); -} - -void CdbEngine::processTerminated(unsigned long exitCode) -{ - if (debugCDBExecution) - qDebug("processTerminated: %lu", exitCode); - showMessage(tr("The process exited with exit code %1.").arg(exitCode)); - m_d->setDebuggeeHandles(0, 0); - m_d->clearForRun(); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorExited"); - notifyInferiorExited(); -} - -bool CdbEnginePrivate::endInferior(bool detachOnly, QString *errorMessage) -{ - QTC_ASSERT(hasInterfaces(), return true; ) - // Prevent repeated invocation. - const bool hasHandles = m_hDebuggeeProcess != NULL; - if (debugCDBExecution) - qDebug("endInferior detach=%d, %s handles=%d", detachOnly, DebuggerEngine::stateName(m_engine->state()), hasHandles); - if (!hasHandles) - return true; - // Are we running - switch (m_engine->state()) { - case InferiorRunRequested: - case InferiorRunOk: - case InferiorRunFailed: - case InferiorStopRequested: - case InferiorStopOk: - case InferiorStopFailed: - case InferiorShutdownRequested: - case EngineShutdownRequested: // Forwarded when choosing 'Abort...' an attached process. - break; - default: - return true; - } - // Detach or terminate? - if (!detachOnly && (m_mode == AttachExternal || m_mode == AttachCrashedExternal)) - detachOnly = true; - // Process must be stopped in order to terminate - const bool wasRunning = isDebuggeeRunning(); - if (debugCDBExecution) - qDebug("endInferior detach=%d, running=%d", detachOnly, wasRunning); - if (wasRunning) { - interruptInterferiorProcess(errorMessage); - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - } - bool success = false; - if (detachOnly) { - if (detachCurrentProcess(errorMessage)) - success = true; - } else { - // Stop debuggee. Weird exit logic. - do { - // The exit process event handler will not be called. - terminateCurrentProcess(errorMessage); - if (wasRunning) { - success = true; - break; - } - if (terminateProcesses(errorMessage)) - success = true; - } while (false); - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - } - // Perform cleanup even when failed..no point clinging to the process - setDebuggeeHandles(0, 0); - killWatchTimer(); - clearForRun(); - if (success) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk"); - m_engine->notifyInferiorShutdownOk(); - } else { - *errorMessage = QString::fromLatin1("Unable to detach from/end the debuggee: %1").arg(*errorMessage); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed"); - m_engine->notifyInferiorShutdownFailed(); - } - return success; -} - -// End debugging. Note that this can invoked via user action -// or the processTerminated() event handler, in which case it -// must not kill the process again. -void CdbEnginePrivate::endDebugging(bool detachOnly) -{ - if (debugCDBExecution) - qDebug("endDebugging() detach=%d, state=%s", detachOnly, DebuggerEngine::stateName(m_engine->state())); - - QTC_ASSERT(hasInterfaces(), return; ) - - switch (m_engine->state()) { - case DebuggerNotReady: - case EngineShutdownOk: - case EngineShutdownFailed: - case DebuggerFinished: - return; - default: - break; - } - // Do we need to stop the process? - QString errorMessage; - if (!endInferior(detachOnly, &errorMessage)) { - m_engine->showMessage(errorMessage, LogError); - errorMessage.clear(); - } - if (endSession(&errorMessage)) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk"); - m_engine->notifyEngineShutdownOk(); - } else { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyEngineShutdownFailed"); - errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage); - m_engine->showMessage(errorMessage, LogError); - m_engine->notifyEngineShutdownFailed(); - } - // At this point release interfaces as we might be kept around by the run control. - releaseInterfaces(); -} - -void CdbEngine::detachDebugger() -{ - m_d->endDebugging(true); -} - -CdbSymbolGroupContext *CdbEnginePrivate::getSymbolGroupContext(int frameIndex, QString *errorMessage) const -{ - if (!m_currentStackTrace) { - *errorMessage = QLatin1String(msgNoStackTraceC); - return 0; - } - if (CdbSymbolGroupContext *sg = m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, errorMessage)) - return sg; - return 0; -} - -void CdbEngine::evaluateWatcher(WatchData *wd) -{ - if (debugCDBWatchHandling) - qDebug() << Q_FUNC_INFO << wd->exp; - QString errorMessage; - QString value; - QString type; - QString exp = wd->exp; - // Remove locals watch prefix. - if (exp.startsWith(QLatin1String("local."))) - exp.remove(0, 6); - if (m_d->evaluateExpression(exp, &value, &type, &errorMessage)) { - wd->setValue(value); - wd->setType(type.toUtf8()); - } else { - wd->setValue(errorMessage); - wd->setTypeUnneeded(); - } - wd->setHasChildren(false); -} - -void CdbEngine::updateWatchData(const WatchData &incomplete, const WatchUpdateFlags & /* flags */) -{ - // Watch item was edited while running - if (m_d->isDebuggeeRunning()) - return; - - if (debugCDBWatchHandling) - qDebug() << Q_FUNC_INFO << "\n " << incomplete.toString(); - - if (incomplete.iname.startsWith("watch.")) { - WatchData watchData = incomplete; - watchData.setError(tr("<not supported>")); - watchHandler()->insertData(watchData); - return; - } - - const int frameIndex = stackHandler()->currentIndex(); - - bool success = false; - QString errorMessage; - do { - CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage); - if (!sg) - break; - if (!sg->completeData(incomplete, watchHandler(), &errorMessage)) - break; - success = true; - } while (false); - if (!success) - warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); - if (debugCDBWatchHandling > 1) - qDebug() << *watchHandler()->model(LocalsWatch); -} - -// Continue inferior with a debugger command, such as "p", "pt" -// or its thread variations -bool CdbEnginePrivate::executeContinueCommand(const QString &command) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << command; - clearForRun(); - updateCodeLevel(); // Step by instruction - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested"); - m_engine->notifyInferiorRunRequested(); - m_engine->showMessage(CdbEngine::tr("Continuing with '%1'...").arg(command)); - QString errorMessage; - const bool success = executeDebuggerCommand(command, &errorMessage); - if (success) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk"); - m_engine->notifyInferiorRunOk(); - startWatchTimer(); - } else { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunFailed"); - m_engine->notifyInferiorRunFailed(); - m_engine->warning(CdbEngine::tr("Unable to continue: %1").arg(errorMessage)); - } - return success; -} - -static inline QString msgStepFailed(unsigned long executionStatus, int threadId, const QString &why) -{ - if (executionStatus == DEBUG_STATUS_STEP_OVER) - return QString::fromLatin1("Thread %1: Unable to step over: %2").arg(threadId).arg(why); - return QString::fromLatin1("Thread %1: Unable to step into: %2").arg(threadId).arg(why); -} - -// Step out has to be done via executing 'gu'. TODO: Remove once it is -// accessible via normal API for SetExecutionStatus(). - -enum { CdbExtendedExecutionStatusStepOut = 7452347 }; - -// Step with DEBUG_STATUS_STEP_OVER ('p'-command), -// DEBUG_STATUS_STEP_INTO ('t'-trace-command) or -// CdbExtendedExecutionStatusStepOut ("gu"-command) -// its reverse equivalents in the case of single threads. - -bool CdbEngine::step(unsigned long executionStatus) -{ - if (debugCDBExecution) - qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId; - - // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404): - // The constants exist, but invoking the calls leads to E_NOINTERFACE. - // Also there is no CDB command for it. - if (executionStatus == DEBUG_STATUS_REVERSE_STEP_OVER || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO) { - warning(tr("Reverse stepping is not implemented.")); - return false; - } - - // Do not step the artifical thread created to interrupt the debuggee. - if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) { - warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId)); - return false; - } - - // SetExecutionStatus() continues the thread that triggered the - // stop event (~# p). This can be confusing if the user is looking - // at the stack trace of another thread and wants to step that one. If that - // is the case, explicitly tell it to step the current thread using a command. - const int triggeringEventThread = m_d->m_eventThreadId; - const bool sameThread = triggeringEventThread == -1 - || m_d->m_currentThreadId == triggeringEventThread - || threadsHandler()->threads().size() == 1; - m_d->clearForRun(); // clears thread ids - m_d->updateCodeLevel(); // Step by instruction or source line - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested"); - notifyInferiorRunRequested(); - bool success = false; - if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API - const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus); - success = SUCCEEDED(hr); - if (!success) - warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr))); - } else { - // Need to use a command to explicitly specify the current thread - QString command; - QTextStream str(&command); - str << '~' << m_d->m_currentThreadId << ' '; - switch (executionStatus) { - case DEBUG_STATUS_STEP_OVER: - str << 'p'; - break; - case DEBUG_STATUS_STEP_INTO: - str << 't'; - break; - case CdbExtendedExecutionStatusStepOut: - str << "gu"; - break; - } - showMessage(tr("Stepping %1").arg(command)); - const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO); - success = SUCCEEDED(hr); - if (!success) - warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr))); - } - if (success) { - // Oddity: Step into will first break at the calling function. Ignore - if (executionStatus == DEBUG_STATUS_STEP_INTO || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO) - m_d->m_breakEventMode = CdbEnginePrivate::BreakEventIgnoreOnce; - m_d->startWatchTimer(); - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk"); - notifyInferiorRunOk(); - } else { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunFailed"); - notifyInferiorRunFailed(); - } - if (debugCDBExecution) - qDebug() << "<step samethread" << sameThread << "succeeded" << success; - return success; -} - -void CdbEngine::executeStep() -{ - step(isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_INTO : DEBUG_STATUS_STEP_INTO); -} - -void CdbEngine::executeNext() -{ - step(isReverseDebugging() ? DEBUG_STATUS_REVERSE_STEP_OVER : DEBUG_STATUS_STEP_OVER); -} - -void CdbEngine::executeStepI() -{ - executeStep(); // Step into by instruction (figured out by step) -} - -void CdbEngine::executeNextI() -{ - executeNext(); // Step over by instruction (figured out by step) -} - -void CdbEngine::executeStepOut() -{ - if (!isReverseDebugging()) - step(CdbExtendedExecutionStatusStepOut); -} - -void CdbEngine::continueInferior() -{ - QString errorMessage; - if (!m_d->continueInferior(&errorMessage)) - warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); -} - -// Continue process without notifications -bool CdbEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */) -{ - if (debugCDBExecution) - qDebug("continueInferiorProcess"); - const HRESULT hr = interfaces().debugControl->SetExecutionStatus(DEBUG_STATUS_GO); - if (FAILED(hr)) { - const QString errorMessage = CdbCore::msgComFailed("SetExecutionStatus", hr); - if (errorMessagePtr) { - *errorMessagePtr = errorMessage; - } else { - m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); - } - return false; - } - return true; -} - -// Continue process with notifications -bool CdbEnginePrivate::continueInferior(QString *errorMessage) -{ - // Check state: Are we running? - const ULONG ex = executionStatus(); - if (debugCDB) - qDebug() << Q_FUNC_INFO << "\n ex=" << ex; - - if (ex == DEBUG_STATUS_GO) { - m_engine->warning(QLatin1String("continueInferior() called while debuggee is running.")); - return true; - } - // Request continue - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested"); - m_engine->notifyInferiorRunRequested(); - bool success = false; - do { - clearForRun(); - updateCodeLevel(); - killWatchTimer(); - m_engine->resetLocation(); - m_engine->showStatusMessage(CdbEngine::tr("Running requested..."), messageTimeOut); - - if (!continueInferiorProcess(errorMessage)) - break; - - startWatchTimer(); - success = true; - } while (false); - if (success) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunOk"); - m_engine->notifyInferiorRunOk(); - } else { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorRunFailed"); - m_engine->notifyInferiorRunFailed(); - } - return true; -} - -bool CdbEnginePrivate::interruptInterferiorProcess(QString *errorMessage) -{ - - // Interrupt the interferior process without notifications - // Could use setInterrupt, but that does not work. - if (debugCDBExecution) { - qDebug() << "interruptInterferiorProcess ex=" << executionStatus(); - } - const bool rc = debugBreakProcess(m_hDebuggeeProcess, errorMessage); - if (rc) - m_interrupted = true; - return rc; -} - -void CdbEnginePrivate::slotModulesLoaded() -{ - // Attaching to crashed windows processes: Unless QtCreator is - // spawned by the debug handler and inherits the handles, - // the event handling does not work reliably (that is, the crash - // event is not delivered). In that case, force a break - if (m_mode == AttachCrashedExternal && m_engine->state() != InferiorStopOk) - QTimer::singleShot(10, m_engine, SLOT(slotBreakAttachToCrashed())); -} - -void CdbEngine::slotBreakAttachToCrashed() -{ - // Force a break when attaching to crashed process (if Creator was not spawned - // from handler). - if (state() != InferiorStopOk) { - showMessage(QLatin1String("Forcing break...")); - m_d->m_dumper->disable(); - interruptInferior(); - } -} - -void CdbEngine::interruptInferior() -{ - if (!m_d->m_hDebuggeeProcess || !m_d->isDebuggeeRunning()) - return; - - QString errorMessage; - if (!m_d->interruptInterferiorProcess(&errorMessage)) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "notifyInferiorStopFailed"); - notifyInferiorStopFailed(); - warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); - } -} - -void CdbEngine::executeRunToLine(const QString &fileName, int lineNumber) -{ - showMessage(tr("Running up to %1:%2...").arg(fileName).arg(lineNumber)); - QString errorMessage; - CdbCore::BreakPoint tempBreakPoint; - tempBreakPoint.fileName = fileName; - tempBreakPoint.lineNumber = lineNumber; - tempBreakPoint.oneShot = true; - const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage) - && m_d->continueInferior(&errorMessage); - if (!ok) - warning(errorMessage); -} - -void CdbEngine::executeRunToFunction(const QString &functionName) -{ - showMessage(tr("Running up to function '%1()'...").arg(functionName)); - QString errorMessage; - CdbCore::BreakPoint tempBreakPoint; - tempBreakPoint.funcName = functionName; - tempBreakPoint.oneShot = true; - const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage) - && m_d->continueInferior(&errorMessage); - if (!ok) - warning(errorMessage); -} - -void CdbEngine::setRegisterValue(int regnr, const QString &valueIn) -{ - bool success = false; - QString errorMessage; - do { - const quint64 value = valueIn.toULongLong(&success, 0); - if (!success) { - errorMessage = tr("Invalid register value '%1'").arg(valueIn); - break; - } - if (!setRegisterValueU64(m_d->interfaces().debugRegisters, regnr, value, &errorMessage)) - break; - showMessage(QString::fromLatin1("Setting register %1 to 0x%2..."). - arg(regnr).arg(value, 0, 16)); - reloadRegisters(); - success =true; - } while (false); - if (!success) - warning(tr("Cannot set register %1 to '%2': %3"). - arg(regnr).arg(valueIn).arg(errorMessage)); -} - -void CdbEngine::executeJumpToLine(const QString &fileName, int lineNumber) -{ - // 'Jump' to line by manipulating the program counter register 'rip'. - bool success = false; - QString errorMessage; - do { - const quint64 address = m_d->getSourceLineAddress(fileName, lineNumber, &errorMessage); - if (address == 0) - break; - - if (!setRegisterValueU64(m_d->interfaces().debugControl, - m_d->interfaces().debugRegisters, -#ifdef Q_OS_WIN64 - QLatin1String("rip"), -#else - QLatin1String("eip"), -#endif - address, &errorMessage)) - break; - showMessage(QString::fromLatin1("Jumping to %1:%2 (0x%3)..."). - arg(QDir::toNativeSeparators(fileName)).arg(lineNumber).arg(address, 0, 16)); - - StackFrame frame; - frame.usable = true; - frame.file = fileName; - frame.line = lineNumber; - gotoLocation(frame); - success = true; - } while (false); - if (!success) - warning(tr("Cannot jump to %1:%2: %3").arg(fileName).arg(lineNumber).arg(errorMessage)); -} - -void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &valueV) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << w->iname << expr << valueV; - const int frameIndex = stackHandler()->currentIndex(); - QString errorMessage; - bool success = false; - QApplication::setOverrideCursor(Qt::BusyCursor); - const QString iname = QLatin1String(w->iname); - const QString type = QLatin1String(w->type); - const QString newValue = valueV.toString(); - //: Arguments: New value, name, (type) - showMessage(tr("Assigning '%1' to '%2' (%3)...").arg(newValue, iname, type), LogMisc); - do { - // Value must be scalar - const QVariant::Type type = valueV.type(); - if (type != QVariant::Double && type != QVariant::Bool - && type != QVariant::Int && type != QVariant::LongLong - && type != QVariant::UInt&& type != QVariant::ULongLong) { - errorMessage = tr("Can assign only scalar values."); - break; - } - // Check the assigneable type - const bool isInt = isIntType(w->type); - const bool isFloat = !isInt && isFloatType(w->type); - const bool isPointer = !isInt && !isFloat && isPointerType(w->type); - if (!isInt && !isFloat & !isPointer) { - errorMessage = tr("Cannot assign values of type '%1'. Only POD-types can be assigned.").arg(type); - break; - } - CdbSymbolGroupContext *sg = m_d->getSymbolGroupContext(frameIndex, &errorMessage); - if (!sg) - break; - QString newValueObtained; - if (!sg->assignValue(w->iname, newValue, &newValueObtained, &errorMessage)) - break; - // Fix the crappy values returned by the symbol group (0n<Decimal>, etc). - // Return pointers as hex - if (isInt || isPointer) { - const QVariant v = CdbCore::SymbolGroupContext::getIntValue(newValueObtained); - if (v.isValid()) - newValueObtained = isPointer ? - (QLatin1String("0x") + QString::number(v.toULongLong(), 16)): - v.toString(); - } - // Update view - if (const WatchData *fwd = watchHandler()->findItem(w->iname)) { - WatchData modified = *fwd; - modified.setValue(newValueObtained); - watchHandler()->insertData(modified); - watchHandler()->updateWatchers(); - } - success = true; - } while (false); - QApplication::restoreOverrideCursor(); - if (!success) { - //: Arguments: New value, name, (type): Error - const QString msg = tr("Unable to assign the value '%1' to '%2' (%3): %4"). - arg(newValue, expr, type, errorMessage); - warning(msg); - } -} - -void CdbEngine::executeDebuggerCommand(const QString &command) -{ - QString errorMessage; - if (!m_d->executeDebuggerCommand(command, &errorMessage)) - warning(errorMessage); -} - -void CdbEngine::activateFrame(int frameIndex) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << frameIndex; - - switch (state()) { - case InferiorStopOk: - case InferiorShutdownRequested: - break; - default: - qWarning("WARNING %s: invoked in invalid state %s\n", - Q_FUNC_INFO, DebuggerEngine::stateName(state())); - return; - } - - QString errorMessage; - bool success = false; - do { - const int oldIndex = stackHandler()->currentIndex(); - if (frameIndex >= stackHandler()->stackSize()) { - errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler()->stackSize()); - break; - } - - if (oldIndex != frameIndex) - stackHandler()->setCurrentIndex(frameIndex); - - const StackFrame &frame = stackHandler()->currentFrame(); - - const bool showAssembler = !frame.isUsable(); - if (showAssembler) { // Assembly code: Clean out model and force instruction mode. - watchHandler()->beginCycle(); - watchHandler()->endCycle(); - QAction *assemblerAction = debuggerCore()->action(OperateByInstruction); - if (!assemblerAction->isChecked()) - assemblerAction->trigger(); - success = true; - break; - } - - gotoLocation(frame); - - if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) { - watchHandler()->beginCycle(); - if (CdbSymbolGroupContext *sgc = m_d->getSymbolGroupContext(frameIndex, &errorMessage)) - success = sgc->populateModelInitially(watchHandler(), &errorMessage); - watchHandler()->endCycle(); - } else { - success = true; - } - } while (false); - - if (!success) { - const QString msg = QString::fromLatin1("Internal error: activateFrame() failed for frame #%1 of %2, thread %3: %4"). - arg(frameIndex).arg(stackHandler()->stackSize()). - arg(m_d->m_currentThreadId).arg(errorMessage); - warning(msg); - } - m_d->m_firstActivatedFrame = false; -} - -void CdbEngine::selectThread(int index) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << index; - - // Reset location arrow. - resetLocation(); - - threadsHandler()->setCurrentThread(index); - const int newThreadId = threadsHandler()->threads().at(index).id; - if (newThreadId != m_d->m_currentThreadId) { - m_d->m_currentThreadId = threadsHandler()->threads().at(index).id; - m_d->updateStackTrace(); - } -} - -bool CdbEngine::stateAcceptsBreakpointChanges() const -{ - switch (state()) { - case InferiorRunOk: - case InferiorStopOk: - return true; - default: - break; - } - return false; -} - -bool CdbEngine::acceptsBreakpoint(BreakpointId id) const -{ - return DebuggerEngine::isCppBreakpoint(breakHandler()->breakpointData(id)); -} - -void CdbEngine::attemptBreakpointSynchronization() -{ - if (!m_d->m_hDebuggeeProcess) // Sometimes called from the breakpoint Window - return; - QString errorMessage; - if (!attemptBreakpointSynchronizationI(&errorMessage)) - warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); -} - -// Figure out what kind of changes are required to synchronize -enum BreakPointSyncType { - BreakpointsUnchanged, BreakpointsAdded, BreakpointsRemovedChanged -}; - -static inline BreakPointSyncType breakPointSyncType(const BreakHandler *handler, const BreakpointIds ids) -{ - bool added = false; - foreach (BreakpointId id, ids) { - switch (handler->state(id)) { - case BreakpointInsertRequested: - added = true; - break; - case BreakpointChangeRequested: - case BreakpointRemoveRequested: - return BreakpointsRemovedChanged; - default: - break; - } - } - return added ? BreakpointsAdded : BreakpointsUnchanged; -} - -bool CdbEngine::attemptBreakpointSynchronizationI(QString *errorMessage) -{ - - if (!m_d->m_hDebuggeeProcess) { - *errorMessage = QLatin1String("attemptBreakpointSynchronization() called while debugger is not running"); - return false; - } - // Might be called nested while attempting to stop. - if (m_d->m_breakEventMode == CdbEnginePrivate::BreakEventSyncBreakPoints) { - *errorMessage = QLatin1String("Nested invocation of attemptBreakpointSynchronization."); - return false; - } - - // Check if there is anything to be done at all. - BreakHandler *handler = breakHandler(); - // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only? - foreach (BreakpointId id, handler->unclaimedBreakpointIds()) - if (acceptsBreakpoint(id)) - handler->setEngine(id, this); - - // Find out if there is a need to synchronize again - const BreakpointIds ids = handler->engineBreakpointIds(this); - const BreakPointSyncType syncType = breakPointSyncType(handler, ids); - if (debugBreakpoints) - qDebug("attemptBreakpointSynchronizationI %d breakpoints, syncType=%d", ids.size(), syncType); - if (syncType == BreakpointsUnchanged) - return true; - - // This is called from - // 1) CreateProcessEvent with the halted engine - // 2) from the break handler, potentially while the debuggee is running - // If the debuggee is running (for which the execution status is - // no reliable indicator), we temporarily halt and have ourselves - // called again from the debug event handler. - - CIDebugControl *control = m_d->interfaces().debugControl; - CIDebugSymbols *symbols = m_d->interfaces().debugSymbols; - - ULONG dummy; - const bool wasRunning = !CdbCore::BreakPoint::getBreakPointCount(control, &dummy); - if (debugCDB) - qDebug() << Q_FUNC_INFO << "\n Running=" << wasRunning; - - if (wasRunning) { - const CdbEnginePrivate::HandleBreakEventMode oldMode = m_d->m_breakEventMode; - m_d->m_breakEventMode = CdbEnginePrivate::BreakEventSyncBreakPoints; - if (!m_d->interruptInterferiorProcess(errorMessage)) { - m_d->m_breakEventMode = oldMode; - return false; - } - return true; - } - - // If there are changes/removals, delete all breakpoints and re-insert - // all enabled breakpoints. This is the simplest way to apply changes - // since CDB ids shift when removing breakpoints and there is no - // easy way to re-match them. - if (syncType == BreakpointsRemovedChanged && !deleteCdbBreakpoints(control, errorMessage)) - return false; - - foreach (BreakpointId id, ids) { - BreakpointResponse response; - const BreakpointParameters &data = handler->breakpointData(id); - errorMessage->clear(); - switch (handler->state(id)) { - case BreakpointInsertRequested: - handler->notifyBreakpointInsertProceeding(id); - if (addCdbBreakpoint(control, symbols, data, &response, errorMessage)) { - handler->notifyBreakpointInsertOk(id); - handler->setResponse(id, response); - } else { - handler->notifyBreakpointInsertOk(id); - showMessage(*errorMessage, LogError); - } - break; - case BreakpointChangeRequested: - // Skip disabled breakpoints, else add. - handler->notifyBreakpointChangeProceeding(id); - if (data.enabled) { - if (addCdbBreakpoint(control, symbols, data, &response, errorMessage)) { - handler->notifyBreakpointChangeOk(id); - handler->setResponse(id, response); - } else { - handler->notifyBreakpointChangeFailed(id); - showMessage(*errorMessage, LogError); - } - } else { - handler->notifyBreakpointChangeOk(id); - } - break; - case BreakpointRemoveRequested: - handler->notifyBreakpointRemoveProceeding(id); - handler->notifyBreakpointRemoveOk(id); - break; - case BreakpointInserted: - // Existing breakpoints were deleted due to change/removal, re-set - if (syncType == BreakpointsRemovedChanged - && !addCdbBreakpoint(control, symbols, handler->breakpointData(id), &response, errorMessage)) - showMessage(*errorMessage, LogError); - break; - default: - break; - } - } - if (debugBreakpoints) - debugCdbBreakpoints(control); - return true; -} - -void CdbEngine::fetchDisassembler(DisassemblerAgent *agent) -{ - enum { ContextLines = 40 }; - QString errorMessage; - const quint64 address = agent->address(); - if (debugCDB) - qDebug() << "fetchDisassembler" << address << " Agent: " << agent->address(); - - DisassemblerLines lines; - if (address == 0) { // Clear window - agent->setContents(lines); - return; - } - QString disassembly; - QApplication::setOverrideCursor(Qt::WaitCursor); - const bool ok = disassemble(m_d, address, ContextLines, ContextLines, QTextStream(&disassembly), &errorMessage); - QApplication::restoreOverrideCursor(); - if (ok) { - foreach(const QString &line, disassembly.remove(QLatin1Char('\r')).split(QLatin1Char('\n'))) - lines.appendLine(DisassemblerLine(line)); - } else { - warning(errorMessage); - } - agent->setContents(lines); -} - -void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *token, quint64 addr, quint64 length) -{ - if (!m_d->m_hDebuggeeProcess && !length) - return; - ULONG received; - QByteArray data(length, '\0'); - const HRESULT hr = m_d->interfaces().debugDataSpaces->ReadVirtual(addr, data.data(), length, &received); - if (FAILED(hr)) { - warning(tr("Unable to retrieve %1 bytes of memory at 0x%2: %3"). - arg(length).arg(addr, 0, 16).arg(CdbCore::msgComFailed("ReadVirtual", hr))); - return; - } - if (received < length) - data.truncate(received); - agent->addLazyData(token, addr, data); -} - -void CdbEngine::reloadModules() -{ -} - -void CdbEngine::loadSymbols(const QString &moduleName) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << moduleName; -} - -void CdbEngine::loadAllSymbols() -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO; -} - -void CdbEngine::requestModuleSymbols(const QString &moduleName) -{ - Symbols 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->interfaces().debugSymbols, moduleName, &rc, &errorMessage)) - break; - success = true; - } while (false); - if (!success) - warning(errorMessage); - debuggerCore()->showModuleSymbols(moduleName, rc); -} - -void CdbEngine::reloadRegisters() -{ - if (state() != InferiorStopOk) - return; - const int intBase = 10; - if (debugCDB) - qDebug() << Q_FUNC_INFO << intBase; - - QString errorMessage; - const Registers registers = getRegisters(m_d->interfaces().debugControl, - m_d->interfaces().debugRegisters, &errorMessage, intBase); - if (registers.isEmpty() && !errorMessage.isEmpty()) - warning(msgFunctionFailed("reloadRegisters" , errorMessage)); - registerHandler()->setRegisters(registers); -} - -void CdbEngine::slotConsoleStubStarted() -{ - const qint64 appPid = m_d->m_consoleStubProc.applicationPID(); - if (debugCDB) - qDebug() << Q_FUNC_INFO << appPid; - // Attach to console process. - QString errorMessage; - if (startAttachDebugger(appPid, AttachExternal, &errorMessage)) { - m_d->startWatchTimer(); - notifyInferiorPid(appPid); - } else { - QMessageBox::critical(debuggerCore()->mainWindow(), tr("Debugger Error"), errorMessage); - } -} - -void CdbEngine::slotConsoleStubMessage(const QString &msg, bool) -{ - QMessageBox::critical(debuggerCore()->mainWindow(), tr("Debugger Error"), msg); -} - -void CdbEngine::slotConsoleStubTerminated() -{ - shutdownEngine(); -} - -void CdbEngine::warning(const QString &msg) -{ - showMessage(msg, LogWarning); - qWarning("%s\n", qPrintable(msg)); -} - -void CdbEnginePrivate::notifyException(long code, bool fatal, const QString &message) -{ - if (debugCDBExecution) - qDebug() << "notifyException code" << code << " fatal=" << fatal; - // Suppress the initial breakpoint that occurs when - // attaching to a console (If a breakpoint is encountered before startup - // is complete, see startAttachDebugger()). - switch (code) { - case winExceptionStartupCompleteTrap: - m_inferiorStartupComplete = true; - break; - case EXCEPTION_BREAKPOINT: - if (m_ignoreInitialBreakPoint && !m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) { - m_engine->showMessage(CdbEngine::tr("Ignoring initial breakpoint...")); - m_breakEventMode = BreakEventIgnoreOnce; - } - break; - } - // Cannot go over crash point to execute calls. - if (fatal) { - m_dumper->disable(); - m_stoppedReason = StoppedCrash; - m_stoppedMessage = message; - } -} - -static int threadIndexById(const ThreadsHandler *threadsHandler, int id) -{ - const Threads threads = threadsHandler->threads(); - const int count = threads.count(); - for (int i = 0; i < count; i++) - if (threads.at(i).id == id) - return i; - return -1; -} - -void CdbEnginePrivate::handleDebugEvent() -{ - if (debugCDBExecution) - qDebug() << "handleDebugEvent mode " << m_breakEventMode - << CdbCore::msgExecutionStatusString(executionStatus()) << " interrupt" << m_interrupted - << " startupcomplete" << m_inferiorStartupComplete; - // restore mode and do special handling - const HandleBreakEventMode mode = m_breakEventMode; - m_breakEventMode = BreakEventHandle; - - switch (mode) { - case BreakEventHandle: { - if (m_interrupted) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "BreakEventHandle / notifyInferiorStopOk"); - m_engine->notifyInferiorStopOk(); - } else { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "BreakEventHandle / notifyInferiorSpontaneousStop"); - m_engine->notifyInferiorSpontaneousStop(); - } - // If this is triggered by breakpoint/crash: Set state to stopping - // to avoid warnings as opposed to interrupt inferior - // Indicate artifical thread that is created when interrupting as such, - // else use stop message with cleaned newlines and blanks. - const QString currentThreadState = - m_interrupted ? CdbEngine::tr("<interrupt thread>") : - (m_stoppedReason == StoppedBreakpoint ? CdbEngine::tr("Breakpoint") : - m_stoppedMessage.simplified() ); - m_eventThreadId = updateThreadList(currentThreadState); - m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1; - // Get thread to stop and its index. If avoidable, do not use - // the artifical thread that is created when interrupting, - // use the oldest thread 0 instead. - ThreadsHandler *threadsHandler = m_engine->threadsHandler(); - m_currentThreadId = m_interrupted ? 0 : m_eventThreadId; - int currentThreadIndex = -1; - m_currentThreadId = -1; - if (m_interrupted) { - m_currentThreadId = 0; - currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); - } - if (!m_interrupted || currentThreadIndex == -1) { - m_currentThreadId = m_eventThreadId; - currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); - } - const QString msg = m_interrupted ? - CdbEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) : - CdbEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId); - m_engine->showMessage(msg); - const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId); - if (threadIndex != -1) - threadsHandler->setCurrentThread(threadIndex); - updateStackTrace(); - } - break; - case BreakEventIgnoreOnce: - startWatchTimer(); - m_interrupted = false; - break; - case BreakEventSyncBreakPoints: { - m_interrupted = false; - // Temp stop to sync breakpoints (without invoking states). - // Triggered when the users changes breakpoints while running. - QString errorMessage; - m_engine->attemptBreakpointSynchronizationI(&errorMessage); - startWatchTimer(); - if (!continueInferiorProcess(&errorMessage)) { - STATE_DEBUG(Q_FUNC_INFO, __LINE__, "BreakEventSyncBreakPoints / notifyInferiorSpontaneousStop"); - m_engine->notifyInferiorSpontaneousStop(); - } - if (!errorMessage.isEmpty()) - m_engine->warning(QString::fromLatin1("In handleDebugEvent: %1").arg(errorMessage)); - } - break; - } -} - -void CdbEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << hDebuggeeProcess << hDebuggeeThread; - m_hDebuggeeProcess = hDebuggeeProcess; - m_hDebuggeeThread = hDebuggeeThread; -} - -// Set thread in CDB engine -bool CdbEnginePrivate::setCDBThreadId(unsigned long threadId, QString *errorMessage) -{ - ULONG currentThreadId; - HRESULT hr = interfaces().debugSystemObjects->GetCurrentThreadId(¤tThreadId); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetCurrentThreadId", hr); - return false; - } - if (currentThreadId == threadId) - return true; - hr = interfaces().debugSystemObjects->SetCurrentThreadId(threadId); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Failed to change to from thread %1 to %2: SetCurrentThreadId() failed: %3"). - arg(currentThreadId).arg(threadId).arg(CdbCore::msgDebugEngineComResult(hr)); - return false; - } - const QString msg = CdbEngine::tr("Changing threads: %1 -> %2").arg(currentThreadId).arg(threadId); - m_engine->showStatusMessage(msg, 500); - return true; -} - -ULONG CdbEnginePrivate::updateThreadList(const QString ¤tThreadState) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess; - - Threads threads; - ULONG currentThreadId; - QString errorMessage; - // When interrupting, an artifical thread with a breakpoint is created. - const bool stopped = m_engine->state() == InferiorStopOk; - if (!CdbStackTraceContext::getThreads(interfaces(), - stopped, - &threads, ¤tThreadId, - &errorMessage)) - m_engine->warning(errorMessage); - // Indicate states 'stopped' or current thread state. - // Do not indicate 'running' since we can't know if it is suspended. - if (stopped) { - const QString state = CdbEngine::tr("stopped"); - const bool hasCurrentState = !currentThreadState.isEmpty(); - const int count = threads.size(); - for (int i= 0; i < count; i++) { - threads[i].state = hasCurrentState && threads.at(i).id == currentThreadId ? - currentThreadState : state; - } - } - m_engine->threadsHandler()->setThreads(threads); - return currentThreadId; -} - -// Figure out the thread to run the dumpers in (see notes on. -// CdbDumperHelper). Avoid the artifical threads created by interrupt -// and threads that are in waitFor(). -// A stricter version could only use the thread if it is the event -// thread of a step or breakpoint hit (see CdbEnginePrivate::m_interrupted). - -static inline unsigned long dumperThreadId(const QList<StackFrame> &frames, - unsigned long currentThread) -{ - if (frames.empty()) - return CdbDumperHelper::InvalidDumperCallThread; - switch (CdbCore::StackTraceContext::specialFunction(frames.at(0).from, frames.at(0).function)) { - case CdbCore::StackTraceContext::BreakPointFunction: - case CdbCore::StackTraceContext::WaitFunction: - return CdbDumperHelper::InvalidDumperCallThread; - default: - break; - } - // Check remaining frames for wait - const int waitCheckDepth = qMin(frames.size(), 5); - for (int f = 1; f < waitCheckDepth; f++) { - if (CdbCore::StackTraceContext::specialFunction(frames.at(f).from, frames.at(f).function) - == CdbCore::StackTraceContext::WaitFunction) - return CdbDumperHelper::InvalidDumperCallThread; - } - return currentThread; -} - -// Format stop message with all available information. -QString CdbEnginePrivate::stoppedMessage(const StackFrame *topFrame /* = 0 */) const -{ - QString msg; - if (topFrame) { - if (topFrame->isUsable()) { - // Stopped at basename:line - const int lastSlashPos = topFrame->file.lastIndexOf(QLatin1Char('/')); - const QString file = lastSlashPos == -1 ? topFrame->file : topFrame->file.mid(lastSlashPos + 1); - msg = CdbEngine::tr("Stopped at %1:%2 in thread %3."). - arg(file).arg(topFrame->line).arg(m_currentThreadId); - } else { - // Somewhere in assembly code. - if (topFrame->function.isEmpty()) { - msg = CdbEngine::tr("Stopped at %1 in thread %2 (missing debug information)."). - arg(topFrame->address).arg(m_currentThreadId); - } else { - msg = CdbEngine::tr("Stopped at %1 (%2) in thread %3 (missing debug information)."). - arg(topFrame->address).arg(topFrame->function).arg(m_currentThreadId); - } - } // isUsable - } else { - msg = CdbEngine::tr("Stopped in thread %1 (missing debug information).").arg(m_currentThreadId); - - } - if (!m_stoppedMessage.isEmpty()) { - msg += QLatin1Char(' '); - msg += m_stoppedMessage; - } - return msg; -} - -void CdbEnginePrivate::updateStackTrace() -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO; - // Create a new context - cleanStackTrace(); - QString errorMessage; - m_engine->reloadRegisters(); - if (!setCDBThreadId(m_currentThreadId, &errorMessage)) { - m_engine->warning(errorMessage); - return; - } - m_currentStackTrace = - CdbStackTraceContext::create(m_dumper, &errorMessage); - if (!m_currentStackTrace) { - m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); - 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->stackFrames(); - // find the first usable frame and select it - int current = -1; - const int count = stackFrames.count(); - for (int i=0; i < count; ++i) - if (stackFrames.at(i).isUsable()) { - current = i; - break; - } - // Format stop message. - const QString stopMessage = stoppedMessage(stackFrames.isEmpty() ? static_cast<const StackFrame *>(0) : &stackFrames.front()); - // Set up dumper with a thread (or invalid) - const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId); - if (debugCDBExecution) - qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread; - m_dumper->setDumperCallThread(dumperThread); - // Display frames - m_engine->stackHandler()->setFrames(stackFrames); - m_firstActivatedFrame = true; - if (current >= 0) { - m_engine->stackHandler()->setCurrentIndex(current); - m_engine->activateFrame(current); - } else { - // Clean out variables - m_engine->watchHandler()->beginCycle(); - m_engine->watchHandler()->endCycle(); - } - m_engine->watchHandler()->updateWatchers(); - // Show message after a lengthy dumper initialization - m_engine->showMessage(stopMessage, StatusBar, 15000); -} - -void CdbEnginePrivate::updateModules() -{ - Modules modules; - QString errorMessage; - if (!getModuleList(interfaces().debugSymbols, &modules, &errorMessage)) - m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); - m_engine->modulesHandler()->setModules(modules); -} - -static const char *dumperPrefixC = "dumper"; - -void CdbEnginePrivate::handleModuleLoad(quint64 offset, const QString &name) -{ - if (debugCDB>2) - qDebug() << Q_FUNC_INFO << "\n " << offset << name; - Module module; - // Determine module parameters by offset. The callback has almost all the - // parameters we need with the exception of 'symbolsRead'. Retrieve the - // parameters by offset as to avoid a hack like 'check last module'. - QString errorMessage; - if (getModuleByOffset(interfaces().debugSymbols, offset, &module, &errorMessage)) { - m_engine->modulesHandler()->addModule(module); - } else { - m_engine->warning(errorMessage); - } - m_dumper->moduleLoadHook(name, m_hDebuggeeProcess); -} - -void CdbEnginePrivate::handleModuleUnload(const QString &imageName) -{ - m_engine->modulesHandler()->removeModule(imageName); -} - -void CdbEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP) -{ - Q_UNUSED(pBP) - if (debugCDB) - qDebug() << Q_FUNC_INFO; - m_stoppedReason = StoppedBreakpoint; - CdbCore::BreakPoint breakpoint; - // Format message unless it is a temporary step-out breakpoint with empty expression. - QString expression; - if (breakpoint.retrieve(pBP, &expression)) { - expression = breakpoint.expression(); - } else { - expression.clear(); - } - if (!expression.isEmpty()) - m_stoppedMessage = breakpoint.type == CdbCore::BreakPoint::Code ? - CdbEngine::tr("Breakpoint: %1").arg(expression) : - CdbEngine::tr("Watchpoint: %1").arg(expression); -} - -void CdbEngine::reloadSourceFiles() -{ -} - -void CdbEngine::syncDebuggerPaths() -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << m_d->m_options->symbolPaths << m_d->m_options->sourcePaths; - QString errorMessage; - if (!m_d->setSourcePaths(m_d->m_options->sourcePaths, &errorMessage) - || !m_d->setSymbolPaths(m_d->m_options->symbolPaths, &errorMessage)) { - errorMessage = QString::fromLatin1("Unable to set the debugger paths: %1").arg(errorMessage); - warning(errorMessage); - } -} - -unsigned CdbEngine::debuggerCapabilities() const -{ - return DisassemblerCapability | RegisterCapability | ShowMemoryCapability - |WatchpointCapability|JumpToLineCapability - |BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw(). -} - -// Accessed by RunControlFactory -bool isCdbEngineEnabled() -{ - return theOptionsPage && theOptionsPage->options()->enabled; -} - -// Accessed by RunControlFactory -DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *errorMessage) -{ - // Create engine - DebuggerEngine *engine = CdbEngine::create(sp, errorMessage); - if (engine) { - QObject::connect(theOptionsPage, SIGNAL(debuggerPathsChanged()), engine, SLOT(syncDebuggerPaths())); - } else { - theOptionsPage->setFailureMessage(*errorMessage); - qWarning("%s\n" ,qPrintable(*errorMessage)); - } - return engine; -} - -void addCdbOptionPages(QList<Core::IOptionsPage *> *opts) -{ - // FIXME: HACK (global variable) - theOptionsPage = new CdbOptionsPage; - opts->push_back(theOptionsPage); -} - -bool checkCdbConfiguration(int toolChainI, QString *errorMsg, QString *settingsPage) -{ - const ProjectExplorer::ToolChainType toolChain = static_cast<ProjectExplorer::ToolChainType>(toolChainI); - switch (toolChain) { - case ProjectExplorer::ToolChain_MinGW: // Do our best - case ProjectExplorer::ToolChain_MSVC: - case ProjectExplorer::ToolChain_WINCE: - case ProjectExplorer::ToolChain_OTHER: - case ProjectExplorer::ToolChain_UNKNOWN: - case ProjectExplorer::ToolChain_INVALID: - break; - default: - //: %1 is something like "GCCE" or "Intel C++ Compiler (Linux)" (see ToolChain context) - *errorMsg = CdbEngine::tr("The CDB debug engine does not support the %1 toolchain."). - arg(ProjectExplorer::ToolChain::toolChainName(toolChain)); - *settingsPage = CdbOptionsPage::settingsId(); - return false; - } - return true; -} - -} // namespace Internal -} // namespace Debugger - diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h deleted file mode 100644 index 9d15803e0a71e329c52a83a763a97d7bbd3bcd91..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbengine.h +++ /dev/null @@ -1,135 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGGER_CDBENGINE_H -#define DEBUGGER_CDBENGINE_H - -#include "debuggerengine.h" - -#include <QtCore/QSharedPointer> - -namespace Debugger { -namespace Internal { - -class DisassemblerAgent; -class CdbDebugEventCallback; -class CdbDebugOutput; -class CdbEnginePrivate; -struct CdbOptions; - -class CdbEngine : public DebuggerEngine -{ - Q_OBJECT - explicit CdbEngine(const DebuggerStartParameters &sp); - -public: - ~CdbEngine(); - - // Factory function that returns 0 if the debug engine library cannot be found. - static DebuggerEngine *create(const DebuggerStartParameters &sp, - QString *errorMessage); - - virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - virtual void setupEngine(); - virtual void setupInferior(); - virtual void runEngine(); - virtual void shutdownInferior(); - virtual void shutdownEngine(); - virtual void detachDebugger(); - virtual void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); - virtual unsigned debuggerCapabilities() const; - - virtual void executeStep(); - virtual void executeStepOut(); - virtual void executeNext(); - virtual void executeStepI(); - virtual void executeNextI(); - - virtual void continueInferior(); - virtual void interruptInferior(); - - virtual void executeRunToLine(const QString &fileName, int lineNumber); - virtual void executeRunToFunction(const QString &functionName); - virtual void executeJumpToLine(const QString &fileName, int lineNumber); - virtual void assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value); - virtual void executeDebuggerCommand(const QString &command); - - virtual void activateFrame(int index); - virtual void selectThread(int index); - - virtual bool stateAcceptsBreakpointChanges() const; - virtual bool acceptsBreakpoint(BreakpointId id) const; - virtual void attemptBreakpointSynchronization(); - - virtual void setRegisterValue(int regnr, const QString &value); - virtual void fetchDisassembler(DisassemblerAgent *agent); - virtual void fetchMemory(MemoryAgent *, QObject *, quint64 addr, quint64 length); - - virtual void reloadModules(); - virtual void loadSymbols(const QString &moduleName); - virtual void loadAllSymbols(); - virtual void requestModuleSymbols(const QString &moduleName); - - virtual void reloadRegisters(); - virtual void reloadSourceFiles(); - virtual void reloadFullStack() {} - -public slots: - void syncDebuggerPaths(); - -private slots: - void slotConsoleStubStarted(); - void slotConsoleStubMessage(const QString &msg, bool); - void slotConsoleStubTerminated(); - void slotBreakAttachToCrashed(); - void warning(const QString &w); - -private: - inline bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage); - void processTerminated(unsigned long exitCode); - void evaluateWatcher(WatchData *wd); - QString editorToolTip(const QString &exp, const QString &function); - bool step(unsigned long executionStatus); - bool attemptBreakpointSynchronizationI(QString *errorMessage); - - CdbEnginePrivate *m_d; - - friend class CdbEnginePrivate; - friend class CdbDebugEventCallback; - friend class CdbDebugOutput; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_CDBENGINE_H diff --git a/src/plugins/debugger/cdb/cdbengine_p.h b/src/plugins/debugger/cdb/cdbengine_p.h deleted file mode 100644 index 796911a5085f7889e9018c8c5858da2af4deb025..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbengine_p.h +++ /dev/null @@ -1,156 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGGER_CDBENGINEPRIVATE_H -#define DEBUGGER_CDBENGINEPRIVATE_H - -#include "coreengine.h" -#include "debuggerconstants.h" -#include "cdboptions.h" -#include "cdbdumperhelper.h" -#include "stackhandler.h" - -#include <utils/consoleprocess.h> - -#include <QtCore/QSharedPointer> -#include <QtCore/QMap> - -namespace Debugger { -namespace Internal { - -class WatchHandler; -class CdbStackTraceContext; -class CdbSymbolGroupContext; - -class CdbEnginePrivate : public CdbCore::CoreEngine -{ - Q_OBJECT -public: - - typedef QMap<QString, QString> EditorToolTipCache; - - enum HandleBreakEventMode { // Special modes for break event handler. - BreakEventHandle, - BreakEventIgnoreOnce, - BreakEventSyncBreakPoints, - }; - - enum StoppedReason { - StoppedCrash, - StoppedBreakpoint, - StoppedOther - }; - - explicit CdbEnginePrivate(CdbEngine* engine); - ~CdbEnginePrivate(); - bool init(QString *errorMessage); - - void checkVersion(); - void processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle); - void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread); - - bool isDebuggeeRunning() const { return isWatchTimerRunning(); } - ULONG updateThreadList(const QString ¤tThreadState = QString()); - bool setCDBThreadId(unsigned long threadId, QString *errorMessage); - void updateStackTrace(); - void updateModules(); - - void handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP); - void cleanStackTrace(); - void clearForRun(); - void handleModuleLoad(quint64 offset, const QString &); - void handleModuleUnload(const QString &name); - CdbSymbolGroupContext *getSymbolGroupContext(int frameIndex, QString *errorMessage) const; - void clearDisplay(); - - bool interruptInterferiorProcess(QString *errorMessage); - - bool continueInferiorProcess(QString *errorMessage = 0); - bool continueInferior(QString *errorMessage); - bool executeContinueCommand(const QString &command); - - void notifyException(long code, bool fatal, const QString &message); - - - bool endInferior(bool detachOnly /* = false */, QString *errorMessage); - - void endDebugging(bool detachOnly = false); - - void updateCodeLevel(); - - QString stoppedMessage(const StackFrame *topFrame = 0) const; - -private slots: - void handleDebugEvent(); - void slotModulesLoaded(); - -public: - const QSharedPointer<CdbOptions> m_options; - HANDLE m_hDebuggeeProcess; - HANDLE m_hDebuggeeThread; - bool m_interrupted; - int m_currentThreadId; - int m_eventThreadId; - int m_interruptArticifialThreadId; - bool m_ignoreInitialBreakPoint; - HandleBreakEventMode m_breakEventMode; - - QSharedPointer<CdbDumperHelper> m_dumper; - - CdbEngine *m_engine; - CdbStackTraceContext *m_currentStackTrace; - EditorToolTipCache m_editorToolTipCache; - - bool m_firstActivatedFrame; - bool m_inferiorStartupComplete; - - DebuggerStartMode m_mode; - Utils::ConsoleProcess m_consoleStubProc; - - StoppedReason m_stoppedReason; - QString m_stoppedMessage; -}; - -enum { messageTimeOut = 5000 }; - -enum { debugCDB = 0 }; -enum { debugCDBExecution = 0 }; -enum { debugCDBWatchHandling = 0 }; -enum { debugToolTips = 0 }; -enum { debugBreakpoints = 0 }; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_CDBENGINEPRIVATE_H - diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp deleted file mode 100644 index a23177c269acef1df86ec9f1dfcde7ca58564633..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbexceptionutils.h" -#include "cdbengine_p.h" -#include "stacktracecontext.h" -#include "dbgwinutils.h" - -#include <QtCore/QString> -#include <QtCore/QTextStream> -#include <QtCore/QDebug> - -enum { debugExc = 0 }; - -namespace Debugger { -namespace Internal { - -static inline void formatDebugFilterExecFlags(ULONG f, const char *title, QTextStream &str) -{ - str.setIntegerBase(16); - str << ' ' << title << "=0x" << f << " ("; - str.setIntegerBase(10); - switch (f) { - case DEBUG_FILTER_BREAK: - str << "DEBUG_FILTER_BREAK"; - break; - case DEBUG_FILTER_SECOND_CHANCE_BREAK: - str << "DEBUG_FILTER_SECOND_CHANCE_BREAK"; - break; - case DEBUG_FILTER_OUTPUT: - str << "DEBUG_FILTER_OUTPUT"; - break; - case DEBUG_FILTER_IGNORE: - str << "DEBUG_FILTER_IGNORE"; - break; - } - str << ')'; -} - -static inline void formatDebugFilterContFlags(ULONG f, const char *title, QTextStream &str) -{ - str.setIntegerBase(16); - str << ' ' << title << "=0x" << f << " ("; - str.setIntegerBase(10); - switch (f) { - case DEBUG_FILTER_GO_HANDLED: - str << "DEBUG_FILTER_GO_HANDLED"; - break; - case DEBUG_FILTER_GO_NOT_HANDLED: - str << "DEBUG_FILTER_GO_NOT_HANDLED"; - } - str << ')'; -} - -ExceptionBlocker::ExceptionBlocker(CIDebugControl *ctrl, ULONG code, Mode m) : - m_ctrl(ctrl), - m_code(code), - m_state(StateError) -{ - // Retrieve current state - memset(&m_oldParameters, 0, sizeof(DEBUG_EXCEPTION_FILTER_PARAMETERS)); - if (getExceptionParameters(ctrl, code, &m_oldParameters, &m_errorString)) { - // Are we in a nested instantiation? - const ULONG desiredExOption = m == IgnoreException ? DEBUG_FILTER_IGNORE : DEBUG_FILTER_OUTPUT; - const bool isAlreadyBlocked = m_oldParameters.ExecutionOption == desiredExOption - && m_oldParameters.ContinueOption == DEBUG_FILTER_GO_NOT_HANDLED; - if (isAlreadyBlocked) { - m_state = StateNested; - } else { - // Nope, block it now. - DEBUG_EXCEPTION_FILTER_PARAMETERS blockedState = m_oldParameters; - blockedState.ExecutionOption = desiredExOption; - blockedState.CommandSize = DEBUG_FILTER_GO_NOT_HANDLED; - const bool ok = setExceptionParameters(m_ctrl, blockedState, &m_errorString); - m_state = ok ? StateOk : StateError; - } // not blocked - } else { - m_state = StateError; - } - if (debugExc) - qDebug() << "ExceptionBlocker: state=" << m_state << format(m_oldParameters) << m_errorString; -} - -ExceptionBlocker::~ExceptionBlocker() -{ - if (m_state == StateOk) { - // Restore - if (debugExc) - qDebug() << "~ExceptionBlocker: unblocking " << m_oldParameters.ExceptionCode; - if (!setExceptionParameters(m_ctrl, m_oldParameters, &m_errorString)) - qWarning("Unable to restore exception state for %lu: %s\n", m_oldParameters.ExceptionCode, qPrintable(m_errorString)); - } -} - -bool ExceptionBlocker::getExceptionParameters(CIDebugControl *ctrl, ULONG exCode, DEBUG_EXCEPTION_FILTER_PARAMETERS *result, QString *errorMessage) -{ - const HRESULT ihr = ctrl->GetExceptionFilterParameters(1, &exCode, 0, result); - if (FAILED(ihr)) { - *errorMessage = CdbCore::msgComFailed("GetExceptionFilterParameters", ihr); - return false; - } - return true; -} - -bool ExceptionBlocker::setExceptionParameters(CIDebugControl *ctrl, const DEBUG_EXCEPTION_FILTER_PARAMETERS &p, QString *errorMessage) -{ - const HRESULT ihr = ctrl->SetExceptionFilterParameters(1, const_cast<DEBUG_EXCEPTION_FILTER_PARAMETERS*>(&p)); - if (FAILED(ihr)) { - *errorMessage = CdbCore::msgComFailed("GetExceptionFilterParameters", ihr); - return false; - } - return true; -} - -QString ExceptionBlocker::format(const DEBUG_EXCEPTION_FILTER_PARAMETERS &p) -{ - QString rc; - QTextStream str(&rc); - str << "Code=" << p.ExceptionCode; - formatDebugFilterExecFlags(p.ExecutionOption, "ExecutionOption", str); - formatDebugFilterContFlags(p.ContinueOption, "ContinueOption", str); - str << " TextSize=" << p.TextSize << " CommandSizes=" << p.CommandSize << ',' - << p.SecondCommandSize; - return rc; -} - -// ------------------ further exception utilities -// Simple exception formatting - -void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) -{ - formatWindowsException(e->ExceptionCode, e->ExceptionAddress, - e->ExceptionFlags, - e->ExceptionInformation[0], - e->ExceptionInformation[1], - str); - str << "\n\n"; -} - -// Format exception with stacktrace in case of C++ exception -void formatException(const EXCEPTION_RECORD64 *e, - const CdbCore::ComInterfaces *cif, - QTextStream &str) -{ - formatException(e, str); - if (e->ExceptionCode == winExceptionCppException) { - QString errorMessage; - if (CdbCore::StackTraceContext *stc = CdbCore::StackTraceContext::create(cif, 9999, &errorMessage)) { - str << "at:\n"; - stc->format(str); - str <<'\n'; - delete stc; - } - } -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.h b/src/plugins/debugger/cdb/cdbexceptionutils.h deleted file mode 100644 index 7460b5a3043dbba55cd978e2e961b121cad32004..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbexceptionutils.h +++ /dev/null @@ -1,100 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBEXCEPTIONUTILS_H -#define CDBEXCEPTIONUTILS_H - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QSharedPointer> - -QT_BEGIN_NAMESPACE -class QTextStream; -QT_END_NAMESPACE - -namespace CdbCore { - struct ComInterfaces; -} - -namespace Debugger { -namespace Internal { - -class CdbDumperHelper; - -// Utility class that blocks out exception handling (breaking) -// for a specific exception (like EXCEPTION_ACCESS_VIOLATION) while in scope. -class ExceptionBlocker { - Q_DISABLE_COPY(ExceptionBlocker) -public: - // Log mode. Note: Does not influence the output callbacks. - enum Mode { - IgnoreException, // Ignore & suppress debugger console notification - LogException // Ignore, still print console notification - }; - - ExceptionBlocker(CIDebugControl *ctrl, ULONG exceptionCode, Mode mode); - ~ExceptionBlocker(); - - operator bool() const { return m_state != StateError; } - QString errorString() const { return m_errorString; } - - // Helpers - static bool getExceptionParameters(CIDebugControl *ctrl, ULONG exCode, DEBUG_EXCEPTION_FILTER_PARAMETERS *result, QString *errorMessage); - static bool setExceptionParameters(CIDebugControl *ctrl, const DEBUG_EXCEPTION_FILTER_PARAMETERS &p, QString *errorMessage); - static QString format(const DEBUG_EXCEPTION_FILTER_PARAMETERS &p); - -private: - enum State { StateOk, - StateNested, // Nested call, exception already blocked, do nothing - StateError }; - - CIDebugControl *m_ctrl; - const LONG m_code; - DEBUG_EXCEPTION_FILTER_PARAMETERS m_oldParameters; - State m_state; - QString m_errorString; -}; - -// Format exception -void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str); - -// Format exception with stacktrace in case of C++ exception -void formatException(const EXCEPTION_RECORD64 *e, - const CdbCore::ComInterfaces *cif, - QTextStream &str); - -} // namespace Internal -} // namespace Debugger - -#endif // CDBEXCEPTIONUTILS_H diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp deleted file mode 100644 index 0c35165512e2fdf1ac8a9b99d502af67d422aeef..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbmodules.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbmodules.h" -#include "moduleshandler.h" -#include "cdbengine_p.h" -#include "breakpoint.h" -#include "shared/dbgwinutils.h" - -#include <QtCore/QFileInfo> -#include <QtCore/QRegExp> -#include <QtCore/QVector> - -namespace Debugger { -namespace Internal { - -static inline bool getModuleCount(CIDebugSymbols *syms, ULONG *count, QString *errorMessage) -{ - *count = 0; - ULONG loadedCount, unloadedCount; - const HRESULT hr = syms->GetNumberModules(&loadedCount, &unloadedCount); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("GetNumberModules", hr); - return false; - } - *count = loadedCount + unloadedCount; - return true; -} - -bool getModuleNameList(CIDebugSymbols *syms, QStringList *modules, QString *errorMessage) -{ - ULONG count; - modules->clear(); - if (!getModuleCount(syms, &count, errorMessage)) - return false; - WCHAR wszBuf[MAX_PATH]; - for (ULONG m = 0; m < count; m++) - if (SUCCEEDED(syms->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0))) - modules->push_back(QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf))); - return true; -} - -// Get basic module parameters from struct (except name) -static inline void getBasicModuleParameters(const DEBUG_MODULE_PARAMETERS &p, - Module *module) -{ - if ((p.Flags & DEBUG_MODULE_USER_MODE) && (p.SymbolType != DEBUG_SYMTYPE_NONE)) - module->symbolsRead = Module::ReadOk; - else - module->symbolsRead = Module::ReadFailed; - module->startAddress = p.Base; - module->endAddress = p.Base + p.Size; -} - -// Get module name by index -static inline bool getModuleName(CIDebugSymbols *syms, ULONG index, QString *n, QString *errorMessage) -{ - WCHAR wszBuf[MAX_PATH]; - const HRESULT hr = syms->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, index, 0, wszBuf, MAX_PATH - 1, 0); - if (FAILED(hr) && hr != E_INVALIDARG) { - *errorMessage= CdbCore::msgComFailed("GetModuleNameStringWide", hr); - return false; - } - *n = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - return true; -} - -bool getModuleByOffset(CIDebugSymbols *syms, quint64 offset, - Module *module, QString *errorMessage) -{ - // Find by base address and set parameters - ULONG index; - HRESULT hr = syms->GetModuleByOffset(offset, 0, &index, 0); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("GetModuleByOffset", hr); - return false; - } - DEBUG_MODULE_PARAMETERS parameters; - memset(¶meters, 0, sizeof(DEBUG_MODULE_PARAMETERS)); - hr = syms->GetModuleParameters(1, 0, 0u, ¶meters); - if (FAILED(hr)) { - *errorMessage= CdbCore::msgComFailed("GetModuleParameters", hr); - return false; - } - getBasicModuleParameters(parameters, module); - return getModuleName(syms, index, &(module->moduleName), errorMessage); -} - -bool getModuleList(CIDebugSymbols *syms, Modules *modules, QString *errorMessage) -{ - ULONG count; - modules->clear(); - if (!getModuleCount(syms, &count, errorMessage)) - return false; - QVector<DEBUG_MODULE_PARAMETERS> parameters(count); - DEBUG_MODULE_PARAMETERS *parmPtr = &(*parameters.begin()); - memset(parmPtr, 0, sizeof(DEBUG_MODULE_PARAMETERS) * count); - HRESULT hr = syms->GetModuleParameters(count, 0, 0u, parmPtr); - // E_INVALIDARG indicates 'Partial results' according to docu - if (FAILED(hr) && hr != E_INVALIDARG) { - *errorMessage= CdbCore::msgComFailed("GetModuleParameters", hr); - return false; - } - // fill array - 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; - getBasicModuleParameters(p, &module); - if (!getModuleName(syms, m, &(module.moduleName), errorMessage)) - return false; - modules->push_back(module); - } - } - return true; -} - -// Search symbols matching a pattern -bool searchSymbols(CIDebugSymbols *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(reinterpret_cast<PCWSTR>(pattern.utf16()), &handle); - if (hr == E_NOINTERFACE) { - if (handle) - syms->EndSymbolMatch(handle); - return true; - } - if (FAILED(hr)) { - *errorMessage= CdbCore::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(reinterpret_cast<const ushort *>(wszBuf))); - } - syms->EndSymbolMatch(handle); - if (matches->empty()) - *errorMessage = QString::fromLatin1("No symbol matches '%1'.").arg(pattern); - return true; -} - -// Helper for the resolveSymbol overloads. -static ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, QString *symbol, - QStringList *matches, - QString *errorMessage) -{ - errorMessage->clear(); - // Is it an incomplete symbol? - if (symbol->contains(QLatin1Char('!'))) - return ResolveSymbolOk; - const bool withinMSVCRunTime = *symbol == QLatin1String(winMSVCThrowFunction) - || *symbol == QLatin1String(winMSVCCatchFunction); - if (*symbol == QLatin1String("qMain")) // 'main' is a #define for gdb, but not for VS - *symbol = QLatin1String("main"); - // resolve - if (!searchSymbols(syms, *symbol, matches, errorMessage)) - return ResolveSymbolError; - // Exception functions sometimes show up ambiguously as'QtGuid4!CxxThrowException', - // 'MSVCR100D!CxxThrowException', QtCored4!CxxThrowException', - // 'MSVCP100D!CxxThrowException' and 'msvcrt!CxxThrowException', - // 'OLEAUT32!CxxThrowException'...restrict to MSVC-RunTime (any MSVC version). - if (withinMSVCRunTime && matches->size() > 1) { - for (QStringList::iterator it = matches->begin(); it != matches->end(); ) - if (it->startsWith(QLatin1String("MSVCR"))) { - ++it; - } else { - it = matches->erase(it); - } - } - if (matches->empty()) { - *errorMessage = QString::fromLatin1("No match for '%1' found").arg(*symbol); - 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; -} - -// Add missing the module specifier: "main" -> "project!main" -ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, QString *symbol, - QString *errorMessage) -{ - QStringList matches; - return resolveSymbol(syms, symbol, &matches, errorMessage); -} - -ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, const QString &pattern, QString *symbol, QString *errorMessage) -{ - QStringList matches; - const ResolveSymbolResult r1 = resolveSymbol(syms, symbol, &matches, errorMessage); - switch (r1) { - case ResolveSymbolOk: - case ResolveSymbolNotFound: - case ResolveSymbolError: - return r1; - case ResolveSymbolAmbiguous: - break; - } - // Filter out - errorMessage->clear(); - const QRegExp re(pattern); - if (!re.isValid()) { - *errorMessage = QString::fromLatin1("Internal error: Invalid pattern '%1'.").arg(pattern); - return ResolveSymbolError; - } - const QStringList filteredMatches = matches.filter(re); - if (filteredMatches.size() == 1) { - *symbol = filteredMatches.front(); - return ResolveSymbolOk; - } - // something went wrong - const QString matchesString = matches.join(QString(QLatin1Char(','))); - if (filteredMatches.empty()) { - *errorMessage = QString::fromLatin1("None of symbols '%1' found for '%2' matches '%3'."). - arg(matchesString, *symbol, pattern); - return ResolveSymbolNotFound; - } - *errorMessage = QString::fromLatin1("Ambiguous match of symbols '%1' found for '%2' (%3)"). - arg(matchesString, *symbol, pattern); - return ResolveSymbolAmbiguous; -} - -// List symbols of a module -bool getModuleSymbols(CIDebugSymbols *syms, const QString &moduleName, - Symbols *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(reinterpret_cast<PCWSTR>(name.utf16()), &offset))) - symbol.address = hexPrefix + QString::number(offset, 16); - symbols->push_back(symbol); - } - return true; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h deleted file mode 100644 index 067379aa1f005a61cea390bc469e5e0ca4066262..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbmodules.h +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBMODULES_H -#define CDBMODULES_H - -#include <QtCore/QStringList> -#include <QtCore/QVector> - -#include "cdbcom.h" - -namespace Debugger { -namespace Internal { - -class Module; -class Symbol; -typedef QVector<Module> Modules; -typedef QVector<Symbol> Symbols; - -bool getModuleList(CIDebugSymbols *syms, Modules *modules, QString *errorMessage); -bool getModuleNameList(CIDebugSymbols *syms, QStringList *modules, QString *errorMessage); -bool getModuleByOffset(CIDebugSymbols *syms, quint64 offset, Module *module, QString *errorMessage); - -// Search symbols matching a pattern. Does not filter on module names. -bool searchSymbols(CIDebugSymbols *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 }; - -// Resolve a symbol that is unique to all modules -ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, QString *symbol, QString *errorMessage); - -// Resolve symbol overload with an additional regexp pattern to filter on modules. -ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, const QString &pattern, QString *symbol, QString *errorMessage); - -// List symbols of a module -bool getModuleSymbols(CIDebugSymbols *syms, const QString &moduleName, - Symbols *symbols, QString *errorMessage); - -} // namespace Internal -} // namespace Debugger - -#endif // CDBMODULES_H diff --git a/src/plugins/debugger/cdb/cdboptions.cpp b/src/plugins/debugger/cdb/cdboptions.cpp deleted file mode 100644 index 85cada164ea1860f710912684a39f93170ce7015..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdboptions.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdboptions.h" -#include "coreengine.h" -#include "cdbsymbolpathlisteditor.h" - -#include <QtCore/QSettings> -#include <QtCore/QDir> -#include <QtCore/QFileInfo> - -static const char *settingsGroupC = "CDB"; -static const char *enabledKeyC = "Enabled"; -static const char *pathKeyC = "Path"; -static const char *symbolPathsKeyC = "SymbolPaths"; -static const char *sourcePathsKeyC = "SourcePaths"; -static const char *breakOnExceptionKeyC = "BreakOnException"; -static const char *verboseSymbolLoadingKeyC = "VerboseSymbolLoading"; -static const char *fastLoadDebuggingHelpersKeyC = "FastLoadDebuggingHelpers"; - -namespace Debugger { -namespace Internal { - -CdbOptions::CdbOptions() : - enabled(false), - breakOnException(false), - verboseSymbolLoading(false), - fastLoadDebuggingHelpers(true) -{ -} - -QString CdbOptions::settingsGroup() -{ - return QLatin1String(settingsGroupC); -} - -void CdbOptions::clear() -{ - enabled = false; - verboseSymbolLoading = false; - fastLoadDebuggingHelpers = true; - path.clear(); -} - -void CdbOptions::fromSettings(const QSettings *s) -{ - clear(); - // Is this the first time we are called -> - // try to find automatically - const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/'); - const QString enabledKey = keyRoot + QLatin1String(enabledKeyC); - const bool firstTime = !s->contains(enabledKey); - if (firstTime) { - enabled = CdbCore::CoreEngine::autoDetectPath(&path); - return; - } - enabled = s->value(enabledKey, false).toBool(); - path = s->value(keyRoot + QLatin1String(pathKeyC), QString()).toString(); - symbolPaths = s->value(keyRoot + QLatin1String(symbolPathsKeyC), QStringList()).toStringList(); - sourcePaths = s->value(keyRoot + QLatin1String(sourcePathsKeyC), QStringList()).toStringList(); - verboseSymbolLoading = s->value(keyRoot + QLatin1String(verboseSymbolLoadingKeyC), false).toBool(); - fastLoadDebuggingHelpers = s->value(keyRoot + QLatin1String(fastLoadDebuggingHelpersKeyC), true).toBool(); - breakOnException = s->value(keyRoot + QLatin1String(breakOnExceptionKeyC), false).toBool(); -} - -void CdbOptions::toSettings(QSettings *s) const -{ - s->beginGroup(QLatin1String(settingsGroupC)); - s->setValue(QLatin1String(enabledKeyC), enabled); - s->setValue(QLatin1String(pathKeyC), path); - s->setValue(QLatin1String(symbolPathsKeyC), symbolPaths); - s->setValue(QLatin1String(sourcePathsKeyC), sourcePaths); - s->setValue(QLatin1String(verboseSymbolLoadingKeyC), verboseSymbolLoading); - s->setValue(QLatin1String(fastLoadDebuggingHelpersKeyC), fastLoadDebuggingHelpers); - s->setValue(QLatin1String(breakOnExceptionKeyC), breakOnException); - s->endGroup(); -} - -unsigned CdbOptions::compare(const CdbOptions &rhs) const -{ - unsigned rc = 0; - if (enabled != rhs.enabled || path != rhs.path) - rc |= InitializationOptionsChanged; - if (symbolPaths != rhs.symbolPaths || sourcePaths != rhs.sourcePaths) - rc |= DebuggerPathsChanged; - if (verboseSymbolLoading != rhs.verboseSymbolLoading) - rc |= SymbolOptionsChanged; - if (fastLoadDebuggingHelpers != rhs.fastLoadDebuggingHelpers) - rc |= FastLoadDebuggingHelpersChanged; - if (breakOnException != rhs.breakOnException) - rc |= OtherOptionsChanged; - return rc; -} - -QString CdbOptions::symbolServerPath(const QString &cacheDir) -{ - return CdbSymbolPathListEditor::symbolServerPath(cacheDir); -} - -int CdbOptions::indexOfSymbolServerPath(const QStringList &symbolPaths, QString *cacheDir) -{ - return CdbSymbolPathListEditor::indexOfSymbolServerPath(symbolPaths, cacheDir); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdboptions.h b/src/plugins/debugger/cdb/cdboptions.h deleted file mode 100644 index 8d2146eef2f162ec9444d446d28fcbaf61f11c1d..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdboptions.h +++ /dev/null @@ -1,88 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBSETTINGS_H -#define CDBSETTINGS_H - -#include <QtCore/QStringList> - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Debugger { -namespace Internal { - -struct CdbOptions -{ -public: - CdbOptions(); - void clear(); - - void fromSettings(const QSettings *s); - void toSettings(QSettings *s) const; - - // A set of flags for comparison function. - enum ChangeFlags { InitializationOptionsChanged = 0x1, - DebuggerPathsChanged = 0x2, - SymbolOptionsChanged = 0x4, - FastLoadDebuggingHelpersChanged = 0x8, - OtherOptionsChanged = 0x100 - }; - unsigned compare(const CdbOptions &s) const; - - // Format a symbol server specification with a cache directory - static QString symbolServerPath(const QString &cacheDir); - // Check whether the path is a symbol server specification and return the cache directory - static int indexOfSymbolServerPath(const QStringList &symbolPaths, QString *cacheDir = 0); - - static QString settingsGroup(); - - bool enabled; - QString path; - QStringList symbolPaths; - QStringList sourcePaths; - bool breakOnException; - bool verboseSymbolLoading; - bool fastLoadDebuggingHelpers; -}; - -inline bool operator==(const CdbOptions &s1, const CdbOptions &s2) -{ return s1.compare(s2) == 0u; } -inline bool operator!=(const CdbOptions &s1, const CdbOptions &s2) -{ return s1.compare(s2) != 0u; } - -} // namespace Internal -} // namespace Debugger - -#endif // CDBSETTINGS_H diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp deleted file mode 100644 index b0bd55ccfda43aa71e82286beee905ef7265e38f..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdboptionspage.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdboptionspage.h" -#include "cdboptions.h" -#include "debuggerconstants.h" -#include "coreengine.h" - -#include <coreplugin/icore.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QUrl> -#include <QtCore/QTextStream> -#include <QtGui/QMessageBox> -#include <QtGui/QDesktopServices> - -static const char *dgbToolsDownloadLink32C = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx"; -static const char *dgbToolsDownloadLink64C = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx"; - -namespace Debugger { -namespace Internal { - -static inline QString msgPathConfigNote() -{ -#ifdef Q_OS_WIN64 - const bool is64bit = true; -#else - const bool is64bit = false; -#endif - const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C); - //: Label text for path configuration. %2 is "x-bit version". - return CdbOptionsPageWidget::tr( - "<html><body><p>Specify the path to the " - "<a href=\"%1\">Debugging Tools for Windows</a>" - " (%2) here.</p>" - "<p><b>Note:</b> Restarting Qt Creator is required for these settings to take effect.</p></p>" - "</body></html>").arg(link, (is64bit ? CdbOptionsPageWidget::tr("64-bit version") - : CdbOptionsPageWidget::tr("32-bit version"))); -} - -CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) : - QWidget(parent) -{ - m_ui.setupUi(this); - m_ui.noteLabel->setText(msgPathConfigNote()); - m_ui.noteLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - connect(m_ui.noteLabel, SIGNAL(linkActivated(QString)), this, SLOT(downLoadLinkActivated(QString))); - - m_ui.pathChooser->setExpectedKind(Utils::PathChooser::Directory); - m_ui.pathChooser->addButton(tr("Autodetect"), this, SLOT(autoDetect())); - m_ui.failureLabel->setVisible(false); -} - - -void CdbOptionsPageWidget::setOptions(CdbOptions &o) -{ - m_ui.pathChooser->setPath(o.path); - m_ui.cdbPathGroupBox->setChecked(o.enabled); - m_ui.symbolPathListEditor->setPathList(o.symbolPaths); - m_ui.sourcePathListEditor->setPathList(o.sourcePaths); - m_ui.verboseSymbolLoadingCheckBox->setChecked(o.verboseSymbolLoading); - m_ui.fastLoadDebuggingHelpersCheckBox->setChecked(o.fastLoadDebuggingHelpers); - m_ui.breakOnExceptionCheckBox->setChecked(o.breakOnException); -} - -CdbOptions CdbOptionsPageWidget::options() const -{ - CdbOptions rc; - rc.path = m_ui.pathChooser->path(); - rc.enabled = m_ui.cdbPathGroupBox->isChecked(); - rc.symbolPaths = m_ui.symbolPathListEditor->pathList(); - rc.sourcePaths = m_ui.sourcePathListEditor->pathList(); - rc.verboseSymbolLoading = m_ui.verboseSymbolLoadingCheckBox->isChecked(); - rc.fastLoadDebuggingHelpers = m_ui.fastLoadDebuggingHelpersCheckBox->isChecked(); - rc.breakOnException = m_ui.breakOnExceptionCheckBox->isChecked(); - return rc; -} - -void CdbOptionsPageWidget::autoDetect() -{ - QString path; - QStringList checkedDirectories; - const bool ok = CdbCore::CoreEngine::autoDetectPath(&path, &checkedDirectories); - m_ui.cdbPathGroupBox->setChecked(ok); - if (ok) { - m_ui.pathChooser->setPath(path); - } else { - const QString msg = tr("\"Debugging Tools for Windows\" could not be found."); - const QString details = tr("Checked:\n%1").arg(checkedDirectories.join(QString(QLatin1Char('\n')))); - QMessageBox msbBox(QMessageBox::Information, tr("Autodetection"), msg, QMessageBox::Ok, this); - msbBox.setDetailedText(details); - msbBox.exec(); - } -} - -void CdbOptionsPageWidget::setFailureMessage(const QString &msg) -{ - m_ui.failureLabel->setText(msg); - m_ui.failureLabel->setVisible(!msg.isEmpty()); -} - -void CdbOptionsPageWidget::downLoadLinkActivated(const QString &link) -{ - QDesktopServices::openUrl(QUrl(link)); -} - -QString CdbOptionsPageWidget::searchKeywords() const -{ - QString rc; - QTextStream(&rc) << m_ui.pathLabel->text() << ' ' << m_ui.symbolPathLabel->text() - << ' ' << m_ui.sourcePathLabel->text() - << ' ' << m_ui.verboseSymbolLoadingCheckBox->text() - << ' ' << m_ui.fastLoadDebuggingHelpersCheckBox->text() - << ' ' << m_ui.breakOnExceptionCheckBox->text(); - rc.remove(QLatin1Char('&')); - return rc; -} - -// ---------- CdbOptionsPage -CdbOptionsPage::CdbOptionsPage() : - m_options(new CdbOptions) -{ - m_options->fromSettings(Core::ICore::instance()->settings()); -} - -CdbOptionsPage::~CdbOptionsPage() -{ -} - -QString CdbOptionsPage::settingsId() -{ - return QLatin1String("F.Cdb"); -} - -QString CdbOptionsPage::displayName() const -{ - return tr("CDB"); -} - -QString CdbOptionsPage::category() const -{ - return QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY); -} - -QString CdbOptionsPage::displayCategory() const -{ - return QCoreApplication::translate("Debugger", Debugger::Constants::DEBUGGER_SETTINGS_TR_CATEGORY); -} - -QIcon CdbOptionsPage::categoryIcon() const -{ - return QIcon(QLatin1String(Debugger::Constants::DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); -} - -QWidget *CdbOptionsPage::createPage(QWidget *parent) -{ - m_widget = new CdbOptionsPageWidget(parent); - m_widget->setOptions(*m_options); - m_widget->setFailureMessage(m_failureMessage); - if (m_searchKeywords.isEmpty()) - m_searchKeywords = m_widget->searchKeywords(); - return m_widget; -} - -void CdbOptionsPage::apply() -{ - if (!m_widget) - return; - const CdbOptions newOptions = m_widget->options(); - if (unsigned changedMask = m_options->compare(newOptions)) { - *m_options = newOptions; - m_options->toSettings(Core::ICore::instance()->settings()); - // Paths changed? - if (changedMask & CdbOptions::DebuggerPathsChanged) { - emit debuggerPathsChanged(); - changedMask &= ~CdbOptions::DebuggerPathsChanged; - } - // Remaining options? - if (changedMask) - emit optionsChanged(); - } -} - -void CdbOptionsPage::finish() -{ -} - -bool CdbOptionsPage::matches(const QString &s) const -{ - return m_searchKeywords.contains(s, Qt::CaseInsensitive); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdboptionspage.h b/src/plugins/debugger/cdb/cdboptionspage.h deleted file mode 100644 index 027254cf4ea341d59c4842884af371969548b70d..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdboptionspage.h +++ /dev/null @@ -1,110 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBSETTINGSPAGE_H -#define CDBSETTINGSPAGE_H - -#include "cdboptions.h" - -#include <coreplugin/dialogs/ioptionspage.h> -#include "ui_cdboptionspagewidget.h" - -#include <QtGui/QWidget> -#include <QtCore/QPointer> -#include <QtCore/QSharedPointer> - -namespace Debugger { -namespace Internal { - -class CdbOptionsPageWidget : public QWidget -{ - Q_OBJECT -public: - explicit CdbOptionsPageWidget(QWidget *parent); - - void setOptions(CdbOptions &o); - CdbOptions options() const; - - void setFailureMessage(const QString &); - - QString searchKeywords() const; - -private slots: - void autoDetect(); - void downLoadLinkActivated(const QString &); - -private: - Ui::CdbOptionsPageWidget m_ui; -}; - -class CdbOptionsPage : public Core::IOptionsPage -{ - Q_DISABLE_COPY(CdbOptionsPage) - Q_OBJECT -public: - explicit CdbOptionsPage(); - virtual ~CdbOptionsPage(); - - // IOptionsPage - virtual QString id() const { return settingsId(); } - virtual QString displayName() const; - virtual QString category() const; - virtual QString displayCategory() const; - QIcon categoryIcon() const; - - virtual QWidget *createPage(QWidget *parent); - virtual void apply(); - virtual void finish(); - virtual bool matches(const QString &) const; - - static QString settingsId(); - - // Load failure messages can be displayed here - void setFailureMessage(const QString &msg) { m_failureMessage = msg; } - QSharedPointer<CdbOptions> options() const { return m_options; } - -signals: - void debuggerPathsChanged(); - void optionsChanged(); - -private: - const QSharedPointer<CdbOptions> m_options; - QPointer<CdbOptionsPageWidget> m_widget; - QString m_failureMessage; - QString m_searchKeywords; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // CDBSETTINGSPAGE_H diff --git a/src/plugins/debugger/cdb/cdboptionspagewidget.ui b/src/plugins/debugger/cdb/cdboptionspagewidget.ui deleted file mode 100644 index 60b0e9959952f3473d990f98f0f799efbc4758ac..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdboptionspagewidget.ui +++ /dev/null @@ -1,162 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>CdbOptionsPageWidget</class> - <widget class="QWidget" name="CdbOptionsPageWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>522</width> - <height>512</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QGroupBox" name="cdbPathGroupBox"> - <property name="toolTip"> - <string>These options take effect at the next start of Qt Creator.</string> - </property> - <property name="title"> - <string extracomment="Placeholder">CDB</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QFormLayout" name="formLayout"> - <item row="1" column="0"> - <widget class="QLabel" name="pathLabel"> - <property name="text"> - <string>Path:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="Utils::PathChooser" name="pathChooser" native="true"/> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="noteLabel"> - <property name="text"> - <string notr="true" extracomment="Placeholder">Note: bla, blah</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QGroupBox" name="pathGroupBox"> - <property name="title"> - <string>Debugger Paths</string> - </property> - <layout class="QFormLayout" name="formLayout_2"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="symbolPathLabel"> - <property name="text"> - <string>Symbol paths:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="Debugger::Internal::CdbSymbolPathListEditor" name="symbolPathListEditor" native="true"/> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="sourcePathLabel"> - <property name="text"> - <string>Source paths:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="Utils::PathListEditor" name="sourcePathListEditor" native="true"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="variousOptionsGroupBox"> - <property name="title"> - <string>Other Options</string> - </property> - <layout class="QFormLayout" name="formLayout_3"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <item row="1" column="0" colspan="2"> - <widget class="QCheckBox" name="verboseSymbolLoadingCheckBox"> - <property name="text"> - <string>Verbose symbol loading</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="fastLoadDebuggingHelpersCheckBox"> - <property name="text"> - <string>Fast loading of debugging helpers</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QCheckBox" name="breakOnExceptionCheckBox"> - <property name="text"> - <string>Break on exception</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>203</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="failureLabel"> - <property name="styleSheet"> - <string notr="true">background-color: 'red';</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>Utils::PathChooser</class> - <extends>QWidget</extends> - <header location="global">utils/pathchooser.h</header> - <container>1</container> - </customwidget> - <customwidget> - <class>Utils::PathListEditor</class> - <extends>QWidget</extends> - <header location="global">utils/pathlisteditor.h</header> - <container>1</container> - </customwidget> - <customwidget> - <class>Debugger::Internal::CdbSymbolPathListEditor</class> - <extends>QWidget</extends> - <header>cdbsymbolpathlisteditor.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp deleted file mode 100644 index c28088f2a1f3620087bbc4f13ff2744888c21c0c..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbstackframecontext.h" -#include "cdbengine_p.h" -#include "cdbsymbolgroupcontext.h" -#include "cdbdumperhelper.h" -#include "debuggeractions.h" -#include "watchhandler.h" -#include "coreengine.h" - -#include <utils/savedaction.h> - -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> - -namespace Debugger { -namespace Internal { - -enum { OwnerNewItem, OwnerSymbolGroup, OwnerSymbolGroupDumper , OwnerDumper }; - -typedef QSharedPointer<CdbDumperHelper> SharedPointerCdbDumperHelper; -typedef QList<WatchData> WatchDataList; - -// Predicates for parametrizing the symbol group -inline bool truePredicate(const WatchData & /* whatever */) { return true; } -inline bool falsePredicate(const WatchData & /* whatever */) { return false; } -inline bool isDumperPredicate(const WatchData &wd) -{ return (wd.source & CdbStackFrameContext::SourceMask) == OwnerDumper; } - -static inline void debugWatchDataList(const QList<WatchData> &l, const char *why = 0) -{ - QDebug nospace = qDebug().nospace(); - if (why) - nospace << why << '\n'; - foreach(const WatchData &wd, l) - nospace << wd.toString() << '\n'; - nospace << '\n'; -} - -// Match an item that is expanded in the watchhandler. -class WatchHandlerExpandedPredicate { -public: - explicit inline WatchHandlerExpandedPredicate(const WatchHandler *wh) : m_wh(wh) {} - inline bool operator()(const WatchData &wd) { return m_wh->isExpandedIName(wd.iname); } -private: - const WatchHandler *m_wh; -}; - -// Match an item by iname -class MatchINamePredicate { -public: - explicit inline MatchINamePredicate(const QString &iname) : m_iname(iname) {} - inline bool operator()(const WatchData &wd) { return wd.iname == m_iname; } -private: - const QString &m_iname; -}; - -// Put a sequence of WatchData into the model for the non-dumper case -class WatchHandlerModelInserter { -public: - explicit WatchHandlerModelInserter(WatchHandler *wh) : m_wh(wh) {} - - inline WatchHandlerModelInserter & operator*() { return *this; } - inline WatchHandlerModelInserter &operator=(const WatchData &wd) { - m_wh->insertData(wd); - return *this; - } - inline WatchHandlerModelInserter &operator++() { return *this; } - -private: - WatchHandler *m_wh; -}; - -// Put a sequence of WatchData into the model for the dumper case. -// Sorts apart a sequence of WatchData using the Dumpers. -// Puts the stuff for which there is no dumper in the model -// as is and sets ownership to symbol group. The rest goes -// to the dumpers. Additionally, checks for items pointing to a -// dumpeable type and inserts a fake dereferenced item and value. -class WatchHandleDumperInserter { -public: - explicit WatchHandleDumperInserter(WatchHandler *wh, - const SharedPointerCdbDumperHelper &dumper); - - inline WatchHandleDumperInserter & operator*() { return *this; } - inline WatchHandleDumperInserter &operator=(WatchData &wd); - inline WatchHandleDumperInserter &operator++() { return *this; } - -private: - bool expandPointerToDumpable(const WatchData &wd, QString *errorMessage); - - const QRegExp m_hexNullPattern; - WatchHandler *m_wh; - const SharedPointerCdbDumperHelper m_dumper; - QList<WatchData> m_dumperResult; -}; - -WatchHandleDumperInserter::WatchHandleDumperInserter(WatchHandler *wh, - const SharedPointerCdbDumperHelper &dumper) : - m_hexNullPattern(QLatin1String("0x0+")), - m_wh(wh), - m_dumper(dumper) -{ - Q_ASSERT(m_hexNullPattern.isValid()); -} - -// Prevent recursion of the model by setting value and type -static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0) -{ - const bool missing = wd->isTypeNeeded() || wd->type.isEmpty(); - if (missing) { - static const QString unknownType = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Type>"); - wd->setType(source ? source->type : unknownType, false); - } - return missing; -} - -static inline bool fixDumperValue(WatchData *wd, const WatchData *source = 0) -{ - const bool missing = wd->isValueNeeded(); - if (missing) { - if (source && source->isValueKnown()) { - wd->setValue(source->value); - } else { - static const QString unknownValue = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Value>"); - wd->setValue(unknownValue); - } - } - return missing; -} - -// When querying an item, the queried item is sometimes returned in incomplete form. -// Take over values from source. -static inline void fixDumperResult(const WatchData &source, - QList<WatchData> *result, - bool suppressGrandChildren) -{ - - const int size = result->size(); - if (!size) - return; - if (debugCDBWatchHandling) - debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult"); - WatchData &returned = result->front(); - if (returned.iname != source.iname) - return; - fixDumperType(&returned, &source); - fixDumperValue(&returned, &source); - // Indicate owner and known children - returned.source = OwnerDumper; - if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren) - returned.source |= CdbStackFrameContext::ChildrenKnownBit; - if (size == 1) - return; - // If the model queries the expanding item by pretending childrenNeeded=1, - // refuse the request as the children are already known - returned.source |= CdbStackFrameContext::ChildrenKnownBit; - // Fix the children: If the address is missing, we cannot query any further. - const QList<WatchData>::iterator wend = result->end(); - QList<WatchData>::iterator it = result->begin(); - for (++it; it != wend; ++it) { - WatchData &wd = *it; - // Indicate owner and known children - it->source = OwnerDumper; - if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren) - it->source |= CdbStackFrameContext::ChildrenKnownBit; - // Cannot dump items with missing addresses or missing types - const bool typeFixed = fixDumperType(&wd); // Order of evaluation! - if ((wd.addr.isEmpty() && wd.isSomethingNeeded()) || typeFixed) { - wd.setHasChildren(false); - wd.setAllUnneeded(); - } else { - // Hack: Suppress endless recursion of the model. To be fixed, - // the model should not query non-visible items. - if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded())) - wd.setHasChildren(false); - } - } - if (debugCDBWatchHandling) - debugWatchDataList(*result, "<fixDumperResult"); -} - -// Is this a non-null pointer to a dumpeable item with a value -// "0x4343 class QString *" ? - Insert a fake '*' dereferenced item -// and run dumpers on it. If that succeeds, insert the fake items owned by dumpers, -// which will trigger the ignore predicate. -// Note that the symbol context does not create '*' dereferenced items for -// classes (see note in its header documentation). -bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug() << ">expandPointerToDumpable" << wd.toString(); - - bool handled = false; - do { - if (wd.error || !isPointerType(wd.type)) - break; - const int classPos = wd.value.indexOf(" class "); - if (classPos == -1) - break; - const QString hexAddrS = wd.value.mid(0, classPos); - if (m_hexNullPattern.exactMatch(hexAddrS)) - break; - const QString type = stripPointerType(wd.value.mid(classPos + 7)); - WatchData derefedWd; - derefedWd.setType(type); - derefedWd.setAddress(hexAddrS); - derefedWd.name = QString(QLatin1Char('*')); - derefedWd.iname = wd.iname + ".*"; - derefedWd.source = OwnerDumper | CdbStackFrameContext::ChildrenKnownBit; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage); - if (dr != CdbDumperHelper::DumpOk) - break; - fixDumperResult(derefedWd, &m_dumperResult, false); - // Insert the pointer item with 1 additional child + its dumper results - // Note: formal arguments might already be expanded in the symbol group. - WatchData ptrWd = wd; - ptrWd.source = OwnerDumper | CdbStackFrameContext::ChildrenKnownBit; - ptrWd.setHasChildren(true); - ptrWd.setChildrenUnneeded(); - m_wh->insertData(ptrWd); - m_wh->insertBulkData(m_dumperResult); - handled = true; - } while (false); - if (debugCDBWatchHandling) - qDebug() << "<expandPointerToDumpable returns " << handled << *errorMessage; - return handled; -} - -WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd) -{ - if (debugCDBWatchHandling) - qDebug() << "WatchHandleDumperInserter::operator=" << wd.toString(); - // Check pointer to dumpeable, dumpeable, insert accordingly. - QString errorMessage; - if (expandPointerToDumpable(wd, &errorMessage)) { - // Nasty side effect: Modify owner for the ignore predicate - wd.source = OwnerDumper; - return *this; - } - // Expanded by internal dumper? : ok - if ((wd.source & CdbStackFrameContext::SourceMask) == OwnerSymbolGroupDumper) { - m_wh->insertData(wd); - return *this; - } - // Try library dumpers. - switch (m_dumper->dumpType(wd, true, &m_dumperResult, &errorMessage)) { - case CdbDumperHelper::DumpOk: - if (debugCDBWatchHandling) - qDebug() << "dumper triggered"; - // Dumpers omit types for complicated templates - fixDumperResult(wd, &m_dumperResult, false); - // Discard the original item and insert the dumper results - m_wh->insertBulkData(m_dumperResult); - // Nasty side effect: Modify owner for the ignore predicate - wd.source = OwnerDumper; - break; - case CdbDumperHelper::DumpNotHandled: - case CdbDumperHelper::DumpError: - wd.source = OwnerSymbolGroup; - m_wh->insertData(wd); - break; - } - return *this; -} - -// -----------CdbStackFrameContext -CdbStackFrameContext::CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper, - CdbSymbolGroupContext *symbolContext) : - m_useDumpers(dumper->isEnabled() && debuggerCore()->boolSetting(UseDebuggingHelpers)), - m_dumper(dumper), - m_symbolContext(symbolContext) -{ -} - -bool CdbStackFrameContext::assignValue(const QString &iname, const QString &value, - QString *newValue /* = 0 */, QString *errorMessage) -{ - return m_symbolContext->assignValue(iname, value, newValue, errorMessage); -} - -bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug() << "populateModelInitially dumpers=" << m_useDumpers; - // Recurse down items that are initially expanded in the view, stop processing for - // dumper items. - const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper); - const bool rc = m_useDumpers ? - CdbSymbolGroupContext::populateModelInitiallyHelper(rctx, - WatchHandleDumperInserter(wh, m_dumper), - WatchHandlerExpandedPredicate(wh), - isDumperPredicate, - errorMessage) : - CdbSymbolGroupContext::populateModelInitiallyHelper(rctx, - WatchHandlerModelInserter(wh), - WatchHandlerExpandedPredicate(wh), - falsePredicate, - errorMessage); - return rc; -} - -bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal, - WatchHandler *wh, - QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug() << ">completeData src=" << incompleteLocal.source << incompleteLocal.toString(); - - const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper); - // Expand symbol group items, recurse one level from desired item - if (!m_useDumpers) { - return CdbSymbolGroupContext::completeDataHelper(rctx, incompleteLocal, - WatchHandlerModelInserter(wh), - MatchINamePredicate(incompleteLocal.iname), - falsePredicate, - errorMessage); - } - - // Expand artifical dumper items - if ((incompleteLocal.source & CdbStackFrameContext::SourceMask) == OwnerDumper) { - // If the model queries the expanding item by pretending childrenNeeded=1, - // refuse the request if the children are already known - if (incompleteLocal.state == WatchData::ChildrenNeeded && (incompleteLocal.source & CdbStackFrameContext::ChildrenKnownBit)) { - WatchData local = incompleteLocal; - local.setChildrenUnneeded(); - wh->insertData(local); - return true; - } - QList<WatchData> dumperResult; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, &dumperResult, errorMessage); - if (dr == CdbDumperHelper::DumpOk) { - // Hack to stop endless model recursion - const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname); - fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren); - wh->insertBulkData(dumperResult); - } else { - const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage); - qWarning("%s", qPrintable(msg)); - WatchData wd = incompleteLocal; - if (wd.isValueNeeded()) - wd.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>")); - wd.setHasChildren(false); - wd.setAllUnneeded(); - wh->insertData(wd); - } - return true; - } - - // Expand symbol group items, recurse one level from desired item - return CdbSymbolGroupContext::completeDataHelper(rctx, incompleteLocal, - WatchHandleDumperInserter(wh, m_dumper), - MatchINamePredicate(incompleteLocal.iname), - isDumperPredicate, - errorMessage); -} - -CdbStackFrameContext::~CdbStackFrameContext() -{ - delete m_symbolContext; -} - -bool CdbStackFrameContext::editorToolTip(const QString &iname, - QString *value, - QString *errorMessage) -{ - value->clear(); - unsigned long index; - if (!m_symbolContext->lookupPrefix(iname, &index)) { - *errorMessage = QString::fromLatin1("%1 not found.").arg(iname); - return false; - } - // Check dumpers. Should actually be just one item. - - WatchData wd; - const unsigned rc = m_symbolContext->watchDataAt(index, &wd); - if (m_useDumpers && !wd.error - && (0u == (rc & CdbCore::SymbolGroupContext::InternalDumperMask)) - && m_dumper->state() != CdbDumperHelper::Disabled) { - QList<WatchData> result; - if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage)) { - foreach (const WatchData &dwd, result) { - if (!value->isEmpty()) - value->append(QLatin1Char('\n')); - value->append(dwd.toToolTip()); - } - return true; - } // Dumped ok - } // has Dumpers - *value = wd.toToolTip(); - return true; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp deleted file mode 100644 index 10b16acdfd79cd5935917e892ae20161ad9a0ad5..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbstacktracecontext.h" - -#include "cdbsymbolgroupcontext.h" -#include "cdbdumperhelper.h" -#include "cdbengine_p.h" -#include "debuggeractions.h" -#include "debuggercore.h" -#include "watchutils.h" -#include "threadshandler.h" - -#include <utils/savedaction.h> - -#include <QtCore/QDebug> -#include <QtCore/QFileInfo> - -enum { debug = 0 }; - -namespace Debugger { -namespace Internal { - -CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper) : - CdbCore::StackTraceContext(dumper->comInterfaces()), - m_dumper(dumper) -{ -} - -CdbStackTraceContext *CdbStackTraceContext::create(const QSharedPointer<CdbDumperHelper> &dumper, - QString *errorMessage) -{ - CdbStackTraceContext *ctx = new CdbStackTraceContext(dumper); - if (!ctx->init(UINT_MAX, errorMessage)) { - delete ctx; - return 0; - } - return ctx; -} - -CdbCore::SymbolGroupContext * -CdbStackTraceContext::createSymbolGroup(const CdbCore::ComInterfaces & /* cif */, - int index, - const QString &prefix, - CIDebugSymbolGroup *comSymbolGroup, - QString *errorMessage) -{ - // Exclude uninitialized variables if desired - QStringList uninitializedVariables; - const CdbCore::StackFrame &frame = stackFrameAt(index); - if (debuggerCore()->action(UseCodeModel)->isChecked()) - getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(), - frame.function, frame.fileName, frame.line, &uninitializedVariables); - if (debug) - qDebug() << frame << uninitializedVariables; - CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(prefix, - comSymbolGroup, - m_dumper, - uninitializedVariables, - errorMessage); - if (!sc) { - *errorMessage = msgFrameContextFailed(index, frame, *errorMessage); - return 0; - } - return sc; -} - -CdbSymbolGroupContext *CdbStackTraceContext::cdbSymbolGroupContextAt(int index, QString *errorMessage) -{ - return static_cast<CdbSymbolGroupContext *>(symbolGroupContextAt(index, errorMessage)); -} - -QList<StackFrame> CdbStackTraceContext::stackFrames() const -{ - // Convert from Core data structures - QList<StackFrame> rc; - const int count = frameCount(); - for(int i = 0; i < count; i++) { - const CdbCore::StackFrame &coreFrame = stackFrameAt(i); - StackFrame frame; - frame.level = i; - frame.file = coreFrame.fileName; - frame.usable = !frame.file.isEmpty() && QFileInfo(frame.file).isFile(); - frame.line = coreFrame.line; - frame.function = coreFrame.function; - frame.from = coreFrame.module; - frame.address = coreFrame.address; - rc.push_back(frame); - } - return rc; -} - -bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif, - bool stopped, - Threads *threads, - ULONG *currentThreadId, - QString *errorMessage) -{ - - QVector<CdbCore::Thread> coreThreads; - if (!CdbCore::StackTraceContext::getThreadList(cif, &coreThreads, currentThreadId, errorMessage)) - return false; - // Get frames only if stopped. - QVector<CdbCore::StackFrame> frames; - if (stopped) - if (!CdbCore::StackTraceContext::getStoppedThreadFrames(cif, *currentThreadId, - coreThreads, &frames, errorMessage)) - return false; - // Convert from Core data structures - threads->clear(); - const int count = coreThreads.size(); - if (!count) - return true; - threads->reserve(count); - const QChar slash(QLatin1Char('/')); - for (int i = 0; i < count; i++) { - const CdbCore::Thread &coreThread = coreThreads.at(i); - ThreadData data(coreThread.id); - data.targetId = QLatin1String("0x") + QString::number(coreThread.systemId); - data.name = coreThread.name; - if (stopped) { - const CdbCore::StackFrame &coreFrame = frames.at(i); - data.address = coreFrame.address; - data.function = coreFrame.function; - data.lineNumber = coreFrame.line; - // Basename only for brevity - const int slashPos = coreFrame.fileName.lastIndexOf(slash); - data.fileName = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1); - } - threads->push_back(data); - } - return true; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h deleted file mode 100644 index 4c3d287afa4a81fc346dcd3d2e1cc9318cdb8f4f..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ /dev/null @@ -1,101 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBSTACKTRACECONTEXT_H -#define CDBSTACKTRACECONTEXT_H - -#include "stackhandler.h" -#include "stacktracecontext.h" -#include "threadshandler.h" - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QSharedPointer> - -QT_BEGIN_NAMESPACE -class QTextStream; -QT_END_NAMESPACE - -namespace CdbCore { - struct ComInterfaces; -} - -namespace Debugger { -namespace Internal { - -class CdbSymbolGroupContext; -class CdbStackFrameContext; -class CdbDumperHelper; -struct ThreadData; - -/* CdbStackTraceContext: Bridges CdbCore data structures and - * Debugger structures and handles CdbSymbolGroupContext's. */ - -class CdbStackTraceContext : public CdbCore::StackTraceContext -{ - Q_DISABLE_COPY(CdbStackTraceContext) - - explicit CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper); - -public: - static CdbStackTraceContext *create(const QSharedPointer<CdbDumperHelper> &dumper, - QString *errorMessage); - - CdbSymbolGroupContext *cdbSymbolGroupContextAt(int index, QString *errorMessage); - - QList<StackFrame> stackFrames() const; - - // get threads in stopped state - static bool getThreads(const CdbCore::ComInterfaces &cif, - bool stopped, - Threads *threads, - ULONG *currentThreadId, - QString *errorMessage); - -protected: - virtual CdbCore::SymbolGroupContext *createSymbolGroup(const CdbCore::ComInterfaces &cif, - int index, - const QString &prefix, - CIDebugSymbolGroup *comSymbolGroup, - QString *errorMessage); - -private: - const QSharedPointer<CdbDumperHelper> m_dumper; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // CDBSTACKTRACECONTEXT_H diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp deleted file mode 100644 index 89be4bf7c6e62e33f9afcbb1c30eb3a8a8bdb7fd..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbsymbolgroupcontext.h" -#include "cdbengine_p.h" -#include "cdbdumperhelper.h" -#include "watchhandler.h" -#include "watchutils.h" -#include "debuggeractions.h" -#include "coreengine.h" -#include "debuggercore.h" - -#include <QtCore/QDebug> -#include <QtCore/QTextStream> -#include <QtCore/QCoreApplication> -#include <QtCore/QRegExp> - -enum { debug = 0 }; -enum { debugInternalDumpers = 0 }; - -namespace Debugger { -namespace Internal { - -enum { OwnerNewItem, OwnerSymbolGroup, OwnerSymbolGroupDumper , OwnerDumper }; - -typedef QSharedPointer<CdbDumperHelper> SharedPointerCdbDumperHelper; -typedef QList<WatchData> WatchDataList; - -// Predicates for parametrizing the symbol group -inline bool truePredicate(const WatchData & /* whatever */) { return true; } -inline bool falsePredicate(const WatchData & /* whatever */) { return false; } -inline bool isDumperPredicate(const WatchData &wd) -{ return (wd.source & CdbSymbolGroupContext::SourceMask) == OwnerDumper; } - -static inline void debugWatchDataList(const QList<WatchData> &l, const char *why = 0) -{ - QDebug nospace = qDebug().nospace(); - if (why) - nospace << why << '\n'; - foreach(const WatchData &wd, l) - nospace << wd.toString() << '\n'; - nospace << '\n'; -} - -// Match an item that is expanded in the watchhandler. -class WatchHandlerExpandedPredicate { -public: - explicit inline WatchHandlerExpandedPredicate(const WatchHandler *wh) : m_wh(wh) {} - inline bool operator()(const WatchData &wd) { return m_wh->isExpandedIName(wd.iname); } -private: - const WatchHandler *m_wh; -}; - -// Match an item by iname -class MatchINamePredicate { -public: - explicit inline MatchINamePredicate(const QString &iname) : m_iname(iname) {} - inline bool operator()(const WatchData &wd) { return wd.iname == m_iname; } -private: - const QString &m_iname; -}; - -// Put a sequence of WatchData into the model for the non-dumper case -class WatchHandlerModelInserter { -public: - explicit WatchHandlerModelInserter(WatchHandler *wh) : m_wh(wh) {} - - inline WatchHandlerModelInserter & operator*() { return *this; } - inline WatchHandlerModelInserter &operator=(const WatchData &wd) { - m_wh->insertData(wd); - return *this; - } - inline WatchHandlerModelInserter &operator++() { return *this; } - -private: - WatchHandler *m_wh; -}; - -// Put a sequence of WatchData into the model for the dumper case. -// Sorts apart a sequence of WatchData using the Dumpers. -// Puts the stuff for which there is no dumper in the model -// as is and sets ownership to symbol group. The rest goes -// to the dumpers. Additionally, checks for items pointing to a -// dumpeable type and inserts a fake dereferenced item and value. -class WatchHandleDumperInserter { -public: - explicit WatchHandleDumperInserter(WatchHandler *wh, - const SharedPointerCdbDumperHelper &dumper); - - inline WatchHandleDumperInserter & operator*() { return *this; } - inline WatchHandleDumperInserter &operator=(WatchData &wd); - inline WatchHandleDumperInserter &operator++() { return *this; } - -private: - bool expandPointerToDumpable(const WatchData &wd, QString *errorMessage); - - const QRegExp m_hexNullPattern; - WatchHandler *m_wh; - const SharedPointerCdbDumperHelper m_dumper; - QList<WatchData> m_dumperResult; -}; - -WatchHandleDumperInserter::WatchHandleDumperInserter(WatchHandler *wh, - const SharedPointerCdbDumperHelper &dumper) : - m_hexNullPattern(QLatin1String("0x0+")), - m_wh(wh), - m_dumper(dumper) -{ - Q_ASSERT(m_hexNullPattern.isValid()); -} - -// Prevent recursion of the model by setting value and type -static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0) -{ - const bool missing = wd->isTypeNeeded() || wd->type.isEmpty(); - if (missing) { - static const QByteArray unknownType = - QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown Type>") - .toUtf8(); - wd->setType(source ? source->type : unknownType, false); - } - return missing; -} - -static inline bool fixDumperValue(WatchData *wd, const WatchData *source = 0) -{ - const bool missing = wd->isValueNeeded(); - if (missing) { - if (source && source->isValueKnown()) { - wd->setValue(source->value); - } else { - static const QString unknownValue = QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown Value>"); - wd->setValue(unknownValue); - } - } - return missing; -} - -// When querying an item, the queried item is sometimes returned in incomplete form. -// Take over values from source. -static inline void fixDumperResult(const WatchData &source, - QList<WatchData> *result, - bool suppressGrandChildren) -{ - - const int size = result->size(); - if (!size) - return; - if (debugCDBWatchHandling) - debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult"); - WatchData &returned = result->front(); - if (returned.iname != source.iname) - return; - fixDumperType(&returned, &source); - fixDumperValue(&returned, &source); - // Indicate owner and known children - returned.source = OwnerDumper; - if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren) - returned.source |= CdbSymbolGroupContext::ChildrenKnownBit; - if (size == 1) - return; - // If the model queries the expanding item by pretending childrenNeeded=1, - // refuse the request as the children are already known - returned.source |= CdbSymbolGroupContext::ChildrenKnownBit; - // Fix the children: Assign sort id , if the address is missing, we cannot query any further. - const int resultSize = result->size(); - for (int i = 1; i < resultSize; i++) { - WatchData &wd = (*result)[i]; - wd.sortId = i; - // Indicate owner and known children - wd.source = OwnerDumper; - if (wd.isChildrenKnown() && wd.isHasChildrenKnown() && wd.hasChildren) - wd.source |= CdbSymbolGroupContext::ChildrenKnownBit; - // Cannot dump items with missing addresses or missing types - const bool typeFixed = fixDumperType(&wd); // Order of evaluation! - if ((wd.address == 0 && wd.isSomethingNeeded()) || typeFixed) { - wd.setHasChildren(false); - wd.setAllUnneeded(); - } else { - // Hack: Suppress endless recursion of the model. To be fixed, - // the model should not query non-visible items. - if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded())) - wd.setHasChildren(false); - } - } - if (debugCDBWatchHandling) - debugWatchDataList(*result, "<fixDumperResult"); -} - -// Is this a non-null pointer to a dumpeable item with a value -// "0x4343 class QString *" ? - Insert a fake '*' dereferenced item -// and run dumpers on it. If that succeeds, insert the fake items owned by dumpers, -// which will trigger the ignore predicate. -// Note that the symbol context does not create '*' dereferenced items for -// classes (see note in its header documentation). -bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QString *errorMessage) -{ - if (debugCDBWatchHandling > 1) - qDebug() << ">expandPointerToDumpable" << wd.toString(); - - bool handled = false; - do { - // Must be a clas pointer item and a non-null-pointer. - if (wd.error || !(wd.source & CdbSymbolGroupContext::ClassPointerBit) - || !isPointerType(wd.type)) - break; - quint64 address = 0; - if (!CdbCore::SymbolGroupContext::getUnsignedHexValue(wd.value, &address) || address == 0) - break; - const QByteArray type = stripPointerType(wd.type); - WatchData derefedWd; - derefedWd.setType(type); - derefedWd.address = address; - derefedWd.name = QString(QLatin1Char('*')); - derefedWd.iname = wd.iname + ".*"; - derefedWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage); - if (dr != CdbDumperHelper::DumpOk) - break; - fixDumperResult(derefedWd, &m_dumperResult, false); - // Insert the pointer item with 1 additional child + its dumper results - // Note: formal arguments might already be expanded in the symbol group. - WatchData ptrWd = wd; - ptrWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit; - ptrWd.setHasChildren(true); - ptrWd.setChildrenUnneeded(); - m_wh->insertData(ptrWd); - m_wh->insertBulkData(m_dumperResult); - handled = true; - } while (false); - if (debugCDBWatchHandling > 1) - qDebug() << "<expandPointerToDumpable returns " << handled << *errorMessage; - return handled; -} - -WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd) -{ - if (debugCDBWatchHandling) - qDebug() << "WatchHandleDumperInserter::operator=" << wd.toString(); - // Check pointer to dumpeable, dumpeable, insert accordingly. - QString errorMessage; - if (expandPointerToDumpable(wd, &errorMessage)) { - // Nasty side effect: Modify owner for the ignore predicate - wd.source = OwnerDumper; - return *this; - } - // Expanded by internal dumper? : ok - if ((wd.source & CdbSymbolGroupContext::SourceMask) == OwnerSymbolGroupDumper) { - m_wh->insertData(wd); - return *this; - } - // Try library dumpers. - switch (m_dumper->dumpType(wd, true, &m_dumperResult, &errorMessage)) { - case CdbDumperHelper::DumpOk: - if (debugCDBWatchHandling) - qDebug() << "dumper triggered"; - // Dumpers omit types for complicated templates - fixDumperResult(wd, &m_dumperResult, false); - // Discard the original item and insert the dumper results - m_wh->insertBulkData(m_dumperResult); - // Nasty side effect: Modify owner for the ignore predicate - wd.source = OwnerDumper; - break; - case CdbDumperHelper::DumpNotHandled: - case CdbDumperHelper::DumpError: - wd.source = OwnerSymbolGroup; - m_wh->insertData(wd); - break; - } - return *this; -} - - -CdbSymbolGroupRecursionContext::CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, - int ido) : - context(ctx), - internalDumperOwner(ido) -{ -} - -static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p) -{ - if (p.SubElements == 0u) - return CdbSymbolGroupContext::LeafSymbol; - return (p.Flags & DEBUG_SYMBOL_EXPANDED) ? - CdbSymbolGroupContext::ExpandedSymbol : - CdbSymbolGroupContext::CollapsedSymbol; -} - -CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - const QSharedPointer<CdbDumperHelper> &dumper, - const QStringList &uninitializedVariables) : - CdbCore::SymbolGroupContext(prefix, symbolGroup, - dumper->comInterfaces()->debugDataSpaces, - uninitializedVariables), - m_useDumpers(dumper->isEnabled() && debuggerCore()->boolSetting(UseDebuggingHelpers)), - m_dumper(dumper) -{ - setShadowedNameFormat(WatchData::shadowedNameFormat()); -} - -CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - const QSharedPointer<CdbDumperHelper> &dumper, - const QStringList &uninitializedVariables, - QString *errorMessage) -{ - CdbSymbolGroupContext *rc = new CdbSymbolGroupContext(prefix, symbolGroup, - dumper, - uninitializedVariables); - if (!rc->init(errorMessage)) { - delete rc; - return 0; - } - return rc; -} - -// Fix display values: Pass through strings, convert unsigned integers -// to decimal ('0x5454`fedf'), remove inner templates from -// "0x4343 class list<>". -static inline QString fixValue(const QString &value, const QByteArray &type, bool *isClassPointer) -{ - *isClassPointer = false; - // Pass through complete strings. Note that char pointers - // (0x00A "hallo") will be reformatted below. - const QChar doubleQuote = QLatin1Char('"'); - if (value.startsWith(doubleQuote) && value.endsWith(doubleQuote)) - return value; - // Real Integer numbers Unsigned hex numbers (0x)/decimal numbers (0n) - if (type != "bool" && isIntType(type)) { - const QVariant intValue = CdbCore::SymbolGroupContext::getIntValue(value); - if (intValue.isValid()) - return intValue.toString(); - } - /* Pointers: Fix the address and strip off lengthy class type specifications - * "0x00000000`000045AA "hallo" -> "0x45AA "hallo" - * "0x00000000`000045AA class Bla<std::....> *" -> "0x45AA" */ - if (isPointerType(type)) { - quint64 ptrValue; - int endPos; - if (CdbCore::SymbolGroupContext::getUnsignedHexValue(value, &ptrValue, &endPos)) { - QString fixedValue = QString::fromAscii("0x%1").arg(ptrValue, 0, 16); - // What is the second token... - if (endPos < value.size() - 1) { - const QString token = value.mid(endPos + 1); - if (token.startsWith(QLatin1String("class")) || token.startsWith(QLatin1String("struct"))) { - *isClassPointer = true; - } else { - fixedValue += QLatin1Char(' '); - fixedValue += token; - } - } // has token - return fixedValue; - } // pointer value conversion ok - } - return value; -} - -unsigned CdbSymbolGroupContext::watchDataAt(unsigned long index, WatchData *wd) -{ - ULONG typeId; - ULONG64 address; - QString iname; - QString value; - QString type; - const unsigned rc = dumpValue(index, &iname, &(wd->name), &address, - &typeId, &type, &value); - wd->exp = wd->iname = iname.toLatin1(); - wd->setAddress(address); - wd->setType(type.toUtf8(), false); - if (rc & OutOfScope) { - wd->setError(WatchData::msgNotInScope()); - } else { - bool isClassPointer; - wd->setValue(fixValue(value, type.toUtf8(), &isClassPointer)); - if (isClassPointer) - wd->source |= CdbSymbolGroupContext::ClassPointerBit; - const bool hasChildren = rc & HasChildren; - wd->setHasChildren(hasChildren); - if (hasChildren) - wd->setChildrenNeeded(); - } - if (debug > 1) - qDebug() << "watchDataAt" << index << QString::number(rc, 16) << wd->toString(); - return rc; -} - -bool CdbSymbolGroupContext::populateModelInitially(WatchHandler *wh, QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug() << ">populateModelInitially dumpers=" << m_useDumpers; - // Recurse down items that are initially expanded in the view, stop processing for - // dumper items. - const CdbSymbolGroupRecursionContext rctx(this, OwnerSymbolGroupDumper); - const bool rc = m_useDumpers ? - populateModelInitiallyHelper(rctx, - WatchHandleDumperInserter(wh, m_dumper), - WatchHandlerExpandedPredicate(wh), - isDumperPredicate, - errorMessage) : - populateModelInitiallyHelper(rctx, - WatchHandlerModelInserter(wh), - WatchHandlerExpandedPredicate(wh), - falsePredicate, - errorMessage); - if (debugCDBWatchHandling) - qDebug("<populateModelInitially\n%s\n", qPrintable(toString())); - return rc; -} - -bool CdbSymbolGroupContext::completeData(const WatchData &incompleteLocal, - WatchHandler *wh, - QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug(">completeData src=%d %s\n%s\n", - incompleteLocal.source, qPrintable(incompleteLocal.toString()), - qPrintable(toString())); - - const CdbSymbolGroupRecursionContext rctx(this, OwnerSymbolGroupDumper); - // Expand symbol group items, recurse one level from desired item - if (!m_useDumpers) { - return completeDataHelper(rctx, incompleteLocal, - WatchHandlerModelInserter(wh), - MatchINamePredicate(incompleteLocal.iname), - falsePredicate, - errorMessage); - } - - // Expand artifical dumper items - if ((incompleteLocal.source & CdbSymbolGroupContext::SourceMask) == OwnerDumper) { - // If the model queries the expanding item by pretending childrenNeeded=1, - // refuse the request if the children are already known - if (incompleteLocal.state == WatchData::ChildrenNeeded && (incompleteLocal.source & CdbSymbolGroupContext::ChildrenKnownBit)) { - WatchData local = incompleteLocal; - local.setChildrenUnneeded(); - wh->insertData(local); - return true; - } - QList<WatchData> dumperResult; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, &dumperResult, errorMessage); - if (dr == CdbDumperHelper::DumpOk) { - // Hack to stop endless model recursion - const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname); - fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren); - wh->insertBulkData(dumperResult); - } else { - const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4") - .arg(incompleteLocal.name) - .arg(QString::fromUtf8(incompleteLocal.type)) - .arg(int(dr)).arg(*errorMessage); - qWarning("%s", qPrintable(msg)); - WatchData wd = incompleteLocal; - if (wd.isValueNeeded()) - wd.setValue(QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown>")); - wd.setHasChildren(false); - wd.setAllUnneeded(); - wh->insertData(wd); - } - return true; - } - - // Expand symbol group items, recurse one level from desired item - return completeDataHelper(rctx, incompleteLocal, - WatchHandleDumperInserter(wh, m_dumper), - MatchINamePredicate(incompleteLocal.iname), - isDumperPredicate, - errorMessage); -} - -bool CdbSymbolGroupContext::editorToolTip(const QString &iname, - QString *value, - QString *errorMessage) -{ - if (debugToolTips) - qDebug() << iname; - value->clear(); - unsigned long index; - if (!lookupPrefix(iname, &index)) { - *errorMessage = QString::fromLatin1("%1 not found.").arg(iname); - return false; - } - // Check dumpers. Should actually be just one item. - - WatchData wd; - const unsigned rc = watchDataAt(index, &wd); - if (m_useDumpers && !wd.error - && (0u == (rc & CdbCore::SymbolGroupContext::InternalDumperMask)) - && m_dumper->state() != CdbDumperHelper::Disabled) { - QList<WatchData> result; - if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage)) { - foreach (const WatchData &dwd, result) { - if (!value->isEmpty()) - value->append(QLatin1Char('\n')); - value->append(dwd.toToolTip()); - } - return true; - } // Dumped ok - } // has Dumpers - if (debugToolTips) - qDebug() << iname << wd.toString(); - *value = wd.toToolTip(); - return true; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h deleted file mode 100644 index ddf4ee52df915c3800a2fc8770c1946287c9ead9..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ /dev/null @@ -1,173 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBSYMBOLGROUPCONTEXT_H -#define CDBSYMBOLGROUPCONTEXT_H - -#include "cdbcom.h" -#include "symbolgroupcontext.h" - -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QList> -#include <QtCore/QStringList> -#include <QtCore/QSharedPointer> -#include <QtCore/QPair> -#include <QtCore/QMap> -#include <QtCore/QSet> - -namespace Debugger { -namespace Internal { - -class WatchData; -class WatchHandler; -struct CdbSymbolGroupRecursionContext; -class CdbDumperHelper; - - -/* CdbSymbolGroupContext manages a symbol group context and - * a dumper context. It dispatches calls between the local items - * that are handled by the symbol group and those that are handled by the dumpers. */ - -class CdbSymbolGroupContext : public CdbCore::SymbolGroupContext -{ - Q_DISABLE_COPY(CdbSymbolGroupContext); - explicit CdbSymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - const QSharedPointer<CdbDumperHelper> &dumper, - const QStringList &uninitializedVariables); - -public: - // Mask bits for the source field of watch data. - enum { SourceMask = 0xFF, - // We know the children although the WatchModel does not believe us. - ChildrenKnownBit = 0x0100, - // Is a pointer to a potentially dumpeable class. - ClassPointerBit = 0x0200 }; - - static CdbSymbolGroupContext *create(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - const QSharedPointer<CdbDumperHelper> &dumper, - const QStringList &uninitializedVariables, - QString *errorMessage); - - bool editorToolTip(const QString &iname, QString *value, QString *errorMessage); - - bool populateModelInitially(WatchHandler *wh, QString *errorMessage); - - bool completeData(const WatchData &incompleteLocal, - WatchHandler *wh, - QString *errorMessage); - -private: - // Initially populate the locals model for a new stackframe. - // Write a sequence of WatchData to it, recurse down if the - // recursionPredicate agrees. The ignorePredicate can be used - // to terminate processing after insertion of an item (if the calling - // routine wants to insert another subtree). - template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> - static bool populateModelInitiallyHelper(const CdbSymbolGroupRecursionContext &ctx, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage); - - // Complete children of a WatchData item. - // Write a sequence of WatchData to it, recurse if the - // recursionPredicate agrees. The ignorePredicate can be used - // to terminate processing after insertion of an item (if the calling - // routine wants to insert another subtree). - template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> - static bool completeDataHelper (const CdbSymbolGroupRecursionContext &ctx, - WatchData incompleteLocal, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage); - - // Retrieve child symbols of prefix as a sequence of WatchData. - template <class OutputIterator> - bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage) - { return getDumpChildSymbols(0, prefix, 0, it, errorMessage); } - // Retrieve child symbols of prefix as a sequence of WatchData. - // Is CIDebugDataSpaces is != 0, try internal dumper and set owner - template <class OutputIterator> - bool getDumpChildSymbols(const QString &prefix, - int dumpedOwner, - OutputIterator it, QString *errorMessage); - - template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> - static bool insertSymbolRecursion(WatchData wd, - const CdbSymbolGroupRecursionContext &ctx, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage); - - unsigned watchDataAt(unsigned long index, WatchData *); - - const bool m_useDumpers; - const QSharedPointer<CdbDumperHelper> m_dumper; -}; - -// A convenience struct to save parameters for the model recursion. -struct CdbSymbolGroupRecursionContext { - explicit CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, int internalDumperOwner); - - CdbSymbolGroupContext *context; - int internalDumperOwner; -}; - -// Helper to a sequence of WatchData into a list. -class WatchDataBackInserter -{ -public: - explicit WatchDataBackInserter(QList<WatchData> &wh) : m_wh(wh) {} - - inline WatchDataBackInserter & operator*() { return *this; } - inline WatchDataBackInserter &operator=(const WatchData &wd) { - m_wh.push_back(wd); - return *this; - } - inline WatchDataBackInserter &operator++() { return *this; } - -private: - QList<WatchData> &m_wh; -}; - -} // namespace Internal -} // namespace Debugger - -#include "cdbsymbolgroupcontext_tpl.h" - -#endif // CDBSYMBOLGROUPCONTEXT_H diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h deleted file mode 100644 index b94fe2595d77abf492440108ef4361ad1ace1a78..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ /dev/null @@ -1,182 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBSYMBOLGROUPCONTEXT_TPL_H -#define CDBSYMBOLGROUPCONTEXT_TPL_H - -#include "watchhandler.h" - -#include <QtCore/QDebug> - -namespace Debugger { -namespace Internal { - -enum { debugSgRecursion = 0 }; - -template <class OutputIterator> -bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix, - int dumpedOwner, - OutputIterator it, QString *errorMessage) -{ - unsigned long start; - unsigned long parentId; - if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage)) - return false; - // Skip over expanded children. Internal dumping might expand - // children, so, re-evaluate size in end condition. - // Note the that the internal dumpers might expand children, - // so the size might change. - int sortId = 0; - for (int s = start; s < size(); ++s) { - const DEBUG_SYMBOL_PARAMETERS &p = symbolParameterAt(s); - if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { - WatchData wd; - const unsigned rc = watchDataAt(s, &wd); - if (rc & InternalDumperMask) - wd.source = dumpedOwner; - wd.sortId = sortId++; - *it = wd; - ++it; - } - } - return true; -} - -// Insert a symbol (and its first level children depending on forceRecursion) -// The parent symbol is inserted before the children to make dumper handling -// simpler. In theory, it can happen that the symbol context indicates -// children but can expand none, which would lead to invalid parent information -// (expand icon), though (ignore for simplicity). -template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> -bool CdbSymbolGroupContext::insertSymbolRecursion(WatchData wd, - const CdbSymbolGroupRecursionContext &ctx, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage) -{ - // Find out whether to recurse (has children and predicate agrees) - const bool hasChildren = wd.hasChildren || wd.isChildrenNeeded(); - const bool recurse = hasChildren && recursionPredicate(wd); - if (debugSgRecursion) - qDebug() << "insertSymbolRecursion" << '\n' << wd.iname << "recurse=" << recurse; - if (!recurse) { - // No further recursion at this level, pretend entry is complete - // to the watchmodel for the parent to show (only remaining watchhandler-specific - // part here). - if (wd.isChildrenNeeded()) { - wd.setHasChildren(true); - wd.setChildrenUnneeded(); - } - if (debugSgRecursion) - qDebug() << " INSERTING non-recursive: " << wd.toString(); - *it = wd; - ++it; - return true; - } - // Recursion: Indicate children unneeded - wd.setHasChildren(true); - wd.setChildrenUnneeded(); - if (debugSgRecursion) - qDebug() << " INSERTING recursive: " << wd.toString(); - *it = wd; - ++it; - // Recurse unless the predicate disagrees - if (ignorePredicate(wd)) - return true; - QList<WatchData> watchList; - // This implicitly enforces expansion - if (!ctx.context->getDumpChildSymbols(wd.iname, - ctx.internalDumperOwner, - WatchDataBackInserter(watchList), errorMessage)) - return false; - const int childCount = watchList.size(); - for (int c = 0; c < childCount; c++) { - const WatchData &cwd = watchList.at(c); - if (wd.isValid()) { // We sometimes get empty names for deeply nested data - if (!insertSymbolRecursion(cwd, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) - return false; - } else { - const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'."). - arg(QLatin1String(Q_FUNC_INFO)).arg(c).arg(cwd.type, QString::fromLatin1(wd.iname)); - qWarning("%s\n", qPrintable(msg)); - } - } - return true; -} - -template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> -bool CdbSymbolGroupContext::populateModelInitiallyHelper(const CdbSymbolGroupRecursionContext &ctx, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage) -{ - if (debugSgRecursion) - qDebug() << "### CdbSymbolGroupContext::populateModelInitially"; - - // Insert root items - QList<WatchData> watchList; - CdbSymbolGroupContext *sg = ctx.context; - if (!sg->getDumpChildSymbols(sg->prefix(), - ctx.internalDumperOwner, - WatchDataBackInserter(watchList), errorMessage)) - return false; - // Insert data - foreach(const WatchData &wd, watchList) - if (!insertSymbolRecursion(wd, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) - return false; - return true; -} - -template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> -bool CdbSymbolGroupContext::completeDataHelper(const CdbSymbolGroupRecursionContext &ctx, - WatchData incompleteLocal, - OutputIterator it, - RecursionPredicate recursionPredicate, - IgnorePredicate ignorePredicate, - QString *errorMessage) -{ - if (debugSgRecursion) - qDebug().nospace() << "###>CdbSymbolGroupContext::completeData" << ' ' << incompleteLocal.iname << '\n'; - // If the symbols are already expanded in the context, they will be re-inserted, - // which is not handled for simplicity. - if (!insertSymbolRecursion(incompleteLocal, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) - return false; - return true; -} - -} // namespace Internal -} // namespace Debugger - -#endif // CDBSYMBOLGROUPCONTEXT_TPL_H diff --git a/src/plugins/debugger/cdb/corebreakpoint.cpp b/src/plugins/debugger/cdb/corebreakpoint.cpp deleted file mode 100644 index b4f005a131e71acd9232951a9ea5f410fe860725..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/corebreakpoint.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "corebreakpoint.h" -#include "coreengine.h" -#ifndef TEST_COMPILE // Usage in manual tests -# include "dbgwinutils.h" -#endif -#include <utils/qtcassert.h> - -#include <QtCore/QTextStream> -#include <QtCore/QDir> -#include <QtCore/QDebug> -#include <QtCore/QMap> - -enum { debugBP = 0 }; - -namespace CdbCore { - -// The CDB breakpoint expression syntax is: -// `foo.cpp:523`[ "condition"] -// module!function[ "condition"] - -static const char sourceFileQuoteC = '`'; - -BreakPoint::BreakPoint() : - type(Code), - lineNumber(-1), - address(0), - threadId(-1), - ignoreCount(0), - oneShot(false), - enabled(true) -{ -} - -void BreakPoint::clear() -{ - type = Code; - ignoreCount = 0; - threadId = -1; - oneShot = false; - enabled = true; - clearExpressionData(); -} - -void BreakPoint::clearExpressionData() -{ - fileName.clear(); - condition.clear(); - funcName.clear(); - lineNumber = -1; - address = 0; -} - -QDebug operator<<(QDebug dbg, const BreakPoint &bp) -{ - dbg.nospace() << bp.toString(); - return dbg; -} - -QString BreakPoint::toString() const -{ - QString rc; - QTextStream str(&rc); - str << (type == BreakPoint::Code ? "Code " : "Data "); - if (address) { - str.setIntegerBase(16); - str << "0x" << address << ' '; - str.setIntegerBase(10); - } - if (!fileName.isEmpty()) { - str << "fileName='" << fileName << ':' << lineNumber << '\''; - } else { - str << "funcName='" << funcName << '\''; - } - if (threadId >= 0) - str << " thread=" << threadId; - if (!condition.isEmpty()) - str << " condition='" << condition << '\''; - if (ignoreCount) - str << " ignoreCount=" << ignoreCount; - str << (enabled ? " enabled" : " disabled"); - if (oneShot) - str << " oneShot"; - return rc; -} - -QString BreakPoint::expression() const -{ - // format the breakpoint expression (file/function and condition) - QString rc; - QTextStream str(&rc); - do { - if (address) { - str.setIntegerBase(16); - str << "0x" << address; - str.setIntegerBase(10); - break; - } - if (!fileName.isEmpty()) { - const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC); - str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':') - << lineNumber << sourceFileQuote; - break; - } - if (!funcName.isEmpty()) { - str << funcName; - break; - } - } while (false); - if (!condition.isEmpty()) - str << " \"" << condition << '"'; - return rc; -} - -static inline QString msgCannotSetBreakpoint(const QString &exp, const QString &why) -{ - return QString::fromLatin1("Unable to set breakpoint '%1' : %2").arg(exp, why); -} - -bool BreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const -{ - const QString expr = expression(); - if (debugBP) - qDebug() << Q_FUNC_INFO << *this << expr; - HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16())); - if (FAILED(hr)) { - *errorMessage = msgCannotSetBreakpoint(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr)); - return false; - } - // Pass Count is ignoreCount + 1 - hr = ibp->SetPassCount(ignoreCount + 1u); - if (FAILED(hr)) - qWarning("Error setting passcount %d %s ", ignoreCount, qPrintable(expr)); - // Set up size for data breakpoints - if (type == Data) { - const ULONG size = 1u; - hr = ibp->SetDataParameters(size, DEBUG_BREAK_READ | DEBUG_BREAK_WRITE); - if (FAILED(hr)) { - const QString msg = QString::fromLatin1("Cannot set watch size to %1: %2"). - arg(size).arg(CdbCore::msgComFailed("SetDataParameters", hr)); - *errorMessage = msgCannotSetBreakpoint(expr, msg); - return false; - } - } - // Thread - if (threadId >= 0) { - hr = ibp->SetMatchThreadId(threadId); - if (FAILED(hr)) { - const QString msg = QString::fromLatin1("Cannot set thread id to %1: %2"). - arg(threadId).arg(CdbCore::msgComFailed("SetMatchThreadId", hr)); - *errorMessage = msgCannotSetBreakpoint(expr, msg); - return false; - } - } - // Flags - ULONG flags = 0; - if (enabled) - flags |= DEBUG_BREAKPOINT_ENABLED; - if (oneShot) - flags |= DEBUG_BREAKPOINT_ONE_SHOT; - hr = ibp->AddFlags(flags); - if (FAILED(hr)) { - const QString msg = QString::fromLatin1("Cannot set flags to 0x%1: %2"). - arg(flags, 0 ,16).arg(CdbCore::msgComFailed("AddFlags", hr)); - *errorMessage = msgCannotSetBreakpoint(expr, msg); - return false; - } - return true; -} - -static inline QString msgCannotAddBreakPoint(const QString &why) -{ - return QString::fromLatin1("Unable to add breakpoint: %1").arg(why); -} - -bool BreakPoint::add(CIDebugControl* debugControl, - QString *errorMessage, - unsigned long *id, - quint64 *address) const -{ - CIDebugBreakpoint* ibp = 0; - if (address) - *address = 0; - if (id) - *id = 0; - const ULONG iType = type == Code ? DEBUG_BREAKPOINT_CODE : DEBUG_BREAKPOINT_DATA; - HRESULT hr = debugControl->AddBreakpoint2(iType, DEBUG_ANY_ID, &ibp); - if (FAILED(hr)) { - *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr)); - return false; - } - if (!ibp) { - *errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>")); - return false; - } - if (!apply(ibp, errorMessage)) - return false; - // GetOffset can fail when attaching to remote processes, ignore return - if (address) { - hr = ibp->GetOffset(address); - if (FAILED(hr)) - *address = 0; - } - if (id) { - hr = ibp->GetId(id); - if (FAILED(hr)) { - *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("GetId", hr)); - return false; - } - } - return true; -} - -// Make sure file can be found in editor manager and text markers -// Use '/', correct case and capitalize drive letter. Use a cache. - -typedef QHash<QString, QString> NormalizedFileCache; -Q_GLOBAL_STATIC(NormalizedFileCache, normalizedFileNameCache) - -QString BreakPoint::normalizeFileName(const QString &f) -{ -#ifdef TEST_COMPILE // Usage in manual tests - return f; -#else - QTC_ASSERT(!f.isEmpty(), return f) - const NormalizedFileCache::const_iterator it = normalizedFileNameCache()->constFind(f); - if (it != normalizedFileNameCache()->constEnd()) - return it.value(); - QString normalizedName = QDir::fromNativeSeparators(Debugger::Internal::winNormalizeFileName(f)); - // Upcase drive letter for consistency even if case mapping fails. - if (normalizedName.size() > 2 && normalizedName.at(1) == QLatin1Char(':')) - normalizedName[0] = normalizedName.at(0).toUpper(); - normalizedFileNameCache()->insert(f, normalizedName); - return normalizedName; -#endif -} - -void BreakPoint::clearNormalizeFileNameCache() -{ - normalizedFileNameCache()->clear(); -} - -static inline QString msgCannotRetrieveBreakpoint(const QString &why) -{ - return QString::fromLatin1("Cannot retrieve breakpoint: %1").arg(why); -} - -static inline int threadIdOfBreakpoint(CIDebugBreakpoint *ibp) -{ - // Thread: E_NOINTERFACE indicates no thread has been set. - int threadId = -1; - ULONG iThreadId; - if (S_OK == ibp->GetMatchThreadId(&iThreadId)) - threadId = iThreadId; - return threadId; -} - -bool BreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage) -{ - clear(); - // Get type - ULONG iType; - ULONG processorType; - HRESULT hr = ibp->GetType(&iType, &processorType); - if (FAILED(hr)) { - *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetType", hr)); - return false; - } - type = iType == DEBUG_BREAKPOINT_CODE ? Code : Data; - // Get & parse expression - WCHAR wszBuf[MAX_PATH]; - hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0); - if (FAILED(hr)) { - *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetOffsetExpressionWide", hr)); - return false; - } - threadId = threadIdOfBreakpoint(ibp); - // Pass Count is ignoreCount + 1 - ibp->GetPassCount(&ignoreCount); - if (ignoreCount) - ignoreCount--; - ULONG flags = 0; - ibp->GetFlags(&flags); - oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT); - enabled = (flags & DEBUG_BREAKPOINT_ENABLED); - const QString expr = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - if (!parseExpression(expr)) { - *errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr); - return false; - } - return true; -} - -bool BreakPoint::parseExpression(const QString &expr) -{ - clearExpressionData(); - const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC); - // Check for file or function - int conditionPos = 0; - if (expr.startsWith(QLatin1String("0x"))) { // Check address token - conditionPos = expr.indexOf(QLatin1Char(' ')); - QString addressS; - if (conditionPos != -1) { - addressS = expr.mid(2, conditionPos - 2); - conditionPos++; - } else { - addressS = expr.mid(2); - conditionPos = expr.size(); - } - addressS.remove(QLatin1Char('\'')); // 64bit separator - bool ok; - address = addressS.toULongLong(&ok, 16); - if (!ok) - return false; - } else if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"] - // Do not fall for the drive letter colon here - const int colonPos = expr.indexOf(QLatin1Char(':'), 3); - if (colonPos == -1) - return false; - conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1); - if (conditionPos == -1) - return false; - fileName = normalizeFileName(expr.mid(1, colonPos - 1)); - const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1); - bool lineNumberOk = false; - lineNumber = lineNumberS.toInt(&lineNumberOk); - if (!lineNumberOk) - return false; - conditionPos++; - } else { - // Check function token - conditionPos = expr.indexOf(QLatin1Char(' ')); - if (conditionPos != -1) { - funcName = expr.mid(0, conditionPos); - conditionPos++; - } else { - funcName = expr; - conditionPos = expr.size(); - } - } - // Condition? ".if bla" - if (conditionPos >= expr.size()) - return true; - const QChar doubleQuote = QLatin1Char('"'); - conditionPos = expr.indexOf(doubleQuote, conditionPos); - if (conditionPos == -1) - return true; - conditionPos++; - const int condEndPos = expr.lastIndexOf(doubleQuote); - if (condEndPos == -1) - return false; - condition = expr.mid(conditionPos, condEndPos - conditionPos); - return true; -} - -bool BreakPoint::getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage /* = 0*/) -{ - const HRESULT hr = debugControl->GetNumberBreakpoints(count); - if (FAILED(hr)) { - if (errorMessage) - *errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1"). - arg(CdbCore::msgComFailed("GetNumberBreakpoints", hr)); - return false; - } - return true; -} - -bool BreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<BreakPoint> *bps, QString *errorMessage) -{ - ULONG count = 0; - bps->clear(); - if (!getBreakPointCount(debugControl, &count, errorMessage)) - return false; - // retrieve one by one and parse - for (ULONG b = 0; b < count; b++) { - CIDebugBreakpoint *ibp = 0; - const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2"). - arg(b).arg(CdbCore::msgComFailed("GetBreakpointByIndex2", hr)); - return false; - } - BreakPoint bp; - if (!bp.retrieve(ibp, errorMessage)) - return false; - bps->push_back(bp); - } - return true; -} - -// Find a breakpoint by id -static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why) -{ - return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why); -} - -CIDebugBreakpoint *BreakPoint::breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage) -{ - CIDebugBreakpoint *ibp = 0; - const HRESULT hr = ctl->GetBreakpointById2(id, &ibp); - if (FAILED(hr)) { - *errorMessage = msgNoBreakPointWithId(id, CdbCore::msgComFailed("GetBreakpointById2", hr)); - return 0; - } - if (!ibp) { - *errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>")); - return 0; - } - return ibp; -} - -// Remove breakpoint by id -bool BreakPoint::removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage) -{ - if (debugBP) - qDebug() << Q_FUNC_INFO << id; - CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage); - if (!ibp) - return false; - const HRESULT hr = ctl->RemoveBreakpoint2(ibp); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(CdbCore::msgComFailed("RemoveBreakpointById2", hr)); - return false; - } - return true; -} - -// Set enabled by id - -// Change enabled state of a breakpoint by id -static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why) -{ - return QString::fromLatin1("Cannot %1 breakpoint %2: %3"). - arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why); -} - -bool BreakPoint::setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage) -{ - if (debugBP) - qDebug() << Q_FUNC_INFO << id << enabled; - CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage); - if (!ibp) { - *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage); - return false; - } - // Compare flags - ULONG flags; - HRESULT hr = ibp->GetFlags(&flags); - if (FAILED(hr)) { - *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("GetFlags", hr)); - return false; - } - const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED); - if (wasEnabled == enabled) - return true; - // Set new value - if (enabled) { - flags |= DEBUG_BREAKPOINT_ENABLED; - } else { - flags &= ~DEBUG_BREAKPOINT_ENABLED; - } - hr = ibp->SetFlags(flags); - if (FAILED(hr)) { - *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("SetFlags", hr)); - return false; - } - return true; -} - -// Change thread-id of a breakpoint -static inline QString msgCannotSetBreakPointThread(unsigned long id, int tid, const QString &why) -{ - return QString::fromLatin1("Cannot set breakpoint %1 thread to %2: %3").arg(id).arg(tid).arg(why); -} - -bool BreakPoint::setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage) -{ - if (debugBP) - qDebug() << Q_FUNC_INFO << id << threadId; - CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage); - if (!ibp) { - *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage); - return false; - } - // Compare thread ids - const int oldThreadId = threadIdOfBreakpoint(ibp); - if (oldThreadId == threadId) - return true; - const ULONG newIThreadId = threadId == -1 ? DEBUG_ANY_ID : static_cast<ULONG>(threadId); - if (debugBP) - qDebug() << "Changing thread id of " << id << " from " << oldThreadId << " to " << threadId - << '(' << newIThreadId << ')'; - const HRESULT hr = ibp->SetMatchThreadId(newIThreadId); - if (FAILED(hr)) { - *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage); - return false; - } - return true; -} -} // namespace CdbCore diff --git a/src/plugins/debugger/cdb/corebreakpoint.h b/src/plugins/debugger/cdb/corebreakpoint.h deleted file mode 100644 index caa671e028441900609dd05edd59b4812277f28a..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/corebreakpoint.h +++ /dev/null @@ -1,113 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBCOREBREAKPOINTS_H -#define CDBCOREBREAKPOINTS_H - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QList> - -QT_BEGIN_NAMESPACE -class QDebug; -QT_END_NAMESPACE - -namespace CdbCore { - -/* CDB Break point data structure with utilities to - * apply to engine and to retrieve them from the engine and comparison. - * Can stop on 'sourcefile:line', function or address. - * When/How many times it triggers can be influenced by - * condition/ignorecount and 'oneshot'-flag. */ - -// Note: File is named corebreakpoint.h/cpp to avoid conflicts with -// ../breakpoint.h/cpp. - -struct BreakPoint -{ - enum Type { Code, // Stop in code. - Data // Stop when accessing address. - }; - - BreakPoint(); - - void clear(); - void clearExpressionData(); - - QString expression() const; - - // Apply parameters (with the exception of type, which is - // passed as a parameter to IDebugControl within add(). - bool apply(CIDebugBreakpoint *ibp, QString *errorMessage) const; - // Convenience to add to a IDebugControl4. - bool add(CIDebugControl* debugControl, - QString *errorMessage, - unsigned long *id = 0, - quint64 *address = 0) const; - - // Retrieve/parse breakpoints from the interfaces - bool retrieve(CIDebugBreakpoint *ibp, QString *errorMessage); - bool parseExpression(const QString &expr); - // Retrieve all breakpoints from the engine - static bool getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage = 0); - static bool getBreakPoints(CIDebugControl* debugControl, QList<BreakPoint> *bps, QString *errorMessage); - // Control helpers - static CIDebugBreakpoint *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage); - static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage); - static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage); - static bool setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage); - - // Return a 'canonical' file (using '/' and capitalized drive letter) - static QString normalizeFileName(const QString &f); - static void clearNormalizeFileNameCache(); - QString toString() const; - - Type type; - QString fileName; // short name of source file - int lineNumber; // line in source file - QString funcName; // name of containing function - quint64 address; - - int threadId; - QString condition; // condition associated with breakpoint - unsigned long ignoreCount; // ignore count associated with breakpoint - bool oneShot; - bool enabled; -}; - -QDebug operator<<(QDebug, const BreakPoint &bp); - -} // namespace CdbCore - -#endif // CDBCOREBREAKPOINTS_H diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp deleted file mode 100644 index e888953138293135f057d98adc32b197f0e9cb26..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/coreengine.cpp +++ /dev/null @@ -1,1220 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "coreengine.h" -#include "debugeventcallbackbase.h" -#include "debugoutputbase.h" -#include "symbolgroupcontext.h" - -#include <utils/winutils.h> -#include <utils/abstractprocess.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QDir> -#include <QtCore/QLibrary> -#include <QtCore/QDebug> - -#define DBGHELP_TRANSLATE_TCHAR -#include <inc/Dbghelp.h> - -static const char *dbgHelpDllC = "dbghelp"; -static const char *dbgEngineDllC = "dbgeng"; -static const char *debugCreateFuncC = "DebugCreate"; - -enum { debug = 0 }; - -Q_GLOBAL_STATIC(QString, baseImagePath) - -static inline QString msgLibLoadFailed(const QString &lib, const QString &why) -{ - return QCoreApplication::translate("Debugger::Cdb", - "Unable to load the debugger engine library '%1': %2"). - arg(lib, why); -} - -static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl) -{ - ULONG rc = 0; - ctl->GetInterruptTimeout(&rc); - return rc; -} - -namespace CdbCore { - -QString msgDebugEngineComResult(HRESULT hr) -{ - switch (hr) { - case S_OK: - return QLatin1String("S_OK"); - case S_FALSE: - return QLatin1String("S_FALSE"); - case E_FAIL: - break; - case E_INVALIDARG: - return QLatin1String("E_INVALIDARG"); - case E_NOINTERFACE: - return QLatin1String("E_NOINTERFACE"); - case E_OUTOFMEMORY: - return QLatin1String("E_OUTOFMEMORY"); - case E_UNEXPECTED: - return QLatin1String("E_UNEXPECTED"); - case E_NOTIMPL: - return QLatin1String("E_NOTIMPL"); - } - if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) - return QLatin1String("ERROR_ACCESS_DENIED");; - if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT)) - return QLatin1String("STATUS_CONTROL_C_EXIT"); - return QLatin1String("E_FAIL ") + Utils::winErrorMessage(HRESULT_CODE(hr)); -} - -QString msgComFailed(const char *func, HRESULT hr) -{ - return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr)); -} - -QString msgDebuggerCommandFailed(const QString &command, HRESULT hr) -{ - return QString::fromLatin1("Unable to execute '%1': %2").arg(command, msgDebugEngineComResult(hr)); -} - -const char *msgExecutionStatusString(ULONG executionStatus) -{ - switch (executionStatus) { - case DEBUG_STATUS_NO_CHANGE: - return "DEBUG_STATUS_NO_CHANGE"; - case DEBUG_STATUS_GO: - return "DEBUG_STATUS_GO"; - case DEBUG_STATUS_GO_HANDLED: - return "DEBUG_STATUS_GO_HANDLED"; - case DEBUG_STATUS_GO_NOT_HANDLED: - return "DEBUG_STATUS_GO_NOT_HANDLED"; - case DEBUG_STATUS_STEP_OVER: - return "DEBUG_STATUS_STEP_OVER"; - case DEBUG_STATUS_STEP_INTO: - return "DEBUG_STATUS_STEP_INTO"; - case DEBUG_STATUS_BREAK: - return "DEBUG_STATUS_BREAK"; - case DEBUG_STATUS_NO_DEBUGGEE: - return "DEBUG_STATUS_NO_DEBUGGEE"; - case DEBUG_STATUS_STEP_BRANCH: - return "DEBUG_STATUS_STEP_BRANCH"; - case DEBUG_STATUS_IGNORE_EVENT: - return "DEBUG_STATUS_IGNORE_EVENT"; - case DEBUG_STATUS_RESTART_REQUESTED: - return "DEBUG_STATUS_RESTART_REQUESTED"; - case DEBUG_STATUS_REVERSE_GO: - return "DEBUG_STATUS_REVERSE_GO"; - case DEBUG_STATUS_REVERSE_STEP_BRANCH: - return "DEBUG_STATUS_REVERSE_STEP_BRANCH"; - case DEBUG_STATUS_REVERSE_STEP_OVER: - return "DEBUG_STATUS_REVERSE_STEP_OVER"; - case DEBUG_STATUS_REVERSE_STEP_INTO: - return "DEBUG_STATUS_REVERSE_STEP_INTO"; - default: - break; - } - return "<Unknown execution status>"; -} - -static const ULONG defaultSymbolOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | - SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | - SYMOPT_AUTO_PUBLICS; - -// ComInterfaces -ComInterfaces::ComInterfaces() : - debugClient(0), - debugControl(0), - debugSystemObjects(0), - debugSymbols(0), - debugRegisters(0), - debugDataSpaces(0), - debugAdvanced(0) -{ -} - -// Thin wrapper around the 'DBEng' debugger engine shared library -// which is loaded at runtime. - -class DebuggerEngineLibrary -{ -public: - DebuggerEngineLibrary(); - bool init(const QString &path, QString *dbgEngDLL, QString *errorMessage); - - inline HRESULT debugCreate(REFIID interfaceId, PVOID *interfaceHandle) const - { return m_debugCreate(interfaceId, interfaceHandle); } - -private: - // The exported functions of the library - typedef HRESULT (STDAPICALLTYPE *DebugCreateFunction)(REFIID, PVOID *); - - DebugCreateFunction m_debugCreate; -}; - -// --------- DebuggerEngineLibrary -DebuggerEngineLibrary::DebuggerEngineLibrary() : - m_debugCreate(0) -{ -} - -// Build a lib name as "Path\x.dll" -static inline QString libPath(const QString &libName, const QString &path = QString()) -{ - QString rc = path; - if (!rc.isEmpty()) - rc += QDir::separator(); - rc += libName; - rc += QLatin1String(".dll"); - return rc; -} - -bool DebuggerEngineLibrary::init(const QString &path, - QString *dbgEngDLL, - QString *errorMessage) -{ - // Load the dependent help lib first - const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path); - QLibrary helpLib(helpLibPath, 0); - if (!helpLib.isLoaded() && !helpLib.load()) { - *errorMessage = msgLibLoadFailed(helpLibPath, helpLib.errorString()); - return false; - } - // Load dbgeng lib - const QString engineLibPath = libPath(QLatin1String(dbgEngineDllC), path); - QLibrary lib(engineLibPath, 0); - if (!lib.isLoaded() && !lib.load()) { - *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString()); - return false; - } - *dbgEngDLL = engineLibPath; - // Locate symbols - void *createFunc = lib.resolve(debugCreateFuncC); - if (!createFunc) { - *errorMessage = QCoreApplication::translate("Debugger::Cdb", "Unable to resolve '%1' in the debugger engine library '%2'"). - arg(QLatin1String(debugCreateFuncC), QLatin1String(dbgEngineDllC)); - return false; - } - m_debugCreate = static_cast<DebugCreateFunction>(createFunc); - return true; -} - -CoreEngine *CoreEngine::m_instance = 0; - -// ------ Engine -CoreEngine::CoreEngine(QObject *parent) : - QObject(parent), - m_watchTimer(-1), - m_moduleCount(0), - m_lastTimerModuleCount(0), - m_modulesLoadedEmitted(true) -{ - m_instance = this; -} - -CoreEngine::~CoreEngine() -{ - releaseInterfaces(); - m_instance = 0; -} - -bool CoreEngine::hasInterfaces() const -{ - return m_cif.debugClient != 0; -} - -bool CoreEngine::interfacesAvailable() -{ - return CoreEngine::m_instance == 0 || - !CoreEngine::m_instance->hasInterfaces(); -} - -void CoreEngine::releaseInterfaces() -{ - if (m_cif.debugClient) { - m_cif.debugClient->SetOutputCallbacksWide(0); - m_cif.debugClient->SetEventCallbacksWide(0); - m_cif.debugClient->Release(); - m_cif.debugClient = 0; - } - if (m_cif.debugControl) { - m_cif.debugControl->Release(); - m_cif.debugControl = 0; - } - if (m_cif.debugSystemObjects) { - m_cif.debugSystemObjects->Release(); - m_cif.debugSystemObjects =0; - } - - if (m_cif.debugSymbols) { - m_cif.debugSymbols->Release(); - m_cif.debugSymbols = 0; - } - - if (m_cif.debugRegisters) { - m_cif.debugRegisters->Release(); - m_cif.debugRegisters = 0; - } - - if (m_cif.debugDataSpaces) { - m_cif.debugDataSpaces->Release(); - m_cif.debugDataSpaces = 0; - } - - if (m_cif.debugAdvanced) { - m_cif.debugAdvanced->Release(); - m_cif.debugAdvanced = 0; - } -} - -bool CoreEngine::init(const QString &dllEnginePath, QString *errorMessage) -{ - if (!CoreEngine::interfacesAvailable()) { - *errorMessage = QString::fromLatin1("Internal error: The COM interfaces are already in use."); - return false; - } - enum { bufLen = 10240 }; - // Load the DLL - DebuggerEngineLibrary lib; - if (!lib.init(dllEnginePath, &m_dbengDLL, errorMessage)) - return false; - // Initialize the COM interfaces - HRESULT hr; - hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - hr = m_cif.debugSymbols->SetSymbolOptions(defaultSymbolOptions); - if (FAILED(hr)) { - *errorMessage = msgComFailed("SetSymbolOptions", hr); - return false; - } - - // Query inherited image path from environment only once as it is remembered. - static bool firstInstance = true; - if (firstInstance) { - firstInstance = false; - WCHAR buf[bufLen]; - hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0); - if (FAILED(hr)) { - *errorMessage = msgComFailed("GetImagePathWide", hr); - return false; - } - *baseImagePath() = QString::fromWCharArray(buf); - } - - hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - hr = lib.debugCreate( __uuidof(IDebugAdvanced2), reinterpret_cast<void**>(&m_cif.debugAdvanced)); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Creation of IDebugAdvanced2 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; - } - - if (debug) - qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl)); - return true; -} - -CoreEngine::DebugOutputBasePtr - CoreEngine::setDebugOutput(const DebugOutputBasePtr &o) -{ - const CoreEngine::DebugOutputBasePtr old = m_debugOutput; - m_debugOutput = o; - m_cif.debugClient->SetOutputCallbacksWide(m_debugOutput.data()); - return old; -} - -CoreEngine::DebugEventCallbackBasePtr - CoreEngine::setDebugEventCallback(const DebugEventCallbackBasePtr &e) -{ - // Keep the module count. - const unsigned oldModuleCount = moduleCount(); - const CoreEngine::DebugEventCallbackBasePtr old = m_debugEventCallback; - m_debugEventCallback = e; - m_cif.debugClient->SetEventCallbacksWide(m_debugEventCallback.data()); - setModuleCount(oldModuleCount); - return old; -} - -void CoreEngine::startWatchTimer() -{ - if (debug) - qDebug() << Q_FUNC_INFO; - - if (m_watchTimer == -1) - m_watchTimer = startTimer(0); -} - -void CoreEngine::killWatchTimer() -{ - if (debug) - qDebug() << Q_FUNC_INFO; - - if (m_watchTimer != -1) { - killTimer(m_watchTimer); - m_watchTimer = -1; - } -} - -HRESULT CoreEngine::waitForEvent(int timeOutMS) -{ - const HRESULT hr = m_cif.debugControl->WaitForEvent(0, timeOutMS); - if (debug) - if (debug > 1 || hr != S_FALSE) - qDebug() << Q_FUNC_INFO << "WaitForEvent" << timeOutMS << msgDebugEngineComResult(hr); - return hr; -} - -void CoreEngine::timerEvent(QTimerEvent* te) -{ - // Fetch away the debug events and notify if debuggee - // stops. Note that IDebugEventCallback does not - // cover all cases of a debuggee stopping execution - // (such as step over,etc). - if (te->timerId() != m_watchTimer) - return; - switch (waitForEvent(1)) { - case S_OK: - killWatchTimer(); - emit watchTimerDebugEvent(); - break; - case S_FALSE: - // Detect startup (all modules loaded) if the module - // count no longer changes in a time-out. - if (!m_modulesLoadedEmitted) { - const int newModuleCount = moduleCount(); - if (newModuleCount && newModuleCount == m_lastTimerModuleCount) { - m_modulesLoadedEmitted = true; - emit modulesLoaded(); - } else { - m_lastTimerModuleCount = newModuleCount; - } - } - break; - case E_PENDING: - case E_FAIL: - break; - case E_UNEXPECTED: // Occurs on ExitProcess. - killWatchTimer(); - break; - } -} - -void CoreEngine::resetModuleLoadTimer() -{ - m_lastTimerModuleCount = 0; - setModuleCount(0); - m_modulesLoadedEmitted = false; -} - -bool CoreEngine::startDebuggerWithExecutable(const QString &workingDirectory, - const QString &filename, - const QString &args, - const QStringList &envList, - QString *errorMessage) -{ - resetModuleLoadTimer(); - DEBUG_CREATE_PROCESS_OPTIONS dbgopts; - memset(&dbgopts, 0, sizeof(dbgopts)); - dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; - - // Set image path - const QFileInfo fi(filename); - QString imagePath = QDir::toNativeSeparators(fi.absolutePath()); - if (!baseImagePath()->isEmpty()) { - imagePath += QLatin1Char(';'); - imagePath += baseImagePath(); - } - - HRESULT hr = m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16())); - if (FAILED(hr)) { - *errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr)); - return false; - } - - if (debug) - qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath; - - const QString cmd = Utils::AbstractProcess::createWinCommandline(filename, args); - if (debug) - qDebug() << "Starting " << cmd; - PCWSTR env = 0; - QByteArray envData; - if (!envList.empty()) { - envData = Utils::AbstractProcess::createWinEnvironment(Utils::AbstractProcess::fixWinEnvironment(envList)); - env = reinterpret_cast<PCWSTR>(envData.data()); - } - // The working directory cannot be empty. - PCWSTR workingDirC = 0; - const QString workingDirN = workingDirectory.isEmpty() ? QString() : QDir::toNativeSeparators(workingDirectory); - if (!workingDirN.isEmpty()) - workingDirC = (PCWSTR)workingDirN.utf16(); - hr = m_cif.debugClient->CreateProcess2Wide(NULL, - reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())), - &dbgopts, sizeof(dbgopts), - workingDirC, env); - if (FAILED(hr)) { - *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr)); - return false; - } - return true; -} - -bool CoreEngine::startAttachDebugger(qint64 pid, - bool suppressInitialBreakPoint, - QString *errorMessage) -{ - resetModuleLoadTimer(); - // Need to attach invasively, otherwise, no notification signals - // for for CreateProcess/ExitProcess occur. - // Initial breakpoint occur: - // 1) Desired: When attaching to a crashed process - // 2) Undesired: When starting up a console process, in conjunction - // with the 32bit Wow-engine - // As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed - // by lookup at the state of the application (startup trap). However, - // there is no startup trap when attaching to a process that has been - // running for a while. (see notifyException). - ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS; - if (suppressInitialBreakPoint) - flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; - const HRESULT hr = m_cif.debugClient->AttachProcess(NULL, pid, flags); - if (debug) - qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr; - if (FAILED(hr)) { - *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr)); - return false; - } - return true; -} - -static inline QString pathString(const QStringList &s) -{ return s.join(QString(QLatin1Char(';'))); } - -QStringList CoreEngine::sourcePaths() const -{ - WCHAR wszBuf[MAX_PATH]; - if (SUCCEEDED(m_cif.debugSymbols->GetSourcePathWide(wszBuf, MAX_PATH, 0))) - return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';')); - return QStringList(); -} - -bool CoreEngine::setSourcePaths(const QStringList &s, QString *errorMessage) -{ - const HRESULT hr = m_cif.debugSymbols->SetSourcePathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16())); - if (FAILED(hr)) { - if (errorMessage) - *errorMessage = msgComFailed("SetSourcePathWide", hr); - return false; - } - return true; -} - -QStringList CoreEngine::symbolPaths() const -{ - WCHAR wszBuf[MAX_PATH]; - if (SUCCEEDED(m_cif.debugSymbols->GetSymbolPathWide(wszBuf, MAX_PATH, 0))) - return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';')); - return QStringList(); -} - -bool CoreEngine::setSymbolPaths(const QStringList &s, QString *errorMessage) -{ - const HRESULT hr = m_cif.debugSymbols->SetSymbolPathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16())); - if (FAILED(hr)) { - if (errorMessage) - *errorMessage = msgComFailed("SetSymbolPathWide", hr); - return false; - } - return true; -} - -bool CoreEngine::isVerboseSymbolLoading() const -{ - ULONG opts; - const HRESULT hr = m_cif.debugSymbols->GetSymbolOptions(&opts); - return SUCCEEDED(hr) && (opts & SYMOPT_DEBUG); -} - -bool CoreEngine::setVerboseSymbolLoading(bool newValue) -{ - ULONG opts; - HRESULT hr = m_cif.debugSymbols->GetSymbolOptions(&opts); - if (FAILED(hr)) { - qWarning("%s", qPrintable(msgComFailed("GetSymbolOptions", hr))); - return false; - } - const bool isVerbose = (opts & SYMOPT_DEBUG); - if (isVerbose == newValue) - return true; - if (newValue) { - opts |= SYMOPT_DEBUG; - } else { - opts &= ~SYMOPT_DEBUG; - } - hr = m_cif.debugSymbols->SetSymbolOptions(opts); - if (FAILED(hr)) { - qWarning("%s", qPrintable(msgComFailed("SetSymbolOptions", hr))); - return false; - } - return true; -} - -bool CoreEngine::executeDebuggerCommand(const QString &command, QString *errorMessage) -{ - // output to all clients, else we do not see anything - const HRESULT hr = m_cif.debugControl->ExecuteWide(DEBUG_OUTCTL_ALL_CLIENTS, reinterpret_cast<PCWSTR>(command.utf16()), 0); - if (debug) - qDebug() << "executeDebuggerCommand" << command << SUCCEEDED(hr); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Unable to execute '%1': %2"). - arg(command, msgDebugEngineComResult(hr)); - return false; - } - return true; -} - -// Those should not fail -CoreEngine::ExpressionSyntax CoreEngine::expressionSyntax() const -{ - ULONG expressionSyntax = DEBUG_EXPR_MASM; - const HRESULT hr = m_cif.debugControl->GetExpressionSyntax(&expressionSyntax); - if (FAILED(hr)) - qWarning("Unable to retrieve expression syntax: %s", qPrintable(msgComFailed("GetExpressionSyntax", hr))); - return expressionSyntax == DEBUG_EXPR_MASM ? AssemblerExpressionSyntax : CppExpressionSyntax; -} - -CoreEngine::ExpressionSyntax CoreEngine::setExpressionSyntax(ExpressionSyntax es) -{ - const ExpressionSyntax old = expressionSyntax(); - if (old != es) { - if (debug) - qDebug() << "Setting expression syntax" << es; - const HRESULT hr = m_cif.debugControl->SetExpressionSyntax(es == AssemblerExpressionSyntax ? DEBUG_EXPR_MASM : DEBUG_EXPR_CPLUSPLUS); - if (FAILED(hr)) - qWarning("Unable to set expression syntax: %s", qPrintable(msgComFailed("SetExpressionSyntax", hr))); - } - return old; -} - -CoreEngine::CodeLevel CoreEngine::codeLevel() const -{ - ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY; - HRESULT hr = m_cif.debugControl->GetCodeLevel(¤tCodeLevel); - if (FAILED(hr)) { - qWarning("Cannot determine code level: %s", qPrintable(msgComFailed("GetCodeLevel", hr))); - } - return currentCodeLevel == DEBUG_LEVEL_ASSEMBLY ? CodeLevelAssembly : CodeLevelSource; -} - -CoreEngine::CodeLevel CoreEngine::setCodeLevel(CodeLevel cl) -{ - const CodeLevel old = codeLevel(); - if (old != cl) { - if (debug) - qDebug() << "Setting code level" << cl; - const HRESULT hr = m_cif.debugControl->SetCodeLevel(cl == CodeLevelAssembly ? DEBUG_LEVEL_ASSEMBLY : DEBUG_LEVEL_SOURCE); - if (FAILED(hr)) - qWarning("Unable to set code level: %s", qPrintable(msgComFailed("SetCodeLevel", hr))); - } - return old; -} - -bool CoreEngine::evaluateExpression(const QString &expression, - QString *value, - QString *type, - QString *errorMessage) -{ - DEBUG_VALUE debugValue; - if (!evaluateExpression(expression, &debugValue, errorMessage)) - return false; - *value = debugValueToString(debugValue, type, 10, m_cif.debugControl); - return true; -} - -bool CoreEngine::evaluateExpression(const QString &expression, - DEBUG_VALUE *debugValue, - QString *errorMessage) -{ - if (debug > 1) - qDebug() << Q_FUNC_INFO << expression; - - memset(debugValue, 0, sizeof(DEBUG_VALUE)); - // Use CPP syntax, original syntax must be restored, else setting breakpoints will fail. - SyntaxSetter syntaxSetter(this, CppExpressionSyntax); - Q_UNUSED(syntaxSetter) - ULONG errorPosition = 0; - const HRESULT hr = m_cif.debugControl->EvaluateWide(reinterpret_cast<PCWSTR>(expression.utf16()), - DEBUG_VALUE_INVALID, debugValue, - &errorPosition); - if (FAILED(hr)) { - if (HRESULT_CODE(hr) == 517) { - *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope."). - arg(expression); - } else { - *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Error at %2: %3"). - arg(expression).arg(errorPosition).arg(msgDebugEngineComResult(hr)); - } - return false; - } - return true; -} - -ULONG CoreEngine::executionStatus() const -{ - ULONG ex = DEBUG_STATUS_NO_CHANGE; - const HRESULT hr = m_cif.debugControl->GetExecutionStatus(&ex); - if (FAILED(hr)) - qWarning("Cannot determine execution status: %s", qPrintable(msgComFailed("GetExecutionStatus", hr))); - return ex; -} - -bool CoreEngine::setExecutionStatus(ULONG ex, QString *errorMessage) -{ - const HRESULT hr = m_cif.debugControl->SetExecutionStatus(ex); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot set execution status to %1: %2") - .arg(QLatin1String(msgExecutionStatusString(ex)), msgComFailed("SetExecutionStatus", hr)); - return false; - } - return true; -} - -static inline void appendError(const QString &what, QString *appendableErrorMessage) -{ - if (!appendableErrorMessage->isEmpty()) - appendableErrorMessage->append(QLatin1Char('\n')); - appendableErrorMessage->append(what); -} - -bool CoreEngine::detachCurrentProcess(QString *appendableErrorMessage) -{ - const HRESULT hr = m_cif.debugClient->DetachCurrentProcess(); - if (FAILED(hr)) { - appendError(msgComFailed("DetachCurrentProcess", hr), appendableErrorMessage); - return false; - } - return true; -} - -bool CoreEngine::terminateCurrentProcess(QString *appendableErrorMessage) -{ - const HRESULT hr = m_cif.debugClient->TerminateCurrentProcess(); - if (FAILED(hr)) { - appendError(msgComFailed("TerminateCurrentProcess", hr), appendableErrorMessage); - return false; - } - return true; -} - -bool CoreEngine::terminateProcesses(QString *appendableErrorMessage) -{ - const HRESULT hr = m_cif.debugClient->TerminateProcesses(); - if (FAILED(hr)) { - appendError(msgComFailed("TerminateProcesses", hr), appendableErrorMessage); - return false; - } - return true; -} - -bool CoreEngine::endSession(QString *appendableErrorMessage) -{ - const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE); - if (FAILED(hr)) { - appendError(msgComFailed("EndSession", hr), appendableErrorMessage); - return false; - } - return true; -} - -bool CoreEngine::allocDebuggeeMemory(int size, ULONG64 *addressPtr, QString *errorMessage) -{ - *addressPtr = 0; - const QString allocCmd = QLatin1String(".dvalloc ") + QString::number(size); - - QSharedPointer<StringOutputHandler> outputHandler(new StringOutputHandler); - OutputRedirector redir(this, outputHandler); - Q_UNUSED(redir) - if (!executeDebuggerCommand(allocCmd, errorMessage)) - return false; - // "Allocated 1000 bytes starting at 003a0000" or - // "Allocated 1000 bytes starting at 00000000'000023ab" (64bit) / hopefully never localized - const QString output = outputHandler->result().trimmed(); - const int lastBlank = output.lastIndexOf(QLatin1Char(' ')); - if (lastBlank != -1) { - const QString hexNumberS = QLatin1String("0x") + output.mid(lastBlank + 1); - quint64 address; - if (SymbolGroupContext::getUnsignedHexValue(hexNumberS, &address)) { - *addressPtr = address; - return true; - } - } // blank - *errorMessage = QString::fromLatin1("Failed to parse output '%1'").arg(output); - return false; -} - -// Alloc an AscII string in debuggee -bool CoreEngine::createDebuggeeAscIIString(const QString &s, - ULONG64 *address, - QString *errorMessage) -{ - QByteArray sAsciiData = s.toLocal8Bit(); - sAsciiData += '\0'; - if (!allocDebuggeeMemory(sAsciiData.size(), address, errorMessage)) - return false; - const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0); - if (FAILED(hr)) { - *errorMessage= msgComFailed("WriteVirtual", hr); - return false; - } - return true; -} - -// Write to debuggee memory in chunks -bool CoreEngine::writeToDebuggee(const QByteArray &buffer, quint64 address, QString *errorMessage) -{ - char *ptr = const_cast<char*>(buffer.data()); - ULONG bytesToWrite = buffer.size(); - while (bytesToWrite > 0) { - ULONG bytesWritten = 0; - const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(address, ptr, bytesToWrite, &bytesWritten); - if (FAILED(hr)) { - *errorMessage = msgComFailed("WriteVirtual", hr); - return false; - } - bytesToWrite -= bytesWritten; - ptr += bytesWritten; - } - return true; -} - -bool CoreEngine::disassemble(ULONG64 offset, - unsigned long beforeLines, - unsigned long afterLines, - QString *target, - QString *errorMessage) -{ - 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. - QSharedPointer<StringOutputHandler> outputHandler(new StringOutputHandler); - OutputRedirector redir(this, outputHandler); - // For some reason, we need to output to "all clients" - const HRESULT hr = m_cif.debugControl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS, - beforeLines, beforeLines + afterLines, - offset, flags, 0, 0, 0, 0); - if (FAILED(hr)) { - *errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2"). - arg(offset, 0, 16).arg(msgComFailed("OutputDisassemblyLines", hr)); - return false; - } - *target = outputHandler->result(); - return true; -} - -quint64 CoreEngine::getSourceLineAddress(const QString &file, - int line, - QString *errorMessage) const -{ - ULONG64 rc = 0; - const HRESULT hr = m_cif.debugSymbols->GetOffsetByLineWide(line, - (wchar_t*)(file.utf16()), - &rc); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Unable to determine address of %1:%2 : %3"). - arg(file).arg(line).arg(msgComFailed("GetOffsetByLine", hr)); - return 0; - } - return rc; -} - -void CoreEngine::outputVersion() -{ - m_cif.debugControl->OutputVersionInformation(DEBUG_OUTCTL_ALL_CLIENTS); -} - -bool CoreEngine::autoDetectPath(QString *outPath, - QStringList *checkedDirectories /* = 0 */) -{ - // Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>" and its - // " (x86)", " (x64)" variations. Qt Creator needs 64/32 bit depending - // on how it was built. -#ifdef Q_OS_WIN64 - static const char *postFixes[] = {" (x64)", " 64-bit" }; -#else - static const char *postFixes[] = { " (x86)", " (x32)" }; -#endif - - outPath->clear(); - const QByteArray programDirB = qgetenv("ProgramFiles"); - if (programDirB.isEmpty()) - return false; - - const QString programDir = QString::fromLocal8Bit(programDirB) + QDir::separator(); - const QString installDir = QLatin1String("Debugging Tools For Windows"); - - QString path = programDir + installDir; - if (checkedDirectories) - checkedDirectories->push_back(path); - if (QFileInfo(path).isDir()) { - *outPath = QDir::toNativeSeparators(path); - return true; - } - const int rootLength = path.size(); - for (int i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) { - path.truncate(rootLength); - path += QLatin1String(postFixes[i]); - if (checkedDirectories) - checkedDirectories->push_back(path); - if (QFileInfo(path).isDir()) { - *outPath = QDir::toNativeSeparators(path); - return true; - } - } - return false; -} - -bool CoreEngine::debugBreakProcess(HANDLE hProcess, QString *errorMessage) -{ - const bool rc = DebugBreakProcess(hProcess); - if (!rc) - *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Utils::winErrorMessage(GetLastError())); - return rc; -} - -bool CoreEngine::setInterrupt(QString *errorMessage) -{ - const HRESULT hr = interfaces().debugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2"). - arg(getInterruptTimeOutSecs(interfaces().debugControl)).arg(msgComFailed("SetInterrupt", hr)); - return false; - } - return true; -} - -// Module count is normally kept in the event callback. -// Should we have none, we do the book-keeping ourselves. -unsigned CoreEngine::moduleCount() const -{ - return m_debugEventCallback.isNull() ? m_moduleCount : m_debugEventCallback->moduleCount(); -} - -void CoreEngine::setModuleCount(unsigned m) -{ - m_moduleCount = m; - if (!m_debugEventCallback.isNull()) - m_debugEventCallback->setModuleCount(m); -} - -static inline const char *debugFilterDescription(ULONG in) -{ - switch (in) { - case DEBUG_FILTER_BREAK: - return "break"; - case DEBUG_FILTER_SECOND_CHANCE_BREAK: - return "2nd-chance-break"; - case DEBUG_FILTER_OUTPUT: - return "output"; - case DEBUG_FILTER_IGNORE: - return "ignore"; - default: - break; - } - return "unknown"; -} - -static inline QString msgCannotChangeExceptionCommands(unsigned long code, const QString &why) -{ - return QString::fromLatin1("Cannot change exception commands for 0x%1: %2"). - arg(code, 0, 16).arg(why); -} - -bool CoreEngine::setBreakOnThrow(bool b, QString *errorMessage) -{ - // See eventFilterStatus() for defaults - const unsigned long code = 0xe06d7363; - const unsigned long executionCommand = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK; - const unsigned long continueCommand = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK; - return setExceptionCommands(code, executionCommand, continueCommand, errorMessage); -} - -bool CoreEngine::setExceptionCommands(ULONG code, - ULONG executionCommand, - ULONG continueCommand, - QString *errorMessage) -{ - DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters; - HRESULT hr = m_cif.debugControl->GetExceptionFilterParameters(1, &code, 0, &exceptionParameters); - if (FAILED(hr)) { - *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("GetExceptionFilterParameters", hr)); - return false; - } - if (exceptionParameters.ExecutionOption == executionCommand - && exceptionParameters.ContinueOption == continueCommand) - return true; - if (debug) - qDebug("Changing exception commands of 0x%x from %s/%s to %s/%s", - code, - debugFilterDescription(exceptionParameters.ExecutionOption), - debugFilterDescription(exceptionParameters.ContinueOption), - debugFilterDescription(executionCommand), - debugFilterDescription(continueCommand)); - - exceptionParameters.ExecutionOption = executionCommand; - exceptionParameters.ContinueOption = continueCommand; - hr = m_cif.debugControl->SetExceptionFilterParameters(1, &exceptionParameters); - if (FAILED(hr)) { - *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("SetExceptionFilterParameters", hr)); - return false; - } - return true; -} - -static void formatEventFilter(CIDebugControl *ctl, unsigned long start, unsigned long end, - bool isException, - QTextStream &str) -{ - enum { bufSize =2048 }; - WCHAR buffer[bufSize]; - for (unsigned long i = start; i < end; i++) { - HRESULT hr = ctl->GetEventFilterTextWide(i, buffer, bufSize, 0); - if (SUCCEEDED(hr)) { - ULONG size; - str << "- #" << i << " \"" << QString::fromWCharArray(buffer) << '"'; - hr = ctl->GetEventFilterCommandWide(i, buffer, bufSize, &size); - if (SUCCEEDED(hr) && size > 1) - str << " command: '" << QString::fromWCharArray(buffer) << '\''; - if (isException) { - DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters; - hr = ctl->GetExceptionFilterParameters(1, 0, i, &exceptionParameters); - if (SUCCEEDED(hr)) { - str.setIntegerBase(16); - str << " code: 0x" << exceptionParameters.ExceptionCode; - str.setIntegerBase(10); - str << " execute: '" - << debugFilterDescription(exceptionParameters.ExecutionOption) - << "' continue: '" << debugFilterDescription(exceptionParameters.ContinueOption) - << '\''; - if (exceptionParameters.SecondCommandSize) { - hr = ctl->GetExceptionFilterSecondCommandWide(i, buffer, bufSize, 0); - if (SUCCEEDED(hr)) - str << " 2nd-command '" << QString::fromWCharArray(buffer) << '\''; - } - } - } // isException - str << '\n'; - } - } -} - -QString CoreEngine::eventFilterStatus() const -{ - ULONG specificEvents, specificExceptions, arbitraryExceptions; - QString rc; - QTextStream str(&rc); - - HRESULT hr = m_cif.debugControl->GetNumberEventFilters(&specificEvents, &specificExceptions, &arbitraryExceptions); - if (FAILED(hr)) - return QString(); - str << "Specific events\n"; - formatEventFilter(m_cif.debugControl, 0, specificEvents, false, str); - const ULONG arbitraryExceptionsStart = specificEvents + specificExceptions; - str << "Specific exceptions\n"; - formatEventFilter(m_cif.debugControl, specificEvents, arbitraryExceptionsStart, true, str); - str << "Arbitrary exceptions\n"; - const ULONG arbitraryExceptionsEnd = arbitraryExceptionsStart + arbitraryExceptions; - formatEventFilter(m_cif.debugControl, arbitraryExceptionsStart, arbitraryExceptionsEnd, true, str); - return rc; -} - -// ------------- DEBUG_VALUE formatting helpers - -// format an array of integers as "0x323, 0x2322, ..." -template <class Integer> -static QString formatArrayHelper(const Integer *array, int size, int base = 10) -{ - QString rc; - const QString hexPrefix = QLatin1String("0x"); - const QString separator = QLatin1String(", "); - const bool hex = base == 16; - for (int i = 0; i < size; i++) { - if (i) - rc += separator; - if (hex) - rc += hexPrefix; - rc += QString::number(array[i], base); - } - return rc; -} - -QString hexFormatArray(const unsigned short *array, int size) -{ - return formatArrayHelper(array, size, 16); -} - -// 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 debugValueToString(const DEBUG_VALUE &dv, - QString *qType /* =0 */, - int integerBase, - CIDebugControl *ctl /* =0 */) -{ - switch (dv.Type) { - case DEBUG_VALUE_INT8: - if (qType) - *qType = QLatin1String("char"); - return formatInteger(dv.I8, integerBase); - case DEBUG_VALUE_INT16: - if (qType) - *qType = QLatin1String("short"); - return formatInteger(static_cast<short>(dv.I16), integerBase); - case DEBUG_VALUE_INT32: - if (qType) - *qType = QLatin1String("long"); - return formatInteger(static_cast<long>(dv.I32), integerBase); - case DEBUG_VALUE_INT64: - if (qType) - *qType = QLatin1String("long long"); - return formatInteger(static_cast<long long>(dv.I64), integerBase); - case DEBUG_VALUE_FLOAT32: - if (qType) - *qType = QLatin1String("float"); - return QString::number(dv.F32); - case DEBUG_VALUE_FLOAT64: - if (qType) - *qType = QLatin1String("double"); - return QString::number(dv.F64); - case DEBUG_VALUE_FLOAT80: - case DEBUG_VALUE_FLOAT128: { // Convert to double - DEBUG_VALUE doubleValue; - double d = 0.0; - if (ctl && SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue))) { - d = dv.F64; - } else { - qWarning("Unable to convert DEBUG_VALUE_FLOAT80/DEBUG_VALUE_FLOAT128 values"); - } - if (qType) - *qType = QLatin1String(dv.Type == DEBUG_VALUE_FLOAT80 ? "80bit-float" : "128bit-float"); - return QString::number(d); - } - case DEBUG_VALUE_VECTOR64: { - if (qType) - *qType = QLatin1String("64bit-vector"); - QString rc = QLatin1String("bytes: "); - rc += formatArrayHelper(dv.VI8, 8, integerBase); - rc += QLatin1String(" long: "); - rc += formatArrayHelper(dv.VI32, 2, integerBase); - return rc; - } - case DEBUG_VALUE_VECTOR128: { - if (qType) - *qType = QLatin1String("128bit-vector"); - QString rc = QLatin1String("bytes: "); - rc += formatArrayHelper(dv.VI8, 16, integerBase); - rc += QLatin1String(" long long: "); - rc += formatArrayHelper(dv.VI64, 2, integerBase); - return rc; - } - } - if (qType) - *qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type); - return formatArrayHelper(dv.RawBytes, 24, integerBase); -} - -bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value) -{ - *value = 0; - switch (dv.Type) { - case DEBUG_VALUE_INT8: - *value = dv.I8; - return true; - case DEBUG_VALUE_INT16: - *value = static_cast<short>(dv.I16); - return true; - case DEBUG_VALUE_INT32: - *value = static_cast<long>(dv.I32); - return true; - case DEBUG_VALUE_INT64: - *value = static_cast<long long>(dv.I64); - return true; - default: - break; - } - return false; -} - -} // namespace CdbCore diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h deleted file mode 100644 index 8cc197fb4591386d2b250e5e0cfbe58967d0d5a0..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/coreengine.h +++ /dev/null @@ -1,230 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef COREENGINE_H -#define COREENGINE_H - -#include "cdbcom.h" - -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QtCore/QSharedPointer> - -namespace CdbCore { - -class DebugOutputBase; -class DebugEventCallbackBase; - -// helper struct to pass interfaces around -struct ComInterfaces -{ - ComInterfaces(); - - CIDebugClient* debugClient; - CIDebugControl* debugControl; - CIDebugSystemObjects* debugSystemObjects; - CIDebugSymbols* debugSymbols; - CIDebugRegisters* debugRegisters; - CIDebugDataSpaces* debugDataSpaces; - CIDebugAdvanced* debugAdvanced; -}; - -class CoreEngine : public QObject -{ - Q_DISABLE_COPY(CoreEngine) - Q_OBJECT -public: - enum ExpressionSyntax { AssemblerExpressionSyntax, CppExpressionSyntax }; - enum CodeLevel { CodeLevelAssembly, CodeLevelSource }; - - typedef QSharedPointer<DebugOutputBase> DebugOutputBasePtr; - typedef QSharedPointer<DebugEventCallbackBase> DebugEventCallbackBasePtr; - - explicit CoreEngine(QObject *parent = 0); - virtual ~CoreEngine(); - - // Preliminary release interfaces. - void releaseInterfaces(); - bool hasInterfaces() const; - static bool interfacesAvailable(); - - bool init(const QString &dllEnginePath, QString *errorMessage); - // code level/output - - inline const ComInterfaces &interfaces() const { return m_cif; } - - // Set handlers - DebugOutputBasePtr setDebugOutput(const DebugOutputBasePtr &); - DebugEventCallbackBasePtr setDebugEventCallback(const DebugEventCallbackBasePtr &); - - // Start functions - bool startDebuggerWithExecutable(const QString &workingDirectory, - const QString &filename, - const QString &args, - const QStringList &env, - QString *errorMessage); - - bool startAttachDebugger(qint64 pid, bool suppressInitialBreakPoint, - QString *errorMessage); - - ULONG executionStatus() const; - bool setExecutionStatus(ULONG ex, QString *errorMessage); - - // break & interrupt - bool debugBreakProcess(HANDLE hProcess, QString *errorMessage); - // Currently does not interrupt debuggee - bool setInterrupt(QString *errorMessage); - - // Helpers for terminating the debuggees and ending the session - bool detachCurrentProcess(QString *appendableErrorMessage); - bool terminateCurrentProcess(QString *appendableErrorMessage); - bool terminateProcesses(QString *appendableErrorMessage); - bool endSession(QString *appendableErrorMessage); - - // Watch timer: Listen for debug events and emit watchTimerDebugEvent() should one - // occur. - void startWatchTimer(); - void killWatchTimer(); - inline bool isWatchTimerRunning() const { return m_watchTimer != -1; } - // Synchronous wait - HRESULT waitForEvent(int timeOutMS); - - // Commands and expressions - bool executeDebuggerCommand(const QString &command, QString *errorMessage); - - bool evaluateExpression(const QString &expression, - DEBUG_VALUE *debugValue, - QString *errorMessage); - bool evaluateExpression(const QString &expression, QString *value, - QString *type /* =0 */, QString *errorMessage); - - // Path getters/setters - QStringList sourcePaths() const; - bool setSourcePaths(const QStringList &s, QString *errorMessage); - QStringList symbolPaths() const; - bool setSymbolPaths(const QStringList &s, QString *errorMessage); - - bool isVerboseSymbolLoading() const; - bool setVerboseSymbolLoading(bool v); - - // Options - ExpressionSyntax expressionSyntax() const; - ExpressionSyntax setExpressionSyntax(ExpressionSyntax es); - - CodeLevel codeLevel() const; - CodeLevel setCodeLevel(CodeLevel); - - QString dbengDLL() const { return m_dbengDLL; } - - // Debuggee memory conveniences - bool allocDebuggeeMemory(int size, ULONG64 *address, QString *errorMessage); - bool createDebuggeeAscIIString(const QString &s, ULONG64 *address, QString *errorMessage); - bool writeToDebuggee(const QByteArray &buffer, quint64 address, QString *errorMessage); - // Write to debuggee memory in chunks - bool disassemble(ULONG64 offset, unsigned long beforeLines, unsigned long afterLines, - QString *target, QString *errorMessage); - - quint64 getSourceLineAddress(const QString &file, int line, QString *errorMessage) const; - - static bool autoDetectPath(QString *outPath, - QStringList *checkedDirectories = 0); - - unsigned moduleCount() const; - - bool setBreakOnThrow(bool b, QString *errorMessage); - bool setExceptionCommands(ULONG code, - ULONG executionCommand, - ULONG continueCommand, - QString *errorMessage); - - QString eventFilterStatus() const; - -signals: - void watchTimerDebugEvent(); - - // Emitted in the first time-out of the event handler in which - // the number of modules no longer changes. Can be used as a - // "startup" signal due to lack of a reliable "startup" detection - // feature of the engine. - void modulesLoaded(); - -public slots: - void outputVersion(); - -protected: - virtual void timerEvent(QTimerEvent* te); - -private: - void setModuleCount(unsigned m); - void resetModuleLoadTimer(); - - static CoreEngine *m_instance; - ComInterfaces m_cif; - DebugOutputBasePtr m_debugOutput; - DebugEventCallbackBasePtr m_debugEventCallback; - QString m_dbengDLL; - int m_watchTimer; - unsigned m_moduleCount; - unsigned m_lastTimerModuleCount; - bool m_modulesLoadedEmitted; -}; - -// Utility messages -QString msgDebugEngineComResult(HRESULT hr); -QString msgComFailed(const char *func, HRESULT hr); -QString msgDebuggerCommandFailed(const QString &command, HRESULT hr); -const char *msgExecutionStatusString(ULONG executionStatus); - -// A class that sets an expression syntax on the debug control while in scope. -// Can be nested as it checks for the old value. -class SyntaxSetter { - Q_DISABLE_COPY(SyntaxSetter) -public: - explicit inline SyntaxSetter(CoreEngine *engine, CoreEngine::ExpressionSyntax es) : - m_oldSyntax(engine->setExpressionSyntax(es)), - m_engine(engine) {} - inline ~SyntaxSetter() { m_engine->setExpressionSyntax(m_oldSyntax); } - -private: - const CoreEngine::ExpressionSyntax m_oldSyntax; - CoreEngine *m_engine; -}; - -// Helpers to convert DEBUG_VALUE structs. The optional control is required to -// convert large floating values. -QString debugValueToString(const DEBUG_VALUE &dv, QString *qType =0, int integerBase = 10, CIDebugControl *ctl = 0); -bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value); - -} // namespace CdbCore - -#endif // COREENGINE_H diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.cpp b/src/plugins/debugger/cdb/debugeventcallbackbase.cpp deleted file mode 100644 index 7c5f7c3a62dd049aa7349fadb9f0f3cd48d1446e..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/debugeventcallbackbase.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "debugeventcallbackbase.h" -#include "coreengine.h" - -namespace CdbCore { - -// DebugEventCallbackBase -DebugEventCallbackBase::DebugEventCallbackBase() -{ -} - -DebugEventCallbackBase::~DebugEventCallbackBase() -{ -} - -STDMETHODIMP DebugEventCallbackBase::QueryInterface( - THIS_ - IN REFIID InterfaceId, - OUT PVOID* Interface) -{ - *Interface = NULL; - - if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || - IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) { - *Interface = (IDebugOutputCallbacks *)this; - AddRef(); - return S_OK; - } else { - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) DebugEventCallbackBase::AddRef(THIS) -{ - // This class is designed to be static so - // there's no true refcount. - return 1; -} - -STDMETHODIMP_(ULONG) DebugEventCallbackBase::Release(THIS) -{ - // This class is designed to be static so - // there's no true refcount. - return 0; -} - -STDMETHODIMP DebugEventCallbackBase::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2) -{ - return S_OK; -} -STDMETHODIMP DebugEventCallbackBase::Exception( - THIS_ - __in PEXCEPTION_RECORD64, - __in ULONG /* FirstChance */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::CreateThread( - THIS_ - __in ULONG64 /* Handle */, - __in ULONG64 /* DataOffset */, - __in ULONG64 /* StartOffset */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::ExitThread( - THIS_ - __in ULONG /* ExitCode */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::CreateProcess( - THIS_ - __in ULONG64 /* ImageFileHandle */, - __in ULONG64 /* Handle */, - __in ULONG64 /* BaseOffset */, - __in ULONG /* ModuleSize */, - __in_opt PCWSTR /* ModuleName */, - __in_opt PCWSTR /* ImageName */, - __in ULONG /* CheckSum */, - __in ULONG /* TimeDateStamp */, - __in ULONG64 /* InitialThreadHandle */, - __in ULONG64 /* ThreadDataOffset */, - __in ULONG64 /* StartOffset */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::ExitProcess( - THIS_ - __in ULONG /* ExitCode */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::LoadModule( - THIS_ - __in ULONG64 /* ImageFileHandle */, - __in ULONG64 /* BaseOffset */, - __in ULONG /* ModuleSize */, - __in_opt PCWSTR /* ModuleName */, - __in_opt PCWSTR /* ImageName */, - __in ULONG /* CheckSum */, - __in ULONG /* TimeDateStamp */ - ) -{ - handleModuleLoad(); - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::UnloadModule( - THIS_ - __in_opt PCWSTR /* ImageBaseName */, - __in ULONG64 /* BaseOffset */ - ) -{ - handleModuleUnload(); - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::SystemError( - THIS_ - __in ULONG /* Error */, - __in ULONG /* Level */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::SessionStatus( - THIS_ - __in ULONG /* Status */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::ChangeDebuggeeState( - THIS_ - __in ULONG /* Flags */, - __in ULONG64 /* Argument */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::ChangeEngineState( - THIS_ - __in ULONG /* Flags */, - __in ULONG64 /* Argument */ - ) -{ - return S_OK; -} - -STDMETHODIMP DebugEventCallbackBase::ChangeSymbolState( - THIS_ - __in ULONG /* Flags */, - __in ULONG64 /* Argument */ - ) -{ - return S_OK; -} - -IDebugEventCallbacksWide *DebugEventCallbackBase::getEventCallback(CIDebugClient *clnt) -{ - IDebugEventCallbacksWide *rc = 0; - if (SUCCEEDED(clnt->GetEventCallbacksWide(&rc))) - return rc; - return 0; -} - -void DebugEventCallbackBase::handleModuleLoad() -{ - m_moduleCount++; -} - -void DebugEventCallbackBase::handleModuleUnload() -{ - m_moduleCount--; -} - -unsigned DebugEventCallbackBase::moduleCount() const -{ - return m_moduleCount; -} - -void DebugEventCallbackBase::setModuleCount(unsigned m) -{ - m_moduleCount = m; -} - -ULONG DebugEventCallbackBase::baseInterestMask() const -{ - return DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE; -} - -// ----------- EventCallbackRedirector - -EventCallbackRedirector::EventCallbackRedirector(CoreEngine *engine, - const DebugEventCallbackBasePtr &cb) : - m_engine(engine), - m_oldCallback(engine->setDebugEventCallback(cb)) -{ -} - -EventCallbackRedirector::~EventCallbackRedirector() -{ - m_engine->setDebugEventCallback(m_oldCallback); -} - - -} // namespace CdbCore diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.h b/src/plugins/debugger/cdb/debugeventcallbackbase.h deleted file mode 100644 index 076ebbb1c818ebfbd9c6b02f42a65c46c3e1d896..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/debugeventcallbackbase.h +++ /dev/null @@ -1,197 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGEVENTCALLBACKBASE_H -#define DEBUGEVENTCALLBACKBASE_H - -#include "cdbcom.h" - -#include <QtCore/QSharedPointer> - -namespace CdbCore { - -class CoreEngine; - -// Base class for event callbacks that takes care -// Active X magic. Provides base implementations with -// the exception of GetInterestMask(). The base class -// needs to do some book-keeping on the modules loaded to -// be able to detect the startup/completed attach of a -// debuggee (see CoreEngine::modulesLoaded()). -// So, the interest mask must be at least baseInterestMask() -// and handleModuleLoad/Unload must be called from derived -// classes when overwriting the handlers. -class DebugEventCallbackBase : public IDebugEventCallbacksWide -{ -protected: - DebugEventCallbackBase(); -public: - virtual ~DebugEventCallbackBase(); - // IUnknown. - STDMETHOD(QueryInterface)( - THIS_ - IN REFIID InterfaceId, - OUT PVOID* Interface - ); - STDMETHOD_(ULONG, AddRef)( - THIS - ); - STDMETHOD_(ULONG, Release)( - THIS - ); - - // IDebugEventCallbacks. - - STDMETHOD(Breakpoint)( - THIS_ - __in PDEBUG_BREAKPOINT2 Bp - ); - - STDMETHOD(Exception)( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG FirstChance - ); - - STDMETHOD(CreateThread)( - THIS_ - __in ULONG64 Handle, - __in ULONG64 DataOffset, - __in ULONG64 StartOffset - ); - STDMETHOD(ExitThread)( - THIS_ - __in ULONG ExitCode - ); - - STDMETHOD(CreateProcess)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 Handle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp, - __in ULONG64 InitialThreadHandle, - __in ULONG64 ThreadDataOffset, - __in ULONG64 StartOffset - ); - - STDMETHOD(ExitProcess)( - THIS_ - __in ULONG ExitCode - ); - - // Call handleModuleLoad() when reimplementing this - STDMETHOD(LoadModule)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp - ); - - // Call handleModuleUnload() when reimplementing this - STDMETHOD(UnloadModule)( - THIS_ - __in_opt PCWSTR ImageBaseName, - __in ULONG64 BaseOffset - ); - - STDMETHOD(SystemError)( - THIS_ - __in ULONG Error, - __in ULONG Level - ); - - STDMETHOD(SessionStatus)( - THIS_ - __in ULONG Status - ); - - STDMETHOD(ChangeDebuggeeState)( - THIS_ - __in ULONG Flags, - __in ULONG64 Argument - ); - - STDMETHOD(ChangeEngineState)( - THIS_ - __in ULONG Flags, - __in ULONG64 Argument - ); - - STDMETHOD(ChangeSymbolState)( - THIS_ - __in ULONG Flags, - __in ULONG64 Argument - ); - - - static IDebugEventCallbacksWide *getEventCallback(CIDebugClient *clnt); - - unsigned moduleCount() const; - void setModuleCount(unsigned m); - -protected: - void handleModuleLoad(); - void handleModuleUnload(); - ULONG baseInterestMask() const; - -private: - unsigned m_moduleCount; -}; - -// Utility class to temporarily redirect events to another handler -// as long as in scope -class EventCallbackRedirector { - Q_DISABLE_COPY(EventCallbackRedirector) -public: - typedef QSharedPointer<DebugEventCallbackBase> DebugEventCallbackBasePtr; - - explicit EventCallbackRedirector(CoreEngine *engine, const DebugEventCallbackBasePtr &cb); - ~EventCallbackRedirector(); - -private: - CoreEngine *m_engine; - const DebugEventCallbackBasePtr m_oldCallback; -}; - -} // namespace CdbCore - -#endif // DEBUGEVENTCALLBACKBASE_H diff --git a/src/plugins/debugger/cdb/debugoutputbase.cpp b/src/plugins/debugger/cdb/debugoutputbase.cpp deleted file mode 100644 index 72ae8789b208f203d0ac9c889cbecf09729657d3..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/debugoutputbase.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "debugoutputbase.h" -#include "coreengine.h" -#include <QtCore/QDebug> - -namespace CdbCore { - -DebugOutputBase::DebugOutputBase() -{ -} - -DebugOutputBase::~DebugOutputBase() // must be present to avoid exit crashes -{ -} - -STDMETHODIMP DebugOutputBase::QueryInterface( - THIS_ - IN REFIID InterfaceId, - OUT PVOID* Interface - ) -{ - *Interface = NULL; - - if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || - IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide))) - { - *Interface = (IDebugOutputCallbacksWide*)this; - AddRef(); - return S_OK; - } else { - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) DebugOutputBase::AddRef(THIS) -{ - // This class is designed to be static so - // there's no true refcount. - return 1; -} - -STDMETHODIMP_(ULONG) DebugOutputBase::Release(THIS) -{ - // This class is designed to be static so - // there's no true refcount. - return 0; -} - -STDMETHODIMP DebugOutputBase::Output( - THIS_ - IN ULONG mask, - IN PCWSTR text - ) -{ - const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text)); - output(mask, msg); - return S_OK; -} - -IDebugOutputCallbacksWide *DebugOutputBase::getOutputCallback(CIDebugClient *client) -{ - IDebugOutputCallbacksWide *rc; - if (FAILED(client->GetOutputCallbacksWide(&rc))) - return 0; - return rc; -} - -const char *DebugOutputBase::maskDescription(ULONG m) -{ - switch (m) { - case DEBUG_OUTPUT_NORMAL: - break; - case DEBUG_OUTPUT_ERROR: - return "error"; - case DEBUG_OUTPUT_WARNING: - return "warn"; - case DEBUG_OUTPUT_VERBOSE: - return "verbose"; - case DEBUG_OUTPUT_PROMPT_REGISTERS: - return "register"; - case DEBUG_OUTPUT_EXTENSION_WARNING: - return "extwarn"; - case DEBUG_OUTPUT_DEBUGGEE: - return "target"; - case DEBUG_OUTPUT_DEBUGGEE_PROMPT: - return "input"; - case DEBUG_OUTPUT_SYMBOLS: - return "symbol"; - default: - break; - } - return "misc"; -} - -OutputRedirector::OutputRedirector(CoreEngine *engine, const DebugOutputBasePtr &o) : - m_engine(engine), - m_oldOutput(engine->setDebugOutput(o)) -{ -} - -OutputRedirector::~OutputRedirector() -{ - m_engine->setDebugOutput(m_oldOutput); -} - -} // namespace CdbCore diff --git a/src/plugins/debugger/cdb/debugoutputbase.h b/src/plugins/debugger/cdb/debugoutputbase.h deleted file mode 100644 index 8df543ae7e8ca957bf62b32e37e8742469f29ed1..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/debugoutputbase.h +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGOUTPUTBASE_H -#define DEBUGOUTPUTBASE_H - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QSharedPointer> - -namespace CdbCore { - -class CoreEngine; - -// CdbDebugOutputBase is a base class for output handlers -// that takes care of the Active X magic and conversion to QString. - -class DebugOutputBase : public IDebugOutputCallbacksWide -{ -public: - virtual ~DebugOutputBase(); - // IUnknown. - STDMETHOD(QueryInterface)( - THIS_ - IN REFIID InterfaceId, - OUT PVOID* Interface - ); - STDMETHOD_(ULONG, AddRef)( - THIS - ); - STDMETHOD_(ULONG, Release)( - THIS - ); - - // IDebugOutputCallbacks. - STDMETHOD(Output)( - THIS_ - IN ULONG mask, - IN PCWSTR text - ); - - // Helpers to retrieve the output callbacks IF - static IDebugOutputCallbacksWide *getOutputCallback(CIDebugClient *client); - static const char *maskDescription(ULONG m); - -protected: - DebugOutputBase(); - virtual void output(ULONG mask, const QString &message) = 0; -}; - -// 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 DebugOutputBase -{ -public: - StringOutputHandler() {} - QString result() const { return m_result; } - -protected: - virtual void output(ULONG, const QString &message) { m_result += message; } - -private: - QString m_result; -}; - -// Utility class to temporarily redirect output to another handler -// as long as in scope -class OutputRedirector { - Q_DISABLE_COPY(OutputRedirector) -public: - typedef QSharedPointer<DebugOutputBase> DebugOutputBasePtr; - - explicit OutputRedirector(CoreEngine *engine, const DebugOutputBasePtr &o); - ~OutputRedirector(); - -private: - CoreEngine *m_engine; - const DebugOutputBasePtr m_oldOutput; -}; - -} // namespace CdbCore - -#endif // DEBUGOUTPUTBASE_H diff --git a/src/plugins/debugger/cdb/stacktracecontext.cpp b/src/plugins/debugger/cdb/stacktracecontext.cpp deleted file mode 100644 index 5a98eebda7faa37cec64ef807bca864f1bfdc5ec..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/stacktracecontext.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "stacktracecontext.h" -#include "symbolgroupcontext.h" -#include "corebreakpoint.h" -#include "coreengine.h" - -#include <QtCore/QDir> -#include <QtCore/QDebug> -#include <QtCore/QTextStream> -#include <QtCore/QScopedArrayPointer> - -enum { debug = 0 }; - -namespace CdbCore { - -StackFrame::StackFrame() : - line(0), address(0) -{ -} - -QString StackFrame::toString() const -{ - QString rc; - QTextStream str(&rc); - format(str); - return rc; -} - -QDebug operator<<(QDebug d, const StackFrame &f) -{ - d.nospace() << f.toString(); - return d; -} - -void StackFrame::format(QTextStream &str) const -{ - // left-pad level - if (hasFile()) - str << QDir::toNativeSeparators(fileName) << ':' << line << " ("; - if (!module.isEmpty()) - str << module << '!'; - str << function; - if (hasFile()) - str << ')'; - str.setIntegerBase(16); - str << " 0x" << address; - str.setIntegerBase(10); -} - -Thread::Thread(unsigned long i, unsigned long si) : - id(i), systemId(si), dataOffset(0) -{ -} - -QString Thread::toString() const -{ - QString rc; - QTextStream str(&rc); - str << "Thread id " << id << " System id " << systemId - << " name='" << name <<"' Data at 0x"; - str.setIntegerBase(16); - str << dataOffset; - return rc; -} - -QDebug operator<<(QDebug d, const Thread &t) -{ - d.nospace() << t.toString(); - return d; -} - -// Check for special functions -StackTraceContext::SpecialFunction StackTraceContext::specialFunction(const QString &module, - const QString &function) -{ - if (module == QLatin1String("ntdll")) { - if (function == QLatin1String("DbgBreakPoint")) - return BreakPointFunction; - if (function == QLatin1String("KiFastSystemCallRet")) - return KiFastSystemCallRet; - if (function.startsWith("ZwWaitFor")) - return WaitFunction; - } - if (module == QLatin1String("kernel32")) { - if (function == QLatin1String("MsgWaitForMultipleObjects")) - return WaitFunction; - if (function.startsWith(QLatin1String("WaitFor"))) - return WaitFunction; - } - return None; -} - -StackTraceContext::StackTraceContext(const ComInterfaces *cif) : - m_cif(cif), - m_instructionOffset(0), - m_lastIndex(-1) -{ -} - -StackTraceContext *StackTraceContext::create(const ComInterfaces *cif, - unsigned long maxFramesIn, - QString *errorMessage) -{ - StackTraceContext *ctx = new StackTraceContext(cif); - if (!ctx->init(maxFramesIn, errorMessage)) { - delete ctx; - return 0; - - } - return ctx; -} - -StackTraceContext::~StackTraceContext() -{ - qDeleteAll(m_frameContexts); -} - -// Convert the DEBUG_STACK_FRAMEs to our StackFrame structure -StackFrame StackTraceContext::frameFromFRAME(const CdbCore::ComInterfaces &cif, - const DEBUG_STACK_FRAME &s) -{ - static WCHAR wszBuf[MAX_PATH]; - StackFrame frame; - frame.address = s.InstructionOffset; - cif.debugSymbols->GetNameByOffsetWide(frame.address, wszBuf, MAX_PATH, 0, 0); - // Determine function and module, if available ("Qt4Core!foo"). - const QString moduleFunction = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - const int moduleSepPos = moduleFunction.indexOf(QLatin1Char('!')); - if (moduleSepPos == -1) { - frame.function = moduleFunction; - } else { - frame.module = moduleFunction.left(moduleSepPos); - frame.function = moduleFunction.mid(moduleSepPos + 1); - } - ULONG64 ul64Displacement; - const HRESULT hr = cif.debugSymbols->GetLineByOffsetWide(frame.address, &frame.line, wszBuf, MAX_PATH, 0, &ul64Displacement); - if (SUCCEEDED(hr)) { - const QString rawName = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - if (!rawName.isEmpty()) - frame.fileName = BreakPoint::normalizeFileName(rawName); - } - return frame; -} - -bool StackTraceContext::init(unsigned long maxFramesIn, QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << maxFramesIn; - - // fill the DEBUG_STACK_FRAME array - ULONG frameCount; - const unsigned long effectiveMaxFrames = qMin(maxFramesIn, unsigned long(StackTraceContext::maxFrames)); - const HRESULT hr = m_cif->debugControl->GetStackTrace(0, 0, 0, m_cdbFrames, - effectiveMaxFrames, - &frameCount); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetStackTrace", hr); - return false; - } - - // Adapt group cache. - m_frameContexts.resize(frameCount); - qFill(m_frameContexts, static_cast<SymbolGroupContext*>(0)); - // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames - for (ULONG i=0; i < frameCount; ++i) - m_frames.push_back(frameFromFRAME(*m_cif, m_cdbFrames[i])); - m_instructionOffset = m_frames.empty() ? ULONG64(0) : m_frames.front().address; - return true; -} - -int StackTraceContext::indexOf(const QString &function, - const QString &module /* = QString() */) const -{ - const bool noModuleMatch = module.isEmpty(); - const int count = m_frames.size(); - for (int i = 0; i < count; i++) { - if (m_frames.at(i).function == function - && (noModuleMatch || module == m_frames.at(i).module)) - return i; - } - return -1; -} - -QString StackTraceContext::msgFrameContextFailed(int index, const StackFrame &f, const QString &why) -{ - return QString::fromLatin1("Unable to create stack frame context #%1, %2!%3:%4 (%5): %6"). - arg(index).arg(f.module).arg(f.function).arg(f.line).arg(f.fileName, why); -} - -SymbolGroupContext *StackTraceContext::createSymbolGroup(const ComInterfaces &cif, - int /* index */, - const QString &prefix, - CIDebugSymbolGroup *comSymbolGroup, - QString *errorMessage) -{ - return SymbolGroupContext::create(prefix, comSymbolGroup, cif.debugDataSpaces, - QStringList(), errorMessage); -} - -SymbolGroupContext *StackTraceContext::symbolGroupContextAt(int index, QString *errorMessage) -{ - // Create a frame on demand - if (debug) - qDebug() << Q_FUNC_INFO << index; - - if (index < 0 || index >= m_frameContexts.size()) { - *errorMessage = QString::fromLatin1("%1: Index %2 out of range %3."). - arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_frameContexts.size()); - return 0; - } - if (m_frameContexts.at(index)) { - // Symbol group only functions correctly if IDebugSymbols has the right scope. - if (m_lastIndex != index) { - if (!setScope(index, errorMessage)) - return 0; - m_lastIndex = index; - } - return m_frameContexts.at(index); - } - CIDebugSymbolGroup *comSymbolGroup = createCOM_SymbolGroup(index, errorMessage); - if (!comSymbolGroup) { - *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); - return 0; - } - SymbolGroupContext *sc = createSymbolGroup(*m_cif, index, QLatin1String("local"), - comSymbolGroup, errorMessage); - if (!sc) { - *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); - return 0; - } - m_frameContexts[index] = sc; - return sc; -} - -bool StackTraceContext::setScope(int index, QString *errorMessage) -{ - if (debug) - qDebug() << "setScope" << index; - const HRESULT hr = m_cif->debugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot set scope %1: %2"). - arg(index).arg(CdbCore::msgComFailed("SetScope", hr)); - return false; - } - return true; -} - -CIDebugSymbolGroup *StackTraceContext::createCOM_SymbolGroup(int index, QString *errorMessage) -{ - CIDebugSymbolGroup *sg = 0; - HRESULT hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr); - return 0; - } - // Set debugSymbols's scope. - if (!setScope(index, errorMessage)) { - sg->Release(); - return 0; - } - // refresh with current frame - hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr); - sg->Release(); - return 0; - } - m_lastIndex = index; - return sg; -} - -QString StackTraceContext::toString() const -{ - QString rc; - QTextStream str(&rc); - format(str); - return rc; -} - -void StackTraceContext::format(QTextStream &str) const -{ - const int count = m_frames.count(); - const int defaultFieldWidth = str.fieldWidth(); - const QTextStream::FieldAlignment defaultAlignment = str.fieldAlignment(); - for (int f = 0; f < count; f++) { - // left-pad level - str << qSetFieldWidth(6) << left << f; - str.setFieldWidth(defaultFieldWidth); - str.setFieldAlignment(defaultAlignment); - m_frames.at(f).format(str); - str << '\n'; - } -} - -// Thread state helper -static inline QString msgGetThreadStateFailed(unsigned long threadId, const QString &why) -{ - return QString::fromLatin1("Unable to determine the state of thread %1: %2").arg(threadId).arg(why); -} - -// Determine information about thread. This changes the -// current thread to thread->id. -bool StackTraceContext::getStoppedThreadState(const CdbCore::ComInterfaces &cif, - unsigned long id, - StackFrame *topFrame, - QString *errorMessage) -{ - enum { MaxFrames = 2 }; - ULONG currentThread; - HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(¤tThread); - if (FAILED(hr)) { - *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("GetCurrentThreadId", hr)); - return false; - } - if (currentThread != id) { - hr = cif.debugSystemObjects->SetCurrentThreadId(id); - if (FAILED(hr)) { - *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("SetCurrentThreadId", hr)); - return false; - } - } - ULONG frameCount; - // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is - // not interesting for display. - DEBUG_STACK_FRAME frames[MaxFrames]; - hr = cif.debugControl->GetStackTrace(0, 0, 0, frames, MaxFrames, &frameCount); - if (FAILED(hr)) { - *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("GetStackTrace", hr)); - return false; - } - // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is - // not interesting for display. - *topFrame = frameFromFRAME(cif, frames[0]); - if (frameCount > 1 - && StackTraceContext::specialFunction(topFrame->module, topFrame->function) == KiFastSystemCallRet) - *topFrame = frameFromFRAME(cif, frames[1]); - return true; -} - -static inline QString msgGetThreadsFailed(const QString &why) -{ - return QString::fromLatin1("Unable to determine the thread information: %1").arg(why); -} - -bool StackTraceContext::getThreadList(const CdbCore::ComInterfaces &cif, - QVector<Thread> *threads, - ULONG *currentThreadId, - QString *errorMessage) -{ - threads->clear(); - ULONG threadCount; - *currentThreadId = 0; - // Get count - HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount); - if (FAILED(hr)) { - *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr)); - return false; - } - // Get index of current - if (!threadCount) - return true; - hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId); - if (FAILED(hr)) { - *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr)); - return false; - } - // Get Identifiers - threads->reserve(threadCount); - QScopedArrayPointer<ULONG> ids(new ULONG[threadCount]); - QScopedArrayPointer<ULONG> systemIds(new ULONG[threadCount]); - hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, ids.data(), systemIds.data()); - if (FAILED(hr)) { - *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr)); - return false; - } - // Create entries - static WCHAR name[256]; - for (ULONG i= 0; i < threadCount ; i++) { - const ULONG id = ids[i]; - Thread thread(id, systemIds[i]); - if (ids[i] == *currentThreadId) { // More info for current - ULONG64 offset; - if (SUCCEEDED(cif.debugSystemObjects->GetCurrentThreadDataOffset(&offset))) - thread.dataOffset = offset; - } - // Name - ULONG bytesReceived = 0; - hr = cif.debugAdvanced->GetSystemObjectInformation(DEBUG_SYSOBJINFO_THREAD_NAME_WIDE, - 0, id, name, - sizeof(name), &bytesReceived); - if (SUCCEEDED(hr) && bytesReceived) - thread.name = QString::fromWCharArray(name); - threads->push_back(thread); - } - return true; -} - -bool StackTraceContext::getStoppedThreadFrames(const CdbCore::ComInterfaces &cif, - ULONG currentThreadId, - const QVector<Thread> &threads, - QVector<StackFrame> *frames, - QString *errorMessage) -{ - frames->clear(); - if (threads.isEmpty()) - return true; - frames->reserve(threads.size()); - - const int threadCount = threads.size(); - for (int i = 0; i < threadCount; i++) { - StackFrame frame; - if (!getStoppedThreadState(cif, threads.at(i).id, &frame, errorMessage)) { - qWarning("%s\n", qPrintable(*errorMessage)); - errorMessage->clear(); - } - frames->append(frame); - } - // Restore thread id - if (threads.back().id != currentThreadId) { - const HRESULT hr = cif.debugSystemObjects->SetCurrentThreadId(currentThreadId); - if (FAILED(hr)) { - *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr)); - return false; - } - } - return true; -} - -QDebug operator<<(QDebug d, const StackTraceContext &t) -{ - d.nospace() << t.toString(); - return d; -} - -} diff --git a/src/plugins/debugger/cdb/stacktracecontext.h b/src/plugins/debugger/cdb/stacktracecontext.h deleted file mode 100644 index 7ec496dd2e745bfec6cdf1f0d732d7e6e3e4230c..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/stacktracecontext.h +++ /dev/null @@ -1,178 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CORESTACKTRACECONTEXT_H -#define CORESTACKTRACECONTEXT_H - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QSharedPointer> -#include <QtCore/QMap> - -QT_BEGIN_NAMESPACE -class QTextStream; -class QDebug; -QT_END_NAMESPACE - -namespace CdbCore { - -struct ComInterfaces; -class SymbolGroupContext; - - -struct StackFrame { - StackFrame(); - - bool hasFile() const { return !fileName.isEmpty(); } - void format(QTextStream &) const; - - QString toString() const; - - QString module; - QString function; - QString fileName; - ULONG line; - ULONG64 address; -}; - -struct Thread { - explicit Thread(unsigned long id = 0, unsigned long sysId = 0); - QString toString() const; - - unsigned long id; - unsigned long systemId; - quint64 dataOffset; // Only for current. - QString name; -}; - -inline bool operator<(const Thread &t1, const Thread &t2) { return t1.id < t2.id; } - -QDebug operator<<(QDebug d, const StackFrame &); -QDebug operator<<(QDebug d, const Thread &); - -/* Context representing a break point stack consisting of several frames. - * Maintains an on-demand constructed list of SymbolGroupContext - * containining the local variables of the stack. */ - -class StackTraceContext -{ - Q_DISABLE_COPY(StackTraceContext) - -protected: - explicit StackTraceContext(const ComInterfaces *cif); - bool init(unsigned long maxFramesIn, QString *errorMessage); - -public: - // Utilities to check for special functions - enum SpecialFunction { - BreakPointFunction, - WaitFunction, - KiFastSystemCallRet, - None - }; - static SpecialFunction specialFunction(const QString &module, const QString &function); - - enum { maxFrames = 100 }; - - ~StackTraceContext(); - static StackTraceContext *create(const ComInterfaces *cif, - unsigned long maxFramesIn, - QString *errorMessage); - - // Search for function. Empty module means "don't match on module" - int indexOf(const QString &function, const QString &module = QString()) const; - - // Top-Level instruction offset for disassembler - ULONG64 instructionOffset() const { return m_instructionOffset; } - int frameCount() const { return m_frames.size(); } - - SymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage); - const StackFrame stackFrameAt(int index) const { return m_frames.at(index); } - - // Format for logging - void format(QTextStream &str) const; - QString toString() const; - - // Thread helpers: Retrieve a list of thread ids. Also works when running. - static bool getThreadList(const CdbCore::ComInterfaces &cif, - QVector<Thread> *threads, - ULONG *currentThreadId, - QString *errorMessage); - - // Retrieve detailed information about a threads in stopped state. - // Potentially changes current thread id. - static inline bool getStoppedThreadState(const CdbCore::ComInterfaces &cif, - unsigned long id, - StackFrame *topFrame, - QString *errorMessage); - - // Get the stack traces for threads in stopped state (only, fails when running). - // Potentially changes and restores current thread. - static bool getStoppedThreadFrames(const CdbCore::ComInterfaces &cif, - ULONG currentThreadId, - const QVector<Thread> &threads, - QVector<StackFrame> *frames, - QString *errorMessage); - -protected: - virtual SymbolGroupContext *createSymbolGroup(const ComInterfaces &cif, - int index, - const QString &prefix, - CIDebugSymbolGroup *comSymbolGroup, - QString *errorMessage); - - static QString msgFrameContextFailed(int index, const StackFrame &f, const QString &why); - -private: - bool setScope(int index, QString *errorMessage); - CIDebugSymbolGroup *createCOM_SymbolGroup(int index, QString *errorMessage); - inline static StackFrame frameFromFRAME(const CdbCore::ComInterfaces &cif, - const DEBUG_STACK_FRAME &s); - - // const QSharedPointer<CdbDumperHelper> m_dumper; - const ComInterfaces *m_cif; - - DEBUG_STACK_FRAME m_cdbFrames[maxFrames]; - QVector <SymbolGroupContext*> m_frameContexts; - QVector<StackFrame> m_frames; - ULONG64 m_instructionOffset; - int m_lastIndex; -}; - -QDebug operator<<(QDebug d, const StackTraceContext &); - -} // namespace Internal - -#endif // CORESTACKTRACECONTEXT_H diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.cpp b/src/plugins/debugger/cdb/symbolgroupcontext.cpp deleted file mode 100644 index 324cd6fdca5f9a54a1b14eae9caa8a4dcaa72a6a..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/symbolgroupcontext.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "symbolgroupcontext.h" -#include "coreengine.h" - -#include <QtCore/QTextStream> -#include <QtCore/QCoreApplication> -#include <QtCore/QRegExp> -#include <QtCore/QString> -#include <QtCore/QVariant> -#include <QtCore/QDebug> - -enum { debug = 0 }; -enum { debugInternalDumpers = 0 }; - -// name separator for shadowed variables -static const char iNameShadowDelimiter = '#'; - -static inline QString msgSymbolNotFound(const QString &s) -{ - return QString::fromLatin1("The symbol '%1' could not be found.").arg(s); -} - -static inline QString msgOutOfScope() -{ - return QCoreApplication::translate("SymbolGroup", "Out of scope"); -} - -static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p) -{ - return p.ParentSymbol == DEBUG_ANY_ID; -} - -static inline void debugSymbolFlags(unsigned long f, QTextStream &str) -{ - if (f & DEBUG_SYMBOL_EXPANDED) - str << "DEBUG_SYMBOL_EXPANDED"; - if (f & DEBUG_SYMBOL_READ_ONLY) - str << "|DEBUG_SYMBOL_READ_ONLY"; - if (f & DEBUG_SYMBOL_IS_ARRAY) - str << "|DEBUG_SYMBOL_IS_ARRAY"; - if (f & DEBUG_SYMBOL_IS_FLOAT) - str << "|DEBUG_SYMBOL_IS_FLOAT"; - if (f & DEBUG_SYMBOL_IS_ARGUMENT) - str << "|DEBUG_SYMBOL_IS_ARGUMENT"; - if (f & DEBUG_SYMBOL_IS_LOCAL) - str << "|DEBUG_SYMBOL_IS_LOCAL"; -} - -QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p) -{ - str << " Type=" << p.TypeId << " parent="; - if (isTopLevelSymbol(p)) { - str << "<ROOT>"; - } else { - str << p.ParentSymbol; - } - str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/'; - debugSymbolFlags(p.Flags, str); - return str; -} - -static inline ULONG64 symbolOffset(CIDebugSymbolGroup *sg, unsigned long index) -{ - ULONG64 rc = 0; - if (FAILED(sg->GetSymbolOffset(index, &rc))) - rc = 0; - return rc; -} - -// A helper function to extract a string value from a member function of -// IDebugSymbolGroup2 taking the symbol index and a character buffer. -// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide' - -typedef HRESULT (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG); - -static inline QString getSymbolString(IDebugSymbolGroup2 *sg, - WideStringRetrievalFunction wsf, - unsigned long index) -{ - // Template type names can get quite long.... - enum { BufSize = 1024 }; - static WCHAR nameBuffer[BufSize + 1]; - // Name - ULONG nameLength; - const HRESULT hr = (sg->*wsf)(index, nameBuffer, BufSize, &nameLength); - if (SUCCEEDED(hr)) { - nameBuffer[qMin(nameLength, ULONG(BufSize))] = 0; - return QString::fromUtf16(reinterpret_cast<const ushort *>(nameBuffer)); - } - return QString(); -} - -namespace CdbCore { - -static inline SymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p) -{ - if (p.SubElements == 0u) - return SymbolGroupContext::LeafSymbol; - return (p.Flags & DEBUG_SYMBOL_EXPANDED) ? - SymbolGroupContext::ExpandedSymbol : - SymbolGroupContext::CollapsedSymbol; -} - -SymbolGroupContext::SymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - CIDebugDataSpaces *dataSpaces, - const QStringList &uninitializedVariables) : - m_prefix(prefix), - m_nameDelimiter(QLatin1Char('.')), - m_uninitializedVariables(uninitializedVariables.toSet()), - m_symbolGroup(symbolGroup), - m_dataSpaces(dataSpaces), - m_unnamedSymbolNumber(1), - m_shadowedNameFormat(QLatin1String("%1#%2")) -{ -} - -SymbolGroupContext::~SymbolGroupContext() -{ - m_symbolGroup->Release(); -} - -SymbolGroupContext *SymbolGroupContext::create(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - CIDebugDataSpaces *dataSpaces, - const QStringList &uninitializedVariables, - QString *errorMessage) -{ - SymbolGroupContext *rc = new SymbolGroupContext(prefix, symbolGroup, dataSpaces, uninitializedVariables); - if (!rc->init(errorMessage)) { - delete rc; - return 0; - } - return rc; -} - -bool SymbolGroupContext::init(QString *errorMessage) -{ - // retrieve the root symbols - ULONG count; - HRESULT hr = m_symbolGroup->GetNumberSymbols(&count); - if (FAILED(hr)) { - *errorMessage = CdbCore::msgComFailed("GetNumberSymbols", hr); - return false; - } - - if (count) { - m_symbolParameters.reserve(3u * count); - m_symbolParameters.resize(count); - - hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters()); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO), - CdbCore::msgComFailed("GetSymbolParameters", hr)).arg(count); - return false; - } - populateINameIndexMap(m_prefix, DEBUG_ANY_ID, count); - } - if (debug) - qDebug() << Q_FUNC_INFO << '\n'<< debugToString(); - return true; -} - -QString SymbolGroupContext::shadowedNameFormat() const -{ - return m_shadowedNameFormat; -} - -void SymbolGroupContext::setShadowedNameFormat(const QString &f) -{ - m_shadowedNameFormat = f; -} - -/* Make the entries for iname->index mapping. We might encounter - * already expanded subitems when doing it for top-level ('this'-pointers), - * recurse in that case, (skip over expanded children). - * Loop backwards to detect shadowed variables in the order the -/* debugger expects them: -\code -int x; // Occurrence (1), should be reported as "x <shadowed 1>" -if (true) { - int x = 5; (2) // Occurrence (2), should be reported as "x" -} -\endcode - * The order in the symbol group is (1),(2). Give them an iname of - * <root>#<shadowed-nr>, which will be split apart for display. */ - -void SymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long parentId, - unsigned long end) -{ - const QString symbolPrefix = prefix + m_nameDelimiter; - if (debug) - qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << parentId << end; - for (unsigned long i = end - 1; ; i--) { - const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); - if (parentId == p.ParentSymbol) { - // "__formal" occurs when someone writes "void foo(int /* x */)..." - static const QString unnamedFormalParameter = QLatin1String("__formal"); - QString symbolName = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); - if (symbolName == unnamedFormalParameter) { - symbolName = QLatin1String("<unnamed"); - symbolName += QString::number(m_unnamedSymbolNumber++); - symbolName += QLatin1Char('>'); - } else { - // Trigger numeric sorting for arrays "local.[22]" -> "local.22" - if (symbolName.startsWith(QLatin1Char('[')) && symbolName.endsWith(QLatin1Char(']'))) { - symbolName.truncate(symbolName.size() - 1); - symbolName.remove(0, 1); - } - } - // Find a unique name in case the variable is shadowed by - // an existing one - const QString namePrefix = symbolPrefix + symbolName; - QString name = namePrefix; - for (int n = 1; m_inameIndexMap.contains(name); n++) { - name.truncate(namePrefix.size()); - name += QLatin1Char(iNameShadowDelimiter); - name += QString::number(n); - } - m_inameIndexMap.insert(name, i); - if (getSymbolState(p) == ExpandedSymbol) - populateINameIndexMap(name, i, i + 1 + p.SubElements); - } - if (i == 0 || i == parentId) - break; - } -} - -QString SymbolGroupContext::toString() -{ - QString rc; - QTextStream str(&rc); - const unsigned long count = m_symbolParameters.size(); - QString iname; - QString name; - ULONG64 addr; - ULONG typeId; - QString typeName; - QString value; - - - for (unsigned long i = 0; i < count; i++) { - const unsigned rc = dumpValue(i, &iname, &name, &addr, - &typeId, &typeName, &value); - str << iname << ' ' << name << ' ' << typeName << " (" << typeId - << ") '" << value; - str.setIntegerBase(16); - str << "' 0x" << addr << " flags: 0x" <<rc << '\n'; - str.setIntegerBase(10); - } // for - - return rc; -} - -QString SymbolGroupContext::debugToString(bool verbose) const -{ - QString rc; - QTextStream str(&rc); - const int count = m_symbolParameters.size(); - for (int i = 0; i < count; i++) { - str << i << ' '; - const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); - if (!isTopLevelSymbol(p)) - str << " "; - str << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); - if (p.Flags & DEBUG_SYMBOL_IS_LOCAL) - str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i) << '\''; - str << " Address: " << symbolOffset(m_symbolGroup, i); - if (verbose) - str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, i) << '\''; - str << p << '\n'; - } - if (verbose) { - str << "NameIndexMap\n"; - NameIndexMap::const_iterator ncend = m_inameIndexMap.constEnd(); - for (NameIndexMap::const_iterator it = m_inameIndexMap.constBegin() ; it != ncend; ++it) - str << it.key() << ' ' << it.value() << '\n'; - } - return rc; -} - -SymbolGroupContext::SymbolState SymbolGroupContext::symbolState(unsigned long index) const -{ - return getSymbolState(m_symbolParameters.at(index)); -} - -SymbolGroupContext::SymbolState SymbolGroupContext::symbolState(const QString &prefix) const -{ - if (prefix == m_prefix) // root - return ExpandedSymbol; - unsigned long index; - if (!lookupPrefix(prefix, &index)) { - qWarning("WARNING %s: %s\n", Q_FUNC_INFO, qPrintable(msgSymbolNotFound(prefix))); - return LeafSymbol; - } - return symbolState(index); -} - -// Find index of a prefix -bool SymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const -{ - *index = 0; - const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix); - if (it == m_inameIndexMap.constEnd()) - return false; - *index = it.value(); - return true; -} - -/* Retrieve children and get the position. */ -bool SymbolGroupContext::getChildSymbolsPosition(const QString &prefix, - unsigned long *start, - unsigned long *parentId, - QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << '\n'<< prefix; - - *start = *parentId = 0; - // Root item? - if (prefix == m_prefix) { - *start = 0; - *parentId = DEBUG_ANY_ID; - if (debug) - qDebug() << '<' << prefix << "at" << *start; - return true; - } - // Get parent index, make sure it is expanded - NameIndexMap::const_iterator nit = m_inameIndexMap.constFind(prefix); - if (nit == m_inameIndexMap.constEnd()) { - *errorMessage = QString::fromLatin1("'%1' not found.").arg(prefix); - return false; - } - *parentId = nit.value(); - *start = nit.value() + 1; - if (!expandSymbol(prefix, *parentId, errorMessage)) - return false; - if (debug) - qDebug() << '<' << prefix << "at" << *start; - return true; -} - -static inline QString msgExpandFailed(const QString &prefix, unsigned long index, const QString &why) -{ - return QString::fromLatin1("Unable to expand '%1' %2: %3").arg(prefix).arg(index).arg(why); -} - -bool SymbolGroupContext::expandSymbol(unsigned long index, QString *errorMessage) -{ - return expandSymbol(m_inameIndexMap.key(index), index, errorMessage); -} - -// Expand a symbol using the symbol group interface. -bool SymbolGroupContext::expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage) -{ - if (debug) - qDebug() << '>' << Q_FUNC_INFO << '\n' << prefix << index; - - if (index >= unsigned(m_symbolParameters.size())) { - *errorMessage = QString::fromLatin1("Index %1 (%2) out of range 0..%3."). - arg(index).arg(prefix).arg(m_symbolParameters.size()); - return false; - } - - switch (symbolState(index)) { - case LeafSymbol: - *errorMessage = QString::fromLatin1("Attempt to expand leaf node '%1' %2!").arg(prefix).arg(index); - return false; - case ExpandedSymbol: - return true; - case CollapsedSymbol: - break; - } - - HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE); - if (FAILED(hr)) { - *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("ExpandSymbol", hr)); - return false; - } - // Hopefully, this will never fail, else data structure will be foobar. - const ULONG oldSize = m_symbolParameters.size(); - ULONG newSize; - hr = m_symbolGroup->GetNumberSymbols(&newSize); - if (FAILED(hr)) { - *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetNumberSymbols", hr)); - return false; - } - - // Retrieve the new parameter structs which will be inserted - // after the parents, offsetting consecutive indexes. - m_symbolParameters.resize(newSize); - - hr = m_symbolGroup->GetSymbolParameters(0, newSize, symbolParameters()); - if (FAILED(hr)) { - *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetSymbolParameters", hr)); - return false; - } - // The new symbols are inserted after the parent symbol. - // We need to correct the following values in the name->index map - const unsigned long newSymbolCount = newSize - oldSize; - const NameIndexMap::iterator nend = m_inameIndexMap.end(); - for (NameIndexMap::iterator it = m_inameIndexMap.begin(); it != nend; ++it) - if (it.value() > index) - it.value() += newSymbolCount; - // insert the new symbols - populateINameIndexMap(prefix, index, index + 1 + newSymbolCount); - if (debug > 1) - qDebug() << '<' << Q_FUNC_INFO << '\n' << prefix << index << '\n' << toString(); - return true; -} - -void SymbolGroupContext::clear() -{ - m_symbolParameters.clear(); - m_inameIndexMap.clear(); -} - -QString SymbolGroupContext::symbolINameAt(unsigned long index) const -{ - return m_inameIndexMap.key(index); -} - -// Return hexadecimal pointer value from a CDB pointer value -// which look like "0x000032a" or "0x00000000`0250124a" or -// "0x1`0250124a" on 64-bit systems. -bool SymbolGroupContext::getUnsignedHexValue(QString stringValue, quint64 *value, - int *endPos /* = 0 */) -{ - if (endPos) - *endPos = -1; - *value = 0; - if (!stringValue.startsWith(QLatin1String("0x"))) - return false; - // Chop off character values (0x76 'a') and return right end position - const int blankPos = stringValue.indexOf(QLatin1Char(' ')); - if (endPos) - *endPos = blankPos != -1 ? blankPos : stringValue.size(); - if (blankPos != -1) - stringValue.truncate(blankPos); - stringValue.remove(0, 2); // Remove '0x', as checked above - // Remove 64bit separator - if (stringValue.size() > 9) { - if (stringValue.at(8) == QLatin1Char('`')) - stringValue.remove(8, 1); - } - bool ok; - *value = stringValue.toULongLong(&ok, 16); - return ok; -} - -// Return the format specification of a '0x..', '0n..' -// integer specification or '0' if there is none. -inline char intFormatSpecification(const QString &stringValue) -{ - if (stringValue.size() > 2) { - const QChar format = stringValue.at(1); - if (!format.isDigit()) - return format.toLatin1(); - } - return char(0); -} - -QVariant SymbolGroupContext::getIntValue(const QString &stringValue) -{ - // Is this a "0x<hex'hex>", "0n<decimal>" or something - switch (intFormatSpecification(stringValue)) { - case 'x': { // Hex unsigned - quint64 uvalue; - if (SymbolGroupContext::getUnsignedHexValue(stringValue, &uvalue)) - return QVariant(uvalue); - } - break; - case '\0': // Decimal or none - case 'n': { - qint64 nvalue; - if (SymbolGroupContext::getDecimalIntValue(stringValue, &nvalue)) - return QVariant(nvalue); - } - break; - default: - break; - } - qWarning("CDB: Integer conversion failed for '%s'.", qPrintable(stringValue)); - return QVariant(); -} - -// check for "0x000", "0x000 class X" or its 64-bit equivalents. -bool SymbolGroupContext::isNullPointer(const QString &type , QString valueS) -{ - if (!type.endsWith(QLatin1String(" *"))) - return false; - const int blankPos = valueS.indexOf(QLatin1Char(' ')); - if (blankPos != -1) - valueS.truncate(blankPos); - quint64 value; - return SymbolGroupContext::getUnsignedHexValue(valueS, &value) && value == 0u; -} - -// Fix a symbol group value. It is set to the class type for -// expandable classes (type="class std::foo<..>[*]", -// value="std::foo<...>[*]". This is not desired -// as it widens the value column for complex std::template types. -// Remove the inner template type. - -QString SymbolGroupContext::removeInnerTemplateType(QString value) -{ - const int firstBracketPos = value.indexOf(QLatin1Char('<')); - const int lastBracketPos = firstBracketPos != -1 ? value.lastIndexOf(QLatin1Char('>')) : -1; - if (lastBracketPos != -1) - value.replace(firstBracketPos + 1, lastBracketPos - firstBracketPos -1, QLatin1String("...")); - return value; -} - -QString SymbolGroupContext::formatShadowedName(const QString &name, int n) const -{ - return n > 0 ? m_shadowedNameFormat.arg(name).arg(n) : name; -} - -unsigned SymbolGroupContext::dumpValueRaw(unsigned long index, - QString *inameIn, - QString *nameIn, - ULONG64 *addrIn, - ULONG *typeIdIn, - QString *typeNameIn, - QString *valueIn) const -{ - unsigned rc = 0; - const QString iname = symbolINameAt(index); - *inameIn = iname; - *addrIn = symbolOffset(m_symbolGroup, index); - // Determine name from iname and format shadowed variables correctly - // as "<shadowed X>, see populateINameIndexMap() (from "name#1"). - const int lastDelimiterPos = iname.lastIndexOf(m_nameDelimiter); - QString name = lastDelimiterPos == -1 ? iname : iname.mid(lastDelimiterPos + 1); - int shadowedNumber = 0; - const int shadowedPos = name.lastIndexOf(QLatin1Char(iNameShadowDelimiter)); - if (shadowedPos != -1) { - shadowedNumber = name.mid(shadowedPos + 1).toInt(); - name.truncate(shadowedPos); - } - // For class hierarchies, we get sometimes complicated std::template types here. - // (std::map extends std::tree<>... Remove them for display only. - *nameIn = formatShadowedName(removeInnerTemplateType(name), shadowedNumber); - *typeNameIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); - // Check for uninitialized variables at level 0 only. - const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(index); - *typeIdIn = p.TypeId; - if (p.ParentSymbol == DEBUG_ANY_ID) { - const QString fullShadowedName = formatShadowedName(name, shadowedNumber); - if (m_uninitializedVariables.contains(fullShadowedName)) { - rc |= OutOfScope; - valueIn->clear(); - return rc; - } - } - // In scope: Figure out value - *valueIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); - // Figure out children. The SubElement is only a guess unless the symbol, - // is expanded, so, we leave this as a guess for later updates. - // If the symbol has children (expanded or not), we leave the 'Children' flag - // in 'needed' state. Suppress 0-pointers right ("0x000 class X") - // here as they only lead to children with memory access errors. - if (p.SubElements && !isNullPointer(*typeNameIn, *valueIn)) - rc |= HasChildren; - return rc; -} - -/* The special type dumpers have an integer return code meaning: - * 0: ok - * 1: Dereferencing or retrieving memory failed, this is out of scope, - * do not try to query further. - * > 1: A structural error was encountered, that is, the implementation - * of the class changed (Qt or say, a different STL implementation). - * Visibly warn about it. - * To add further types, have a look at the toString() output of the - * symbol group. */ - -static QString msgStructuralError(const QString &name, const QString &type, int code) -{ - return QString::fromLatin1("Warning: Internal dumper for '%1' (%2) failed with %3.").arg(name, type).arg(code); -} - -static inline bool isStdStringOrPointer(const QString &type) -{ -#define STD_WSTRING "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >" -#define STD_STRING "std::basic_string<char,std::char_traits<char>,std::allocator<char> >" - return type.endsWith(QLatin1String(STD_STRING)) - || type.endsWith(QLatin1String(STD_STRING" *")) - || type.endsWith(QLatin1String(STD_WSTRING)) - || type.endsWith(QLatin1String(STD_WSTRING" *")); -#undef STD_WSTRING -#undef STD_STRING -} - -unsigned SymbolGroupContext::dumpValue(unsigned long index, - QString *inameIn, - QString *nameIn, - ULONG64 *addrIn, - ULONG *typeIdIn, - QString *typeNameIn, - QString *valueIn) -{ - unsigned rc = dumpValueRaw(index, inameIn, nameIn, addrIn, typeIdIn, - typeNameIn, valueIn); - do { - // Is this a previously detected Null-Pointer or out of scope - if ( (rc & OutOfScope) || !(rc & HasChildren) ) - break; - // QString - if (typeNameIn->endsWith(QLatin1String("QString")) || typeNameIn->endsWith(QLatin1String("QString *"))) { - const int drc = dumpQString(index, *inameIn, valueIn); - switch (drc) { - case 0: - rc |= InternalDumperSucceeded; - rc &= ~HasChildren; - break; - case 1: - rc |= InternalDumperError; - break; - default: - rc |= InternalDumperFailed; - qWarning("%s\n", qPrintable(msgStructuralError(*inameIn, *typeNameIn, drc))); - break; - } - } - // StdString - if (isStdStringOrPointer(*typeNameIn)) { - const int drc = dumpStdString(index, *inameIn, valueIn); - switch (drc) { - case 0: - rc |= InternalDumperSucceeded; - rc &= ~HasChildren; - break; - case 1: - rc |= InternalDumperError; - break; - default: - rc |= InternalDumperFailed; - qWarning("%s\n", qPrintable(msgStructuralError(*inameIn, *typeNameIn, drc))); - break; - } - - } - } while (false); - if (debugInternalDumpers) { - QString msg; - QTextStream str(&msg); - str.setIntegerBase(16); - str << "SymbolGroupContext::dump rc=0x" << rc; - str.setIntegerBase(10); - str << " Type='" << *typeNameIn; - str << " (" << *typeIdIn << ") Name='" << *nameIn << "' Value='" << *valueIn << '\''; - qDebug("%s", qPrintable(msg)); - } - return rc; -} - -bool SymbolGroupContext::getDecimalIntValue(QString stringValue, qint64 *value) -{ - // Strip '0n<digits>' format specifier that occurs - // with Debugging tools v6.12 or later - if (stringValue.startsWith(QLatin1String("0n"))) - stringValue.remove(0, 2); - // Chop off character values (0n97 'a') - const int blankPos = stringValue.indexOf(QLatin1Char(' ')); - if (blankPos != -1) - stringValue.truncate(blankPos); - bool ok; - *value = stringValue.toInt(&ok); - return ok; -} - -// Get integer value of symbol group -static inline bool getSG_DecimalIntValue(CIDebugSymbolGroup *sg, int index, qint64 *value) -{ - const QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); - return SymbolGroupContext::getDecimalIntValue(valueS, value); -} - -// Get pointer value of symbol group ("0xAAB") -// Note that this is on "00000000`0250124a" on 64bit systems. -static inline bool getSG_UnsignedHexValue(CIDebugSymbolGroup *sg, int index, quint64 *value) -{ - const QString stringValue = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); - return SymbolGroupContext::getUnsignedHexValue(stringValue, value); -} - -enum { maxStringLength = 4096 }; - -int SymbolGroupContext::dumpQString(unsigned long index, - const QString &iname, - QString *valueIn) -{ - valueIn->clear(); - QString errorMessage; - // Expand string and it's "d" (step over 'static null') - if (!expandSymbol(iname, index, &errorMessage)) - return 2; - const unsigned long dIndex = index + 4; - if (!expandSymbol(dIndex, &errorMessage)) - return 3; - const unsigned long sizeIndex = dIndex + 3; - const unsigned long arrayIndex = dIndex + 4; - // Get size and pointer - qint64 size; - if (!getSG_DecimalIntValue(m_symbolGroup, sizeIndex, &size)) - return 4; - quint64 array; - if (!getSG_UnsignedHexValue(m_symbolGroup, arrayIndex, &array)) - return 5; - // Fetch - const bool truncated = size > maxStringLength; - if (truncated) - size = maxStringLength; - const QChar doubleQuote = QLatin1Char('"'); - if (size > 0) { - valueIn->append(doubleQuote); - // Should this ever be a remote debugger, need to check byte order. - unsigned short *buf = new unsigned short[size + 1]; - unsigned long bytesRead; - const HRESULT hr = m_dataSpaces->ReadVirtual(array, buf, size * ULONG(sizeof(unsigned short)), &bytesRead); - if (FAILED(hr)) { - delete [] buf; - return 1; - } - buf[bytesRead / sizeof(unsigned short)] = 0; - valueIn->append(QString::fromUtf16(buf)); - delete [] buf; - if (truncated) - valueIn->append(QLatin1String("...")); - valueIn->append(doubleQuote); - } else if (size == 0) { - *valueIn = QString(doubleQuote) + doubleQuote; - } else { - *valueIn = QLatin1String("Invalid QString"); - } - return 0; -} - -int SymbolGroupContext::dumpStdString(unsigned long index, - const QString &inameIn, - QString *valueIn) - -{ - QString errorMessage; - // Expand string ->string_val->_bx. - if (!expandSymbol(inameIn, index, &errorMessage)) - return 1; - int sizeIndex = -1; - int bufIndex = -1; - if (m_symbolParameters.at(index).SubElements >= 3 - && m_inameIndexMap.key(index + 3).endsWith(QLatin1String("Bx"))) { - // Up to MSVC 2008 - const int bxIndex = index + 3; - if (m_symbolParameters.at(bxIndex).SubElements < 2 - || !expandSymbol(index + 3, &errorMessage)) - return 2; - // Check if size is something sane - sizeIndex = index + 6; - bufIndex = index + 4; - } else { - // MSVC10 onwards: Large nested string_val structure containing Bx - if (m_symbolParameters.at(index + 1).SubElements < 5 - || !expandSymbol(index + 1, &errorMessage)) - return 3; - const int bxIndex = index + 3; - if (m_symbolParameters.at(bxIndex).SubElements < 3 - || !m_inameIndexMap.key(bxIndex).endsWith(QLatin1String("Bx")) - || !expandSymbol(bxIndex, &errorMessage)) - return 4; - sizeIndex = index + 7; - bufIndex = index + 4; - } - if (sizeIndex < 0 || bufIndex < 0 - || sizeIndex >= m_symbolParameters.size() || bufIndex >= m_symbolParameters.size()) - return 5; - // Extract size and buffer - qint64 size; - if (!getSG_DecimalIntValue(m_symbolGroup, sizeIndex, &size)) - return 6; - if (size < 0) - return 1; - // Just copy over the value of the buf[]-array, which should be the string - *valueIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, bufIndex); - const QChar doubleQuote = QLatin1Char('"'); - const int quotePos = valueIn->indexOf(doubleQuote); - if (quotePos == -1) - return 7; - valueIn->remove(0, quotePos); - if (valueIn->size() > maxStringLength) { - valueIn->truncate(maxStringLength); - valueIn->append(QLatin1String("...\"")); - } - return 0; -} - -bool SymbolGroupContext::assignValue(const QString &iname, const QString &value, - QString *newValue, QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << '\n' << iname << value; - const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(iname); - if (it == m_inameIndexMap.constEnd()) { - *errorMessage = msgSymbolNotFound(iname); - return false; - } - const unsigned long index = it.value(); - const HRESULT hr = m_symbolGroup->WriteSymbolWide(index, reinterpret_cast<PCWSTR>(value.utf16())); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Unable to assign '%1' to '%2': %3"). - arg(value, iname, CdbCore::msgComFailed("WriteSymbolWide", hr)); - return false; - } - if (newValue) - *newValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); - return true; -} - -} // namespace CdbCore diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.h b/src/plugins/debugger/cdb/symbolgroupcontext.h deleted file mode 100644 index 0cc9c6d1ec816be53a67230aa80ef1de1cd340d5..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/cdb/symbolgroupcontext.h +++ /dev/null @@ -1,191 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SYMBOLGROUPCONTEXT_H -#define SYMBOLGROUPCONTEXT_H - -#include "cdbcom.h" - -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QList> -#include <QtCore/QStringList> -#include <QtCore/QPair> -#include <QtCore/QMap> -#include <QtCore/QSet> - -namespace CdbCore { - -/* A thin wrapper around the IDebugSymbolGroup2 interface which represents - * a flat list of symbols using an index (for example, belonging to a stack - * frame). It uses the hierarchical naming convention of WatchHandler as in: - * "local" (invisible root) - * "local.string" (local class variable) - * "local.string.data" (class member) - * and maintains a mapping iname -> index. - * IDebugSymbolGroup2 can "expand" expandable symbols, inserting them into the - * flat list after their parent. - * - * Note the pecularity of IDebugSymbolGroup2 with regard to pointed to items: - * 1) A pointer to a POD (say int *) will expand to a pointed-to integer named '*'. - * 2) A pointer to a class (QString *), will expand to the class members right away, - * omitting the '*' derefenced item. That is a problem since the dumpers trigger - * only on the derefenced item, so, additional handling is required. - */ - -class SymbolGroupContext -{ - Q_DISABLE_COPY(SymbolGroupContext); -protected: - explicit SymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - CIDebugDataSpaces *dataSpaces, - const QStringList &uninitializedVariables = QStringList()); - bool init(QString *errorMessage); - -public: - virtual ~SymbolGroupContext(); - static SymbolGroupContext *create(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, - CIDebugDataSpaces *dataSpaces, - const QStringList &uninitializedVariables, - QString *errorMessage); - - QString prefix() const { return m_prefix; } - int size() const { return m_symbolParameters.size(); } - - // Format a shadowed variable name/iname using a format taking two arguments: - // "x <shadowed n" - QString shadowedNameFormat() const; - void setShadowedNameFormat(const QString &); - - bool assignValue(const QString &iname, const QString &value, - QString *newValue /* = 0 */, QString *errorMessage); - - bool lookupPrefix(const QString &prefix, unsigned long *index) const; - - enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol }; - SymbolState symbolState(unsigned long index) const; - SymbolState symbolState(const QString &prefix) const; - - inline bool isExpanded(unsigned long index) const { return symbolState(index) == ExpandedSymbol; } - inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; } - - // Dump name/type of an entry running the internal dumpers for known types - // May expand symbols. - - enum ValueFlags { - HasChildren = 0x1, - OutOfScope = 0x2, - InternalDumperSucceeded = 0x4, - InternalDumperError = 0x8, // Hard error - InternalDumperFailed = 0x10, - InternalDumperMask = InternalDumperSucceeded|InternalDumperError|InternalDumperFailed - }; - - unsigned dumpValue(unsigned long index, QString *inameIn, QString *nameIn, ULONG64 *addrIn, - ULONG *typeIdIn, QString *typeNameIn, QString *valueIn); - - // For 64bit values (returned as dec), potentially '0n..'. - static bool getDecimalIntValue(QString stringValue, qint64 *value); - // For pointers and 64bit values (returned as hex) - static bool getUnsignedHexValue(QString stringValue, quint64 *value, int *endPos = 0); - // Convenience to return an integer (hex/decimal) as matching variant (signed/unsigned). - static QVariant getIntValue(const QString &stringValue); - - // Null-check for pointers - static bool isNullPointer(const QString &type , QString valueS); - // Symbol group values may contain template types which is not desired. - static QString removeInnerTemplateType(QString value); - - QString debugToString(bool verbose = false) const; - QString toString(); // calls dump/potentially expands - - // Filter out locale variables and arguments - inline static bool isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p); - -protected: - bool getChildSymbolsPosition(const QString &prefix, - unsigned long *startPos, - unsigned long *parentId, - QString *errorMessage); - - const DEBUG_SYMBOL_PARAMETERS &symbolParameterAt(int i) const { return m_symbolParameters.at(i); } - -private: - typedef QMap<QString, unsigned long> NameIndexMap; - - void clear(); - bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage); - bool expandSymbol(unsigned long index, QString *errorMessage); - void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long end); - QString symbolINameAt(unsigned long index) const; - inline QString formatShadowedName(const QString &name, int n) const; - - // Raw dump of an entry (without dumpers) - unsigned dumpValueRaw(unsigned long index, QString *inameIn, QString *nameIn, - ULONG64 *addrIn, ULONG *typeIdIn, QString *typeNameIn, - QString *valueIn) const; - - int dumpQString(unsigned long index, const QString &inameIn, QString *valueIn); - int dumpStdString(unsigned long index, const QString &inameIn, QString *valueIn); - - inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } - inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); } - - const QString m_prefix; - const QChar m_nameDelimiter; - const QSet<QString> m_uninitializedVariables; - - CIDebugSymbolGroup *m_symbolGroup; - CIDebugDataSpaces *m_dataSpaces; - NameIndexMap m_inameIndexMap; - QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters; - int m_unnamedSymbolNumber; - QString m_shadowedNameFormat; -}; - -// Filter out locale variables and arguments -bool SymbolGroupContext::isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p) -{ - if (p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT)) - return true; - // Do not display static members. - if (p.Flags & DEBUG_SYMBOL_READ_ONLY) - return false; - return true; -} - -} // namespace CdbCore - -#endif // SYMBOLGROUPCONTEXT_H diff --git a/src/plugins/debugger/cdb2/cdbengine2.cpp b/src/plugins/debugger/cdb2/cdbengine2.cpp index e295d3f065b788536ec738ec0814f20e752e943c..0c710d1f8a3266a52b5655de8cecca1ab6a03766 100644 --- a/src/plugins/debugger/cdb2/cdbengine2.cpp +++ b/src/plugins/debugger/cdb2/cdbengine2.cpp @@ -54,6 +54,7 @@ #include <coreplugin/icore.h> #include <texteditor/itexteditor.h> +#include <projectexplorer/toolchain.h> #include <utils/synchronousprocess.h> #include <utils/winutils.h> @@ -248,14 +249,26 @@ static inline bool validMode(DebuggerStartMode sm) return true; } +static inline QString msgCdbDisabled(ProjectExplorer::ToolChainType tc) +{ + return CdbEngine::tr("The CDB debug engine required for %1 is currently disabled."). + arg(ProjectExplorer::ToolChain::toolChainName(tc)); +} + // Accessed by RunControlFactory DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *errorMessage) { #ifdef Q_OS_WIN CdbOptionsPage *op = CdbOptionsPage::instance(); - QTC_ASSERT(op, return 0); - if (validMode(sp.startMode)) - return new CdbEngine(sp, op->options()); + if (!op || !op->options()->isValid()) { + *errorMessage = msgCdbDisabled(static_cast<ProjectExplorer::ToolChainType>(sp.toolChainType)); + return 0; + } + if (!validMode(sp.startMode)) { + *errorMessage = CdbEngine::tr("The CDB debug engine does not support start mode %1.").arg(sp.startMode); + return 0; + } + return new CdbEngine(sp, op->options()); #else Q_UNUSED(sp) #endif @@ -266,12 +279,38 @@ DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *erro bool isCdbEngineEnabled() { #ifdef Q_OS_WIN - return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->enabled; + return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid(); #else return false; #endif } +bool checkCdbConfiguration(int toolChainI, QString *errorMsg, QString *settingsPage) +{ + const ProjectExplorer::ToolChainType toolChain = static_cast<ProjectExplorer::ToolChainType>(toolChainI); + switch (toolChain) { + case ProjectExplorer::ToolChain_MinGW: // Do our best + case ProjectExplorer::ToolChain_MSVC: + case ProjectExplorer::ToolChain_WINCE: + case ProjectExplorer::ToolChain_OTHER: + case ProjectExplorer::ToolChain_UNKNOWN: + case ProjectExplorer::ToolChain_INVALID: + if (!isCdbEngineEnabled()) { + *errorMsg = msgCdbDisabled(toolChain); + *settingsPage = CdbOptionsPage::settingsId(); + return false; + } + break; + default: + //: %1 is something like "GCCE" or "Intel C++ Compiler (Linux)" (see ToolChain context) + *errorMsg = CdbEngine::tr("The CDB debug engine does not support the %1 toolchain."). + arg(ProjectExplorer::ToolChain::toolChainName(toolChain)); + *settingsPage = CdbOptionsPage::settingsId(); + return false; + } + return true; +} + void addCdb2OptionPages(QList<Core::IOptionsPage *> *opts) { opts->push_back(new CdbOptionsPage); diff --git a/src/plugins/debugger/cdb2/cdboptions2.h b/src/plugins/debugger/cdb2/cdboptions2.h index cb7f94c31f883c869d5290b5580840d0205f529d..c881fe8b0bc16560229b449d743e0066f975beb0 100644 --- a/src/plugins/debugger/cdb2/cdboptions2.h +++ b/src/plugins/debugger/cdb2/cdboptions2.h @@ -47,6 +47,9 @@ struct CdbOptions { public: CdbOptions(); + + bool isValid() const { return enabled && !executable.isEmpty(); } + void clearExecutable(); void clear(); diff --git a/src/plugins/debugger/cdb2/cdboptionspage2.cpp b/src/plugins/debugger/cdb2/cdboptionspage2.cpp index f1651dd5f1de396ef3aeee6452d060a80dc5edcd..c92f60d68d506cd77cdc852549eb63f67ab9b296 100644 --- a/src/plugins/debugger/cdb2/cdboptionspage2.cpp +++ b/src/plugins/debugger/cdb2/cdboptionspage2.cpp @@ -394,7 +394,7 @@ QString CdbOptionsPage::settingsId() QString CdbOptionsPage::displayName() const { - return tr("CDB (new, experimental)"); + return tr("CDB"); } QString CdbOptionsPage::category() const diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 68f145c250b5814f726e1b0c528d4540bb9609c9..a945b8df2a7d7ed5aeb915a4d8374c7f5789a670 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -126,7 +126,6 @@ SOURCES += registerpostmortemaction.cpp LIBS *= -lole32 \ -lshell32 } -include(cdb/cdb.pri) include(cdb2/cdb2.pri) include(gdb/gdb.pri) include(script/script.pri) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index e918e521d27159324766c9e51ef89075d28194a3..56f1346555f81c7745507d6ecf7e6d48fb4fa551 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -418,9 +418,6 @@ namespace Internal { void addGdbOptionPages(QList<IOptionsPage*> *opts); void addScriptOptionPages(QList<IOptionsPage*> *opts); void addTcfOptionPages(QList<IOptionsPage*> *opts); -#ifdef CDB_ENABLED -void addCdbOptionPages(QList<IOptionsPage*> *opts); -#endif #ifdef WITH_LLDB void addLldbOptionPages(QList<IOptionsPage*> *opts); @@ -3018,10 +3015,6 @@ void DebuggerPluginPrivate::extensionsInitialized() QList<Core::IOptionsPage *> engineOptionPages; if (m_cmdLineEnabledEngines & GdbEngineType) addGdbOptionPages(&engineOptionPages); -#ifdef CDB_ENABLED - if (m_cmdLineEnabledEngines & CdbEngineType) - addCdbOptionPages(&engineOptionPages); -#endif #ifdef Q_OS_WIN Debugger::Cdb::addCdb2OptionPages(&engineOptionPages); #endif diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 65a00bbe82b30d27cdce682da0e85d97cb2ef8aa..ef43875b2216f8f19cd062e94a49f356d25734c5 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -71,6 +71,7 @@ namespace Debugger { namespace Cdb { DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *error); bool isCdbEngineEnabled(); // Check the configuration page +bool checkCdbConfiguration(int toolChainI, QString *errorMsg, QString *settingsPage); } namespace Internal { @@ -85,32 +86,6 @@ DebuggerEngine *createLldbEngine(const DebuggerStartParameters &); extern QString msgNoBinaryForToolChain(int tc); -// FIXME: Outdated? -// The createCdbEngine function takes a list of options pages it can add to. -// This allows for having a "enabled" toggle on the page independently -// of the engine. That's good for not enabling the related ActiveX control -// unnecessarily. - -#ifdef CDB_ENABLED - -DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *error); -bool checkCdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage); -bool isCdbEngineEnabled(); // Check the configuration page - -#else - -DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *) -{ - return 0; -} - -bool checkCdbConfiguration(int, QString *, QString *) -{ - return false; -} - -#endif - static QString msgEngineNotAvailable(const char *engine) { return DebuggerPlugin::tr("The application requires the debugger engine '%1', " @@ -343,11 +318,7 @@ DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration, d->m_engine = createScriptEngine(sp); break; case CdbEngineType: - // Try new engine, fall back to old. - if (Cdb::isCdbEngineEnabled()) - d->m_engine = Cdb::createCdbEngine(sp, &d->m_errorMessage); - else - d->m_engine = Internal::createCdbEngine(sp, &d->m_errorMessage); + d->m_engine = Cdb::createCdbEngine(sp, &d->m_errorMessage); break; case PdbEngineType: d->m_engine = createPdbEngine(sp); @@ -445,7 +416,7 @@ bool DebuggerRunControl::checkDebugConfiguration(int toolChain, } break; case ProjectExplorer::ToolChain_MSVC: - success = checkCdbConfiguration(toolChain, errorMessage, settingsPage); + success = Cdb::checkCdbConfiguration(toolChain, errorMessage, settingsPage); if (!success) { *errorMessage += msgEngineNotAvailable("Cdb"); if (settingsPage) diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 0b8f53b2ea75551c4e89dcc9a5c62d31d0446306..c9741c332ed5018f03b5ad8412ffc0598df08c92 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -10,11 +10,13 @@ #include <QtCore/QTimer> namespace Debugger { +namespace Cdb { +DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *); +} namespace Internal { const int ConnectionWaitTimeMs = 5000; -DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *); DebuggerEngine *createGdbEngine(const DebuggerStartParameters &); DebuggerEngine *createQmlEngine(const DebuggerStartParameters &); @@ -58,7 +60,7 @@ QmlCppEngine::QmlCppEngine(const DebuggerStartParameters &sp) d->m_cppEngine = createGdbEngine(sp); } else { QString errorMessage; - d->m_cppEngine = createCdbEngine(sp, &errorMessage); + d->m_cppEngine = Debugger::Cdb::createCdbEngine(sp, &errorMessage); if (!d->m_cppEngine) { qWarning("%s", qPrintable(errorMessage)); return; diff --git a/tests/tools/ccdb/README b/tests/tools/ccdb/README deleted file mode 100644 index 56e3426f2f4241dd4cf39b4424ccd67203eb7e0e..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/README +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains a command line tool to the Debugging Tools for -Windows for testing/scripting purposes. diff --git a/tests/tools/ccdb/ccdb.pro b/tests/tools/ccdb/ccdb.pro deleted file mode 100644 index fc6de24eb0cc45b662d1ebe0b7c51c6af09e9d10..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/ccdb.pro +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------- -# Project created by QtCreator 2010-01-22T10:11:10 -# ------------------------------------------------- -QT += core -TARGET = ccdb -CONFIG += console -CONFIG -= app_bundle -TEMPLATE = app - -DEFINES += TEST_COMPILE -# -- Add CDB core engine -CDB_CORE = ../../../src/plugins/debugger/cdb -include($$CDB_CORE/cdbcore.pri) -INCLUDEPATH *= $$CDB_CORE - -include(../../../qtcreator.pri) - -# -- Add creator 'utils' lib -CREATOR_LIB_LIB = ../../../lib/qtcreator -LIBS *= -L$$CREATOR_LIB_LIB -LIBS *= -l$$qtLibraryName(Utils) -CREATOR_LIB_SRC = ../../../src/libs -INCLUDEPATH *= $$CREATOR_LIB_SRC - -# -- App sources -SOURCES += main.cpp \ - cdbapplication.cpp \ - debugeventcallback.cpp \ - cdbpromptthread.cpp -HEADERS += cdbapplication.h \ - debugeventcallback.h \ - cdbpromptthread.h diff --git a/tests/tools/ccdb/cdbapplication.cpp b/tests/tools/ccdb/cdbapplication.cpp deleted file mode 100644 index b886652d7bcb0196625bb3fff4ead14d8cb09525..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/cdbapplication.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbapplication.h" -#include "coreengine.h" -#include "cdbdebugoutput.h" -#include "cdbpromptthread.h" -#include "debugeventcallback.h" -#include "symbolgroupcontext.h" -#include "stacktracecontext.h" -#include <QtCore/QStringList> -#include <QtCore/QTimer> -#include <QtCore/QDebug> - -#include <cstdio> -#include <cerrno> - -const char usage[] = -"CDB command line test tool\n\n" -"ccdb <Options>\n" -"Options: -p engine path\n" -" -c initial_command_file\n"; - -class PrintfOutputHandler : public CdbCore::DebugOutputBase -{ -public: - PrintfOutputHandler() {} - -protected: - virtual void output(ULONG mask, const QString &message) - { std::printf("%10s: %s\n", maskDescription(mask), qPrintable(message)); } -}; - - -// -------------- CdbApplication -CdbApplication::CdbApplication(int argc, char *argv[]) : - QCoreApplication(argc, argv), - m_engine(new CdbCore::CoreEngine), - m_promptThread(0), - m_processHandle(0) -{ -} - -CdbApplication::~CdbApplication() -{ -} - -CdbApplication::InitResult CdbApplication::init() -{ - FILE *inputFile; - if (!parseOptions(&inputFile)) { - printf(usage); - return InitUsageShown; - } - QString errorMessage; - std::printf("Initializing engine %s...\n", qPrintable(m_engineDll)); - if (!m_engine->init(m_engineDll, &errorMessage)) { - std::fprintf(stderr, "Failed: %s\n", qPrintable(errorMessage)); - return InitFailed; - } - m_engine->setDebugOutput(CdbCore::CoreEngine::DebugOutputBasePtr(new PrintfOutputHandler)); - DebugEventCallback *evt = new DebugEventCallback; - connect(evt, SIGNAL(processAttached(void*)), this, SLOT(processAttached(void*))); - m_engine->setDebugEventCallback(CdbCore::CoreEngine::DebugEventCallbackBasePtr(evt)); - m_engine->setExpressionSyntax(CdbCore::CoreEngine::CppExpressionSyntax); - m_engine->setCodeLevel(CdbCore::CoreEngine::CodeLevelSource); - connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), this, SLOT(debugEvent())); - std::printf("Succeded.\n"); - // Prompt - m_promptThread = new CdbPromptThread(inputFile, this); - connect(m_promptThread, SIGNAL(finished()), this, SLOT(promptThreadTerminated())); - connect(m_promptThread, SIGNAL(asyncCommand(int,QString)), - this, SLOT(asyncCommand(int,QString)), Qt::QueuedConnection); - connect(m_promptThread, SIGNAL(syncCommand(int,QString)), - this, SLOT(syncCommand(int,QString)), Qt::BlockingQueuedConnection); - connect(m_promptThread, SIGNAL(executionCommand(int,QString)), - this, SLOT(executionCommand(int,QString)), Qt::BlockingQueuedConnection); - connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), m_promptThread, SLOT(notifyDebugEvent()), - Qt::QueuedConnection); - m_promptThread->start(); - return InitOk; -} - -void CdbApplication::promptThreadTerminated() -{ - QString errorMessage; - m_engine->endSession(&errorMessage); - std::printf("Terminating.\n"); - m_promptThread->wait(); - quit(); -} - -bool CdbApplication::parseOptions(FILE **inputFile) -{ - *inputFile = NULL; - const QStringList args = QCoreApplication::arguments(); - const QStringList::const_iterator cend = args.constEnd(); - QStringList::const_iterator it = args.constBegin(); - for (++it; it != cend ; ++it) { - const QString &a = *it; - if (a.startsWith(QLatin1Char('-')) && a.size() >= 2) { - switch (a.at(1).toAscii()) { - case 'p': - ++it; - if (it == cend) { - std::fprintf(stderr, "Option -p is missing an argument.\n"); - return false; - } - m_engineDll = *it; - break; - case 'c': - ++it; - if (it == cend) { - std::fprintf(stderr, "Option -c is missing an argument.\n"); - return false; - } - *inputFile = std::fopen( it->toLocal8Bit().constData(), "r"); - if (*inputFile == NULL) { - std::fprintf(stderr, "Cannot open %s: %s\n", qPrintable(*it), std::strerror(errno)); - return false; - } - break; - - default: - std::fprintf(stderr, "Invalid option %s\n", qPrintable(a)); - return false; - } - } - } - return true; -} - -void CdbApplication::asyncCommand(int command, const QString &arg) -{ - Q_UNUSED(arg) - QString errorMessage; - switch (command) { - case Async_Interrupt: - if (m_processHandle) { - if (m_engine->debugBreakProcess(m_processHandle, &errorMessage)) { - std::printf("Stopped\n"); - } else { - std::printf("%s\n", qPrintable(errorMessage)); - } - } - break; - } -} - -void CdbApplication::printFrame(const QString &arg) -{ - QString errorMessage; - do { - if (m_stackTrace.isNull()) { - errorMessage = QLatin1String("No trace."); - break; - } - bool ok; - const int frame = arg.toInt(&ok); - if (!ok || frame < 0 || frame >= m_stackTrace->frameCount()) { - errorMessage = QLatin1String("Invalid or out of range."); - break; - } - CdbCore::SymbolGroupContext *ctx = m_stackTrace->symbolGroupContextAt(frame, &errorMessage); - if (!ctx) - break; - printf("%s\n", qPrintable(ctx->toString())); - } while (false); - if (!errorMessage.isEmpty()) - printf("%s\n", qPrintable(errorMessage)); -} - -// Return address or 0 on failure -quint64 CdbApplication::addQueuedBreakPoint(const QString &arg, QString *errorMessage) -{ - // Queue file:line - const int cpos = arg.lastIndexOf(QLatin1Char(':')); - if (cpos == -1) { - *errorMessage = QString::fromLatin1("Syntax error in '%1': No colon.").arg(arg); - return 0; - } - - const QString fileName = arg.left(cpos); - bool ok; - const int lineNumber = arg.mid(cpos + 1).toInt(&ok); - if (!ok || lineNumber < 1) { - *errorMessage = QString::fromLatin1("Syntax error in '%1': No line number.").arg(arg); - return 0; - } - CdbCore::BreakPoint bp; - bp.address = m_engine->getSourceLineAddress(fileName, lineNumber, errorMessage); - if (!bp.address) - return 0; - if (!bp.add(m_engine->interfaces().debugControl, errorMessage)) - return 0; - return bp.address; -} - -void CdbApplication::syncCommand(int command, const QString &arg) -{ - QString errorMessage; - switch (command) { - case Sync_EvalExpression: { - QString value; - QString type; - std::printf("Evaluating '%s' in code level %d, syntax %d\n", - qPrintable(arg), m_engine->codeLevel(), m_engine->expressionSyntax()); - if (m_engine->evaluateExpression(arg, &value, &type, &errorMessage)) { - std::printf("[%s] %s\n", qPrintable(type), qPrintable(value)); - } else { - std::printf("%s\n", qPrintable(errorMessage)); - } - } - break; - case Sync_Queue: { - const QString targs = arg.trimmed(); - if (targs.isEmpty()) { - std::printf("Queue cleared\n"); - m_queuedCommands.clear(); - } else { - std::printf("Queueing %s\n", qPrintable(targs)); - m_queuedCommands.push_back(targs); - } - } - break; - case Sync_QueueBreakPoint: { - const QString targs = arg.trimmed(); - if (targs.isEmpty()) { - std::printf("Breakpoint queue cleared\n"); - m_queuedBreakPoints.clear(); - } else { - m_queuedBreakPoints.push_back(targs); - std::printf("Queueing breakpoint %s\n", qPrintable(targs)); - } - } - break; - case Sync_ListBreakPoints: { - QList<CdbCore::BreakPoint> bps; - if (CdbCore::BreakPoint::getBreakPoints(m_engine->interfaces().debugControl, &bps, &errorMessage)) { - foreach (const CdbCore::BreakPoint &bp, bps) - std::printf("%s\n", qPrintable(bp.expression())); - } else { - std::printf("BREAKPOINT LIST FAILED: %s\n", qPrintable(errorMessage)); - } -} - break; - case Sync_PrintFrame: - printFrame(arg); - break; - case Sync_OutputVersion: - m_engine->outputVersion(); - break; - case Sync_Python: - break; - case Unknown: - std::printf("Executing '%s' in code level %d, syntax %d\n", - qPrintable(arg), m_engine->codeLevel(), m_engine->expressionSyntax()); - if (!m_engine->executeDebuggerCommand(arg, &errorMessage)) - std::printf("%s\n", qPrintable(errorMessage)); - break; - } -} - -void CdbApplication::executionCommand(int command, const QString &arg) -{ - bool ok = false; - QString errorMessage; - switch (command) { - case Execution_StartBinary: { - QStringList args = arg.split(QLatin1Char(' '), QString::SkipEmptyParts); - if (args.isEmpty()) { - errorMessage = QLatin1String("Specify executable."); - } else { - std::printf("Starting\n"); - const QString binary = args.front(); - args.pop_front(); - ok = m_engine->startDebuggerWithExecutable(QString(), binary, args, - QStringList(), &errorMessage); - } - } - break; - case Execution_Go: - std::printf("Go\n"); - ok = m_engine->setExecutionStatus(DEBUG_STATUS_GO, &errorMessage); - break; - } - if (ok) { - m_engine->startWatchTimer(); - m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>(); - } else { - std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); - } -} - -void CdbApplication::debugEvent() -{ - QString errorMessage; - std::printf("Debug event\n"); - - QVector<CdbCore::Thread> threads; - QVector<CdbCore::StackFrame> threadFrames; - ULONG currentThreadId; - - if (CdbCore::StackTraceContext::getThreadList(m_engine->interfaces(), &threads, ¤tThreadId, &errorMessage) - && CdbCore::StackTraceContext::getStoppedThreadFrames(m_engine->interfaces(), currentThreadId, threads, &threadFrames, &errorMessage)) { - const int count = threadFrames.size(); - for (int i = 0; i < count; i++) { - printf("Thread #%02d ID %10d SYSID %10d %s\n", i, - threads.at(i).id, threads.at(i).systemId, qPrintable(threadFrames.at(i).toString())); - } - } else { - std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); - } - - CdbCore::StackTraceContext *trace = - CdbCore::StackTraceContext::create(&m_engine->interfaces(), - 0xFFFF, &errorMessage); - if (trace) { - m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>(trace); - printf("%s\n", qPrintable(m_stackTrace->toString())); - } else { - std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); - } -} - -void CdbApplication::processAttached(void *handle) -{ - std::printf("### Process attached\n"); - m_processHandle = handle; - QString errorMessage; - // Commands - foreach(const QString &qc, m_queuedCommands) { - if (m_engine->executeDebuggerCommand(qc, &errorMessage)) { - std::printf("'%s' [ok]\n", qPrintable(qc)); - } else { - std::printf("%s\n", qPrintable(errorMessage)); - } - } - // Breakpoints - foreach(const QString &bp, m_queuedBreakPoints) { - if (const quint64 address = addQueuedBreakPoint(bp, &errorMessage)) { - std::printf("'%s' 0x%lx [ok]\n", qPrintable(bp), address); - } else { - std::fprintf(stderr, "%s: %s\n", - qPrintable(bp), - qPrintable(errorMessage)); - } - } -} diff --git a/tests/tools/ccdb/cdbapplication.h b/tests/tools/ccdb/cdbapplication.h deleted file mode 100644 index df497a4ff0f055b8996db24b5df988820ce7f2f5..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/cdbapplication.h +++ /dev/null @@ -1,88 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CDBAPPLICATION_H -#define CDBAPPLICATION_H - -#include "corebreakpoint.h" - -#include <QtCore/QCoreApplication> -#include <QtCore/QSharedPointer> -#include <QtCore/QScopedPointer> -#include <QtCore/QStringList> - -#include <cstdio> - -namespace CdbCore { - class CoreEngine; - class StackTraceContext; -} - -class CdbPromptThread; - -class CdbApplication : public QCoreApplication -{ - Q_OBJECT - Q_DISABLE_COPY(CdbApplication) -public: - enum InitResult { InitFailed, InitUsageShown, InitOk }; - - CdbApplication(int argc, char *argv[]); - ~CdbApplication(); - - InitResult init(); - -private slots: - void promptThreadTerminated(); - void asyncCommand(int command, const QString &arg); - void syncCommand(int command, const QString &arg); - void executionCommand(int command, const QString &arg); - void debugEvent(); - void processAttached(void *handle); - -private: - bool parseOptions(FILE **inputFile); - void printFrame(const QString &arg); - quint64 addQueuedBreakPoint(const QString &arg, QString *errorMessage); - - QString m_engineDll; - QSharedPointer<CdbCore::CoreEngine> m_engine; - QSharedPointer<CdbCore::StackTraceContext> m_stackTrace; - CdbPromptThread *m_promptThread; - QStringList m_queuedCommands; - QStringList m_queuedBreakPoints; - - void *m_processHandle; -}; - -#endif // CDBAPPLICATION_H diff --git a/tests/tools/ccdb/cdbpromptthread.cpp b/tests/tools/ccdb/cdbpromptthread.cpp deleted file mode 100644 index 414c616166ef8d14eaa728af6ba3b25b583e564d..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/cdbpromptthread.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbpromptthread.h" - -#include <QtCore/QDebug> - -static const char help[] = -"Special commands:\n\n" -"H Display Help\n" -"V Output version\n" -"E expression Evaluate C++expression\n" -"S binary args Start binary\n" -"I Interrupt\n" -"G Go\n" -"Q cmd Queue command for execution in AttachProcess\n" -"Q Clear command queue\n" -"B file:line Queue a breakpoint for adding in AttachProcess\n" -"B Clear breakpoint queue\n" -"L List breakpoints\n" -"F <n> Print stack frame <n>, 0 being top\n" -"P <cmd> Run Python command\n" -"W Synchronous wait for debug event\n" -"\nThe remaining commands are passed to CDB.\n"; - -CdbPromptThread::CdbPromptThread(FILE *file, QObject *parent) : - QThread(parent), - m_waitingForDebugEvent(false), - m_inputFile(file) -{ - if (!m_inputFile) - m_inputFile = stdin; -} - -void CdbPromptThread::run() -{ - enum { bufSize =1024 }; - - QString cmd; - char buf[bufSize]; - std::putc('>', stdout); - // When reading from an input file, switch to stdin after reading it out - while (true) { - if (std::fgets(buf, bufSize, m_inputFile) == NULL) { - if (m_inputFile == stdin) { - break; - } else { - fclose(m_inputFile); - m_inputFile = stdin; - continue; - } - } - cmd += QString::fromLatin1(buf); - if (cmd.endsWith(QLatin1Char('\n'))) { - cmd.truncate(cmd.size() - 1); - if (!cmd.isEmpty() && !handleCommand(cmd.trimmed())) - break; - cmd.clear(); - } - std::putc('>', stdout); - } - if (m_inputFile != stdin) - fclose(m_inputFile); -} - -// Determine the command -static Command evaluateCommand(const QString &cmdToken) -{ - if (cmdToken.size() == 1) { - switch(cmdToken.at(0).toAscii()) { - case 'I': - return Async_Interrupt; - case 'Q': - return Sync_Queue; - case 'B': - return Sync_QueueBreakPoint; - case 'L': - return Sync_ListBreakPoints; - case 'E': - return Sync_EvalExpression; - case 'G': - return Execution_Go; - case 'S': - return Execution_StartBinary; - case 'F': - return Sync_PrintFrame; - case 'P': - return Sync_Python; - case 'V': - return Sync_OutputVersion; - case 'W': - return WaitCommand; - default: - break; - } - return UnknownCommand; - } - return UnknownCommand; -} - -// Chop off command and return argument list -static Command parseCommand(QString *s) -{ - if (s->isEmpty()) - return UnknownCommand; - int firstBlank = s->indexOf(QLatin1Char(' ')); - // No further arguments - if (firstBlank == -1) { - const Command rc1 = evaluateCommand(*s); - if (rc1 != UnknownCommand) // pass through debugger cmds - s->clear(); - return rc1; - } - // Chop - const Command rc = evaluateCommand(s->left(firstBlank)); - if (rc != UnknownCommand) { // pass through debugger cmds) - int nextToken = firstBlank + 1; - for ( ; nextToken < s->size() && s->at(nextToken).isSpace(); nextToken++) ; - s->remove(0, nextToken); - } - return rc; -} - -void CdbPromptThread::notifyDebugEvent() -{ - if (m_waitingForDebugEvent) - m_debugEventWaitCondition.wakeAll(); -} - -bool CdbPromptThread::handleCommand(QString cmd) -{ - if (cmd == QLatin1String("q")) - return false; - if (cmd == QLatin1String("H")) { - std::fputs(help, stdout); - return true; - } - const Command c = parseCommand(&cmd); - if (c == WaitCommand) { - std::fputs("Waiting for debug event\n", stdout); - m_debugEventMutex.lock(); - m_waitingForDebugEvent = true; - m_debugEventWaitCondition.wait(&m_debugEventMutex); - m_debugEventMutex.unlock(); - std::fputs("Debug event received\n", stdout); - m_waitingForDebugEvent = false; - return true; - } - if (c & AsyncCommand) { - emit asyncCommand(c, cmd); - return true; - } - if (c & ExecutionCommand) { - emit executionCommand(c, cmd); - return true; - } - // Let Unknown default to sync exeute - emit syncCommand(c, cmd); - return true; -} diff --git a/tests/tools/ccdb/cdbpromptthread.h b/tests/tools/ccdb/cdbpromptthread.h deleted file mode 100644 index 78b323140a0fae5bb70ae154b770d6f1e20e23f6..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/cdbpromptthread.h +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef PROMPTTHREAD_H -#define PROMPTTHREAD_H - -#include <QtCore/QThread> -#include <QtCore/QWaitCondition> -#include <QtCore/QMutex> - -#include <cstdio> - -enum CommandTypeFlags { - // Interrupt or something. - AsyncCommand = 0x0010000, - // Synchronous execution before next prompt, - // eg eval expression. Connect with blocking slot. - SyncCommand = 0x0020000, - // Starts debuggee. Requires starting the debug event - // watch timer afterwards. - ExecutionCommand = 0x0040000 -}; - -enum Command { - UnknownCommand = 0, - Async_Interrupt = AsyncCommand|1, - Sync_EvalExpression = SyncCommand|1, - Sync_Queue = SyncCommand|2, - Sync_QueueBreakPoint = SyncCommand|3, - Sync_ListBreakPoints = SyncCommand|4, - Sync_PrintFrame = SyncCommand|5, - Sync_OutputVersion = SyncCommand|6, - Sync_Python = SyncCommand|7, - Execution_Go = ExecutionCommand|1, - Execution_StartBinary = ExecutionCommand|2, - WaitCommand = 0xFFFF -}; - -class CdbPromptThread : public QThread -{ - Q_OBJECT -public: - explicit CdbPromptThread(FILE *file, QObject *parent = 0); - - virtual void run(); - -public slots: - void notifyDebugEvent(); - -signals: - void asyncCommand(int command, const QString &arg); - void syncCommand(int command, const QString &arg); - void executionCommand(int command, const QString &arg); - -private: - bool handleCommand(QString); - QWaitCondition m_debugEventWaitCondition; - QMutex m_debugEventMutex; - bool m_waitingForDebugEvent; - FILE *m_inputFile; -}; - -#endif // PROMPTTHREAD_H diff --git a/tests/tools/ccdb/debugeventcallback.cpp b/tests/tools/ccdb/debugeventcallback.cpp deleted file mode 100644 index 12ec1ba8d72f68ec0c7d1e8a5162df754423e86c..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/debugeventcallback.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "debugeventcallback.h" - -#include <cstdio> - -DebugEventCallback::DebugEventCallback() -{ -} - -STDMETHODIMP DebugEventCallback::GetInterestMask(THIS_ __out PULONG mask) -{ - *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS - | DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE - | DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD - | DEBUG_EVENT_BREAKPOINT - | DEBUG_EVENT_EXCEPTION; - return S_OK; -} - -STDMETHODIMP DebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2) -{ - printf("Breakpoint hit\n"); - return S_OK; -} -STDMETHODIMP DebugEventCallback::Exception( - THIS_ - __in PEXCEPTION_RECORD64 exc, - __in ULONG firstChance - ) -{ - printf("Exception %ul occurred first-chance: %ul\n", exc->ExceptionCode, firstChance); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::CreateThread( - THIS_ - __in ULONG64 /* Handle */, - __in ULONG64 /* DataOffset */, - __in ULONG64 /* StartOffset */ - ) -{ - printf("Thread created\n"); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::ExitThread( - THIS_ - __in ULONG /* ExitCode */ - ) -{ - printf("Thread quit\n"); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::CreateProcess( - THIS_ - __in ULONG64 /* ImageFileHandle */, - __in ULONG64 Handle, - __in ULONG64 /* Offset */, - __in ULONG /* ModuleSize */, - __in_opt PCWSTR /* ModuleName */, - __in_opt PCWSTR /* ImageName */, - __in ULONG /* CheckSum */, - __in ULONG /* TimeDateStamp */, - __in ULONG64 /* InitialThreadHandle */, - __in ULONG64 /* ThreadDataOffset */, - __in ULONG64 /* StartOffset */ - ) -{ - printf("Process created %Ld\n", Handle); - emit processAttached(reinterpret_cast<void*>(Handle)); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::ExitProcess( - THIS_ - __in ULONG /* ExitCode */ - ) -{ - printf("Process quit\n"); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::LoadModule( - THIS_ - __in ULONG64 /* ImageFileHandle */, - __in ULONG64 /* Offset */, - __in ULONG /* ModuleSize */, - __in_opt PCWSTR /* ModuleName */, - __in_opt PCWSTR /* ImageName */, - __in ULONG /* CheckSum */, - __in ULONG /* TimeDateStamp */ - ) -{ - printf("Module loaded\n"); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::UnloadModule( - THIS_ - __in_opt PCWSTR /* ImageName */, - __in ULONG64 /* Offset */ - ) -{ - printf("Module unloaded\n"); - return S_OK; -} - -STDMETHODIMP DebugEventCallback::SystemError( - THIS_ - __in ULONG Error, - __in ULONG Level - ) -{ - printf("System error %ul at %ul\n", Error, Level); - return S_OK; -} - - -STDMETHODIMP DebugEventCallback::ChangeDebuggeeState( - THIS_ - __in ULONG Flags, - __in ULONG64 Argument - ) -{ - printf("Debuggee state changed %ul %ul\n", Flags, Argument); - return S_OK; -} diff --git a/tests/tools/ccdb/debugeventcallback.h b/tests/tools/ccdb/debugeventcallback.h deleted file mode 100644 index b28521c854619dca081183e8a8dd887d77d14a73..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/debugeventcallback.h +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef DEBUGEVENTCALLBACK_H -#define DEBUGEVENTCALLBACK_H - -#include "debugeventcallbackbase.h" -#include <QtCore/QObject> - -class DebugEventCallback : - public QObject, - public CdbCore::DebugEventCallbackBase - -{ - Q_OBJECT -public: - DebugEventCallback(); - - STDMETHOD(GetInterestMask)( - THIS_ - __out PULONG mask - ); - - STDMETHOD(Breakpoint)( - THIS_ - __in PDEBUG_BREAKPOINT2 Bp - ); - - STDMETHOD(Exception)( - THIS_ - __in PEXCEPTION_RECORD64 Exception, - __in ULONG FirstChance - ); - - STDMETHOD(CreateThread)( - THIS_ - __in ULONG64 Handle, - __in ULONG64 DataOffset, - __in ULONG64 StartOffset - ); - STDMETHOD(ExitThread)( - THIS_ - __in ULONG ExitCode - ); - - STDMETHOD(CreateProcess)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 Handle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp, - __in ULONG64 InitialThreadHandle, - __in ULONG64 ThreadDataOffset, - __in ULONG64 StartOffset - ); - - STDMETHOD(ExitProcess)( - THIS_ - __in ULONG ExitCode - ); - - STDMETHOD(LoadModule)( - THIS_ - __in ULONG64 ImageFileHandle, - __in ULONG64 BaseOffset, - __in ULONG ModuleSize, - __in_opt PCWSTR ModuleName, - __in_opt PCWSTR ImageName, - __in ULONG CheckSum, - __in ULONG TimeDateStamp - ); - - STDMETHOD(UnloadModule)( - THIS_ - __in_opt PCWSTR ImageBaseName, - __in ULONG64 BaseOffset - ); - - STDMETHOD(SystemError)( - THIS_ - __in ULONG Error, - __in ULONG Level - ); - - STDMETHOD(ChangeDebuggeeState)( - THIS_ - __in ULONG Flags, - __in ULONG64 Argument - ); - -signals: - void processAttached(void *h); -}; - -#endif // DEBUGEVENTCALLBACK_H diff --git a/tests/tools/ccdb/main.cpp b/tests/tools/ccdb/main.cpp deleted file mode 100644 index 963d5cc41d50b6d8776eae0e64597a163b84dd2f..0000000000000000000000000000000000000000 --- a/tests/tools/ccdb/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cdbapplication.h" -#include <QtCore/QString> - -int main(int argc, char *argv[]) -{ - CdbApplication app(argc, argv); - int rc = 0; - - switch (app.init()) { - case CdbApplication::InitOk: - rc = app.exec(); - break; - case CdbApplication::InitFailed: - rc = 1; - break; - case CdbApplication::InitUsageShown: - break; - } - return rc; -}