Skip to content

Commit

Permalink
feat: add new symbol data format reader
Browse files Browse the repository at this point in the history
  • Loading branch information
OEOTYAN committed Jun 27, 2024
1 parent 2cdd2f5 commit 6df7337
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 44 deletions.
146 changes: 103 additions & 43 deletions src/pl/SymbolProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string>
#include <string_view>

#include "parallel_hashmap/btree.h"
#include "parallel_hashmap/phmap.h"

#include "PDB.h"
Expand All @@ -21,6 +22,8 @@
#include "PDB_RawFile.h"
#include "PDB_Types.h"

#include "snappy.h"

#include "pl/internal/FakeSymbol.h"
#include "pl/internal/Logger.h"
#include "pl/internal/MemoryFile.h"
Expand All @@ -38,20 +41,20 @@ static uintptr_t imageBaseAddr;

// phmap hash maps is thread-safe when reading
using Symbol2RvaMap = phmap::flat_hash_map<std::string, uint32_t>;
using Rva2SymbolMap = phmap::flat_hash_map<uint32_t, std::list<const std::string*>>;
using Rva2SymbolMap = phmap::btree_map<uint32_t, std::vector<std::string const*>>;
Symbol2RvaMap* funcMap = nullptr;
Rva2SymbolMap* rvaMap = nullptr;

