#ifndef __PY_IDP__
#define __PY_IDP__
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
/*
#
def AssembleLine(ea, cs, ip, use32, line):
"""
Assemble an instruction to a string (display a warning if an error is found)
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment
@param line: line to assemble
@return:
- None on failure
- or a string containing the assembled instruction
"""
pass
#
*/
static PyObject *AssembleLine(
ea_t ea,
ea_t cs,
ea_t ip,
bool use32,
const char *line)
{
int inslen;
char buf[MAXSTR];
bool ok = false;
if (ph.notify != NULL &&
(inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf)) > 0)
{
ok = true;
}
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( ok )
return PyString_FromStringAndSize(buf, inslen);
else
Py_RETURN_NONE;
}
//---------------------------------------------------------------------------
/*
#
def assemble(ea, cs, ip, use32, line):
"""
Assemble an instruction into the database (display a warning if an error is found)
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment?
@param line: line to assemble
@return: Boolean. True on success.
"""
#
*/
bool assemble(
ea_t ea,
ea_t cs,
ea_t ip,
bool use32,
const char *line)
{
int inslen;
char buf[MAXSTR];
PYW_GIL_CHECK_LOCKED_SCOPE();
bool rc = false;
Py_BEGIN_ALLOW_THREADS;
if (ph.notify != NULL)
{
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
if (inslen > 0)
{
patch_many_bytes(ea, buf, inslen);
rc = true;
}
}
Py_END_ALLOW_THREADS;
return rc;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_id():
"""
Returns the 'ph.id' field
"""
pass
#
*/
static size_t ph_get_id()
{
return ph.id;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_version():
"""
Returns the 'ph.version'
"""
pass
#
*/
static size_t ph_get_version()
{
return ph.version;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_flag():
"""
Returns the 'ph.flag'
"""
pass
#
*/
static size_t ph_get_flag()
{
return ph.flag;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_cnbits():
"""
Returns the 'ph.cnbits'
"""
pass
#
*/
static size_t ph_get_cnbits()
{
return ph.cnbits;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_dnbits():
"""
Returns the 'ph.dnbits'
"""
pass
#
*/
static size_t ph_get_dnbits()
{
return ph.dnbits;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_regFirstSreg():
"""
Returns the 'ph.regFirstSreg'
"""
pass
#
*/
static size_t ph_get_regFirstSreg()
{
return ph.regFirstSreg;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_regLastSreg():
"""
Returns the 'ph.regLastSreg'
"""
pass
#
*/
static size_t ph_get_regLastSreg()
{
return ph.regLastSreg;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_segreg_size():
"""
Returns the 'ph.segreg_size'
"""
pass
#
*/
static size_t ph_get_segreg_size()
{
return ph.segreg_size;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_regCodeSreg():
"""
Returns the 'ph.regCodeSreg'
"""
pass
#
*/
static size_t ph_get_regCodeSreg()
{
return ph.regCodeSreg;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_regDataSreg():
"""
Returns the 'ph.regDataSreg'
"""
pass
#
*/
static size_t ph_get_regDataSreg()
{
return ph.regDataSreg;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_high_fixup_bits():
"""
Returns the 'ph.high_fixup_bits'
"""
pass
#
*/
static size_t ph_get_high_fixup_bits()
{
return ph.high_fixup_bits;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_icode_return():
"""
Returns the 'ph.icode_return'
"""
pass
#
*/
static size_t ph_get_icode_return()
{
return ph.icode_return;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_instruc_start():
"""
Returns the 'ph.instruc_start'
"""
pass
#
*/
static size_t ph_get_instruc_start()
{
return ph.instruc_start;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_instruc_end():
"""
Returns the 'ph.instruc_end'
"""
pass
#
*/
static size_t ph_get_instruc_end()
{
return ph.instruc_end;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_tbyte_size():
"""
Returns the 'ph.tbyte_size' field as defined in he processor module
"""
pass
#
*/
static size_t ph_get_tbyte_size()
{
return ph.tbyte_size;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_instruc():
"""
Returns a list of tuples (instruction_name, instruction_feature) containing the
instructions list as defined in he processor module
"""
pass
#
*/
static PyObject *ph_get_instruc()
{
Py_ssize_t i = 0;
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *py_result = PyTuple_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 )
{
PyTuple_SetItem(py_result, i++, Py_BuildValue("(sI)", p->name, p->feature));
}
return py_result;
}
//-------------------------------------------------------------------------
/*
#
def ph_get_regnames():
"""
Returns the list of register names as defined in the processor module
"""
pass
#
*/
static PyObject *ph_get_regnames()
{
Py_ssize_t i = 0;
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *py_result = PyList_New(ph.regsNum);
for ( Py_ssize_t i=0; i
def ph_get_operand_info():
"""
Returns the operand information given an ea and operand number.
@param ea: address
@param n: operand number
@return: Returns an idd_opinfo_t as a tuple: (modified, ea, reg_ival, regidx, value_size).
Please refer to idd_opinfo_t structure in the SDK.
"""
pass
#
*/
static PyObject *ph_get_operand_info(
ea_t ea,
int n)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
bool ok = false;
idd_opinfo_t opinf;
Py_BEGIN_ALLOW_THREADS;
do
{
if ( dbg == NULL || n == - 1 )
break;
// Allocate register space
thid_t tid = get_current_thread();
regvals_t regvalues;
regvalues.resize(dbg->registers_size);
// Read registers
if ( get_reg_vals(tid, -1, regvalues.begin()) != 1 )
break;
// Call the processor module
if ( ph.notify(ph.get_operand_info,
ea,
n,
tid,
_py_getreg,
regvalues.begin(),
&opinf) != 0 )
{
break;
}
ok = true;
} while (false);
Py_END_ALLOW_THREADS;
if ( ok )
return Py_BuildValue("(i" PY_FMT64 "Kii)",
opinf.modified,
opinf.ea,
opinf.value.ival,
opinf.debregidx,
opinf.value_size);
else
Py_RETURN_NONE;
}
//-------------------------------------------------------------------------
/*
#
class IDP_Hooks(object):
def hook(self):
"""
Creates an IDP hook
@return: Boolean true on success
"""
pass
def unhook(self):
"""
Removes the IDP hook
@return: Boolean true on success
"""
pass
def custom_ana(self):
"""
Analyzes and decodes an instruction at idaapi.cmd.ea
- cmd.itype must be set >= idaapi.CUSTOM_CMD_ITYPE
- cmd.size must be set to the instruction length
@return: Boolean
- False if the instruction is not recognized
- True if the instruction was decoded. idaapi.cmd should be filled in that case.
"""
pass
def custom_out(self):
"""
Outputs the instruction defined in idaapi.cmd
@return: Boolean (whether this instruction can be outputted or not)
"""
pass
def custom_emu(self):
"""
Emulate instruction, create cross-references, plan to analyze
subsequent instructions, modify flags etc. Upon entrance to this function
all information about the instruction is in 'cmd' structure.
@return: Boolean (whether this instruction has been emulated or not)
"""
pass
def custom_outop(self, op):
"""
Notification to generate operand text.
If False was returned, then the standard operand output function will be called.
The output buffer is inited with init_output_buffer()
and this notification may use out_...() functions to form the operand text
@return: Boolean (whether the operand has been outputted or not)
"""
pass
def custom_mnem(self):
"""
Prints the mnemonic of the instruction defined in idaapi.cmd
@return:
- None: No mnemonic. IDA will use the default mnemonic value if present
- String: The desired mnemonic string
"""
pass
def is_sane_insn(self, no_crefs):
"""
is the instruction sane for the current file type?
@param no_crefs:
- 1: the instruction has no code refs to it.
ida just tries to convert unexplored bytes
to an instruction (but there is no other
reason to convert them into an instruction)
- 0: the instruction is created because
of some coderef, user request or another
weighty reason.
@return: 1-ok, <=0-no, the instruction isn't likely to appear in the program
"""
pass
def may_be_func(self, no_crefs):
"""
Can a function start here?
@param state: autoanalysis phase
0: creating functions
1: creating chunks
@return: integer (probability 0..100)
"""
pass
def closebase(self):
"""
The database will be closed now
"""
pass
def savebase(self):
"""
The database is being saved. Processor module should
"""
pass
def rename(self, ea, new_name):
"""
The kernel is going to rename a byte.
@param ea: Address
@param new_name: The new name
@return:
- If returns value <=0, then the kernel should
not rename it. See also the 'renamed' event
"""
pass
def renamed(self, ea, new_name, local_name):
"""
The kernel has renamed a byte
@param ea: Address
@param new_name: The new name
@param local_name: Is local name
@return: Ignored
"""
pass
def undefine(self, ea):
"""
An item in the database (insn or data) is being deleted
@param ea: Address
@return:
- returns: >0-ok, <=0-the kernel should stop
- if the return value is positive:
bit0 - ignored
bit1 - do not delete srareas at the item end
"""
pass
def make_code(self, ea, size):
"""
An instruction is being created
@param ea: Address
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
pass
def make_code(self, ea, size):
"""
An instruction is being created
@param ea: Address
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
pass
def make_data(self, ea, flags, tid, len):
"""
A data item is being created
@param ea: Address
@param tid: type id
@param flags: item flags
@param len: data item size
@return: 1-ok, <=0-the kernel should stop
"""
pass
def load_idasgn(self, short_sig_name):
"""
FLIRT signature have been loaded for normal processing
(not for recognition of startup sequences)
@param short_sig_name: signature name
@return: Ignored
"""
pass
def add_func(self, func):
"""
The kernel has added a function
@param func: the func_t instance
@return: Ignored
"""
pass
def del_func(self, func):
"""
The kernel is about to delete a function
@param func: the func_t instance
@return: 1-ok,<=0-do not delete
"""
pass
def is_call_insn(self, ea, func_name):
"""
Is the instruction a "call"?
@param ea: instruction address
@return: 1-unknown, 0-no, 2-yes
"""
pass
def is_ret_insn(self, ea, func_name):
"""
Is the instruction a "return"?
@param ea: instruction address
@param strict: - True: report only ret instructions
False: include instructions like "leave" which begins the function epilog
@return: 1-unknown, 0-no, 2-yes
"""
pass
def assemble(self, ea, cs, ip, use32, line):
"""
Assembles an instruction
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment?
@param line: line to assemble
@return: - None to let the underlying processor module assemble the line
- or a string containing the assembled buffer
"""
pass
#
*/
//---------------------------------------------------------------------------
// IDP hooks
//---------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
class IDP_Hooks
{
public:
virtual ~IDP_Hooks()
{
unhook();
}
bool hook()
{
return hook_to_notification_point(HT_IDP, IDP_Callback, this);
}
bool unhook()
{
return unhook_from_notification_point(HT_IDP, IDP_Callback, this);
}
virtual bool custom_ana()
{
return false;
}
virtual bool custom_out()
{
return false;
}
virtual bool custom_emu()
{
return false;
}
virtual bool custom_outop(PyObject *py_op)
{
return false;
}
virtual PyObject *custom_mnem()
{
Py_RETURN_NONE;
}
virtual int is_sane_insn(int no_crefs)
{
return 0;
}
virtual int may_be_func(int state)
{
return 0;
}
virtual int closebase()
{
return 0;
}
virtual void savebase()
{
}
virtual int rename(ea_t ea, const char *new_name)
{
return 0;
}
virtual void renamed(ea_t ea, const char *new_name, bool local_name)
{
}
virtual int undefine(ea_t ea)
{
return 0;
}
virtual int make_code(ea_t ea, asize_t size)
{
return 0;
}
virtual int make_data(ea_t ea, flags_t flags, tid_t tid, asize_t len)
{
return 0;
}
virtual void load_idasgn(const char *short_sig_name)
{
}
virtual void add_func(func_t *func)
{
}
virtual int del_func(func_t *func)
{
return 0;
}
virtual int is_call_insn(ea_t /*ea*/)
{
return 0;
}
virtual int is_ret_insn(ea_t /*ea*/, bool /*strict*/)
{
return 0;
}
virtual PyObject *assemble(
ea_t /*ea*/,
ea_t /*cs*/,
ea_t /*ip*/,
bool /*use32*/,
const char * /*line*/)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
Py_RETURN_NONE;
}
};
enum areacb_type_t
{
AREACB_TYPE_UNKNOWN,
AREACB_TYPE_FUNC,
AREACB_TYPE_SEGMENT,
AREACB_TYPE_HIDDEN_AREA,
AREACB_TYPE_SRAREA,
};
//---------------------------------------------------------------------------
// IDB hooks
//---------------------------------------------------------------------------
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
class IDB_Hooks
{
public:
virtual ~IDB_Hooks() { unhook(); };
bool hook()
{
return hook_to_notification_point(HT_IDB, IDB_Callback, this);
}
bool unhook()
{
return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
}
// Hook functions to override in Python
virtual int byte_patched(ea_t /*ea*/) { return 0; };
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; }
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
virtual int enum_created(enum_t /*id*/) { return 0; };
virtual int enum_deleted(enum_t /*id*/) { return 0; };
virtual int enum_bf_changed(enum_t /*id*/) { return 0; };
virtual int enum_renamed(enum_t /*id*/) { return 0; };
virtual int enum_cmt_changed(enum_t /*id*/) { return 0; };
virtual int enum_member_created(enum_t /*id*/, const_t cid) { return 0; };
virtual int enum_member_deleted(enum_t /*id*/, const_t cid) { return 0; };
virtual int struc_created(tid_t /*struc_id*/) { return 0; };
virtual int struc_deleted(tid_t /*struc_id*/) { return 0; };
virtual int struc_renamed(struc_t * /*sptr*/) { return 0; };
virtual int struc_expanded(struc_t * /*sptr*/) { return 0; };
virtual int struc_cmt_changed(tid_t /*struc_id*/) { return 0; };
virtual int struc_member_created(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; };
virtual int struc_member_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { return 0; };
virtual int struc_member_renamed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; };
virtual int struc_member_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; };
virtual int thunk_func_created(func_t * /*pfn*/) { return 0; };
virtual int func_tail_appended(func_t * /*pfn*/, func_t * /*tail*/) { return 0; };
virtual int func_tail_removed(func_t * /*pfn*/, ea_t /*tail_ea*/) { return 0; };
virtual int tail_owner_changed(func_t * /*tail*/, ea_t /*owner_func*/) { return 0; };
virtual int func_noret_changed(func_t * /*pfn*/) { return 0; };
virtual int segm_added(segment_t * /*s*/) { return 0; };
virtual int segm_deleted(ea_t /*startEA*/) { return 0; };
virtual int segm_start_changed(segment_t * /*s*/) { return 0; };
virtual int segm_end_changed(segment_t * /*s*/) { return 0; };
virtual int segm_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; };
};
//
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
{
// This hook gets called from the kernel. Ensure we hold the GIL.
PYW_GIL_GET;
IDP_Hooks *proxy = (IDP_Hooks *)ud;
int ret = 0;
try
{
switch ( notification_code )
{
case processor_t::custom_ana:
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
break;
case processor_t::custom_out:
ret = proxy->custom_out() ? 2 : 0;
break;
case processor_t::custom_emu:
ret = proxy->custom_emu() ? 2 : 0;
break;
case processor_t::custom_outop:
{
op_t *op = va_arg(va, op_t *);
ref_t py_obj(create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op));
if ( py_obj == NULL )
break;
ret = proxy->custom_outop(py_obj.o) ? 2 : 0;
break;
}
case processor_t::custom_mnem:
{
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *py_ret = proxy->custom_mnem();
if ( py_ret != NULL && PyString_Check(py_ret) )
{
char *outbuffer = va_arg(va, char *);
size_t bufsize = va_arg(va, size_t);
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
ret = 2;
}
else
{
ret = 0;
}
Py_XDECREF(py_ret);
break;
}
case processor_t::is_sane_insn:
{
int no_crefs = va_arg(va, int);
ret = proxy->is_sane_insn(no_crefs);
break;
}
case processor_t::may_be_func:
{
int state = va_arg(va, int);
ret = proxy->may_be_func(state);
break;
}
case processor_t::closebase:
{
proxy->closebase();
break;
}
case processor_t::savebase:
{
proxy->savebase();
break;
}
case processor_t::rename:
{
ea_t ea = va_arg(va, ea_t);
const char *new_name = va_arg(va, const char *);
ret = proxy->rename(ea, new_name);
break;
}
case processor_t::renamed:
{
ea_t ea = va_arg(va, ea_t);
const char *new_name = va_arg(va, const char *);
bool local_name = va_argi(va, bool);
proxy->renamed(ea, new_name, local_name);
break;
}
case processor_t::undefine:
{
ea_t ea = va_arg(va, ea_t);
ret = proxy->undefine(ea);
break;
}
case processor_t::make_code:
{
ea_t ea = va_arg(va, ea_t);
asize_t size = va_arg(va, asize_t);
ret = proxy->make_code(ea, size);
break;
}
case processor_t::make_data:
{
ea_t ea = va_arg(va, ea_t);
flags_t flags = va_arg(va, flags_t);
tid_t tid = va_arg(va, tid_t);
asize_t len = va_arg(va, asize_t);
ret = proxy->make_data(ea, flags, tid, len);
break;
}
case processor_t::load_idasgn:
{
const char *short_sig_name = va_arg(va, const char *);
proxy->load_idasgn(short_sig_name);
break;
}
case processor_t::add_func:
{
func_t *func = va_arg(va, func_t *);
proxy->add_func(func);
break;
}
case processor_t::del_func:
{
func_t *func = va_arg(va, func_t *);
ret = proxy->del_func(func);
break;
}
case processor_t::is_call_insn:
{
ea_t ea = va_arg(va, ea_t);
ret = proxy->is_call_insn(ea);
break;
}
case processor_t::is_ret_insn:
{
ea_t ea = va_arg(va, ea_t);
bool strict = va_argi(va, bool);
ret = proxy->is_ret_insn(ea, strict);
break;
}
case processor_t::assemble:
{
ea_t ea = va_arg(va, ea_t);
ea_t cs = va_arg(va, ea_t);
ea_t ip = va_arg(va, ea_t);
bool use32 = va_argi(va, bool);
const char *line = va_arg(va, const char *);
// Extract user buffer (we hardcode the MAXSTR size limit)
uchar *bin = va_arg(va, uchar *);
// Call python
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *py_buffer = proxy->assemble(ea, cs, ip, use32, line);
if ( py_buffer != NULL && PyString_Check(py_buffer) )
{
char *s;
Py_ssize_t len;
if ( PyString_AsStringAndSize(py_buffer, &s, &len) != -1 )
{
if ( len > MAXSTR )
len = MAXSTR;
memcpy(bin, s, len);
ret = len;
}
}
// ret = 0 otherwise
Py_XDECREF(py_buffer);
break;
}
// validate_flirt_func, // flirt has recognized a library function
// // this callback can be used by a plugin or proc module
// // to intercept it and validate such a function
// // args: ea_t start_ea
// // const char *funcname
// // returns: -1-do not create a function,
// // 1-function is validated
// // the idp module is allowed to modify 'cmd'
// set_func_start, // Function chunk start address will be changed
// // args: func_t *pfn
// // ea_t new_start
// // Returns: 1-ok,<=0-do not change
// set_func_end, // Function chunk end address will be changed
// // args: func_t *pfn
// // ea_t new_end
// // Returns: 1-ok,<=0-do not change
// outlabel, // The kernel is going to generate an instruction
// // label line or a function header
// // args:
// // ea_t ea -
// // const char *colored_name -
// // If returns value <=0, then the kernel should
// // not generate the label
// may_show_sreg, // The kernel wants to display the segment registers
// // in the messages window.
// // arg - ea_t current_ea
// // if this function returns 0
// // then the kernel will not show
// // the segment registers.
// // (assuming that the module have done it)
// coagulate, // Try to define some unexplored bytes
// // This notification will be called if the
// // kernel tried all possibilities and could
// // not find anything more useful than to
// // convert to array of bytes.
// // The module can help the kernel and convert
// // the bytes into something more useful.
// // arg:
// // ea_t start_ea
// // returns: number of converted bytes + 1
// auto_empty, // Info: all analysis queues are empty
// // args: none
// // returns: none
// // This callback is called once when the
// // initial analysis is finished. If the queue is
// // not empty upon the return from this callback,
// // it will be called later again.
// // See also auto_empty_finally.
// auto_queue_empty, // One analysis queue is empty
// // args: atype_t type
// // returns: 1-yes, keep the queue empty
// // <=0-no, the queue is not empty anymore
// // This callback can be called many times, so
// // only the autoMark() functions can be used from it
// // (other functions may work but it is not tested)
// func_bounds, // find_func_bounds() finished its work
// // The module may fine tune the function bounds
// // args: int *possible_return_code
// // func_t *pfn
// // ea_t max_func_end_ea (from the kernel's point of view)
// // returns: none
// is_jump_func, // is the function a trivial "jump" function?
// // args: func_t *pfn
// // ea_t *jump_target
// // ea_t *func_pointer
// // returns: 0-no, 1-don't know, 2-yes, see jump_target
// // and func_pointer
// gen_regvar_def, // generate register variable definition line
// // args: regvar_t *v
// // returns: 0-ok
// setsgr, // The kernel has changed a segment register value
// // args: ea_t startEA
// // ea_t endEA
// // int regnum
// // sel_t value
// // sel_t old_value
// // uchar tag (SR_... values)
// // returns: 1-ok, 0-error
// set_compiler, // The kernel has changed the compiler information
// // (inf.cc structure)
// is_basic_block_end, // Is the current instruction end of a basic block?
// // This function should be defined for processors
// // with delayed jump slots. The current instruction
// // is stored in 'cmd'
// // args: bool call_insn_stops_block
// // returns: 1-unknown, 0-no, 2-yes
// reglink, // IBM PC only, ignore it
// get_vxd_name, // IBM PC only, ignore it
// // Get Vxd function name
// // args: int vxdnum
// // int funcnum
// // char *outbuf
// // returns: nothing
//
//
// moving_segm, // May the kernel move the segment?
// // args: segment_t - segment to move
// // ea_t to - new segment start address
// // returns: 1-yes, <=0-the kernel should stop
// move_segm, // A segment is moved
// // Fix processor dependent address sensitive information
// // args: ea_t from - old segment address
// // segment_t* - moved segment
// // returns: nothing
//
//
// get_stkvar_scale_factor,// Should stack variable references be multiplied by
// // a coefficient before being used in the stack frame?
// // Currently used by TMS320C55 because the references into
// // the stack should be multiplied by 2
// // Returns: scaling factor
// // Note: PR_SCALE_STKVARS should be set to use this callback
//
// create_flat_group, // Create special segment representing the flat group
// // (to use for PC mainly)
// // args - ea_t image_base, int bitness, sel_t dataseg_sel
//
// kernel_config_loaded, // This callback is called when ida.cfg is parsed
// // args - none, returns - nothing
//
// might_change_sp, // Does the instruction at 'ea' modify the stack pointer?
// // args: ea_t ea
// // returns: 1-yes, 0-false
// // (not used yet)
//
// is_alloca_probe, // Does the function at 'ea' behave as __alloca_probe?
// // args: ea_t ea
// // returns: 2-yes, 1-false
//
// out_3byte, // Generate text representation of 3byte data
// // init_out_buffer() is called before this function
// // and all Out... function can be used.
// // uFlag contains the flags.
// // This callback might be implemented by the processor
// // module to generate custom representation of 3byte data.
// // args:
// // ea_t dataea - address of the data item
// // uint32 value - value to output
// // bool analyze_only - only create xrefs if necessary
// // do not generate text representation
// // returns: 2-yes, 1-false
//
// get_reg_name, // Generate text representation of a register
// // int reg - internal register number as defined in the processor module
// // size_t width - register width in bytes
// // char *buf - output buffer
// // size_t bufsize - size of output buffer
// // int reghi - if not -1 then this function will return the register pair
// // returns: -1 if error, strlen(buf)+2 otherwise
// // Most processor modules do not need to implement this callback
// // It is useful only if ph.regNames[reg] does not provide
// // the correct register names
// // save its local data
// out_src_file_lnnum, // Callback: generate analog of
// // #line "file.c" 123
// // directive.
// // const char *file - source file (may be NULL)
// // size_t lnnum - line number
// // returns: 2-directive has been generated
// get_autocmt, // Callback: get dynamic auto comment
// // Will be called if the autocomments are enabled
// // and the comment retrieved from ida.int starts with
// // '$!'. 'cmd' is contains valid info.
// // char *buf - output buffer
// // size_t bufsize - output buffer size
// // returns: 2-new comment has been generated
// // 1-callback has not been handled
// // the buffer must not be changed in this case
// is_insn_table_jump, // Callback: determine if instruction is a table jump or call
// // If CF_JUMP bit can not describe all kinds of table
// // jumps, please define this callback.
// // It will be called for insns with CF_JUMP bit set.
// // input: cmd structure contains the current instruction
// // returns: 1-yes, 0-no
// auto_empty_finally, // Info: all analysis queues are empty definitively
// // args: none
// // returns: none
// // This callback is called only once.
// // See also auto_empty.
// loader_finished, // Event: external file loader finished its work
// // linput_t *li
// // uint16 neflags
// // const char *filetypename
// // Use this event to augment the existing loader functionality
// loader_elf_machine, // Event: ELF loader machine type checkpoint
// // linput_t *li
// // int machine_type
// // const char **p_procname
// // proc_def **p_pd (see ldr\elf.h)
// // set_elf_reloc_t *set_reloc
// // A plugin check the machine_type. If it is the desired one,
// // the the plugin fills p_procname with the processor name.
// // p_pd is used to handle relocations, otherwise can be left untouched
// // set_reloc can be later used by the plugin to specify relocations
// // returns: e_machine value (if it is different from the
// // original e_machine value, procname and p_pd will be ignored
// // and the new value will be used)
// // This event occurs for each loaded ELF file
// is_indirect_jump, // Callback: determine if instruction is an indrect jump
// // If CF_JUMP bit can not describe all jump types
// // jumps, please define this callback.
// // input: cmd structure contains the current instruction
// // returns: 1-use CF_JUMP, 2-no, 3-yes
// verify_noreturn, // The kernel wants to set 'noreturn' flags for a function
// // func_t *pfn
// // Returns: 1-ok, any other value-do not set 'noreturn' flag
// verify_sp, // All function instructions have been analyzed
// // Now the processor module can analyze the stack pointer
// // for the whole function
// // input: func_t *pfn
// // Returns: 1-ok, 0-bad stack pointer
// treat_hindering_item, // An item hinders creation of another item
// // args: ea_t hindering_item_ea
// // flags_t new_item_flags (0 for code)
// // ea_t new_item_ea
// // asize_t new_item_length
// // Returns: 1-no reaction, <=0-the kernel may delete the hindering item
// str2reg, // Convert a register name to a register number
// // args: const char *regname
// // Returns: register number + 2
// // The register number is the register index in the regNames array
// // Most processor modules do not need to implement this callback
// // It is useful only if ph.regNames[reg] does not provide
// // the correct register names
// create_switch_xrefs, // Create xrefs for a custom jump table
// // in: ea_t jumpea; - address of the jump insn
// // switch_info_ex_t *; - switch information
// // returns: must return 2
// calc_switch_cases, // Calculate case values and targets for a custom jump table
// // in: ea_t insn_ea - address of the 'indirect jump' instruction
// // switch_info_ex_t *si - switch information
// // casevec_t *casevec - vector of case values...
// // evec_t *targets - ...and corresponding target addresses
// // casevec and targets may be NULL
// // returns: 2-ok, 1-failed
// determined_main, // The main() function has been determined
// // in: ea_t main - address of the main() function
// // returns: none
// preprocess_chart, // gui has retrieved a function flow chart
// // in: qflow_chart_t *fc
// // returns: none
// // Plugins may modify the flow chart in this callback
// get_bg_color, // Get item background color
// // in: ea_t ea, bgcolor_t *color
// // Returns: 1-not implemented, 2-color set
// // Plugins can hook this callback to color disassembly lines
// // dynamically
// get_operand_string, // Request text string for operand (cli, java, ...)
// // args: int opnum
// // char *buf
// // size_t buflen
// // (cmd structure must contain info for the desired insn)
// // opnum is the operand number; -1 means any string operand
// // returns: 1 - no string (or empty string)
// // >1 - original string length with terminating zero
//
// // the following 5 events are very low level
// // take care of possible recursion
// add_cref, // a code reference is being created
// // args: ea_t from, ea_t to, cref_t type
// // returns: <0 - cancel cref creation
// add_dref, // a data reference is being created
// // args: ea_t from, ea_t to, dref_t type
// // returns: <0 - cancel dref creation
// del_cref, // a code reference is being deleted
// // args: ea_t from, ea_t to, bool expand
// // returns: <0 - cancel cref deletion
// del_dref, // a data reference is being deleted
// // args: ea_t from, ea_t to
// // returns: <0 - cancel dref deletion
// coagulate_dref, // data reference is being analyzed
// // args: ea_t from, ea_t to, bool may_define, ea_t *code_ea
// // plugin may correct code_ea (e.g. for thumb mode refs, we clear the last bit)
// // returns: <0 - cancel dref analysis
// custom_fixup, // mutipurpose notification for FIXUP_CUSTOM
// // args: cust_fix oper, ea_t ea, const fixup_data_t*, ... (see cust_fix)
// // returns: 1 - no accepted (fixup ignored by ida)
// // >1 - accepted (see cust_fix)
// off_preproc, // called from get_offset_expr, when refinfo_t
// // contain flag REFINFO_PREPROC. Normally this
// // notification used in a combination with custom_fixup
// // args: ea_t ea, int numop, ea_t* opval, const refinfo_t* ri,
// // char* buf, size_t bufsize, ea_t* target,
// // ea_t* fullvalue, ea_t from, int getn_flags
// // returns: 2 - buf filled as simple expression
// // 3 - buf filled as complex expression
// // 4 - apply standard processing (with - possible - changed values)
// // others - can't convert to offset expression
//
// set_proc_options, // called if the user specified an option string in the command line:
// // -p:
// // can be used for e.g. setting a processor subtype
// // also called if option string is passed to set_processor_type()
// // and IDC's SetProcessorType()
// // args: const char * options
// // returns: <0 - bad option string
//
}
}
catch (Swig::DirectorException &e)
{
msg("Exception in IDP Hook function: %s\n", e.getMessage());
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( PyErr_Occurred() )
PyErr_Print();
}
return ret;
}
//---------------------------------------------------------------------------
int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
{
// This hook gets called from the kernel. Ensure we hold the GIL.
PYW_GIL_GET;
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
ea_t ea, ea2;
bool repeatable_cmt;
type_t *type;
p_list *fnames;
int n;
enum_t id;
const_t cid;
tid_t struc_id;
struc_t *sptr;
member_t *mptr;
tid_t member_id;
func_t *pfn;
func_t *tail;
segment_t *seg;
asize_t size;
try {
switch (notification_code)
{
case idb_event::byte_patched:
ea = va_arg(va, ea_t);
return proxy->byte_patched(ea);
case idb_event::cmt_changed:
ea = va_arg(va, ea_t);
repeatable_cmt = va_arg(va, int);
return proxy->cmt_changed(ea, repeatable_cmt);
case idb_event::area_cmt_changed:
{
areacb_t *cb = va_arg(va, areacb_t*);
area_t *area = va_arg(va, area_t*);
const char *cmt = va_arg(va, char*);
repeatable_cmt = va_arg(va, int);
return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt);
}
case idb_event::ti_changed:
ea = va_arg(va, ea_t);
type = va_arg(va, type_t *);
fnames = va_arg(va, p_list *);
return proxy->ti_changed(ea, type, fnames);
case idb_event::op_ti_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);
type = va_arg(va, type_t *);
fnames = va_arg(va, p_list *);
return proxy->op_ti_changed(ea, n, type, fnames);
case idb_event::op_type_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);
return proxy->op_type_changed(ea, n);
case idb_event::enum_created:
id = va_arg(va, enum_t);
return proxy->enum_created(id);
case idb_event::enum_deleted:
id = va_arg(va, enum_t);
return proxy->enum_deleted(id);
case idb_event::enum_bf_changed:
id = va_arg(va, enum_t);
return proxy->enum_bf_changed(id);
case idb_event::enum_cmt_changed:
id = va_arg(va, enum_t);
return proxy->enum_cmt_changed(id);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_created:
#else
case idb_event::enum_const_created:
#endif
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_created(id, cid);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_deleted:
#else
case idb_event::enum_const_deleted:
#endif
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_deleted(id, cid);
case idb_event::struc_created:
struc_id = va_arg(va, tid_t);
return proxy->struc_created(struc_id);
case idb_event::struc_deleted:
struc_id = va_arg(va, tid_t);
return proxy->struc_deleted(struc_id);
case idb_event::struc_renamed:
sptr = va_arg(va, struc_t *);
return proxy->struc_renamed(sptr);
case idb_event::struc_expanded:
sptr = va_arg(va, struc_t *);
return proxy->struc_expanded(sptr);
case idb_event::struc_cmt_changed:
struc_id = va_arg(va, tid_t);
return proxy->struc_cmt_changed(struc_id);
case idb_event::struc_member_created:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_created(sptr, mptr);
case idb_event::struc_member_deleted:
sptr = va_arg(va, struc_t *);
member_id = va_arg(va, tid_t);
ea = va_arg(va, ea_t);
return proxy->struc_member_deleted(sptr, member_id, ea);
case idb_event::struc_member_renamed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_renamed(sptr, mptr);
case idb_event::struc_member_changed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_changed(sptr, mptr);
case idb_event::thunk_func_created:
pfn = va_arg(va, func_t *);
return proxy->thunk_func_created(pfn);
case idb_event::func_tail_appended:
pfn = va_arg(va, func_t *);
tail = va_arg(va, func_t *);
return proxy->func_tail_appended(pfn, tail);
case idb_event::func_tail_removed:
pfn = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->func_tail_removed(pfn, ea);
case idb_event::tail_owner_changed:
tail = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->tail_owner_changed(tail, ea);
case idb_event::func_noret_changed:
pfn = va_arg(va, func_t *);
return proxy->func_noret_changed(pfn);
case idb_event::segm_added:
seg = va_arg(va, segment_t *);
return proxy->segm_added(seg);
case idb_event::segm_deleted:
ea = va_arg(va, ea_t);
return proxy->segm_deleted(ea);
case idb_event::segm_start_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_start_changed(seg);
case idb_event::segm_end_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_end_changed(seg);
case idb_event::segm_moved:
ea = va_arg(va, ea_t);
ea2 = va_arg(va, ea_t);
size = va_arg(va, asize_t);
return proxy->segm_moved(ea, ea2, size);
}
}
catch (Swig::DirectorException &e)
{
msg("Exception in IDB Hook function: %s\n", e.getMessage());
PYW_GIL_CHECK_LOCKED_SCOPE();
if (PyErr_Occurred())
PyErr_Print();
}
return 0;
}
//-------------------------------------------------------------------------
static const regval_t *idaapi _py_getreg(
const char *name,
const regval_t *regvals)
{
for ( int i=dbg->registers_size - 1; i >= 0; i-- )
{
if ( stricmp(name, dbg->registers[i].name) == 0 )
return ®vals[i];
}
static regval_t rv;
return &rv;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
#endif