[decompiler] Jak 2 modifications, new all-types code (#1553)

* temp

* look at old game types

* clean up
This commit is contained in:
water111
2022-06-25 21:26:15 -04:00
committed by GitHub
parent c9de15ba64
commit 91fa0122d8
40 changed files with 1762 additions and 586 deletions
+2 -2
View File
@@ -400,7 +400,7 @@ void LinkedObjectFile::find_code() {
/*!
* Find all the functions in each segment.
*/
void LinkedObjectFile::find_functions() {
void LinkedObjectFile::find_functions(GameVersion version) {
if (segments == 1) {
// it's a v2 file, shouldn't have any functions
ASSERT(offset_of_data_zone_by_seg.at(0) == 0);
@@ -427,7 +427,7 @@ void LinkedObjectFile::find_functions() {
// mark this as a function, and try again from the current function start
ASSERT(found_function_tag_loc);
stats.function_count++;
functions_by_seg.at(seg).emplace_back(function_tag_loc, function_end);
functions_by_seg.at(seg).emplace_back(function_tag_loc, function_end, version);
function_end = function_tag_loc;
}
+1 -1
View File
@@ -52,7 +52,7 @@ class LinkedObjectFile {
uint32_t set_ordered_label_names();
void find_code();
std::string print_words();
void find_functions();
void find_functions(GameVersion version);
void disassemble_functions();
void process_fp_relative_links();
std::string print_scripts();
+1 -1
View File
@@ -589,7 +589,7 @@ void ObjectFileDB::find_code(const Config& config) {
for_each_obj([&](ObjectFileData& obj) {
// printf("fc %s\n", obj.record.to_unique_name().c_str());
obj.linked_data.find_code();
obj.linked_data.find_functions();
obj.linked_data.find_functions(config.game_version);
obj.linked_data.disassemble_functions();
if (config.game_version == GameVersion::Jak1 || obj.to_unique_name() != "effect-control-v0") {
+3 -1
View File
@@ -158,7 +158,6 @@ class ObjectFileDB {
void extract_art_info();
void dump_art_info(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,
@@ -192,6 +191,9 @@ class ObjectFileDB {
void ir2_do_segment_analysis_phase2(int seg, const Config& config, ObjectFileData& data);
void ir2_setup_labels(const Config& config, ObjectFileData& data);
void ir2_run_mips2c(const Config& config, ObjectFileData& data);
void ir2_analyze_all_types(const std::string& output_file,
const std::optional<std::string>& previous_game_types,
const std::unordered_set<std::string>& bad_types);
std::string ir2_to_file(ObjectFileData& data, const Config& config);
std::string ir2_function_to_string(ObjectFileData& data, Function& function, int seg);
std::string ir2_final_out(ObjectFileData& data,
+73 -19
View File
@@ -12,6 +12,7 @@
#include "common/util/Timer.h"
#include "decompiler/IR2/Form.h"
#include "decompiler/analysis/analyze_inspect_method.h"
#include "decompiler/analysis/cfg_builder.h"
#include "decompiler/analysis/expression_build.h"
#include "decompiler/analysis/final_output.h"
@@ -103,7 +104,22 @@ void ObjectFileDB::analyze_functions_ir2(
data.full_output = ir2_final_out(data, imports, {});
}
for_each_function_def_order_in_obj(data, [&](Function& f, int) { f.ir2 = {}; });
if (!config.generate_all_types) {
// this frees ir2 memory, but means future passes can't look back on this function.
for_each_function_def_order_in_obj(data, [&](Function& f, int) { f.ir2 = {}; });
} else {
for_each_function_def_order_in_obj(data, [&](Function& f, int seg) {
if (seg == 0) {
return; // keep top-levels
}
if (f.guessed_name.kind == FunctionName::FunctionKind::METHOD &&
f.guessed_name.method_id == GOAL_INSPECT_METHOD) {
return; // keep inspects
}
// otherwise free memory
f.ir2 = {};
});
}
fmt::print("Done in {:.2f}ms\n", file_timer.getMs());
});
@@ -280,6 +296,61 @@ void ObjectFileDB::ir2_top_level_pass(const Config& config) {
lg::info("{:4d} logins {:.2f}%\n", total_top_levels, 100.f * total_top_levels / total_functions);
}
void ObjectFileDB::ir2_analyze_all_types(const std::string& output_file,
const std::optional<std::string>& previous_game_types,
const std::unordered_set<std::string>& bad_types) {
struct PerObject {
std::string object_name;
std::vector<std::string> type_defs;
std::string symbol_defs;
};
std::vector<PerObject> per_object;
DecompilerTypeSystem previous_game_ts;
if (previous_game_types) {
previous_game_ts.parse_type_defs({*previous_game_types});
}
std::unordered_set<std::string> already_seen;
for_each_obj([&](ObjectFileData& data) {
if (data.obj_version != 3) {
return;
}
auto& object_result = per_object.emplace_back();
object_result.object_name = data.to_unique_name();
for_each_function_def_order_in_obj(data, [&](Function& f, int seg) {
if (seg == TOP_LEVEL_SEGMENT) {
object_result.symbol_defs += inspect_top_level_symbol_defines(
already_seen, f, data.linked_data, dts, previous_game_ts);
} else {
if (f.is_inspect_method && bad_types.find(f.guessed_name.type_name) == bad_types.end()) {
object_result.type_defs.push_back(inspect_inspect_method(
f, f.guessed_name.type_name, dts, data.linked_data, previous_game_ts.ts));
}
}
});
});
std::string result;
result += ";; All Types\n\n";
for (auto& obj : per_object) {
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
result += fmt::format(";; {:30s} ;;\n", obj.object_name);
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");
for (auto& t : obj.type_defs) {
result += t;
result += "\n";
}
result += obj.symbol_defs;
result += "\n";
}
file_util::write_text_file(output_file, result);
}
/*!
* Initial Function Analysis Pass to build the control flow graph.
* - Find basic blocks
@@ -322,7 +393,7 @@ void ObjectFileDB::ir2_basic_block_pass(int seg, const Config& config, ObjectFil
asm_br_blocks = asm_lookup->second;
}
func.cfg = build_cfg(data.linked_data, seg, func, hack, asm_br_blocks);
func.cfg = build_cfg(data.linked_data, seg, func, hack, asm_br_blocks, config.game_version);
if (!func.cfg->is_fully_resolved()) {
lg::warn("Function {} from {} failed to build control flow graph!", func.name(),
data.to_unique_name());
@@ -548,23 +619,6 @@ void ObjectFileDB::ir2_cfg_build_pass(int seg, ObjectFileData& data) {
});
}
// void ObjectFileDB::ir2_store_current_forms(int seg) {
// Timer timer;
// int total = 0;
//
// for_each_function_in_seg(seg, [&](Function& func, ObjectFileData& data) {
// (void)data;
//
// if (func.ir2.top_form) {
// total++;
// func.ir2.debug_form_string =
// pretty_print::to_string(func.ir2.top_form->to_form(func.ir2.env));
// }
// });
//
// lg::info("Stored debug forms for {} functions in {:.2f} ms\n", total, timer.getMs());
//}
//
void ObjectFileDB::ir2_build_expressions(int seg, const Config& config, ObjectFileData& data) {
for_each_function_in_seg_in_obj(seg, data, [&](Function& func) {
(void)data;