diff --git a/include/logger.hpp b/include/logger.hpp new file mode 100644 index 0000000..5523282 --- /dev/null +++ b/include/logger.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "paper/shared/logger.hpp" + +namespace flamingo { + +// Register file log in main.cpp +static constexpr auto Logger = Paper::ConstLoggerContext("Flamingo"); //Paper::Logger::WithContext<"Flamingo", false>(); + +} \ No newline at end of file diff --git a/qpm.json b/qpm.json index 662c8bc..4f188e6 100644 --- a/qpm.json +++ b/qpm.json @@ -18,7 +18,7 @@ }, { "id": "paper", - "versionRange": "^1.0.0", + "versionRange": "^1.2.1", "additionalData": {} }, { diff --git a/src/hook-installer.cpp b/src/hook-installer.cpp index 595406a..4bbdbd3 100644 --- a/src/hook-installer.cpp +++ b/src/hook-installer.cpp @@ -1,3 +1,4 @@ +#include "logger.hpp" #include "hook-installer.hpp" #include "enum-helpers.hpp" #include @@ -9,27 +10,31 @@ std::unordered_map> HookInstaller::adjacency_map; void HookInstaller::CreateAdjacencyMap() { // After we collected all hooks, create an adjacency map so we can do leapfrog hooks. // This is O(N^2) N being hooks that are small. + flamingo::Logger.fmtLog("Creating adjacency map!"); // Log begin - for (auto [target, hook] : collected_hooks) { + for (auto const& [target, hook] : collected_hooks) { if (hook.method_size < MinimumMethodSize) { // Oh no! We have a method that needs to be leapfrog hooked. // For now, we shall add an entry to the adjacency map. auto lst_pair = adjacency_map.insert({target, std::list()}); - for (auto [target2, hook2] : collected_hooks) { + for (auto const& [target2, hook2] : collected_hooks) { if (hook2.method_size > MinimumMethodSize + LeapfrogSize) { // Space for a POTENTIAL leapfrog hook // Need to make sure it's actually within an acceptable range, of course // Nested leapfrogs may also need to apply // Log additions here lst_pair.first->second.push_back(target2); + flamingo::Logger.fmtLog("Added adjacency {} for {}", fmt::ptr(lst_pair.first->first), fmt::ptr(target2)); } } } } + flamingo::Logger.fmtLog("Created adjacency_map for leap frog hooks!"); // Log completion } void HookInstaller::CollectHooks() { + flamingo::Logger.fmtLog("Beginning collection!"); // Beginning collection! for (auto& hook : HookData::hooks_to_install) { // For each hook, resolve target @@ -41,8 +46,11 @@ void HookInstaller::CollectHooks() { } // TODO: Consider if we need to add more metadata for hook installation smoothness? // Log what we are doing: + flamingo::Logger.fmtLog("Collecting hook at: {} target, with target method size: {} size, with signature: retSize(paramSizes...) {}, and metadata: {} metadata, with hook:{} ptr, trampoline: ptr", + fmt::ptr(target.target_method), target.method_size, (int) target.calling_convention, (int) hook.metadata.is_midpoint, fmt::ptr(hook.hook_ptr)); // Collecting hook at: target, with target method size: size, with signature: retSize(paramSizes...), and metadata: metadata, with hook: ptr, trampoline: ptr } + flamingo::Logger.fmtLog("Hook collection complete!"); // Collection of hooks complete! } @@ -50,6 +58,7 @@ void HookInstaller::InstallConventionalHook(HookTargetInstallation& toInstall) { #ifndef FLAMINGO_NO_REGISTRATION_CHECKS assert(toInstall.registration_status == HookTargetInstallation::RegistrationStatus::Ok); #endif + flamingo::Logger.fmtLog("Installing a conventional hook"); // The metadata for is_midpoint is actually not necessary here-- only whether we want an orig // If we do, we should allocate space for one. The space we allocate should be based off of two factors: // 1. The size of our hook in instructions @@ -69,6 +78,8 @@ void HookInstaller::InstallConventionalHook(HookTargetInstallation& toInstall) { targetHook.Finish(); // Flush icache to update hook __builtin___clear_cache(reinterpret_cast(toInstall.target), reinterpret_cast(toInstall.target) + hookSize); + + flamingo::Logger.fmtLog("Finalizing hook install"); // Log what we have done so far and also the rest of this for (auto revItr = toInstall.installation_info.rbegin(); revItr != toInstall.installation_info.rend();) { // hook_ptr is where we want to jump to FIRST. @@ -103,6 +114,7 @@ void HookInstaller::InstallHooks() { // We have a NONZERO quantity of hooks that need to be leapfrogged. // All hooks that are in the dst of this list need to be managed. // TODO: For now, simply say that we can't handle this circumstance. + flamingo::Logger.fmtLog("Unable to setup adjacency_map"); // Log this } #endif @@ -111,16 +123,24 @@ void HookInstaller::InstallHooks() { #ifndef FLAMINGO_NO_REGISTRATION_CHECKS if (hook.registration_status == HookTargetInstallation::RegistrationStatus::Ok) { // Installed OK! + flamingo::Logger.fmtLog("Installing hook {} to target {}", fmt::ptr(hook.target), fmt::ptr(target)); // Log what we are doing } else { + flamingo::Logger.fmtLog("Errors found!"); + if (flamingo::enum_helpers::HasFlag(hook.registration_status)) { // Log mismatch of target convention + flamingo::Logger.fmtLog("Mismatched target convention!"); } if (flamingo::enum_helpers::HasFlag(hook.registration_status)) { // Log mismatch of sizes + flamingo::Logger.fmtLog("Mismatched hook return size!"); } if (flamingo::enum_helpers::HasFlag(hook.registration_status)) { // Log mismatch of param sizes + flamingo::Logger.fmtLog("Mismatched hook parameter sizes!"); } + + flamingo::Logger.fmtLog("Continuing anyways!"); // Continue even after noting this. // Log this } @@ -131,9 +151,11 @@ void HookInstaller::InstallHooks() { // TODO: However, this should only be the case if we ALSO are not going to allocate space for a leapfrog destination. InstallConventionalHook(hook); } else { + flamingo::Logger.fmtLog("Leapfrog hook required, skipping install"); // TODO: Leapfrog install and determine validity // Log and skip this install } } + flamingo::Logger.fmtLog("All hooks were installed!"); // Log all hooks are installed! } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 71e827e..0a4dd2b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ // On dlopen, we should basically just construct our vectors and everything else // As well as our analytics data +#include "logger.hpp" #include "more_stuff.hpp" #include "hook-installer.hpp" // #include "hook-installer.hpp" @@ -17,7 +18,8 @@ namespace { template<> \ struct ErrorReporter { \ static void ReportError(Type value, HookTargetInstallation& existing, HookData& incoming) { \ - if ((static_cast(value) & static_cast(Type::Value)) != 0) { \ + if ((static_cast(value) & static_cast(Type::Value)) != 0) { \ + Paper::Logger::fmtLog("Error registering hook! Error: {}", msg); \ /* TODO: printf("Error registering hook! Error: " msg "\n"); */ \ } \ } \ @@ -46,6 +48,7 @@ void HookData::RegisterHook(HookData&& data) { } extern "C" void load() { + Paper::Logger::RegisterFileContextId(flamingo::Logger.tag); // Here's where we will INSTALL all of our hooks! HookInstaller::CollectHooks(); #ifndef FLAMINGO_NO_LEAPFROG diff --git a/src/trampoline-allocator.cpp b/src/trampoline-allocator.cpp index f2b6d70..8ecdced 100644 --- a/src/trampoline-allocator.cpp +++ b/src/trampoline-allocator.cpp @@ -1,7 +1,8 @@ +#include "logger.hpp" #include "trampoline-allocator.hpp" #include #include -#include +#include #include "beatsaber-hook/shared/utils/utils-functions.h" #ifdef ID @@ -24,6 +25,7 @@ void Trampoline::Write(uint32_t instruction) { assert((instruction_count + 1) * sizeof(uint32_t) <= alloc_size); + flamingo::Logger.fmtLog("Trampoline writing instruction {} count {} instruction {}", fmt::ptr(address), instruction_count, instruction); // Log what we are writing (and also our state) *(address + instruction_count) = instruction; instruction_count++; @@ -32,6 +34,8 @@ void Trampoline::Write(uint32_t instruction) { void Trampoline::Write(void const* ptr) { assert(instruction_count * sizeof(uint32_t) + sizeof(void*) <= alloc_size); // Log what we are writing (and also our state) + flamingo::Logger.fmtLog("Trampoline writing pointer instruction {} count {} ptr {}", fmt::ptr(address), instruction_count, fmt::ptr(ptr)); + *reinterpret_cast(address + instruction_count) = const_cast(ptr); instruction_count += sizeof(void*) / sizeof(uint32_t); } @@ -333,11 +337,13 @@ Trampoline TrampolineAllocator::Allocate(std::size_t trampolineSize) { void* ptr; if (!::posix_memalign(&ptr, PageSize, PageSize)) { // Log error on memalign allocation! + flamingo::Logger.fmtLog("Failed to allocate trampoline page of size: {} for size: {}", PageSize, trampolineSize); SAFE_ABORT_MSG("Failed to allocate trampoline page of size: %zu for size: %zu", PageSize, trampolineSize); } // Mark full page as rxw if (!::mprotect(ptr, PageSize, PROT_READ | PROT_WRITE | PROT_EXEC)) { // Log error on mprotect! + flamingo::Logger.fmtLog("Failed to mark allocated page at: {} as +rwx!", fmt::ptr(ptr)); SAFE_ABORT_MSG("Failed to mark allocated page at: %p as +rwx!", ptr); } auto& page = pages.emplace_back(ptr, trampolineSize); @@ -358,6 +364,7 @@ void TrampolineAllocator::Free(Trampoline const& toFree) { if (p.trampoline_count == 0) { if (!::mprotect(p.ptr, PageSize, PROT_READ)) { // Log error on mprotect + flamingo::Logger.fmtLog("Failed to mark page at: {} as read only!", fmt::ptr(p.ptr)); SAFE_ABORT_MSG("Failed to mark page at: %p as read only!", p.ptr); } ::free(p.ptr);