diff --git a/decompiler/Function/TypeInspector.cpp b/decompiler/Function/TypeInspector.cpp index 34c3c255ca..6e8c6ef7fe 100644 --- a/decompiler/Function/TypeInspector.cpp +++ b/decompiler/Function/TypeInspector.cpp @@ -727,7 +727,8 @@ int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorRes TypeInspectorResult inspect_inspect_method(Function& inspect, const std::string& type_name, DecompilerTypeSystem& dts, - LinkedObjectFile& file) { + LinkedObjectFile& file, + bool skip_fields) { TypeInspectorResult result; TypeFlags flags; flags.flag = 0; @@ -740,9 +741,8 @@ TypeInspectorResult inspect_inspect_method(Function& inspect, result.type_heap_base = flags.heap_base; assert(flags.pad == 0); - auto& bad_set = get_config().bad_inspect_types; int idx = get_start_idx(inspect, file, &result, result.parent_type_name); - if (idx == 0 || bad_set.find(type_name) != bad_set.end()) { + if (idx == 0 || skip_fields) { // printf("was weird: %s\n", result.warnings.c_str()); return result; } diff --git a/decompiler/Function/TypeInspector.h b/decompiler/Function/TypeInspector.h index a11315964e..cb3bd3c855 100644 --- a/decompiler/Function/TypeInspector.h +++ b/decompiler/Function/TypeInspector.h @@ -35,5 +35,6 @@ struct TypeInspectorResult { TypeInspectorResult inspect_inspect_method(Function& inspect, const std::string& type_name, DecompilerTypeSystem& dts, - LinkedObjectFile& file); + LinkedObjectFile& file, + bool skip_fields); } // namespace decompiler \ No newline at end of file diff --git a/decompiler/ObjectFile/LinkedObjectFile.cpp b/decompiler/ObjectFile/LinkedObjectFile.cpp index 3013d4d981..649a712503 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.cpp +++ b/decompiler/ObjectFile/LinkedObjectFile.cpp @@ -680,8 +680,7 @@ std::string LinkedObjectFile::print_asm_function_disassembly(const std::string& /*! * Print disassembled functions and data segments. */ -std::string LinkedObjectFile::print_disassembly() { - bool write_hex = get_config().write_hex_near_instructions; +std::string LinkedObjectFile::print_disassembly(bool write_hex) { std::string result; assert(segments <= 3); diff --git a/decompiler/ObjectFile/LinkedObjectFile.h b/decompiler/ObjectFile/LinkedObjectFile.h index 9b574cc124..51e9f7a5e0 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.h +++ b/decompiler/ObjectFile/LinkedObjectFile.h @@ -51,7 +51,7 @@ class LinkedObjectFile { void disassemble_functions(); void process_fp_relative_links(); std::string print_scripts(); - std::string print_disassembly(); + std::string print_disassembly(bool write_hex); bool has_any_functions(); void append_word_to_string(std::string& dest, const LinkedWord& word) const; std::string print_function_disassembly(Function& func, diff --git a/decompiler/ObjectFile/LinkedObjectFileCreation.cpp b/decompiler/ObjectFile/LinkedObjectFileCreation.cpp index dcb83716ef..740d0b1a89 100644 --- a/decompiler/ObjectFile/LinkedObjectFileCreation.cpp +++ b/decompiler/ObjectFile/LinkedObjectFileCreation.cpp @@ -609,7 +609,8 @@ static void link_v5(LinkedObjectFile& f, static void link_v3(LinkedObjectFile& f, const std::vector& data, const std::string& name, - DecompilerTypeSystem& dts) { + DecompilerTypeSystem& dts, + int game_version) { auto header = (const LinkHeaderV3*)(&data.at(0)); assert(name == header->name); assert(header->segments == 3); @@ -656,11 +657,11 @@ static void link_v3(LinkedObjectFile& f, // HACK! // why is this a thing? // HACK! - if (get_config().game_version == 1 && name == "level-h" && seg_id == 0) { + if (game_version == 1 && name == "level-h" && seg_id == 0) { segment_size++; } - if (get_config().game_version == 2) { + if (game_version == 2) { bool adjusted = false; while (segment_size % 4) { segment_size++; @@ -800,14 +801,15 @@ static void link_v3(LinkedObjectFile& f, */ LinkedObjectFile to_linked_object_file(const std::vector& data, const std::string& name, - DecompilerTypeSystem& dts) { + DecompilerTypeSystem& dts, + int game_version) { LinkedObjectFile result; const auto* header = (const LinkHeaderCommon*)&data.at(0); // use appropriate linker if (header->version == 3) { assert(header->type_tag == 0); - link_v3(result, data, name, dts); + link_v3(result, data, name, dts, game_version); } else if (header->version == 4 || header->version == 2) { assert(header->type_tag == 0xffffffff); link_v2_or_v4(result, data, name, dts); diff --git a/decompiler/ObjectFile/LinkedObjectFileCreation.h b/decompiler/ObjectFile/LinkedObjectFileCreation.h index c304aa0b0d..a165c51714 100644 --- a/decompiler/ObjectFile/LinkedObjectFileCreation.h +++ b/decompiler/ObjectFile/LinkedObjectFileCreation.h @@ -6,16 +6,12 @@ * This implements a decoder for the GOAL linking format. */ -#ifndef NEXT_LINKEDOBJECTFILECREATION_H -#define NEXT_LINKEDOBJECTFILECREATION_H - #include "LinkedObjectFile.h" namespace decompiler { class DecompilerTypeSystem; LinkedObjectFile to_linked_object_file(const std::vector& data, const std::string& name, - DecompilerTypeSystem& dts); + DecompilerTypeSystem& dts, + int game_version); } // namespace decompiler - -#endif // NEXT_LINKEDOBJECTFILECREATION_H diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index f74ee7bf7d..98e55a51a6 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -110,7 +110,8 @@ ObjectFileData& ObjectFileDB::lookup_record(const ObjectFileRecord& rec) { ObjectFileDB::ObjectFileDB(const std::vector& _dgos, const std::string& obj_file_name_map_file, const std::vector& object_files, - const std::vector& str_files) { + const std::vector& str_files, + const Config& config) { Timer timer; lg::info("-Loading types..."); @@ -128,14 +129,14 @@ ObjectFileDB::ObjectFileDB(const std::vector& _dgos, lg::info("-Loading {} DGOs...", _dgos.size()); for (auto& dgo : _dgos) { - get_objs_from_dgo(dgo); + get_objs_from_dgo(dgo, config); } lg::info("-Loading {} plain object files...", object_files.size()); for (auto& obj : object_files) { auto data = file_util::read_binary_file(obj); auto name = obj_filename_to_name(obj); - add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO"); + add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO", config); } lg::info("-Loading {} streaming object files...", str_files.size()); @@ -149,7 +150,7 @@ ObjectFileDB::ObjectFileDB(const std::vector& _dgos, // append the chunk ID to the full name std::string name = obj_name + fmt::format("+{}", i); auto& data = reader.get_chunk(i); - add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO"); + add_obj_from_dgo(name, name, data.data(), data.size(), "NO-XGO", config); } } @@ -190,7 +191,7 @@ constexpr int MAX_CHUNK_SIZE = 0x8000; /*! * Load the objects stored in the given DGO into the ObjectFileDB */ -void ObjectFileDB::get_objs_from_dgo(const std::string& filename) { +void ObjectFileDB::get_objs_from_dgo(const std::string& filename, const Config& config) { auto dgo_data = file_util::read_binary_file(filename); stats.total_dgo_bytes += dgo_data.size(); @@ -221,7 +222,8 @@ void ObjectFileDB::get_objs_from_dgo(const std::string& filename) { auto name = get_object_file_name(obj_header.name, reader.here(), obj_header.object_count); - add_obj_from_dgo(name, obj_header.name, reader.here(), obj_header.object_count, dgo_base_name); + add_obj_from_dgo(name, obj_header.name, reader.here(), obj_header.object_count, dgo_base_name, + config); reader.ffwd(obj_header.object_count); } @@ -236,8 +238,8 @@ void ObjectFileDB::add_obj_from_dgo(const std::string& obj_name, const std::string& name_in_dgo, const uint8_t* obj_data, uint32_t obj_size, - const std::string& dgo_name) { - const auto& config = get_config(); + const std::string& dgo_name, + const Config& config) { if (!config.allowed_objects.empty()) { if (config.allowed_objects.find(obj_name) == config.allowed_objects.end()) { return; @@ -390,14 +392,14 @@ std::string ObjectFileDB::generate_obj_listing() { /*! * Process all of the linking data of all objects. */ -void ObjectFileDB::process_link_data() { +void ObjectFileDB::process_link_data(const Config& config) { lg::info("Processing Link Data..."); Timer process_link_timer; LinkedObjectFile::Stats combined_stats; for_each_obj([&](ObjectFileData& obj) { - obj.linked_data = to_linked_object_file(obj.data, obj.record.name, dts); + obj.linked_data = to_linked_object_file(obj.data, obj.record.name, dts, config.game_version); combined_stats.add(obj.linked_data.stats); }); @@ -454,7 +456,8 @@ void ObjectFileDB::write_object_file_words(const std::string& output_dir, */ void ObjectFileDB::write_disassembly(const std::string& output_dir, bool disassemble_data, - bool disassemble_code) { + bool disassemble_code, + bool print_hex) { lg::info("- Writing functions..."); Timer timer; uint32_t total_bytes = 0, total_files = 0; @@ -463,7 +466,7 @@ void ObjectFileDB::write_disassembly(const std::string& output_dir, for_each_obj([&](ObjectFileData& obj) { if ((obj.obj_version == 3 && disassemble_code) || (obj.obj_version != 3 && disassemble_data)) { - auto file_text = obj.linked_data.print_disassembly(); + auto file_text = obj.linked_data.print_disassembly(print_hex); asm_functions += obj.linked_data.print_asm_function_disassembly(obj.to_unique_name()); auto file_name = file_util::combine_path(output_dir, obj.to_unique_name() + ".asm"); @@ -488,7 +491,7 @@ void ObjectFileDB::write_disassembly(const std::string& output_dir, /*! * Find code/data zones, identify functions, and disassemble */ -void ObjectFileDB::find_code() { +void ObjectFileDB::find_code(const Config& config) { lg::info("Finding code in object files..."); LinkedObjectFile::Stats combined_stats; Timer timer; @@ -499,7 +502,7 @@ void ObjectFileDB::find_code() { obj.linked_data.find_functions(); obj.linked_data.disassemble_functions(); - if (get_config().game_version == 1 || obj.to_unique_name() != "effect-control-v0") { + if (config.game_version == 1 || obj.to_unique_name() != "effect-control-v0") { obj.linked_data.process_fp_relative_links(); } else { lg::warn("Skipping process_fp_relative_links in {}", obj.to_unique_name().c_str()); @@ -619,12 +622,11 @@ std::string ObjectFileDB::process_game_count_file() { /*! * This is the main decompiler routine which runs after we've identified functions. */ -void ObjectFileDB::analyze_functions_ir1() { +void ObjectFileDB::analyze_functions_ir1(const Config& config) { lg::info("- Analyzing Functions..."); Timer timer; int total_functions = 0; - const auto& config = get_config(); // Step 1 - analyze the "top level" or "login" code for each object file. // this will give us type definitions, method definitions, and function definitions... @@ -665,7 +667,8 @@ void ObjectFileDB::analyze_functions_ir1() { unique_names.insert(name); - if (config.asm_functions_by_name.find(name) != config.asm_functions_by_name.end()) { + if (config.hacks.asm_functions_by_name.find(name) != + config.hacks.asm_functions_by_name.end()) { func.warnings.info("Flagged as asm by config"); func.suspected_asm = true; } @@ -735,7 +738,10 @@ void ObjectFileDB::analyze_functions_ir1() { // if we got an inspect method, inspect it. if (func.is_inspect_method) { - auto result = inspect_inspect_method(func, func.method_of_type, dts, data.linked_data); + auto result = inspect_inspect_method( + func, func.method_of_type, dts, data.linked_data, + config.hacks.types_with_bad_inspect_methods.find(func.method_of_type) != + config.hacks.types_with_bad_inspect_methods.end()); all_type_defs += ";; " + data.to_unique_name() + "\n"; all_type_defs += result.print_as_deftype() + "\n"; } diff --git a/decompiler/ObjectFile/ObjectFileDB.h b/decompiler/ObjectFile/ObjectFileDB.h index 05afc27fab..9b8e33f799 100644 --- a/decompiler/ObjectFile/ObjectFileDB.h +++ b/decompiler/ObjectFile/ObjectFileDB.h @@ -49,32 +49,34 @@ class ObjectFileDB { ObjectFileDB(const std::vector& _dgos, const std::string& obj_file_name_map_file, const std::vector& object_files, - const std::vector& str_files); + const std::vector& str_files, + const Config& config); std::string generate_dgo_listing(); std::string generate_obj_listing(); - void process_link_data(); + void process_link_data(const Config& config); void process_labels(); - void find_code(); + void find_code(const Config& config); void find_and_write_scripts(const std::string& output_dir); void dump_raw_objects(const std::string& output_dir); void write_object_file_words(const std::string& output_dir, bool dump_data, bool dump_code); void write_disassembly(const std::string& output_dir, bool disassemble_data, - bool disassemble_code); + bool disassemble_code, + bool print_hex); - void analyze_functions_ir1(); - void analyze_functions_ir2(const std::string& output_dir); - void ir2_top_level_pass(); + void analyze_functions_ir1(const Config& config); + void analyze_functions_ir2(const std::string& output_dir, const Config& config); + void ir2_top_level_pass(const Config& config); void ir2_stack_spill_slot_pass(); void ir2_basic_block_pass(); - void ir2_atomic_op_pass(); - void ir2_type_analysis_pass(); + void ir2_atomic_op_pass(const Config& config); + void ir2_type_analysis_pass(const Config& config); void ir2_register_usage_pass(); void ir2_variable_pass(); void ir2_cfg_build_pass(); void ir2_store_current_forms(); - void ir2_build_expressions(); + void ir2_build_expressions(const Config& config); void ir2_insert_lets(); void ir2_rewrite_inline_asm_instructions(); void ir2_insert_anonymous_functions(); @@ -94,16 +96,18 @@ class ObjectFileDB { bool lookup_function_type(const FunctionName& name, const std::string& obj_name, + const Config& config, TypeSpec* result); public: void load_map_file(const std::string& map_data); - void get_objs_from_dgo(const std::string& filename); + void get_objs_from_dgo(const std::string& filename, const Config& config); void add_obj_from_dgo(const std::string& obj_name, const std::string& name_in_dgo, const uint8_t* obj_data, uint32_t obj_size, - const std::string& dgo_name); + const std::string& dgo_name, + const Config& config); /*! * Apply f to all ObjectFileData's. Does it in the right order. diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 3fddfece64..1af799a618 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -29,18 +29,18 @@ namespace decompiler { * At this point, we assume that the files are loaded and we've run find_code to locate all * functions, but nothing else. */ -void ObjectFileDB::analyze_functions_ir2(const std::string& output_dir) { +void ObjectFileDB::analyze_functions_ir2(const std::string& output_dir, const Config& config) { lg::info("Using IR2 analysis..."); lg::info("Processing top-level functions..."); - ir2_top_level_pass(); + ir2_top_level_pass(config); lg::info("Processing basic blocks and control flow graph..."); ir2_basic_block_pass(); lg::info("Finding stack spills..."); ir2_stack_spill_slot_pass(); lg::info("Converting to atomic ops..."); - ir2_atomic_op_pass(); + ir2_atomic_op_pass(config); lg::info("Running type analysis..."); - ir2_type_analysis_pass(); + ir2_type_analysis_pass(config); lg::info("Register usage analysis..."); ir2_register_usage_pass(); lg::info("Variable analysis..."); @@ -51,7 +51,7 @@ void ObjectFileDB::analyze_functions_ir2(const std::string& output_dir) { lg::info("Storing temporary form result..."); ir2_store_current_forms(); lg::info("Expression building..."); - ir2_build_expressions(); + ir2_build_expressions(config); lg::info("Re-writing inline asm instructions..."); ir2_rewrite_inline_asm_instructions(); @@ -74,7 +74,7 @@ void ObjectFileDB::analyze_functions_ir2(const std::string& output_dir) { * - Find method definitions * - Warn for non-unique function names. */ -void ObjectFileDB::ir2_top_level_pass() { +void ObjectFileDB::ir2_top_level_pass(const Config& config) { Timer timer; int total_functions = 0; int total_named_global_functions = 0; @@ -134,8 +134,8 @@ void ObjectFileDB::ir2_top_level_pass() { unique_names.insert(name); - if (get_config().asm_functions_by_name.find(name) != - get_config().asm_functions_by_name.end()) { + if (config.hacks.asm_functions_by_name.find(name) != + config.hacks.asm_functions_by_name.end()) { func.warnings.info("Flagged as asm by config"); func.suspected_asm = true; } @@ -253,7 +253,7 @@ void ObjectFileDB::ir2_stack_spill_slot_pass() { * Conversion of MIPS instructions into AtomicOps. The AtomicOps represent what we * think are IR of the original GOAL compiler. */ -void ObjectFileDB::ir2_atomic_op_pass() { +void ObjectFileDB::ir2_atomic_op_pass(const Config& config) { Timer timer; int total_functions = 0; int attempted = 0; @@ -266,8 +266,8 @@ void ObjectFileDB::ir2_atomic_op_pass() { attempted++; try { bool inline_asm = - get_config().hint_inline_assembly_functions.find(func.guessed_name.to_string()) != - get_config().hint_inline_assembly_functions.end(); + config.hacks.hint_inline_assembly_functions.find(func.guessed_name.to_string()) != + config.hacks.hint_inline_assembly_functions.end(); auto ops = convert_function_to_atomic_ops(func, data.linked_data.labels, func.warnings, inline_asm); func.ir2.atomic_ops = std::make_shared(std::move(ops)); @@ -288,13 +288,23 @@ void ObjectFileDB::ir2_atomic_op_pass() { 100.f * attempted / total_functions, 100.f * successful / attempted); } +template +Value try_lookup(const std::unordered_map& map, const Key& key) { + auto lookup = map.find(key); + if (lookup == map.end()) { + return Value(); + } else { + return lookup->second; + } +} + /*! * Analyze registers and determine the type in each register at each instruction. * - Figure out the type of each function, from configs. * - Propagate types. * - NOTE: this will update register info usage more accurately for functions. */ -void ObjectFileDB::ir2_type_analysis_pass() { +void ObjectFileDB::ir2_type_analysis_pass(const Config& config) { Timer timer; int total_functions = 0; int non_asm_functions = 0; @@ -307,21 +317,21 @@ void ObjectFileDB::ir2_type_analysis_pass() { if (!func.suspected_asm) { non_asm_functions++; TypeSpec ts; - if (lookup_function_type(func.guessed_name, data.to_unique_name(), &ts) && + if (lookup_function_type(func.guessed_name, data.to_unique_name(), config, &ts) && func.ir2.atomic_ops_succeeded) { func.type = ts; attempted_functions++; // try type analysis here. auto func_name = func.guessed_name.to_string(); - auto casts = get_config().type_casts_by_function_by_atomic_op_idx[func_name]; - auto label_types = get_config().label_types[data.to_unique_name()]; + auto casts = try_lookup(config.type_casts_by_function_by_atomic_op_idx, func_name); + auto label_types = try_lookup(config.label_types, data.to_unique_name()); func.ir2.env.set_type_casts(casts); func.ir2.env.set_label_types(label_types); - if (get_config().pair_functions_by_name.find(func_name) != - get_config().pair_functions_by_name.end()) { + if (config.hacks.pair_functions_by_name.find(func_name) != + config.hacks.pair_functions_by_name.end()) { func.ir2.env.set_sloppy_pair_typing(); } - func.ir2.env.set_stack_var_hints(get_config().stack_var_hints_by_function[func_name]); + func.ir2.env.set_stack_var_hints(try_lookup(config.stack_var_hints_by_function, func_name)); if (run_type_analysis_ir2(ts, dts, func)) { successful_functions++; func.ir2.env.types_succeeded = true; @@ -436,7 +446,7 @@ void ObjectFileDB::ir2_store_current_forms() { lg::info("Stored debug forms for {} functions in {:.2f} ms\n", total, timer.getMs()); } -void ObjectFileDB::ir2_build_expressions() { +void ObjectFileDB::ir2_build_expressions(const Config& config) { Timer timer; int total = 0; int attempted = 0; @@ -449,13 +459,13 @@ void ObjectFileDB::ir2_build_expressions() { func.ir2.env.types_succeeded) { attempted++; auto name = func.guessed_name.to_string(); - auto arg_config = get_config().function_arg_names.find(name); - auto var_config = get_config().function_var_overrides.find(name); + auto arg_config = config.function_arg_names.find(name); + auto var_config = config.function_var_overrides.find(name); if (convert_to_expressions(func.ir2.top_form, *func.ir2.form_pool, func, - arg_config != get_config().function_arg_names.end() + arg_config != config.function_arg_names.end() ? arg_config->second : std::vector{}, - var_config != get_config().function_var_overrides.end() + var_config != config.function_var_overrides.end() ? var_config->second : std::unordered_map{}, dts)) { @@ -826,12 +836,11 @@ std::string ObjectFileDB::ir2_function_to_string(ObjectFileData& data, Function& */ bool ObjectFileDB::lookup_function_type(const FunctionName& name, const std::string& obj_name, + const Config& config, TypeSpec* result) { - auto& cfg = get_config(); - // don't return function types that are explictly flagged as bad in config. - if (cfg.no_type_analysis_functions_by_name.find(name.to_string()) != - cfg.no_type_analysis_functions_by_name.end()) { + if (config.hacks.no_type_analysis_functions_by_name.find(name.to_string()) != + config.hacks.no_type_analysis_functions_by_name.end()) { return false; } @@ -867,7 +876,7 @@ bool ObjectFileDB::lookup_function_type(const FunctionName& name, return true; } else if (name.kind == FunctionName::FunctionKind::UNIDENTIFIED) { // try looking up the object - const auto& map = get_config().anon_function_types_by_obj_by_id; + const auto& map = config.anon_function_types_by_obj_by_id; auto obj_kv = map.find(obj_name); if (obj_kv != map.end()) { auto func_kv = obj_kv->second.find(name.get_anon_id()); diff --git a/decompiler/config.cpp b/decompiler/config.cpp index c0e901d6c5..4485ea7b3e 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -6,11 +6,6 @@ #include "decompiler/util/config_parsers.h" namespace decompiler { -Config gConfig; - -Config& get_config() { - return gConfig; -} namespace { /*! @@ -25,60 +20,39 @@ nlohmann::json read_json_file_from_config(const nlohmann::json& cfg, const std:: } // namespace /*! - * Parse the main config file and set the global decompiler configuration. + * Parse the main config file and return decompiler config. */ -void set_config(const std::string& path_to_config_file) { +Config read_config_file(const std::string& path_to_config_file) { + Config config; auto config_str = file_util::read_text_file(path_to_config_file); auto cfg = parse_commented_json(config_str); - gConfig.game_version = cfg.at("game_version").get(); - gConfig.dgo_names = cfg.at("dgo_names").get>(); - gConfig.object_file_names = cfg.at("object_file_names").get>(); - gConfig.str_file_names = cfg.at("str_file_names").get>(); + config.game_version = cfg.at("game_version").get(); + + auto inputs_json = read_json_file_from_config(cfg, "inputs_file"); + config.dgo_names = inputs_json.at("dgo_names").get>(); + config.object_file_names = inputs_json.at("object_file_names").get>(); + config.str_file_names = inputs_json.at("str_file_names").get>(); + if (cfg.contains("obj_file_name_map_file")) { - gConfig.obj_file_name_map_file = cfg.at("obj_file_name_map_file").get(); - } - gConfig.disassemble_code = cfg.at("disassemble_code").get(); - gConfig.decompile_code = cfg.at("decompile_code").get(); - gConfig.regenerate_all_types = cfg.at("regenerate_all_types").get(); - gConfig.write_hex_near_instructions = cfg.at("write_hex_near_instructions").get(); - gConfig.write_scripts = cfg.at("write_scripts").get(); - gConfig.disassemble_data = cfg.at("disassemble_data").get(); - gConfig.process_tpages = cfg.at("process_tpages").get(); - gConfig.process_game_text = cfg.at("process_game_text").get(); - gConfig.process_game_count = cfg.at("process_game_count").get(); - gConfig.hexdump_code = cfg.at("hexdump_code").get(); - gConfig.hexdump_data = cfg.at("hexdump_data").get(); - gConfig.dump_objs = cfg.at("dump_objs").get(); - gConfig.hint_inline_assembly_functions = - cfg.at("inline_asm_hint").get>(); - - std::vector asm_functions_by_name = - cfg.at("asm_functions_by_name").get>(); - for (const auto& x : asm_functions_by_name) { - gConfig.asm_functions_by_name.insert(x); - } - - std::vector pair_functions_by_name = - cfg.at("pair_functions_by_name").get>(); - for (const auto& x : pair_functions_by_name) { - gConfig.pair_functions_by_name.insert(x); - } - - std::vector no_type_analysis_functions_by_name = - cfg.at("no_type_analysis_functions_by_name").get>(); - for (const auto& x : no_type_analysis_functions_by_name) { - gConfig.no_type_analysis_functions_by_name.insert(x); - } - - auto bad_inspect = cfg.at("types_with_bad_inspect_methods").get>(); - for (const auto& x : bad_inspect) { - gConfig.bad_inspect_types.insert(x); + config.obj_file_name_map_file = cfg.at("obj_file_name_map_file").get(); } + config.disassemble_code = cfg.at("disassemble_code").get(); + config.decompile_code = cfg.at("decompile_code").get(); + config.regenerate_all_types = cfg.at("regenerate_all_types").get(); + config.write_hex_near_instructions = cfg.at("write_hex_near_instructions").get(); + config.write_scripts = cfg.at("write_scripts").get(); + config.disassemble_data = cfg.at("disassemble_data").get(); + config.process_tpages = cfg.at("process_tpages").get(); + config.process_game_text = cfg.at("process_game_text").get(); + config.process_game_count = cfg.at("process_game_count").get(); + config.hexdump_code = cfg.at("hexdump_code").get(); + config.hexdump_data = cfg.at("hexdump_data").get(); + config.dump_objs = cfg.at("dump_objs").get(); auto allowed = cfg.at("allowed_objects").get>(); for (const auto& x : allowed) { - gConfig.allowed_objects.insert(x); + config.allowed_objects.insert(x); } auto type_casts_json = read_json_file_from_config(cfg, "type_casts_file"); @@ -92,7 +66,7 @@ void set_config(const std::string& path_to_config_file) { type_cast.atomic_op_idx = idx; type_cast.reg = Register(cast.at(1)); type_cast.type_name = cast.at(2).get(); - gConfig.type_casts_by_function_by_atomic_op_idx[function_name][idx].push_back(type_cast); + config.type_casts_by_function_by_atomic_op_idx[function_name][idx].push_back(type_cast); } } } @@ -104,7 +78,7 @@ void set_config(const std::string& path_to_config_file) { for (auto& anon_type : anon_types) { auto id = anon_type.at(0).get(); const auto& type_name = anon_type.at(1).get(); - gConfig.anon_function_types_by_obj_by_id[obj_file_name][id] = type_name; + config.anon_function_types_by_obj_by_id[obj_file_name][id] = type_name; } } auto var_names_json = read_json_file_from_config(cfg, "var_names_file"); @@ -113,7 +87,7 @@ void set_config(const std::string& path_to_config_file) { auto arg = kv.value().find("args"); if (arg != kv.value().end()) { for (auto& x : arg.value()) { - gConfig.function_arg_names[function_name].push_back(x); + config.function_arg_names[function_name].push_back(x); } } @@ -129,7 +103,7 @@ void set_config(const std::string& path_to_config_file) { } else { throw std::runtime_error("Invalid function var override."); } - gConfig.function_var_overrides[function_name][vkv.first] = override; + config.function_var_overrides[function_name][vkv.first] = override; } } } @@ -142,7 +116,7 @@ void set_config(const std::string& path_to_config_file) { const auto& name = x.at(0).get(); const auto& type_name = x.at(1).get(); bool is_const = x.at(2).get(); - auto& config_entry = gConfig.label_types[obj_name][name]; + auto& config_entry = config.label_types[obj_name][name]; config_entry = {type_name, is_const, {}}; if (x.size() > 3) { config_entry.array_size = x.at(3).get(); @@ -154,8 +128,21 @@ void set_config(const std::string& path_to_config_file) { for (auto& kv : stack_vars_json.items()) { auto& func_name = kv.key(); auto& stack_vars = kv.value(); - gConfig.stack_var_hints_by_function[func_name] = parse_stack_var_hints(stack_vars); + config.stack_var_hints_by_function[func_name] = parse_stack_var_hints(stack_vars); } + + auto hacks_json = read_json_file_from_config(cfg, "hacks_file"); + config.hacks.hint_inline_assembly_functions = + hacks_json.at("hint_inline_assembly_functions").get>(); + config.hacks.asm_functions_by_name = + hacks_json.at("asm_functions_by_name").get>(); + config.hacks.pair_functions_by_name = + hacks_json.at("pair_functions_by_name").get>(); + config.hacks.no_type_analysis_functions_by_name = + hacks_json.at("no_type_analysis_functions_by_name").get>(); + config.hacks.types_with_bad_inspect_methods = + hacks_json.at("types_with_bad_inspect_methods").get>(); + return config; } } // namespace decompiler \ No newline at end of file diff --git a/decompiler/config.h b/decompiler/config.h index 9fa04bb350..ccdf8cacb1 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -42,12 +42,20 @@ struct StackVariableHint { int stack_offset = 0; // where it's located on the stack (relative to sp after prologue) }; +struct DecompileHacks { + std::unordered_set types_with_bad_inspect_methods; + std::unordered_set no_type_analysis_functions_by_name; + std::unordered_set hint_inline_assembly_functions; + std::unordered_set asm_functions_by_name; + std::unordered_set pair_functions_by_name; +}; + struct Config { int game_version = -1; std::vector dgo_names; std::vector object_file_names; std::vector str_file_names; - std::unordered_set bad_inspect_types; + std::string obj_file_name_map_file; bool disassemble_code = false; @@ -64,9 +72,6 @@ struct Config { bool hexdump_data = false; bool dump_objs = false; - std::unordered_set asm_functions_by_name; - std::unordered_set pair_functions_by_name; - std::unordered_set no_type_analysis_functions_by_name; std::unordered_set allowed_objects; std::unordered_map>> type_casts_by_function_by_atomic_op_idx; @@ -78,10 +83,9 @@ struct Config { std::unordered_map> label_types; std::unordered_map> stack_var_hints_by_function; - std::unordered_set hint_inline_assembly_functions; + DecompileHacks hacks; }; -Config& get_config(); -void set_config(const std::string& path_to_config_file); +Config read_config_file(const std::string& path_to_config_file); } // namespace decompiler diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index e08c994feb..553eddd267 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -1,68 +1,9 @@ - - { - "game_version":1, + "game_version": 1, - - ////////////////////// - // INPUT FILES - ////////////////////// - - // input is GOAL object files, possibly in containers. - // most objects are part of CGO/DGO files (both go in dgo_names). This includes levels and the engine - // the DGOs will be processed in this order. Usually it's best to have KERNEL, ENGINE, then the levels when - // you want to run on the entire game. - "dgo_names":["CGO/KERNEL.CGO","CGO/ENGINE.CGO", "CGO/GAME.CGO", - "CGO/ART.CGO", "DGO/BEA.DGO", "DGO/CIT.DGO", "CGO/COMMON.CGO", "DGO/DAR.DGO", "DGO/DEM.DGO", - "DGO/FIN.DGO", "DGO/INT.DGO", "DGO/JUB.DGO", "DGO/JUN.DGO", "CGO/JUNGLE.CGO", "CGO/L1.CGO", "DGO/FIC.DGO", - "DGO/LAV.DGO", "DGO/MAI.DGO", "CGO/MAINCAVE.CGO", "DGO/MIS.DGO", "DGO/OGR.DGO", "CGO/RACERP.CGO", "DGO/ROB.DGO", "DGO/ROL.DGO", - "DGO/SNO.DGO", "DGO/SUB.DGO", "DGO/SUN.DGO", "CGO/SUNKEN.CGO", "DGO/SWA.DGO", "DGO/TIT.DGO", "DGO/TRA.DGO", "DGO/VI1.DGO", - "DGO/VI2.DGO", "DGO/VI3.DGO", "CGO/VILLAGEP.CGO", "CGO/WATER-AN.CGO" - ], - - // some objects are part of STR files (streaming data). In Jak 1 this is just animations - "str_file_names":["STR/BAFCELL.STR", "STR/SWTE4.STR", "STR/SWTE3.STR", "STR/SWTE2.STR", "STR/SWTE1.STR", - "STR/SNRBSBFC.STR", "STR/SNRBIPFC.STR", "STR/SNRBICFC.STR", "STR/ORR3.STR", "STR/ORR2.STR", "STR/MICANNON.STR", - "STR/BECANNON.STR", "STR/SWTS4.STR", "STR/SWTS3.STR", "STR/SWTS2.STR", "STR/SW4.STR", "STR/SW3.STR", "STR/SW2.STR", - "STR/SWTS1.STR", "STR/ORREYE.STR", "STR/ORLEYE.STR", "STR/SW1.STR", "STR/MAGFCELL.STR", "STR/GNFCELL.STR", - "STR/ORRE3.STR","STR/ORRE2.STR","STR/ORRE1.STR","STR/ORR1.STR","STR/ORLE3.STR","STR/ORLE2.STR","STR/ORI3.STR", - "STR/ORI2.STR","STR/DE0202.STR","STR/RARSANIM.STR","STR/RARANIM.STR","STR/EIFISH.STR","STR/ORLE1.STR", - "STR/SWTEF4.STR","STR/SWTEF3.STR","STR/SWTEF2.STR","STR/SWTEF1.STR","STR/ORI1.STR","STR/EIICE.STR","STR/EIA3.STR", - "STR/DE0191.STR","STR/DE0186.STR","STR/DE0187.STR","STR/EIA4.STR","STR/EIPOLE.STR","STR/RARASECO.STR", - "STR/RARA2.STR","STR/DE0184.STR","STR/DE0181.STR","STR/PESEXT.STR","STR/DE0195.STR","STR/EIA2.STR","STR/FIR1.STR", - "STR/DE0182.STR","STR/BIR1.STR","STR/HAPOPEN.STR","STR/EITUBE.STR","STR/SCR1.STR","STR/DE0197.STR", - "STR/DE0193.STR","STR/EIA1.STR","STR/FAR2.STR","STR/FAR1.STR","STR/DE0199.STR","STR/GERMONEY.STR", - "STR/BIRESOLU.STR","STR/GARMONEY.STR","STR/BIADVENT.STR","STR/FUCRV1.STR","STR/BIREJECT.STR","STR/WAR1.STR", - "STR/BIACCEPT.STR","STR/SA3R1DEC.STR","STR/ASR1GENE.STR","STR/FIREJECT.STR","STR/GARRACE.STR","STR/GEZMONEY.STR", - "STR/LRFALLIN.STR","STR/EXR2.STR","STR/GERMOLES.STR","STR/FUCVICTO.STR","STR/MIR1ORBS.STR","STR/SA3R1RAM.STR", - "STR/AS2R1FLU.STR","STR/FUCV2.STR","STR/MIR1GNAW.STR","STR/GAZMONEY.STR","STR/AS3REMIN.STR","STR/SIHISA.STR", - "STR/FIACCEPT.STR","STR/FIWECO.STR","STR/FARESOLU.STR","STR/ASR1RBIK.STR","STR/MARDONAT.STR","STR/GAZRACE.STR", - "STR/FUCFV1.STR","STR/FUCV5.STR","STR/SABR1CDU.STR","STR/FLLINTRO.STR","STR/SAR1ECOR.STR","STR/AS2R1ROB.STR", - "STR/MIR2ORBS.STR","STR/MARBEAMS.STR","STR/LOI2.STR","STR/SAR1GENE.STR","STR/BILR1.STR","STR/AS2R1ROO.STR", - "STR/ASR1BESW.STR","STR/LOLOOP.STR","STR/FAINTROD.STR","STR/GEZMOLES.STR","STR/V1IN.STR","STR/FUCV4.STR", - "STR/SAIECORO.STR","STR/MIR1SWIT.STR","STR/LOINTRO.STR","STR/SAR2GENE.STR","STR/MUVICTOR.STR","STR/SAR1MCAN.STR", - "STR/FUCV7.STR","STR/MIZ1ORBS.STR","STR/FUCV8.STR","STR/BILR2.STR","STR/FUCV6.STR","STR/FUCV3.STR", - "STR/PLLBLOWU.STR","STR/PLBMAIN.STR","STR/WARESOLU.STR","STR/EIRACER.STR","STR/MAZDONAT.STR","STR/MAZBEAMS.STR", - "STR/MIISWITC.STR","STR/FIBRTVIL.STR","STR/FIBRTMIS.STR","STR/SABR1PAR.STR","STR/NDINTRO.STR","STR/GORDOWN.STR", - "STR/GORUP.STR","STR/SA3IRAMS.STR","STR/YERESOLU.STR","STR/EIFLUT.STR","STR/GRSDSACR.STR","STR/EXR1.STR", - "STR/SCRESOLU.STR","STR/FIRESOLU.STR","STR/SIHITEST.STR","STR/GAI1.STR","STR/EXRESOLU.STR","STR/MIZ2ORBS.STR", - "STR/ASIRBIKE.STR","STR/GRSOBBEC.STR","STR/BIINTROD.STR","STR/GRSOBBNC.STR","STR/AS2IROBB.STR","STR/GRSOBFIN.STR", - "STR/RERESOLU.STR","STR/BLRESOLU.STR","STR/SABIPARM.STR","STR/EVMEND.STR","STR/AS2RESOL.STR","STR/SAIMCANN.STR", - "STR/MIIGNAWE.STR","STR/GRSOBBA.STR","STR/GRSINTRO.STR","STR/SAISE.STR","STR/SA3IDECO.STR","STR/ASFRESOL.STR", - "STR/EXINTROD.STR","STR/BILINTRO.STR","STR/FIINTROD.STR","STR/MAINTROD.STR","STR/SCINTROD.STR","STR/AS2IFLUT.STR", - "STR/ASLERESO.STR","STR/ASLSRESO.STR","STR/AS2IROOM.STR","STR/GRSRESOL.STR","STR/SABICDUS.STR","STR/SIHISB.STR", - "STR/ASIBESWI.STR","STR/BILBRESO.STR","STR/FIBRT1AL.STR","STR/AS2INTRO.STR","STR/GEINTROD.STR","STR/SAISD1.STR", - "STR/SAISA.STR","STR/SIHISC.STR","STR/MIIORBS.STR","STR/WAINTROD.STR","STR/SAISD2.STR","STR/GRSOPREB.STR", - "STR/GRSOBBB.STR","STR/SA3INTRO.STR" - ], - - // some objects are directly stored as files on the DVD. This is just text files. - "object_file_names":["TEXT/0COMMON.TXT", "TEXT/1COMMON.TXT", "TEXT/2COMMON.TXT", "TEXT/3COMMON.TXT", "TEXT/4COMMON.TXT", - "TEXT/5COMMON.TXT", "TEXT/6COMMON.TXT"], - // if you want to filter to only some object names. // it will make the decompiler much faster. - "allowed_objects":[], + "allowed_objects": [], //////////////////////////// // CODE ANALYSIS OPTIONS @@ -70,10 +11,10 @@ // set to true to generate plain .asm files with MIPS disassembly, with no fancy decompilation. // this is fast and should succeed 100% of the time. - "disassemble_code":false, + "disassemble_code": false, // Run the decompiler - "decompile_code":true, + "decompile_code": true, //////////////////////////// // DATA ANALYSIS OPTIONS @@ -82,14 +23,14 @@ // set to true to generate plain .asm files for data files. // this will display most data as hex, but will add labels/references/type pointers/strings // this generates a huge amount of output if you run it on the entire game. - "disassemble_data":false, + "disassemble_data": false, // unpack textures to assets folder - "process_tpages":true, + "process_tpages": true, // unpack game text to assets folder - "process_game_text":true, + "process_game_text": true, // unpack game count to assets folder - "process_game_count":true, + "process_game_count": true, /////////////////////////// // WEIRD OPTIONS @@ -98,464 +39,33 @@ // these options are used rarely and should usually be left at false // output a file type_defs.gc which is used the types part of all-types.gc - "regenerate_all_types":false, + "regenerate_all_types": false, // debug option for instruction decoder - "write_hex_near_instructions":false, + "write_hex_near_instructions": false, // experimental tool to extract linked lists used for region scripting in Jak 2 and Jak 3. - "write_scripts":false, + "write_scripts": false, // hex dump of code/data files. - "hexdump_code":false, - "hexdump_data":false, + "hexdump_code": false, + "hexdump_data": false, // dump raw obj files - "dump_objs":false, + "dump_objs": false, - //////////////////////////// // CONFIG FILES //////////////////////////// - "type_casts_file":"decompiler/config/jak1_ntsc_black_label/type_casts.jsonc", - "anonymous_function_types_file":"decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc", - "var_names_file":"decompiler/config/jak1_ntsc_black_label/var_names.jsonc", - "label_types_file":"decompiler/config/jak1_ntsc_black_label/label_types.jsonc", - "stack_vars_file":"decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc", + "type_casts_file": "decompiler/config/jak1_ntsc_black_label/type_casts.jsonc", + "anonymous_function_types_file": "decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc", + "var_names_file": "decompiler/config/jak1_ntsc_black_label/var_names.jsonc", + "label_types_file": "decompiler/config/jak1_ntsc_black_label/label_types.jsonc", + "stack_vars_file": "decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc", + "hacks_file": "decompiler/config/jak1_ntsc_black_label/hacks.jsonc", + "inputs_file": "decompiler/config/jak1_ntsc_black_label/inputs.jsonc", // optional: a predetermined object file name map from a file. // this will make decompilation naming consistent even if you only run on some objects. - "obj_file_name_map_file":"goal_src/build/all_objs.json", - - - //////////////////////////// - // HACKS and ASM FUNCTIONS - //////////////////////////// - - "types_with_bad_inspect_methods":[ - "engine", - "bsp-header", - "joint-anim-matrix", - "part-tracker"], - - "no_type_analysis_functions_by_name":[], - - // this provides a hint to the decompiler that these functions will have a lot of inline assembly. - "inline_asm_hint":["matrix-transpose!"], - - "asm_functions_by_name":[ - // gcommon - "quad-copy!", - - // gkernel - "(method 11 cpu-thread)", - "throw", - "return-from-thread", - "return-from-thread-dead", - "reset-and-call", - "(method 10 cpu-thread)", - "(method 0 catch-frame)", - "throw-dispatch", - "set-to-run-bootstrap", - "run-function-in-process", // not asm, but it uses the stack. - - // pskernel - "return-from-exception", // F: eret - "kernel-read-function", // F: delay slot tricks - "kernel-write-function", // F: delay slot tricks - "kernel-copy-function", - "kernel-check-hardwired-addresses", - - // math - "rand-uint31-gen", - - // bounding box - "(method 9 bounding-box)", // F: asm branching - "(method 14 bounding-box)", - - // matrix - "(method 9 matrix)", // F: asm branching - "matrix-axis-sin-cos!", // F: asm branching - "matrix-axis-sin-cos-vu!", - - // geometry - "curve-evaluate!", // BUG: cfg fails, suspected weird gotos - "circle-circle-xz-intersect", // F: asm branching - "closest-pt-in-triangle", // F: asm branching - "find-knot-span", // ?? - "vector-segment-distance-point!", - - // trigonometry - "exp", // BUG: cfg is wrong. - "atan0", // P: manual use of stack - "sincos!", // P: manual use of stack - "sincos-rad!", - - // dma-h - "dma-count-until-done", // F: asm branching - "dma-sync-with-count", // F: asm branching - "dma-send-no-scratch", // F: asm branching - "dma-sync-fast", - - // dma - "symlink3", // F: asm branching - "symlink2", // F: asm branching - "dma-sync-hang", - - // display - "vblank-handler", // F: weird asm for interrupt handler - "vif1-handler", // F: weird asm for interrupt handler - "vif1-handler-debug", - - // vector - "vector=", // asm branching - - // texture - "adgif-shader<-texture-with-update!", // F: asm branching - "(method 9 texture-page-dir)", - - // collide-mesh-h - "(method 11 collide-mesh-cache)", - - // actor-link-h (BUG) - "(method 21 actor-link-info)", // BUG: sc cfg / cfg-ir bug - "(method 20 actor-link-info)", - - // collide-func - "moving-sphere-triangle-intersect", // P: weird branching - "collide-do-primitives", // P: asm branching - "ray-triangle-intersect", // F: asm branching - "ray-cylinder-intersect", // F: asm branching - "raw-ray-sphere-intersect", - - // joint - "calc-animation-from-spr", // F: asm branching - "decompress-frame-data-pair-to-accumulator", // P: asm calling - "decompress-frame-data-to-accumulator", // P: asm calling - "decompress-fixed-data-to-accumulator", // P: asm calling - "normalize-frame-quaternions", // F: asm branching, return - "clear-frame-accumulator", // F: asm branching - "cspace<-parented-transformq-joint!", - - // bsp - "level-remap-texture", // BUG: probably missing branch case? - "bsp-camera-asm", // F: asm branching - "sprite-draw-distorters", - - // merc-blend-shape - "setup-blerc-chains-for-one-fragment", // F: asm branching - "blerc-execute", // F: asm branching - "merc-dma-chain-to-spr", // F: asm branching - "blerc-a-fragment", - - // ripple - "ripple-matrix-scale", - "ripple-apply-wave-table", - "ripple-create-wave-table", - "ripple-execute-init", - - // bones - "draw-bones-hud", - "draw-bones", - "draw-bones-check-longest-edge-asm", - "draw-bones-merc", - "bones-mtx-calc-execute", - "bones-mtx-calc", - "texscroll-execute", - - // generic-effect - "generic-debug-light-proc", - "generic-none-dma-wait", - "generic-copy-vtx-dclr-dtex", - "generic-light", - "generic-envmap-only-proc", - "generic-no-light", - "generic-no-light+envmap", - "generic-no-light-dproc", - "generic-no-light-dproc-only", - "generic-no-light-proc", - "generic-interp-dproc", - "generic-envmap-dproc", - "generic-prepare-dma-single", - "generic-prepare-dma-double", - "generic-envmap-proc", - "generic-light-proc", - "generic-dma-from-spr", - "upload-vu0-program", - - // generic-merc - "generic-merc-execute-all", - "generic-merc-execute-asm", - "high-speed-reject", - "mercneric-convert", - "mercneric-bittable-asm", - "mercneric-shader-asm", - "mercneric-matrix-asm", - "generic-merc-init-asm", - - // generic-tie - "generic-tie-convert", - "generic-tie-convert-proc", - "generic-tie-upload-next", - "generic-tie-decompress", - "generic-tie-dma-to-spad-sync", - - // shadow-cpu - "shadow-execute", - "shadow-add-double-edges", - "shadow-add-double-tris", - "shadow-add-single-edges", - "shadow-add-facing-single-tris", - "shadow-add-verts", - "shadow-find-double-edges", - "shadow-find-facing-double-tris", - "shadow-find-single-edges", - "shadow-find-facing-single-tris", - "shadow-scissor-top", - "shadow-scissor-edges", - "shadow-calc-dual-verts", - - // font - "get-string-length", - "draw-string", - - // decomp - "(method 16 level)", // BUG: cfg fails - "unpack-comp-huf", - "unpack-comp-rle", - - // background - "upload-vis-bits", - "background-upload-vu0", - - // draw-node - "draw-node-cull", - - // shrubbery - "test-func", - "draw-inline-array-instance-shrub", - - // tfrag - "stats-tfrag-asm", - "draw-inline-array-tfrag-near", - "draw-inline-array-tfrag", - - // tie-methods - "draw-inline-array-prototype-tie-near-asm", - "draw-inline-array-prototype-tie-asm", - "draw-inline-array-prototype-tie-generic-asm", - "draw-inline-array-instance-tie", - - // sparticle-launcher - "(method 11 sparticle-launch-control)", // BUG: cfg ir - "sp-launch-particles-var", - "particle-adgif", - "sp-init-fields!", - - // sparticle - "memcpy", - "sp-process-block-3d", - "sp-process-block-2d", - "sp-get-particle", - - // loader BUG - "(method 10 external-art-buffer)", - - // game-info BUG - "(method 11 fact-info-target)", - - // game-save BUG - "(anon-function 5 game-save)", // BUG: - "(anon-function 6 game-save)", // BUG: - "(anon-function 7 game-save)", // BUG: - "(anon-function 8 game-save)", // BUG: - "(anon-function 9 game-save)", // BUG: - "(anon-function 10 game-save)", - - // mood BUG - "update-mood-lava", // BUG: - "update-mood-lightning", - - // time-of-day - "time-of-day-interp-colors-scratch", - "time-of-day-interp-colors", - - // sky-tng - "clip-polygon-against-negative-hyperplane", - "clip-polygon-against-positive-hyperplane", - "draw-large-polygon", - - // load-boundary - "render-boundary-tri", - "render-boundary-quad", - "draw-boundary-polygon", - - // level BUG - "level-update-after-load", - - // text BUG - "load-game-text-info", - - // collide-probe - "collide-probe-instance-tie", - "collide-probe-node", - - // collide-mesh - "(method 10 collide-mesh)", - "(method 13 collide-mesh)", - "(method 9 collide-mesh-cache)", - "(method 15 collide-mesh)", - "(method 14 collide-mesh)", - "(method 11 collide-mesh)", - "(method 12 collide-mesh)", - - // collide-edge-grab - "(method 13 collide-edge-work)", - "(method 17 collide-edge-work)", - "(method 15 collide-edge-work)", - "(method 16 collide-edge-work)", - "(method 9 edge-grab-info)", // maybe bug - "(method 18 collide-edge-work)", - "(method 10 collide-edge-hold-list)", - - // collide-shape - "(method 15 collide-shape-prim-mesh)", // BUG: - "(method 15 collide-shape-prim-sphere)", // BUG: - "(method 16 collide-shape-prim)", - "(method 15 collide-shape-prim-group)", - "(method 40 collide-shape)", - "(method 45 collide-shape)", - "(method 28 collide-shape-prim-mesh)", // BUG: - "(method 29 collide-shape-prim-group)", - "(method 20 collide-shape-prim-group)", - "(method 19 collide-shape-prim-sphere)", - "(method 18 collide-shape-prim-sphere)", - "(method 23 collide-shape-prim-sphere)", - "(method 23 collide-shape-prim-mesh)", // BUG: maybe - "(method 24 collide-shape-prim)", - "(method 23 collide-shape-prim-group)", - "(method 42 collide-shape)", - - // collide-shape-rider - "(method 35 collide-shape)", - - // cam-master BUG - "master-is-hopeful-better?", - - // cam-layout BUG - "cam-layout-save-cam-trans", - - // process-drawable BUG - "cspace-inspect-tree", // BUG: - "process-drawable-birth-fuel-cell", // BUG: - "(method 19 process-drawable)", - - // ambient - "ambient-inspect", - - // generic-obs BUG - "camera-change-to", - - // target BUG - "target-falling-anim-trans", - - // target2 BUG - "(anon-function 33 target2)", // BUG: - "(anon-function 67 target2)", // BUG: - "look-for-points-of-interest", - - // menu BUG - "debug-menu-item-var-render", - - // drawable-tree - "(method 16 drawable-tree)", - - // collide-cache - "(method 10 collide-puss-work)", - "(method 9 collide-puss-work)", - "(method 19 collide-cache)", - "(method 10 collide-cache-prim)", - "(method 9 collide-cache-prim)", - "(method 30 collide-cache)", - "(method 13 collide-shape-prim-group)", - "(method 13 collide-shape-prim-sphere)", - "(method 13 collide-shape-prim-mesh)", - "(method 14 collide-shape-prim-group)", - "(method 14 collide-shape-prim-sphere)", - "(method 14 collide-shape-prim-mesh)", - "(method 12 collide-shape-prim-group)", // BUG: maybe - "(method 12 collide-shape-prim-sphere)", - "(method 12 collide-shape-prim-mesh)", - "(method 29 collide-cache)", - "(method 27 collide-cache)", - "(method 14 collide-cache)", - "(method 28 collide-cache)", - "(method 26 collide-cache)", - "(method 21 collide-cache)", - "(method 32 collide-cache)", - - // memory-usage BUG - "(method 14 level)", - - // navigate BUG - "(method 32 nav-control)", - - // collectables BUG - "birth-pickup-at-point", - "add-blue-motion", - - // ocean - "draw-large-polygon-ocean", - - // ocean-vu0 - "ocean-generate-verts", - "ocean-interp-wave", - - // anim-tester BUG - "anim-tester-add-newobj", - - // nav-enemy BUG - "(anon-function 28 nav-enemy)", - - // orb-cache BUG - "(method 27 orb-cache-top)", - - // ropebridge BUG - "(method 27 ropebridge)", - - // all unchecked.and in level DGO code - "(anon-function 11 robotboss)", - "(anon-function 18 robotboss)", - "(anon-function 49 robotboss)", - "(anon-function 21 plant-boss)", - "(anon-function 10 ice-cube)", - "(anon-function 15 ice-cube)", - "(anon-function 45 lavatube-energy)", - "(anon-function 5 game-save)", - "(anon-function 6 game-save)", - "(anon-function 7 game-save)", - "(anon-function 8 game-save)", - "(anon-function 9 game-save)", - "(anon-function 10 game-save)", - "(anon-function 28 nav-enemy)", - "mistycannon-find-best-solution", - "target-flut-falling-anim-trans", - "kermit-check-to-hit-player?", - "(anon-function 6 title-obs)", - "(anon-function 36 mistycannon)", - "(anon-function 5 battlecontroller)", - "(anon-function 43 maincave-obs)", - "(anon-function 2 target-tube)", - "(anon-function 5 orbit-plat)", - "(anon-function 2 ogreboss)", - - // not enough type info to decompile these - // (these are NOT actually asm functions) - "(method 15 sync-info)", // NEED *res-static-buf* - "(method 15 sync-info-eased)", // NEED *res-static-buf* - "(method 15 sync-info-paused)" // NEED *res-static-buf* - ], - -"pair_functions_by_name":["ref", "last", "member", "nmember", "assoc", "assoce", "append!", "delete!", "delete-car!", - "insert-cons!", "sort", "unload-package", "(method 4 pair)", "nassoc", "nassoce", "lookup-level-info", "(method 21 level-group)"] -} \ No newline at end of file + "obj_file_name_map_file": "goal_src/build/all_objs.json" +} diff --git a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc new file mode 100644 index 0000000000..0fd937d80e --- /dev/null +++ b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc @@ -0,0 +1,450 @@ +{ + //////////////////////////// + // HACKS and ASM FUNCTIONS + //////////////////////////// + + "types_with_bad_inspect_methods": [ + "engine", + "bsp-header", + "joint-anim-matrix", + "part-tracker" + ], + + "no_type_analysis_functions_by_name": [], + + // this provides a hint to the decompiler that these functions will have a lot of inline assembly. + "hint_inline_assembly_functions": ["matrix-transpose!"], + + "asm_functions_by_name": [ + // gcommon + "quad-copy!", + + // gkernel + "(method 11 cpu-thread)", + "throw", + "return-from-thread", + "return-from-thread-dead", + "reset-and-call", + "(method 10 cpu-thread)", + "(method 0 catch-frame)", + "throw-dispatch", + "set-to-run-bootstrap", + "run-function-in-process", // not asm, but it uses the stack. + + // pskernel + "return-from-exception", // F: eret + "kernel-read-function", // F: delay slot tricks + "kernel-write-function", // F: delay slot tricks + "kernel-copy-function", + "kernel-check-hardwired-addresses", + + // math + "rand-uint31-gen", + + // bounding box + "(method 9 bounding-box)", // F: asm branching + "(method 14 bounding-box)", + + // matrix + "(method 9 matrix)", // F: asm branching + "matrix-axis-sin-cos!", // F: asm branching + "matrix-axis-sin-cos-vu!", + + // geometry + "curve-evaluate!", // BUG: cfg fails, suspected weird gotos + "circle-circle-xz-intersect", // F: asm branching + "closest-pt-in-triangle", // F: asm branching + "find-knot-span", // ?? + "vector-segment-distance-point!", + + // trigonometry + "exp", // BUG: cfg is wrong. + "atan0", // P: manual use of stack + "sincos!", // P: manual use of stack + "sincos-rad!", + + // dma-h + "dma-count-until-done", // F: asm branching + "dma-sync-with-count", // F: asm branching + "dma-send-no-scratch", // F: asm branching + "dma-sync-fast", + + // dma + "symlink3", // F: asm branching + "symlink2", // F: asm branching + "dma-sync-hang", + + // display + "vblank-handler", // F: weird asm for interrupt handler + "vif1-handler", // F: weird asm for interrupt handler + "vif1-handler-debug", + + // vector + "vector=", // asm branching + + // texture + "adgif-shader<-texture-with-update!", // F: asm branching + "(method 9 texture-page-dir)", + + // collide-mesh-h + "(method 11 collide-mesh-cache)", + + // actor-link-h (BUG) + "(method 21 actor-link-info)", // BUG: sc cfg / cfg-ir bug + "(method 20 actor-link-info)", + + // collide-func + "moving-sphere-triangle-intersect", // P: weird branching + "collide-do-primitives", // P: asm branching + "ray-triangle-intersect", // F: asm branching + "ray-cylinder-intersect", // F: asm branching + "raw-ray-sphere-intersect", + + // joint + "calc-animation-from-spr", // F: asm branching + "decompress-frame-data-pair-to-accumulator", // P: asm calling + "decompress-frame-data-to-accumulator", // P: asm calling + "decompress-fixed-data-to-accumulator", // P: asm calling + "normalize-frame-quaternions", // F: asm branching, return + "clear-frame-accumulator", // F: asm branching + "cspace<-parented-transformq-joint!", + + // bsp + "level-remap-texture", // BUG: probably missing branch case? + "bsp-camera-asm", // F: asm branching + "sprite-draw-distorters", + + // merc-blend-shape + "setup-blerc-chains-for-one-fragment", // F: asm branching + "blerc-execute", // F: asm branching + "merc-dma-chain-to-spr", // F: asm branching + "blerc-a-fragment", + + // ripple + "ripple-matrix-scale", + "ripple-apply-wave-table", + "ripple-create-wave-table", + "ripple-execute-init", + + // bones + "draw-bones-hud", + "draw-bones", + "draw-bones-check-longest-edge-asm", + "draw-bones-merc", + "bones-mtx-calc-execute", + "bones-mtx-calc", + "texscroll-execute", + + // generic-effect + "generic-debug-light-proc", + "generic-none-dma-wait", + "generic-copy-vtx-dclr-dtex", + "generic-light", + "generic-envmap-only-proc", + "generic-no-light", + "generic-no-light+envmap", + "generic-no-light-dproc", + "generic-no-light-dproc-only", + "generic-no-light-proc", + "generic-interp-dproc", + "generic-envmap-dproc", + "generic-prepare-dma-single", + "generic-prepare-dma-double", + "generic-envmap-proc", + "generic-light-proc", + "generic-dma-from-spr", + "upload-vu0-program", + + // generic-merc + "generic-merc-execute-all", + "generic-merc-execute-asm", + "high-speed-reject", + "mercneric-convert", + "mercneric-bittable-asm", + "mercneric-shader-asm", + "mercneric-matrix-asm", + "generic-merc-init-asm", + + // generic-tie + "generic-tie-convert", + "generic-tie-convert-proc", + "generic-tie-upload-next", + "generic-tie-decompress", + "generic-tie-dma-to-spad-sync", + + // shadow-cpu + "shadow-execute", + "shadow-add-double-edges", + "shadow-add-double-tris", + "shadow-add-single-edges", + "shadow-add-facing-single-tris", + "shadow-add-verts", + "shadow-find-double-edges", + "shadow-find-facing-double-tris", + "shadow-find-single-edges", + "shadow-find-facing-single-tris", + "shadow-scissor-top", + "shadow-scissor-edges", + "shadow-calc-dual-verts", + + // font + "get-string-length", + "draw-string", + + // decomp + "(method 16 level)", // BUG: cfg fails + "unpack-comp-huf", + "unpack-comp-rle", + + // background + "upload-vis-bits", + "background-upload-vu0", + + // draw-node + "draw-node-cull", + + // shrubbery + "test-func", + "draw-inline-array-instance-shrub", + + // tfrag + "stats-tfrag-asm", + "draw-inline-array-tfrag-near", + "draw-inline-array-tfrag", + + // tie-methods + "draw-inline-array-prototype-tie-near-asm", + "draw-inline-array-prototype-tie-asm", + "draw-inline-array-prototype-tie-generic-asm", + "draw-inline-array-instance-tie", + + // sparticle-launcher + "(method 11 sparticle-launch-control)", // BUG: cfg ir + "sp-launch-particles-var", + "particle-adgif", + "sp-init-fields!", + + // sparticle + "memcpy", + "sp-process-block-3d", + "sp-process-block-2d", + "sp-get-particle", + + // loader BUG + "(method 10 external-art-buffer)", + + // game-info BUG + "(method 11 fact-info-target)", + + // game-save BUG + "(anon-function 5 game-save)", // BUG: + "(anon-function 6 game-save)", // BUG: + "(anon-function 7 game-save)", // BUG: + "(anon-function 8 game-save)", // BUG: + "(anon-function 9 game-save)", // BUG: + "(anon-function 10 game-save)", + + // mood BUG + "update-mood-lava", // BUG: + "update-mood-lightning", + + // time-of-day + "time-of-day-interp-colors-scratch", + "time-of-day-interp-colors", + + // sky-tng + "clip-polygon-against-negative-hyperplane", + "clip-polygon-against-positive-hyperplane", + "draw-large-polygon", + + // load-boundary + "render-boundary-tri", + "render-boundary-quad", + "draw-boundary-polygon", + + // level BUG + "level-update-after-load", + + // text BUG + "load-game-text-info", + + // collide-probe + "collide-probe-instance-tie", + "collide-probe-node", + + // collide-mesh + "(method 10 collide-mesh)", + "(method 13 collide-mesh)", + "(method 9 collide-mesh-cache)", + "(method 15 collide-mesh)", + "(method 14 collide-mesh)", + "(method 11 collide-mesh)", + "(method 12 collide-mesh)", + + // collide-edge-grab + "(method 13 collide-edge-work)", + "(method 17 collide-edge-work)", + "(method 15 collide-edge-work)", + "(method 16 collide-edge-work)", + "(method 9 edge-grab-info)", // maybe bug + "(method 18 collide-edge-work)", + "(method 10 collide-edge-hold-list)", + + // collide-shape + "(method 15 collide-shape-prim-mesh)", // BUG: + "(method 15 collide-shape-prim-sphere)", // BUG: + "(method 16 collide-shape-prim)", + "(method 15 collide-shape-prim-group)", + "(method 40 collide-shape)", + "(method 45 collide-shape)", + "(method 28 collide-shape-prim-mesh)", // BUG: + "(method 29 collide-shape-prim-group)", + "(method 20 collide-shape-prim-group)", + "(method 19 collide-shape-prim-sphere)", + "(method 18 collide-shape-prim-sphere)", + "(method 23 collide-shape-prim-sphere)", + "(method 23 collide-shape-prim-mesh)", // BUG: maybe + "(method 24 collide-shape-prim)", + "(method 23 collide-shape-prim-group)", + "(method 42 collide-shape)", + + // collide-shape-rider + "(method 35 collide-shape)", + + // cam-master BUG + "master-is-hopeful-better?", + + // cam-layout BUG + "cam-layout-save-cam-trans", + + // process-drawable BUG + "cspace-inspect-tree", // BUG: + "process-drawable-birth-fuel-cell", // BUG: + "(method 19 process-drawable)", + + // ambient + "ambient-inspect", + + // generic-obs BUG + "camera-change-to", + + // target BUG + "target-falling-anim-trans", + + // target2 BUG + "(anon-function 33 target2)", // BUG: + "(anon-function 67 target2)", // BUG: + "look-for-points-of-interest", + + // menu BUG + "debug-menu-item-var-render", + + // drawable-tree + "(method 16 drawable-tree)", + + // collide-cache + "(method 10 collide-puss-work)", + "(method 9 collide-puss-work)", + "(method 19 collide-cache)", + "(method 10 collide-cache-prim)", + "(method 9 collide-cache-prim)", + "(method 30 collide-cache)", + "(method 13 collide-shape-prim-group)", + "(method 13 collide-shape-prim-sphere)", + "(method 13 collide-shape-prim-mesh)", + "(method 14 collide-shape-prim-group)", + "(method 14 collide-shape-prim-sphere)", + "(method 14 collide-shape-prim-mesh)", + "(method 12 collide-shape-prim-group)", // BUG: maybe + "(method 12 collide-shape-prim-sphere)", + "(method 12 collide-shape-prim-mesh)", + "(method 29 collide-cache)", + "(method 27 collide-cache)", + "(method 14 collide-cache)", + "(method 28 collide-cache)", + "(method 26 collide-cache)", + "(method 21 collide-cache)", + "(method 32 collide-cache)", + + // memory-usage BUG + "(method 14 level)", + + // navigate BUG + "(method 32 nav-control)", + + // collectables BUG + "birth-pickup-at-point", + "add-blue-motion", + + // ocean + "draw-large-polygon-ocean", + + // ocean-vu0 + "ocean-generate-verts", + "ocean-interp-wave", + + // anim-tester BUG + "anim-tester-add-newobj", + + // nav-enemy BUG + "(anon-function 28 nav-enemy)", + + // orb-cache BUG + "(method 27 orb-cache-top)", + + // ropebridge BUG + "(method 27 ropebridge)", + + // all unchecked.and in level DGO code + "(anon-function 11 robotboss)", + "(anon-function 18 robotboss)", + "(anon-function 49 robotboss)", + "(anon-function 21 plant-boss)", + "(anon-function 10 ice-cube)", + "(anon-function 15 ice-cube)", + "(anon-function 45 lavatube-energy)", + "(anon-function 5 game-save)", + "(anon-function 6 game-save)", + "(anon-function 7 game-save)", + "(anon-function 8 game-save)", + "(anon-function 9 game-save)", + "(anon-function 10 game-save)", + "(anon-function 28 nav-enemy)", + "mistycannon-find-best-solution", + "target-flut-falling-anim-trans", + "kermit-check-to-hit-player?", + "(anon-function 6 title-obs)", + "(anon-function 36 mistycannon)", + "(anon-function 5 battlecontroller)", + "(anon-function 43 maincave-obs)", + "(anon-function 2 target-tube)", + "(anon-function 5 orbit-plat)", + "(anon-function 2 ogreboss)", + + // not enough type info to decompile these + // (these are NOT actually asm functions) + "(method 15 sync-info)", // NEED *res-static-buf* + "(method 15 sync-info-eased)", // NEED *res-static-buf* + "(method 15 sync-info-paused)" // NEED *res-static-buf* + ], + + "pair_functions_by_name": [ + "ref", + "last", + "member", + "nmember", + "assoc", + "assoce", + "append!", + "delete!", + "delete-car!", + "insert-cons!", + "sort", + "unload-package", + "(method 4 pair)", + "nassoc", + "nassoce", + "lookup-level-info", + "(method 21 level-group)" + ] +} diff --git a/decompiler/config/jak1_ntsc_black_label/inputs.jsonc b/decompiler/config/jak1_ntsc_black_label/inputs.jsonc new file mode 100644 index 0000000000..6a816ad2ba --- /dev/null +++ b/decompiler/config/jak1_ntsc_black_label/inputs.jsonc @@ -0,0 +1,260 @@ +{ + ////////////////////// + // INPUT FILES + ////////////////////// + + // input is GOAL object files, possibly in containers. + // most objects are part of CGO/DGO files (both go in dgo_names). This includes levels and the engine + // the DGOs will be processed in this order. Usually it's best to have KERNEL, ENGINE, then the levels when + // you want to run on the entire game. + "dgo_names": [ + "CGO/KERNEL.CGO", + "CGO/ENGINE.CGO", + "CGO/GAME.CGO", + "CGO/ART.CGO", + "DGO/BEA.DGO", + "DGO/CIT.DGO", + "CGO/COMMON.CGO", + "DGO/DAR.DGO", + "DGO/DEM.DGO", + "DGO/FIN.DGO", + "DGO/INT.DGO", + "DGO/JUB.DGO", + "DGO/JUN.DGO", + "CGO/JUNGLE.CGO", + "CGO/L1.CGO", + "DGO/FIC.DGO", + "DGO/LAV.DGO", + "DGO/MAI.DGO", + "CGO/MAINCAVE.CGO", + "DGO/MIS.DGO", + "DGO/OGR.DGO", + "CGO/RACERP.CGO", + "DGO/ROB.DGO", + "DGO/ROL.DGO", + "DGO/SNO.DGO", + "DGO/SUB.DGO", + "DGO/SUN.DGO", + "CGO/SUNKEN.CGO", + "DGO/SWA.DGO", + "DGO/TIT.DGO", + "DGO/TRA.DGO", + "DGO/VI1.DGO", + "DGO/VI2.DGO", + "DGO/VI3.DGO", + "CGO/VILLAGEP.CGO", + "CGO/WATER-AN.CGO" + ], + + // some objects are part of STR files (streaming data). In Jak 1 this is just animations + "str_file_names": [ + "STR/BAFCELL.STR", + "STR/SWTE4.STR", + "STR/SWTE3.STR", + "STR/SWTE2.STR", + "STR/SWTE1.STR", + "STR/SNRBSBFC.STR", + "STR/SNRBIPFC.STR", + "STR/SNRBICFC.STR", + "STR/ORR3.STR", + "STR/ORR2.STR", + "STR/MICANNON.STR", + "STR/BECANNON.STR", + "STR/SWTS4.STR", + "STR/SWTS3.STR", + "STR/SWTS2.STR", + "STR/SW4.STR", + "STR/SW3.STR", + "STR/SW2.STR", + "STR/SWTS1.STR", + "STR/ORREYE.STR", + "STR/ORLEYE.STR", + "STR/SW1.STR", + "STR/MAGFCELL.STR", + "STR/GNFCELL.STR", + "STR/ORRE3.STR", + "STR/ORRE2.STR", + "STR/ORRE1.STR", + "STR/ORR1.STR", + "STR/ORLE3.STR", + "STR/ORLE2.STR", + "STR/ORI3.STR", + "STR/ORI2.STR", + "STR/DE0202.STR", + "STR/RARSANIM.STR", + "STR/RARANIM.STR", + "STR/EIFISH.STR", + "STR/ORLE1.STR", + "STR/SWTEF4.STR", + "STR/SWTEF3.STR", + "STR/SWTEF2.STR", + "STR/SWTEF1.STR", + "STR/ORI1.STR", + "STR/EIICE.STR", + "STR/EIA3.STR", + "STR/DE0191.STR", + "STR/DE0186.STR", + "STR/DE0187.STR", + "STR/EIA4.STR", + "STR/EIPOLE.STR", + "STR/RARASECO.STR", + "STR/RARA2.STR", + "STR/DE0184.STR", + "STR/DE0181.STR", + "STR/PESEXT.STR", + "STR/DE0195.STR", + "STR/EIA2.STR", + "STR/FIR1.STR", + "STR/DE0182.STR", + "STR/BIR1.STR", + "STR/HAPOPEN.STR", + "STR/EITUBE.STR", + "STR/SCR1.STR", + "STR/DE0197.STR", + "STR/DE0193.STR", + "STR/EIA1.STR", + "STR/FAR2.STR", + "STR/FAR1.STR", + "STR/DE0199.STR", + "STR/GERMONEY.STR", + "STR/BIRESOLU.STR", + "STR/GARMONEY.STR", + "STR/BIADVENT.STR", + "STR/FUCRV1.STR", + "STR/BIREJECT.STR", + "STR/WAR1.STR", + "STR/BIACCEPT.STR", + "STR/SA3R1DEC.STR", + "STR/ASR1GENE.STR", + "STR/FIREJECT.STR", + "STR/GARRACE.STR", + "STR/GEZMONEY.STR", + "STR/LRFALLIN.STR", + "STR/EXR2.STR", + "STR/GERMOLES.STR", + "STR/FUCVICTO.STR", + "STR/MIR1ORBS.STR", + "STR/SA3R1RAM.STR", + "STR/AS2R1FLU.STR", + "STR/FUCV2.STR", + "STR/MIR1GNAW.STR", + "STR/GAZMONEY.STR", + "STR/AS3REMIN.STR", + "STR/SIHISA.STR", + "STR/FIACCEPT.STR", + "STR/FIWECO.STR", + "STR/FARESOLU.STR", + "STR/ASR1RBIK.STR", + "STR/MARDONAT.STR", + "STR/GAZRACE.STR", + "STR/FUCFV1.STR", + "STR/FUCV5.STR", + "STR/SABR1CDU.STR", + "STR/FLLINTRO.STR", + "STR/SAR1ECOR.STR", + "STR/AS2R1ROB.STR", + "STR/MIR2ORBS.STR", + "STR/MARBEAMS.STR", + "STR/LOI2.STR", + "STR/SAR1GENE.STR", + "STR/BILR1.STR", + "STR/AS2R1ROO.STR", + "STR/ASR1BESW.STR", + "STR/LOLOOP.STR", + "STR/FAINTROD.STR", + "STR/GEZMOLES.STR", + "STR/V1IN.STR", + "STR/FUCV4.STR", + "STR/SAIECORO.STR", + "STR/MIR1SWIT.STR", + "STR/LOINTRO.STR", + "STR/SAR2GENE.STR", + "STR/MUVICTOR.STR", + "STR/SAR1MCAN.STR", + "STR/FUCV7.STR", + "STR/MIZ1ORBS.STR", + "STR/FUCV8.STR", + "STR/BILR2.STR", + "STR/FUCV6.STR", + "STR/FUCV3.STR", + "STR/PLLBLOWU.STR", + "STR/PLBMAIN.STR", + "STR/WARESOLU.STR", + "STR/EIRACER.STR", + "STR/MAZDONAT.STR", + "STR/MAZBEAMS.STR", + "STR/MIISWITC.STR", + "STR/FIBRTVIL.STR", + "STR/FIBRTMIS.STR", + "STR/SABR1PAR.STR", + "STR/NDINTRO.STR", + "STR/GORDOWN.STR", + "STR/GORUP.STR", + "STR/SA3IRAMS.STR", + "STR/YERESOLU.STR", + "STR/EIFLUT.STR", + "STR/GRSDSACR.STR", + "STR/EXR1.STR", + "STR/SCRESOLU.STR", + "STR/FIRESOLU.STR", + "STR/SIHITEST.STR", + "STR/GAI1.STR", + "STR/EXRESOLU.STR", + "STR/MIZ2ORBS.STR", + "STR/ASIRBIKE.STR", + "STR/GRSOBBEC.STR", + "STR/BIINTROD.STR", + "STR/GRSOBBNC.STR", + "STR/AS2IROBB.STR", + "STR/GRSOBFIN.STR", + "STR/RERESOLU.STR", + "STR/BLRESOLU.STR", + "STR/SABIPARM.STR", + "STR/EVMEND.STR", + "STR/AS2RESOL.STR", + "STR/SAIMCANN.STR", + "STR/MIIGNAWE.STR", + "STR/GRSOBBA.STR", + "STR/GRSINTRO.STR", + "STR/SAISE.STR", + "STR/SA3IDECO.STR", + "STR/ASFRESOL.STR", + "STR/EXINTROD.STR", + "STR/BILINTRO.STR", + "STR/FIINTROD.STR", + "STR/MAINTROD.STR", + "STR/SCINTROD.STR", + "STR/AS2IFLUT.STR", + "STR/ASLERESO.STR", + "STR/ASLSRESO.STR", + "STR/AS2IROOM.STR", + "STR/GRSRESOL.STR", + "STR/SABICDUS.STR", + "STR/SIHISB.STR", + "STR/ASIBESWI.STR", + "STR/BILBRESO.STR", + "STR/FIBRT1AL.STR", + "STR/AS2INTRO.STR", + "STR/GEINTROD.STR", + "STR/SAISD1.STR", + "STR/SAISA.STR", + "STR/SIHISC.STR", + "STR/MIIORBS.STR", + "STR/WAINTROD.STR", + "STR/SAISD2.STR", + "STR/GRSOPREB.STR", + "STR/GRSOBBB.STR", + "STR/SA3INTRO.STR" + ], + + // some objects are directly stored as files on the DVD. This is just text files. + "object_file_names": [ + "TEXT/0COMMON.TXT", + "TEXT/1COMMON.TXT", + "TEXT/2COMMON.TXT", + "TEXT/3COMMON.TXT", + "TEXT/4COMMON.TXT", + "TEXT/5COMMON.TXT", + "TEXT/6COMMON.TXT" + ] +} diff --git a/decompiler/main.cpp b/decompiler/main.cpp index c91c533676..f58898d625 100644 --- a/decompiler/main.cpp +++ b/decompiler/main.cpp @@ -25,20 +25,20 @@ int main(int argc, char** argv) { } // collect all files to process - set_config(argv[1]); + auto config = read_config_file(argv[1]); std::string in_folder = argv[2]; std::string out_folder = argv[3]; std::vector dgos, objs, strs; - for (const auto& dgo_name : get_config().dgo_names) { + for (const auto& dgo_name : config.dgo_names) { dgos.push_back(file_util::combine_path(in_folder, dgo_name)); } - for (const auto& obj_name : get_config().object_file_names) { + for (const auto& obj_name : config.object_file_names) { objs.push_back(file_util::combine_path(in_folder, obj_name)); } - for (const auto& str_name : get_config().str_file_names) { + for (const auto& str_name : config.str_file_names) { strs.push_back(file_util::combine_path(in_folder, str_name)); } @@ -46,7 +46,7 @@ int main(int argc, char** argv) { // build file database lg::info("Setting up object file DB..."); - ObjectFileDB db(dgos, get_config().obj_file_name_map_file, objs, strs); + ObjectFileDB db(dgos, config.obj_file_name_map_file, objs, strs, config); // write out DGO file info file_util::write_text_file(file_util::combine_path(out_folder, "dgo.txt"), @@ -56,57 +56,58 @@ int main(int argc, char** argv) { db.generate_obj_listing()); // dump raw objs - if (get_config().dump_objs) { + if (config.dump_objs) { auto path = file_util::combine_path(out_folder, "raw_obj"); file_util::create_dir_if_needed(path); db.dump_raw_objects(path); } // process files (required for all analysis) - db.process_link_data(); - db.find_code(); + db.process_link_data(config); + db.find_code(config); db.process_labels(); // print disassembly - if (get_config().disassemble_code || get_config().disassemble_data) { - db.write_disassembly(out_folder, get_config().disassemble_data, get_config().disassemble_code); + if (config.disassemble_code || config.disassemble_data) { + db.write_disassembly(out_folder, config.disassemble_data, config.disassemble_code, + config.write_hex_near_instructions); } // regenerate all-types if needed - if (get_config().regenerate_all_types) { - db.analyze_functions_ir1(); + if (config.regenerate_all_types) { + db.analyze_functions_ir1(config); file_util::write_text_file(file_util::combine_path(out_folder, "type_defs.gc"), db.all_type_defs); } // main decompile. - if (get_config().decompile_code) { - db.analyze_functions_ir2(out_folder); + if (config.decompile_code) { + db.analyze_functions_ir2(out_folder, config); } // write out all symbols TODO - organize by file file_util::write_text_file(file_util::combine_path(out_folder, "all-syms.gc"), db.dts.dump_symbol_types()); - if (get_config().hexdump_code || get_config().hexdump_data) { - db.write_object_file_words(out_folder, get_config().hexdump_data, get_config().hexdump_code); + if (config.hexdump_code || config.hexdump_data) { + db.write_object_file_words(out_folder, config.hexdump_data, config.hexdump_code); } // data stuff - if (get_config().write_scripts) { + if (config.write_scripts) { db.find_and_write_scripts(out_folder); } - if (get_config().process_game_text) { + if (config.process_game_text) { auto result = db.process_game_text_files(); file_util::write_text_file(file_util::get_file_path({"assets", "game_text.txt"}), result); } - if (get_config().process_tpages) { + if (config.process_tpages) { db.process_tpages(); } - if (get_config().process_game_count) { + if (config.process_game_count) { auto result = db.process_game_count_file(); file_util::write_text_file(file_util::get_file_path({"assets", "game_count.txt"}), result); } diff --git a/scripts/shell/offline_test_git_branch.sh b/scripts/shell/offline_test_git_branch.sh index 2decbcf7b5..605a568f92 100755 --- a/scripts/shell/offline_test_git_branch.sh +++ b/scripts/shell/offline_test_git_branch.sh @@ -8,7 +8,6 @@ echo "=======================================" echo "" echo " ================= Cloning..." -cd ../.. ISO_DATA_PATH=${1} BRANCH_NAME=${2:-master} # Provide a default location to bind the ISO_DATA_PATH @@ -42,19 +41,22 @@ make -j echo " ================ Running unit tests..." ../test.sh +echo " ================ Running offline decompiler tests..." +./offline-test + echo " ================ Decompiling..." -../decomp.sh +../scripts/shell/decomp.sh echo " ================ Building assets..." -../gc.sh -cmd \(build-data\) +../scripts/shell/gc.sh -cmd \(build-data\) echo " ================ Checking assets..." -../check.sh +../scripts/shell/check.sh echo " ================ Building game..." -../gc.sh -cmd \(build-game\) +../scripts/shell/gc.sh -cmd \(build-game\) echo " ================ Booting game..." -../boot_game.sh +../scripts/shell/boot_game.sh echo "Offline test has completed successfully!" diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 727563f878..71a0d499e4 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -206,18 +206,19 @@ int main(int argc, char** argv) { class OfflineDecompilation : public ::testing::Test { protected: static std::unique_ptr db; + static std::unique_ptr config; static void SetUpTestCase() { // global setup file_util::init_crc(); decompiler::init_opcode_info(); - decompiler::set_config( - file_util::get_file_path({"decompiler", "config", "jak1_ntsc_black_label.jsonc"})); + config = std::make_unique(decompiler::read_config_file( + file_util::get_file_path({"decompiler", "config", "jak1_ntsc_black_label.jsonc"}))); std::unordered_set object_files; for (auto& p : g_object_files_to_decompile_or_ref_check) { object_files.insert(p.first); } - decompiler::get_config().allowed_objects = object_files; + config->allowed_objects = object_files; std::vector dgos = {"CGO/KERNEL.CGO", "CGO/ENGINE.CGO"}; std::vector dgo_paths; @@ -231,23 +232,27 @@ class OfflineDecompilation : public ::testing::Test { } } - db = std::make_unique( - dgo_paths, decompiler::get_config().obj_file_name_map_file, std::vector{}, - std::vector{}); + db = std::make_unique(dgo_paths, config->obj_file_name_map_file, + std::vector{}, + std::vector{}, *config); // basic processing to find functions/data/disassembly - db->process_link_data(); - db->find_code(); + db->process_link_data(*config); + db->find_code(*config); db->process_labels(); // fancy decompilation. - db->analyze_functions_ir2({}); + db->analyze_functions_ir2({}, *config); } - static void TearDownTestCase() { db.reset(); } + static void TearDownTestCase() { + db.reset(); + config.reset(); + } }; std::unique_ptr OfflineDecompilation::db; +std::unique_ptr OfflineDecompilation::config; /*! * Check that the most basic disassembly into files/functions/instructions has succeeded. @@ -263,7 +268,7 @@ TEST_F(OfflineDecompilation, CheckBasicDecode) { EXPECT_EQ(stats.n_fp_reg_use, stats.n_fp_reg_use_resolved); }); - EXPECT_EQ(obj_count, decompiler::get_config().allowed_objects.size()); + EXPECT_EQ(obj_count, config->allowed_objects.size()); } /*! @@ -302,7 +307,7 @@ TEST_F(OfflineDecompilation, FunctionDetect) { }); // one login per object file - EXPECT_EQ(decompiler::get_config().allowed_objects.size(), login_count); + EXPECT_EQ(config->allowed_objects.size(), login_count); // not many lambdas. EXPECT_TRUE(unknown_count < 10);