//------------------------------------------------------------------------- // #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 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::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; } // // //--------------------------------------------------------------------- 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; } // // try_init(); hook_to_notification_point(HT_UI, on_ui_notification, NULL); //