diff --git a/src/plugins/debugger/name_demangler.cpp b/src/plugins/debugger/name_demangler.cpp index a847bb16e64a9f8602e7282d1ba99cc74248f002..8d9f0e9f035ccd60bcd2ac553ac9b9f98bec3b4e 100644 --- a/src/plugins/debugger/name_demangler.cpp +++ b/src/plugins/debugger/name_demangler.cpp @@ -31,17 +31,15 @@ ** **************************************************************************/ +#include "name_demangler.h" + #include <QtCore/QChar> -#include <QtCore/QCoreApplication> -#include <QtCore/QLatin1String> #include <QtCore/QMap> #include <QtCore/QRegExp> #include <QtCore/QSet> #include <QtCore/QString> #include <QtCore/QStringList> -#include "name_demangler.h" - // Debugging facility. //#define DO_TRACE #ifdef DO_TRACE @@ -59,7 +57,6 @@ namespace Internal { class NameDemanglerPrivate { - Q_DECLARE_TR_FUNCTIONS(NameDemanglerPrivate) public: NameDemanglerPrivate(); ~NameDemanglerPrivate(); @@ -332,7 +329,7 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) if (m_demangledName.startsWith(QLatin1String("::"))) m_demangledName.remove(0, 2); if (!parseError && pos != mangledName.size()) - error(tr("Premature end of input")); + error(QString::fromLatin1("Premature end of input")); #ifdef DO_TRACE qDebug("%d", substitutions.size()); @@ -422,7 +419,7 @@ const QString NameDemanglerPrivate::parseEncoding() } else if (firstSetSpecialName.contains(next)) { encoding = parseSpecialName(); } else { - error(tr("Invalid encoding")); + error(QString::fromLatin1("Invalid encoding")); } FUNC_END(encoding); @@ -476,7 +473,7 @@ const QString NameDemanglerPrivate::parseName() } else if (firstSetLocalName.contains(next)) { name = parseLocalName(); } else { - error(tr("Invalid name")); + error(QString::fromLatin1("Invalid name")); } } @@ -516,7 +513,7 @@ const QString NameDemanglerPrivate::parseNestedName() QString name; if (advance() != 'N') { - error(tr("Invalid nested-name")); + error(QString::fromLatin1("Invalid nested-name")); } else { QString cvQualifiers; if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm' @@ -525,7 +522,7 @@ const QString NameDemanglerPrivate::parseNestedName() if (!parseError) { name = parsePrefix(); if (!parseError && advance() != 'E') - error(tr("Invalid nested-name")); + error(QString::fromLatin1("Invalid nested-name")); /* * These are member function qualifiers which will have to @@ -636,7 +633,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs() QString args = QLatin1String("<"); if (advance() != 'I') { - error(tr("Invalid template args")); + error(QString::fromLatin1("Invalid template args")); } else { do { if (args.length() > 1) @@ -644,7 +641,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs() args += parseTemplateArg(); } while (!parseError && firstSetTemplateArg.contains(peek())); if (!parseError && advance() != 'E') - error(tr("Invalid template args")); + error(QString::fromLatin1("Invalid template args")); } args += '>'; @@ -662,7 +659,7 @@ const QString NameDemanglerPrivate::parseTemplateParam() QString param; if (advance() != 'T') { - error(tr("Invalid template-param")); + error(QString::fromLatin1("Invalid template-param")); } else { int index; if (peek() == '_') @@ -670,7 +667,7 @@ const QString NameDemanglerPrivate::parseTemplateParam() else index = parseNonNegativeNumber() + 1; if (!parseError && advance() != '_') - error(tr("Invalid template-param")); + error(QString::fromLatin1("Invalid template-param")); param = templateParams.at(index); } @@ -689,7 +686,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers() while (true) { if (peek() == 'V') { if (volatileFound || constFound) { - error(tr("Invalid qualifiers: unexpected 'volatile'")); + error(QString::fromLatin1("Invalid qualifiers: unexpected 'volatile'")); break; } else { volatileFound = true; @@ -698,7 +695,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers() } } else if (peek() == 'K') { if (constFound) { - error(tr("Invalid qualifiers: 'const' appears twice")); + error(QString::fromLatin1("Invalid qualifiers: 'const' appears twice")); break; } else { constFound = true; @@ -741,7 +738,7 @@ int NameDemanglerPrivate::parseNonNegativeNumber(int base) advance(); int number; if (pos == startPos) { - error(tr("Invalid non-negative number")); + error(QString::fromLatin1("Invalid non-negative number")); number = 0; } else { number = mangledName.mid(startPos, pos - startPos).toInt(0, base); @@ -799,7 +796,7 @@ const QString NameDemanglerPrivate::parseTemplateArg() advance(); arg = parseExpression(); if (!parseError && advance() != 'E') - error(tr("Invalid template-arg")); + error(QString::fromLatin1("Invalid template-arg")); } else if (next == 'I') { advance(); while (!parseError && firstSetTemplateArg.contains(peek())) { @@ -808,9 +805,9 @@ const QString NameDemanglerPrivate::parseTemplateArg() arg += parseTemplateArg(); } if (!parseError && advance() != 'E') - error(tr("Invalid template-arg")); + error(QString::fromLatin1("Invalid template-arg")); } else { - error(tr("Invalid template-arg")); + error(QString::fromLatin1("Invalid template-arg")); } templateParams.append(arg); @@ -874,7 +871,7 @@ const QString NameDemanglerPrivate::parseExpression() while (!parseError && firstSetExpression.contains(peek())) expr += parseExpression(); if (!parseError && advance() != 'E') - error(tr("Invalid expression")); + error(QString::fromLatin1("Invalid expression")); } else if (str == QLatin1String("cv")) { advance(2); expr = parseType() + QLatin1String("("); @@ -889,7 +886,7 @@ const QString NameDemanglerPrivate::parseExpression() expr += parseExpression(); } if (!parseError && advance() != 'E') - error(tr("Invalid expression")); + error(QString::fromLatin1("Invalid expression")); } else { expr += parseExpression(); } @@ -932,7 +929,7 @@ const QString NameDemanglerPrivate::parseExpression() } else if (firstSetExprPrimary.contains(next)) { expr = parseExprPrimary(); } else { - error(tr("Invalid expression")); + error(QString::fromLatin1("Invalid expression")); } } @@ -952,7 +949,7 @@ const QString NameDemanglerPrivate::parseExprPrimary() QString expr; if (advance() != 'L') { - error(tr("Invalid primary expression")); + error(QString::fromLatin1("Invalid primary expression")); } else { QChar next = peek(); if (firstSetType.contains(next)) { @@ -963,15 +960,15 @@ const QString NameDemanglerPrivate::parseExprPrimary() else if (true /* type just parsed indicates float */) expr += QString::number(parseFloat()); else - error(tr("Invalid expr-primary")); + error(QString::fromLatin1("Invalid expr-primary")); } } else if (firstSetMangledName.contains(next)) { expr = parseMangledName(); } else { - error(tr("Invalid expr-primary")); + error(QString::fromLatin1("Invalid expr-primary")); } if (!parseError && advance() != 'E') - error(tr("Invalid expr-primary")); + error(QString::fromLatin1("Invalid expr-primary")); } FUNC_END(expr); @@ -1106,12 +1103,12 @@ const QString NameDemanglerPrivate::parseType() advance(2); type = parseExpression(); // TODO: See above if (!parseError && advance() != 'E') - error(tr("Invalid type")); + error(QString::fromLatin1("Invalid type")); } else if (str == QLatin1String("DT")) { advance(2); type = parseExpression(); // TODO: See above if (!parseError && advance() != 'E') - error(tr("Invalid type")); + error(QString::fromLatin1("Invalid type")); } else { QChar next = peek(); if (str == QLatin1String("Dd") || str == QLatin1String("De") @@ -1179,7 +1176,7 @@ const QString NameDemanglerPrivate::parseType() if (!parseError) type += parseType(); // TODO: handle this correctly } else { - error(tr("Invalid type")); + error(QString::fromLatin1("Invalid type")); } } @@ -1317,14 +1314,14 @@ const QString NameDemanglerPrivate::parseBuiltinType() break; break; default: - error(tr("Invalid built-in type")); + error(QString::fromLatin1("Invalid built-in type")); } break; case 'u': type = parseSourceName(); break; default: - error(tr("Invalid builtin-type")); + error(QString::fromLatin1("Invalid builtin-type")); } FUNC_END(type); @@ -1340,7 +1337,7 @@ const QString NameDemanglerPrivate::parseFunctionType() QString funcType; bool externC = false; if (advance() != 'F') { - error(tr("Invalid function type")); + error(QString::fromLatin1("Invalid function type")); } else { if (peek() == 'Y') { advance(); @@ -1348,7 +1345,7 @@ const QString NameDemanglerPrivate::parseFunctionType() } const QStringList &signature = parseBareFunctionType(); if (!parseError && advance() != 'E') - error(tr("Invalid function type")); + error(QString::fromLatin1("Invalid function type")); if (!parseError) { QString returnType = signature.first(); QString argList = QLatin1String("("); @@ -1428,7 +1425,7 @@ const QString NameDemanglerPrivate::parseUnqualifiedName() else if (firstSetSourceName.contains(next)) name = QLatin1String("::") + parseSourceName(); else - error(tr("Invalid unqualified-name")); + error(QString::fromLatin1("Invalid unqualified-name")); FUNC_END(name); return name; @@ -1519,7 +1516,7 @@ const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName() static const UnaryOperator pseudoOp(QLatin1String("invalid"), QLatin1String("invalid")); op = &pseudoOp; - error(tr("Invalid operator-name '%s'").arg(id)); + error(QString::fromLatin1("Invalid operator-name '%s'").arg(id)); } } } @@ -1541,7 +1538,7 @@ const QString NameDemanglerPrivate::parseArrayType() QString type; if (advance() != 'A') { - error(tr("Invalid array-type")); + error(QString::fromLatin1("Invalid array-type")); } else { QChar next = peek(); QString dimension; @@ -1551,7 +1548,7 @@ const QString NameDemanglerPrivate::parseArrayType() dimension = parseExpression(); } if (!parseError && advance() != '_') - error(tr("Invalid array-type")); + error(QString::fromLatin1("Invalid array-type")); if (!parseError) type = QString::fromLocal8Bit("%1[%2]"). arg(parseType()).arg(dimension); @@ -1568,7 +1565,7 @@ const QString NameDemanglerPrivate::parsePointerToMemberType() QString type; if (advance() != 'M') { - error(tr("Invalid pointer-to-member-type")); + error(QString::fromLatin1("Invalid pointer-to-member-type")); } else { const QString classType = parseType(); QString memberType; @@ -1615,22 +1612,22 @@ const QString NameDemanglerPrivate::parseSubstitution() QString substitution; if (advance() != 'S') { - error(tr("Invalid substitution")); + error(QString::fromLatin1("Invalid substitution")); } else if (firstSetSeqId.contains(peek())) { int substIndex = parseSeqId() + 1; if (!parseError && substIndex >= substitutions.size()) - error(tr("Invalid substitution: element %1 was requested, " + error(QString::fromLatin1("Invalid substitution: element %1 was requested, " "but there are only %2"). arg(substIndex + 1).arg(substitutions.size())); else substitution = substitutions.at(substIndex); if (!parseError && advance() != '_') - error(tr("Invalid substitution")); + error(QString::fromLatin1("Invalid substitution")); } else { switch (advance().toAscii()) { case '_': if (substitutions.isEmpty()) - error(tr("Invalid substitution: There are no elements")); + error(QString::fromLatin1("Invalid substitution: There are no elements")); else substitution = substitutions.first(); break; @@ -1661,7 +1658,7 @@ const QString NameDemanglerPrivate::parseSubstitution() "::std::basic_iostream<char, std::char_traits<char> >"); break; default: - error(tr("Invalid substitution")); + error(QString::fromLatin1("Invalid substitution")); } } @@ -1733,7 +1730,7 @@ const QString NameDemanglerPrivate::parseSpecialName() if (!parseError) parseEncoding(); } else { - error(tr("Invalid special-name")); + error(QString::fromLatin1("Invalid special-name")); } FUNC_END(name); @@ -1756,7 +1753,7 @@ const QString NameDemanglerPrivate::parseUnscopedName() } else if (firstSetUnqualifiedName.contains(peek())) { name = parseUnqualifiedName(); } else { - error(tr("Invalid unqualified-name")); + error(QString::fromLatin1("Invalid unqualified-name")); } FUNC_END(name); @@ -1776,11 +1773,11 @@ const QString NameDemanglerPrivate::parseLocalName() QString name; if (advance() != 'Z') { - error(tr("Invalid local-name")); + error(QString::fromLatin1("Invalid local-name")); } else { name = parseEncoding(); if (!parseError && advance() != 'E') { - error(tr("Invalid local-name")); + error(QString::fromLatin1("Invalid local-name")); } else { QString str = readAhead(2); QChar next = peek(); @@ -1793,7 +1790,7 @@ const QString NameDemanglerPrivate::parseLocalName() advance(); name += QLatin1String("::\"string literal\""); } else { - error(tr("Invalid local-name")); + error(QString::fromLatin1("Invalid local-name")); } if (!parseError && firstSetDiscriminator.contains(peek())) parseDiscriminator(); @@ -1809,7 +1806,7 @@ int NameDemanglerPrivate::parseDiscriminator() { int index; if (advance() != '_') { - error(tr("Invalid discriminator")); + error(QString::fromLatin1("Invalid discriminator")); index = -1; } else { index = parseNonNegativeNumber(); @@ -1841,7 +1838,7 @@ const QString NameDemanglerPrivate::parseCtorDtorName() case '3': break; default: - error(tr("Invalid ctor-dtor-name")); + error(QString::fromLatin1("Invalid ctor-dtor-name")); } break; case 'D': @@ -1852,11 +1849,11 @@ const QString NameDemanglerPrivate::parseCtorDtorName() destructor = true; break; default: - error(tr("Invalid ctor-dtor-name")); + error(QString::fromLatin1("Invalid ctor-dtor-name")); } break; default: - error(tr("Invalid ctor-dtor-name")); + error(QString::fromLatin1("Invalid ctor-dtor-name")); } if (!parseError) { @@ -1904,10 +1901,10 @@ void NameDemanglerPrivate::parseCallOffset() parseVOffset(); break; default: - error(tr("Invalid call-offset")); + error(QString::fromLatin1("Invalid call-offset")); } if (!parseError && advance() != '_') - error(tr("Invalid call-offset")); + error(QString::fromLatin1("Invalid call-offset")); FUNC_END(QString()); } @@ -1929,7 +1926,7 @@ void NameDemanglerPrivate::parseVOffset() parseNumber(); if (advance() != '_') - error(tr("Invalid v-offset")); + error(QString::fromLatin1("Invalid v-offset")); parseNumber(); FUNC_END(QString()); @@ -1941,7 +1938,7 @@ int NameDemanglerPrivate::parseDigit() int digit = advance().digitValue(); if (digit == -1) - error(tr("Invalid digit")); + error(QString::fromLatin1("Invalid digit")); FUNC_END(QString::number(digit)); return digit; @@ -1950,7 +1947,7 @@ int NameDemanglerPrivate::parseDigit() void NameDemanglerPrivate::error(const QString &errorSpec) { parseError = true; - m_errorString = tr("At position %1: ").arg(pos) + errorSpec; + m_errorString = QString::fromLatin1("At position %1: ").arg(pos) + errorSpec; } QChar NameDemanglerPrivate::peek(int ahead) diff --git a/src/plugins/debugger/name_demangler.h b/src/plugins/debugger/name_demangler.h index d4a17a1ef3b5df47a4bd5d5b2b7c07c71e1d9ae1..7e2e2c1823a4b5da4a01622a02c5060540cf57da 100644 --- a/src/plugins/debugger/name_demangler.h +++ b/src/plugins/debugger/name_demangler.h @@ -34,6 +34,8 @@ #ifndef NAME_DEMANGLER_H #define NAME_DEMANGLER_H +#include <QtCore/QtGlobal> + QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE diff --git a/src/plugins/debugger/shared/shared.pri b/src/plugins/debugger/shared/shared.pri index 9f4666d54bf0a85b3bf7584c45d2522b2aa9cc31..c0f63a76028efef74604dc2f003bf00c69926756 100644 --- a/src/plugins/debugger/shared/shared.pri +++ b/src/plugins/debugger/shared/shared.pri @@ -8,12 +8,10 @@ INCLUDEPATH+=$$PWD win32 { SOURCES += $$PWD/peutils.cpp \ - $$PWD/dbgwinutils.cpp \ - $$PWD/sharedlibraryinjector.cpp + $$PWD/dbgwinutils.cpp HEADERS += $$PWD/peutils.h \ - $$PWD/dbgwinutils.h \ - $$PWD/sharedlibraryinjector.h + $$PWD/dbgwinutils.h contains(QMAKE_CXX, cl) { # For the Privilege manipulation functions in sharedlibraryinjector.cpp. diff --git a/src/plugins/debugger/shared/sharedlibraryinjector.cpp b/src/plugins/debugger/shared/sharedlibraryinjector.cpp deleted file mode 100644 index 97450bd4c54d8d0ff1711ff4bf7772f41e35d68e..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/shared/sharedlibraryinjector.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Marius Storm-Olsen -** -** 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 "sharedlibraryinjector.h" -#include <utils/winutils.h> - -#include <QtCore/QDebug> - -#ifdef __GNUC__ // MinGW does not have a complete windows.h - -typedef DWORD (__stdcall *PTHREAD_START_ROUTINE) (LPVOID lpThreadParameter); - -#endif - -enum { debug = 0 }; - -static QString msgFuncFailed(const char *f, unsigned long error) -{ - return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(f), Utils::winErrorMessage(error)); -} - -// Resolve a symbol from a library handle -template <class SymbolType> -inline bool resolveSymbol(const char *libraryName, HMODULE libraryHandle, const char *symbolName, SymbolType *s, QString *errorMessage) -{ - *s = 0; - FARPROC vs = ::GetProcAddress(libraryHandle, symbolName); - if (vs == 0) { - *errorMessage = QString::fromLatin1("Unable to resolve '%2' in '%1'.").arg(QString::fromAscii(symbolName), QString::fromAscii(libraryName)); - return false; - } - *s = reinterpret_cast<SymbolType>(vs); - return true; -} - -// Resolve a symbol from a library -template <class SymbolType> -inline bool resolveSymbol(const char *library, const char *symbolName, SymbolType *s, QString *errorMessage) -{ - *s = 0; - const HMODULE hm = ::GetModuleHandleA(library); - if (hm == NULL) { - *errorMessage = QString::fromLatin1("Module '%1' does not exist.").arg(QString::fromAscii(library)); - return false; - } - return resolveSymbol(library, hm , symbolName, s, errorMessage); -} - - -namespace Debugger { -namespace Internal { - -SharedLibraryInjector::SharedLibraryInjector(unsigned long processId, - unsigned long threadId) : - m_processId(processId), - m_threadId(threadId), - m_hasEscalatedPrivileges(false) -{ -} - -SharedLibraryInjector::~SharedLibraryInjector() -{ -} - -void SharedLibraryInjector::setPid(unsigned long pid) -{ - m_processId = pid; -} - -void SharedLibraryInjector::setThreadId(unsigned long tid) -{ - m_threadId = tid; -} - -void SharedLibraryInjector::setModulePath(const QString &modulePath) -{ - m_modulePath = modulePath; -} - -bool SharedLibraryInjector::remoteInject(const QString &modulePath, - bool waitForThread, QString *errorMessage) -{ - setModulePath(modulePath); - return doRemoteInjection(m_processId, NULL, m_modulePath, waitForThread, errorMessage); -} - -bool SharedLibraryInjector::stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage) -{ - setModulePath(modulePath); - return doStubInjection(m_processId, m_modulePath, entryPoint, errorMessage); -} - -bool SharedLibraryInjector::unload(HMODULE hFreeModule, QString *errorMessage) -{ - return doRemoteInjection(m_processId, hFreeModule, QString(), true, errorMessage); // Always use remote thread to unload -} - -bool SharedLibraryInjector::unload(const QString &modulePath, QString *errorMessage) -{ - const HMODULE hMod = modulePath.isEmpty() ? - findModuleHandle(m_modulePath, errorMessage) : - findModuleHandle(modulePath, errorMessage); - if (!hMod) - return false; - - return doRemoteInjection(m_processId, hMod, NULL, true, errorMessage); // Always use remote thread to unload -} - -bool SharedLibraryInjector::hasLoaded(const QString &modulePath) -{ - QString errorMessage; - return findModuleHandle(modulePath.isEmpty() ? m_modulePath : modulePath, &errorMessage) != NULL; -} - -QString SharedLibraryInjector::findModule(const QString &moduleName) -{ - const TCHAR *moduleNameC = reinterpret_cast<const TCHAR*>(moduleName.utf16()); - if (GetFileAttributesW(moduleNameC) != INVALID_FILE_ATTRIBUTES) - return moduleName; - - TCHAR testpathC[MAX_PATH]; - // Check application path first - GetModuleFileNameW(NULL, testpathC, MAX_PATH); - QString testPath = QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC)); - const int lastSlash = testPath.lastIndexOf(QLatin1Char('\\')); - if (lastSlash != -1) - testPath.truncate(lastSlash + 1); - testPath += moduleName; - if (GetFileAttributesW(reinterpret_cast<const TCHAR*>(testPath.utf16())) != INVALID_FILE_ATTRIBUTES) - return testPath; - // Path Search - if (SearchPathW(NULL, reinterpret_cast<const TCHAR*>(moduleName.utf16()), NULL, sizeof(testpathC)/2, testpathC, NULL)) - return QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC)); - // Last chance, if the module has already been loaded in this process, then use that path - const HMODULE loadedModule = GetModuleHandleW(reinterpret_cast<const TCHAR*>(moduleName.utf16())); - if (loadedModule) { - GetModuleFileNameW(loadedModule, testpathC, sizeof(testpathC)); - if (GetFileAttributes(testpathC) != INVALID_FILE_ATTRIBUTES) - return QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC)); - } - return QString(); -} - -unsigned long SharedLibraryInjector::getModuleEntryPoint(const QString &moduleName) -{ - // If file doesn't exist, just treat it like we cannot figure out the entry point - if (moduleName.isEmpty() || GetFileAttributesW(reinterpret_cast<const TCHAR*>(moduleName.utf16())) == INVALID_FILE_ATTRIBUTES) - return 0; - - // Read the first 1K of data from the file - unsigned char peData[1024]; - unsigned long peDataSize = 0; - const HANDLE hFile = CreateFileW(reinterpret_cast<const WCHAR*>(moduleName.utf16()), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (hFile == INVALID_HANDLE_VALUE - || !ReadFile(hFile, peData, sizeof(peData), &peDataSize, NULL)) - return 0; - CloseHandle(hFile); - - // Now we check to see if there is an optional header we can read - IMAGE_DOS_HEADER *dosHeader = reinterpret_cast<IMAGE_DOS_HEADER *>(peData); - if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE // DOS signature is incorrect, or - || dosHeader->e_lfanew == 0) // executable's PE data contains no offset to New EXE header - return 0; - - IMAGE_NT_HEADERS *ntHeaders = (IMAGE_NT_HEADERS *)(peData + dosHeader->e_lfanew); - if (ntHeaders->Signature != IMAGE_NT_SIGNATURE // NT signature is incorrect, or - || !ntHeaders->OptionalHeader.ImageBase // ImageBase or EntryPoint addresses are incorrect - || !ntHeaders->OptionalHeader.AddressOfEntryPoint) - return 0; - - return ntHeaders->OptionalHeader.ImageBase - + ntHeaders->OptionalHeader.AddressOfEntryPoint; -} - -bool SharedLibraryInjector::escalatePrivileges(QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << m_hasEscalatedPrivileges; - - if (m_hasEscalatedPrivileges) - return true; - - bool success = false; - HANDLE hToken = 0; - do { - TOKEN_PRIVILEGES Debug_Privileges; - if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &Debug_Privileges.Privileges[0].Luid)) { - *errorMessage = msgFuncFailed("LookupPrivilegeValue", GetLastError()); - break; - } - - Debug_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // set to enable privilege - Debug_Privileges.PrivilegeCount = 1; // working with only 1 - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { - *errorMessage = msgFuncFailed("OpenProcessToken", GetLastError()); - break; - } - if (!AdjustTokenPrivileges(hToken, FALSE, &Debug_Privileges, 0, NULL, NULL)) { - *errorMessage = msgFuncFailed("AdjustTokenPrivileges", GetLastError()); - break; - - } - success = true; - } while (false); - - if (hToken) - CloseHandle (hToken); - - m_hasEscalatedPrivileges = success; - return success; -} - -static void *writeDataToProcess(HANDLE process, void *data, unsigned size, QString *errorMessage) -{ - void *memory = VirtualAllocEx(process, NULL, size, MEM_COMMIT, PAGE_READWRITE); - if (!memory) { - *errorMessage = msgFuncFailed("VirtualAllocEx", GetLastError()); - return 0; - } - if (!WriteProcessMemory(process, memory, data, size, NULL)) { - *errorMessage = msgFuncFailed("WriteProcessMemory", GetLastError()); - return 0; - } - return memory; -} - -static void *writeUtf16StringToProcess(HANDLE process, const QString &what, QString *errorMessage) -{ - QByteArray whatData = QByteArray(reinterpret_cast<const char*>(what.utf16()), what.size() * 2); - whatData += '\0'; - whatData += '\0'; - return writeDataToProcess(process, whatData.data(), whatData.size(), errorMessage); -} - -bool SharedLibraryInjector::doStubInjection(unsigned long pid, - const QString &modulePath, - unsigned long entryPoint, - QString *errorMessage) -{ - if (debug) - qDebug() << pid << modulePath << entryPoint; - if (modulePath.isEmpty()) - return false; - - if (!escalatePrivileges(errorMessage)) - return false; -// MinGW lacks OpenThread() and the advapi.lib as of 6.5.2009 -#if (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) || defined(__GNUC__) - *errorMessage = QLatin1String("Not implemented for this architecture."); - return false; -#else - byte stubCode[] = { - 0x68, 0, 0, 0, 0, // push 0x00000000 - Placeholder for the entrypoint address - 0x9C, // pushfd - Save the flags and registers - 0x60, // pushad - 0x68, 0, 0, 0, 0, // push 0x00000000 - Placeholder for the string address - 0xB8, 0, 0, 0, 0, // mov eax, 0x00000000 - Placeholder for the LoadLibrary address - 0xFF, 0xD0, // call eax - Call LoadLibrary with string address - 0x61, // popad - Restore flags and registry - 0x9D, // popfd - 0xC3 // retn - Return (pops the entrypoint, and executes) - }; - - const HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (!hProcess) - return false; - - const HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, m_threadId); - if (!hThread) { - CloseHandle(hProcess); - return false; - } - - // Get address of LoadLibraryW in kernel32.dll - unsigned long funcPtr; - if (!resolveSymbol("kernel32.dll", "LoadLibraryW", &funcPtr, errorMessage)) - return false; - - // Allocate and write DLL path to target process' memory - // 0-terminated Utf16 string. - void *dllString = writeUtf16StringToProcess(hProcess, modulePath, errorMessage); - if (!dllString) - return false; - - // Allocate memory in target process, for the stubCode which will load the module, and execute - // the process' entry-point - const unsigned long stubLen = sizeof(stubCode); - // Modify the stubCode to have the proper entry-point, DLL module string, and function pointer - *(unsigned long*)(stubCode+1) = entryPoint; - *(unsigned long*)(stubCode+8) = reinterpret_cast<unsigned long>(dllString); - *(unsigned long*)(stubCode+13) = funcPtr; - - // If we cannot write the stubCode into the process, we simply bail out, and the process will - // continues execution as normal - void *stub = writeDataToProcess(hProcess, stubCode, stubLen, errorMessage); - if (!stub) - return false; - // Set the process' main thread to start executing from the stubCode address which we've just - // allocated in the process' memory.. If we cannot do that, bail out - CONTEXT ctx; - ctx.ContextFlags = CONTEXT_CONTROL; - if(!GetThreadContext(hThread, &ctx)) - return false; - ctx.Eip = reinterpret_cast<DWORD>(stub); - ctx.ContextFlags = CONTEXT_CONTROL; - if(!SetThreadContext(hThread, &ctx)) - return false; - - CloseHandle(hProcess); - CloseHandle(hThread); - return true; -#endif -} - -// ------------------------------------------------------------------------------------------------- - -bool SharedLibraryInjector::doRemoteInjection(unsigned long pid, - HMODULE hFreeModule, - const QString &modulePath, - bool waitForThread, - QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << '\n' << hFreeModule << pid << waitForThread<< modulePath; - - if (!hFreeModule && modulePath.isEmpty()) - return false; - - escalatePrivileges(errorMessage); - - const HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (hProcess == NULL) { - *errorMessage = msgFuncFailed("OpenProcess", GetLastError()); - qDebug() << "Failed to open process PID %d with all access\n" << pid; - return false; - } - - void *pszLibFileRemote = 0; - HANDLE hThread = 0; - // Call "FreeLibrary(hFreeModule)" to unload - if (hFreeModule) { - PTHREAD_START_ROUTINE pfnThreadRtn; - if (!resolveSymbol("Kernel32", "FreeLibrary", &pfnThreadRtn, errorMessage)) - return false; - hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, hFreeModule, 0, NULL); - } else { - pszLibFileRemote = writeUtf16StringToProcess(hProcess, modulePath, errorMessage); - if (!pszLibFileRemote) - return false; - // Loadlibrary routine - PTHREAD_START_ROUTINE pfnThreadRtn; - if (!resolveSymbol("Kernel32", "LoadLibraryW", &pfnThreadRtn, errorMessage)) - return false; - hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL); - } - if (hThread == NULL) { - *errorMessage = msgFuncFailed("CreateRemoteThread", GetLastError()); - return false; - } - - if (!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST)) { - *errorMessage = msgFuncFailed("SetThreadPriority", GetLastError()); - return false; - } - - if (waitForThread) { - if (::WaitForSingleObject(hThread, 20000) != WAIT_OBJECT_0) { - *errorMessage = QString::fromLatin1("WaitForSingleObject timeout"); - ::CloseHandle(hThread); - ::CloseHandle(hProcess); - return false; - } - - if (pszLibFileRemote) - ::VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE); - } - - if (hThread) - ::CloseHandle(hThread); - - if (hProcess) - ::CloseHandle(hProcess); - if (debug) - qDebug() << "success" << Q_FUNC_INFO; - return true; -} - -typedef BOOL (WINAPI *PFNENUMPROCESSMODULES) (HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded); -typedef DWORD (WINAPI *PFNGETMODULEFILENAMEEXW) (HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize); - -// We will require this function to get a module handle of our original module -HMODULE SharedLibraryInjector::findModuleHandle(const QString &modulePath, QString *errorMessage) -{ - if (debug) - qDebug() << Q_FUNC_INFO << modulePath; - - if (!escalatePrivileges(errorMessage)) - return 0; - - HMODULE hMods[1024]; - DWORD cbNeeded; - - HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_processId); - if (hProcess == NULL) - return 0; - - const char *psAPI_Lib = "PSAPI.DLL"; - HMODULE m_hModPSAPI = ::LoadLibraryA(psAPI_Lib); - PFNENUMPROCESSMODULES m_pfnEnumProcessModules; - PFNGETMODULEFILENAMEEXW m_pfnGetModuleFileNameExW; - if (!resolveSymbol(psAPI_Lib, m_hModPSAPI, "EnumProcessModules", &m_pfnEnumProcessModules, errorMessage) - || !resolveSymbol(psAPI_Lib, m_hModPSAPI, "GetModuleFileNameExW", &m_pfnGetModuleFileNameExW, errorMessage)) - return false; - - if(m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { - const unsigned count = cbNeeded / sizeof(HMODULE); - for (unsigned i = 0; i < count; i++) { - TCHAR szModName[MAX_PATH]; - if (m_pfnGetModuleFileNameExW(hProcess, hMods[i], szModName, sizeof(szModName))) { - if (QString::fromUtf16(reinterpret_cast<const unsigned short *>(szModName)) == modulePath) { - ::FreeLibrary(m_hModPSAPI); - ::CloseHandle(hProcess); - return hMods[i]; - } - } - } - } - - ::CloseHandle(hProcess); - return 0; -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/shared/sharedlibraryinjector.h b/src/plugins/debugger/shared/sharedlibraryinjector.h deleted file mode 100644 index b1cc59ff382af86cf8dc03ba99ed2c6cedd8c843..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/shared/sharedlibraryinjector.h +++ /dev/null @@ -1,89 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Marius Storm-Olsen -** -** 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 SHAREDLIBRARYINJECTOR_H -#define SHAREDLIBRARYINJECTOR_H - -#include <windows.h> -#include <QtCore/QString> - -namespace Debugger { -namespace Internal { - -/* SharedLibraryInjector: Injects a DLL into a remote process. - * Escalates the calling process rights. */ -class SharedLibraryInjector { - Q_DISABLE_COPY(SharedLibraryInjector) -public: - - explicit SharedLibraryInjector(unsigned long remotePid, unsigned long remoteThreadId = 0); - ~SharedLibraryInjector(); - - void setModulePath(const QString &modulePath); - bool hasLoaded(const QString &modulePath = QString()); - - // Remote injection, to be used for running processes - bool remoteInject(const QString &modulePath, bool waitForThread, QString *errorMessage); - - // Stub injection, to be used before execution starts - bool stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage); - - bool unload(const QString &modulePath /* = QString()*/, QString *errorMessage); - bool unload(HMODULE hFreeModule, QString *errorMessage); - - void setPid(unsigned long pid); - void setThreadId(unsigned long tid); - - static QString findModule(const QString &moduleName); - static unsigned long getModuleEntryPoint(const QString &moduleName); - -private: - bool escalatePrivileges(QString *errorMessage); - bool doRemoteInjection(unsigned long pid, HMODULE hFreeModule, - const QString &modulePath, bool waitForThread, - QString *errorMessage); - bool doStubInjection(unsigned long pid, const QString &modulePath, - unsigned long entryPoint, QString *errorMessage); - - HMODULE findModuleHandle(const QString &modulePath, QString *errorMessage); - - unsigned long m_processId; - unsigned long m_threadId; - QString m_modulePath; - bool m_hasEscalatedPrivileges; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // SHAREDLIBRARYINJECTOR_H