From 6df73372fb972e1015a81a8fc04702a407c48f67 Mon Sep 17 00:00:00 2001 From: OEOTYAN Date: Fri, 28 Jun 2024 03:31:14 +0800 Subject: [PATCH] feat: add new symbol data format reader --- src/pl/SymbolProvider.cpp | 146 +++++++++++++++++++++++++++----------- src/pl/SymbolProvider.h | 2 + xmake.lua | 3 +- 3 files changed, 107 insertions(+), 44 deletions(-) diff --git a/src/pl/SymbolProvider.cpp b/src/pl/SymbolProvider.cpp index 4f4fee5..734d8b0 100644 --- a/src/pl/SymbolProvider.cpp +++ b/src/pl/SymbolProvider.cpp @@ -7,6 +7,7 @@ #include #include +#include "parallel_hashmap/btree.h" #include "parallel_hashmap/phmap.h" #include "PDB.h" @@ -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" @@ -38,20 +41,20 @@ static uintptr_t imageBaseAddr; // phmap hash maps is thread-safe when reading using Symbol2RvaMap = phmap::flat_hash_map; -using Rva2SymbolMap = phmap::flat_hash_map>; +using Rva2SymbolMap = phmap::btree_map>; 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 modules = moduleInfoStream.GetModules(); - const ArrayView publicSymbolRecord = publicSymbolStream.GetRecords(); + ArrayView const modules = moduleInfoStream.GetModules(); + ArrayView const publicSymbolRecord = publicSymbolStream.GetRecords(); // pre alloc hash buckets, 1.2x for public symbols funcMap = new Symbol2RvaMap((size_t)((double)publicSymbolRecord.GetLength() * 1.2)); @@ -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(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); } @@ -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::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(func); - auto it = rvaMap->find(static_cast(funcAddr - imageBaseAddr)); - if (it == rvaMap->end()) { + auto rva = static_cast(reinterpret_cast(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 diff --git a/src/pl/SymbolProvider.h b/src/pl/SymbolProvider.h index c11f8d1..5b0334f 100644 --- a/src/pl/SymbolProvider.h +++ b/src/pl/SymbolProvider.h @@ -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. * diff --git a/xmake.lua b/xmake.lua index 6a40771..af9e9b3 100644 --- a/xmake.lua +++ b/xmake.lua @@ -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") @@ -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")