#include <string>
#include <pro.h>
#include <ida.hpp>
#include <nalt.hpp>
#include <typeinf.hpp>
#include "gen_type_build.h"
#include "internal.h"
#include "gen_bridge.h"
#include "type_write_common.h"
using namespace facade;
namespace gen {
namespace {
bool read_func_details(ea_t addr, tinfo_t &tif, func_type_data_t &ftd) {
return get_tinfo(&tif, addr) && !tif.empty() && tif.get_func_details(&ftd, GTD_NO_ARGLOCS);
}
int rebuild_and_apply(ea_t addr, func_type_data_t &ftd) {
ftd.flags &= ~(FTI_ARGLOCS | FTI_EXPLOCS);
tinfo_t new_type;
if (!new_type.create_func(ftd))
return SIG_APPLY;
if (!apply_tinfo(addr, new_type, TINFO_DEFINITE))
return SIG_APPLY;
return SIG_OK;
}
}
TypeWriteResult func_set_rettype(uint64_t addr, rust::Slice<const uint8_t> recipe) {
try {
TypeWriteResult out{};
out.code = guarded<int>(SIG_APPLY, true, [&]() -> int {
tinfo_t tif;
func_type_data_t ftd;
if (!read_func_details(static_cast<ea_t>(addr), tif, ftd))
return SIG_NO_PROTOTYPE;
tinfo_t ret_type;
if (build_recipe(recipe.data(), recipe.size(), ret_type) != TYPE_OK)
return SIG_BUILD;
ftd.rettype = ret_type;
return rebuild_and_apply(static_cast<ea_t>(addr), ftd);
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
SigWriteResult func_set_argtype(uint64_t addr, size_t idx, rust::Slice<const uint8_t> recipe) {
try {
SigWriteResult out{};
size_t arity = 0;
out.code = guarded<int>(SIG_APPLY, true, [&]() -> int {
tinfo_t tif;
func_type_data_t ftd;
if (!read_func_details(static_cast<ea_t>(addr), tif, ftd))
return SIG_NO_PROTOTYPE;
arity = ftd.size();
if (idx >= ftd.size())
return SIG_ARG_RANGE;
tinfo_t arg_type;
if (build_recipe(recipe.data(), recipe.size(), arg_type) != TYPE_OK)
return SIG_BUILD;
ftd[idx].type = arg_type;
return rebuild_and_apply(static_cast<ea_t>(addr), ftd);
});
out.arity = arity;
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
SigWriteResult func_rename_arg(uint64_t addr, size_t idx, rust::Str name) {
try {
SigWriteResult out{};
std::string names(name.data(), name.size());
size_t arity = 0;
out.code = guarded<int>(SIG_APPLY, true, [&]() -> int {
tinfo_t tif;
func_type_data_t ftd;
if (!read_func_details(static_cast<ea_t>(addr), tif, ftd))
return SIG_NO_PROTOTYPE;
arity = ftd.size();
if (idx >= ftd.size())
return SIG_ARG_RANGE;
ftd[idx].name = names.c_str();
return rebuild_and_apply(static_cast<ea_t>(addr), ftd);
});
out.arity = arity;
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult func_set_cc(uint64_t addr, int32_t cc) {
try {
TypeWriteResult out{};
out.code = guarded<int>(SIG_APPLY, true, [&]() -> int {
tinfo_t tif;
func_type_data_t ftd;
if (!read_func_details(static_cast<ea_t>(addr), tif, ftd))
return SIG_NO_PROTOTYPE;
ftd.set_cc(static_cast<callcnv_t>(cc));
return rebuild_and_apply(static_cast<ea_t>(addr), ftd);
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult func_prepend_this(uint64_t addr, rust::Slice<const uint8_t> recipe) {
try {
TypeWriteResult out{};
out.code = guarded<int>(SIG_APPLY, true, [&]() -> int {
tinfo_t tif;
func_type_data_t ftd;
if (!read_func_details(static_cast<ea_t>(addr), tif, ftd))
return SIG_NO_PROTOTYPE;
tinfo_t this_type;
if (build_recipe(recipe.data(), recipe.size(), this_type) != TYPE_OK)
return SIG_BUILD;
funcarg_t self_arg;
self_arg.type = this_type;
self_arg.name = "this";
ftd.insert(ftd.begin(), self_arg);
return rebuild_and_apply(static_cast<ea_t>(addr), ftd);
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
}