Implement nrm filename toml input, renaming list, trace mode, and context dumping flag (#111)

* implement nrm filename toml input

* change name of mod toml setting to 'mod_filename'

* add renaming and re mode

* fix --dump-context arg, fix entrypoint detection

* refactor re_mode to function_trace_mode

* adjust trace mode to use a general TRACE_ENTRY() macro

* fix some renaming and trace mode comments, revert no toml entrypoint code, add TODO to broken block

* fix arg2 check and usage string
This commit is contained in:
LittleCube 2024-12-24 02:10:26 -05:00 committed by GitHub
parent d33d381617
commit 17438755a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 95 additions and 12 deletions

View file

@ -93,7 +93,7 @@ std::vector<std::string> get_ignored_funcs(const toml::table* patches_data) {
// Make room for all the ignored funcs in the array.
ignored_funcs.reserve(ignored_funcs_array->size());
// Gather the stubs and place them into the array.
// Gather the ignored and place them into the array.
ignored_funcs_array->for_each([&ignored_funcs](auto&& el) {
if constexpr (toml::is_string<decltype(el)>) {
ignored_funcs.push_back(*el);
@ -104,6 +104,29 @@ std::vector<std::string> get_ignored_funcs(const toml::table* patches_data) {
return ignored_funcs;
}
std::vector<std::string> get_renamed_funcs(const toml::table* patches_data) {
std::vector<std::string> renamed_funcs{};
// Check if the renamed funcs array exists.
const toml::node_view renamed_funcs_data = (*patches_data)["renamed"];
if (renamed_funcs_data.is_array()) {
const toml::array* renamed_funcs_array = renamed_funcs_data.as_array();
// Make room for all the renamed funcs in the array.
renamed_funcs.reserve(renamed_funcs_array->size());
// Gather the renamed and place them into the array.
renamed_funcs_array->for_each([&renamed_funcs](auto&& el) {
if constexpr (toml::is_string<decltype(el)>) {
renamed_funcs.push_back(*el);
}
});
}
return renamed_funcs;
}
std::vector<N64Recomp::FunctionSize> get_func_sizes(const toml::table* patches_data) {
std::vector<N64Recomp::FunctionSize> func_sizes{};
@ -377,6 +400,9 @@ N64Recomp::Config::Config(const char* path) {
// Ignored funcs array (optional)
ignored_funcs = get_ignored_funcs(table);
// Renamed funcs array (optional)
renamed_funcs = get_renamed_funcs(table);
// Single-instruction patches (optional)
instruction_patches = get_instruction_patches(table);
@ -387,6 +413,18 @@ N64Recomp::Config::Config(const char* path) {
function_hooks = get_function_hooks(table);
}
// Use trace mode if enabled (optional)
std::optional<bool> trace_mode_opt = input_data["trace_mode"].value<bool>();
if (trace_mode_opt.has_value()) {
trace_mode = trace_mode_opt.value();
if (trace_mode) {
recomp_include += "\n#include \"trace.h\"";
}
}
else {
trace_mode = false;
}
// Function reference symbols file (optional)
std::optional<std::string> func_reference_syms_file_opt = input_data["func_reference_syms_file"].value<std::string>();
if (func_reference_syms_file_opt.has_value()) {

View file

@ -42,6 +42,7 @@ namespace N64Recomp {
bool single_file_output;
bool use_absolute_symbols;
bool unpaired_lo16_warnings;
bool trace_mode;
bool allow_exports;
bool strict_patch_mode;
std::filesystem::path elf_path;
@ -54,6 +55,7 @@ namespace N64Recomp {
std::filesystem::path output_binary_path;
std::vector<std::string> stubbed_funcs;
std::vector<std::string> ignored_funcs;
std::vector<std::string> renamed_funcs;
std::vector<InstructionPatch> instruction_patches;
std::vector<FunctionHook> function_hooks;
std::vector<FunctionSize> manual_func_sizes;

View file

@ -58,8 +58,9 @@ bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELF
continue;
}
if (section_index < context.sections.size()) {
if (section_index < context.sections.size()) {
// Check if this symbol is the entrypoint
// TODO this never fires, the check is broken due to signedness
if (elf_config.has_entrypoint && value == elf_config.entrypoint_address && type == ELFIO::STT_FUNC) {
if (found_entrypoint_func) {
fmt::print(stderr, "Ambiguous entrypoint: {}\n", name);

View file

@ -272,12 +272,18 @@ int main(int argc, char** argv) {
std::exit(EXIT_FAILURE);
};
// TODO expose a way to dump the context from the command line.
bool dumping_context = false;
bool dumping_context;
if (argc != 2) {
fmt::print("Usage: {} [config file]\n", argv[0]);
std::exit(EXIT_SUCCESS);
if (argc >= 3) {
std::string arg2 = argv[2];
if (arg2 == "--dump-context") {
dumping_context = true;
} else {
fmt::print("Usage: {} <config file> [--dump-context]\n", argv[0]);
std::exit(EXIT_SUCCESS);
}
} else {
dumping_context = false;
}
const char* config_path = argv[1];
@ -485,10 +491,27 @@ int main(int argc, char** argv) {
// This helps prevent typos in the config file or functions renamed between versions from causing issues.
exit_failure(fmt::format("Function {} is set as ignored in the config file but does not exist!", ignored_func));
}
// Mark the function as .
// Mark the function as ignored.
context.functions[func_find->second].ignored = true;
}
// Rename any functions specified in the config file.
for (const std::string& renamed_func : config.renamed_funcs) {
// Check if the specified function exists.
auto func_find = context.functions_by_name.find(renamed_func);
if (func_find == context.functions_by_name.end()) {
// Function doesn't exist, present an error to the user instead of silently failing to rename it.
// This helps prevent typos in the config file or functions renamed between versions from causing issues.
exit_failure(fmt::format("Function {} is set as renamed in the config file but does not exist!", renamed_func));
}
// Rename the function.
N64Recomp::Function* func = &context.functions[func_find->second];
func->name = func->name + "_recomp";
}
// Propogate the trace mode parameter.
context.trace_mode = config.trace_mode;
// Apply any single-instruction patches.
for (const N64Recomp::InstructionPatch& patch : config.instruction_patches) {
// Check if the specified function exists.

View file

@ -745,6 +745,12 @@ bool N64Recomp::recompile_function(const N64Recomp::Context& context, const N64R
" int c1cs = 0;\n", // cop1 conditional signal
func.name);
if (context.trace_mode) {
fmt::print(output_file,
" TRACE_ENTRY();",
func.name);
}
// Skip analysis and recompilation of this function is stubbed.
if (!func.stubbed) {
// Use a set to sort and deduplicate labels

View file

@ -1,6 +1,6 @@
#include "n64recomp.h"
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs{
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs {
// OS initialize functions
"__osInitialize_common",
"osInitialize",
@ -557,7 +557,7 @@ const std::unordered_set<std::string> N64Recomp::ignored_funcs {
"kdebugserver",
};
const std::unordered_set<std::string> N64Recomp::renamed_funcs{
const std::unordered_set<std::string> N64Recomp::renamed_funcs {
// Math
"sincosf",
"sinf",