Code Cleanup: Remove sharedlibraryinjector.

Make NameDemangler's message non-translateable.
This commit is contained in:
Friedemann Kleint
2011-01-11 16:17:14 +01:00
parent d8035bcaca
commit d8d038daf4
5 changed files with 59 additions and 616 deletions

View File

@@ -31,17 +31,15 @@
** **
**************************************************************************/ **************************************************************************/
#include "name_demangler.h"
#include <QtCore/QChar> #include <QtCore/QChar>
#include <QtCore/QCoreApplication>
#include <QtCore/QLatin1String>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QRegExp> #include <QtCore/QRegExp>
#include <QtCore/QSet> #include <QtCore/QSet>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include "name_demangler.h"
// Debugging facility. // Debugging facility.
//#define DO_TRACE //#define DO_TRACE
#ifdef DO_TRACE #ifdef DO_TRACE
@@ -59,7 +57,6 @@ namespace Internal {
class NameDemanglerPrivate class NameDemanglerPrivate
{ {
Q_DECLARE_TR_FUNCTIONS(NameDemanglerPrivate)
public: public:
NameDemanglerPrivate(); NameDemanglerPrivate();
~NameDemanglerPrivate(); ~NameDemanglerPrivate();
@@ -332,7 +329,7 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName)
if (m_demangledName.startsWith(QLatin1String("::"))) if (m_demangledName.startsWith(QLatin1String("::")))
m_demangledName.remove(0, 2); m_demangledName.remove(0, 2);
if (!parseError && pos != mangledName.size()) if (!parseError && pos != mangledName.size())
error(tr("Premature end of input")); error(QString::fromLatin1("Premature end of input"));
#ifdef DO_TRACE #ifdef DO_TRACE
qDebug("%d", substitutions.size()); qDebug("%d", substitutions.size());
@@ -422,7 +419,7 @@ const QString NameDemanglerPrivate::parseEncoding()
} else if (firstSetSpecialName.contains(next)) { } else if (firstSetSpecialName.contains(next)) {
encoding = parseSpecialName(); encoding = parseSpecialName();
} else { } else {
error(tr("Invalid encoding")); error(QString::fromLatin1("Invalid encoding"));
} }
FUNC_END(encoding); FUNC_END(encoding);
@@ -476,7 +473,7 @@ const QString NameDemanglerPrivate::parseName()
} else if (firstSetLocalName.contains(next)) { } else if (firstSetLocalName.contains(next)) {
name = parseLocalName(); name = parseLocalName();
} else { } else {
error(tr("Invalid name")); error(QString::fromLatin1("Invalid name"));
} }
} }
@@ -516,7 +513,7 @@ const QString NameDemanglerPrivate::parseNestedName()
QString name; QString name;
if (advance() != 'N') { if (advance() != 'N') {
error(tr("Invalid nested-name")); error(QString::fromLatin1("Invalid nested-name"));
} else { } else {
QString cvQualifiers; QString cvQualifiers;
if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm' if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm'
@@ -525,7 +522,7 @@ const QString NameDemanglerPrivate::parseNestedName()
if (!parseError) { if (!parseError) {
name = parsePrefix(); name = parsePrefix();
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid nested-name")); error(QString::fromLatin1("Invalid nested-name"));
/* /*
* These are member function qualifiers which will have to * These are member function qualifiers which will have to
@@ -636,7 +633,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs()
QString args = QLatin1String("<"); QString args = QLatin1String("<");
if (advance() != 'I') { if (advance() != 'I') {
error(tr("Invalid template args")); error(QString::fromLatin1("Invalid template args"));
} else { } else {
do { do {
if (args.length() > 1) if (args.length() > 1)
@@ -644,7 +641,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs()
args += parseTemplateArg(); args += parseTemplateArg();
} while (!parseError && firstSetTemplateArg.contains(peek())); } while (!parseError && firstSetTemplateArg.contains(peek()));
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid template args")); error(QString::fromLatin1("Invalid template args"));
} }
args += '>'; args += '>';
@@ -662,7 +659,7 @@ const QString NameDemanglerPrivate::parseTemplateParam()
QString param; QString param;
if (advance() != 'T') { if (advance() != 'T') {
error(tr("Invalid template-param")); error(QString::fromLatin1("Invalid template-param"));
} else { } else {
int index; int index;
if (peek() == '_') if (peek() == '_')
@@ -670,7 +667,7 @@ const QString NameDemanglerPrivate::parseTemplateParam()
else else
index = parseNonNegativeNumber() + 1; index = parseNonNegativeNumber() + 1;
if (!parseError && advance() != '_') if (!parseError && advance() != '_')
error(tr("Invalid template-param")); error(QString::fromLatin1("Invalid template-param"));
param = templateParams.at(index); param = templateParams.at(index);
} }
@@ -689,7 +686,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers()
while (true) { while (true) {
if (peek() == 'V') { if (peek() == 'V') {
if (volatileFound || constFound) { if (volatileFound || constFound) {
error(tr("Invalid qualifiers: unexpected 'volatile'")); error(QString::fromLatin1("Invalid qualifiers: unexpected 'volatile'"));
break; break;
} else { } else {
volatileFound = true; volatileFound = true;
@@ -698,7 +695,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers()
} }
} else if (peek() == 'K') { } else if (peek() == 'K') {
if (constFound) { if (constFound) {
error(tr("Invalid qualifiers: 'const' appears twice")); error(QString::fromLatin1("Invalid qualifiers: 'const' appears twice"));
break; break;
} else { } else {
constFound = true; constFound = true;
@@ -741,7 +738,7 @@ int NameDemanglerPrivate::parseNonNegativeNumber(int base)
advance(); advance();
int number; int number;
if (pos == startPos) { if (pos == startPos) {
error(tr("Invalid non-negative number")); error(QString::fromLatin1("Invalid non-negative number"));
number = 0; number = 0;
} else { } else {
number = mangledName.mid(startPos, pos - startPos).toInt(0, base); number = mangledName.mid(startPos, pos - startPos).toInt(0, base);
@@ -799,7 +796,7 @@ const QString NameDemanglerPrivate::parseTemplateArg()
advance(); advance();
arg = parseExpression(); arg = parseExpression();
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid template-arg")); error(QString::fromLatin1("Invalid template-arg"));
} else if (next == 'I') { } else if (next == 'I') {
advance(); advance();
while (!parseError && firstSetTemplateArg.contains(peek())) { while (!parseError && firstSetTemplateArg.contains(peek())) {
@@ -808,9 +805,9 @@ const QString NameDemanglerPrivate::parseTemplateArg()
arg += parseTemplateArg(); arg += parseTemplateArg();
} }
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid template-arg")); error(QString::fromLatin1("Invalid template-arg"));
} else { } else {
error(tr("Invalid template-arg")); error(QString::fromLatin1("Invalid template-arg"));
} }
templateParams.append(arg); templateParams.append(arg);
@@ -874,7 +871,7 @@ const QString NameDemanglerPrivate::parseExpression()
while (!parseError && firstSetExpression.contains(peek())) while (!parseError && firstSetExpression.contains(peek()))
expr += parseExpression(); expr += parseExpression();
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid expression")); error(QString::fromLatin1("Invalid expression"));
} else if (str == QLatin1String("cv")) { } else if (str == QLatin1String("cv")) {
advance(2); advance(2);
expr = parseType() + QLatin1String("("); expr = parseType() + QLatin1String("(");
@@ -889,7 +886,7 @@ const QString NameDemanglerPrivate::parseExpression()
expr += parseExpression(); expr += parseExpression();
} }
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid expression")); error(QString::fromLatin1("Invalid expression"));
} else { } else {
expr += parseExpression(); expr += parseExpression();
} }
@@ -932,7 +929,7 @@ const QString NameDemanglerPrivate::parseExpression()
} else if (firstSetExprPrimary.contains(next)) { } else if (firstSetExprPrimary.contains(next)) {
expr = parseExprPrimary(); expr = parseExprPrimary();
} else { } else {
error(tr("Invalid expression")); error(QString::fromLatin1("Invalid expression"));
} }
} }
@@ -952,7 +949,7 @@ const QString NameDemanglerPrivate::parseExprPrimary()
QString expr; QString expr;
if (advance() != 'L') { if (advance() != 'L') {
error(tr("Invalid primary expression")); error(QString::fromLatin1("Invalid primary expression"));
} else { } else {
QChar next = peek(); QChar next = peek();
if (firstSetType.contains(next)) { if (firstSetType.contains(next)) {
@@ -963,15 +960,15 @@ const QString NameDemanglerPrivate::parseExprPrimary()
else if (true /* type just parsed indicates float */) else if (true /* type just parsed indicates float */)
expr += QString::number(parseFloat()); expr += QString::number(parseFloat());
else else
error(tr("Invalid expr-primary")); error(QString::fromLatin1("Invalid expr-primary"));
} }
} else if (firstSetMangledName.contains(next)) { } else if (firstSetMangledName.contains(next)) {
expr = parseMangledName(); expr = parseMangledName();
} else { } else {
error(tr("Invalid expr-primary")); error(QString::fromLatin1("Invalid expr-primary"));
} }
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid expr-primary")); error(QString::fromLatin1("Invalid expr-primary"));
} }
FUNC_END(expr); FUNC_END(expr);
@@ -1106,12 +1103,12 @@ const QString NameDemanglerPrivate::parseType()
advance(2); advance(2);
type = parseExpression(); // TODO: See above type = parseExpression(); // TODO: See above
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid type")); error(QString::fromLatin1("Invalid type"));
} else if (str == QLatin1String("DT")) { } else if (str == QLatin1String("DT")) {
advance(2); advance(2);
type = parseExpression(); // TODO: See above type = parseExpression(); // TODO: See above
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid type")); error(QString::fromLatin1("Invalid type"));
} else { } else {
QChar next = peek(); QChar next = peek();
if (str == QLatin1String("Dd") || str == QLatin1String("De") if (str == QLatin1String("Dd") || str == QLatin1String("De")
@@ -1179,7 +1176,7 @@ const QString NameDemanglerPrivate::parseType()
if (!parseError) if (!parseError)
type += parseType(); // TODO: handle this correctly type += parseType(); // TODO: handle this correctly
} else { } else {
error(tr("Invalid type")); error(QString::fromLatin1("Invalid type"));
} }
} }
@@ -1317,14 +1314,14 @@ const QString NameDemanglerPrivate::parseBuiltinType()
break; break;
break; break;
default: default:
error(tr("Invalid built-in type")); error(QString::fromLatin1("Invalid built-in type"));
} }
break; break;
case 'u': case 'u':
type = parseSourceName(); type = parseSourceName();
break; break;
default: default:
error(tr("Invalid builtin-type")); error(QString::fromLatin1("Invalid builtin-type"));
} }
FUNC_END(type); FUNC_END(type);
@@ -1340,7 +1337,7 @@ const QString NameDemanglerPrivate::parseFunctionType()
QString funcType; QString funcType;
bool externC = false; bool externC = false;
if (advance() != 'F') { if (advance() != 'F') {
error(tr("Invalid function type")); error(QString::fromLatin1("Invalid function type"));
} else { } else {
if (peek() == 'Y') { if (peek() == 'Y') {
advance(); advance();
@@ -1348,7 +1345,7 @@ const QString NameDemanglerPrivate::parseFunctionType()
} }
const QStringList &signature = parseBareFunctionType(); const QStringList &signature = parseBareFunctionType();
if (!parseError && advance() != 'E') if (!parseError && advance() != 'E')
error(tr("Invalid function type")); error(QString::fromLatin1("Invalid function type"));
if (!parseError) { if (!parseError) {
QString returnType = signature.first(); QString returnType = signature.first();
QString argList = QLatin1String("("); QString argList = QLatin1String("(");
@@ -1428,7 +1425,7 @@ const QString NameDemanglerPrivate::parseUnqualifiedName()
else if (firstSetSourceName.contains(next)) else if (firstSetSourceName.contains(next))
name = QLatin1String("::") + parseSourceName(); name = QLatin1String("::") + parseSourceName();
else else
error(tr("Invalid unqualified-name")); error(QString::fromLatin1("Invalid unqualified-name"));
FUNC_END(name); FUNC_END(name);
return name; return name;
@@ -1519,7 +1516,7 @@ const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName()
static const UnaryOperator pseudoOp(QLatin1String("invalid"), static const UnaryOperator pseudoOp(QLatin1String("invalid"),
QLatin1String("invalid")); QLatin1String("invalid"));
op = &pseudoOp; 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; QString type;
if (advance() != 'A') { if (advance() != 'A') {
error(tr("Invalid array-type")); error(QString::fromLatin1("Invalid array-type"));
} else { } else {
QChar next = peek(); QChar next = peek();
QString dimension; QString dimension;
@@ -1551,7 +1548,7 @@ const QString NameDemanglerPrivate::parseArrayType()
dimension = parseExpression(); dimension = parseExpression();
} }
if (!parseError && advance() != '_') if (!parseError && advance() != '_')
error(tr("Invalid array-type")); error(QString::fromLatin1("Invalid array-type"));
if (!parseError) if (!parseError)
type = QString::fromLocal8Bit("%1[%2]"). type = QString::fromLocal8Bit("%1[%2]").
arg(parseType()).arg(dimension); arg(parseType()).arg(dimension);
@@ -1568,7 +1565,7 @@ const QString NameDemanglerPrivate::parsePointerToMemberType()
QString type; QString type;
if (advance() != 'M') { if (advance() != 'M') {
error(tr("Invalid pointer-to-member-type")); error(QString::fromLatin1("Invalid pointer-to-member-type"));
} else { } else {
const QString classType = parseType(); const QString classType = parseType();
QString memberType; QString memberType;
@@ -1615,22 +1612,22 @@ const QString NameDemanglerPrivate::parseSubstitution()
QString substitution; QString substitution;
if (advance() != 'S') { if (advance() != 'S') {
error(tr("Invalid substitution")); error(QString::fromLatin1("Invalid substitution"));
} else if (firstSetSeqId.contains(peek())) { } else if (firstSetSeqId.contains(peek())) {
int substIndex = parseSeqId() + 1; int substIndex = parseSeqId() + 1;
if (!parseError && substIndex >= substitutions.size()) 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"). "but there are only %2").
arg(substIndex + 1).arg(substitutions.size())); arg(substIndex + 1).arg(substitutions.size()));
else else
substitution = substitutions.at(substIndex); substitution = substitutions.at(substIndex);
if (!parseError && advance() != '_') if (!parseError && advance() != '_')
error(tr("Invalid substitution")); error(QString::fromLatin1("Invalid substitution"));
} else { } else {
switch (advance().toAscii()) { switch (advance().toAscii()) {
case '_': case '_':
if (substitutions.isEmpty()) if (substitutions.isEmpty())
error(tr("Invalid substitution: There are no elements")); error(QString::fromLatin1("Invalid substitution: There are no elements"));
else else
substitution = substitutions.first(); substitution = substitutions.first();
break; break;
@@ -1661,7 +1658,7 @@ const QString NameDemanglerPrivate::parseSubstitution()
"::std::basic_iostream<char, std::char_traits<char> >"); "::std::basic_iostream<char, std::char_traits<char> >");
break; break;
default: default:
error(tr("Invalid substitution")); error(QString::fromLatin1("Invalid substitution"));
} }
} }
@@ -1733,7 +1730,7 @@ const QString NameDemanglerPrivate::parseSpecialName()
if (!parseError) if (!parseError)
parseEncoding(); parseEncoding();
} else { } else {
error(tr("Invalid special-name")); error(QString::fromLatin1("Invalid special-name"));
} }
FUNC_END(name); FUNC_END(name);
@@ -1756,7 +1753,7 @@ const QString NameDemanglerPrivate::parseUnscopedName()
} else if (firstSetUnqualifiedName.contains(peek())) { } else if (firstSetUnqualifiedName.contains(peek())) {
name = parseUnqualifiedName(); name = parseUnqualifiedName();
} else { } else {
error(tr("Invalid unqualified-name")); error(QString::fromLatin1("Invalid unqualified-name"));
} }
FUNC_END(name); FUNC_END(name);
@@ -1776,11 +1773,11 @@ const QString NameDemanglerPrivate::parseLocalName()
QString name; QString name;
if (advance() != 'Z') { if (advance() != 'Z') {
error(tr("Invalid local-name")); error(QString::fromLatin1("Invalid local-name"));
} else { } else {
name = parseEncoding(); name = parseEncoding();
if (!parseError && advance() != 'E') { if (!parseError && advance() != 'E') {
error(tr("Invalid local-name")); error(QString::fromLatin1("Invalid local-name"));
} else { } else {
QString str = readAhead(2); QString str = readAhead(2);
QChar next = peek(); QChar next = peek();
@@ -1793,7 +1790,7 @@ const QString NameDemanglerPrivate::parseLocalName()
advance(); advance();
name += QLatin1String("::\"string literal\""); name += QLatin1String("::\"string literal\"");
} else { } else {
error(tr("Invalid local-name")); error(QString::fromLatin1("Invalid local-name"));
} }
if (!parseError && firstSetDiscriminator.contains(peek())) if (!parseError && firstSetDiscriminator.contains(peek()))
parseDiscriminator(); parseDiscriminator();
@@ -1809,7 +1806,7 @@ int NameDemanglerPrivate::parseDiscriminator()
{ {
int index; int index;
if (advance() != '_') { if (advance() != '_') {
error(tr("Invalid discriminator")); error(QString::fromLatin1("Invalid discriminator"));
index = -1; index = -1;
} else { } else {
index = parseNonNegativeNumber(); index = parseNonNegativeNumber();
@@ -1841,7 +1838,7 @@ const QString NameDemanglerPrivate::parseCtorDtorName()
case '3': case '3':
break; break;
default: default:
error(tr("Invalid ctor-dtor-name")); error(QString::fromLatin1("Invalid ctor-dtor-name"));
} }
break; break;
case 'D': case 'D':
@@ -1852,11 +1849,11 @@ const QString NameDemanglerPrivate::parseCtorDtorName()
destructor = true; destructor = true;
break; break;
default: default:
error(tr("Invalid ctor-dtor-name")); error(QString::fromLatin1("Invalid ctor-dtor-name"));
} }
break; break;
default: default:
error(tr("Invalid ctor-dtor-name")); error(QString::fromLatin1("Invalid ctor-dtor-name"));
} }
if (!parseError) { if (!parseError) {
@@ -1904,10 +1901,10 @@ void NameDemanglerPrivate::parseCallOffset()
parseVOffset(); parseVOffset();
break; break;
default: default:
error(tr("Invalid call-offset")); error(QString::fromLatin1("Invalid call-offset"));
} }
if (!parseError && advance() != '_') if (!parseError && advance() != '_')
error(tr("Invalid call-offset")); error(QString::fromLatin1("Invalid call-offset"));
FUNC_END(QString()); FUNC_END(QString());
} }
@@ -1929,7 +1926,7 @@ void NameDemanglerPrivate::parseVOffset()
parseNumber(); parseNumber();
if (advance() != '_') if (advance() != '_')
error(tr("Invalid v-offset")); error(QString::fromLatin1("Invalid v-offset"));
parseNumber(); parseNumber();
FUNC_END(QString()); FUNC_END(QString());
@@ -1941,7 +1938,7 @@ int NameDemanglerPrivate::parseDigit()
int digit = advance().digitValue(); int digit = advance().digitValue();
if (digit == -1) if (digit == -1)
error(tr("Invalid digit")); error(QString::fromLatin1("Invalid digit"));
FUNC_END(QString::number(digit)); FUNC_END(QString::number(digit));
return digit; return digit;
@@ -1950,7 +1947,7 @@ int NameDemanglerPrivate::parseDigit()
void NameDemanglerPrivate::error(const QString &errorSpec) void NameDemanglerPrivate::error(const QString &errorSpec)
{ {
parseError = true; 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) QChar NameDemanglerPrivate::peek(int ahead)

View File

@@ -34,6 +34,8 @@
#ifndef NAME_DEMANGLER_H #ifndef NAME_DEMANGLER_H
#define NAME_DEMANGLER_H #define NAME_DEMANGLER_H
#include <QtCore/QtGlobal>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QString; class QString;
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -8,12 +8,10 @@ INCLUDEPATH+=$$PWD
win32 { win32 {
SOURCES += $$PWD/peutils.cpp \ SOURCES += $$PWD/peutils.cpp \
$$PWD/dbgwinutils.cpp \ $$PWD/dbgwinutils.cpp
$$PWD/sharedlibraryinjector.cpp
HEADERS += $$PWD/peutils.h \ HEADERS += $$PWD/peutils.h \
$$PWD/dbgwinutils.h \ $$PWD/dbgwinutils.h
$$PWD/sharedlibraryinjector.h
contains(QMAKE_CXX, cl) { contains(QMAKE_CXX, cl) {
# For the Privilege manipulation functions in sharedlibraryinjector.cpp. # For the Privilege manipulation functions in sharedlibraryinjector.cpp.

View File

@@ -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

View File

@@ -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