#include <cstdint>
#include <string>
#include <pro.h>
#include <ida.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 {
int resolve_member(const tinfo_t &tif, const char *member_name, uint64_t member_bit) {
udm_t key;
int flags;
if (member_name != nullptr) {
key.name = member_name;
flags = STRMEM_NAME;
} else {
key.offset = member_bit;
flags = STRMEM_OFFSET;
}
return tif.find_udm(&key, flags);
}
bool bitfield_width_bits(const tinfo_t &member_type, uint16 &width) {
if (!member_type.is_bitfield())
return false;
bitfield_type_data_t details;
if (!member_type.get_bitfield_details(&details))
return false;
width = details.width;
return true;
}
}
TypeWriteResult udt_add_member(rust::Str type_name, rust::Str member_name,
rust::Slice<const uint8_t> recipe, uint64_t member_bit) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
tinfo_t member_type;
if (build_recipe(recipe.data(), recipe.size(), member_type) != TYPE_OK)
return TEDIT_BUILD;
uint64_t offset = member_bit;
if (offset == MEMBER_APPEND) {
asize_t sz = tif.is_union() ? 0 : tif.get_size();
offset = (sz == BADSIZE ? 0 : static_cast<uint64_t>(sz)) * 8;
}
uint16 width;
if (bitfield_width_bits(member_type, width)) {
udm_t udm;
udm.name = mnp != nullptr ? mnp : "";
udm.type = member_type;
udm.offset = offset;
udm.size = width;
return static_cast<int>(tif.add_udm(udm));
}
return static_cast<int>(tif.add_udm(mnp, member_type, offset));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult udt_set_member_type(rust::Str type_name, rust::Str member_name, uint64_t member_bit,
rust::Slice<const uint8_t> recipe, uint32_t etf_flags) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
int idx = resolve_member(tif, mnp, member_bit);
if (idx < 0)
return TEDIT_NO_MEMBER;
tinfo_t member_type;
if (build_recipe(recipe.data(), recipe.size(), member_type) != TYPE_OK)
return TEDIT_BUILD;
return static_cast<int>(tif.set_udm_type(static_cast<size_t>(idx), member_type, etf_flags));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult udt_rename_member(rust::Str type_name, rust::Str member_name, uint64_t member_bit,
rust::Str new_name) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
std::string nn(new_name.data(), new_name.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
int idx = resolve_member(tif, mnp, member_bit);
if (idx < 0)
return TEDIT_NO_MEMBER;
return static_cast<int>(tif.rename_udm(static_cast<size_t>(idx), nn.c_str()));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult udt_set_member_comment(rust::Str type_name, rust::Str member_name,
uint64_t member_bit, rust::Str comment) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
std::string cn(comment.data(), comment.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
int idx = resolve_member(tif, mnp, member_bit);
if (idx < 0)
return TEDIT_NO_MEMBER;
return static_cast<int>(tif.set_udm_cmt(static_cast<size_t>(idx), cn.c_str()));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult udt_set_member_repr(rust::Str type_name, rust::Str member_name, uint64_t member_bit,
uint32_t vtype, bool is_signed, bool leading_zeros) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
int idx = resolve_member(tif, mnp, member_bit);
if (idx < 0)
return TEDIT_NO_MEMBER;
value_repr_t repr;
repr.set_vtype(vtype);
repr.set_signed(is_signed);
repr.set_lzeroes(leading_zeros);
return static_cast<int>(tif.set_udm_repr(static_cast<size_t>(idx), repr));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
TypeWriteResult udt_del_member(rust::Str type_name, rust::Str member_name, uint64_t member_bit) {
try {
TypeWriteResult out{};
std::string tn(type_name.data(), type_name.size());
std::string mn(member_name.data(), member_name.size());
const char *mnp = member_name.empty() ? nullptr : mn.c_str();
out.code = guarded<int>(static_cast<int>(TERR_SAVE_ERROR), true, [&]() -> int {
tinfo_t tif;
if (!load_named_type(tn.c_str(), tif))
return TEDIT_NO_TYPE;
int idx = resolve_member(tif, mnp, member_bit);
if (idx < 0)
return TEDIT_NO_MEMBER;
return static_cast<int>(tif.del_udm(static_cast<size_t>(idx)));
});
out.reason = captured_reason();
return out;
} catch (...) {
std::abort();
}
}
}