mirror of
https://github.com/open-goal/jak-project
synced 2026-05-23 06:54:31 -04:00
[decompiler] Jak 2 modifications, new all-types code (#1553)
* temp * look at old game types * clean up
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user