Skip to content
Permalink
Browse files

Merge PR #2512: Plugins: lay the groundwork for using Windows PA plug…

…ins on Linux with Wine

This PR implements support for running Windows PA plugins on Linux with Wine.

The existing plugins should, in most cases, be usable without many source changes.

The PR also ports the Rocket League PA plugin for Windows to run on Linux/Wine, as a proof of concept.
  • Loading branch information...
mkrautz committed Aug 13, 2016
2 parents 86824a3 + 743f129 commit 2396a998aa45c5439373e82004f77f861d1dcb8c
@@ -144,14 +144,14 @@ static int trylock(const std::multimap<std::wstring, unsigned long long int> &pi
return false;
}

procptr32_t steamclient = getModuleAddr("steamclient.so"); // Retrieve "steamclient.so" module's memory address
procptr32_t steamclient = getModuleAddr(L"steamclient.so"); // Retrieve "steamclient.so" module's memory address
// This prevents the plugin from linking to the game in case something goes wrong during module linking.
if (steamclient == 0)
return false;

serverid_steamclient = steamclient + 0x118E965; // Module + Server ID offset

procptr32_t server = getModuleAddr("server.so"); // Retrieve "server.so" module's memory address
procptr32_t server = getModuleAddr(L"server.so"); // Retrieve "server.so" module's memory address
// This prevents the plugin from linking to the game in case something goes wrong during module linking.
if (server == 0)
return false;
@@ -15,6 +15,14 @@
# define MUMBLE_PLUGIN_CALLING_CONVENTION
#endif

#if defined(__GNUC__)
# define MUMBLE_PLUGIN_EXPORT __attribute__((visibility("default")))
#elif defined(_MSC_VER)
# define MUMBLE_PLUGIN_EXPORT __declspec(dllexport)
#else
# error No MUMBLE_PLUGIN_EXPORT definition available
#endif

// Visual Studio 2008 x86
#if _MSC_VER == 1500 && defined(_M_IX86)
# define MUMBLE_PLUGIN_MAGIC 0xd63ab7ef
@@ -43,7 +43,10 @@ static inline std::string readAll(std::string fn) {
return content;
}

static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) {
static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, const wchar_t *modname) {
std::wstring modnameWide(modname);
std::string modnameNonWide(modnameWide.begin(), modnameWide.end());

std::stringstream ss;
ss << std::string("/proc/");
ss << static_cast<unsigned long>(pid);
@@ -137,7 +140,7 @@ static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) {
size_t lastSlash = pathname.find_last_of('/');
if (pathname.size() > lastSlash + 1) {
std::string basename = pathname.substr(lastSlash + 1);
if (basename == mod) {
if (basename == modnameNonWide) {
unsigned long addr = strtoul(baseaddr.c_str(), NULL, 16);
return addr;
}
@@ -148,7 +151,7 @@ static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) {
return 0;
}

static inline PTR_TYPE_CONCRETE getModuleAddr(std::string modname) {
static inline PTR_TYPE_CONCRETE getModuleAddr(const wchar_t *modname) {
return getModuleAddr(pPid, modname);
}

@@ -166,6 +169,15 @@ static inline bool peekProc(PTR_TYPE base, void *dest, size_t len) {
return (nread != -1 && static_cast<size_t>(nread) == in.iov_len);
}

template<class T>
T peekProc(PTR_TYPE base) {
T v = 0;
if (!peekProc(base, reinterpret_cast<T *>(&v), sizeof(T))) {
return 0;
}
return v;
}

template<class T>
bool peekProc(PTR_TYPE base, T &dest) {
struct iovec in;
@@ -181,11 +193,11 @@ bool peekProc(PTR_TYPE base, T &dest) {
return (nread != -1 && static_cast<size_t>(nread) == in.iov_len);
}

static bool inline initialize(const std::multimap<std::wstring, unsigned long long int> &pids, std::wstring procname, std::wstring modname = NULL) {
static bool inline initialize(const std::multimap<std::wstring, unsigned long long int> &pids, const wchar_t *procname, const wchar_t *modname = NULL) {
pModule = 0;

if (! pids.empty()) {
std::multimap<std::wstring, unsigned long long int>::const_iterator iter = pids.find(procname);
std::multimap<std::wstring, unsigned long long int>::const_iterator iter = pids.find(std::wstring(procname));

if (iter != pids.end())
pPid = static_cast<pid_t>(iter->second);
@@ -198,9 +210,7 @@ static bool inline initialize(const std::multimap<std::wstring, unsigned long lo
if (pPid == 0)
return false;

std::string procnameNonWide(procname.begin(), procname.end());
std::string modnameNonWide(modname.begin(), modname.end());
pModule = getModuleAddr((modnameNonWide.size() > 0) ? modnameNonWide : procnameNonWide);
pModule = getModuleAddr(modname ? modname : procname);

if (pModule == 0) {
pPid = 0;
@@ -6,9 +6,15 @@
#ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_
#define MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_

#if defined(__linux__)
# include "mumble_plugin_linux_32bit.h"
#else

typedef unsigned long procptr32_t;

#define PTR_TYPE procptr32_t
#include "mumble_plugin_win32_ptr_type.h"

#endif

#endif
@@ -6,9 +6,15 @@
#ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_
#define MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_

#if defined(__linux__)
#include "mumble_plugin_linux_64bit.h"
#else

typedef unsigned long long procptr64_t;

#define PTR_TYPE procptr64_t
#include "mumble_plugin_win32_ptr_type.h"

#endif

#endif
@@ -93,10 +93,10 @@ static MumblePlugin2 rlplug2 = {
trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() {
return &rlplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin2 *getMumblePlugin2() {
return &rlplug2;
}
@@ -5,7 +5,8 @@

include(../plugins.pri)

TARGET = rl
SOURCES = rl.cpp
LIBS += -luser32
TARGET = rl
linux:TARGET = mumble_paplugin_win32_rl

SOURCES = rl.cpp
win32:LIBS = -luser32
@@ -511,6 +511,27 @@ void Plugins::on_Timer_timeout() {
baseName = firstPart + QLatin1String(".") + completeSuffix;
}

if (baseName == QLatin1String("wine-preloader") || baseName == QLatin1String("wine64-preloader")) {
QFile f(QString(QLatin1String("/proc/%1/cmdline")).arg(entry));
if (f.open(QIODevice::ReadOnly)) {
QByteArray cmdline = f.readAll();
f.close();

int nul = cmdline.indexOf('\0');
if (nul != -1) {
cmdline.truncate(nul);
}

QString exe = QString::fromUtf8(cmdline);
if (exe.contains(QLatin1String("\\"))) {
int lastBackslash = exe.lastIndexOf(QLatin1String("\\"));
if (exe.count() > lastBackslash + 1) {
baseName = exe.mid(lastBackslash + 1);
}
}
}
}

if (!baseName.isEmpty()) {
pids.insert(std::pair<std::wstring, unsigned long long int>(baseName.toStdWString(), pid));
}

0 comments on commit 2396a99

Please sign in to comment.
You can’t perform that action at this time.