Commit a26d745c authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

m.txt

parent 3d6f7de9
......@@ -28,6 +28,7 @@
**************************************************************************/
#include "consoleprocess.h"
#include "winutils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
......@@ -122,7 +123,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
delete m_tempFile;
m_tempFile = 0;
stubServerShutdown();
emit processError(tr("The process could not be started!"));
emit processError(tr("The process '%1' could not be started: %2").arg(cmdLine, winErrorMessage(GetLastError())));
return false;
}
......@@ -173,18 +174,6 @@ void ConsoleProcess::stubConnectionAvailable()
connect(m_stubSocket, SIGNAL(readyRead()), SLOT(readStubOutput()));
}
static QString errorMsg(int code)
{
LPVOID lpMsgBuf;
int len = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, (DWORD)code, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
QString ret = QString::fromUtf16((ushort *)lpMsgBuf, len);
LocalFree(lpMsgBuf);
return ret;
}
void ConsoleProcess::readStubOutput()
{
while (m_stubSocket->canReadLine()) {
......@@ -192,10 +181,10 @@ void ConsoleProcess::readStubOutput()
out.chop(2); // \r\n
if (out.startsWith("err:chdir ")) {
emit processError(tr("Cannot change to working directory %1: %2")
.arg(workingDirectory(), errorMsg(out.mid(10).toInt())));
.arg(workingDirectory(), winErrorMessage(out.mid(10).toInt())));
} else if (out.startsWith("err:exec ")) {
emit processError(tr("Cannot execute %1: %2")
.arg(m_executable, errorMsg(out.mid(9).toInt())));
.arg(m_executable, winErrorMessage(out.mid(9).toInt())));
} else if (out.startsWith("pid ")) {
// Will not need it any more
delete m_tempFile;
......@@ -207,7 +196,7 @@ void ConsoleProcess::readStubOutput()
FALSE, m_appPid);
if (m_hInferior == NULL) {
emit processError(tr("Cannot obtain a handle to the inferior: %1")
.arg(errorMsg(GetLastError())));
.arg(winErrorMessage(GetLastError())));
// Uhm, and now what?
continue;
}
......@@ -237,7 +226,7 @@ void ConsoleProcess::inferiorExited()
if (!GetExitCodeProcess(m_hInferior, &chldStatus))
emit processError(tr("Cannot obtain exit status from inferior: %1")
.arg(errorMsg(GetLastError())));
.arg(winErrorMessage(GetLastError())));
cleanupInferior();
m_appStatus = QProcess::NormalExit;
m_appCode = chldStatus;
......
......@@ -26,8 +26,13 @@ SOURCES += \
submiteditorwidget.cpp \
synchronousprocess.cpp
win32:SOURCES += consoleprocess_win.cpp
else:SOURCES += consoleprocess_unix.cpp
win32 {
SOURCES += consoleprocess_win.cpp \
winutils.cpp
HEADERS += winutils.h
} else {
SOURCES += consoleprocess_unix.cpp
}
HEADERS += \
utils_global.h \
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#include "winutils.h"
#include <windows.h>
#include <QtCore/QString>
namespace Core {
namespace Utils {
QWORKBENCH_UTILS_EXPORT QString winErrorMessage(unsigned long error)
{
QString rc = QString::fromLatin1("#%1: ").arg(error);
ushort *lpMsgBuf;
const int len = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
if (len) {
rc = QString::fromUtf16(lpMsgBuf, len);
LocalFree(lpMsgBuf);
} else {
rc += QString::fromLatin1("<unknown error>");
}
return rc;
}
} // namespace Utils
} // namespace Core
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef WINUTILS_H
#define WINUTILS_H
#include "utils_global.h"
QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
namespace Core {
namespace Utils {
// Helper to format a Windows error message, taking the
// code as returned by the GetLastError()-API.
QWORKBENCH_UTILS_EXPORT QString winErrorMessage(unsigned long error);
} // namespace Utils
} // namespace Core
#endif // WINUTILS_H
......@@ -198,7 +198,7 @@ bool CdbDebugEngine::startDebugger()
m_d->m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
//m_pDebugSymbols->AddSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH);
if (m_d->m_debuggerManager->startMode() == DebuggerManager::AttachExternal) {
if (m_d->m_debuggerManager->startMode() == AttachExternal) {
qWarning("CdbDebugEngine: attach to process not yet implemented!");
return false;
} else {
......
......@@ -86,4 +86,7 @@ HEADERS += $$PWD/modeltest.h
DEFINES += USE_MODEL_TEST=1
}
CONFIG(cdbdebugger):include(cdb\cdb.pri)
win32 {
include(win/win.pri)
CONFIG(cdbdebugger):include(cdb\cdb.pri)
}
......@@ -53,6 +53,9 @@ const char * const GDBRUNNING = "Gdb.Running";
const char * const PROPERTY_REGISTER_FORMAT = "Debugger.Property.RegisterFormat";
namespace Internal {
enum { debug = 0 };
}
} // namespace Constants
} // namespace Debugger
......
......@@ -52,7 +52,9 @@
#include "watchhandler.h"
#include "debuggerdialogs.h"
#ifdef Q_OS_WIN
# include "peutils.h"
#endif
#include <utils/qtcassert.h>
#include <QtCore/QDebug>
......@@ -432,6 +434,8 @@ void DebuggerManager::init()
winEngine = createWinEngine(this);
scriptEngine = createScriptEngine(this);
setDebuggerType(GdbDebugger);
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine;
}
void DebuggerManager::setDebuggerType(DebuggerType type)
......@@ -549,7 +553,8 @@ void DebuggerManager::clearStatusMessage()
void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
{
Q_UNUSED(timeout)
//qDebug() << "STATUS: " << msg;
if (Debugger::Constants::Internal::debug)
qDebug() << "STATUS MSG: " << msg;
showDebuggerOutput("status:", msg);
m_statusLabel->setText(" " + msg);
if (timeout > 0) {
......@@ -594,8 +599,9 @@ void DebuggerManager::notifyInferiorExited()
void DebuggerManager::notifyInferiorPidChanged(int pid)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << pid;
//QMessageBox::warning(0, "PID", "PID: " + QString::number(pid));
//qDebug() << "PID: " << pid;
emit inferiorPidChanged(pid);
}
......@@ -606,11 +612,11 @@ void DebuggerManager::showApplicationOutput(const QString &str)
void DebuggerManager::shutdown()
{
//qDebug() << "DEBUGGER_MANAGER SHUTDOWN START";
if (m_engine) {
//qDebug() << "SHUTTING DOWN ENGINE" << m_engine;
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << m_engine;
if (m_engine)
m_engine->shutdown();
}
m_engine = 0;
delete scriptEngine;
......@@ -673,6 +679,9 @@ void DebuggerManager::toggleBreakpoint()
void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
QTC_ASSERT(m_engine, return);
QTC_ASSERT(m_breakHandler, return);
if (status() != DebuggerInferiorRunning
......@@ -779,8 +788,43 @@ void DebuggerManager::attachCore()
emit debuggingFinished();
}
// Figure out the debugger type of an exexcutable
static bool determineDebuggerType(const QString &executable,
DebuggerManager::DebuggerType *dt,
QString *errorMessage)
{
if (executable.endsWith(QLatin1String(".js"))) {
*dt = DebuggerManager::ScriptDebugger;
return true;
}
#ifndef Q_WS_WIN
*dt = DebuggerManager::GdbDebugger;
return true;
#else
// If a file has PDB files, it has been compiled by VS.
QStringList pdbFiles;
if (!getPDBFiles(executable, &pdbFiles, errorMessage))
return false;
if (pdbFiles.empty()) {
*dt = DebuggerManager::GdbDebugger;
return true;
}
// We need the CDB debugger in order to be able to debug VS
// executables
if (!winEngine) {
*errorMessage = DebuggerManager::tr("Debugging VS executables is not supported.");
return false;
}
*dt = DebuggerManager::WinDebugger;
return true;
#endif
}
bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << mode;
m_startMode = mode;
// FIXME: Clean up
......@@ -858,11 +902,18 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
emit debugModeRequested();
if (m_executable.endsWith(".js"))
setDebuggerType(ScriptDebugger);
else
setDebuggerType(GdbDebugger);
DebuggerType type;
QString errorMessage;
if (!determineDebuggerType(m_executable, &type, &errorMessage)) {
QMessageBox::warning(mainWindow(), tr("Warning"),
tr("Cannot debug '%1': %2").arg(m_executable, errorMessage));
return false;
}
if (Debugger::Constants::Internal::debug)
qDebug() << m_executable << type;
setDebuggerType(type);
setStatus(DebuggerProcessStartingUp);
if (!m_engine->startDebugger()) {
setStatus(DebuggerProcessNotReady);
......@@ -886,7 +937,9 @@ void DebuggerManager::cleanupViews()
void DebuggerManager::exitDebugger()
{
//qDebug() << "DebuggerManager::exitDebugger";
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO;
if (m_engine)
m_engine->exitDebugger();
cleanupViews();
......@@ -962,6 +1015,9 @@ void DebuggerManager::nextIExec()
void DebuggerManager::executeDebuggerCommand(const QString &command)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO <<command;
QTC_ASSERT(m_engine, return);
m_engine->executeDebuggerCommand(command);
}
......@@ -1030,6 +1086,9 @@ void DebuggerManager::watchExpression(const QString &expression)
void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
QTC_ASSERT(m_breakHandler, return);
QTC_ASSERT(m_engine, return);
m_breakHandler->setBreakpoint(fileName, lineNumber);
......@@ -1062,7 +1121,8 @@ void DebuggerManager::breakAtMain()
void DebuggerManager::setStatus(int status)
{
//qDebug() << "STATUS CHANGE: from" << m_status << "to" << status;
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << "STATUS CHANGE: from" << m_status << "to" << status;
if (status == m_status)
return;
......@@ -1179,8 +1239,9 @@ void DebuggerManager::continueExec()
void DebuggerManager::interruptDebuggingRequest()
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << status();
QTC_ASSERT(m_engine, return);
//qDebug() << "INTERRUPTING AT" << status();
bool interruptIsExit = (status() != DebuggerInferiorRunning);
if (interruptIsExit)
exitDebugger();
......@@ -1197,8 +1258,11 @@ void DebuggerManager::runToLineExec()
QString fileName;
int lineNumber = -1;
emit currentTextEditorRequested(&fileName, &lineNumber, 0);
if (!fileName.isEmpty())
if (!fileName.isEmpty()) {
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
m_engine->runToLineExec(fileName, lineNumber);
}
}
void DebuggerManager::runToFunctionExec()
......@@ -1228,7 +1292,9 @@ void DebuggerManager::runToFunctionExec()
}
}
}
//qDebug() << "RUN TO FUNCTION " << functionName;
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << functionName;
if (!functionName.isEmpty())
m_engine->runToFunctionExec(functionName);
}
......@@ -1238,8 +1304,11 @@ void DebuggerManager::jumpToLineExec()
QString fileName;
int lineNumber = -1;
emit currentTextEditorRequested(&fileName, &lineNumber, 0);
if (!fileName.isEmpty())
if (!fileName.isEmpty()) {
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
m_engine->jumpToLineExec(fileName, lineNumber);
}
}
void DebuggerManager::resetLocation()
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#include "peutils.h"
#include <utils/winutils.h>
#include <QtCore/QStringList>
#include <QtCore/QDebug>
#include <windows.h>
using Core::Utils::winErrorMessage;
// Create a pointer from base and offset when rummaging around in
// a memory mapped file
template <class Ptr>
inline Ptr *makePtr(void *base, ptrdiff_t offset)
{
return reinterpret_cast<Ptr*>(static_cast<char*>(base) + offset);
}
// CodeView header
struct CV_HEADER
{
DWORD CvSignature; // NBxx
LONG Offset; // Always 0 for NB10
};
// CodeView NB10 debug information of a PDB 2.00 file (VS 6)
struct CV_INFO_PDB20
{
CV_HEADER Header;
DWORD Signature;
DWORD Age;
BYTE PdbFileName[1];
};
// CodeView RSDS debug information of a PDB 7.00 file
struct CV_INFO_PDB70
{
DWORD CvSignature;
GUID Signature;
DWORD Age;
BYTE PdbFileName[1];
};
// Retrieve the NT image header of an executable via the legacy DOS header.
static IMAGE_NT_HEADERS *getNtHeader(void *fileMemory, QString *errorMessage)
{
IMAGE_DOS_HEADER *dosHeader = static_cast<PIMAGE_DOS_HEADER>(fileMemory);
// Check DOS header consistency
if (IsBadReadPtr(dosHeader, sizeof(IMAGE_DOS_HEADER))
|| dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
*errorMessage = QString::fromLatin1("DOS header check failed.");
return 0;
}
// Retrieve NT header
IMAGE_NT_HEADERS *ntHeaders = makePtr<IMAGE_NT_HEADERS>(dosHeader, dosHeader->e_lfanew);
// check NT header consistency
if (IsBadReadPtr(ntHeaders, sizeof(ntHeaders->Signature))
|| ntHeaders->Signature != IMAGE_NT_SIGNATURE
|| IsBadReadPtr(&ntHeaders->FileHeader, sizeof(IMAGE_FILE_HEADER))) {
*errorMessage = QString::fromLatin1("NT header check failed.");
return 0;
}
// Check magic
const WORD magic = ntHeaders->OptionalHeader.Magic;
#ifdef __GNUC__ // MinGW does not have complete 64bit definitions.
if (magic != 0x10b) {
*errorMessage = QString::fromLatin1("NT header check failed; magic %1 is not that of a 32-bit executable.").
arg(magic);
return 0;
}
#else
if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
*errorMessage = QString::fromLatin1("NT header check failed; magic %1 is none of %2, %3.").
arg(magic).arg(IMAGE_NT_OPTIONAL_HDR32_MAGIC).arg(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
return 0;
}
#endif
// Check section headers
IMAGE_SECTION_HEADER *sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
if (IsBadReadPtr(sectionHeaders, ntHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER))) {
*errorMessage = QString::fromLatin1("NT header section header check failed.");
return 0;
}
return ntHeaders;
}
// Find the COFF section an RVA belongs to and convert to file offset
static bool getFileOffsetFromRVA(IMAGE_NT_HEADERS *ntHeaders, DWORD rva, DWORD* fileOffset)
{
IMAGE_SECTION_HEADER *sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);
for( int i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++, sectionHeader++ ) {
const DWORD sectionSize = sectionHeader->Misc.VirtualSize ?
sectionHeader->Misc.VirtualSize : sectionHeader->SizeOfRawData;
if ((rva >= sectionHeader->VirtualAddress) && (rva < sectionHeader->VirtualAddress + sectionSize)) {
const DWORD diff = sectionHeader->VirtualAddress - sectionHeader->PointerToRawData;
*fileOffset = rva - diff;
return true;
}
}
return false;
}
// Retrieve debug directory and number of entries
static bool getDebugDirectory(IMAGE_NT_HEADERS *ntHeaders,
void *fileMemory,
IMAGE_DEBUG_DIRECTORY **debugDir,
int *count,
QString *errorMessage)
{
DWORD debugDirRva = 0;
DWORD debugDirSize;
*debugDir = 0;
*count = 0;
#ifdef __GNUC__ // MinGW does not have complete 64bit definitions.
typedef IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER32;
#else
// Find the virtual address
const bool is64Bit = ntHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
if (is64Bit) {
IMAGE_OPTIONAL_HEADER64 *optionalHeader64 = reinterpret_cast<IMAGE_OPTIONAL_HEADER64*>(&(ntHeaders->OptionalHeader));
debugDirRva = optionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
debugDirSize = optionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
} else {
#endif
IMAGE_OPTIONAL_HEADER32 *optionalHeader32 = reinterpret_cast<IMAGE_OPTIONAL_HEADER32*>(&(ntHeaders->OptionalHeader));
debugDirRva = optionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
debugDirSize = optionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
#ifndef __GNUC__
}
#endif
// Empty. This is the case for MinGW binaries
if (debugDirSize == 0)
return true;
// Look up in file
DWORD debugDirOffset;
if (!getFileOffsetFromRVA(ntHeaders, debugDirRva, &debugDirOffset)) {
*errorMessage = QString::fromLatin1("Unable to locate debug dir RVA %1/%2.").arg(debugDirRva).arg(debugDirSize);
return false;
}
*debugDir = makePtr<IMAGE_DEBUG_DIRECTORY>(fileMemory, debugDirOffset);
// Check
if (IsBadReadPtr(*debugDir, debugDirSize) || debugDirSize < sizeof(IMAGE_DEBUG_DIRECTORY)) {
*errorMessage = QString::fromLatin1("Debug directory corrupted.");
return 0;
}
*count = debugDirSize / sizeof(IMAGE_DEBUG_DIRECTORY);
return debugDir;