Recognize auto-generated inspect methods and create deftypes from them (#95)

- Recognize new type definitions/parents/type flags in the decompiler
- Analyze autogenerated inspect methods and dump guesses at fields to a file
- Utility functions for accessing static data by label
- Better ordering in the decompiler to go through functions in the order they appeared in the source
- Added a decent number of types to `all-types.gc` based on the new field analyzer
- Correct a few `int`/`integer` mistakes in `gcommon.gc` (this should really be a warning)
- Correct a few type issues in `gcommon` and `gkernel-h`
- Option in the decompiler to be strict about `define-extern` redefining a type of a symbol
- Add a test to check consistency in types between `all-types.gc` (used by decompiler) and `goal_src` (used by the compiler)
This commit is contained in:
water111
2020-10-24 22:51:40 -04:00
committed by GitHub
parent b561cdfade
commit b56025412b
23 changed files with 3363 additions and 82 deletions
+106 -1
View File
@@ -5,6 +5,7 @@
#include "decompiler/Disasm/InstructionMatching.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
#include "decompiler/util/DecompilerTypeSystem.h"
#include "TypeInspector.h"
namespace {
std::vector<Register> gpr_backups = {make_gpr(Reg::GP), make_gpr(Reg::S5), make_gpr(Reg::S4),
@@ -474,7 +475,8 @@ void Function::find_global_function_defs(LinkedObjectFile& file, DecompilerTypeS
* Look through this function to find calls to method-set! which define methods.
* Updates the guessed_name of the function and updates type_info.
*/
void Function::find_method_defs(LinkedObjectFile& file) {
void Function::find_method_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts) {
(void)dts;
int state = 0;
int label_id = -1;
int method_id = -1;
@@ -546,6 +548,11 @@ void Function::find_method_defs(LinkedObjectFile& file) {
auto& func = file.get_function_at_label(label_id);
assert(func.guessed_name.empty());
func.guessed_name.set_as_method(type_name, method_id);
func.method_of_type = type_name;
if (method_id == GOAL_INSPECT_METHOD) {
func.is_inspect_method = true;
}
state = 0;
continue;
}
@@ -553,6 +560,104 @@ void Function::find_method_defs(LinkedObjectFile& file) {
}
}
void Function::find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts) {
int state = 0;
Register temp_reg;
std::string type_name;
std::string parent_type;
int label_idx = -1;
for (const auto& instr : instructions) {
// look for lw xx, type(s7)
if (instr.kind == InstructionKind::LW && instr.get_src(0).kind == InstructionAtom::IMM_SYM &&
instr.get_src(0).get_sym() == "type" && instr.get_src(1).get_reg() == make_gpr(Reg::S7)) {
state = 1;
temp_reg = instr.get_dst(0).get_reg();
continue;
}
if (state == 1) {
// look for lwu t9, 16, v1
if (instr.kind == InstructionKind::LWU && instr.get_dst(0).get_reg() == make_gpr(Reg::T9) &&
instr.get_src(0).get_imm() == 16 && instr.get_src(1).get_reg() == temp_reg) {
state = 2;
continue;
} else {
state = 0;
}
}
if (state == 2) {
// look for daddiu a0, s7, name-of-type
if (instr.kind == InstructionKind::DADDIU &&
instr.get_dst(0).get_reg() == make_gpr(Reg::A0) &&
instr.get_src(0).get_reg() == make_gpr(Reg::S7) && instr.get_src(1).is_sym()) {
state = 3;
type_name = instr.get_src(1).get_sym();
continue;
} else {
state = 0;
}
}
if (state == 3) {
// look for lw a1, parent-type(s7)
if (instr.kind == InstructionKind::LW && instr.get_dst(0).get_reg() == make_gpr(Reg::A1) &&
instr.get_src(0).kind == InstructionAtom::IMM_SYM &&
instr.get_src(1).get_reg() == make_gpr(Reg::S7)) {
state = 4;
parent_type = instr.get_src(0).get_sym();
continue;
} else {
state = 0;
}
}
if (state == 4) {
// look for ld a2, LXX(fp)
if (instr.kind == InstructionKind::LD && instr.get_dst(0).get_reg() == make_gpr(Reg::A2) &&
instr.get_src(0).is_label() && instr.get_src(1).get_reg() == make_gpr(Reg::FP)) {
state = 5;
label_idx = instr.get_src(0).get_label();
continue;
} else {
state = 0;
}
}
if (state == 5) {
if (instr.kind == InstructionKind::JALR && instr.get_dst(0).get_reg() == make_gpr(Reg::RA) &&
instr.get_src(0).get_reg() == make_gpr(Reg::T9)) {
state = 6;
continue;
} else {
state = 0;
}
}
if (state == 6) {
// look for sll v0, ra, 0
if (instr.kind == InstructionKind::SLL && instr.get_dst(0).get_reg() == make_gpr(Reg::V0) &&
instr.get_src(0).get_reg() == make_gpr(Reg::RA) && instr.get_src(1).get_imm() == 0) {
// done!
// fmt::print("Got type {} parent {}\n", type_name, parent_type);
dts.add_type_parent(type_name, parent_type);
Label flag_label = file.labels.at(label_idx);
u64 word = file.read_data_word(flag_label);
flag_label.offset += 4;
u64 word2 = file.read_data_word(flag_label);
word |= (word2 << 32);
dts.add_type_flags(type_name, word);
// fmt::print("Flags are 0x{:x}\n", word);
state = 0;
continue;
}
} else {
state = 0;
}
}
}
void Function::add_basic_op(std::shared_ptr<IR> op, int start_instr, int end_instr) {
op->is_basic_op = true;
assert(end_instr > start_instr);