mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 22:22:21 -04:00
[Decompiler, Game] Run type prop on gstring (#168)
* run type prop on gstring * add types-h * new settings * cmake switch * down to 4 failing functions * clang format
This commit is contained in:
+6
-1
@@ -1,5 +1,10 @@
|
||||
# Top Level CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
if (UNIX)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
else ()
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
endif ()
|
||||
|
||||
project(jak)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug")
|
||||
|
||||
@@ -732,6 +732,10 @@ void TypeSystem::add_builtin_types() {
|
||||
builtin_structure_inherit(string_type);
|
||||
add_field_to_type(string_type, "allocated-length", make_typespec("int32")); // todo integer type
|
||||
add_field_to_type(string_type, "data", make_typespec("uint8"), false, true); // todo integer type
|
||||
// string is never deftype'd for the decompiler, so we need to manually give the constructor
|
||||
// type here.
|
||||
add_method(string_type, "new",
|
||||
make_function_typespec({"symbol", "type", "int", "string"}, "_type_"));
|
||||
|
||||
// FUNCTION
|
||||
builtin_structure_inherit(function_type);
|
||||
|
||||
@@ -50,6 +50,11 @@ struct FunctionName {
|
||||
}
|
||||
}
|
||||
|
||||
int get_anon_id() const {
|
||||
assert(kind == FunctionKind::UNIDENTIFIED);
|
||||
return id_in_object;
|
||||
}
|
||||
|
||||
bool empty() const { return kind == FunctionKind::UNIDENTIFIED; }
|
||||
|
||||
void set_as_top_level() { kind = FunctionKind::TOP_LEVEL_INIT; }
|
||||
|
||||
@@ -15,6 +15,9 @@ TypeState construct_initial_typestate(const TypeSpec& f_ts) {
|
||||
auto reg_type = f_ts.get_arg(i);
|
||||
result.gpr_types[reg_id] = TP_Type::make_from_typespec(reg_type);
|
||||
}
|
||||
|
||||
// todo, more specific process types for behaviors.
|
||||
result.gpr_types[Reg::S6] = TP_Type::make_from_typespec(TypeSpec("process"));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "decompiler/Function/BasicBlocks.h"
|
||||
#include "decompiler/Disasm/InstructionMatching.h"
|
||||
#include "decompiler/IR/IR.h"
|
||||
#include "common/symbols.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -753,6 +754,13 @@ std::shared_ptr<IR_Atomic> try_daddiu(Instruction& instr, int idx) {
|
||||
op->write_regs.push_back(instr.get_dst(0).get_reg());
|
||||
op->reg_info_set = true;
|
||||
return op;
|
||||
} else if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::S7)) &&
|
||||
instr.get_src(1).is_imm() && instr.get_src(1).get_imm() == FIX_SYM_TRUE) {
|
||||
auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx),
|
||||
std::make_shared<IR_Symbol>("#t"));
|
||||
op->write_regs.push_back(instr.get_dst(0).get_reg());
|
||||
op->reg_info_set = true;
|
||||
return op;
|
||||
} else if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::FP)) &&
|
||||
instr.get_src(1).kind == InstructionAtom::LABEL) {
|
||||
auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx),
|
||||
@@ -1032,14 +1040,42 @@ std::shared_ptr<IR_Atomic> try_sw(Instruction& instr, int idx) {
|
||||
|
||||
std::shared_ptr<IR_Atomic> try_sb(Instruction& instr, int idx) {
|
||||
if (instr.kind == InstructionKind::SB && instr.get_src(1).is_imm()) {
|
||||
auto op = std::make_shared<IR_Store_Atomic>(
|
||||
IR_Store_Atomic::INTEGER,
|
||||
std::make_shared<IR_IntMath2>(
|
||||
IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx),
|
||||
std::make_shared<IR_IntegerConstant>(instr.get_src(1).get_imm())),
|
||||
make_reg(instr.get_src(0).get_reg(), idx), 1);
|
||||
op->update_reginfo_self(0, 2, 0);
|
||||
return op;
|
||||
if (instr.get_src(1).get_imm() == 0) {
|
||||
if (instr.get_src(0).is_reg(make_gpr(Reg::R0))) {
|
||||
auto op = std::make_shared<IR_Store_Atomic>(IR_Store_Atomic::INTEGER,
|
||||
make_reg(instr.get_src(2).get_reg(), idx),
|
||||
std::make_shared<IR_IntegerConstant>(0), 1);
|
||||
op->update_reginfo_self(0, 1, 0);
|
||||
return op;
|
||||
} else {
|
||||
auto op = std::make_shared<IR_Store_Atomic>(IR_Store_Atomic::INTEGER,
|
||||
make_reg(instr.get_src(2).get_reg(), idx),
|
||||
make_reg(instr.get_src(0).get_reg(), idx), 1);
|
||||
op->update_reginfo_self(0, 2, 0);
|
||||
return op;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (instr.get_src(0).is_reg(make_gpr(Reg::R0))) {
|
||||
auto op = std::make_shared<IR_Store_Atomic>(
|
||||
IR_Store_Atomic::INTEGER,
|
||||
std::make_shared<IR_IntMath2>(
|
||||
IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx),
|
||||
std::make_shared<IR_IntegerConstant>(instr.get_src(1).get_imm())),
|
||||
std::make_shared<IR_IntegerConstant>(0), 1);
|
||||
op->update_reginfo_self(0, 1, 0);
|
||||
return op;
|
||||
} else {
|
||||
auto op = std::make_shared<IR_Store_Atomic>(
|
||||
IR_Store_Atomic::INTEGER,
|
||||
std::make_shared<IR_IntMath2>(
|
||||
IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx),
|
||||
std::make_shared<IR_IntegerConstant>(instr.get_src(1).get_imm())),
|
||||
make_reg(instr.get_src(0).get_reg(), idx), 1);
|
||||
op->update_reginfo_self(0, 2, 0);
|
||||
return op;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1169,6 +1205,7 @@ std::shared_ptr<IR_Atomic> try_movn(Instruction& instr, int idx) {
|
||||
op->write_regs.push_back(dst);
|
||||
op->read_regs.push_back(src);
|
||||
op->reg_info_set = true;
|
||||
return op;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1182,6 +1219,7 @@ std::shared_ptr<IR_Atomic> try_movz(Instruction& instr, int idx) {
|
||||
op->write_regs.push_back(dst);
|
||||
op->read_regs.push_back(src);
|
||||
op->reg_info_set = true;
|
||||
return op;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1982,7 +2020,7 @@ std::shared_ptr<IR_Atomic> try_lwu(Instruction& i0,
|
||||
i2.get_src(0).get_imm() == 12 && i2.get_src(1).is_reg(s6) &&
|
||||
i3.kind == InstructionKind::JALR && i3.get_dst(0).is_reg(make_gpr(Reg::RA)) &&
|
||||
i3.get_src(0).is_reg(s6) && i4.kind == InstructionKind::MFLO1 && i4.get_dst(0).is_reg(s6)) {
|
||||
auto op = std::make_shared<IR_Suspend>();
|
||||
auto op = std::make_shared<IR_Suspend_Atomic>();
|
||||
op->reg_info_set = true;
|
||||
return op;
|
||||
}
|
||||
|
||||
@@ -975,7 +975,7 @@ void IR_Compare::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
condition.get_children(output);
|
||||
}
|
||||
|
||||
goos::Object IR_Suspend::to_form(const LinkedObjectFile& file) const {
|
||||
goos::Object IR_Suspend_Atomic::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return pretty_print::build_list("suspend!");
|
||||
}
|
||||
@@ -984,7 +984,7 @@ void IR_Nop::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
void IR_Suspend::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
void IR_Suspend_Atomic::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -278,9 +278,9 @@ class IR_FloatMath1 : public virtual IR {
|
||||
std::shared_ptr<IR> arg;
|
||||
goos::Object to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
// TP_Type get_expression_type(const TypeState& input,
|
||||
// const LinkedObjectFile& file,
|
||||
// DecompilerTypeSystem& dts) override;
|
||||
TP_Type get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) override;
|
||||
};
|
||||
|
||||
class IR_IntMath2 : public virtual IR {
|
||||
@@ -505,11 +505,14 @@ class IR_Nop_Atomic : public IR_Nop, public IR_Atomic {
|
||||
DecompilerTypeSystem& dts) override;
|
||||
};
|
||||
|
||||
class IR_Suspend : public virtual IR, public IR_Atomic {
|
||||
class IR_Suspend_Atomic : public virtual IR, public IR_Atomic {
|
||||
public:
|
||||
IR_Suspend() = default;
|
||||
IR_Suspend_Atomic() = default;
|
||||
goos::Object to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
void propagate_types(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) override;
|
||||
};
|
||||
|
||||
class IR_Breakpoint_Atomic : public virtual IR_Atomic {
|
||||
@@ -668,6 +671,9 @@ class IR_CMoveF : public virtual IR {
|
||||
: src(std::move(_src)), on_zero(_on_zero) {}
|
||||
goos::Object to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
TP_Type get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) override;
|
||||
};
|
||||
|
||||
class IR_AsmReg : public virtual IR {
|
||||
|
||||
@@ -367,26 +367,26 @@ TP_Type IR_FloatMath2::get_expression_type(const TypeState& input,
|
||||
}
|
||||
}
|
||||
|
||||
// TP_Type IR_FloatMath1::get_expression_type(const TypeState& input,
|
||||
// const LinkedObjectFile& file,
|
||||
// DecompilerTypeSystem& dts) {
|
||||
// (void)input;
|
||||
// (void)file;
|
||||
// (void)dts;
|
||||
// // FLOAT_TO_INT, INT_TO_FLOAT, ABS, NEG, SQRT
|
||||
// switch (kind) {
|
||||
// case FLOAT_TO_INT:
|
||||
// return TP_Type(TypeSpec("int"));
|
||||
// case INT_TO_FLOAT:
|
||||
// case ABS:
|
||||
// case NEG:
|
||||
// case SQRT:
|
||||
// return TP_Type(TypeSpec("float"));
|
||||
// default:
|
||||
// assert(false);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
TP_Type IR_FloatMath1::get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) {
|
||||
(void)input;
|
||||
(void)file;
|
||||
(void)dts;
|
||||
// FLOAT_TO_INT, INT_TO_FLOAT, ABS, NEG, SQRT
|
||||
switch (kind) {
|
||||
case FLOAT_TO_INT:
|
||||
return TP_Type::make_from_typespec(TypeSpec("int"));
|
||||
case INT_TO_FLOAT:
|
||||
case ABS:
|
||||
case NEG:
|
||||
case SQRT:
|
||||
return TP_Type::make_from_typespec(TypeSpec("float"));
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
TP_Type IR_IntMath2::get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) {
|
||||
@@ -534,24 +534,30 @@ TP_Type IR_IntMath2::get_expression_type(const TypeState& input,
|
||||
return TP_Type::make_object_plus_product(arg0_type.typespec(), arg1_type.get_multiplier());
|
||||
}
|
||||
|
||||
if (kind == ADD && arg0_type.typespec() == TypeSpec("pointer") &&
|
||||
if (kind == ADD && arg0_type.typespec().base_type() == "pointer" &&
|
||||
tc(dts, TypeSpec("integer"), arg1_type)) {
|
||||
// plain pointer plus integer = plain pointer
|
||||
return TP_Type::make_from_typespec(TypeSpec("pointer"));
|
||||
}
|
||||
|
||||
if (kind == ADD && arg1_type.typespec() == TypeSpec("pointer") &&
|
||||
if (kind == ADD && arg1_type.typespec().base_type() == "pointer" &&
|
||||
tc(dts, TypeSpec("integer"), arg0_type)) {
|
||||
// plain pointer plus integer = plain pointer
|
||||
return TP_Type::make_from_typespec(TypeSpec("pointer"));
|
||||
}
|
||||
|
||||
// byte access of offset array field trick.
|
||||
// arg1 holds a structure.
|
||||
// arg0 is an integer in a register.
|
||||
if (tc(dts, TypeSpec("structure"), arg1_type) && !dynamic_cast<IR_IntegerConstant*>(arg0.get()) &&
|
||||
is_int_or_uint(dts, arg0_type)) {
|
||||
return TP_Type::make_object_plus_product(arg1_type.typespec(), 1);
|
||||
if (arg1_type.typespec() == TypeSpec("symbol") &&
|
||||
arg0_type.is_integer_constant(SYM_INFO_OFFSET + POINTER_SIZE)) {
|
||||
// symbol -> GOAL String
|
||||
return TP_Type::make_from_typespec(dts.ts.make_pointer_typespec("string"));
|
||||
} else {
|
||||
// byte access of offset array field trick.
|
||||
// arg1 holds a structure.
|
||||
// arg0 is an integer in a register.
|
||||
return TP_Type::make_object_plus_product(arg1_type.typespec(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (kind == AND) {
|
||||
@@ -687,7 +693,7 @@ TP_Type IR_IntMath1::get_expression_type(const TypeState& input,
|
||||
}
|
||||
|
||||
throw std::runtime_error("IR_IntMath1::get_expression_type case not handled: " +
|
||||
to_form(file).print());
|
||||
to_form(file).print() + " " + arg_type.print());
|
||||
}
|
||||
|
||||
TP_Type IR_SymbolValue::get_expression_type(const TypeState& input,
|
||||
@@ -760,6 +766,14 @@ void IR_Nop_Atomic::propagate_types(const TypeState& input,
|
||||
end_types = input;
|
||||
}
|
||||
|
||||
void IR_Suspend_Atomic::propagate_types(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) {
|
||||
(void)file;
|
||||
(void)dts;
|
||||
end_types = input;
|
||||
}
|
||||
|
||||
void IR_Call_Atomic::propagate_types(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) {
|
||||
@@ -871,8 +885,10 @@ TP_Type IR_StaticAddress::get_expression_type(const TypeState& input,
|
||||
(void)input;
|
||||
(void)dts;
|
||||
// todo - we should map out static data and use a real type system lookup here.
|
||||
|
||||
auto label = file.labels.at(label_id);
|
||||
if ((label.offset & 0xf) == 4) {
|
||||
// strings are 16-byte aligned, but functions are 8 byte aligned?
|
||||
if ((label.offset & 7) == BASIC_OFFSET) {
|
||||
// it's a basic! probably.
|
||||
const auto& word = file.words_by_seg.at(label.target_segment).at((label.offset - 4) / 4);
|
||||
if (word.kind == LinkedWord::TYPE_PTR) {
|
||||
@@ -883,6 +899,8 @@ TP_Type IR_StaticAddress::get_expression_type(const TypeState& input,
|
||||
return TP_Type::make_from_typespec(TypeSpec(word.symbol_name));
|
||||
}
|
||||
}
|
||||
} else if ((label.offset & 7) == PAIR_OFFSET) {
|
||||
return TP_Type::make_from_typespec(TypeSpec("pair"));
|
||||
}
|
||||
|
||||
throw std::runtime_error("IR_StaticAddress couldn't figure out the type: " + label.name);
|
||||
@@ -918,4 +936,13 @@ TP_Type IR_EmptyPair::get_expression_type(const TypeState& input,
|
||||
(void)dts;
|
||||
// GOAL's empty pair is actually a pair type, containing the empty pair as the car and cdr
|
||||
return TP_Type::make_from_typespec(TypeSpec("pair"));
|
||||
}
|
||||
|
||||
TP_Type IR_CMoveF::get_expression_type(const TypeState& input,
|
||||
const LinkedObjectFile& file,
|
||||
DecompilerTypeSystem& dts) {
|
||||
(void)input;
|
||||
(void)file;
|
||||
(void)dts;
|
||||
return TP_Type::make_from_typespec(TypeSpec("symbol"));
|
||||
}
|
||||
@@ -828,7 +828,7 @@ void ObjectFileDB::analyze_functions() {
|
||||
|
||||
if (duplicated_functions.find(name) != duplicated_functions.end()) {
|
||||
duplicated_functions[name].insert(data.to_unique_name());
|
||||
func.warnings += ";; this function exists in multiple non-identical object files";
|
||||
func.warnings += ";; this function exists in multiple non-identical object files\n";
|
||||
}
|
||||
});
|
||||
/*
|
||||
@@ -851,6 +851,7 @@ void ObjectFileDB::analyze_functions() {
|
||||
int successful_cfg_irs = 0;
|
||||
int successful_type_analysis = 0;
|
||||
int attempted_type_analysis = 0;
|
||||
int bad_type_analysis = 0; // didn't attempt because we didn't know how + attempted but failed
|
||||
|
||||
std::map<int, std::vector<std::string>> unresolved_by_length;
|
||||
|
||||
@@ -941,7 +942,13 @@ void ObjectFileDB::analyze_functions() {
|
||||
// kv->second.print());
|
||||
if (func.run_type_analysis(kv->second, dts, data.linked_data, hints)) {
|
||||
successful_type_analysis++;
|
||||
} else {
|
||||
// bad, failed.
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else {
|
||||
// bad, don't know global type
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else if (func.guessed_name.kind == FunctionName::FunctionKind::METHOD) {
|
||||
// it's a method.
|
||||
@@ -963,12 +970,56 @@ void ObjectFileDB::analyze_functions() {
|
||||
// func.type.print());
|
||||
if (func.run_type_analysis(func.type, dts, data.linked_data, hints)) {
|
||||
successful_type_analysis++;
|
||||
} else {
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else {
|
||||
// not enough type info
|
||||
bad_type_analysis++;
|
||||
}
|
||||
|
||||
} catch (std::runtime_error& e) {
|
||||
// failed to lookup method info
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else if (func.guessed_name.kind == FunctionName::FunctionKind::TOP_LEVEL_INIT) {
|
||||
attempted_type_analysis++;
|
||||
func.type = dts.ts.make_function_typespec({}, "none");
|
||||
func.attempted_type_analysis = true;
|
||||
if (func.run_type_analysis(func.type, dts, data.linked_data, hints)) {
|
||||
successful_type_analysis++;
|
||||
} else {
|
||||
// failed
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else if (func.guessed_name.kind == FunctionName::FunctionKind::UNIDENTIFIED) {
|
||||
auto obj_name = data.to_unique_name();
|
||||
// try looking up the object
|
||||
const auto& map = get_config().anon_function_types_by_obj_by_id;
|
||||
auto obj_kv = map.find(obj_name);
|
||||
if (obj_kv != map.end()) {
|
||||
auto func_kv = obj_kv->second.find(func.guessed_name.get_anon_id());
|
||||
if (func_kv != obj_kv->second.end()) {
|
||||
attempted_type_analysis++;
|
||||
func.type = dts.parse_type_spec(func_kv->second);
|
||||
func.attempted_type_analysis = true;
|
||||
if (func.run_type_analysis(func.type, dts, data.linked_data, hints)) {
|
||||
successful_type_analysis++;
|
||||
} else {
|
||||
// tried, but failed.
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else {
|
||||
// no id
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else {
|
||||
// no object in map
|
||||
bad_type_analysis++;
|
||||
}
|
||||
} else {
|
||||
// unsupported function kind
|
||||
bad_type_analysis++;
|
||||
}
|
||||
|
||||
if (!func.attempted_type_analysis) {
|
||||
@@ -1024,8 +1075,12 @@ void ObjectFileDB::analyze_functions() {
|
||||
spdlog::info(" {}/{} functions that attempted type analysis succeeded ({:.2f}%)",
|
||||
successful_type_analysis, attempted_type_analysis,
|
||||
100.f * float(successful_type_analysis) / float(attempted_type_analysis));
|
||||
spdlog::info(" {}/{} functions passed type analysis ({:.2f}%)\n", successful_type_analysis,
|
||||
spdlog::info(" {}/{} functions passed type analysis ({:.2f}%)", successful_type_analysis,
|
||||
non_asm_funcs, 100.f * float(successful_type_analysis) / float(non_asm_funcs));
|
||||
spdlog::info(
|
||||
" {} functions were supposed to do type analysis but either failed or didn't know their "
|
||||
"types.\n",
|
||||
bad_type_analysis);
|
||||
|
||||
// for (auto& kv : unresolved_by_length) {
|
||||
// printf("LEN %d\n", kv.first);
|
||||
|
||||
+27
-4
@@ -8,6 +8,21 @@ Config& get_config() {
|
||||
return gConfig;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/*!
|
||||
* Read an entry from cfg containing the name of a json file, and parse that file.
|
||||
* Relative to jak-project directory.
|
||||
*/
|
||||
nlohmann::json read_json_file_from_config(const nlohmann::json& cfg, const std::string& file_key) {
|
||||
auto file_name = cfg.at(file_key).get<std::string>();
|
||||
auto file_txt = file_util::read_text_file(file_util::get_file_path({file_name}));
|
||||
return nlohmann::json::parse(file_txt, nullptr, true, true);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
* Parse the main config file and set the global decompiler configuration.
|
||||
*/
|
||||
void set_config(const std::string& path_to_config_file) {
|
||||
auto config_str = file_util::read_text_file(path_to_config_file);
|
||||
// to ignore comments in json, which may be useful
|
||||
@@ -59,10 +74,7 @@ void set_config(const std::string& path_to_config_file) {
|
||||
gConfig.bad_inspect_types.insert(x);
|
||||
}
|
||||
|
||||
auto type_hints_file_name = cfg.at("type_hints_file").get<std::string>();
|
||||
auto type_hints_txt = file_util::read_text_file(file_util::get_file_path({type_hints_file_name}));
|
||||
auto type_hints_json = nlohmann::json::parse(type_hints_txt, nullptr, true, true);
|
||||
|
||||
auto type_hints_json = read_json_file_from_config(cfg, "type_hints_file");
|
||||
for (auto& kv : type_hints_json.items()) {
|
||||
auto& function_name = kv.key();
|
||||
auto& hints = kv.value();
|
||||
@@ -77,4 +89,15 @@ void set_config(const std::string& path_to_config_file) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto anon_func_json = read_json_file_from_config(cfg, "anonymous_function_types_file");
|
||||
for (auto& kv : anon_func_json.items()) {
|
||||
auto& obj_file_name = kv.key();
|
||||
auto& anon_types = kv.value();
|
||||
for (auto& anon_type : anon_types) {
|
||||
auto id = anon_type.at(0).get<int>();
|
||||
const auto& type_name = anon_type.at(1).get<std::string>();
|
||||
gConfig.anon_function_types_by_obj_by_id[obj_file_name][id] = type_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -40,7 +40,8 @@ struct Config {
|
||||
std::unordered_set<std::string> no_type_analysis_functions_by_name;
|
||||
std::unordered_map<std::string, std::unordered_map<int, std::vector<TypeHint>>>
|
||||
type_hints_by_function_by_idx;
|
||||
// ...
|
||||
std::unordered_map<std::string, std::unordered_map<int, std::string>>
|
||||
anon_function_types_by_obj_by_id;
|
||||
};
|
||||
|
||||
Config& get_config();
|
||||
|
||||
+120
-86
@@ -7,20 +7,17 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; to move
|
||||
(define-extern name= (function basic basic symbol)) ;; gstring
|
||||
(define-extern stop (function int)) ;; logic-target
|
||||
(define-extern set-blackout-frames (function int int))
|
||||
|
||||
|
||||
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; BUILT-IN / C TYPES ;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
|
||||
;; built-in
|
||||
;; built-in. these need to be listed so the type symbols have type of type
|
||||
;; in the decompiler.
|
||||
(define-extern symbol type)
|
||||
(define-extern object type)
|
||||
(define-extern #f symbol)
|
||||
@@ -37,17 +34,27 @@
|
||||
(define-extern string type)
|
||||
(define-extern uint8 type)
|
||||
(define-extern int8 type)
|
||||
(define-extern uint16 type)
|
||||
(define-extern int16 type)
|
||||
(define-extern uint32 type)
|
||||
(define-extern int32 type)
|
||||
(define-extern uint64 type)
|
||||
(define-extern int64 type)
|
||||
(define-extern uint128 type)
|
||||
(define-extern int128 type)
|
||||
(define-extern float type)
|
||||
(define-extern nothing (function none))
|
||||
(define-extern nothing (function none))
|
||||
|
||||
|
||||
;; C
|
||||
;; functions defined in C. TODO - this will end up being a duplicate of kernel-defs.gc?
|
||||
(define-extern dgo-load (function string kheap int int none))
|
||||
(define-extern *kernel-boot-message* symbol)
|
||||
(define-extern *debug-segment* symbol)
|
||||
(define-extern _format (function _varargs_ object))
|
||||
(define-extern method-set! (function type int function none)) ;; may actually return function.
|
||||
(define-extern *listener-function* (function object))
|
||||
(define-extern *enable-method-set* int)
|
||||
(define-extern install-debug-handler (function int object symbol))
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -75,7 +82,16 @@
|
||||
(define-extern false-func (function symbol))
|
||||
(define-extern true-func (function symbol))
|
||||
(define-extern format (function _varargs_ object))
|
||||
;; TODO - vec4s (or just forget it)
|
||||
(define-extern vec4s type)
|
||||
|
||||
; ;; gcommon
|
||||
; (deftype vec4s (uint128)
|
||||
; ()
|
||||
; :method-count-assert 9
|
||||
; :size-assert #x10
|
||||
; :flag-assert #x900000010
|
||||
; ;; a bitfield type
|
||||
; )
|
||||
|
||||
(deftype bfloat (basic)
|
||||
((data float :offset-assert 4)
|
||||
@@ -127,7 +143,7 @@
|
||||
(define-extern print (function object object))
|
||||
(define-extern printl (function object object))
|
||||
(define-extern inspect (function object object))
|
||||
(define-extern mem-print (function pointer int symbol))
|
||||
(define-extern mem-print (function (pointer uint32) int symbol))
|
||||
(define-extern *trace-list* pair)
|
||||
(define-extern print-tree-bitmask (function int int symbol))
|
||||
(define-extern valid? (function object type basic basic object symbol))
|
||||
@@ -135,23 +151,7 @@
|
||||
;; has issues:
|
||||
(define-extern breakpoint-range-set! function)
|
||||
|
||||
; ;; gcommon
|
||||
; (deftype array (UNKNOWN)
|
||||
; ()
|
||||
; :method-count-assert 0
|
||||
; :size-assert #x0
|
||||
; :flag-assert #x0
|
||||
; ;; too many basic blocks
|
||||
; )
|
||||
|
||||
; ;; gcommon
|
||||
; (deftype vec4s (uint128)
|
||||
; ()
|
||||
; :method-count-assert 9
|
||||
; :size-assert #x10
|
||||
; :flag-assert #x900000010
|
||||
; ;; likely a bitfield type
|
||||
; )
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -270,7 +270,7 @@
|
||||
(state state :offset-assert #x38)
|
||||
(trans-hook function :offset-assert #x3c)
|
||||
(post-hook function :offset-assert #x40)
|
||||
(event-hook function :offset-assert #x44)
|
||||
(event-hook (function stack-frame (function object) function state object) :offset-assert #x44)
|
||||
(allocated-length int32 :offset-assert #x48)
|
||||
(next-state basic :offset-assert #x4c)
|
||||
(heap-base pointer :offset-assert #x50)
|
||||
@@ -409,9 +409,9 @@
|
||||
;; gkernel-h
|
||||
(deftype state (protect-frame)
|
||||
((code function :offset-assert 16)
|
||||
(trans function :offset-assert 20)
|
||||
(trans (function object) :offset-assert 20)
|
||||
(post function :offset-assert 24)
|
||||
(enter function :offset-assert 28)
|
||||
(enter (function object object object object object object object) :offset-assert 28)
|
||||
(event basic :offset-assert 32)
|
||||
)
|
||||
(:methods
|
||||
@@ -470,7 +470,6 @@
|
||||
(define-extern *debug-dead-pool* dead-pool-heap)
|
||||
(define-extern *null-process* process)
|
||||
(define-extern *vis-boot* basic)
|
||||
(define-extern *stdcon* basic) ;; todo, more specific
|
||||
|
||||
(define-extern *global-search-name* basic)
|
||||
(define-extern *global-search-count* int)
|
||||
@@ -486,7 +485,10 @@
|
||||
(define-extern search-process-tree (function process-tree (function process-tree object) process))
|
||||
(define-extern execute-process-tree (function process-tree (function object object) kernel-context object))
|
||||
|
||||
(define-extern previous-brother (function process-tree process-tree))
|
||||
(define-extern change-parent (function process-tree process-tree process-tree))
|
||||
(define-extern change-brother (function process-tree process-tree process-tree))
|
||||
(define-extern change-to-last-brother (function process-tree process-tree))
|
||||
|
||||
(define-extern *active-pool* process-tree)
|
||||
(define-extern kernel-dispatcher (function (function object)))
|
||||
@@ -520,7 +522,7 @@
|
||||
(define-extern *camera-pool* process-tree)
|
||||
|
||||
(define-extern *nk-dead-pool* dead-pool-heap)
|
||||
(define-extern change-to-last-brother function)
|
||||
|
||||
(define-extern *pickup-dead-pool* dead-pool)
|
||||
(define-extern *camera-master-dead-pool* dead-pool)
|
||||
(define-extern *camera-dead-pool* dead-pool)
|
||||
@@ -549,11 +551,14 @@
|
||||
;;(define-extern dead object) ;; unknown type
|
||||
|
||||
;; todo
|
||||
(define-extern previous-brother function)
|
||||
(define-extern change-brother function)
|
||||
;;(define-extern *dead-pool-list* object) ;; unknown type
|
||||
|
||||
;; pskernel
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; PSKERNEL ;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
|
||||
(deftype lowmemmap (structure)
|
||||
((irq-info-stack uint32 :offset-assert 0)
|
||||
(irq2-info-stack uint32 :offset-assert 4)
|
||||
@@ -575,6 +580,67 @@
|
||||
:flag-assert #x900000044
|
||||
)
|
||||
|
||||
(define-extern kernel-copy-function (function object object object object none))
|
||||
(define-extern kernel-copy-to-kernel-ram (function none))
|
||||
(define-extern kernel-write-function (function object object object none))
|
||||
(define-extern kernel-write (function none))
|
||||
(define-extern kernel-read-function (function object object none))
|
||||
(define-extern kernel-read (function none))
|
||||
(define-extern kernel-check-hardwired-addresses (function none))
|
||||
(define-extern install-default-debug-handler (function object none))
|
||||
(define-extern return-from-exception (function object none))
|
||||
(define-extern kernel-set-exception-vector (function none))
|
||||
(define-extern kernel-set-interrupt-vector (function none))
|
||||
(define-extern kernel-set-level2-vector (function none))
|
||||
(define-extern deinstall-debug-handler (function none))
|
||||
(define-extern deinstall-debug-handlers (function none))
|
||||
(define-extern resend-exception (function none))
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; GSTRING ;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
(define-extern *string-tmp-str* string)
|
||||
(define-extern *temp-string* string)
|
||||
(define-extern *stdcon0* string)
|
||||
(define-extern *stdcon1* string)
|
||||
(define-extern *stdcon* string)
|
||||
(define-extern *debug-draw-pauseable* symbol)
|
||||
|
||||
(define-extern copy-string<-string (function string string string))
|
||||
(define-extern string= (function string string symbol))
|
||||
(define-extern string-charp= (function string (pointer uint8) symbol))
|
||||
(define-extern name= (function basic basic symbol))
|
||||
(define-extern copyn-string<-charp (function string (pointer uint8) int string))
|
||||
(define-extern string<-charp (function string (pointer uint8) string))
|
||||
(define-extern charp<-string (function (pointer uint8) string int))
|
||||
(define-extern copy-charp<-charp (function (pointer uint8) (pointer uint8) (pointer uint8)))
|
||||
(define-extern cat-string<-string (function string string string))
|
||||
(define-extern catn-string<-charp (function string (pointer uint8) int string))
|
||||
(define-extern cat-string<-string_to_charp (function string string int (pointer uint8)))
|
||||
(define-extern append-character-to-string (function string uint8 int))
|
||||
(define-extern charp-basename (function (pointer uint8) (pointer uint8)))
|
||||
(define-extern clear (function string string))
|
||||
(define-extern string<? (function string string symbol))
|
||||
(define-extern string>? (function string string symbol))
|
||||
(define-extern string<=? (function string string symbol))
|
||||
(define-extern string>=? (function string string symbol))
|
||||
(define-extern string-skip-to-char (function (pointer uint8) uint8 (pointer uint8)))
|
||||
;; this one might be wrong
|
||||
(define-extern string-cat-to-last-char (function uint8 string uint8 (pointer uint8)))
|
||||
(define-extern string-skip-whitespace (function (pointer uint8) (pointer uint8)))
|
||||
(define-extern string-suck-up! (function string (pointer uint8) symbol))
|
||||
(define-extern string-strip-leading-whitespace! (function string symbol))
|
||||
(define-extern string-strip-trailing-whitespace! (function string symbol))
|
||||
(define-extern string-strip-whitespace! (function string symbol))
|
||||
(define-extern string-get-arg!! (function string string symbol))
|
||||
(define-extern string->int (function string int))
|
||||
(define-extern string->float (function string float))
|
||||
(define-extern string-get-int32!! (function (pointer int32) string symbol))
|
||||
(define-extern string-get-float!! (function (pointer float) string symbol))
|
||||
(define-extern string-get-flag!! (function (pointer symbol) string string string symbol))
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; DGO-H ;;;;;;;;;;;;;;;;;;;
|
||||
@@ -603,6 +669,26 @@
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; GSTATE ;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
|
||||
(define-extern looping-code (function symbol))
|
||||
(define-extern send-event-function (function process state object))
|
||||
(define-extern enter-state (function object object object object object object object))
|
||||
(define-extern inherit-state (function state state state))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;; END OF KERNEL.CGO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;; START OF GAME.CGO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; MATH ;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -31215,61 +31301,9 @@
|
||||
;; KERNEL
|
||||
|
||||
|
||||
(define-extern install-default-debug-handler function)
|
||||
(define-extern return-from-exception function)
|
||||
;;(define-extern lowmemmap object) ;; unknown type
|
||||
(define-extern kernel-write function)
|
||||
(define-extern kernel-read function)
|
||||
(define-extern deinstall-debug-handlers function)
|
||||
(define-extern kernel-set-exception-vector function)
|
||||
(define-extern kernel-copy-function function)
|
||||
(define-extern kernel-check-hardwired-addresses function)
|
||||
(define-extern kernel-set-level2-vector function)
|
||||
(define-extern kernel-set-interrupt-vector function)
|
||||
(define-extern kernel-read-function function)
|
||||
(define-extern kernel-copy-to-kernel-ram function)
|
||||
(define-extern kernel-write-function function)
|
||||
(define-extern resend-exception function)
|
||||
(define-extern deinstall-debug-handler function)
|
||||
;;(define-extern install-debug-handler object) ;; unknown type
|
||||
(define-extern copyn-string<-charp function)
|
||||
(define-extern string<-charp function)
|
||||
(define-extern string-get-arg!! function)
|
||||
(define-extern string-get-float!! function)
|
||||
(define-extern append-character-to-string function)
|
||||
(define-extern string-get-int32!! function)
|
||||
(define-extern charp-basename function)
|
||||
(define-extern copy-charp<-charp function)
|
||||
(define-extern string-skip-whitespace function)
|
||||
(define-extern string-strip-whitespace! function)
|
||||
(define-extern string<? function)
|
||||
(define-extern string-get-flag!! function)
|
||||
(define-extern charp<-string (function (pointer uint8) string int))
|
||||
(define-extern string>=? function)
|
||||
(define-extern string-charp= function)
|
||||
(define-extern string->float function)
|
||||
(define-extern cat-string<-string_to_charp function)
|
||||
(define-extern string->int function)
|
||||
(define-extern string<=? function)
|
||||
(define-extern cat-string<-string function)
|
||||
(define-extern clear function)
|
||||
(define-extern string= function)
|
||||
;;(define-extern *temp-string* object) ;; unknown type
|
||||
(define-extern string-strip-leading-whitespace! function)
|
||||
(define-extern catn-string<-charp function)
|
||||
;;(define-extern *string-tmp-str* object) ;; unknown type
|
||||
(define-extern string-suck-up! function)
|
||||
(define-extern copy-string<-string (function string string symbol))
|
||||
(define-extern string-skip-to-char function)
|
||||
(define-extern string-strip-trailing-whitespace! function)
|
||||
(define-extern string>? function)
|
||||
(define-extern string-cat-to-last-char function)
|
||||
|
||||
;;(define-extern dgo-entry object) ;; unknown type
|
||||
;;(define-extern dgo-file object) ;; unknown type
|
||||
(define-extern enter-state function)
|
||||
(define-extern send-event-function function)
|
||||
(define-extern looping-code function)
|
||||
(define-extern inherit-state function)
|
||||
;;(define-extern time-frame object) ;; unknown type
|
||||
;;(define-extern part-id object) ;; unknown type
|
||||
|
||||
|
||||
@@ -53,10 +53,11 @@
|
||||
"str_file_names_":[],
|
||||
|
||||
"type_hints_file":"decompiler/config/jak1_ntsc_black_label/type_hints.jsonc",
|
||||
"anonymous_function_types_file":"decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc",
|
||||
|
||||
"analyze_functions":true,
|
||||
"analyze_expressions":false,
|
||||
"function_type_prop":false,
|
||||
"function_type_prop":true,
|
||||
"write_disassembly":true,
|
||||
"write_hex_near_instructions":false,
|
||||
|
||||
@@ -92,6 +93,9 @@
|
||||
"(method 3 vec4s)", // 128-bit bitfield
|
||||
"qmem-copy<-!", // 128-bit loads and stores
|
||||
"qmem-copy->!", // 128-bit loads and stores
|
||||
"breakpoint-range-set!", // messing with COP0 registers
|
||||
"(method 0 catch-frame)", // kernel asm
|
||||
"throw-dispatch", // kernel asm
|
||||
"reset-and-call", // stack manipulation
|
||||
"(method 10 cpu-thread)" // loading saved regs off of the stack.
|
||||
],
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"gkernel":[
|
||||
[16, "(function process symbol)"],
|
||||
[22, "(function process symbol)"],
|
||||
[25, "(function process symbol)"],
|
||||
[28, "(function process symbol)"],
|
||||
[30, "(function process symbol)"],
|
||||
[32, "(function process symbol)"]
|
||||
]
|
||||
}
|
||||
@@ -45,6 +45,21 @@
|
||||
[13, ["v0", "cpu-thread"]]
|
||||
],
|
||||
|
||||
"(method 0 dead-pool-heap)":[
|
||||
[60, ["v0", "int"]], // a lie, actually the 115 is an align16 constant propagated on addr of heap start.
|
||||
[61, ["a0", "pointer"], ["v0", "dead-pool-heap"]]
|
||||
],
|
||||
|
||||
"(method 21 dead-pool-heap)":[
|
||||
[5, ["v1", "pointer"]],
|
||||
[13, ["a0", "pointer"]],
|
||||
[25, ["v1", "pointer"]]
|
||||
],
|
||||
|
||||
"(method 5 dead-pool-heap)":[
|
||||
[3, ["v1", "int"], ["a0", "int"]]
|
||||
],
|
||||
|
||||
"remove-exit":[
|
||||
[0, ["s6", "process"]]
|
||||
],
|
||||
@@ -66,6 +81,32 @@
|
||||
"(method 14 dead-pool)":[
|
||||
[23, ["v1", "process"]], // bad visit order with #f?
|
||||
[28, ["s4", "(pointer process-tree)"]] // bug in real game, see gkernel.gc
|
||||
],
|
||||
|
||||
"throw":[
|
||||
[20, ["s4", "protect-frame"]] // type case
|
||||
],
|
||||
|
||||
"(method 0 protect-frame)":[
|
||||
[0, ["a0", "int"]],
|
||||
[1, ["v0", "protect-frame"]]
|
||||
],
|
||||
|
||||
"(method 9 process)":[
|
||||
[43, ["s5", "process"]]
|
||||
],
|
||||
|
||||
"(method 10 process)":[
|
||||
[24, ["s4", "protect-frame"]]
|
||||
],
|
||||
|
||||
"enter-state":[
|
||||
[67, ["s0", "protect-frame"]]
|
||||
],
|
||||
|
||||
"name=":[
|
||||
[24, ["a1", "symbol"]],
|
||||
[39, ["a0", "symbol"]]
|
||||
]
|
||||
|
||||
}
|
||||
@@ -58,7 +58,8 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
add_symbol(sym_name.as_symbol()->name, parse_typespec(&ts, sym_type));
|
||||
|
||||
} else if (car(o).as_symbol()->name == "deftype") {
|
||||
parse_deftype(cdr(o), &ts);
|
||||
auto dtr = parse_deftype(cdr(o), &ts);
|
||||
add_symbol(dtr.type.base_type(), "type");
|
||||
} else if (car(o).as_symbol()->name == "declare-type") {
|
||||
auto* rest = &cdr(o);
|
||||
auto type_name = car(*rest);
|
||||
@@ -267,8 +268,8 @@ TP_Type DecompilerTypeSystem::tp_lca(const TP_Type& existing, const TP_Type& add
|
||||
}
|
||||
|
||||
// otherwise, as an absolute fallback, convert both to TypeSpecs and do TypeSpec LCA
|
||||
auto new_result =
|
||||
TP_Type::make_from_typespec(ts.lowest_common_ancestor(existing.typespec(), add.typespec()));
|
||||
auto new_result = TP_Type::make_from_typespec(
|
||||
coerce_to_reg_type(ts.lowest_common_ancestor(existing.typespec(), add.typespec())));
|
||||
*changed = (new_result != existing);
|
||||
return new_result;
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ class TP_Type {
|
||||
bool is_integer_constant() const { return kind == Kind::INTEGER_CONSTANT; }
|
||||
bool is_integer_constant(int64_t value) const { return is_integer_constant() && m_int == value; }
|
||||
bool is_product() const { return kind == Kind::PRODUCT_WITH_CONSTANT; }
|
||||
bool is_product_plus_obj() const { return kind == Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT; }
|
||||
bool is_product_with(int64_t value) const {
|
||||
return kind == Kind::PRODUCT_WITH_CONSTANT && m_int == value;
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
;; name in dgo: vu1-macros
|
||||
;; dgos: GAME, ENGINE
|
||||
|
||||
;; this file has no code!
|
||||
@@ -5,3 +5,15 @@
|
||||
;; name in dgo: types-h
|
||||
;; dgos: GAME, ENGINE
|
||||
|
||||
;; these types may have bitfields in them.
|
||||
;; these have runtime types. But nothing appears to use them?
|
||||
|
||||
(deftype time-frame (int64)
|
||||
()
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
(deftype part-id (uint32)
|
||||
()
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
@@ -232,7 +232,7 @@
|
||||
(state state :offset-assert #x38)
|
||||
(trans-hook function :offset-assert #x3c)
|
||||
(post-hook function :offset-assert #x40)
|
||||
(event-hook function :offset-assert #x44)
|
||||
(event-hook (function stack-frame (function object) function state object) :offset-assert #x44)
|
||||
(allocated-length int32 :offset-assert #x48)
|
||||
(next-state basic :offset-assert #x4c)
|
||||
(heap-base pointer :offset-assert #x50)
|
||||
@@ -413,23 +413,20 @@
|
||||
obj
|
||||
)
|
||||
|
||||
;; GOAL State. A Process can be in a State.
|
||||
(deftype state (protect-frame) ; state is a protect frame so we can "exit" it with cleanup
|
||||
((code function :offset-assert 16) ;; main code to run in this state
|
||||
(trans function :offset-assert 20) ;; ? run once and return ? when ?
|
||||
(post function :offset-assert 24) ;; ?
|
||||
(enter function :offset-assert 28) ;; ?
|
||||
(event basic :offset-assert 32) ;; event handler function?
|
||||
(deftype state (protect-frame)
|
||||
((code function :offset-assert 16)
|
||||
(trans (function object) :offset-assert 20)
|
||||
(post function :offset-assert 24)
|
||||
(enter (function object object object object object object object) :offset-assert 28)
|
||||
(event basic :offset-assert 32)
|
||||
)
|
||||
|
||||
(:methods
|
||||
(new ((allocation symbol) (type-to-make type) (name basic) (code function)
|
||||
(trans function) (enter function) (exit (function object)) (event function)) _type_ 0)
|
||||
)
|
||||
|
||||
:size-assert #x24
|
||||
:method-count-assert 9
|
||||
:flag-assert #x900000024
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1286,8 +1286,6 @@
|
||||
obj
|
||||
)
|
||||
|
||||
(define-extern *stdcon* basic) ;; todo, more specific
|
||||
|
||||
(defmethod compact dead-pool-heap ((obj dead-pool-heap) (count int))
|
||||
"Do heap compaction. The count argument tells us how much work to do.
|
||||
If the heap is very full we will automatically do more work than requested."
|
||||
@@ -1592,9 +1590,6 @@
|
||||
|
||||
(define-extern *listener-process* process)
|
||||
(define-extern *active-pool* process-tree)
|
||||
(define-extern *stdcon0* basic) ; more specific?
|
||||
(define-extern *stdcon1* basic) ; more specific?
|
||||
(define-extern *debug-draw-pauseable* symbol)
|
||||
|
||||
(defun kernel-dispatcher ()
|
||||
"Run the kernel!
|
||||
|
||||
@@ -5,3 +5,9 @@
|
||||
;; name in dgo: gstring-h
|
||||
;; dgos: KERNEL
|
||||
|
||||
(define-extern *string-tmp-str* string)
|
||||
(define-extern *temp-string* string)
|
||||
(define-extern *stdcon0* string)
|
||||
(define-extern *stdcon1* string)
|
||||
(define-extern *stdcon* string)
|
||||
(define-extern *debug-draw-pauseable* symbol)
|
||||
@@ -36,6 +36,7 @@
|
||||
(&+! src-ptr 1)
|
||||
)
|
||||
)
|
||||
dst
|
||||
)
|
||||
|
||||
(defmethod new string ((allocation symbol) (type-to-make type) (size int) (other string))
|
||||
@@ -59,6 +60,12 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; string=
|
||||
;; string-charp=
|
||||
;; name=
|
||||
;; copyn-string<-charp
|
||||
;; string<-charp
|
||||
|
||||
(defun charp<-string ((dst (pointer uint8)) (src-string string))
|
||||
"Copy a GOAL string into a character array."
|
||||
(let ((src (-> src-string data)))
|
||||
@@ -70,4 +77,38 @@
|
||||
(set! (-> dst) 0)
|
||||
0
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; copy-charp<-charp
|
||||
;; cat-string<-string
|
||||
;; catn-string<-charp
|
||||
;; cat-string<-string_to_charp
|
||||
;; append-character-to-string
|
||||
;; charp-basename
|
||||
;; clear
|
||||
;; string<?
|
||||
;; string>?
|
||||
;; string<=?
|
||||
;; string>=?
|
||||
|
||||
(define *string-tmp-str* (new 'global 'string 128 (the string #f)))
|
||||
|
||||
;; string-skip-to-char
|
||||
;; string-cat-to-last-char
|
||||
;; string-skip-whitespace
|
||||
;; string-suck-up!
|
||||
;; string-strip-leading-whitespace
|
||||
;; string-strip-trailing-whitespace
|
||||
;; string-strip-whitespace
|
||||
;; string-get-arg!!
|
||||
;; string->int
|
||||
;; string->float
|
||||
;; string-get-int32!!
|
||||
;; string-get-float!!
|
||||
;; string-get-flag!!
|
||||
|
||||
(define *debug-draw-pauseable* #f)
|
||||
(define *stdcon0* (new 'global 'string 16384 (the string #f)))
|
||||
(define *stdcon1* (new 'global 'string 16384 (the string #f)))
|
||||
(define *stdcon* *stdcon0*)
|
||||
(define *temp-string* (new 'global 'string 256 (the string #f)))
|
||||
@@ -5,3 +5,128 @@
|
||||
;; name in dgo: pskernel
|
||||
;; dgos: KERNEL
|
||||
|
||||
#|
|
||||
pskernel.gc contains a bunch of utilities for poking around the PS2's kernel.
|
||||
These are unused in the retail game, and wouldn't be "safe" to use on a retail console,
|
||||
as later console revisions may have different memory layout of the BIOS. I suspect this
|
||||
was used for the purposes of debugging and handling crashes.
|
||||
They took over syscall 102 to access memory inside the kernel.
|
||||
|
||||
There's an error message:
|
||||
"I CANNOT CONTINUE TO LOAD GOAL, BECAUSE THE KERNEL VERSION HAS CHANGED~%"
|
||||
"~%Alternatively, try removing pskernel.gc and debug-handlers.gc from project.cl, do an (lg) and then (:r) again~%"
|
||||
|
||||
My theory is that debug-handlers.gc held crash handlers, and on load would install them using functions defined in pskernel.gc.
|
||||
In the retail game, they removed debug-handlers, but not pskernel.
|
||||
|
||||
In the PC port, all of these functions are just stubs.
|
||||
|#
|
||||
|
||||
;; map of the kernel's memory.
|
||||
(deftype lowmemmap (structure)
|
||||
((irq-info-stack uint32 :offset-assert 0)
|
||||
(irq2-info-stack uint32 :offset-assert 4)
|
||||
(kernel-copy-fn uint32 :offset-assert 8)
|
||||
(kernel-write-fn uint32 :offset-assert 12)
|
||||
(r1-save uint128 :offset-assert 16)
|
||||
(last-time uint32 :offset-assert 32)
|
||||
(high-time uint32 :offset-assert 36)
|
||||
(dma-status uint32 :offset-assert 40)
|
||||
(dma-qnext uint32 :offset-assert 44)
|
||||
(dma-qwc uint32 :offset-assert 48)
|
||||
(dma-tnext uint32 :offset-assert 52)
|
||||
(dma-stack0 uint32 :offset-assert 56)
|
||||
(dma-stack1 uint32 :offset-assert 60)
|
||||
(kernel-read-fn uint32 :offset-assert 64)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x44
|
||||
:flag-assert #x900000044
|
||||
)
|
||||
|
||||
(defmacro nyi-break (name)
|
||||
`(begin
|
||||
(format 0 "~A is not implemented!~%" (quote ,name))
|
||||
(break)
|
||||
(none)
|
||||
)
|
||||
)
|
||||
|
||||
(defun kernel-copy-function (unused source dest size)
|
||||
"Copy size words from source to dest. The a0 argument is ignored.
|
||||
Uses registers a0, a1, a2, a3"
|
||||
(nyi-break kernel-copy-function)
|
||||
)
|
||||
|
||||
(defun kernel-copy-to-kernel-ram ()
|
||||
"Does a syscall 102. This is CpuConfig on released PS2 BIOSes.
|
||||
I'm guessing this somehow calls kernel-copy-function"
|
||||
(nyi-break kernel-copy-to-kernel-ram)
|
||||
)
|
||||
|
||||
(defun kernel-write-function (unused source dest)
|
||||
"Writes a single word to the destination"
|
||||
(nyi-break kernel-write-function)
|
||||
)
|
||||
|
||||
(defun kernel-write ()
|
||||
"Does a syscall 102. I'm guessing this somehow calls kernel-write-function."
|
||||
(nyi-break kernel-write)
|
||||
)
|
||||
|
||||
(defun kernel-read-function (unused source)
|
||||
"Read a single word (signed) from source"
|
||||
(nyi-break kernel-read-function)
|
||||
)
|
||||
|
||||
(defun kernel-read ()
|
||||
"Does a syscall 102. I'm guessing this somehow calls kernel-read-function"
|
||||
(nyi-break kernel-read)
|
||||
)
|
||||
|
||||
(defun kernel-check-hardwired-addresses ()
|
||||
"Checks a bunch of stuff in the kernel using kernel-read.
|
||||
If the memory layout isn't what it expects, it prints an error and crashes."
|
||||
(nyi-break kernel-check-hardwired-addresses)
|
||||
)
|
||||
|
||||
(defun install-default-debug-handler (handler)
|
||||
"Installs the given handler as the debug handler 1 through 13.
|
||||
Uses the install-debug-handler function defined in kmachine.cpp"
|
||||
(nyi-break install-default-debug-handler)
|
||||
)
|
||||
|
||||
(defun return-from-exception (regs)
|
||||
"Restore the registers and eret."
|
||||
(nyi-break return-from-exception)
|
||||
)
|
||||
|
||||
(defun kernel-set-exception-vector ()
|
||||
"Use syscall 13/syscall 14 to set exception handlers"
|
||||
(nyi-break kernel-set-exception-vector)
|
||||
)
|
||||
|
||||
(defun kernel-set-interrupt-vector ()
|
||||
"Use syscall 15 to set an interrupt handler"
|
||||
(nyi-break kernel-set-interrupt-vector)
|
||||
)
|
||||
|
||||
(defun kernel-set-level2-vector ()
|
||||
"Set some handler by writing directly to kernel memory. Not sure what this is."
|
||||
(nyi-break kernel-set-level2-vector)
|
||||
)
|
||||
|
||||
(defun deinstall-debug-handler ()
|
||||
"Set the kernel exception handler back to the default?"
|
||||
(nyi-break deinstall-debug-handler)
|
||||
)
|
||||
|
||||
(defun deinstall-debug-handlers ()
|
||||
"Set a bunch of excpetion handlers back to the default?"
|
||||
(nyi-break deinstall-debug-handlers)
|
||||
)
|
||||
|
||||
(defun resend-exception ()
|
||||
"I think this was to return from a GOAL crash handler back to the EE kernel's crash handler."
|
||||
(nyi-break resend-exception)
|
||||
)
|
||||
Reference in New Issue
Block a user