Consolidate context dumping toggle into a single bool, begin work on data symbol context dumping

This commit is contained in:
Mr-Wiseguy 2024-06-23 14:24:11 -04:00
parent 16819a0515
commit 873219d4c5

View file

@ -672,7 +672,7 @@ std::unordered_set<std::string> renamed_funcs{
"_matherr", "_matherr",
}; };
bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols) { bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols, bool do_renaming) {
bool found_entrypoint_func = false; bool found_entrypoint_func = false;
ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section }; ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section };
fmt::print("Num symbols: {}\n", symbols.get_symbols_num()); fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
@ -732,13 +732,15 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
type = ELFIO::STT_FUNC; type = ELFIO::STT_FUNC;
} }
if (reimplemented_funcs.contains(name)) { if (do_renaming) {
reimplemented = true; if (reimplemented_funcs.contains(name)) {
name = name + "_recomp"; reimplemented = true;
ignored = true; name = name + "_recomp";
} else if (ignored_funcs.contains(name)) { ignored = true;
name = name + "_recomp"; } else if (ignored_funcs.contains(name)) {
ignored = true; name = name + "_recomp";
ignored = true;
}
} }
auto& section = context.sections[section_index]; auto& section = context.sections[section_index];
@ -746,9 +748,11 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
// Check if this symbol is a function or has no type (like a regular glabel would) // Check if this symbol is a function or has no type (like a regular glabel would)
// Symbols with no type have a dummy entry created so that their symbol can be looked up for function calls // Symbols with no type have a dummy entry created so that their symbol can be looked up for function calls
if (ignored || type == ELFIO::STT_FUNC || type == ELFIO::STT_NOTYPE || type == ELFIO::STT_OBJECT) { if (ignored || type == ELFIO::STT_FUNC || type == ELFIO::STT_NOTYPE || type == ELFIO::STT_OBJECT) {
if (renamed_funcs.contains(name)) { if (do_renaming) {
name = name + "_recomp"; if (renamed_funcs.contains(name)) {
ignored = false; name = name + "_recomp";
ignored = false;
}
} }
if (section_index < context.sections.size()) { if (section_index < context.sections.size()) {
@ -1258,48 +1262,61 @@ std::vector<std::string> reloc_names {
"R_MIPS_GPREL16", "R_MIPS_GPREL16",
}; };
void dump_context(const RecompPort::Context& context, const std::filesystem::path& path) { void dump_context(const RecompPort::Context& context, const std::filesystem::path& func_path, const std::filesystem::path& data_path) {
std::ofstream context_file {path}; std::ofstream func_context_file {func_path};
std::ofstream data_context_file {data_path};
fmt::print(func_context_file, "# Autogenerated from an ELF via N64Recomp\n");
fmt::print(data_context_file, "# Autogenerated from an ELF via N64Recomp\n");
auto print_section = [](std::ofstream& output_file, const std::string& name, uint64_t rom_addr, uint64_t ram_addr, uint64_t size) {
fmt::print(output_file,
"[[section]]\n"
"name = \"{}\"\n"
"rom = 0x{:08X}\n"
"vram = 0x{:08X}\n"
"size = 0x{:X}\n"
"\n",
name, rom_addr, ram_addr, size);
};
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) { for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
const RecompPort::Section& section = context.sections[section_index]; const RecompPort::Section& section = context.sections[section_index];
const std::vector<size_t>& section_funcs = context.section_functions[section_index]; const std::vector<size_t>& section_funcs = context.section_functions[section_index];
if (!section_funcs.empty()) { if (!section_funcs.empty()) {
fmt::print(context_file, print_section(func_context_file, section.name, section.rom_addr, section.ram_addr, section.size);
"# Autogenerated from an ELF via N64Recomp\n" print_section(data_context_file, section.name, section.rom_addr, section.ram_addr, section.size);
"[[section]]\n"
"name = \"{}\"\n"
"rom = 0x{:08X}\n"
"vram = 0x{:08X}\n"
"size = 0x{:X}\n"
"\n",
section.name, section.rom_addr, section.ram_addr, section.size);
// Dump relocs into the function context file.
if (!section.relocs.empty()) { if (!section.relocs.empty()) {
fmt::print(context_file, "relocs = [\n"); fmt::print(func_context_file, "relocs = [\n");
for (const RecompPort::Reloc& reloc : section.relocs) { for (const RecompPort::Reloc& reloc : section.relocs) {
if (reloc.target_section == section_index || reloc.target_section == section.bss_section_index) { if (reloc.target_section == section_index || reloc.target_section == section.bss_section_index) {
// TODO allow MIPS32 relocs for TLB mapping support. // TODO allow MIPS32 relocs for TLB mapping support.
if (reloc.type == RecompPort::RelocType::R_MIPS_HI16 || reloc.type == RecompPort::RelocType::R_MIPS_LO16) { if (reloc.type == RecompPort::RelocType::R_MIPS_HI16 || reloc.type == RecompPort::RelocType::R_MIPS_LO16) {
fmt::print(context_file, " {{ type = \"{}\", vram = 0x{:08X}, target_vram = 0x{:08X} }},\n", fmt::print(func_context_file, " {{ type = \"{}\", vram = 0x{:08X}, target_vram = 0x{:08X} }},\n",
reloc_names[static_cast<int>(reloc.type)], reloc.address, reloc.target_address); reloc_names[static_cast<int>(reloc.type)], reloc.address, reloc.target_address);
} }
} }
} }
fmt::print(context_file, "]\n\n"); fmt::print(func_context_file, "]\n\n");
} }
fmt::print(context_file, "functions = [\n"); // Dump functions into the function context file.
fmt::print(func_context_file, "functions = [\n");
for (const size_t& function_index : section_funcs) { for (const size_t& function_index : section_funcs) {
const RecompPort::Function& func = context.functions[function_index]; const RecompPort::Function& func = context.functions[function_index];
fmt::print(context_file, " {{ name = \"{}\", vram = 0x{:08X}, size = 0x{:X} }},\n", fmt::print(func_context_file, " {{ name = \"{}\", vram = 0x{:08X}, size = 0x{:X} }},\n",
func.name, func.vram, func.words.size() * sizeof(func.words[0])); func.name, func.vram, func.words.size() * sizeof(func.words[0]));
} }
fmt::print(context_file, "]\n\n"); // Dump variables into the data context file.
fmt::print(func_context_file, "]\n\n");
} }
} }
} }
@ -1326,6 +1343,9 @@ int main(int argc, char** argv) {
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
}; };
// TODO expose a way to dump the context from the command line.
bool dumping_context = false;
if (argc != 2) { if (argc != 2) {
fmt::print("Usage: {} [config file]\n", argv[0]); fmt::print("Usage: {} [config file]\n", argv[0]);
std::exit(EXIT_SUCCESS); std::exit(EXIT_SUCCESS);
@ -1397,7 +1417,7 @@ int main(int argc, char** argv) {
} }
// Read all of the symbols in the elf and look for the entrypoint function // Read all of the symbols in the elf and look for the entrypoint function
bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols); bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols, !dumping_context);
// Add any manual functions // Add any manual functions
add_manual_functions(context, elf_file, config.manual_functions); add_manual_functions(context, elf_file, config.manual_functions);
@ -1405,6 +1425,12 @@ int main(int argc, char** argv) {
if (config.has_entrypoint && !found_entrypoint_func) { if (config.has_entrypoint && !found_entrypoint_func) {
exit_failure("Could not find entrypoint function\n"); exit_failure("Could not find entrypoint function\n");
} }
if (dumping_context) {
fmt::print("Dumping context\n");
dump_context(context, "dump.toml", "data_dump.toml");
return 0;
}
} }
// Build a context from the provided symbols file. // Build a context from the provided symbols file.
else if (!config.symbols_file_path.empty()) { else if (!config.symbols_file_path.empty()) {
@ -1412,6 +1438,10 @@ int main(int argc, char** argv) {
exit_failure("A ROM file must be provided when using a symbols file\n"); exit_failure("A ROM file must be provided when using a symbols file\n");
} }
if (dumping_context) {
exit_failure("Cannot dump context when using a symbols file\n");
}
std::vector<uint8_t> rom = read_file(config.rom_file_path); std::vector<uint8_t> rom = read_file(config.rom_file_path);
if (rom.empty()) { if (rom.empty()) {
exit_failure("Failed to load ROM file: " + config.rom_file_path.string() + "\n"); exit_failure("Failed to load ROM file: " + config.rom_file_path.string() + "\n");
@ -1485,11 +1515,6 @@ int main(int argc, char** argv) {
std::vector<std::vector<uint32_t>> static_funcs_by_section{ context.sections.size() }; std::vector<std::vector<uint32_t>> static_funcs_by_section{ context.sections.size() };
// TODO expose a way to dump the context from the command line. Make sure not to rename functions when doing so.
//fmt::print("Dumping context\n");
//dump_context(context, "dump.toml");
//return 0;
fmt::print("Working dir: {}\n", std::filesystem::current_path().string()); fmt::print("Working dir: {}\n", std::filesystem::current_path().string());
// Stub out any functions specified in the config file. // Stub out any functions specified in the config file.