From 25301a8bbce7c603a7dade470e2f94e2b1c3da11 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 26 Dec 2020 11:09:59 -0500 Subject: [PATCH] [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 --- CMakeLists.txt | 7 +- common/type_system/TypeSystem.cpp | 4 + decompiler/Function/Function.h | 5 + decompiler/Function/TypeAnalysis.cpp | 3 + decompiler/IR/BasicOpBuilder.cpp | 56 ++++- decompiler/IR/IR.cpp | 4 +- decompiler/IR/IR.h | 16 +- decompiler/IR/IR_TypeAnalysis.cpp | 83 ++++--- decompiler/ObjectFile/ObjectFileDB.cpp | 59 ++++- decompiler/config.cpp | 31 ++- decompiler/config.h | 3 +- decompiler/config/all-types.gc | 206 ++++++++++-------- decompiler/config/jak1_ntsc_black_label.jsonc | 6 +- .../anonymous_function_types.jsonc | 10 + .../jak1_ntsc_black_label/type_hints.jsonc | 41 ++++ decompiler/util/DecompilerTypeSystem.cpp | 7 +- decompiler/util/TP_Type.h | 1 + goal_src/engine/ps2/vu1-macros.gc | 1 + goal_src/engine/util/types-h.gc | 12 + goal_src/kernel/gkernel-h.gc | 21 +- goal_src/kernel/gkernel.gc | 5 - goal_src/kernel/gstring-h.gc | 6 + goal_src/kernel/gstring.gc | 43 +++- goal_src/kernel/pskernel.gc | 125 +++++++++++ 24 files changed, 595 insertions(+), 160 deletions(-) create mode 100644 decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc diff --git a/CMakeLists.txt b/CMakeLists.txt index 203df86406..2418cbff8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index ad2c32f561..28184c52e3 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -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); diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index b1fd56ed58..9d0bfbfa48 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -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; } diff --git a/decompiler/Function/TypeAnalysis.cpp b/decompiler/Function/TypeAnalysis.cpp index 585cc81ebf..b9ec4897b6 100644 --- a/decompiler/Function/TypeAnalysis.cpp +++ b/decompiler/Function/TypeAnalysis.cpp @@ -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; } diff --git a/decompiler/IR/BasicOpBuilder.cpp b/decompiler/IR/BasicOpBuilder.cpp index c88419c85a..3ee9869204 100644 --- a/decompiler/IR/BasicOpBuilder.cpp +++ b/decompiler/IR/BasicOpBuilder.cpp @@ -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 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("#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 try_sw(Instruction& instr, int idx) { std::shared_ptr 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::INTEGER, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), - std::make_shared(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::INTEGER, + make_reg(instr.get_src(2).get_reg(), idx), + std::make_shared(0), 1); + op->update_reginfo_self(0, 1, 0); + return op; + } else { + auto op = std::make_shared(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::INTEGER, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), + std::make_shared(instr.get_src(1).get_imm())), + std::make_shared(0), 1); + op->update_reginfo_self(0, 1, 0); + return op; + } else { + auto op = std::make_shared( + IR_Store_Atomic::INTEGER, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), + std::make_shared(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 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 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 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(); + auto op = std::make_shared(); op->reg_info_set = true; return op; } diff --git a/decompiler/IR/IR.cpp b/decompiler/IR/IR.cpp index a8b22b8da4..dc7b571ffd 100644 --- a/decompiler/IR/IR.cpp +++ b/decompiler/IR/IR.cpp @@ -975,7 +975,7 @@ void IR_Compare::get_children(std::vector>* 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>* output) const { (void)output; } -void IR_Suspend::get_children(std::vector>* output) const { +void IR_Suspend_Atomic::get_children(std::vector>* output) const { (void)output; } diff --git a/decompiler/IR/IR.h b/decompiler/IR/IR.h index cea9791217..16c217be5a 100644 --- a/decompiler/IR/IR.h +++ b/decompiler/IR/IR.h @@ -278,9 +278,9 @@ class IR_FloatMath1 : public virtual IR { std::shared_ptr arg; goos::Object to_form(const LinkedObjectFile& file) const override; void get_children(std::vector>* 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>* 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>* output) const override; + TP_Type get_expression_type(const TypeState& input, + const LinkedObjectFile& file, + DecompilerTypeSystem& dts) override; }; class IR_AsmReg : public virtual IR { diff --git a/decompiler/IR/IR_TypeAnalysis.cpp b/decompiler/IR/IR_TypeAnalysis.cpp index 22c19ce34f..4485653388 100644 --- a/decompiler/IR/IR_TypeAnalysis.cpp +++ b/decompiler/IR/IR_TypeAnalysis.cpp @@ -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(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")); } \ No newline at end of file diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index 312405f35c..bc43535645 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -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> 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); diff --git a/decompiler/config.cpp b/decompiler/config.cpp index d451b80174..bf125d101e 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -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(); + 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(); - 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(); + const auto& type_name = anon_type.at(1).get(); + gConfig.anon_function_types_by_obj_by_id[obj_file_name][id] = type_name; + } + } } diff --git a/decompiler/config.h b/decompiler/config.h index 9d7aeab4bd..7b8b08c0d4 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -40,7 +40,8 @@ struct Config { std::unordered_set no_type_analysis_functions_by_name; std::unordered_map>> type_hints_by_function_by_idx; - // ... + std::unordered_map> + anon_function_types_by_obj_by_id; }; Config& get_config(); diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index a83a986d97..a720141863 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -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-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-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 diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index d1823cfacc..f398881499 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -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. ], diff --git a/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc b/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc new file mode 100644 index 0000000000..cc85744d56 --- /dev/null +++ b/decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc @@ -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)"] + ] +} \ No newline at end of file diff --git a/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc b/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc index 148d724a01..e9f9839b87 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc @@ -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"]] ] } \ No newline at end of file diff --git a/decompiler/util/DecompilerTypeSystem.cpp b/decompiler/util/DecompilerTypeSystem.cpp index 7943ad3132..3e4ca1d8a4 100644 --- a/decompiler/util/DecompilerTypeSystem.cpp +++ b/decompiler/util/DecompilerTypeSystem.cpp @@ -58,7 +58,8 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector& 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; } diff --git a/decompiler/util/TP_Type.h b/decompiler/util/TP_Type.h index dfb154ef36..592f78dee7 100644 --- a/decompiler/util/TP_Type.h +++ b/decompiler/util/TP_Type.h @@ -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; } diff --git a/goal_src/engine/ps2/vu1-macros.gc b/goal_src/engine/ps2/vu1-macros.gc index e7c128aa86..b725c05552 100644 --- a/goal_src/engine/ps2/vu1-macros.gc +++ b/goal_src/engine/ps2/vu1-macros.gc @@ -5,3 +5,4 @@ ;; name in dgo: vu1-macros ;; dgos: GAME, ENGINE +;; this file has no code! \ No newline at end of file diff --git a/goal_src/engine/util/types-h.gc b/goal_src/engine/util/types-h.gc index 6311abf158..579c00075d 100644 --- a/goal_src/engine/util/types-h.gc +++ b/goal_src/engine/util/types-h.gc @@ -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 + ) \ No newline at end of file diff --git a/goal_src/kernel/gkernel-h.gc b/goal_src/kernel/gkernel-h.gc index 104838560f..c79e996017 100644 --- a/goal_src/kernel/gkernel-h.gc +++ b/goal_src/kernel/gkernel-h.gc @@ -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 ) diff --git a/goal_src/kernel/gkernel.gc b/goal_src/kernel/gkernel.gc index a2db3eb445..0d35e29323 100644 --- a/goal_src/kernel/gkernel.gc +++ b/goal_src/kernel/gkernel.gc @@ -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! diff --git a/goal_src/kernel/gstring-h.gc b/goal_src/kernel/gstring-h.gc index 7b3331ed05..ab00e25787 100644 --- a/goal_src/kernel/gstring-h.gc +++ b/goal_src/kernel/gstring-h.gc @@ -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) \ No newline at end of file diff --git a/goal_src/kernel/gstring.gc b/goal_src/kernel/gstring.gc index c509ffb6da..19add59a46 100644 --- a/goal_src/kernel/gstring.gc +++ b/goal_src/kernel/gstring.gc @@ -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 ) - ) \ No newline at end of file + ) + +;; copy-charp<-charp +;; cat-string<-string +;; catn-string<-charp +;; cat-string<-string_to_charp +;; append-character-to-string +;; charp-basename +;; clear +;; 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))) \ No newline at end of file diff --git a/goal_src/kernel/pskernel.gc b/goal_src/kernel/pskernel.gc index dff343339f..eb08f749ee 100644 --- a/goal_src/kernel/pskernel.gc +++ b/goal_src/kernel/pskernel.gc @@ -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) + ) \ No newline at end of file