[Decompiler] Static Data Decomp (#280)

* update all-types

* begin work on static data decompiler

* working for vif disasm array

* mostly working

* finish static data decompilation
This commit is contained in:
water111
2021-02-25 09:51:28 -05:00
committed by GitHub
parent 9d84ba8ca4
commit 791c4abfc0
31 changed files with 2064 additions and 69 deletions
+18
View File
@@ -7,11 +7,29 @@
#include <cassert>
#include <stdexcept>
#include <utility>
#include <cstring>
#include "PrettyPrinter.h"
#include "Reader.h"
#include "third-party/fmt/core.h"
namespace pretty_print {
/*!
* Print a float in a nice representation if possibly, or an exact 32-bit integer constant to
* be reinterpreted.
*/
goos::Object float_representation(float value) {
int rounded = value;
bool exact_int = ((float)rounded) == value;
if (value == 0.5 || value == -0.5 || value == 0.0 || value == 1.0 || value == -1.0 || exact_int) {
return goos::Object::make_float(value);
} else {
u32 int_value;
memcpy(&int_value, &value, 4);
return pretty_print::build_list("the-as", "float", fmt::format("#x{:x}", int_value));
}
}
/*!
* A single token which cannot be split between lines.
*/
+2
View File
@@ -51,4 +51,6 @@ goos::Object build_list(const goos::Object& car, Args... rest) {
goos::Reader& get_pretty_printer_reader();
goos::Object float_representation(float value);
} // namespace pretty_print
+11 -6
View File
@@ -51,8 +51,10 @@ Field::Field(std::string name, TypeSpec ts, int offset)
*/
std::string Field::print() const {
return fmt::format(
"Field: ({} {} :offset {}) inline: {:5}, dynamic: {:5}, array: {:5}, array size {:3}", m_name,
m_type.print(), m_offset, m_inline, m_dynamic, m_array, m_array_size);
"Field: ({} {} :offset {}) inline: {:5}, dynamic: {:5}, array: {:5}, array size {:3}, align "
"{:2}, skip {}",
m_name, m_type.print(), m_offset, m_inline, m_dynamic, m_array, m_array_size, m_alignment,
m_skip_in_static_decomp);
}
/*!
@@ -90,7 +92,8 @@ bool Field::operator==(const Field& other) const {
m_dynamic == other.m_dynamic &&
m_array == other.m_array &&
m_array_size == other.m_array_size &&
m_alignment == other.m_alignment;
m_alignment == other.m_alignment &&
m_skip_in_static_decomp == other.m_skip_in_static_decomp;
// clang-format on
}
@@ -480,8 +483,9 @@ StructureType::StructureType(std::string parent,
std::string StructureType::print() const {
std::string result = fmt::format(
"[StructureType] {}\n parent: {}\n boxed: {}\n dynamic: {}\n size: {}\n pack: {}\n fields:\n",
m_name, m_parent, m_is_boxed, m_dynamic, m_size_in_mem, m_pack);
"[StructureType] {}\n parent: {}\n boxed: {}\n dynamic: {}\n size: {}\n pack: {}\n misalign: "
"{}\n fields:\n",
m_name, m_parent, m_is_boxed, m_dynamic, m_size_in_mem, m_pack, m_allow_misalign);
for (auto& x : m_fields) {
result += " " + x.print() + "\n";
}
@@ -507,7 +511,8 @@ bool StructureType::operator==(const Type& other) const {
m_fields == p_other->m_fields &&
m_dynamic == p_other->m_dynamic &&
m_size_in_mem == p_other->m_size_in_mem &&
m_pack == p_other->m_pack;
m_pack == p_other->m_pack &&
m_allow_misalign == p_other->m_allow_misalign;
// clang-format on
}
+3
View File
@@ -192,6 +192,7 @@ class Field {
bool is_dynamic() const { return m_dynamic; }
const std::string& name() const { return m_name; }
int offset() const { return m_offset; }
bool skip_in_decomp() const { return m_skip_in_static_decomp; }
bool operator==(const Field& other) const;
int alignment() const {
@@ -208,6 +209,7 @@ class Field {
friend class TypeSystem;
void set_alignment(int alignment) { m_alignment = alignment; }
void set_offset(int offset) { m_offset = offset; }
void set_skip_in_static_decomp() { m_skip_in_static_decomp = true; }
std::string m_name;
TypeSpec m_type;
@@ -218,6 +220,7 @@ class Field {
bool m_array = false;
int m_array_size = 0;
int m_alignment = -1;
bool m_skip_in_static_decomp = false;
};
class StructureType : public ReferenceType {
+5 -1
View File
@@ -616,7 +616,8 @@ int TypeSystem::add_field_to_type(StructureType* type,
bool is_inline,
bool is_dynamic,
int array_size,
int offset_override) {
int offset_override,
bool skip_in_static_decomp) {
if (type->lookup_field(field_name, nullptr)) {
fmt::print("[TypeSystem] Type {} already has a field named {}\n", type->get_name(), field_name);
throw std::runtime_error("add_field_to_type duplicate field names");
@@ -656,6 +657,9 @@ int TypeSystem::add_field_to_type(StructureType* type,
field.set_offset(offset);
field.set_alignment(field_alignment);
if (skip_in_static_decomp) {
field.set_skip_in_static_decomp();
}
int after_field = offset + get_size_in_type(field);
if (type->get_size_in_memory() < after_field) {
+4 -2
View File
@@ -145,7 +145,8 @@ class TypeSystem {
bool is_inline = false,
bool is_dynamic = false,
int array_size = -1,
int offset_override = -1);
int offset_override = -1,
bool skip_in_static_decomp = false);
void add_builtin_types();
@@ -182,6 +183,8 @@ class TypeSystem {
TypeSpec lowest_common_ancestor_reg(const TypeSpec& a, const TypeSpec& b) const;
TypeSpec lowest_common_ancestor(const std::vector<TypeSpec>& types) const;
int get_size_in_type(const Field& field) const;
private:
bool try_reverse_lookup(const FieldReverseLookupInput& input,
std::vector<FieldReverseLookupOutput::Token>* path,
@@ -205,7 +208,6 @@ class TypeSystem {
TypeSpec* result_type) const;
std::string lca_base(const std::string& a, const std::string& b) const;
bool typecheck_base_types(const std::string& expected, const std::string& actual) const;
int get_size_in_type(const Field& field) const;
int get_alignment_in_type(const Field& field);
Field lookup_field(const std::string& type_name, const std::string& field_name) const;
StructureType* add_builtin_structure(const std::string& parent,
+4 -1
View File
@@ -98,6 +98,7 @@ void add_field(StructureType* structure, TypeSystem* ts, const goos::Object& def
bool is_dynamic = false;
int offset_override = -1;
int offset_assert = -1;
bool skip_in_decomp = false;
if (!rest->is_empty_list()) {
if (car(rest).is_int()) {
@@ -122,6 +123,8 @@ void add_field(StructureType* structure, TypeSystem* ts, const goos::Object& def
throw std::runtime_error("Cannot use -1 as offset-assert");
}
rest = cdr(rest);
} else if (opt_name == ":do-not-decompile") {
skip_in_decomp = true;
} else {
throw std::runtime_error("Invalid option in field specification: " + opt_name);
}
@@ -129,7 +132,7 @@ void add_field(StructureType* structure, TypeSystem* ts, const goos::Object& def
}
int actual_offset = ts->add_field_to_type(structure, name, type, is_inline, is_dynamic,
array_size, offset_override);
array_size, offset_override, skip_in_decomp);
if (offset_assert != -1 && actual_offset != offset_assert) {
throw std::runtime_error("Field " + name + " was placed at " + std::to_string(actual_offset) +
" but offset-assert was set to " + std::to_string(offset_assert));