void initFunctionMap(const PDB::RawFile& rawPdbFile, const PDB::DBIStream& dbiStream) {
void initFunctionMap(PDB::RawFile const& rawPdbFile, PDB::DBIStream const& dbiStream) {
Info("Loading symbols from pdb...");

const PDB::ImageSectionStream imageSectionStream = dbiStream.CreateImageSectionStream(rawPdbFile);
const PDB::CoalescedMSFStream symbolRecordStream = dbiStream.CreateSymbolRecordStream(rawPdbFile);
const PDB::PublicSymbolStream publicSymbolStream = dbiStream.CreatePublicSymbolStream(rawPdbFile);
const PDB::ModuleInfoStream moduleInfoStream = dbiStream.CreateModuleInfoStream(rawPdbFile);
PDB::ImageSectionStream const imageSectionStream = dbiStream.CreateImageSectionStream(rawPdbFile);
PDB::CoalescedMSFStream const symbolRecordStream = dbiStream.CreateSymbolRecordStream(rawPdbFile);
PDB::PublicSymbolStream const publicSymbolStream = dbiStream.CreatePublicSymbolStream(rawPdbFile);
PDB::ModuleInfoStream const moduleInfoStream = dbiStream.CreateModuleInfoStream(rawPdbFile);

const ArrayView<PDB::ModuleInfoStream::Module> modules = moduleInfoStream.GetModules();
const ArrayView<PDB::HashRecord> publicSymbolRecord = publicSymbolStream.GetRecords();
ArrayView<PDB::ModuleInfoStream::Module> const modules = moduleInfoStream.GetModules();
ArrayView<PDB::HashRecord> const publicSymbolRecord = publicSymbolStream.GetRecords();

// pre alloc hash buckets, 1.2x for public symbols
funcMap = new Symbol2RvaMap((size_t)((double)publicSymbolRecord.GetLength() * 1.2));
Expand Down Expand Up @@ -107,41 +110,90 @@ void initFunctionMap(const PDB::RawFile& rawPdbFile, const PDB::DBIStream& dbiSt
fflush(stdout);
}

void initFunctionMap(std::string_view compressed) {
Info("Loading symbols from data...");
funcMap = new Symbol2RvaMap{};
std::string data;
snappy::Uncompress(compressed.data(), compressed.size(), &data);
uint32_t rva{0};
for (size_t i = 0; i < data.size(); i++) {
uint8_t c = data[i++];
bool const isFunction = c & (1 << 0);
bool const fromModule = c & (1 << 1);
bool const skipped = c & (1 << 2);
uint32_t rrva{0};
int shift_amount = 0;
do {
rrva |= (uint32_t)(data[i] & 0x7F) << shift_amount;
shift_amount += 7;
} while ((data[i++] & 0x80) != 0);
rva += rrva;

if (skipped) {
for (; data[i] != '\n'; i++) {}
continue;
}
std::string name;
for (; data[i] != '\n'; i++) { name += data[i]; }
if (!fromModule) {
auto fake = pl::fake_symbol::getFakeSymbol(name);
if (fake.has_value()) funcMap->emplace(fake.value(), rva);
if (isFunction) {
// MCVAPI
fake = pl::fake_symbol::getFakeSymbol(name, true);
if (fake.has_value()) funcMap->emplace(fake.value(), rva);
}
}
funcMap->emplace(std::move(name), rva);
}
Info("Loaded {} symbols", funcMap->size());
fflush(stdout);
}
void initReverseLookup() {
Info("Loading Reverse Lookup Table");
rvaMap = new Rva2SymbolMap(funcMap->size());
rvaMap = new Rva2SymbolMap();
for (auto& [sym, rva] : *funcMap) { (*rvaMap)[rva].push_back(&sym); }
}

namespace pl::symbol_provider {

void init() {
const wchar_t* const pdbPath = LR"(./bedrock_server.pdb)";
MemoryFile pdbFile = MemoryFile::Open(pdbPath);
if (!pdbFile.baseAddress) {
if (!pdbFile.baseAddress && !std::filesystem::exists(LR"(./bedrock_symbol_data)")) {
Error("bedrock_server.pdb not found");
return;
} else if (!pdbFile.baseAddress) {
std::ifstream fRead;
fRead.open(LR"(./bedrock_symbol_data)", std::ios_base::in | std::ios_base::binary);
if (!fRead.is_open()) {
Error("can't open bedrock_symbol_data");
return;
}
std::string data((std::istreambuf_iterator<char>(fRead)), {});
fRead.close();
initFunctionMap(data);
} else {
if (handleError(PDB::ValidateFile(pdbFile.baseAddress))) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::RawFile rawPdbFile = PDB::CreateRawFile(pdbFile.baseAddress);
if (handleError(PDB::HasValidDBIStream(rawPdbFile))) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::InfoStream infoStream(rawPdbFile);
if (infoStream.UsesDebugFastLink()) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::DBIStream dbiStream = PDB::CreateDBIStream(rawPdbFile);
if (!checkValidDBIStreams(rawPdbFile, dbiStream)) {
MemoryFile::Close(pdbFile);
return;
}
initFunctionMap(rawPdbFile, dbiStream);
}
if (handleError(PDB::ValidateFile(pdbFile.baseAddress))) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::RawFile rawPdbFile = PDB::CreateRawFile(pdbFile.baseAddress);
if (handleError(PDB::HasValidDBIStream(rawPdbFile))) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::InfoStream infoStream(rawPdbFile);
if (infoStream.UsesDebugFastLink()) {
MemoryFile::Close(pdbFile);
return;
}
const PDB::DBIStream dbiStream = PDB::CreateDBIStream(rawPdbFile);
if (!checkValidDBIStreams(rawPdbFile, dbiStream)) {
MemoryFile::Close(pdbFile);
return;
}
initFunctionMap(rawPdbFile, dbiStream);
initReverseLookup();
imageBaseAddr = (uintptr_t)GetModuleHandle(nullptr);
}
Expand Down Expand Up @@ -174,35 +226,43 @@ void* pl_resolve_symbol_silent_n(const char* symbolName, size_t size) {
return (void*)(imageBaseAddr + iter->second);
}

const char* const* pl_lookup_symbol(void* func, size_t* resultLength) {
template <typename C>
typename C::const_iterator find_key_less_equal(const C& c, const typename C::key_type& key) {
auto iter = c.upper_bound(key);
if (iter == c.cbegin()) return c.cend();
return --iter;
}

const char* const* pl_lookup_symbol_disp(void* func, size_t* resultLength, unsigned int* displacement) {
if (!rvaMap) {
if (resultLength) *resultLength = 0;
Error("pl_lookup_symbol called before init");
return nullptr;
}
auto funcAddr = reinterpret_cast<uintptr_t>(func);
auto it = rvaMap->find(static_cast<uint32_t>(funcAddr - imageBaseAddr));
if (it == rvaMap->end()) {
auto rva = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(func) - imageBaseAddr);
auto lastSymbol = find_key_less_equal(*rvaMap, rva);
if (lastSymbol == rvaMap->end()) {
if (resultLength) *resultLength = 0;
return nullptr;
}

auto result = new char*[it->second.size() + 1];
if (resultLength) *resultLength = it->second.size();

if (displacement) *displacement = rva - lastSymbol->first;
auto size = lastSymbol->second.size();
auto result = new char*[size + 1];
result[size] = nullptr; // nullptr terminated
if (resultLength) *resultLength = size;
size_t i = 0;
for (auto& sym : it->second) {
for (auto& sym : lastSymbol->second) {
result[i] = new char[sym->length() + 1];
std::copy(sym->begin(), sym->end(), result[i]);
result[i][sym->length()] = '\0';
}
result[it->second.size()] = nullptr; // nullptr terminated
return result;
}

const char* const* pl_lookup_symbol(void* func, size_t* resultLength) {
return pl_lookup_symbol_disp(func, resultLength, nullptr);
}
void pl_free_lookup_result(const char* const* result) {
for (int i = 0; result[i] != nullptr; i++) { delete[] result[i]; }
delete[] result;
}

} // namespace pl::symbol_provider
2 changes: 2 additions & 0 deletions src/pl/SymbolProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ PLCAPI void* pl_resolve_symbol_silent_n(const char* symbolName, size_t size);
*/
PLCAPI const char* const* pl_lookup_symbol(void* func, size_t* resultLength);

PLCAPI const char* const* pl_lookup_symbol_disp(void* func, size_t* resultLength, unsigned int* displacement);

/**
* @brief Free the result of pl_lookup_symbol.
*
Expand Down
3 changes: 2 additions & 1 deletion xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_requires("pe_bliss v1.0.0")

add_requires("detours v4.0.1-xmake.1")
add_requires("demangler v17.0.7")
add_requires("snappy 1.1.10")

target("PreLoader")
set_kind("shared")
Expand All @@ -25,4 +26,4 @@ target("PreLoader")
add_defines("PRELOADER_EXPORT", "UNICODE")
add_cxflags("/utf-8", "/EHa")
add_files("src/**.cpp")
add_packages("raw_pdb", "nlohmann_json", "parallel-hashmap", "demangler", "detours", "fmt", "pe_bliss")
add_packages("raw_pdb", "nlohmann_json", "parallel-hashmap", "demangler", "detours", "fmt", "pe_bliss", "snappy")

0 comments on commit 6df7337

Please sign in to comment.