iw9: impl hashing & missing opcodes

This commit is contained in:
xensik 2022-11-16 18:23:30 +01:00
parent ad29da7bf3
commit ce69051956
4 changed files with 97 additions and 119 deletions

View File

@ -1330,7 +1330,7 @@ void decompiler::decompile_instruction(const instruction::ptr& inst)
for (auto i = 1; i <= count; i++) for (auto i = 1; i <= count; i++)
{ {
func_->params->list.push_back(std::make_unique<ast::expr_identifier>(loc, "var_" + inst->data[i])); func_->params->list.push_back(std::make_unique<ast::expr_identifier>(loc, inst->data[i]));
} }
break; break;
} }
@ -2625,8 +2625,7 @@ void decompiler::process_stmt_for(const ast::stmt_for::ptr& stmt, const block::p
for (const auto& index : stmt->vars) for (const auto& index : stmt->vars)
{ {
auto var = utils::string::va("var_%d", std::stoi(index)); blk->local_vars.push_back({ index, static_cast<uint8_t>(blk->local_vars_create_count), true });
blk->local_vars.push_back({ var, static_cast<uint8_t>(std::stoi(index)), true });
blk->local_vars_create_count++; blk->local_vars_create_count++;
} }
@ -2654,8 +2653,7 @@ void decompiler::process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const
for (const auto& index : stmt->vars) for (const auto& index : stmt->vars)
{ {
auto var1 = utils::string::va("var_%d", std::stoi(index)); blk->local_vars.push_back({ index, static_cast<uint8_t>(blk->local_vars_create_count), true });
blk->local_vars.push_back({ var1, static_cast<uint8_t>(std::stoi(index)), true });
blk->local_vars_create_count++; blk->local_vars_create_count++;
} }
@ -3079,7 +3077,7 @@ void decompiler::process_var_create(ast::expr& expr, const block::ptr& blk, bool
{ {
if (fromstmt) if (fromstmt)
{ {
auto var = utils::string::va("var_%s", expr.as_asm_create->index.data()); auto var = expr.as_asm_create->index;
blk->local_vars.push_back({ var, static_cast<uint8_t>(blk->local_vars_create_count), true }); blk->local_vars.push_back({ var, static_cast<uint8_t>(blk->local_vars_create_count), true });
blk->local_vars_create_count++; blk->local_vars_create_count++;
} }
@ -3087,11 +3085,11 @@ void decompiler::process_var_create(ast::expr& expr, const block::ptr& blk, bool
{ {
for (const auto& entry : expr.as_asm_create->vars) for (const auto& entry : expr.as_asm_create->vars)
{ {
blk->local_vars.push_back({ utils::string::va("var_%s", entry.data()), static_cast<uint8_t>(blk->local_vars_create_count), true }); blk->local_vars.push_back({ entry, static_cast<uint8_t>(blk->local_vars_create_count), true });
blk->local_vars_create_count++; blk->local_vars_create_count++;
} }
auto var = utils::string::va("var_%s", expr.as_asm_create->index.data()); auto var = expr.as_asm_create->index;
blk->local_vars.push_back({ var, static_cast<uint8_t>(blk->local_vars_create_count), true }); blk->local_vars.push_back({ var, static_cast<uint8_t>(blk->local_vars_create_count), true });
blk->local_vars_create_count++; blk->local_vars_create_count++;

View File

@ -50,7 +50,7 @@ void disassembler::disassemble(const std::string& file, std::vector<std::uint8_t
func->index = static_cast<std::uint32_t>(script_->pos()); func->index = static_cast<std::uint32_t>(script_->pos());
func->size = stack_->read<std::uint32_t>(); func->size = stack_->read<std::uint32_t>();
func->name = utils::string::va("id_%016llX", stack_->read<std::uint64_t>()); func->name = resolver::hash_name(stack_->read<std::uint64_t>());
dissasemble_function(func); dissasemble_function(func);
@ -215,13 +215,13 @@ void disassembler::dissasemble_instruction(const instruction::ptr& inst)
case opcode::OP_EvalFieldVariableRef: case opcode::OP_EvalFieldVariableRef:
case opcode::OP_EvalLevelFieldVariable: case opcode::OP_EvalLevelFieldVariable:
case opcode::OP_EvalAnimFieldVariableRef: case opcode::OP_EvalAnimFieldVariableRef:
inst->data.push_back(utils::string::va("id_%016llX", script_->read<std::uint64_t>())); inst->data.push_back(resolver::hash_name(script_->read<std::uint64_t>()));
break; break;
case opcode::OP_CreateLocalVariable: case opcode::OP_CreateLocalVariable:
case opcode::OP_EvalNewLocalArrayRefCached0: case opcode::OP_EvalNewLocalArrayRefCached0:
case opcode::OP_SafeCreateVariableFieldCached: case opcode::OP_SafeCreateVariableFieldCached:
case opcode::OP_SetNewLocalVariableFieldCached0: case opcode::OP_SetNewLocalVariableFieldCached0:
inst->data.push_back(utils::string::va("%016llX", script_->read<std::uint64_t>())); inst->data.push_back(resolver::hash_name(script_->read<std::uint64_t>()));
break; break;
case opcode::OP_SetLocalVariableFieldCached: case opcode::OP_SetLocalVariableFieldCached:
case opcode::OP_RemoveLocalVariables: case opcode::OP_RemoveLocalVariables:
@ -311,6 +311,16 @@ void disassembler::dissasemble_instruction(const instruction::ptr& inst)
case opcode::OP_FormalParams_Precompiled: case opcode::OP_FormalParams_Precompiled:
disassemble_formal_params(inst); disassemble_formal_params(inst);
break; break;
case opcode::OP_unk_134:
case opcode::OP_unk_137:
script_->seek(4);
break;
case opcode::OP_unk_133: // eval something
case opcode::OP_unk_135:
case opcode::OP_unk_136:
case opcode::OP_unk_138:
inst->data.push_back(resolver::hash_name(script_->read<std::uint64_t>()));
break;
default: default:
throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index)); throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
} }
@ -326,12 +336,24 @@ void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool m
if (method) // TODO if (method) // TODO
{ {
auto str = stack_->read_c_string(); auto str = stack_->read_c_string();
if (str.starts_with("#xS"))
{
str = resolver::hash_name(std::stoull(str.substr(3), 0 ,16));
}
script_->seek(2); script_->seek(2);
inst->data.emplace(inst->data.begin(), str); inst->data.emplace(inst->data.begin(), str);
} }
else else
{ {
auto str = stack_->read_c_string(); auto str = stack_->read_c_string();
if (str.starts_with("#xS"))
{
str = resolver::hash_name(std::stoull(str.substr(3), 0 ,16));
}
script_->seek(2); script_->seek(2);
inst->data.emplace(inst->data.begin(), str); inst->data.emplace(inst->data.begin(), str);
} }
@ -369,8 +391,8 @@ void disassembler::disassemble_far_call(const instruction::ptr& inst, bool threa
} }
else else
{ {
inst->data.emplace(inst->data.begin(), utils::string::va("id_%016llX", file)); inst->data.emplace(inst->data.begin(), resolver::hash_name(file));
inst->data.emplace(inst->data.begin(), utils::string::va("id_%016llX", name)); inst->data.emplace(inst->data.begin(), resolver::hash_name(name));
} }
} }
@ -433,7 +455,7 @@ void disassembler::disassemble_end_switch(const instruction::ptr& inst)
void disassembler::disassemble_field_variable(const instruction::ptr& inst) void disassembler::disassemble_field_variable(const instruction::ptr& inst)
{ {
inst->data.push_back(utils::string::va("id_%016llX", script_->read<std::uint64_t>())); inst->data.push_back(resolver::hash_name(script_->read<std::uint64_t>()));
} }
void disassembler::disassemble_formal_params(const instruction::ptr& inst) void disassembler::disassemble_formal_params(const instruction::ptr& inst)
@ -445,7 +467,7 @@ void disassembler::disassemble_formal_params(const instruction::ptr& inst)
for (auto i = 0u; i < count; i++) for (auto i = 0u; i < count; i++)
{ {
inst->data.push_back(utils::string::va("%016llX", script_->read<std::uint64_t>())); inst->data.push_back(resolver::hash_name(script_->read<std::uint64_t>()));
} }
} }

