Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2020-11-06 23:37:06 +0300
committerDavide Beatrici <git@davidebeatrici.dev>2020-11-06 23:37:06 +0300
commit988b8417acfc4ca4b19283afe7e1973d05a39be8 (patch)
tree160e79e9d7dc57ac27e02279775ea29418a537ae /plugins
parenta3480a2a6b432b247821add175f725714692ef1e (diff)
REFAC(positional-audio): Proper functions/classes for module-related operations
Previously, only module() was present: it retrieved the base address of the specified module. It worked fine, but it iterated through the process' modules every time it was called. This commit replaces it with modules(), which returns an std::unordered_map containing all modules. The map uses the module name as key and Module as value. Aside from the performance improvement, the new code also provides info for each module region: - Start address. - Size. - Whether it's readable, writable and/or executable.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/HostLinux.cpp166
-rw-r--r--plugins/HostLinux.h7
-rw-r--r--plugins/HostWindows.cpp59
-rw-r--r--plugins/HostWindows.h7
-rw-r--r--plugins/Module.cpp18
-rw-r--r--plugins/Module.h48
-rw-r--r--plugins/Process.h1
-rw-r--r--plugins/ProcessLinux.cpp8
-rw-r--r--plugins/ProcessWindows.cpp8
-rw-r--r--plugins/mumble_plugin_utils.h32
-rw-r--r--plugins/se/CMakeLists.txt1
-rw-r--r--plugins/se/se.cpp16
12 files changed, 261 insertions, 110 deletions
diff --git a/plugins/HostLinux.cpp b/plugins/HostLinux.cpp
index cf8fcb4c4..2c5131ac2 100644
--- a/plugins/HostLinux.cpp
+++ b/plugins/HostLinux.cpp
@@ -32,112 +32,110 @@ bool HostLinux::peek(const procptr_t address, void *dst, const size_t size) cons
return (ret != -1 && static_cast< size_t >(ret) == in.iov_len);
}
-procptr_t HostLinux::module(const std::string &module) const {
- std::stringstream ss;
- ss << "/proc/";
- ss << m_pid;
- ss << "/maps";
- const auto maps = readFile(ss.str());
+Modules HostLinux::modules() const {
+ std::ostringstream path;
+ path << "/proc/";
+ path << m_pid;
+ path << "/maps";
+ const auto maps = readFile(path.str());
if (maps.size() == 0) {
- return 0;
+ return {};
}
- std::stringstream ssPath(maps);
- while (ssPath.good()) {
- std::string baseaddr;
-
- int ch;
- while (1) {
- ch = ssPath.get();
- if (ch == '-') {
- break;
- } else if (ch == EOF) {
- return 0;
- }
- baseaddr.push_back(static_cast< char >(ch));
+ Modules modules;
+ std::string name;
+ std::stringstream stream(maps);
+
+ while (stream) {
+ auto ret = readUntil(stream, '-');
+ if (!ret.second) {
+ return modules;
}
- // seek to perms
- do {
- ch = ssPath.get();
- if (ch == EOF) {
- return 0;
- }
- } while (ch != ' ');
+ MemoryRegion region;
+ region.address = std::stoull(ret.first, nullptr, 16);
- // seek to offset
- do {
- ch = ssPath.get();
- if (ch == EOF) {
- return 0;
- }
- } while (ch != ' ');
+ ret = readUntil(stream, ' ');
+ if (!ret.second) {
+ return modules;
+ }
- // seek to dev
- do {
- ch = ssPath.get();
- if (ch == EOF) {
- return 0;
- }
- } while (ch != ' ');
+ region.size = std::stoull(ret.first, nullptr, 16) - region.address;
- // seek to inode
- do {
- ch = ssPath.get();
- if (ch == EOF) {
- return 0;
- }
- } while (ch != ' ');
+ ret = readUntil(stream, ' ');
+ if (!ret.second) {
+ return modules;
+ }
- // seek to pathname
- do {
- ch = ssPath.get();
- if (ch == EOF) {
- return 0;
+ for (const auto character : ret.first) {
+ switch (character) {
+ case 'r':
+ region.readable = true;
+ break;
+ case 'w':
+ region.writable = true;
+ break;
+ case 'x':
+ region.executable = true;
+ break;
}
- } while (ch != ' ');
+ }
- // eat spaces until we're at the beginning of pathname.
- while (ch == ' ') {
- if (ch == EOF) {
- return 0;
+ // Skip offset, dev and inode
+ for (uint8_t i = 0; i < 3; ++i) {
+ if (!skipUntil(stream, ' ', false)) {
+ return modules;
}
- ch = ssPath.get();
}
- ssPath.unget();
-
- std::string pathname;
- while (1) {
- ch = ssPath.get();
- if (ch == '\n') {
- break;
- } else if (ch == EOF) {
- return 0;
+
+ // Eat spaces until we're at the beginning of the path
+ if (!skipUntil(stream, ' ', true)) {
+ return modules;
+ }
+
+ // Throw up last eaten character
+ stream.unget();
+
+ ret = readUntil(stream, '\n');
+ if (!ret.second) {
+ return modules;
+ }
+
+ if (ret.first.size() == 0) {
+ // Anonymous region, let's add it to the module that owns the previous one
+ if (!name.empty()) {
+ auto iter = modules.find(name);
+ iter->second.addRegion(region);
}
- pathname.push_back(static_cast< char >(ch));
- };
-
- // OK, we found 'em!
- // Only treat path as a real path if it starts with /.
- if (pathname.size() > 0 && pathname.at(0) == '/') {
- // Find the basename.
- size_t lastSlash = pathname.find_last_of('/');
- if (pathname.size() > lastSlash + 1) {
- std::string basename = pathname.substr(lastSlash + 1);
- if (basename == module) {
- unsigned long addr = strtoul(baseaddr.c_str(), nullptr, 16);
- return addr;
- }
+
+ continue;
+ }
+
+ // Only treat path as a real path if it starts with "/"
+ if (ret.first[0] != '/') {
+ continue;
+ }
+
+ const auto lastSlashPos = ret.first.find_last_of('/');
+ if (ret.first.size() > lastSlashPos + 1) {
+ name = ret.first.substr(lastSlashPos + 1);
+ const auto iter = modules.find(name);
+ if (iter != modules.cend()) {
+ iter->second.addRegion(region);
+ } else {
+ Module module(name);
+ module.addRegion(region);
+ modules.insert(std::make_pair(name, module));
}
}
}
- return 0;
+ return modules;
}
bool HostLinux::isWine(const procid_t id) {
- std::stringstream ss;
+ std::ostringstream ss;
ss << "/proc/";
ss << id;
ss << "/exe";
diff --git a/plugins/HostLinux.h b/plugins/HostLinux.h
index 6cf56fcf3..c6b0ed42c 100644
--- a/plugins/HostLinux.h
+++ b/plugins/HostLinux.h
@@ -6,12 +6,9 @@
#ifndef HOSTLINUX_H_
#define HOSTLINUX_H_
-#include <cstddef>
-#include <cstdint>
-#include <string>
+#include "Module.h"
typedef uint32_t procid_t;
-typedef uint64_t procptr_t;
class HostLinux {
protected:
@@ -19,7 +16,7 @@ protected:
public:
bool peek(const procptr_t address, void *dst, const size_t size) const;
- procptr_t module(const std::string &module) const;
+ Modules modules() const;
static bool isWine(const procid_t id);
diff --git a/plugins/HostWindows.cpp b/plugins/HostWindows.cpp
index 66e6c6d43..768c542fb 100644
--- a/plugins/HostWindows.cpp
+++ b/plugins/HostWindows.cpp
@@ -22,24 +22,61 @@ bool HostWindows::peek(const procptr_t address, void *dst, const size_t size) co
return (ok && read == size);
}
-procptr_t HostWindows::module(const std::string &module) const {
- const auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, m_pid);
- if (handle == INVALID_HANDLE_VALUE) {
- return 0;
+Modules HostWindows::modules() const {
+ const auto processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, false, m_pid);
+ if (!processHandle) {
+ return {};
}
- procptr_t ret = 0;
+ const auto snapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, m_pid);
+ if (snapshotHandle == INVALID_HANDLE_VALUE) {
+ return {};
+ }
+
+ Modules modules;
MODULEENTRY32 me;
me.dwSize = sizeof(me);
- for (BOOL ok = Module32First(handle, &me); ok; ok = Module32Next(handle, &me)) {
- if (me.szModule == utf8ToUtf16(module)) {
- ret = reinterpret_cast< procptr_t >(me.modBaseAddr);
- break;
+ for (auto ok = Module32First(snapshotHandle, &me); ok; ok = Module32Next(snapshotHandle, &me)) {
+ const auto name = utf16ToUtf8(reinterpret_cast< char16_t * >(me.szModule));
+ if (modules.find(name) != modules.cend()) {
+ continue;
+ }
+
+ Module module(name);
+ MEMORY_BASIC_INFORMATION64 mbi;
+ auto address = reinterpret_cast< procptr_t >(me.modBaseAddr);
+ while (VirtualQueryEx(processHandle, reinterpret_cast< LPCVOID >(address),
+ reinterpret_cast< PMEMORY_BASIC_INFORMATION >(&mbi), sizeof(mbi))) {
+ MemoryRegion region{};
+ region.address = address;
+ region.size = mbi.RegionSize;
+ switch (mbi.Protect) {
+ case PAGE_READWRITE:
+ region.writable = true;
+ case PAGE_READONLY:
+ case PAGE_WRITECOPY:
+ region.readable = true;
+ break;
+ case PAGE_EXECUTE_READWRITE:
+ region.writable = true;
+ case PAGE_EXECUTE_READ:
+ case PAGE_EXECUTE_WRITECOPY:
+ region.readable = true;
+ case PAGE_EXECUTE:
+ region.executable = true;
+ break;
+ }
+ module.addRegion(region);
+
+ address += region.size;
}
+
+ modules.insert(std::make_pair(name, module));
}
- CloseHandle(handle);
+ CloseHandle(processHandle);
+ CloseHandle(snapshotHandle);
- return ret;
+ return modules;
}
diff --git a/plugins/HostWindows.h b/plugins/HostWindows.h
index b42c1dbc1..06a344b43 100644
--- a/plugins/HostWindows.h
+++ b/plugins/HostWindows.h
@@ -6,12 +6,9 @@
#ifndef HOSTWINDOWS_H_
#define HOSTWINDOWS_H_
-#include <cstddef>
-#include <cstdint>
-#include <string>
+#include "Module.h"
typedef uint32_t procid_t;
-typedef uint64_t procptr_t;
class HostWindows {
protected:
@@ -19,7 +16,7 @@ protected:
public:
bool peek(const procptr_t address, void *dst, const size_t size) const;
- procptr_t module(const std::string &module) const;
+ Modules modules() const;
HostWindows(const procid_t pid);
virtual ~HostWindows();
diff --git a/plugins/Module.cpp b/plugins/Module.cpp
new file mode 100644
index 000000000..d50a5c45b
--- /dev/null
+++ b/plugins/Module.cpp
@@ -0,0 +1,18 @@
+// Copyright 2020 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+#include "Module.h"
+
+Module::Module(const std::string &name) : m_name(name) {
+}
+
+procptr_t Module::baseAddress() const {
+ const auto iter = m_regions.cbegin();
+ if (iter != m_regions.cend()) {
+ return iter->address;
+ }
+
+ return 0;
+}
diff --git a/plugins/Module.h b/plugins/Module.h
new file mode 100644
index 000000000..d3d54af38
--- /dev/null
+++ b/plugins/Module.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#include <set>
+#include <string>
+#include <unordered_map>
+
+typedef uint64_t procptr_t;
+
+struct MemoryRegion {
+ procptr_t address;
+ size_t size;
+
+ bool readable;
+ bool writable;
+ bool executable;
+
+ bool operator<(const MemoryRegion &region) const { return address < region.address; }
+
+ MemoryRegion() : address(0), size(0), readable(false), writable(false), executable(false) {}
+};
+
+typedef std::set< MemoryRegion > MemoryRegions;
+
+class Module {
+protected:
+ std::string m_name;
+ MemoryRegions m_regions;
+
+public:
+ inline std::string name() const { return m_name; }
+ inline MemoryRegions regions() const { return m_regions; }
+
+ inline bool addRegion(const MemoryRegion &region) { return m_regions.insert(region).second; }
+
+ procptr_t baseAddress() const;
+
+ Module(const std::string &name);
+};
+
+typedef std::unordered_map< std::string, Module > Modules;
+
+#endif // MODULE_H
diff --git a/plugins/Process.h b/plugins/Process.h
index 8e1db93ab..df78a2a2e 100644
--- a/plugins/Process.h
+++ b/plugins/Process.h
@@ -26,7 +26,6 @@ protected:
uint8_t m_pointerSize;
public:
- using Host::module;
using Host::peek;
inline bool isOk() const { return m_ok; }
diff --git a/plugins/ProcessLinux.cpp b/plugins/ProcessLinux.cpp
index a263d4c55..741f2f8c2 100644
--- a/plugins/ProcessLinux.cpp
+++ b/plugins/ProcessLinux.cpp
@@ -8,7 +8,13 @@
#include <elf.h>
ProcessLinux::ProcessLinux(const procid_t id, const std::string &name) : Process(id, name) {
- const auto address = module(name);
+ const auto mods = modules();
+ const auto iter = mods.find(name);
+ if (iter == mods.cend()) {
+ return;
+ }
+
+ const auto address = iter->second.baseAddress();
if (!address) {
return;
}
diff --git a/plugins/ProcessWindows.cpp b/plugins/ProcessWindows.cpp
index b872cf64d..77cf304fa 100644
--- a/plugins/ProcessWindows.cpp
+++ b/plugins/ProcessWindows.cpp
@@ -8,7 +8,13 @@
#include "mumble_plugin_win32_internals.h"
ProcessWindows::ProcessWindows(const procid_t id, const std::string &name) : Process(id, name) {
- const auto address = module(name);
+ const auto mods = modules();
+ const auto iter = mods.find(name);
+ if (iter == mods.cend()) {
+ return;
+ }
+
+ const auto address = iter->second.baseAddress();
if (!address) {
return;
}
diff --git a/plugins/mumble_plugin_utils.h b/plugins/mumble_plugin_utils.h
index fb82cbca1..260b0b20a 100644
--- a/plugins/mumble_plugin_utils.h
+++ b/plugins/mumble_plugin_utils.h
@@ -10,6 +10,7 @@
#include <codecvt>
#include <fstream>
#include <locale>
+#include <sstream>
#ifdef OS_LINUX
# include <fenv.h>
@@ -118,6 +119,37 @@ static inline std::string readFile(const std::string &path) {
return content;
}
+/// Reads characters from the stream until \p character is encountered.
+/// @return Read characters and whether the stream is still good.
+static inline std::pair< std::string, bool > readUntil(std::stringstream &stream,
+ const std::stringstream::int_type character) {
+ std::string buf;
+
+ for (auto input = stream.get(); input != character; input = stream.get()) {
+ if (!stream) {
+ return { buf, false };
+ }
+
+ buf.push_back(input);
+ };
+
+ return { buf, true };
+}
+
+/// Discards characters in the stream until the specified one is encountered.
+/// @param[inverted] Inverts the behavior.
+/// @return Whether the stream is still good.
+static inline bool skipUntil(std::stringstream &stream, const std::stringstream::int_type character,
+ const bool inverted) {
+ for (auto input = stream.get(); inverted ? (input == character) : (input != character); input = stream.get()) {
+ if (!stream) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/// Calculates sine and cosine of the specified value.
/// On Linux the calculation is guaranteed to be simultaneous.
static inline bool sinCos(const float value, float &outSin, float &outCos) {
diff --git a/plugins/se/CMakeLists.txt b/plugins/se/CMakeLists.txt
index aaf63ac7d..e6f56857e 100644
--- a/plugins/se/CMakeLists.txt
+++ b/plugins/se/CMakeLists.txt
@@ -6,6 +6,7 @@
add_library(se SHARED
"se.cpp"
+ "../Module.cpp"
"../Process.cpp"
"../ProcessWindows.cpp"
)
diff --git a/plugins/se/se.cpp b/plugins/se/se.cpp
index 4560046e5..dd256afbc 100644
--- a/plugins/se/se.cpp
+++ b/plugins/se/se.cpp
@@ -215,12 +215,24 @@ static int tryLock(const std::multimap< std::wstring, unsigned long long int > &
return false;
}
- const auto engine = proc->module(isWin32 ? "engine.dll" : "engine.so");
+ const auto modules = proc->modules();
+
+ auto iter = modules.find(isWin32 ? "engine.dll" : "engine.so");
+ if (iter == modules.cend()) {
+ return false;
+ }
+
+ const auto engine = iter->second.baseAddress();
if (!engine) {
return false;
}
- const auto client = proc->module(isWin32 ? "client.dll" : "client.so");
+ iter = modules.find(isWin32 ? "client.dll" : "client.so");
+ if (iter == modules.cend()) {
+ return false;
+ }
+
+ const auto client = iter->second.baseAddress();
if (!client) {
return false;
}