mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
522 lines
14 KiB
C++
522 lines
14 KiB
C++
#ifndef __PY_IDP__
|
|
#define __PY_IDP__
|
|
|
|
//-------------------------------------------------------------------------
|
|
//<inline(py_idp)>
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *AssembleLine(
|
|
ea_t ea,
|
|
ea_t cs,
|
|
ea_t ip,
|
|
bool use32,
|
|
const char *line)
|
|
{
|
|
if ( line != nullptr )
|
|
{
|
|
char buf[MAXSTR];
|
|
int inslen = processor_t::assemble((uchar *)buf, ea, cs, ip, use32, line);
|
|
PYW_GIL_CHECK_LOCKED_SCOPE();
|
|
if ( inslen > 0 )
|
|
return PyBytes_FromStringAndSize(buf, inslen);
|
|
}
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool assemble(
|
|
ea_t ea,
|
|
ea_t cs,
|
|
ea_t ip,
|
|
bool use32,
|
|
const char *line)
|
|
{
|
|
char buf[MAXSTR];
|
|
PYW_GIL_CHECK_LOCKED_SCOPE();
|
|
bool rc = false;
|
|
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
|
|
int inslen = processor_t::assemble((uchar *)buf, ea, cs, ip, use32, line);
|
|
if ( inslen > 0 )
|
|
{
|
|
patch_bytes(ea, buf, inslen);
|
|
rc = true;
|
|
}
|
|
SWIG_PYTHON_THREAD_END_ALLOW;
|
|
return rc;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_id()
|
|
{
|
|
return PH.id;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_version()
|
|
{
|
|
return PH.version;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_flag()
|
|
{
|
|
return PH.flag;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_cnbits()
|
|
{
|
|
return PH.cnbits;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_dnbits()
|
|
{
|
|
return PH.dnbits;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_reg_first_sreg()
|
|
{
|
|
return PH.reg_first_sreg;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_reg_last_sreg()
|
|
{
|
|
return PH.reg_last_sreg;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_segreg_size()
|
|
{
|
|
return PH.segreg_size;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_reg_code_sreg()
|
|
{
|
|
return PH.reg_code_sreg;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_reg_data_sreg()
|
|
{
|
|
return PH.reg_data_sreg;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_icode_return()
|
|
{
|
|
return PH.icode_return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_instruc_start()
|
|
{
|
|
return PH.instruc_start;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_instruc_end()
|
|
{
|
|
return PH.instruc_end;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static size_t ph_get_tbyte_size()
|
|
{
|
|
return PH.tbyte_size;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *ph_get_instruc()
|
|
{
|
|
Py_ssize_t i = 0;
|
|
PYW_GIL_CHECK_LOCKED_SCOPE();
|
|
processor_t &ph = PH;
|
|
PyObject *py_result = PyList_New(ph.instruc_end - ph.instruc_start);
|
|
for ( const instruc_t *p = ph.instruc + ph.instruc_start, *end = ph.instruc + ph.instruc_end;
|
|
p != end;
|
|
++p )
|
|
{
|
|
PyList_SetItem(py_result, i++, Py_BuildValue("(sI)", p->name, p->feature));
|
|
}
|
|
return py_result;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *ph_get_regnames()
|
|
{
|
|
PYW_GIL_CHECK_LOCKED_SCOPE();
|
|
processor_t &ph = PH;
|
|
PyObject *py_result = PyList_New(ph.regs_num);
|
|
for ( Py_ssize_t i=0; i < ph.regs_num; i++ )
|
|
PyList_SetItem(py_result, i, PyUnicode_FromString(ph.reg_names[i]));
|
|
return py_result;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
static const regval_t *idaapi _py_getreg(
|
|
const char *name,
|
|
const regval_t *regvals);
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *ph_get_operand_info(
|
|
ea_t ea,
|
|
int n)
|
|
{
|
|
PYW_GIL_CHECK_LOCKED_SCOPE();
|
|
bool ok = false;
|
|
idd_opinfo_t opinf;
|
|
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
|
|
do
|
|
{
|
|
if ( dbg == nullptr || n == - 1 )
|
|
break;
|
|
|
|
// Allocate register space
|
|
thid_t tid = get_current_thread();
|
|
regvals_t regvalues;
|
|
regvalues.resize(dbg->nregisters);
|
|
// Read registers
|
|
if ( get_reg_vals(tid, -1, regvalues.begin()) != DRC_OK )
|
|
break;
|
|
|
|
// Call the processor module
|
|
if ( processor_t::notify(processor_t::ev_get_idd_opinfo,
|
|
&opinf,
|
|
ea,
|
|
n,
|
|
tid,
|
|
_py_getreg,
|
|
regvalues.begin()) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
ok = true;
|
|
} while (false);
|
|
|
|
SWIG_PYTHON_THREAD_END_ALLOW;
|
|
if ( ok )
|
|
return Py_BuildValue("(i" PY_BV_EA "Kii)",
|
|
opinf.modified,
|
|
bvea_t(opinf.ea),
|
|
opinf.value.ival,
|
|
opinf.debregidx,
|
|
opinf.value_size);
|
|
else
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static void ph_calcrel(bytevec_t *out_relbits, size_t *out_consumed, ea_t ea)
|
|
{
|
|
processor_t::calcrel(out_relbits, out_consumed, ea);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static ssize_t ph_find_reg_value(uval_t *out, const insn_t &insn, int reg)
|
|
{
|
|
return processor_t::find_reg_value(out, insn, reg);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static ssize_t ph_find_op_value(uval_t *out, const insn_t &insn, int op)
|
|
{
|
|
return processor_t::find_op_value(out, insn, op);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static ssize_t ph_get_reg_accesses(
|
|
reg_accesses_t *accvec,
|
|
const insn_t &insn,
|
|
int flags)
|
|
{
|
|
return processor_t::get_reg_accesses(accvec, insn, flags);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static ssize_t ph_get_abi_info(
|
|
qstrvec_t *abi_names,
|
|
qstrvec_t *abi_opts,
|
|
comp_t comp)
|
|
{
|
|
return processor_t::get_abi_info(abi_names, abi_opts, comp);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// IDP hooks
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Necessary forward declarations; idp.hpp itself doesn't need them.
|
|
struct mblock_t;
|
|
struct proc_def;
|
|
struct libfunc_t;
|
|
|
|
ssize_t idaapi IDP_Callback(void *ud, int notification_code, va_list va);
|
|
struct IDP_Hooks : public hooks_base_t
|
|
{
|
|
// hookgenIDP:methodsinfo_decl
|
|
|
|
IDP_Hooks(uint32 _flags=0, uint32 _hkcb_flags=HKCB_GLOBAL)
|
|
: hooks_base_t("ida_idp.IDP_Hooks", IDP_Callback, HT_IDP, _flags, _hkcb_flags) {}
|
|
|
|
bool hook() { return hooks_base_t::hook(); }
|
|
bool unhook() { return hooks_base_t::unhook(); }
|
|
#ifdef TESTABLE_BUILD
|
|
PyObject *dump_state(bool assert_all_reimplemented=false) { return hooks_base_t::dump_state(mappings, mappings_size, assert_all_reimplemented); }
|
|
#endif
|
|
|
|
// hookgenIDP:methods
|
|
|
|
ssize_t dispatch(int code, va_list va)
|
|
{
|
|
ssize_t ret = 0;
|
|
switch ( code )
|
|
{
|
|
// hookgenIDP:notifications
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
protected:
|
|
static PyObject *new_PyObject_from_idpopt_value(
|
|
int value_type,
|
|
const void *value)
|
|
{
|
|
switch ( value_type )
|
|
{
|
|
case IDPOPT_STR:
|
|
return PyUnicode_FromString((const char *) value);
|
|
case IDPOPT_NUM:
|
|
#ifdef __EA64__
|
|
return PyLong_FromLongLong(*(const uval_t *) value);
|
|
#else
|
|
return PyLong_FromLong(*(const uval_t *) value);
|
|
#endif
|
|
case IDPOPT_BIT:
|
|
return PyLong_FromLong(*(const int *) value);
|
|
case IDPOPT_I64:
|
|
return PyLong_FromLongLong(*(const int64 *) value);
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
private:
|
|
static ssize_t bool_to_insn_t_size(bool in, const insn_t *insn) { return in ? insn->size : 0; }
|
|
static ssize_t bool_to_1or0(bool in) { return in ? 1 : 0; }
|
|
static ssize_t cm_t_to_ssize_t(cm_t cm) { return ssize_t(cm); }
|
|
static bool _handle_qstring_output(PyObject *o, qstring *buf)
|
|
{
|
|
bool is_str = o != nullptr && PyUnicode_Check(o);
|
|
if ( is_str && buf != nullptr )
|
|
PyUnicode_as_qstring(buf, o);
|
|
Py_XDECREF(o);
|
|
return is_str;
|
|
}
|
|
static ssize_t handle_custom_mnem_output(PyObject *o, qstring *out, const insn_t *)
|
|
{
|
|
return _handle_qstring_output(o, out) && !out->empty() ? 1 : 0;
|
|
}
|
|
static ssize_t handle_assemble_output(
|
|
PyObject *o,
|
|
uchar *bin,
|
|
ea_t /*ea*/,
|
|
ea_t /*cs*/,
|
|
ea_t /*ip*/,
|
|
bool /*use32*/,
|
|
const char * /*line*/)
|
|
{
|
|
ssize_t rc = 0;
|
|
if ( o != nullptr && PyBytes_Check(o) )
|
|
{
|
|
char *s;
|
|
Py_ssize_t len = 0;
|
|
if ( PyBytes_AsStringAndSize(o, &s, &len) != -1 )
|
|
{
|
|
if ( len > MAXSTR )
|
|
len = MAXSTR;
|
|
memcpy(bin, s, len);
|
|
}
|
|
rc = ssize_t(len);
|
|
}
|
|
Py_XDECREF(o);
|
|
return rc;
|
|
}
|
|
static ssize_t handle_get_reg_name_output(PyObject *o, qstring *buf, int /*reg*/, size_t /*width*/, int /*reghi*/)
|
|
{
|
|
return _handle_qstring_output(o, buf) ? buf->length() : 0;
|
|
}
|
|
static ssize_t handle_decorate_name3_output(PyObject *o, qstring *outbuf, const char * /*name*/, bool /*mangle*/, int /*cc*/, const tinfo_t * /*type*/)
|
|
{
|
|
return _handle_qstring_output(o, outbuf) ? 1 : 0;
|
|
}
|
|
static ssize_t handle_delay_slot_insn_output(PyObject *o, ea_t *pea, bool *pbexec, bool *pfexec)
|
|
{
|
|
if ( PySequence_Check(o) && PySequence_Size(o) == 3 )
|
|
{
|
|
newref_t py_ea(PySequence_GetItem(o, 0));
|
|
newref_t py_bexec(PySequence_GetItem(o, 1));
|
|
newref_t py_fexec(PySequence_GetItem(o, 2));
|
|
uint64 nea = 0;
|
|
if ( PyW_GetNumber(py_ea.o, &nea)
|
|
&& PyBool_Check(py_bexec.o)
|
|
&& PyBool_Check(py_fexec.o) )
|
|
{
|
|
if ( pea != nullptr )
|
|
*pea = nea;
|
|
if ( pbexec != nullptr )
|
|
*pbexec = py_bexec.o == Py_True;
|
|
if ( pfexec != nullptr )
|
|
*pfexec = py_fexec.o == Py_True;
|
|
return 1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
static ssize_t handle_use_regarg_type_output(PyObject *o, int *idx, ea_t, const funcargvec_t *)
|
|
{
|
|
ssize_t rc = 0;
|
|
if ( PySequence_Check(o) && PySequence_Size(o) == 2 )
|
|
{
|
|
newref_t py_rc(PySequence_GetItem(o, 0));
|
|
newref_t py_idx(PySequence_GetItem(o, 1));
|
|
if ( PyLong_Check(py_rc.o) && PyLong_Check(py_idx.o) )
|
|
{
|
|
rc = PyLong_AsLong(py_rc.o);
|
|
*idx = PyLong_AsLong(py_idx.o);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
static ssize_t handle_demangle_name_output(
|
|
PyObject *o,
|
|
int32 *out_res,
|
|
qstring *out,
|
|
const char * /*name*/,
|
|
uint32 /*disable_mask*/,
|
|
demreq_type_t /*demreq*/)
|
|
{
|
|
ssize_t rc = 0;
|
|
if ( PySequence_Check(o) && PySequence_Size(o) == 3 )
|
|
{
|
|
newref_t py_rc(PySequence_GetItem(o, 0));
|
|
newref_t py_out(PySequence_GetItem(o, 1));
|
|
newref_t py_out_res(PySequence_GetItem(o, 2));
|
|
qstring qs;
|
|
if ( PyLong_Check(py_rc.o)
|
|
&& PyLong_Check(py_out_res.o)
|
|
&& PyUnicode_Check(py_out.o)
|
|
&& PyUnicode_as_qstring(&qs, py_out.o) )
|
|
{
|
|
rc = PyLong_AsLong(py_rc.o);
|
|
*out_res = PyLong_AsLong(py_out_res.o);
|
|
if ( out != nullptr )
|
|
out->swap(qs);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
static ssize_t handle_find_value_output(
|
|
PyObject *o,
|
|
uval_t *out,
|
|
const insn_t * /*pinsn*/,
|
|
int /*reg*/)
|
|
{
|
|
uint64 num;
|
|
ssize_t rc = PyW_GetNumber(o, &num);
|
|
if ( rc )
|
|
*out = num;
|
|
return rc;
|
|
}
|
|
static ssize_t handle_get_autocmt_output(
|
|
PyObject *o,
|
|
qstring *buf,
|
|
const insn_t * /*pinsn*/)
|
|
{
|
|
return PyUnicode_Check(o) && PyUnicode_as_qstring(buf, o);
|
|
}
|
|
static ssize_t handle_get_operand_string_output(
|
|
PyObject *o,
|
|
qstring *buf,
|
|
const insn_t * /*pinsn*/,
|
|
int /*opnum*/)
|
|
{
|
|
return PyUnicode_Check(o) && PyUnicode_as_qstring(buf, o);
|
|
}
|
|
};
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *_wrap_addr_in_pycapsule(void *addr);
|
|
PyObject *get_idp_notifier_addr(PyObject *)
|
|
{
|
|
return _wrap_addr_in_pycapsule((void *) IDP_Callback);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
PyObject *get_idp_notifier_ud_addr(IDP_Hooks *hooks)
|
|
{
|
|
return _wrap_addr_in_pycapsule(hooks);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
inline bool delay_slot_insn(ea_t *ea, bool *bexec, bool *fexec)
|
|
{
|
|
processor_t &ph = PH;
|
|
return ph.delay_slot_insn(ea, bexec, fexec);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
inline const char *get_reg_info(const char *regname, bitrange_t *bitrange)
|
|
{
|
|
processor_t &ph = PH;
|
|
return ph.get_reg_info(regname, bitrange);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
inline size_t sizeof_ldbl(void)
|
|
{
|
|
processor_t &ph = PH;
|
|
return ph.sizeof_ldbl();
|
|
}
|
|
//</inline(py_idp)>
|
|
|
|
//-------------------------------------------------------------------------
|
|
//<code(py_idp)>
|
|
|
|
// hookgenIDP:methodsinfo_def
|
|
|
|
//-------------------------------------------------------------------------
|
|
static PyObject *_wrap_addr_in_pycapsule(void *addr)
|
|
{
|
|
return PyCapsule_New(addr, VALID_CAPSULE_NAME, nullptr);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
ssize_t idaapi IDP_Callback(void *ud, int code, va_list va)
|
|
{
|
|
// hookgenIDP:safecall=IDP_Hooks
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static const regval_t *idaapi _py_getreg(
|
|
const char *name,
|
|
const regval_t *regvals)
|
|
{
|
|
for ( int i=dbg->nregisters - 1; i >= 0; i-- )
|
|
{
|
|
if ( strieq(name, dbg->regs(i).name) )
|
|
return ®vals[i];
|
|
}
|
|
static regval_t rv;
|
|
return &rv;
|
|
}
|
|
//-------------------------------------------------------------------------
|
|
//</code(py_idp)>
|
|
//-------------------------------------------------------------------------
|
|
|
|
#endif
|