LuaFunctionRegisterSpreadsheet/GhidraParser/FunctionInfo.cpp

111 lines
3.1 KiB
C++
Raw Normal View History

#include "FunctionInfo.hpp"
#include <algorithm>
#include <format>
#include <regex>
std::smatch match;
const std::regex usg_vld_rgx(R"(Usage: .+?\((.*?)\))");
void FunctionInfo::chk_vld()
{ // run all checks, so we have the full picture
bool vld = true;
if (prs_msg.size() > 0) vld = false; // parsing messages up until this point are hard errors
if (in_cnt > -1)
{ // in varmap is not dynamic
if (!usg.empty())
{ // check against usage string
if (std::regex_search(usg, match, usg_vld_rgx))
{
std::string usg_params = match[1];
int comma_cnt = 0;
for (char c : usg_params) comma_cnt += c == ',';
if (in_cnt == 0 && !usg_params.empty() || in_cnt != comma_cnt + 1)
{
prs_msg.push_back(std::format("in param count ({}) does not match usage string ({})", in_cnt, !usg_params.empty() * (comma_cnt + 1)));
vld = false;
}
}
else prs_msg.push_back("usage string is malformed"); // do not consider this for validity
}
for (int i = 1; i <= in_cnt; i++)
{ // lua indexes start with 1
if (!in.contains(i))
{
prs_msg.push_back("in param index not in order");
vld = false;
break;
}
}
}
if (out_cnt != -1 && out_cnt != out.size())
{
prs_msg.push_back(std::format("out param count ({}) does not match return value ({})", out.size(), out_cnt));
vld = false;
}
prs_vld = vld;
}
bool FunctionInfo::nil_in_varmap(bool proc_in) const
{
const varmap& params = proc_in ? in : out;
for (auto& [key, value] : params)
if (std::find(value.begin(), value.end(), "nil") != value.end())
return true;
return false;
}
void FunctionInfo::cln_varmap(bool proc_in)
{
varmap& params = proc_in ? in : out;
int cnt = proc_in ? in_cnt : out_cnt;
if (cnt == -1)
{
params.clear(); // dynamic varmap does not need entries
return;
}
for (auto& [lua_index, lua_types] : params)
{
std::sort(lua_types.begin(), lua_types.end());
lua_types.erase(std::unique(lua_types.begin(), lua_types.end()), lua_types.end());
}
if (proc_in) in_cnt = in.size(); // input count can only be inferred by in varmap size
}
std::string FunctionInfo::str() const
{
std::string str = std::format("{:X} {}{}\n", addr, nm, prs_vld ? "" : " (invalid)");
if (!usg.empty()) str += " " + usg + "\n";
str += " in: " + str_varmap(true) + "\n";
str += " out: " + str_varmap(false);
for (const std::string& err : prs_msg) str += "\n " + err;
return str;
}
std::string FunctionInfo::str_varmap(bool proc_in) const
{
int cnt = proc_in ? in_cnt : out_cnt;
switch (cnt)
{
case -1:
return "dynamic";
case 0:
return "0 ()";
}
const varmap& params = proc_in ? in : out;
if (params.size() > 0)
{ // cnt and params.size() might differ - lua_push* calls can be undetected
std::string str = std::to_string(cnt) + " (";
for (const auto& [lua_index, lua_types] : params)
{
for (const auto& lua_type : lua_types) str += lua_type + "/";
str.pop_back(); // remove last slash
str += ", ";
}
str[str.length() - 2] = ')'; // replace last comma with closing bracket
str.pop_back(); // remove space after last comma
return str;
}
return std::to_string(cnt) + " ()";
}