mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 18:22:33 +01:00
aarch64: Support calloc patch blocks
This commit is contained in:
parent
4d193ecb6a
commit
c80342e8d4
@ -1,7 +1,9 @@
|
|||||||
#include "bin_patch.h"
|
#include "bin_patch.h"
|
||||||
|
#include "ppu_patch.h"
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "Emu/IdManager.h"
|
||||||
#include "Emu/Memory/vm.h"
|
#include "Emu/Memory/vm.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/VFS.h"
|
#include "Emu/VFS.h"
|
||||||
@ -896,10 +898,6 @@ void patch_engine::append_title_patches(std::string_view title_id)
|
|||||||
load(m_map, fmt::format("%s%s_patch.yml", get_patches_path(), title_id));
|
load(m_map, fmt::format("%s%s_patch.yml", get_patches_path(), title_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppu_register_range(u32 addr, u32 size);
|
|
||||||
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
|
|
||||||
u32 ppu_generate_id(std::string_view name);
|
|
||||||
|
|
||||||
void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
|
void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
|
||||||
{
|
{
|
||||||
if (ptr && ptr->flags & (1ull << 62))
|
if (ptr && ptr->flags & (1ull << 62))
|
||||||
@ -1216,6 +1214,10 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record the insertion point as a faux block.
|
||||||
|
g_fxo->need<ppu_patch_block_registry_t>();
|
||||||
|
g_fxo->get<ppu_patch_block_registry_t>().block_addresses.insert(resval);
|
||||||
|
|
||||||
relocate_instructions_at = addr;
|
relocate_instructions_at = addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
20
Utilities/ppu_patch.h
Normal file
20
Utilities/ppu_patch.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <util/types.hpp>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Patch utilities specific to PPU code
|
||||||
|
struct ppu_patch_block_registry_t
|
||||||
|
{
|
||||||
|
ppu_patch_block_registry_t() = default;
|
||||||
|
ppu_patch_block_registry_t(const ppu_patch_block_registry_t&) = delete;
|
||||||
|
ppu_patch_block_registry_t& operator=(const ppu_patch_block_registry_t&) = delete;
|
||||||
|
|
||||||
|
std::unordered_set<u32> block_addresses{};
|
||||||
|
};
|
||||||
|
|
||||||
|
void ppu_register_range(u32 addr, u32 size);
|
||||||
|
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
|
||||||
|
u32 ppu_generate_id(std::string_view name);
|
@ -1,6 +1,5 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
|
||||||
#include "AArch64JIT.h"
|
#include "AArch64JIT.h"
|
||||||
#include "AArch64ASM.h"
|
#include "AArch64ASM.h"
|
||||||
|
|
||||||
@ -415,9 +414,9 @@ namespace aarch64
|
|||||||
ensure(llvm::isa<llvm::ReturnInst>(where));
|
ensure(llvm::isa<llvm::ReturnInst>(where));
|
||||||
irb->SetInsertPoint(llvm::dyn_cast<llvm::Instruction>(where));
|
irb->SetInsertPoint(llvm::dyn_cast<llvm::Instruction>(where));
|
||||||
|
|
||||||
if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return
|
if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return
|
||||||
!instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not
|
!instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not
|
||||||
instruction_info.callee_name.find("-pp-") == umax) // Skip branch patch-points as those are just indirect calls. TODO: Move this to instruction decode.
|
!is_faux_function(instruction_info.callee_name)) // Ignore branch patch-points and imposter functions. Their behavior is unreliable.
|
||||||
{
|
{
|
||||||
// We're making a one-way call. This branch shouldn't even bother linking as it will never return here.
|
// We're making a one-way call. This branch shouldn't even bother linking as it will never return here.
|
||||||
ASMBlock c;
|
ASMBlock c;
|
||||||
@ -487,6 +486,24 @@ namespace aarch64
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GHC_frame_preservation_pass::is_faux_function(const std::string& function_name)
|
||||||
|
{
|
||||||
|
// Is it a branch patch-point?
|
||||||
|
if (function_name.find("-pp-") != umax)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we search the known imposters list
|
||||||
|
if (m_config.faux_function_list.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& x = m_config.faux_function_list;
|
||||||
|
return std::find(x.begin(), x.end(), function_name) != x.end();
|
||||||
|
}
|
||||||
|
|
||||||
void GHC_frame_preservation_pass::process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f)
|
void GHC_frame_preservation_pass::process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f)
|
||||||
{
|
{
|
||||||
for (auto &bb : f)
|
for (auto &bb : f)
|
||||||
|
@ -41,12 +41,13 @@ namespace aarch64
|
|||||||
|
|
||||||
struct config_t
|
struct config_t
|
||||||
{
|
{
|
||||||
bool debug_info = false; // Record debug information
|
bool debug_info = false; // Record debug information
|
||||||
bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch.
|
bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch.
|
||||||
bool optimize = true; // Optimize instructions when possible. Set to false when debugging.
|
bool optimize = true; // Optimize instructions when possible. Set to false when debugging.
|
||||||
u32 hypervisor_context_offset = 0; // Offset within the "thread" object where we can find the hypervisor context (registers configured at gateway).
|
u32 hypervisor_context_offset = 0; // Offset within the "thread" object where we can find the hypervisor context (registers configured at gateway).
|
||||||
std::function<bool(const std::string&)> exclusion_callback; // [Optional] Callback run on each function before transform. Return "true" to exclude from frame processing.
|
std::function<bool(const std::string&)> exclusion_callback; // [Optional] Callback run on each function before transform. Return "true" to exclude from frame processing.
|
||||||
std::vector<std::pair<std::string, gpr>> base_register_lookup; // [Optional] Function lookup table to determine the location of the "thread" context.
|
std::vector<std::pair<std::string, gpr>> base_register_lookup; // [Optional] Function lookup table to determine the location of the "thread" context.
|
||||||
|
std::vector<std::string> faux_function_list; // [Optional] List of faux block names to treat as untrusted - typically fake functions representing codecaves.
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -64,6 +65,8 @@ namespace aarch64
|
|||||||
|
|
||||||
bool is_inlined_call(const llvm::CallInst* ci);
|
bool is_inlined_call(const llvm::CallInst* ci);
|
||||||
|
|
||||||
|
bool is_faux_function(const std::string& function_name);
|
||||||
|
|
||||||
gpr get_base_register_for_call(const std::string& callee_name, gpr default_reg = gpr::x19);
|
gpr get_base_register_for_call(const std::string& callee_name, gpr default_reg = gpr::x19);
|
||||||
|
|
||||||
void process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f);
|
void process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f);
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#ifdef ARCH_ARM64
|
#ifdef ARCH_ARM64
|
||||||
#include "Emu/CPU/Backends/AArch64/AArch64JIT.h"
|
#include "Emu/CPU/Backends/AArch64/AArch64JIT.h"
|
||||||
|
#include "Emu/IdManager.h"
|
||||||
|
#include "Utilities/ppu_patch.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
@ -48,13 +50,22 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_mo
|
|||||||
{ "__", aarch64::x19 } // Probably link table entries
|
{ "__", aarch64::x19 } // Probably link table entries
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Build list of imposter functions built by the patch manager.
|
||||||
|
g_fxo->need<ppu_patch_block_registry_t>();
|
||||||
|
std::vector<std::string> faux_functions_list;
|
||||||
|
for (const auto& a : g_fxo->get<ppu_patch_block_registry_t>().block_addresses)
|
||||||
|
{
|
||||||
|
faux_functions_list.push_back(fmt::format("__0x%x", a));
|
||||||
|
}
|
||||||
|
|
||||||
aarch64::GHC_frame_preservation_pass::config_t config =
|
aarch64::GHC_frame_preservation_pass::config_t config =
|
||||||
{
|
{
|
||||||
.debug_info = false, // Set to "true" to insert debug frames on x27
|
.debug_info = false, // Set to "true" to insert debug frames on x27
|
||||||
.use_stack_frames = false, // We don't need this since the PPU GW allocates global scratch on the stack
|
.use_stack_frames = false, // We don't need this since the PPU GW allocates global scratch on the stack
|
||||||
.hypervisor_context_offset = ::offset32(&ppu_thread::hv_ctx),
|
.hypervisor_context_offset = ::offset32(&ppu_thread::hv_ctx),
|
||||||
.exclusion_callback = {}, // Unused, we don't have special exclusion functions on PPU
|
.exclusion_callback = {}, // Unused, we don't have special exclusion functions on PPU
|
||||||
.base_register_lookup = base_reg_lookup
|
.base_register_lookup = base_reg_lookup,
|
||||||
|
.faux_function_list = std::move(faux_functions_list)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create transform pass
|
// Create transform pass
|
||||||
|
Loading…
Reference in New Issue
Block a user