View File

@ -14,14 +14,9 @@
namespace xsk::gsc::iw9 namespace xsk::gsc::iw9
{ {
std::unordered_map<std::uint64_t, std::string_view> hash_map;
std::unordered_map<std::uint8_t, std::string_view> opcode_map; std::unordered_map<std::uint8_t, std::string_view> opcode_map;
std::unordered_map<std::uint16_t, std::string_view> function_map;
std::unordered_map<std::uint16_t, std::string_view> method_map;
std::unordered_map<std::uint32_t, std::string_view> token_map;
std::unordered_map<std::string_view, std::uint8_t> opcode_map_rev; std::unordered_map<std::string_view, std::uint8_t> opcode_map_rev;
std::unordered_map<std::string_view, std::uint16_t> function_map_rev;
std::unordered_map<std::string_view, std::uint16_t> method_map_rev;
std::unordered_map<std::string_view, std::uint32_t> token_map_rev;
std::unordered_map<std::string, std::vector<std::uint8_t>> files; std::unordered_map<std::string, std::vector<std::uint8_t>> files;
read_cb_type read_callback = nullptr; read_cb_type read_callback = nullptr;
std::set<std::string> string_map; std::set<std::string> string_map;
@ -62,88 +57,31 @@ auto resolver::opcode_name(std::uint8_t id) -> std::string
auto resolver::function_id(const std::string& name) -> std::uint16_t auto resolver::function_id(const std::string& name) -> std::uint16_t
{ {
if (name.starts_with("_func_"))
{
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
}
const auto itr = function_map_rev.find(name);
if (itr != function_map_rev.end())
{
return itr->second;
}
throw error(utils::string::va("couldn't resolve builtin function id for name '%s'!", name.data())); throw error(utils::string::va("couldn't resolve builtin function id for name '%s'!", name.data()));
} }
auto resolver::function_name(std::uint16_t id) -> std::string auto resolver::function_name(std::uint16_t id) -> std::string
{ {
const auto itr = function_map.find(id);
if (itr != function_map.end())
{
return std::string(itr->second);
}
return utils::string::va("_func_%04X", id); return utils::string::va("_func_%04X", id);
} }
auto resolver::method_id(const std::string& name) -> std::uint16_t auto resolver::method_id(const std::string& name) -> std::uint16_t
{ {
if (name.starts_with("_meth_"))
{
return static_cast<std::uint16_t>(std::stoul(name.substr(6), nullptr, 16));
}
const auto itr = method_map_rev.find(name);
if (itr != method_map_rev.end())
{
return itr->second;
}
throw error(utils::string::va("couldn't resolve builtin method id for name '%s'!", name.data())); throw error(utils::string::va("couldn't resolve builtin method id for name '%s'!", name.data()));
} }
auto resolver::method_name(std::uint16_t id) -> std::string auto resolver::method_name(std::uint16_t id) -> std::string
{ {
const auto itr = method_map.find(id);
if (itr != method_map.end())
{
return std::string(itr->second);
}
return utils::string::va("_meth_%04X", id); return utils::string::va("_meth_%04X", id);
} }
auto resolver::token_id(const std::string& name) -> std::uint32_t auto resolver::token_id(const std::string&) -> std::uint32_t
{ {
if (name.starts_with("_id_"))
{
return static_cast<std::uint32_t>(std::stoul(name.substr(4), nullptr, 16));
}
const auto itr = token_map_rev.find(name);
if (itr != token_map_rev.end())
{
return itr->second;
}
return 0; return 0;
} }
auto resolver::token_name(std::uint32_t id) -> std::string auto resolver::token_name(std::uint32_t id) -> std::string
{ {
const auto itr = token_map.find(id);
if (itr != token_map.end())
{
return std::string(itr->second);
}
return utils::string::va("_id_%04X", id); return utils::string::va("_id_%04X", id);
} }
@ -151,12 +89,12 @@ auto resolver::find_function(const std::string& name) -> bool
{ {
if (name.starts_with("_func_")) return true; if (name.starts_with("_func_")) return true;
const auto itr = function_map_rev.find(name); /* const auto itr = function_map_rev.find(name);
if (itr != function_map_rev.end()) if (itr != function_map_rev.end())
{ {
return true; return true;
} }*/
return false; return false;
} }
@ -165,19 +103,19 @@ auto resolver::find_method(const std::string& name) -> bool
{ {
if (name.starts_with("_meth_")) return true; if (name.starts_with("_meth_")) return true;
const auto itr = method_map_rev.find(name); /*const auto itr = method_map_rev.find(name);
if (itr != method_map_rev.end()) if (itr != method_map_rev.end())
{ {
return true; return true;
} }*/
return false; return false;
} }
void resolver::add_function(const std::string& name, std::uint16_t id) void resolver::add_function(const std::string& , std::uint16_t )
{ {
const auto itr = function_map_rev.find(name); /*const auto itr = function_map_rev.find(name);
if (itr != function_map_rev.end()) if (itr != function_map_rev.end())
{ {
@ -200,12 +138,12 @@ void resolver::add_function(const std::string& name, std::uint16_t id)
function_map.insert({ id, *ins.first }); function_map.insert({ id, *ins.first });
function_map_rev.insert({ *ins.first, id }); function_map_rev.insert({ *ins.first, id });
} }
} }*/
} }
void resolver::add_method(const std::string& name, std::uint16_t id) void resolver::add_method(const std::string& , std::uint16_t )
{ {
const auto itr = method_map_rev.find(name); /*const auto itr = method_map_rev.find(name);
if (itr != method_map_rev.end()) if (itr != method_map_rev.end())
{ {
@ -228,7 +166,7 @@ void resolver::add_method(const std::string& name, std::uint16_t id)
method_map.insert({ id, *ins.first }); method_map.insert({ id, *ins.first });
method_map_rev.insert({ *ins.first, id }); method_map_rev.insert({ *ins.first, id });
} }
} }*/
} }
auto resolver::make_token(std::string_view str) -> std::string auto resolver::make_token(std::string_view str) -> std::string
@ -295,6 +233,45 @@ auto resolver::fs_to_game_path(const std::filesystem::path& file) -> std::filesy
return result.empty() ? file : result; return result.empty() ? file : result;
} }
auto resolver::hash_id(const std::string& name) -> std::uint64_t
{
if (name.starts_with("id_"))
{
return static_cast<std::uint64_t>(std::stoull(name.substr(3), nullptr, 16));
}
const char* str = name.data();
uint64_t hash = 0x79D6530B0BB9B5D1;
while ( *str )
{
uint8_t byte = *str++;
if (static_cast<uint8_t>(byte - 65) <= 25)
{
byte += 32;
}
printf("%c", byte);
hash = (uint64_t)0x10000000233 * ((uint64_t)byte ^ hash);
}
return hash;
}
auto resolver::hash_name(std::uint64_t id) -> std::string
{
const auto itr = hash_map.find(id);
if (itr != hash_map.end())
{
return std::string(itr->second);
}
return utils::string::va("id_%016llX", id);
}
const std::array<std::pair<std::uint8_t, const char*>, 167> opcode_list const std::array<std::pair<std::uint8_t, const char*>, 167> opcode_list
{{ {{
{ 0x00, "OP_CastFieldObject" }, { 0x00, "OP_CastFieldObject" },
@ -466,16 +443,12 @@ const std::array<std::pair<std::uint8_t, const char*>, 167> opcode_list
{ 0xA6, "OP_unk_166" }, { 0xA6, "OP_unk_166" },
}}; }};
const std::array<std::pair<std::uint16_t, const char*>, 0> function_list const std::array<std::pair<std::uint64_t, const char*>, 4> hash_list
{{
}};
const std::array<std::pair<std::uint16_t, const char*>, 0> method_list
{{
}};
const std::array<std::pair<std::uint32_t, const char*>, 0> token_list
{{ {{
{ 0xC92DD50E8E081414, "main" },
{ 0xAD3D69B62BC6FB2F, "init" },
{ 0x4CCFEE6F73819653, "getfirstarraykey" },
{ 0x6DB433AE7304A362, "getnextarraykey" },
}}; }};
struct __init__ struct __init__
@ -488,12 +461,7 @@ struct __init__
opcode_map.reserve(opcode_list.size()); opcode_map.reserve(opcode_list.size());
opcode_map_rev.reserve(opcode_list.size()); opcode_map_rev.reserve(opcode_list.size());
function_map.reserve(function_list.size()); hash_map.reserve(hash_list.size());
function_map_rev.reserve(function_list.size());
method_map.reserve(method_list.size());
method_map_rev.reserve(method_list.size());
token_map.reserve(token_list.size());
token_map_rev.reserve(token_list.size());
for (const auto& entry : opcode_list) for (const auto& entry : opcode_list)
{ {
@ -501,22 +469,9 @@ struct __init__
opcode_map_rev.insert({ entry.second, entry.first }); opcode_map_rev.insert({ entry.second, entry.first });
} }
for (const auto& entry : function_list) for (const auto& entry : hash_list)
{ {
function_map.insert({ entry.first, entry.second }); hash_map.insert({ entry.first, entry.second });
function_map_rev.insert({ entry.second, entry.first });
}
for (const auto& entry : method_list)
{
method_map.insert({ entry.first, entry.second });
method_map_rev.insert({ entry.second, entry.first });
}
for (const auto& entry : token_list)
{
token_map.insert({ entry.first, entry.second });
token_map_rev.insert({ entry.second, entry.first });
} }
} }
}; };

View File

@ -26,6 +26,9 @@ public:
static auto token_id(const std::string& name) -> std::uint32_t; static auto token_id(const std::string& name) -> std::uint32_t;
static auto token_name(std::uint32_t id) -> std::string; static auto token_name(std::uint32_t id) -> std::string;
static auto hash_id(const std::string& name) -> std::uint64_t;
static auto hash_name(std::uint64_t id) -> std::string;
static auto find_function(const std::string& name) -> bool; static auto find_function(const std::string& name) -> bool;
static auto find_method(const std::string& name) -> bool; static auto find_method(const std::string& name) -> bool;