#include <pro.h>
#include <ida.hpp>
#include <funcs.hpp>
#include <hexrays.hpp>
#include <lines.hpp>
#include <stdexcept>
#include "idakit_facade_internal.hpp"
#include "gen_hexrays.h"
#include "gen_bridge.h"
using namespace idakit_facade;
namespace idakit_gen {
namespace {
struct ctree_counter_t : public ctree_visitor_t {
int n_insn = 0;
int n_expr = 0;
int n_calls = 0;
ctree_counter_t() : ctree_visitor_t(CV_FAST) {}
int idaapi visit_insn(cinsn_t *) override {
++n_insn;
return 0;
}
int idaapi visit_expr(cexpr_t *e) override {
++n_expr;
if (e->op == cot_call)
++n_calls;
return 0;
}
};
struct expr_gap_visitor_t : public ctree_visitor_t {
int *v;
int *w;
expr_gap_visitor_t(int *vh, int *wh) : ctree_visitor_t(CV_PARENTS), v(vh), w(wh) {}
bool elided_empty(const cexpr_t *e) {
if (e->op != cot_empty)
return false;
const cinsn_t *p = parent_insn();
if (p == nullptr)
return false;
switch (p->op) {
case cit_for:
return e == &p->cfor->init || e == &p->cfor->expr || e == &p->cfor->step;
case cit_return:
return e == &p->creturn->expr;
case cit_throw:
return e == &p->cthrow->expr;
default:
return false;
}
}
int idaapi visit_expr(cexpr_t *e) override {
v[e->op]++;
if (!elided_empty(e))
w[e->op]++;
return 0;
}
};
}
std::unique_ptr<::cfuncptr_t> decompile(uint64_t ea) {
std::string reason;
::cfuncptr_t *result = guarded<::cfuncptr_t *>(nullptr, false, [&]() -> ::cfuncptr_t * {
func_t *pfn = get_func((ea_t)ea);
if (pfn == nullptr) {
reason = "no function at address";
return nullptr;
}
hexrays_failure_t hf;
::cfuncptr_t cf = decompile_func(pfn, &hf, 0);
if (cf == nullptr) {
reason = hf.desc().c_str();
return nullptr;
}
return new ::cfuncptr_t(cf);
});
if (result == nullptr) {
if (g_trapped)
reason = "the IDA kernel aborted during decompilation";
throw std::runtime_error(reason);
}
return std::unique_ptr<::cfuncptr_t>(result);
}
rust::String cfunc_pseudocode(const ::cfuncptr_t &cf) {
cfunc_t *p = cf;
const strvec_t &sv = p->get_pseudocode();
qstring out;
for (size_t i = 0; i < sv.size(); ++i) {
qstring line;
tag_remove(&line, sv[i].line);
out.append(line);
out.append('\n');
}
return rust::String(out.c_str(), out.length());
}
CtreeCounts cfunc_counts(const ::cfuncptr_t &cf) {
cfunc_t *p = cf;
ctree_counter_t vis;
vis.apply_to(&p->body, nullptr);
CtreeCounts out{};
out.insns = vis.n_insn;
out.expressions = vis.n_expr;
out.calls = vis.n_calls;
return out;
}
ExprGap cfunc_expr_gap(const ::cfuncptr_t &cf) {
cfunc_t *p = cf;
int v_hist[256] = {0};
int w_hist[256] = {0};
expr_gap_visitor_t vis(v_hist, w_hist);
vis.apply_to(&p->body, nullptr);
int vt = 0;
int ex = 0;
for (int k = 0; k < 256; ++k) {
vt += v_hist[k];
ex += w_hist[k];
}
ExprGap out{};
out.visitor_total = vt;
out.expected = ex;
return out;
}
}