2020-09-13 21:32:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include <stdexcept>
|
2020-08-22 23:30:17 -04:00
|
|
|
#include <string>
|
2020-10-29 21:27:52 -04:00
|
|
|
#include <unordered_map>
|
2020-12-17 15:48:07 -05:00
|
|
|
#include <unordered_set>
|
2022-06-22 23:37:46 -04:00
|
|
|
#include <vector>
|
|
|
|
|
2020-08-22 23:30:17 -04:00
|
|
|
#include "BasicBlocks.h"
|
|
|
|
#include "CfgVtx.h"
|
2021-02-15 11:55:10 -05:00
|
|
|
#include "Warnings.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
|
|
|
#include "common/type_system/TypeSpec.h"
|
2021-08-17 20:54:03 -04:00
|
|
|
#include "common/type_system/state.h"
|
2020-09-29 20:24:15 -04:00
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "decompiler/Disasm/Instruction.h"
|
|
|
|
#include "decompiler/Disasm/Register.h"
|
|
|
|
#include "decompiler/analysis/atomic_op_builder.h"
|
|
|
|
#include "decompiler/config.h"
|
|
|
|
|
2021-01-06 20:04:15 -05:00
|
|
|
namespace decompiler {
|
2020-09-29 20:24:15 -04:00
|
|
|
class DecompilerTypeSystem;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
|
|
|
struct FunctionName {
|
|
|
|
enum class FunctionKind {
|
2020-08-26 01:21:33 -04:00
|
|
|
UNIDENTIFIED, // hasn't been identified yet.
|
|
|
|
GLOBAL, // global named function
|
2020-08-22 23:30:17 -04:00
|
|
|
METHOD,
|
2021-08-17 20:54:03 -04:00
|
|
|
NV_STATE,
|
|
|
|
V_STATE,
|
|
|
|
TOP_LEVEL_INIT
|
2020-08-22 23:30:17 -04:00
|
|
|
} kind = FunctionKind::UNIDENTIFIED;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
std::string function_name; // only applicable for GLOBAL
|
2021-08-17 20:54:03 -04:00
|
|
|
std::string type_name; // only applicable for METHOD or v state
|
|
|
|
std::string state_name; // for nv state or v state
|
|
|
|
StateHandler handler_kind; // for nv state or v state
|
2020-08-26 01:21:33 -04:00
|
|
|
int method_id = -1; // only applicable for METHOD
|
2020-10-11 18:27:44 -04:00
|
|
|
int unique_id = -1;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
2020-10-24 14:27:50 -04:00
|
|
|
int id_in_object = -1;
|
|
|
|
std::string object_name;
|
|
|
|
|
2020-08-22 23:30:17 -04:00
|
|
|
std::string to_string() const {
|
2020-08-26 01:21:33 -04:00
|
|
|
switch (kind) {
|
2020-08-22 23:30:17 -04:00
|
|
|
case FunctionKind::GLOBAL:
|
|
|
|
return function_name;
|
|
|
|
case FunctionKind::METHOD:
|
|
|
|
return "(method " + std::to_string(method_id) + " " + type_name + ")";
|
|
|
|
case FunctionKind::TOP_LEVEL_INIT:
|
2021-07-01 21:38:19 -04:00
|
|
|
return "(top-level-login " + object_name + ")";
|
2020-08-22 23:30:17 -04:00
|
|
|
case FunctionKind::UNIDENTIFIED:
|
2020-10-24 14:27:50 -04:00
|
|
|
return "(anon-function " + std::to_string(id_in_object) + " " + object_name + ")";
|
2021-08-17 20:54:03 -04:00
|
|
|
case FunctionKind::NV_STATE:
|
|
|
|
return fmt::format("({} {})", handler_kind_to_name(handler_kind), state_name);
|
|
|
|
case FunctionKind::V_STATE:
|
|
|
|
return fmt::format("({} {} {})", handler_kind_to_name(handler_kind), state_name, type_name);
|
2020-08-22 23:30:17 -04:00
|
|
|
default:
|
2020-09-13 21:10:43 -04:00
|
|
|
throw std::runtime_error("Unsupported FunctionKind");
|
2020-08-22 23:30:17 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-26 11:09:59 -05:00
|
|
|
int get_anon_id() const {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(kind == FunctionKind::UNIDENTIFIED);
|
2020-12-26 11:09:59 -05:00
|
|
|
return id_in_object;
|
|
|
|
}
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
bool empty() const { return kind == FunctionKind::UNIDENTIFIED; }
|
2020-08-22 23:30:17 -04:00
|
|
|
|
2022-11-12 17:56:07 -05:00
|
|
|
bool is_handler() const {
|
|
|
|
return kind == FunctionKind::NV_STATE || kind == FunctionKind::V_STATE;
|
|
|
|
}
|
|
|
|
bool is_handler(StateHandler shk) const { return is_handler() && handler_kind == shk; }
|
|
|
|
|
|
|
|
bool is_event_handler() const { return is_handler(StateHandler::EVENT); }
|
|
|
|
|
2021-07-01 21:38:19 -04:00
|
|
|
void set_as_top_level(const std::string& object_file_name) {
|
|
|
|
kind = FunctionKind::TOP_LEVEL_INIT;
|
|
|
|
object_name = object_file_name;
|
|
|
|
}
|
2020-08-22 23:30:17 -04:00
|
|
|
|
|
|
|
void set_as_global(std::string name) {
|
|
|
|
kind = FunctionKind::GLOBAL;
|
|
|
|
function_name = std::move(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_as_method(std::string tn, int id) {
|
|
|
|
kind = FunctionKind::METHOD;
|
|
|
|
type_name = std::move(tn);
|
|
|
|
method_id = id;
|
|
|
|
}
|
2021-08-17 20:54:03 -04:00
|
|
|
|
|
|
|
void set_as_nv_state(const std::string& state, StateHandler hk) {
|
|
|
|
state_name = state;
|
|
|
|
handler_kind = hk;
|
|
|
|
kind = FunctionKind::NV_STATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_as_v_state(const std::string& type, const std::string& state, StateHandler hk) {
|
|
|
|
state_name = state;
|
|
|
|
handler_kind = hk;
|
|
|
|
kind = FunctionKind::V_STATE;
|
|
|
|
type_name = type;
|
|
|
|
}
|
2020-08-22 23:30:17 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class Function {
|
|
|
|
public:
|
2022-06-25 21:26:15 -04:00
|
|
|
Function(int _start_word, int _end_word, GameVersion version);
|
2021-01-24 16:39:15 -05:00
|
|
|
~Function();
|
2020-08-22 23:30:17 -04:00
|
|
|
void analyze_prologue(const LinkedObjectFile& file);
|
2020-09-29 20:24:15 -04:00
|
|
|
void find_global_function_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts);
|
2020-10-24 22:51:40 -04:00
|
|
|
void find_method_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts);
|
|
|
|
void find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts);
|
2020-09-29 20:24:15 -04:00
|
|
|
bool instr_starts_basic_op(int idx);
|
2021-01-09 20:01:48 -05:00
|
|
|
bool instr_starts_atomic_op(int idx);
|
|
|
|
const AtomicOp& get_atomic_op_at_instr(int idx);
|
2020-11-28 15:35:38 -05:00
|
|
|
BlockTopologicalSort bb_topo_sort();
|
2021-09-11 20:52:35 -04:00
|
|
|
std::string name() const;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
2020-10-23 17:20:04 -04:00
|
|
|
TypeSpec type;
|
|
|
|
|
2020-08-22 23:30:17 -04:00
|
|
|
int segment = -1;
|
|
|
|
int start_word = -1;
|
|
|
|
int end_word = -1; // not inclusive, but does include padding.
|
|
|
|
|
|
|
|
FunctionName guessed_name;
|
2022-10-29 16:08:04 -04:00
|
|
|
std::string state_handler_as_anon_func;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
|
|
|
bool suspected_asm = false;
|
2020-10-24 22:51:40 -04:00
|
|
|
bool is_inspect_method = false;
|
|
|
|
std::string method_of_type;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
|
|
|
std::vector<Instruction> instructions;
|
|
|
|
std::vector<BasicBlock> basic_blocks;
|
|
|
|
std::shared_ptr<ControlFlowGraph> cfg = nullptr;
|
2021-05-12 15:54:33 -04:00
|
|
|
bool cfg_ok = false;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
|
|
|
int prologue_start = -1;
|
|
|
|
int prologue_end = -1;
|
|
|
|
|
|
|
|
int epilogue_start = -1;
|
|
|
|
int epilogue_end = -1;
|
|
|
|
|
2021-02-15 11:55:10 -05:00
|
|
|
DecompWarnings warnings;
|
|
|
|
|
2020-10-11 18:27:44 -04:00
|
|
|
bool contains_asm_ops = false;
|
2020-08-22 23:30:17 -04:00
|
|
|
|
2020-11-28 15:35:38 -05:00
|
|
|
bool attempted_type_analysis = false;
|
|
|
|
|
2020-08-22 23:30:17 -04:00
|
|
|
struct Prologue {
|
|
|
|
bool decoded = false; // have we removed the prologue from basic blocks?
|
|
|
|
int total_stack_usage = -1;
|
|
|
|
|
|
|
|
// ra/fp are treated differently from other register backups
|
|
|
|
bool ra_backed_up = false;
|
|
|
|
int ra_backup_offset = -1;
|
|
|
|
|
|
|
|
bool fp_backed_up = false;
|
|
|
|
int fp_backup_offset = -1;
|
|
|
|
|
|
|
|
bool fp_set = false;
|
|
|
|
|
|
|
|
int n_gpr_backup = 0;
|
|
|
|
int gpr_backup_offset = -1;
|
|
|
|
|
|
|
|
int n_fpr_backup = 0;
|
|
|
|
int fpr_backup_offset = -1;
|
|
|
|
|
|
|
|
int n_stack_var_bytes = 0;
|
|
|
|
int stack_var_offset = -1;
|
|
|
|
|
|
|
|
bool epilogue_ok = false;
|
|
|
|
|
|
|
|
std::string to_string(int indent = 0) const;
|
|
|
|
|
|
|
|
} prologue;
|
|
|
|
|
|
|
|
bool uses_fp_register = false;
|
|
|
|
|
2021-01-09 20:01:48 -05:00
|
|
|
struct {
|
|
|
|
bool atomic_ops_attempted = false;
|
|
|
|
bool atomic_ops_succeeded = false;
|
|
|
|
std::shared_ptr<FunctionAtomicOps> atomic_ops = nullptr;
|
|
|
|
Env env;
|
2021-01-24 16:39:15 -05:00
|
|
|
std::shared_ptr<FormPool> form_pool = nullptr;
|
2021-01-17 18:08:18 -05:00
|
|
|
Form* top_form = nullptr;
|
2021-01-22 20:50:37 -05:00
|
|
|
std::string debug_form_string;
|
|
|
|
bool print_debug_forms = false;
|
2021-03-03 15:42:55 -05:00
|
|
|
bool expressions_succeeded = false;
|
2021-01-09 20:01:48 -05:00
|
|
|
} ir2;
|
|
|
|
|
2021-09-11 20:52:35 -04:00
|
|
|
std::optional<std::string> mips2c_output;
|
|
|
|
|
2021-05-31 10:43:25 -04:00
|
|
|
std::vector<std::string> types_defined;
|
|
|
|
|
2020-08-22 23:30:17 -04:00
|
|
|
private:
|
|
|
|
void check_epilogue(const LinkedObjectFile& file);
|
2021-03-22 20:04:00 -04:00
|
|
|
void resize_first_block(int new_start, const LinkedObjectFile& file);
|
2020-09-29 20:24:15 -04:00
|
|
|
std::unordered_map<int, int> instruction_to_basic_op;
|
|
|
|
std::unordered_map<int, int> basic_op_to_instruction;
|
2020-08-22 23:30:17 -04:00
|
|
|
};
|
2021-01-06 20:04:15 -05:00
|
|
|
} // namespace decompiler
|