mirror of
https://github.com/open-goal/jak-project
synced 2026-08-05 01:30:22 -04:00
Add prototype decompiler GUI (#93)
* json output for basic ops * add prototype gui * add some more fields and layout the gui a little bit nicer
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "LinkedObjectFile.h"
|
||||
#include "decompiler/Disasm/InstructionDecode.h"
|
||||
#include "decompiler/config.h"
|
||||
#include "third-party/json.hpp"
|
||||
|
||||
/*!
|
||||
* Set the number of segments in this object file.
|
||||
@@ -504,6 +505,70 @@ void LinkedObjectFile::process_fp_relative_links() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string LinkedObjectFile::to_asm_json() {
|
||||
nlohmann::json data;
|
||||
std::vector<nlohmann::json::object_t> functions;
|
||||
|
||||
std::unordered_map<std::string, int> functions_seen;
|
||||
for (int seg = segments; seg-- > 0;) {
|
||||
for (size_t fi = functions_by_seg.at(seg).size(); fi--;) {
|
||||
auto& func = functions_by_seg.at(seg).at(fi);
|
||||
auto fname = func.guessed_name.to_string();
|
||||
if (functions_seen.find(fname) != functions_seen.end()) {
|
||||
printf("duplicated %s\n", fname.c_str()); // todo - this needs fixing
|
||||
functions_seen[fname]++;
|
||||
fname += "-v" + std::to_string(functions_seen[fname]);
|
||||
} else {
|
||||
functions_seen[fname] = 0;
|
||||
}
|
||||
|
||||
nlohmann::json::object_t f;
|
||||
f["name"] = fname;
|
||||
f["type"] = func.type.print();
|
||||
f["segment"] = seg;
|
||||
f["warnings"] = func.warnings;
|
||||
std::vector<nlohmann::json::object_t> ops;
|
||||
|
||||
for (int i = 1; i < func.end_word - func.start_word; i++) {
|
||||
nlohmann::json::object_t op;
|
||||
auto label_id = get_label_at(seg, (func.start_word + i) * 4);
|
||||
if (label_id != -1) {
|
||||
op["label"] = labels.at(label_id).name;
|
||||
}
|
||||
auto& instr = func.instructions.at(i);
|
||||
op["id"] = i;
|
||||
op["asm_op"] = instr.to_string(*this);
|
||||
|
||||
if (func.has_basic_ops() && func.instr_starts_basic_op(i)) {
|
||||
op["basic_op"] = func.get_basic_op_at_instr(i)->print(*this);
|
||||
if (func.has_typemaps()) {
|
||||
auto& tm = func.get_typemap_by_instr_idx(i);
|
||||
auto& json_type_map = op["type_map"];
|
||||
for (auto& kv : tm) {
|
||||
json_type_map[kv.first.to_charp()] = kv.second.print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int iidx = 0; iidx < instr.n_src; iidx++) {
|
||||
if (instr.get_src(iidx).is_label()) {
|
||||
auto lab = labels.at(instr.get_src(iidx).get_label());
|
||||
if (is_string(lab.target_segment, lab.offset)) {
|
||||
op["referenced_string"] = get_goal_string(lab.target_segment, lab.offset / 4 - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ops.push_back(op);
|
||||
}
|
||||
f["asm"] = ops;
|
||||
functions.push_back(f);
|
||||
}
|
||||
}
|
||||
data["functions"] = functions;
|
||||
return data.dump();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Print disassembled functions and data segments.
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,7 @@ class LinkedObjectFile {
|
||||
std::string print_disassembly();
|
||||
bool has_any_functions();
|
||||
void append_word_to_string(std::string& dest, const LinkedWord& word) const;
|
||||
std::string to_asm_json();
|
||||
|
||||
struct Stats {
|
||||
uint32_t total_code_bytes = 0;
|
||||
|
||||
@@ -324,7 +324,7 @@ std::string pad_string(const std::string& in, size_t length) {
|
||||
} // namespace
|
||||
|
||||
std::string ObjectFileDB::generate_obj_listing() {
|
||||
std::string result;
|
||||
std::string result = "[";
|
||||
std::set<std::string> all_unique_names;
|
||||
int unique_count = 0;
|
||||
for (auto& obj_file : obj_file_order) {
|
||||
@@ -348,7 +348,9 @@ std::string ObjectFileDB::generate_obj_listing() {
|
||||
// this check is extremely important. It makes sure we don't have any repeat names. This could
|
||||
// be caused by two files with the same name, in the same DGOs, but different data.
|
||||
assert(int(all_unique_names.size()) == unique_count);
|
||||
return result;
|
||||
result.pop_back(); // kill last new line
|
||||
result.pop_back(); // kill last comma
|
||||
return result + "]";
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -447,9 +449,14 @@ void ObjectFileDB::write_disassembly(const std::string& output_dir,
|
||||
if (obj.linked_data.has_any_functions() || disassemble_objects_without_functions) {
|
||||
auto file_text = obj.linked_data.print_disassembly();
|
||||
auto file_name = combine_path(output_dir, obj.record.to_unique_name() + ".func");
|
||||
total_bytes += file_text.size();
|
||||
|
||||
auto json_asm_text = obj.linked_data.to_asm_json();
|
||||
auto json_asm_file_name = combine_path(output_dir, obj.to_unique_name() + "_asm.json");
|
||||
file_util::write_text_file(json_asm_file_name, json_asm_text);
|
||||
|
||||
total_bytes += file_text.size() + json_asm_text.size();
|
||||
file_util::write_text_file(file_name, file_text);
|
||||
total_files++;
|
||||
total_files += 2;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -655,6 +662,7 @@ void ObjectFileDB::analyze_functions() {
|
||||
assert(false);
|
||||
}
|
||||
// GOOD!
|
||||
func.type = kv->second;
|
||||
spdlog::info("Type Analysis on {} {}", func.guessed_name.to_string(),
|
||||
kv->second.print());
|
||||
func.run_type_analysis(kv->second, dts, data.linked_data);
|
||||
|
||||
Reference in New Issue
Block a user