Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/logger.hpp
Original file line number Diff line number Diff line change
@@ -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>();

}
2 changes: 1 addition & 1 deletion qpm.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
{
"id": "paper",
"versionRange": "^1.0.0",
"versionRange": "^1.2.1",
"additionalData": {}
},
{
Expand Down
26 changes: 24 additions & 2 deletions src/hook-installer.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "logger.hpp"
#include "hook-installer.hpp"
#include "enum-helpers.hpp"
#include <cassert>
Expand All @@ -9,27 +10,31 @@ std::unordered_map<void*, std::list<void*>> 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<Paper::LogLevel::INF>("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<void*>()});
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<Paper::LogLevel::INF>("Added adjacency {} for {}", fmt::ptr(lst_pair.first->first), fmt::ptr(target2));
}
}
}
}
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("Created adjacency_map for leap frog hooks!");
// Log completion
}

void HookInstaller::CollectHooks() {
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("Beginning collection!");
// Beginning collection!
for (auto& hook : HookData::hooks_to_install) {
// For each hook, resolve target
Expand All @@ -41,15 +46,19 @@ void HookInstaller::CollectHooks() {
}
// TODO: Consider if we need to add more metadata for hook installation smoothness?
// Log what we are doing:
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("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<Paper::LogLevel::INF>("Hook collection complete!");
// Collection of hooks complete!
}

void HookInstaller::InstallConventionalHook(HookTargetInstallation& toInstall) {
#ifndef FLAMINGO_NO_REGISTRATION_CHECKS
assert(toInstall.registration_status == HookTargetInstallation::RegistrationStatus::Ok);
#endif
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("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
Expand All @@ -69,6 +78,8 @@ void HookInstaller::InstallConventionalHook(HookTargetInstallation& toInstall) {
targetHook.Finish();
// Flush icache to update hook
__builtin___clear_cache(reinterpret_cast<char*>(toInstall.target), reinterpret_cast<char*>(toInstall.target) + hookSize);

flamingo::Logger.fmtLog<Paper::LogLevel::INF>("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.
Expand Down Expand Up @@ -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<Paper::LogLevel::ERR>("Unable to setup adjacency_map");
// Log this
}
#endif
Expand All @@ -111,16 +123,24 @@ void HookInstaller::InstallHooks() {
#ifndef FLAMINGO_NO_REGISTRATION_CHECKS
if (hook.registration_status == HookTargetInstallation::RegistrationStatus::Ok) {
// Installed OK!
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("Installing hook {} to target {}", fmt::ptr(hook.target), fmt::ptr(target));
// Log what we are doing
}
else {
flamingo::Logger.fmtLog<Paper::LogLevel::ERR>("Errors found!");

if (flamingo::enum_helpers::HasFlag<HookTargetInstallation::RegistrationStatus::MismatchTargetConv>(hook.registration_status)) {
// Log mismatch of target convention
flamingo::Logger.fmtLog<Paper::LogLevel::ERR>("Mismatched target convention!");
} if (flamingo::enum_helpers::HasFlag<HookTargetInstallation::RegistrationStatus::MismatchReturnSize>(hook.registration_status)) {
// Log mismatch of sizes
flamingo::Logger.fmtLog<Paper::LogLevel::ERR>("Mismatched hook return size!");
} if (flamingo::enum_helpers::HasFlag<HookTargetInstallation::RegistrationStatus::MismatchTargetParamSizes>(hook.registration_status)) {
// Log mismatch of param sizes
flamingo::Logger.fmtLog<Paper::LogLevel::ERR>("Mismatched hook parameter sizes!");
}

flamingo::Logger.fmtLog<Paper::LogLevel::ERR>("Continuing anyways!");
// Continue even after noting this.
// Log this
}
Expand All @@ -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<Paper::LogLevel::INF>("Leapfrog hook required, skipping install");
// TODO: Leapfrog install and determine validity
// Log and skip this install
}
}
flamingo::Logger.fmtLog<Paper::LogLevel::INF>("All hooks were installed!");
// Log all hooks are installed!
}
5 changes: 4 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -17,7 +18,8 @@ namespace {
template<> \
struct ErrorReporter<Type, Type::Value> { \
static void ReportError(Type value, HookTargetInstallation& existing, HookData& incoming) { \
if ((static_cast<int>(value) & static_cast<int>(Type::Value)) != 0) { \
if ((static_cast<int>(value) & static_cast<int>(Type::Value)) != 0) { \
Paper::Logger::fmtLog<Paper::LogLevel::ERR>("Error registering hook! Error: {}", msg); \
/* TODO: printf("Error registering hook! Error: " msg "\n"); */ \
} \
} \
Expand Down Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion src/trampoline-allocator.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include "logger.hpp"
#include "trampoline-allocator.hpp"
#include <list>
#include <sys/mman.h>
#include <stdlib.h>
#include <cstdlib>
#include "beatsaber-hook/shared/utils/utils-functions.h"

#ifdef ID
Expand All @@ -24,6 +25,7 @@

void Trampoline::Write(uint32_t instruction) {
assert((instruction_count + 1) * sizeof(uint32_t) <= alloc_size);
flamingo::Logger.fmtLog<Paper::LogLevel::DBG>("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++;
Expand All @@ -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<Paper::LogLevel::DBG>("Trampoline writing pointer instruction {} count {} ptr {}", fmt::ptr(address), instruction_count, fmt::ptr(ptr));

*reinterpret_cast<void**>(address + instruction_count) = const_cast<void*>(ptr);
instruction_count += sizeof(void*) / sizeof(uint32_t);
}
Expand Down Expand Up @@ -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<Paper::LogLevel::INF>("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<Paper::LogLevel::INF>("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);
Expand All @@ -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<Paper::LogLevel::INF>("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);
Expand Down