Files
idapython-src/pywraps/py_hexrays.hpp
T
2016-08-09 10:01:18 +02:00

440 lines
14 KiB
C++

//-------------------------------------------------------------------------
//<code(py_hexrays)>
#ifdef WITH_HEXRAYS
hexdsp_t *hexdsp = NULL;
#endif // WITH_HEXRAYS
//-------------------------------------------------------------------------
qstring_printer_t *new_qstring_printer_t(const cfunc_t *f, bool tags)
{
return new qstring_printer_t(f, * (new qstring()), tags);
}
//-------------------------------------------------------------------------
void delete_qstring_printer_t(qstring_printer_t *qs)
{
delete &(qs->s);
delete qs;
}
//---------------------------------------------------------------------
static int hexrays_python_call(ref_t fct, ref_t args)
{
PYW_GIL_GET;
newref_t resultobj(PyEval_CallObject(fct.o, args.o));
if ( PyErr_Occurred() )
{
PyErr_Print();
return 0;
}
int result;
if ( SWIG_IsOK(SWIG_AsVal_int(resultobj.o, &result)) )
return result;
msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n");
return 0;
}
//---------------------------------------------------------------------
static bool idaapi __python_custom_viewer_popup_item_callback(void *ud)
{
PYW_GIL_GET;
int ret;
borref_t fct((PyObject *)ud);
newref_t nil(NULL);
ret = hexrays_python_call(fct, nil);
return ret ? true : false;
}
//---------------------------------------------------------------------
static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_list va)
{
PYW_GIL_GET;
int ret;
borref_t fct((PyObject *)ud);
switch ( event )
{
case hxe_maturity:
///< Ctree maturity level is being changed.
///< cfunc_t *cfunc
///< ctree_maturity_t new_maturity
{
cfunc_t *arg0 = va_arg(va, cfunc_t *);
ctree_maturity_t arg1 = va_argi(va, ctree_maturity_t);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 ));
newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_interr:
///< Internal error has occurred.
///< int errcode
{
int arg0 = va_argi(va, int);
newref_t args(Py_BuildValue("(ii)", event, arg0));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_print_func:
///< Printing ctree and generating text.
///< cfunc_t *cfunc
///< vc_printer_t *vp
///< Returns: 1 if text has been generated by the plugin
{
cfunc_t *arg0 = va_arg(va, cfunc_t *);
vc_printer_t *arg1 = va_arg(va, vc_printer_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 ));
newref_t arg1obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg1), SWIGTYPE_p_vc_printer_t, 0 ));
newref_t args(Py_BuildValue("(iOO)", event, arg0obj.o, arg1obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_func_printed:
///< Function text has been generated. Plugins may
///< modify the text in \ref sv.
///< cfunc_t *cfunc
{
cfunc_t *arg0 = va_arg(va, cfunc_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
// User interface related events:
case hxe_open_pseudocode:
///< New pseudocode view has been opened.
///< vdui_t *vu
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_switch_pseudocode:
///< Existing pseudocode view has been reloaded
///< with a new function. Its text has not been
///< refreshed yet, only cfunc and mba pointers are ready.
///< vdui_t *vu
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_refresh_pseudocode:
///< Existing pseudocode text has been refreshed.
///< vdui_t *vu
///< See also hxe_text_ready, which happens earlier
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_close_pseudocode:
///< Pseudocode view is being closed.
///< vdui_t *vu
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_keyboard:
///< Keyboard has been hit.
///< vdui_t *vu
///< int key_code (VK_...)
///< int shift_state
///< Should return: 1 if the event has been handled
{
vdui_t *arg0 = va_arg(va, vdui_t *);
int arg1 = va_argi(va, int);
int arg2 = va_argi(va, int);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iOii)", event, arg0obj.o, arg1, arg2));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_right_click:
///< Mouse right click. We can add menu items now.
///< vdui_t *vu
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_double_click:
///< Mouse double click.
///< vdui_t *vu
///< int shift_state
///< Should return: 1 if the event has been handled
{
vdui_t *arg0 = va_arg(va, vdui_t *);
int arg1 = va_argi(va, int);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_curpos:
///< Current cursor position has been changed.
///< (for example, by left-clicking or using keyboard)
///< vdui_t *vu
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_create_hint:
///< Create a hint for the current item.
///< vdui_t *vu
///< qstring *result_hint
///< int *implines
///< Possible return values:
///< 0: the event has not been handled
///< 1: hint has been created (should set *implines to nonzero as well)
///< 2: hint has been created but the standard hints must be
///< appended by the decompiler
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_text_ready:
///< Decompiled text is ready.
///< vdui_t *vu
///< This event can be used to modify the output text (sv).
///< The text uses regular color codes (see lines.hpp)
///< COLOR_ADDR is used to store pointers to ctree elements
{
vdui_t *arg0 = va_arg(va, vdui_t *);
newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 ));
newref_t args(Py_BuildValue("(iO)", event, arg0obj.o));
ret = hexrays_python_call(fct, args);
}
break;
case hxe_populating_popup:
///< Populating popup menu. We can add menu items now.
///< TForm *form
///< TPopupMenu *popup_handle
///< vdui_t *vu
{
TForm *form = va_arg(va, TForm *);
TPopupMenu *pp = va_arg(va, TPopupMenu*);
vdui_t *vdui = va_arg(va, vdui_t *);
newref_t py_form(SWIG_NewPointerObj(SWIG_as_voidptr(form), SWIGTYPE_p_Forms__TForm, 0));
newref_t py_popup(SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_Menus__TPopupMenu, 0));
newref_t py_vdui(SWIG_NewPointerObj(SWIG_as_voidptr(vdui), SWIGTYPE_p_vdui_t, 0 ));
newref_t py_args(Py_BuildValue("(iOOO)", event, py_form.o, py_popup.o, py_vdui.o));
ret = hexrays_python_call(fct, py_args);
}
break;
default:
//~ msg("IDAPython: Unknown event `%u' occured\n", event);
ret = 0;
break;
}
return ret;
}
//-------------------------------------------------------------------------
// A set of cfuncptr_t objects that were created from IDAPython.
// This is necessary in order to delete those objects before the hexrays
// plugin is unloaded. Otherwise, IDAPython will still delete them, but
// the plugin's 'hexdsp' dispatcher function will point to dlclose()'d
// code.
static qvector<cfuncptr_t*> python_cfuncptrs;
void hexrays_clear_python_cfuncptr_t_references(void)
{
for ( size_t i = 0, n = python_cfuncptrs.size(); i < n; ++i )
python_cfuncptrs[i]->reset();
// NOTE: Don't clear() the array of pointers. All the python-exposed
// cfuncptr_t instances will be deleted through the python
// shutdown/ref-decrementing process anyway, and the entries will be
// properly pulled out of the vector when that happens.
}
//-------------------------------------------------------------------------
void hexrays_register_python_cfuncptr_t_instance(cfuncptr_t *fp)
{
QASSERT(30457, !python_cfuncptrs.has(fp));
python_cfuncptrs.push_back(fp);
}
//-------------------------------------------------------------------------
void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp)
{
qvector<cfuncptr_t*>::iterator found = python_cfuncptrs.find(fp);
if ( found != python_cfuncptrs.end() )
{
fp->reset();
python_cfuncptrs.erase(found);
}
}
//-------------------------------------------------------------------------
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf)
{
try
{
cfuncptr_t cfunc = decompile(pfn, hf);
return cfunc;
}
catch(...)
{
error("Hex-Rays Python: decompiler threw an exception.\n");
}
return cfuncptr_t(0);
}
//-------------------------------------------------------------------------
static bool is_hexrays_plugin(const plugin_info_t *pinfo)
{
bool is_hx = false;
if ( pinfo != NULL && pinfo->entry != NULL )
{
const plugin_t *p = pinfo->entry;
if ( streq(p->wanted_name, "Hex-Rays Decompiler") )
is_hx = true;
}
return is_hx;
}
//-------------------------------------------------------------------------
static void try_init()
{
init_hexrays_plugin(0);
if ( hexdsp != NULL )
msg("IDAPython Hex-Rays bindings initialized.\n");
}
//-------------------------------------------------------------------------
static int idaapi on_ui_notification(void *, int code, va_list va)
{
switch ( code )
{
case ui_plugin_loaded:
if ( hexdsp == NULL && is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
try_init();
break;
case ui_plugin_unloading:
{
if ( hexdsp != NULL )
{
// Hex-Rays will close. Make sure all the refcounted cfunc_t objects
// are cleared right away.
if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
{
hexrays_clear_python_cfuncptr_t_references();
hexdsp = NULL;
}
}
}
break;
}
return 0;
}
//</code(py_hexrays)>
//<inline(py_hexrays)>
//---------------------------------------------------------------------
extern hexdsp_t *hexdsp;
bool py_init_hexrays_plugin(int flags=0)
{
// Only initialize one time
if ( hexdsp == NULL )
return init_hexrays_plugin(flags);
else
return true;
}
//---------------------------------------------------------------------
void py_add_custom_viewer_popup_item(
TCustomControl *custom_viewer,
const char *title,
const char *hotkey,
PyObject *custom_viewer_popup_item_callback)
{
PYW_GIL_GET;
Py_INCREF(custom_viewer_popup_item_callback);
add_custom_viewer_popup_item(custom_viewer, title, hotkey, __python_custom_viewer_popup_item_callback, custom_viewer_popup_item_callback);
};
//---------------------------------------------------------------------
bool py_install_hexrays_callback(PyObject *hx_cblist_callback)
{
PYW_GIL_GET;
if ( install_hexrays_callback(__hexrays_python_callback, hx_cblist_callback) )
{
Py_INCREF(hx_cblist_callback);
return true;
}
return false;
}
//---------------------------------------------------------------------
int py_remove_hexrays_callback(PyObject *hx_cblist_callback)
{
PYW_GIL_GET;
int result, i;
result = remove_hexrays_callback(__hexrays_python_callback, hx_cblist_callback);
for ( i = 0; i < result; i++ )
Py_DECREF(hx_cblist_callback);
return result;
}
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf);
//-------------------------------------------------------------------------
bool py_decompile_many(const char *outfile, PyObject *funcaddrs, int flags)
{
eavec_t leas, *eas = NULL;
if ( funcaddrs != Py_None )
{
if ( !PyW_PyListToEaVec(funcaddrs, leas) )
return false;
eas = &leas;
}
return decompile_many(outfile, eas, flags);
}
//-------------------------------------------------------------------------
// Some examples will want to use action_handler_t's whose update() method
// calls get_tform_vdui() to figure out whether the action should be enabled
// for the current form. Unfortunately, if hexrays is first unloaded before
// the widget cleanup is performed (e.g., while loading another IDB),
// the action would crash. Ideally we should wrap all toplevel calls
// with such wrappers, but it doesn't seem to be really necessary at the
// moment: only corner-cases will reveal this issue (reported by
// the idapython_hr-decompile test.)
vdui_t *py_get_tform_vdui(TForm *f)
{
return hexdsp != NULL ? get_tform_vdui(f) : NULL;
}
//</inline(py_hexrays)>
//<init(py_hexrays)>
try_init();
hook_to_notification_point(HT_UI, on_ui_notification, NULL);
//</init(py_hexrays)>