diff --git a/Scripts/3rd/BboeVt.py b/Scripts/3rd/BboeVt.py old mode 100644 new mode 100755 diff --git a/Scripts/AsmViewer.py b/Scripts/AsmViewer.py old mode 100644 new mode 100755 diff --git a/Scripts/CallStackWalk.py b/Scripts/CallStackWalk.py old mode 100644 new mode 100755 diff --git a/Scripts/DbgCmd.py b/Scripts/DbgCmd.py old mode 100644 new mode 100755 diff --git a/Scripts/DrvsDispatch.py b/Scripts/DrvsDispatch.py old mode 100644 new mode 100755 diff --git a/Scripts/ExchainDump.py b/Scripts/ExchainDump.py old mode 100644 new mode 100755 diff --git a/Scripts/FindInstructions.py b/Scripts/FindInstructions.py old mode 100644 new mode 100755 diff --git a/Scripts/ImpRef.py b/Scripts/ImpRef.py old mode 100644 new mode 100755 diff --git a/Scripts/ImportExportViewer.py b/Scripts/ImportExportViewer.py old mode 100644 new mode 100755 diff --git a/Scripts/SEHGraph.py b/Scripts/SEHGraph.py old mode 100644 new mode 100755 diff --git a/Scripts/VaDump.py b/Scripts/VaDump.py old mode 100644 new mode 100755 diff --git a/Scripts/VirusTotal.py b/Scripts/VirusTotal.py old mode 100644 new mode 100755 diff --git a/Scripts/callstack_test.py b/Scripts/callstack_test.py old mode 100644 new mode 100755 diff --git a/Scripts/msdnapihelp.py b/Scripts/msdnapihelp.py old mode 100644 new mode 100755 diff --git a/api_contents.txt b/api_contents.txt index 6593fb9..99cb140 100644 --- a/api_contents.txt +++ b/api_contents.txt @@ -95,6 +95,7 @@ 'IDP_Hooks_add_dref', 'IDP_Hooks_add_func', 'IDP_Hooks_adjust_libfunc_ea', + 'IDP_Hooks_adjust_refinfo', 'IDP_Hooks_assemble', 'IDP_Hooks_auto_empty', 'IDP_Hooks_auto_empty_finally', @@ -140,7 +141,6 @@ 'IDP_Hooks_get_func_cvtarg_map', 'IDP_Hooks_get_jump_target', 'IDP_Hooks_get_macro_insn_head', - 'IDP_Hooks_get_operand_info', 'IDP_Hooks_get_operand_string', 'IDP_Hooks_get_reg_info2', 'IDP_Hooks_get_reg_name', @@ -164,7 +164,6 @@ 'IDP_Hooks_kernel_config_loaded', 'IDP_Hooks_load_idasgn', 'IDP_Hooks_loader', - 'IDP_Hooks_loader_elf_machine', 'IDP_Hooks_loader_finished', 'IDP_Hooks_make_code', 'IDP_Hooks_make_data', @@ -179,7 +178,6 @@ 'IDP_Hooks_newfile', 'IDP_Hooks_newprc', 'IDP_Hooks_newseg', - 'IDP_Hooks_obsolete_get_operand_info', 'IDP_Hooks_obsolete_makemicro', 'IDP_Hooks_oldfile', 'IDP_Hooks_out_3byte', @@ -283,6 +281,7 @@ '_askseg', '_askseg__varargs__', '_decompile', + '_kludge_use_TPopupMenu', 'a2funcoff', 'accepts_udts', 'action_ctx_base_t_action_get', @@ -341,6 +340,7 @@ 'add_const', 'add_cref', 'add_custom_viewer_popup_item', + 'add_custom_viewer_popup_item__SWIG_1', 'add_dref', 'add_encoding', 'add_entry', @@ -416,6 +416,7 @@ 'append_func_tail', 'append_name', 'append_struct_fields2', + 'append_tinfo_covered', 'append_varloc', 'apply_callee_tinfo', 'apply_cdecl', @@ -557,6 +558,7 @@ 'argloc_t_is_custom', 'argloc_t_is_ea', 'argloc_t_is_fragmented', + 'argloc_t_is_mixed_scattered', 'argloc_t_is_reg', 'argloc_t_is_reg1', 'argloc_t_is_reg2', @@ -992,10 +994,9 @@ 'calc_reference_target', 'calc_stkvar_struc_offset', 'calc_switch_cases', - 'calc_switch_cases__SWIG_0', - 'calc_switch_cases__SWIG_1', 'calc_target', 'calc_thunk_func_target', + 'calc_tinfo_gaps', 'calc_type_size', 'calc_varloc_info', 'calcexpr', @@ -1456,6 +1457,7 @@ 'cinsn_t_creturn_get', 'cinsn_t_cswitch_get', 'cinsn_t_cwhile_get', + 'cinsn_t_is_epilog', 'cinsn_t_is_ordinary_flow', 'cinsn_t_new_insn', 'cinsn_t_print1', @@ -1540,6 +1542,7 @@ 'citem_t_print1', 'citem_t_swap', 'cleanup_appcall', + 'cleanup_name', 'cleanup_varloc', 'clearBreak', 'clear_cached_cfuncs', @@ -1599,7 +1602,8 @@ 'codeflag', 'compact_til', 'compare', - 'compare__SWIG_0', + 'compare', + 'compare', 'compare__SWIG_1', 'compare__SWIG_12', 'compare__SWIG_13', @@ -1621,6 +1625,7 @@ 'compare__SWIG_28', 'compare__SWIG_29', 'compare__SWIG_3', + 'compare__SWIG_3', 'compare__SWIG_30', 'compare__SWIG_4', 'compare__SWIG_5', @@ -1657,6 +1662,7 @@ 'convert_argloc_to_varloc', 'convert_encoding', 'convert_pt_flags_to_hti', + 'convert_to_user_call', 'convert_varloc_to_argloc', 'copy_srareas', 'copy_tinfo_t', @@ -1672,6 +1678,7 @@ 'create_helper__varargs__', 'create_insn', 'create_memory_linput', + 'create_menu', 'create_numbered_type_name', 'create_numbered_type_reference', 'create_source_viewer', @@ -1679,6 +1686,7 @@ 'create_switch_xrefs', 'create_tform', 'create_tinfo', + 'create_toolbar', 'create_typedef', 'create_typedef__SWIG_0', 'create_typedef__SWIG_1', @@ -2113,6 +2121,10 @@ 'delete_lvar_uservec_t', 'delete_lvars_t', 'delete_member_t', + 'delete_memreg_info_t', + 'delete_memreg_infos_t', + 'delete_menu', + 'delete_microcode_filter_t', 'delete_module_info_t', 'delete_netnode', 'delete_node_info_t', @@ -2140,6 +2152,7 @@ 'delete_refinfo_t', 'delete_reg_info_t', 'delete_regarg_t', + 'delete_reginfovec_t', 'delete_regobj_t', 'delete_regobjs_t', 'delete_regval_t', @@ -2178,6 +2191,7 @@ 'delete_til_t', 'delete_tinfo_t', 'delete_tinfo_visitor_t', + 'delete_toolbar', 'delete_treeloc_t', 'delete_twinpos_t', 'delete_type_attr_t', @@ -2188,6 +2202,9 @@ 'delete_type_visitor_t', 'delete_typedef_type_data_t', 'delete_uchar_array', + 'delete_udc_filter_t', + 'delete_udcall_map_iterator_t', + 'delete_udcall_t', 'delete_udt_member_t', 'delete_udt_type_data_t', 'delete_udtmembervec_t', @@ -2299,9 +2316,11 @@ 'disown_ctree_visitor_t', 'disown_enum_member_visitor_t', 'disown_highlighter_cbs_t', + 'disown_microcode_filter_t', 'disown_struct_field_visitor_t', 'disown_text_sink_t', 'disown_tinfo_visitor_t', + 'disown_udc_filter_t', 'disown_user_lvar_modifier_t', 'display_complex_call_chart', 'display_copyright_warning', @@ -2906,6 +2925,7 @@ 'get_c_header_path', 'get_c_macros', 'get_call_tev_callee', + 'get_chooser_data', 'get_chooser_obj', 'get_cmt', 'get_colored_demangled_name', @@ -3077,6 +3097,7 @@ 'get_hidden_area_num', 'get_hidden_area_qty', 'get_highlighted_identifier', + 'get_ida_subdirs', 'get_idainfo_by_type', 'get_idainfo_by_type2', 'get_idainfo_by_type3', @@ -3230,6 +3251,7 @@ 'get_reg_name', 'get_reg_val', 'get_reg_vals', + 'get_registered_actions', 'get_ret_tev_return', 'get_root_filename', 'get_running_notification', @@ -3318,7 +3340,6 @@ 'get_tev_info', 'get_tev_memory_info', 'get_tev_qty', - 'get_tev_reg_mem', 'get_tev_reg_mem_ea', 'get_tev_reg_mem_qty', 'get_tev_reg_val', @@ -3561,6 +3582,7 @@ 'idainfo_is_64bit', 'idainfo_is_dll', 'idainfo_is_flat_off32', + 'idainfo_is_hard_float', 'idainfo_is_mem_aligned4', 'idainfo_is_snapshot', 'idainfo_lenxref_get', @@ -3799,6 +3821,7 @@ 'install_command_interpreter', 'install_extlang', 'install_hexrays_callback', + 'install_microcode_filter', 'instant_dbgopts_t__pass_get', 'instant_dbgopts_t__pass_set', 'instant_dbgopts_t_attach_get', @@ -4193,6 +4216,7 @@ 'load_loader_module', 'load_plugin', 'load_til', + 'load_til2', 'load_til__SWIG_0', 'load_til__SWIG_1', 'load_til_header', @@ -4491,7 +4515,50 @@ 'member_t_soff_get', 'member_t_soff_set', 'member_t_unimem', + 'memreg_info_t_ea_get', + 'memreg_info_t_ea_set', + 'memreg_info_t_get_bytes', + 'memreg_infos_t___getitem__', + 'memreg_infos_t___len__', + 'memreg_infos_t___setitem__', + 'memreg_infos_t_at', + 'memreg_infos_t_back', + 'memreg_infos_t_back__SWIG_0', + 'memreg_infos_t_back__SWIG_1', + 'memreg_infos_t_begin', + 'memreg_infos_t_begin__SWIG_0', + 'memreg_infos_t_begin__SWIG_1', + 'memreg_infos_t_capacity', + 'memreg_infos_t_clear', + 'memreg_infos_t_empty', + 'memreg_infos_t_end', + 'memreg_infos_t_end__SWIG_0', + 'memreg_infos_t_end__SWIG_1', + 'memreg_infos_t_erase', + 'memreg_infos_t_erase__SWIG_0', + 'memreg_infos_t_erase__SWIG_1', + 'memreg_infos_t_extract', + 'memreg_infos_t_front', + 'memreg_infos_t_front__SWIG_0', + 'memreg_infos_t_front__SWIG_1', + 'memreg_infos_t_grow', + 'memreg_infos_t_inject', + 'memreg_infos_t_insert', + 'memreg_infos_t_pop_back', + 'memreg_infos_t_push_back', + 'memreg_infos_t_push_back__SWIG_0', + 'memreg_infos_t_push_back__SWIG_1', + 'memreg_infos_t_qclear', + 'memreg_infos_t_reserve', + 'memreg_infos_t_resize', + 'memreg_infos_t_resize__SWIG_0', + 'memreg_infos_t_resize__SWIG_1', + 'memreg_infos_t_size', + 'memreg_infos_t_swap', + 'memreg_infos_t_truncate', 'micro_err_format', + 'microcode_filter_t_apply', + 'microcode_filter_t_match', 'modify_user_lvars', 'module_info_t_base_get', 'module_info_t_base_set', @@ -4634,6 +4701,8 @@ 'new_argloc_t__SWIG_0', 'new_argloc_t__SWIG_1', 'new_argpart_t', + 'new_argpart_t__SWIG_0', + 'new_argpart_t__SWIG_1', 'new_array_parameters_t', 'new_array_type_data_t', 'new_asm_t', @@ -4841,6 +4910,11 @@ 'new_lvar_uservec_t', 'new_lvars_t', 'new_member_t', + 'new_memreg_info_t', + 'new_memreg_infos_t', + 'new_memreg_infos_t__SWIG_0', + 'new_memreg_infos_t__SWIG_1', + 'new_microcode_filter_t', 'new_module_info_t', 'new_netnode', 'new_netnode__SWIG_0', @@ -4888,6 +4962,9 @@ 'new_refinfo_t', 'new_reg_info_t', 'new_regarg_t', + 'new_reginfovec_t', + 'new_reginfovec_t__SWIG_0', + 'new_reginfovec_t__SWIG_1', 'new_regobj_t', 'new_regobjs_t', 'new_regval_t', @@ -4954,6 +5031,9 @@ 'new_typedef_type_data_t__SWIG_0', 'new_typedef_type_data_t__SWIG_1', 'new_uchar_array', + 'new_udc_filter_t', + 'new_udcall_map_iterator_t', + 'new_udcall_t', 'new_udt_member_t', 'new_udt_type_data_t', 'new_udtmembervec_t', @@ -5198,6 +5278,7 @@ 'parse_decls', 'parse_reg_name', 'parse_types2', + 'parse_user_call', 'partial_type_num', 'patch_byte', 'patch_long', @@ -5798,6 +5879,52 @@ 'regarg_t_reg_set', 'regarg_t_type_get', 'regarg_t_type_set', + 'reginfovec_t___eq__', + 'reginfovec_t___getitem__', + 'reginfovec_t___len__', + 'reginfovec_t___ne__', + 'reginfovec_t___setitem__', + 'reginfovec_t__del', + 'reginfovec_t_add_unique', + 'reginfovec_t_at', + 'reginfovec_t_back', + 'reginfovec_t_back__SWIG_0', + 'reginfovec_t_back__SWIG_1', + 'reginfovec_t_begin', + 'reginfovec_t_begin__SWIG_0', + 'reginfovec_t_begin__SWIG_1', + 'reginfovec_t_capacity', + 'reginfovec_t_clear', + 'reginfovec_t_empty', + 'reginfovec_t_end', + 'reginfovec_t_end__SWIG_0', + 'reginfovec_t_end__SWIG_1', + 'reginfovec_t_erase', + 'reginfovec_t_erase__SWIG_0', + 'reginfovec_t_erase__SWIG_1', + 'reginfovec_t_extract', + 'reginfovec_t_find', + 'reginfovec_t_find__SWIG_0', + 'reginfovec_t_find__SWIG_1', + 'reginfovec_t_front', + 'reginfovec_t_front__SWIG_0', + 'reginfovec_t_front__SWIG_1', + 'reginfovec_t_grow', + 'reginfovec_t_has', + 'reginfovec_t_inject', + 'reginfovec_t_insert', + 'reginfovec_t_pop_back', + 'reginfovec_t_push_back', + 'reginfovec_t_push_back__SWIG_0', + 'reginfovec_t_push_back__SWIG_1', + 'reginfovec_t_qclear', + 'reginfovec_t_reserve', + 'reginfovec_t_resize', + 'reginfovec_t_resize__SWIG_0', + 'reginfovec_t_resize__SWIG_1', + 'reginfovec_t_size', + 'reginfovec_t_swap', + 'reginfovec_t_truncate', 'register_action', 'register_addon', 'register_and_attach_to_menu', @@ -5924,6 +6051,7 @@ 'resolve_typedef2', 'restore_database_snapshot', 'restore_user_cmts', + 'restore_user_defined_calls', 'restore_user_iflags', 'restore_user_labels', 'restore_user_lvar_settings', @@ -5952,6 +6080,7 @@ 'save_tinfo', 'save_trace_file', 'save_user_cmts', + 'save_user_defined_calls', 'save_user_iflags', 'save_user_labels', 'save_user_lvar_settings', @@ -6127,6 +6256,7 @@ 'set_const_cmt', 'set_const_name', 'set_custom_data_type_ids', + 'set_custom_fixup_ex', 'set_custom_viewer_qt_aware', 'set_dbg_default_options', 'set_dbg_options', @@ -6541,6 +6671,8 @@ 'tinfo_t___ne__', 'tinfo_t___str__', 'tinfo_t__print', + 'tinfo_t_append_covered', + 'tinfo_t_calc_gaps', 'tinfo_t_calc_purged_bytes', 'tinfo_t_calc_score', 'tinfo_t_calc_udt_aligns', @@ -6717,6 +6849,7 @@ 'tinfo_t_set_const', 'tinfo_t_set_declalign', 'tinfo_t_set_modifiers', + 'tinfo_t_set_named_type', 'tinfo_t_set_numbered_type', 'tinfo_t_set_volatile', 'tinfo_t_swap', @@ -6797,6 +6930,30 @@ 'uchar_array___setitem__', 'uchar_array_cast', 'uchar_array_frompointer', + 'udc_filter_t_apply', + 'udc_filter_t_init', + 'udc_filter_t_match', + 'udcall_map_begin', + 'udcall_map_clear', + 'udcall_map_end', + 'udcall_map_erase', + 'udcall_map_find', + 'udcall_map_first', + 'udcall_map_free', + 'udcall_map_insert', + 'udcall_map_iterator_t___eq__', + 'udcall_map_iterator_t___ne__', + 'udcall_map_iterator_t_x_get', + 'udcall_map_iterator_t_x_set', + 'udcall_map_new', + 'udcall_map_next', + 'udcall_map_prev', + 'udcall_map_second', + 'udcall_map_size', + 'udcall_t_name_get', + 'udcall_t_name_set', + 'udcall_t_tif_get', + 'udcall_t_tif_set', 'udt_member_t___eq__', 'udt_member_t___lt__', 'udt_member_t___ne__', @@ -6833,6 +6990,7 @@ 'udt_type_data_t_effalign_get', 'udt_type_data_t_effalign_set', 'udt_type_data_t_is_cppobj', + 'udt_type_data_t_is_last_baseclass', 'udt_type_data_t_is_msstruct', 'udt_type_data_t_is_unaligned', 'udt_type_data_t_is_union_get', diff --git a/basetsd.h b/basetsd.h deleted file mode 100644 index 5fdca7c..0000000 --- a/basetsd.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _BASETSD_H -#define _BASETSD_H -/* Microsoft free compilers seem to lack this file and Python needs it */ -#endif diff --git a/build.py b/build.py index 2a5c9a0..a5d4648 100755 --- a/build.py +++ b/build.py @@ -40,6 +40,7 @@ parser.add_argument("--swig-inc", type=str, help="Path(s) to the SWIG includes d parser.add_argument("--with-hexrays", help="Build Hex-Rays decompiler bindings (requires the 'hexrays.hpp' header to be present in the SDK's include/ directory)", default=False, action="store_true") parser.add_argument("--debug", help="Build debug version of the plugin", default=False, action="store_true") parser.add_argument("--python-home", help="Python home, where the 'include' directory can be found", default=None) +parser.add_argument("-j", "--parallel", action="store_true", help="Build in parallel", default=False) parser.add_argument("-v", "--verbose", help="Verbose mode", default=False, action="store_true") args = parser.parse_args() @@ -58,6 +59,8 @@ def run(proc_argv, env=None): def main(): argv = ["make"] + if args.parallel: + argv.append("-j") env = os.environ.copy() env["OUT_OF_TREE_BUILD"] = "1" if args.swig_bin: @@ -79,9 +82,7 @@ def main(): if "__EA64__" in env: del env["__EA64__"] print "\n### Building EAsize=%d(bit) version of the plugin" % (64 if ea64 else 32) - run(argv + ["dist"], env=env) # 'dist' depends on build phases - print "\n### Packaging" - run(argv + ["package"], env=env) + run(argv, env=env) # ----------------------------------------------------------------------- if __name__ == "__main__": diff --git a/chkapi.py b/chkapi.py deleted file mode 100644 index 1b884f5..0000000 --- a/chkapi.py +++ /dev/null @@ -1,312 +0,0 @@ -from __future__ import with_statement - -import sys, optparse, re, pprint - -ignorable_api_contents = [ - "qwait" - ] - -class TextStream: - def __init__(self, text): - self.text = text - self.point = 0 - self.maxpoint = len(self.text) - self.line_nr = 0 - self.char_nr = 0 - self.curline = None - - def line(self): - pt = self.point - self.advance_to_newline() - return self.text[pt : self.point] - - def char(self): - c, self.point = self.text[self.point], self.point + 1 - if c == '\n': - self.line_nr += 1 - self.char_nr = 0 - return c - - def advance_to_newline(self): - p = self.point - while self.text[p] != '\n': - p += 1 - p += 1 - self.line_nr += 1 - self.char_nr = 0 - self.point = p - - def empty(self): - return self.point >= self.maxpoint - - -if __name__ == "__main__": - - p = optparse.OptionParser(description='Check the generated idaapi_include.cpp file') - p.add_option('-v', "--verbose", dest="verbose", action="store_true") - p.add_option('-f', "--file", dest="path", type="string") - p.add_option('-x', "--with-hexrays", dest="with_hexrays", action="store_true") - p.add_option('-r', "--report-contents", dest="report_contents", type="string") - opts, _ = p.parse_args(sys.argv[1:]) - - api_contents = { - "functions" : [] - } - - if not opts.path: - p.print_help() - sys.exit(1) - - functions_coherence_base = { - # - # qstrvec_t: Specialized, internal, clink'ed object. - # - "_wrap_qstrvec_t_assign" : { - "mustcall" : "qstrvec_t_assign" - }, - "_wrap_qstrvec_t_addressof" : { - "mustcall" : "qstrvec_t_addressof" - }, - "_wrap_qstrvec_t_set" : { - "mustcall" : "qstrvec_t_set" - }, - "_wrap_qstrvec_t_from_list" : { - "mustcall" : "qstrvec_t_from_list" - }, - "_wrap_qstrvec_t_size" : { - "mustcall" : "qstrvec_t_size" - }, - "_wrap_qstrvec_t_get" : { - "mustcall" : "qstrvec_t_get" - }, - "_wrap_qstrvec_t_add" : { - "mustcall" : "qstrvec_t_add" - }, - "_wrap_qstrvec_t_clear" : { - "mustcall" : "qstrvec_t_clear" - }, - "_wrap_qstrvec_t_insert" : { - "mustcall" : "qstrvec_t_insert" - }, - "_wrap_qstrvec_t_remove" : { - "mustcall" : "qstrvec_t_remove" - }, - - # - # Misc. - # - "_wrap_areacb_t_get_type" : { - "mustcall" : "get_type", - }, - "_wrap_tinfo_t_deserialize__SWIG_2" : { - "mustcall" : "tinfo_t_deserialize__SWIG_2", - }, - "_wrap_get_bpt_group" : { - "mustcall" : "PyString_FromStringAndSize", - }, - "_wrap_get_jumptable_info" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_get_array_parameters" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_read_dbg_memory" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_write_dbg_memory" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_get_grp_bpts" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_generic_linput_t_read" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_generic_linput64_t_read64" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_linput_buffer_t_read" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_get_ptr_object_size" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_tag_strlen" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_get_next_member_idx" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - "_wrap_get_prev_member_idx" : { - "string" : "resultobj = PyLong_FromLongLong(result)", - }, - # char[ANY] out typemap - "_wrap_idainfo_tag_get" : { - "nostring" : " --size;", - }, - # char[ANY] varout typemap - "Swig_var_database_idb_get" : { - "nostring" : " --size;", - }, - } - - functions_coherence_hexrays = { - "_wrap_cfuncptr_t___str__" : { - "mustcall" : ["cfunc_t___str__", "PyString_FromStringAndSize"], - }, - "_wrap_cfunc_t___str__" : { - "mustcall" : ["cfunc_t___str__", "PyString_FromStringAndSize"], - }, - "_wrap_hexrays_failure_t_desc" : { - "mustcall" : "PyString_FromStringAndSize", - }, - "_wrap_vd_failure_t_desc" : { - "mustcall" : "PyString_FromStringAndSize", - }, - "_wrap_create_field_name" : { - "mustcall" : "PyString_FromStringAndSize", - }, - "delete_qrefcnt_t_Sl_cfunc_t_Sg_" : { - "mustcall" : "hexrays_deregister_python_cfuncptr_t_instance", - }, - "_wrap__decompile" : { - "mustcall" : "hexrays_register_python_cfuncptr_t_instance", - }, - "_wrap_vdui_t_cfunc_get" : { - "mustcall" : "hexrays_register_python_cfuncptr_t_instance", - }, - # - # qvector - # - "_wrap_strvec_t___len__" : { - "mustcall" : "qvector_Sl_simpleline_t_Sg____len__", - }, - "_wrap_strvec_t___setitem__" : { - "mustcall" : "qvector_Sl_simpleline_t_Sg____setitem__", - }, - "_wrap_strvec_t___getitem__" : { - "mustcall" : "qvector_Sl_simpleline_t_Sg____getitem__", - }, - # - # vdui_t::cfunc - # - "_wrap_vdui_t_cfunc_get" : { - "string" : "SWIGTYPE_p_qrefcnt_tT_cfunc_t_t", # proper typemap must be used - }, - } - - functions_coherence = functions_coherence_base.copy() - if opts.with_hexrays: - functions_coherence.update(functions_coherence_hexrays) - - # Mark all functions as not-spotted. - for fname in functions_coherence.keys(): - chk = functions_coherence[fname] - chk["spotted"] = False - - # Read and go through lines - with open(opts.path, "r") as f: - ts = TextStream(f.read()) - - def dbg(msg): - if opts.verbose: - print("DEBUG: %s" % msg) - - def is_fundecl(line): - if len(line) <= 2: - return False - if line[0:1].isspace(): - return False - if line[len(line)-1:] != "{": - return False - if line.find("(") == -1 or line.find(")") == -1: - return False - return True - - def collect_funbody_lines(ts): - pt = ts.point - braces_cnt = 1 - while True: - c = ts.char() - if c == "{": - braces_cnt = braces_cnt + 1 - elif c == "}": - braces_cnt = braces_cnt - 1 - if braces_cnt == 0: - break; - # TODO: Skip strings! - return ts.text[pt : ts.point].split("\n") - - api_fname_regex = re.compile(".*PyObject \\*_wrap_([^\\(]*)\\(.*\\).*") - - # Process lines - STATE_UNKNOWN = 0 - STATE_IN_FUN = 1 - state = STATE_UNKNOWN - while not ts.empty(): - line = ts.line().rstrip() - # dbg("Line: '%s'" % line) - if is_fundecl(line): - # dbg("Entering function (from line %d: '%s')" % (ts.line_nr, line)) - state = STATE_IN_FUN - funstart = line - match = api_fname_regex.match(funstart) - if match: - fname = match.group(1) - if fname not in ignorable_api_contents: - api_contents["functions"].append(fname) - funlines = collect_funbody_lines(ts) - # Do we care about this function? - check_for = None - for fname in functions_coherence.keys(): - if funstart.find(fname + "(") > -1: - check_for = fname - break - if check_for: - dbg("Checking function at line %d: '%s'" % (ts.line_nr, check_for)) - chk = functions_coherence[check_for] - chk["spotted"] = True - def look_for_stuff(stuff, isFuncall, lookForPresence=True): - if isinstance(stuff, str): - stuff = [stuff] - for bit in stuff: - found = False - bit_pat = ("%s(" % bit) if isFuncall else bit - dbg("Thing to look for: '%s'" % bit_pat) - for funline in funlines: - # dbg("Testing line: '%s'" % funline) - if funline.find(bit_pat) > -1: - found = True - break - if lookForPresence: - if not found: - raise Exception("Couldn't find '%s', from function '%s' (lines: %s)" % - (bit_pat, check_for, "\n".join([""] + funlines))) - else: - if found: - raise Exception("Did find unwanted '%s', from function '%s' (lines: %s)" % - (bit_pat, check_for, "\n".join([""] + funlines))) - - if "mustcall" in chk: - look_for_stuff(chk["mustcall"], True) - if "string" in chk: - look_for_stuff(chk["string"], False) - if "nostring" in chk: - look_for_stuff(chk["nostring"], False, lookForPresence=False) - - # Ensure all functions were spotted. - for fname in functions_coherence.keys(): - chk = functions_coherence[fname] - if not chk["spotted"]: - raise Exception("Couldn't spot function '%s'" % fname) - - # Report contents - if opts.report_contents: - # NB: we use "wb" here so that the endlines - # are written as-is, in Unix format - # and so 'diff' does not report bogus changes - # against the file from repository - with open(opts.report_contents, "wb") as f: - api_contents["functions"].sort() - f.write(pprint.pformat(api_contents)) - diff --git a/examples/chooser.py b/examples/chooser.py old mode 100644 new mode 100755 diff --git a/examples/colours.py b/examples/colours.py old mode 100644 new mode 100755 diff --git a/examples/debughook.py b/examples/debughook.py old mode 100644 new mode 100755 diff --git a/examples/ex1_idaapi.py b/examples/ex1_idaapi.py old mode 100644 new mode 100755 diff --git a/examples/ex1_idautils.py b/examples/ex1_idautils.py old mode 100644 new mode 100755 diff --git a/examples/ex_actions.py b/examples/ex_actions.py old mode 100644 new mode 100755 diff --git a/examples/ex_add_menu_item.py b/examples/ex_add_menu_item.py deleted file mode 100644 index c01e777..0000000 --- a/examples/ex_add_menu_item.py +++ /dev/null @@ -1,18 +0,0 @@ -import idaapi - -def cb(*args): - print("Callback called!") - return 1 - -try: - ex_addmenu_item_ctx - idaapi.del_menu_item(ex_addmenu_item_ctx) - print("Menu removed") - del ex_addmenu_item_ctx -except: - ex_addmenu_item_ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world")) - if ex_addmenu_item_ctx is None: - print("Failed to add menu!") - del ex_addmenu_item_ctx - else: - print("Menu added successfully. Run the script again to delete the menu") \ No newline at end of file diff --git a/examples/ex_askusingform.py b/examples/ex_askusingform.py old mode 100644 new mode 100755 index 977e364..aef440d --- a/examples/ex_askusingform.py +++ b/examples/ex_askusingform.py @@ -50,6 +50,7 @@ Form Test {FormChangeCb} This is a string: +{cStr1}+ This is an address: +{cAddr1}+ +This is some HTML: +{cHtml1}+ Escape\{control} This is a string: '{cStr2}' @@ -85,6 +86,7 @@ The end! """, { 'cStr1': Form.StringLabel("Hello"), 'cStr2': Form.StringLabel("StringTest"), + 'cHtml1': Form.StringLabel("Is this red?", tp=Form.FT_HTML_LABEL), 'cAddr1': Form.NumericLabel(0x401000, Form.FT_ADDR), 'cVal1' : Form.NumericLabel(99, Form.FT_HEX), 'iStr1': Form.StringInput(), diff --git a/examples/ex_choose2.py b/examples/ex_choose2.py old mode 100644 new mode 100755 diff --git a/examples/ex_cli.py b/examples/ex_cli.py old mode 100644 new mode 100755 diff --git a/examples/ex_custdata.py b/examples/ex_custdata.py old mode 100644 new mode 100755 diff --git a/examples/ex_custview.py b/examples/ex_custview.py old mode 100644 new mode 100755 diff --git a/examples/ex_dbg.py b/examples/ex_dbg.py old mode 100644 new mode 100755 diff --git a/examples/ex_debug_names.py b/examples/ex_debug_names.py old mode 100644 new mode 100755 diff --git a/examples/ex_func_chooser.py b/examples/ex_func_chooser.py old mode 100644 new mode 100755 diff --git a/examples/ex_gdl_qflow_chart.py b/examples/ex_gdl_qflow_chart.py old mode 100644 new mode 100755 diff --git a/examples/ex_graph.py b/examples/ex_graph.py old mode 100644 new mode 100755 diff --git a/examples/ex_imports.py b/examples/ex_imports.py old mode 100644 new mode 100755 diff --git a/examples/ex_prefix_plugin.py b/examples/ex_prefix_plugin.py old mode 100644 new mode 100755 diff --git a/examples/ex_pyqt.py b/examples/ex_pyqt.py old mode 100644 new mode 100755 index f137122..6a0914d --- a/examples/ex_pyqt.py +++ b/examples/ex_pyqt.py @@ -1,5 +1,6 @@ + from idaapi import PluginForm -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets import sip class MyPluginFormClass(PluginForm): @@ -15,12 +16,12 @@ class MyPluginFormClass(PluginForm): def PopulateForm(self): # Create layout - layout = QtGui.QVBoxLayout() + layout = QtWidgets.QVBoxLayout() layout.addWidget( - QtGui.QLabel("Hello from PyQt")) + QtWidgets.QLabel("Hello from PyQt")) layout.addWidget( - QtGui.QLabel("Hello from IDAPython")) + QtWidgets.QLabel("Hello from IDAPython")) self.parent.setLayout(layout) diff --git a/examples/ex_pyside.py b/examples/ex_pyside.py deleted file mode 100644 index dba9911..0000000 --- a/examples/ex_pyside.py +++ /dev/null @@ -1,34 +0,0 @@ -from idaapi import PluginForm -from PySide import QtGui, QtCore - -class MyPluginFormClass(PluginForm): - def OnCreate(self, form): - """ - Called when the plugin form is created - """ - - # Get parent widget - self.parent = self.FormToPySideWidget(form) - self.PopulateForm() - - - def PopulateForm(self): - # Create layout - layout = QtGui.QVBoxLayout() - - layout.addWidget( - QtGui.QLabel("Hello from PySide")) - layout.addWidget( - QtGui.QLabel("Hello from IDAPython")) - - self.parent.setLayout(layout) - - - def OnClose(self, form): - """ - Called when the plugin form is closed - """ - pass - -plg = MyPluginFormClass() -plg.Show("PySide hello world") diff --git a/examples/ex_strings.py b/examples/ex_strings.py old mode 100644 new mode 100755 diff --git a/examples/ex_uihook.py b/examples/ex_uihook.py old mode 100644 new mode 100755 diff --git a/examples/hotkey.py b/examples/hotkey.py old mode 100644 new mode 100755 diff --git a/examples/idapythonrc.py b/examples/idapythonrc.py old mode 100644 new mode 100755 diff --git a/examples/structure.py b/examples/structure.py old mode 100644 new mode 100755 diff --git a/examples/vds6.py b/examples/vds6.py new file mode 100644 index 0000000..eac7657 --- /dev/null +++ b/examples/vds6.py @@ -0,0 +1,93 @@ + +""" +This is a crude (and not very pythonic) reimplementation of the example +hexrays plugin 'hexrays_sample6.cpp', shipped with the Hex-Rays decompiler. + +It modifies the decompilation output: removes some space characters. +""" + +import idautils +import idc +import ida_hexrays +import ida_lines + +def dbg(msg): + #print msg + pass + +def is_cident_char(c): + return c.isalnum() or c == '_' + +def my_tag_skipcodes(l, storage): + n = ida_lines.tag_skipcodes(l) + dbg("Skipping %d chars ('%s')" % (n, l[0:n])) + storage.append(l[0:n]) + return l[n:] + +def remove_spaces(sl): + dbg("*" * 80) + l = sl.line + out = [] + + def push(c): + dbg("Appending '%s'" % c) + out.append(c) + + # skip initial spaces, do not compress them + while True: + l = my_tag_skipcodes(l, out) + if not l: + break + c = l[0] + if not c.isspace(): + break + push(c) + l = l[1:] + + # remove all spaces except in string and char constants + delim = None # if not None, then we are skipping until 'delim' + last = None # last seen character + while True: + # go until comments + dbg("-" * 60) + nchars = ida_lines.tag_advance(l, 1) + push(l[0:nchars]) + l = l[nchars:] + l = my_tag_skipcodes(l, out) + if not l: + break + if l.startswith("//"): + push(l) + break + c = l[0] + dbg("c: '%s', last: '%s', l: '%s'" % (c, last, l)) + if delim: + # we're inside a literal. + if c == delim: + delim = None # literal ended + elif c == '"' or c == "'": + delim = c # string/char literal started + elif c.isspace(): + end = l.lstrip() + nptr = my_tag_skipcodes(end, out) + dbg("end: '%s', nptr: '%s'" % (end, nptr)) + # do not concatenate idents + if not is_cident_char(last) or not is_cident_char(nptr[0]): + l = end + c = l[0] if l else '' + dbg("new l: '%s'" % l) + last = l[0] if l else '' + + sl.line = "".join(out) + +def cb(event, *args): + if event == ida_hexrays.hxe_func_printed: + cf = args[0] + for sl in cf.get_pseudocode(): + remove_spaces(sl); + return 0 + +if ida_hexrays.init_hexrays_plugin(): + ida_hexrays.install_hexrays_callback(cb) +else: + print 'remove spaces: hexrays is not available.' diff --git a/idaapi.cpp b/idaapi.cpp deleted file mode 100644 index 6ca3913..0000000 --- a/idaapi.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// This file just includes the correct idaapi_include.cpp file -// We need it because we can not compile a file from a subdirectory - -#include diff --git a/idapython.vcxproj b/idapython.vcxproj index bfb6177..17090a7 100644 --- a/idapython.vcxproj +++ b/idapython.vcxproj @@ -1,5 +1,5 @@  - + Debug64 @@ -27,25 +27,25 @@ DynamicLibrary false MultiByte - v120 + v140 DynamicLibrary false MultiByte - v120 + v140 DynamicLibrary false MultiByte - v120 + v140 DynamicLibrary false MultiByte - v120 + v140 diff --git a/makefile b/makefile index 8443621..4552454 100644 --- a/makefile +++ b/makefile @@ -27,25 +27,17 @@ all: else PROC=python -STRIPOBJS=idaapi.cpp API_CONTENTS=api_contents.txt +PYDOC_INJECTIONS=pydoc_injections.txt IDA_INCLUDE=../../include -STAGING=./staging -ST_SWIG=$(STAGING)/swig -ST_SDK=$(STAGING)/idasdk -ST_PYW=$(STAGING)/pywraps -ST_PARSED_HEADERS=$(STAGING)/parsed_notifications/xml - -# ATM, 'dist' in in staging/, but that will change since -# staging directories will be $(SYSDIR)-dependent -DIST=$(STAGING)/dist +DIST=$(F)dist ifdef __NT__ SYSNAME=win + MSRUNTIME=/MD else -.NOTPARALLEL: endif ifdef __LINUX__ SYSNAME=linux @@ -62,11 +54,103 @@ ifdef __MAC__ DEFS=-D__MAC__ endif -O1=idaapi -ADDITIONAL_GOALS=pyfiles config $(TEST_IDC) +# O1=idaapi + +# __USE_RTTI__=1 + + +DONT_ERASE_LIB=1 -__USE_RTTI__=1 include ../plugin.mak +PLUGIN_SCRIPT= +ifdef __LINUX__ +OUTDLLOPTS=-Wl,-soname,$(notdir $(BINARY)) +else + ifdef __MAC__ + OUTDLLOPTS=-Wl,-install_name,@executable_path/plugins/$(notdir $(BINARY)) + endif +endif + + +ST_SWIG=$(F)swig +ifeq ($(OUT_OF_TREE_BUILD),) + ST_SDK=$(F)idasdk +else + ST_SDK=$(IDA_INCLUDE) +endif +ST_PYW=$(F)pywraps +ST_WRAP=$(F)wrappers +ST_PARSED_HEADERS_NOXML=$(F)parsed_notifications +ST_PARSED_HEADERS=$(ST_PARSED_HEADERS_NOXML)/xml +ST_API_CONTENTS=$(F)api_contents.txt.new +ST_PYDOC_INJECTIONS=$(F)pydoc_injections.txt + +# output directory for python scripts +DEPLOY_PYDIR=$(R)python +DEPLOY_INIT_PY=$(DEPLOY_PYDIR)/init.py +DEPLOY_IDC_PY=$(DEPLOY_PYDIR)/idc.py +DEPLOY_IDAUTILS_PY=$(DEPLOY_PYDIR)/idautils.py +ifeq ($(OUT_OF_TREE_BUILD),) + TEST_IDC=test_idc + DBLZIP_SCRIPT:=$(abspath ../../ida/build/dblzip.py) + PKGBIN_SCRIPT:=$(abspath ../../ida/build/pkgbin.py) +endif + +# +SDK_SOURCES=$(wildcard $(IDA_INCLUDE)/*.h) $(wildcard $(IDA_INCLUDE)/*.hpp) +ifeq ($(OUT_OF_TREE_BUILD),) + ST_SDK_TARGETS=$(SDK_SOURCES:$(IDA_INCLUDE)/%=$(ST_SDK)/%) +else + ST_SDK_TARGETS=$(SDK_SOURCES) +endif + +PYTHON_DYNLOAD=$(BIN_PATH)../python/lib/python2.7/lib-dynload +DEPLOY_LIBDIR=$(PYTHON_DYNLOAD)/ida_$(ADRSIZE) + +$(DEPLOY_LIBDIR): + -@if [ ! -d "$(DEPLOY_LIBDIR)" ] ; then mkdir -p 2>/dev/null $(DEPLOY_LIBDIR) ; fi + +$(DEPLOY_PYDIR): + -@if [ ! -d "$(DEPLOY_PYDIR)" ] ; then mkdir -p 2>/dev/null $(DEPLOY_PYDIR) ; fi + +ifdef __NT__ +MODULE_SFX=.pyd +else +MODULE_SFX=.so +endif + +# We are building 'MODULES_NAMES' from subvars because it appears some versions +# of make do not deal too well with '\'s, and introduce spaces, which later is +# problematic when substituting ' ' for ',' & passing modules list to scripts +MNAMES_0=allins area auto bytes dbg diskio entry enum expr fixup +MNAMES_1=fpro frame funcs gdl graph hexrays ida idaapi idd idp ints +MNAMES_2=kernwin lines loader moves nalt name netnode offset pro queue +MNAMES_3=registry search segment srarea strlist struct typeinf ua xref +MODULES_NAMES=$(MNAMES_0) $(MNAMES_1) $(MNAMES_2) $(MNAMES_3) + +MODULES=$(MODULES_NAMES:%=$(F)_ida_%$(MODULE_SFX)) +DEPLOYED_MODULES=$(MODULES_NAMES:%=$(DEPLOY_LIBDIR)/_ida_%$(MODULE_SFX)) +MODULES_OBJECTS=$(MODULES_NAMES:%=$(F)%$(O)) + +ALL_ST_SWIG=$(foreach mod,$(MODULES_NAMES),$(ST_SWIG)/$(mod).i) +ALL_ST_WRAP_CPP=$(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/$(mod).cpp) +ALL_ST_WRAP_PY=$(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/ida_$(mod).py) + +PYTHON_MODULES=$(MODULES_NAMES:%=$(DEPLOY_PYDIR)/ida_%.py) + +ifdef __NT__ +MODULE_LINKIDA= +CREATE_IMPLIB=$(RS)lib32.bat +IDAPYTHON_IMPLIB_DEF=$(F)idapython_implib.def +IDAPYTHON_IMPLIB_DEF_IN=tools/idapython_implib.def.in +IDAPYTHON_IMPLIB_PATH=$(F)python.lib +BINARY_LINKOPTS=/def:$(IDAPYTHON_IMPLIB_DEF) /IMPLIB:$(IDAPYTHON_IMPLIB_PATH) +RESFILES=$(IDAPYTHON_IMPLIB_DEF) +else +MODULE_LINKIDA=-L$(R) $(LINKIDA) $(BINARY) +endif + +all: objdir pyfiles config $(DEPLOYED_MODULES) $(PYTHON_MODULES) $(ST_API_CONTENTS) $(IDAPYTHON_IMPLIB) $(ST_PYDOC_INJECTIONS) #$(TEST_IDC) # used python version PYTHON_VERSION_MAJOR?=2 @@ -75,8 +159,8 @@ PYTHON_VERSION_MINOR?=7 # IDAPython version IDAPYTHON_VERSION_MAJOR=6 IDAPYTHON_VERSION_MINOR=9 -IDAPYTHON_VERSION_PATCH=0 -PACKAGE_NAME=idapython-$(IDAPYTHON_VERSION_MAJOR).$(IDAPYTHON_VERSION_MINOR).$(IDAPYTHON_VERSION_PATCH)-python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)-$(SYSNAME).zip +IDAPYTHON_VERSION_PATCH=5 +PACKAGE_NAME=idapython-$(IDAPYTHON_VERSION_MAJOR).$(IDAPYTHON_VERSION_MINOR).$(IDAPYTHON_VERSION_PATCH)-python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)-$(SYSNAME) # HIJACK the $(I) variable to point to our staging SDK @@ -87,19 +171,6 @@ ifdef __CODE_CHECKER__ OBJS:=$(filter-out $(OBJ1),$(OBJS)) endif -# output directory for python scripts - -ifeq ($(OUT_OF_TREE_BUILD),) - SCRIPTDIR=$(R)python - DEPLOY_INIT_PY=$(SCRIPTDIR)/init.py - DEPLOY_IDC_PY=$(SCRIPTDIR)/idc.py - DEPLOY_IDAUTILS_PY=$(SCRIPTDIR)/idautils.py - DEPLOY_PYTHON_CFG=$(C)python.cfg - TEST_IDC=test_idc -else - SCRIPTDIR=python -endif - ifdef __NT__ # os and compiler specific flags ifneq ($(UCRT_INCLUDE),) I_UCRT_INCLUDE=/I$(UCRT_INCLUDE) @@ -114,16 +185,18 @@ endif endif _SWIGFLAGS=-D__NT__ -DWIN32 -D_USRDLL -I$(PYTHON_DIR)/include SWIGINCLUDES?= # nothing - OSFLAGS=$(_SWIGFLAGS) -UNO_OBSOLETE_FUNCS + # FIXME: Cannot enable the .cfg file ATM, because there's just too many errors if I do. + PLATFORM_CFLAGS=$(_SWIGFLAGS) -UNO_OBSOLETE_FUNCS else # unix/mac ifdef __LINUX__ # use the precompiled 2.7 ifeq ($(OUT_OF_TREE_BUILD),) - PYDIR=$(shell pwd)/precompiled + # assign right away, so it won't be eval'd 10301829 times + PYDIR:=$(shell pwd)/precompiled PYLIBDIR=$(PYDIR) # copy these files to IDA's directory - PYLIBFILES=$(shell find precompiled/lib -type f) - PRECOMPILED_COPY=$(R)$(PYTHONLIBNAME) $(patsubst precompiled/%,$(SCRIPTDIR)/%,$(PYLIBFILES)) + PYLIBFILES:=$(shell find precompiled/lib -type f) + PRECOMPILED_COPY=$(R)$(PYTHONLIBNAME) $(patsubst precompiled/%,$(DEPLOY_PYDIR)/%,$(PYLIBFILES)) else PYDIR=$(IDAPYTHON_PYTHONHOME) PYLIBDIR=$(PYDIR)/lib @@ -138,40 +211,50 @@ else # unix/mac MACDEFINES=-DMACSDKVER=$(MACSDKVER) endif IDAPYTHON_CFLAGS=-w -g - OSFLAGS=$(SYS) -g $(PYTHON32_INCLUDE) $(ARCH_CFLAGS) $(PIC) -UNO_OBSOLETE_FUNCS # gcc flags + PLATFORM_CFLAGS=$(SYS) -g $(PYTHON32_INCLUDE) $(ARCH_CFLAGS) $(PIC) -UNO_OBSOLETE_FUNCS # gcc flags _SWIGFLAGS=$(DEFS) SWIGINCLUDES?=-I$(SWIGDIR)share/swig/$(SWIG_VERSION)/python -I$(SWIGDIR)share/swig/$(SWIG_VERSION) endif -SWIGFLAGS=$(_SWIGFLAGS) $(SWIGINCLUDES) +# Apparently that's not needed, but I don't understand why ATM, since doc says: +# ...Then, only modules compiled with SWIG_TYPE_TABLE set to myprojectname +# will share type information. So if your project has three modules, all three +# should be compiled with -DSWIG_TYPE_TABLE=myprojectname, and then these +# three modules will share type information. But any other project's +# types will not interfere or clash with the types in your module. +DEF_TYPE_TABLE=-DSWIG_TYPE_TABLE=idaapi +SWIGFLAGS=$(_SWIGFLAGS) $(SWIGINCLUDES) $(DEF_TYPE_TABLE) ADDITIONAL_LIBS=$(PYTHONLIB) +PUBTREE_DIR=$(F)/public_tree -.PHONY: pyfiles docs $(TEST_IDC) staging_dirs clean check_python dist dist_dirs dist_cfg package +.PHONY: pyfiles docs $(TEST_IDC) staging_dirs clean check_python package public_tree config: $(C)python.cfg clean: - rm -rf $(STAGING)/ obj/ + rm -rf obj/ -pyfiles: $(SCRIPTDIR)/idautils.py \ - $(SCRIPTDIR)/idc.py \ - $(SCRIPTDIR)/init.py \ - $(SCRIPTDIR)/idaapi.py +pyfiles: $(DEPLOY_PYDIR)/idautils.py \ + $(DEPLOY_PYDIR)/idc.py \ + $(DEPLOY_PYDIR)/init.py \ + $(DEPLOY_PYDIR)/idaapi.py GENHOOKS=tools/genhooks/ +_SPACE := $(null) # +_COMMA := , -$(DEPLOY_INIT_PY): python/init.py +$(DEPLOY_INIT_PY): python/init.py | $(DEPLOY_PYDIR) $(CP) $? $@ -$(DEPLOY_IDC_PY): python/idc.py +$(DEPLOY_IDC_PY): python/idc.py | $(DEPLOY_PYDIR) $(CP) $? $@ -$(DEPLOY_IDAUTILS_PY): python/idautils.py +$(DEPLOY_IDAUTILS_PY): python/idautils.py | $(DEPLOY_PYDIR) $(CP) $? $@ -$(SCRIPTDIR)/idaapi.py: $(F)idaapi.py - $(PYTHON) inject_pydoc.py swig/ $? $@ +$(DEPLOY_PYDIR)/idaapi.py: python/idaapi.py tools/genidaapi.py | $(DEPLOY_PYDIR) + $(PYTHON) tools/genidaapi.py -i $< -o $@ -m $(subst $(_SPACE),$(_COMMA),$(MODULES_NAMES)) -$(SCRIPTDIR)/lib/%: precompiled/lib/% +$(DEPLOY_PYDIR)/lib/%: precompiled/lib/% mkdir -p $(@D) cp $< $@ @chmod +w $@ @@ -184,41 +267,37 @@ $(R)$(PYTHONLIBNAME): $(PYDIR)/$(PYTHONLIBNAME) # ------------------------------------------------------------------------- # Hooks generation -$(ST_PARSED_HEADERS)/structprocessor__t.xml: $(I)idp.hpp $(GENHOOKS)doxy_gen_notifs.cfg | $(ST_SDK_TARGETS) - @$(DOXYGEN_BIN) $(GENHOOKS)doxy_gen_notifs.cfg - -$(ST_PARSED_HEADERS)/dbg_8hpp.xml: $(I)dbg.hpp $(GENHOOKS)doxy_gen_notifs.cfg | $(ST_SDK_TARGETS) - @$(DOXYGEN_BIN) $(GENHOOKS)doxy_gen_notifs.cfg - -$(ST_PARSED_HEADERS)/kernwin_8hpp.xml: $(I)kernwin.hpp $(GENHOOKS)doxy_gen_notifs.cfg | $(ST_SDK_TARGETS) - @$(DOXYGEN_BIN) $(GENHOOKS)doxy_gen_notifs.cfg - -$(ST_PARSED_HEADERS)/namespaceidb__event.xml: $(I)kernwin.hpp $(GENHOOKS)doxy_gen_notifs.cfg | $(ST_SDK_TARGETS) - @$(DOXYGEN_BIN) $(GENHOOKS)doxy_gen_notifs.cfg +# http://stackoverflow.com/questions/11032280/specify-doxygen-parameters-through-command-line +GENERATED_HEADERS=$(ST_PARSED_HEADERS)/headers_generated.marker +$(GENERATED_HEADERS): $(I)idp.hpp $(I)dbg.hpp $(I)kernwin.hpp $(GENHOOKS)doxy_gen_notifs.cfg $(ST_SDK_TARGETS) +ifeq ($(OUT_OF_TREE_BUILD),) + @( cat $(GENHOOKS)doxy_gen_notifs.cfg; echo "OUTPUT_DIRECTORY=$(ST_PARSED_HEADERS_NOXML)" ) | $(DOXYGEN_BIN) - +else + (cd $(F) && unzip ../../out_of_tree/parsed_notifications.zip) +endif + @touch $@ # staging_dirs: -@if [ ! -d "$(ST_SDK)" ] ; then mkdir -p 2>/dev/null $(ST_SDK) ; fi -@if [ ! -d "$(ST_SWIG)" ] ; then mkdir -p 2>/dev/null $(ST_SWIG) ; fi -@if [ ! -d "$(ST_PYW)" ] ; then mkdir -p 2>/dev/null $(ST_PYW) ; fi + -@if [ ! -d "$(ST_WRAP)" ] ; then mkdir -p 2>/dev/null $(ST_WRAP) ; fi -@if [ ! -d "$(ST_PARSED_HEADERS)" ] ; then mkdir -p 2>/dev/null $(ST_PARSED_HEADERS) ; fi # ------------------------------------------------------------------------- -# Rules for preparing 'staging/idasdk/*.h[pp]' +# obj/.../idasdk/*.h[pp] # -SDK_SOURCES=$(wildcard $(IDA_INCLUDE)/*.h) $(wildcard $(IDA_INCLUDE)/*.hpp) -ST_SDK_TARGETS=$(SDK_SOURCES:$(IDA_INCLUDE)/%=$(ST_SDK)/%) -$(ST_SDK)/%.h: $(IDA_INCLUDE)/%.h | staging_dirs - @$(CP) $^ $@ && chmod +rw $@ -$(ST_SDK)/%.hpp: $(IDA_INCLUDE)/%.hpp | staging_dirs - @$(CP) $^ $@ && chmod +rw $@ - +ifeq ($(OUT_OF_TREE_BUILD),) +$(ST_SDK)/%.h: $(IDA_INCLUDE)/%.h | staging_dirs $(PRECOMPILED_COPY) + $(PYTHON) ../../bin/update_sdk.py -filter-file -input $^ -output $@ +$(ST_SDK)/%.hpp: $(IDA_INCLUDE)/%.hpp | staging_dirs $(PRECOMPILED_COPY) + $(PYTHON) ../../bin/update_sdk.py -filter-file -input $^ -output $@ +endif # ------------------------------------------------------------------------- -# Rules for preparing 'staging/pywraps/*' +# obj/.../pywraps/* # -PYW_SOURCES=$(wildcard pywraps/*.hpp) $(wildcard pywraps/*.py) -ST_PYW_TARGETS=$(PYW_SOURCES:pywraps/%=$(ST_PYW)/%) $(ST_PYW)/%.hpp: pywraps/%.hpp | staging_dirs @$(CP) $^ $@ && chmod +rw $@ $(ST_PYW)/%.py: pywraps/%.py | staging_dirs @@ -226,121 +305,190 @@ $(ST_PYW)/%.py: pywraps/%.py | staging_dirs ifneq ($(OUT_OF_TREE_BUILD),) - # envvar HAS_HEXRAYS must have been set by build.py if needed + # envvar HAS_HEXRAYS must have been set by build.py if needed else + HAS_HEXRAYS=1 # force hexrays bindings +endif - # force hexrays bindings - HAS_HEXRAYS=1 - # These require special care, as they will have to be injected w/ hooks -- this - # only happens if we are sitting in the hexrays source tree; when published to - # the outside world, the pywraps must already contain the injected code. - $(ST_PYW)/py_idp.hpp: pywraps/py_idp.hpp \ +# These require special care, as they will have to be injected w/ hooks -- this +# only happens if we are sitting in the hexrays source tree; when published to +# the outside world, the pywraps must already contain the injected code. +$(ST_PYW)/py_idp.hpp: pywraps/py_idp.hpp \ $(I)idp.hpp \ $(GENHOOKS)genhooks.py \ $(GENHOOKS)recipe_idphooks.py \ - $(ST_PARSED_HEADERS)/structprocessor__t.xml | staging_dirs $(SDK_SOURCES) + $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -x $(ST_PARSED_HEADERS)/structprocessor__t.xml -e idp_notify \ -r int -n 0 -m hookgenIDP -q "processor_t::" \ -R $(GENHOOKS)recipe_idphooks.py - $(ST_PYW)/py_idbhooks.hpp: pywraps/py_idbhooks.hpp \ +$(ST_PYW)/py_idp_idbhooks.hpp: pywraps/py_idp_idbhooks.hpp \ $(I)idp.hpp \ $(GENHOOKS)genhooks.py \ $(GENHOOKS)recipe_idbhooks.py \ - $(ST_PARSED_HEADERS)/namespaceidb__event.xml | staging_dirs $(SDK_SOURCES) + $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -x $(ST_PARSED_HEADERS)/namespaceidb__event.xml -e event_code_t \ -r int -n 0 -m hookgenIDB -q "idb_event::" \ -R $(GENHOOKS)recipe_idbhooks.py - $(ST_PYW)/py_dbg.hpp: pywraps/py_dbg.hpp \ +$(ST_PYW)/py_dbg.hpp: pywraps/py_dbg.hpp \ $(I)dbg.hpp \ $(GENHOOKS)genhooks.py \ $(GENHOOKS)recipe_dbghooks.py \ - $(ST_PARSED_HEADERS)/dbg_8hpp.xml | staging_dirs $(SDK_SOURCES) + $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -x $(ST_PARSED_HEADERS)/dbg_8hpp.xml -e dbg_notification_t \ -r void -n 0 -m hookgenDBG \ -R $(GENHOOKS)recipe_dbghooks.py - $(ST_PYW)/py_kernwin.hpp: pywraps/py_kernwin.hpp \ +$(ST_PYW)/py_kernwin.hpp: pywraps/py_kernwin.hpp \ $(I)kernwin.hpp \ $(GENHOOKS)genhooks.py \ $(GENHOOKS)recipe_uihooks.py \ - $(ST_PARSED_HEADERS)/kernwin_8hpp.xml | staging_dirs $(SDK_SOURCES) + $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -x $(ST_PARSED_HEADERS)/kernwin_8hpp.xml -e ui_notification_t \ -r void -n 0 -m hookgenUI \ -R $(GENHOOKS)recipe_uihooks.py \ -d "ui_dbg_,ui_obsolete" -D "ui:" -s "ui_" -endif # OUT_OF_TREE_BUILD ifneq ($(HAS_HEXRAYS),) WITH_HEXRAYS=-DWITH_HEXRAYS WITH_HEXRAYS_CHKAPI=--with-hexrays endif +CFLAGS= $(CCOPT) $(PLATFORM_CFLAGS) $(MSRUNTIME) -D__EXPR_SRC -I. -I$(ST_SWIG) -I$(ST_SDK) -I$(F) \ + -DVER_MAJOR="1" -DVER_MINOR="7" -DVER_PATCH="0" -D__IDP__ \ + -DUSE_STANDARD_FILE_FUNCTIONS $(IDAPYTHON_CFLAGS) \ + $(SWITCH64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) $(DEF_TYPE_TABLE) -# ------------------------------------------------------------------------- -# Rules for preparing 'staging/swig/*.i' -# -# Note: At the time we define those rules, we cannot go and look in -# staging/pywraps/ just yet, as those will/might not have been deployed at -# that point (i.e., when building from scratch.) -# Thus, we must find the dependencies in pywraps/, and then re-route them to -# staging/pywraps/ -SWIG_SOURCES=$(wildcard swig/*.i) -ST_SWIG_TARGETS=$(SWIG_SOURCES:swig/%.i=$(ST_SWIG)/%.i) -find-pywraps-deps = $(wildcard pywraps/py_$(subst .i,,$(notdir $1)).*) -define make-deploy-swig-file-rule -$1: $(subst staging/,,$1) $(addprefix staging/,$(call find-pywraps-deps,$1)) | $(ST_PYW_TARGETS) - @$(PYTHON) tools/deploy.py --pywraps $(ST_PYW) --template $$(subst staging/,,$$@) --output $$@ --module $$(subst .i,,$$(notdir $$@)) +ST_SWIG_HEADER=$(ST_SWIG)/header.i +$(ST_SWIG)/header.i: tools/deploy/header.i.in tools/genswigheader.py $(ST_SDK_TARGETS) | staging_dirs + $(PYTHON) tools/genswigheader.py -i $< -o $@ -m $(subst $(_SPACE),$(_COMMA),$(MODULES_NAMES)) -s $(ST_SDK) + + +ifdef __NT__ +$(IDAPYTHON_IMPLIB_DEF): $(IDAPYTHON_IMPLIB_DEF_IN) + sed s/%LIBNAME%/$(notdir $(BINARY))/ < $? > $@ +endif + +find-pywraps-deps = $(wildcard pywraps/py_$(subst .i,,$(notdir $1))*.*) + +# Some .i files depend on some other .i files in order to be parseable by SWiG +# (e.g., srarea.i imports area.i). Declare the list of such dependencies here +# so they will be picked by the auto-generated rules. +SWIG_IFACE_bytes=area +SWIG_IFACE_dbg=idd +SWIG_IFACE_frame=area +SWIG_IFACE_funcs=area +SWIG_IFACE_gdl=area +SWIG_IFACE_hexrays=typeinf +SWIG_IFACE_segment=area +SWIG_IFACE_srarea=area +SWIG_IFACE_typeinf=idp + +define make-module-rules + + # Note: apparently make cannot work well when a given recipe generates multiple files + # http://stackoverflow.com/questions/19822435/multiple-targets-from-one-recipe-and-parallel-execution + # Consequently, rules such as this: + # + # $(ST_WRAP)/ida_$1.py: $(ST_WRAP)/$1.cpp + # + # i.e., that do nothing but rely on the generation of another file, + # will not work in // execution. Thus, we will rely exclusively on + # the presence of the generated .cpp file, and not other generated + # files. + + # ../../bin/x86_linux_gcc/python/ida_$1.py (note: dep. on .cpp. See note above.) + $(DEPLOY_PYDIR)/ida_$1.py: $(ST_WRAP)/$1.cpp | $(DEPLOY_PYDIR) tools/inject_pydoc.py + $(PYTHON) tools/inject_pydoc.py \ + -i $(ST_WRAP)/ida_$1.py \ + -w $(ST_SWIG)/$1.i \ + -o $$@ \ + -v > $(ST_WRAP)/ida_$1.pydoc_injection 2>&1 + + # obj/x86_linux_gcc/swig/X.i + $(ST_SWIG)/$1.i: $(addprefix $(F),$(call find-pywraps-deps,$1)) swig/$1.i $(ST_SWIG_HEADER) $(SWIG_IFACE_$1:%=$(ST_SWIG)/%.i) $(ST_SWIG_HEADER) tools/deploy.py + $(PYTHON) tools/deploy.py --pywraps $(ST_PYW) --template $$(subst $(F),,$$@) --output $$@ --module $$(subst .i,,$$(notdir $$@)) --interface-dependencies=$(subst $(_SPACE),$(_COMMA),$(SWIG_IFACE_$1)) + + # obj/x86_linux_gcc/wrappers/X.cpp + $(ST_WRAP)/$1.cpp: $(ST_SWIG)/$1.i + $(SWIG) -modern $(WITH_HEXRAYS) -python -threads -c++ -shadow \ + $(MACDEFINES) -D__GNUC__ $(SWIGFLAGS) $(SWITCH64) -I$(ST_SWIG) \ + -outdir $(ST_WRAP) -o $$@ -I$(ST_SDK) $$< + @$(PYTHON) tools/patch_constants.py --file $(ST_WRAP)/$1.cpp + ifdef __NT__ + @$(PYTHON) tools/patch_directors_cc.py --file $(ST_WRAP)/$1.h + endif + # The copying of the .py will preserve attributes (including timestamps). + # And, since we have patched $1.cpp, it'll be more recent than ida_$1.py, + # and make would keep copying the .py file at each invocation. + # To prevent that, let's make the source .py file more recent than .cpp. + @touch $(ST_WRAP)/ida_$1.py + + # obj/x86_linux_gcc/X.o32 + $(F)$1$(O): $(ST_WRAP)/$1.cpp + ifdef __CODE_CHECKER__ + touch $$@ + else + $(CXX) $(CFLAGS) $(MSRUNTIME) $(NORTTI) -DPLUGIN_SUBMODULE -DSWIG_DIRECTOR_NORTTI -c $(OBJSW)$$@ $(ST_WRAP)/$1.cpp + ifndef __NT__ + ifeq ($(OUT_OF_TREE_BUILD),) + @$(STRIPSYM_TOOL) $$@ $(STRIPSYMS) > /dev/null || ($(RM) $$@; false) + endif + endif + endif + + # obj/x86_linux_gcc/_ida_X.so + $(F)_ida_$1$(MODULE_SFX): $(F)$1$(O) $(BINARY) $(IDAPYTHON_IMPLIB_DEF) + ifdef __NT__ + $(LINKER) $(LINKOPTS) /OPT:ICF /OPT:REF /INCREMENTAL:NO /STUB:../../plugins/stub /OUT:$$@ $$< $(IDALIB) user32.lib $(ADDITIONAL_LIBS) $(IDAPYTHON_IMPLIB_PATH) + else + $(CCL) $(OUTDLL) $(OUTSW)$$@ $$< $(MODULE_LINKIDA) $(PLUGIN_SCRIPT) $(ADDITIONAL_LIBS) $(STDLIBS) + endif + + # ../../bin/x86_linux_gcc/python/lib/lib-dynload/ida_32/_ida_X.so + $(DEPLOY_LIBDIR)/_ida_$1$(MODULE_SFX): $(F)_ida_$1$(MODULE_SFX) | $(DEPLOY_LIBDIR) + @$(CP) $$< $$@ endef -$(foreach tgt,$(ST_SWIG_TARGETS),$(eval $(call make-deploy-swig-file-rule,$(tgt)))) +$(foreach mod,$(MODULES_NAMES),$(eval $(call make-module-rules,$(mod)))) + +$(ST_API_CONTENTS): $(ALL_ST_WRAP_CPP) + $(PYTHON) tools/chkapi.py $(WITH_HEXRAYS_CHKAPI) -i $(subst $(_SPACE),$(_COMMA),$(ALL_ST_WRAP_CPP)) -p $(subst $(_SPACE),$(_COMMA),$(ALL_ST_WRAP_PY)) -r $(ST_API_CONTENTS) + @(diff -w $(API_CONTENTS) $(ST_API_CONTENTS)) > /dev/null || \ + (echo "API CONTENTS CHANGED! update api_contents.txt or fix the API" && \ + echo "(New API: $(ST_API_CONTENTS)) ***" && \ + (diff -U 1 -w $(API_CONTENTS) $(ST_API_CONTENTS) && false)) + +# Check that doc injection is stable +PYDOC_INJECTIONS_RESULTS=$(MODULES_NAMES:%=$(ST_WRAP)/ida_%.pydoc_injection) +$(ST_PYDOC_INJECTIONS): $(PYTHON_MODULES) + cat $(PYDOC_INJECTIONS_RESULTS) > $@ + @(diff -w $(PYDOC_INJECTIONS) $(ST_PYDOC_INJECTIONS)) > /dev/null || \ + (echo "PYDOC INJECTION CHANGED! update $(PYDOC_INJECTIONS) or fix .. what needs fixing" && \ + echo "(New API: $(ST_PYDOC_INJECTIONS)) ***" && \ + (diff -U 1 -w $(PYDOC_INJECTIONS) $(ST_PYDOC_INJECTIONS) && false)) # Require a strict SWiG version (other versions might generate different code.) SWIG_VERSION_ACTUAL=$(shell $(SWIG) -version | awk "/SWIG Version [0-9.]+/ { if (match(\$$0, /([0-9.]+)/)) { print substr(\$$0, RSTART, RLENGTH); } }") -# idaapi.py is created together with idaapi_include.cpp -$(F)idaapi.py: | $(F)idaapi_include.cpp -# idaapi_include.h is created together with idaapi_include.cpp -patched_idaapi_include_h: patch_directors_cc.py | $(F)idaapi_include.h -ifdef __NT__ - @$(PYTHON) patch_directors_cc.py -f $(F)idaapi_include.h -endif +# ST_WRAP_FILES=$(MODULES_NAMES:%=$(ST_WRAP)/%.cpp) $(MODULES_NAMES:%=$(ST_WRAP)/%.h) $(MODULES_NAMES:%=$(ST_WRAP)/ida_%.py) +# .PRECIOUS: $(ST_WRAP_FILES) $(MODULES_OBJECTS) +.PRECIOUS: $(ST_API_CONTENTS) $(ST_PYDOC_INJECTIONS) -$(F)idaapi_include.h: | $(F)idaapi_include.cpp -$(F)idaapi_include.cpp: $(PRECOMPILED_COPY) \ - $(ST_SDK_TARGETS) \ - $(ST_PYW_TARGETS) \ - $(ST_SWIG_TARGETS) \ - pywraps.hpp | objdir - @ ! (grep __EA64__ swig/* | grep -v typeconv.i) || \ - (echo "ERROR: __EA64__ macro is foribidden in swig subdirectory (to ensure the same api for both ida versions)" && false) -ifneq ($(SWIG_VERSION_ACTUAL),$(SWIG_VERSION)) - $(error Expected SWIG version "$(SWIG_VERSION)", but got "$(SWIG_VERSION_ACTUAL)" (from $(SWIG))) -endif - $(SWIG) -modern $(WITH_HEXRAYS) -python -threads -c++ -shadow \ - $(MACDEFINES) -D__GNUC__ $(SWIGFLAGS) $(SWITCH64) -I$(ST_SWIG) \ - -outdir $(F) -o $@ -I$(ST_SDK) $(ST_SWIG)/idaapi.i || \ - { $(RM) $(F)idaapi_include.*; exit 1 ;} - $(PYTHON) chkapi.py $(WITH_HEXRAYS_CHKAPI) -f $@ -r $(API_CONTENTS).new - @(diff $(API_CONTENTS) $(API_CONTENTS).new) > /dev/null || \ - (rm -f $@ $(F)idaapi_include.h && \ - echo "API CONTENTS CHANGED! update api_contents.txt or fix the API" && \ - echo "(New API: $(API_CONTENTS).new) ***" && \ - (diff -U 1 -w $(API_CONTENTS) $(API_CONTENTS).new && false)) - - -# Python version -CFLAGS= $(CCOPT) $(OSFLAGS) -D__EXPR_SRC -I. -I$(ST_SWIG) -I$(ST_SDK) -I$(F) \ - -DVER_MAJOR="1" -DVER_MINOR="7" -DVER_PATCH="0" -D__IDP__ \ - -DUSE_STANDARD_FILE_FUNCTIONS $(IDAPYTHON_CFLAGS) \ - $(SWITCH64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) +DOCS_MODULES=$(MODULES_NAMES:%=ida_%) +tools/docs/hrdoc.cfg: tools/docs/hrdoc.cfg.in + sed s/%IDA_MODULES%/"$(DOCS_MODULES)"/ < $? > $@ # the html files are produced in docs\hr-html directory -docs: hrdoc.py hrdoc.cfg hrdoc.css - idaq -Shrdoc.py -t +docs: tools/docs/hrdoc.py tools/docs/hrdoc.cfg tools/docs/hrdoc.css +ifndef __NT__ + TVHEADLESS=1 $(R)idal -Stools/docs/hrdoc.py -t > /dev/null +else + $(R)idaq -Stools/docs/hrdoc.py -t +endif # Test that all functions that are present in ftable.cpp # are present in idc.py (and therefore made available by @@ -367,52 +515,37 @@ ifneq ($(wildcard ../../tests),) (echo "ERROR: The IDAPython IDC interface is incomplete. IDA log:" && cat $(F)idctest.log && false) endif -dist_dirs: - -@if [ ! -d "$(DIST)/plugins" ] ; then mkdir -p 2>/dev/null $(DIST)/plugins ; fi - -DIST_OTHER_SOURCES=python.cfg README.md AUTHORS.txt CHANGES.txt COPYING.txt STATUS.txt -DIST_OTHER_TARGETS=$(DIST_OTHER_SOURCES:%=$(DIST)/%) -$(DIST)/%: % | dist_dirs - @$(CP) $^ $@ && chmod +rw $@ - -DIST_BINARY=$(DIST)/plugins/$(PROC)$(PLUGIN) -$(DIST_BINARY): $(BINARY) | dist_dirs - $(CP) $? $@ -ifdef __LINUX__ - strip $@ -else - ifdef __MAC__ - strip -x $@ - endif +package: +ifeq ($(OUT_OF_TREE_BUILD),) + -@if [ ! -d "$(DIST)" ] ; then mkdir -p 2>/dev/null $(DIST) ; fi + $(PYTHON) $(PKGBIN_SCRIPT) \ + --input-binary-tree $(R) \ + --output-dir $(DIST) \ + --confirmed \ + --component plugins/idapython + (cd $(DIST) && $(PYTHON) $(DBLZIP_SCRIPT) --once --output ../../../obj/$(PACKAGE_NAME)) endif -dist: $(BINARY) pyfiles $(DIST_OTHER_TARGETS) $(DIST_BINARY) dist_cfg | dist_dirs - # rsync -a docs $(DIST)/ - rsync -a examples $(DIST)/ - rsync -a python $(DIST)/ - -package: - (cd $(DIST) && zip -r ../../$(PACKAGE_NAME) *) +public_tree: all +ifeq ($(OUT_OF_TREE_BUILD),) + -@if [ ! -d "$(PUBTREE_DIR)/out_of_tree" ] ; then mkdir -p 2>/dev/null $(PUBTREE_DIR)/out_of_tree ; fi + rsync -a --exclude=obj/ \ + --exclude=precompiled/ \ + --exclude=repl.py \ + --exclude=test_idc.py \ + --exclude=RELEASE.md \ + . $(PUBTREE_DIR) + (cd $(F) && zip -r ../../$(PUBTREE_DIR)/out_of_tree/parsed_notifications.zip parsed_notifications) +endif +echo_modules: + @echo $(MODULES_NAMES) # MAKEDEP dependency list ------------------ -$(F)idaapi$(O) : $(F)idaapi_include.cpp $(I)allins.hpp $(I)area.hpp \ - $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp $(I)dbg.hpp \ - $(I)diskio.hpp $(I)entry.hpp $(I)enum.hpp $(I)err.h \ - $(I)expr.hpp $(I)fixup.hpp $(I)fpro.h $(I)frame.hpp \ - $(I)funcs.hpp $(I)gdl.hpp $(I)graph.hpp $(I)ida.hpp \ - $(I)idd.hpp $(I)idp.hpp $(I)ieee.h $(I)ints.hpp \ - $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \ - $(I)loader.hpp $(I)moves.hpp $(I)nalt.hpp $(I)name.hpp \ - $(I)netnode.hpp $(I)offset.hpp $(I)pro.h $(I)queue.hpp \ - $(I)search.hpp $(I)segment.hpp $(I)sistack.hpp \ - $(I)srarea.hpp $(I)strlist.hpp $(I)struct.hpp \ - $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \ - idaapi.cpp pywraps.hpp | patched_idaapi_include_h $(ST_SDK_TARGETS) $(F)python$(O) : $(I)area.hpp $(I)bitrange.hpp $(I)bytes.hpp \ $(I)diskio.hpp $(I)expr.hpp $(I)fpro.h $(I)funcs.hpp \ $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp \ $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \ $(I)netnode.hpp $(I)pro.h $(I)segment.hpp $(I)ua.hpp \ - $(I)xref.hpp python.cpp pywraps.hpp | $(ST_SDK_TARGETS) + $(I)xref.hpp python.cpp pywraps.hpp pywraps.cpp | $(ST_SDK_TARGETS) endif diff --git a/out_of_tree/parsed_notifications.zip b/out_of_tree/parsed_notifications.zip new file mode 100644 index 0000000..05a4b6f Binary files /dev/null and b/out_of_tree/parsed_notifications.zip differ diff --git a/patch_directors_cc.py b/patch_directors_cc.py deleted file mode 100644 index 0bc3fb3..0000000 --- a/patch_directors_cc.py +++ /dev/null @@ -1,80 +0,0 @@ - -import os, shutil, sys, optparse - -if __name__ == "__main__": - - p = optparse.OptionParser(description='Patch calling conventions for some functions, so it builds on windows') - p.add_option('-v', "--verbose", dest="verbose", action="store_true") - p.add_option('-f', "--file", dest="path", type="string", help="File name, without extension.") - opts, _ = p.parse_args(sys.argv[1:]) - - if not opts.path: - p.print_help() - sys.exit(1) - - patches = [ - # text_sink_t - "virtual int idaapi print", - - # user_lvar_modifier_t - "virtual bool idaapi modify_lvars", - - # ctree_visitor_t - "virtual int idaapi visit_insn", - "virtual int idaapi visit_expr", - "virtual int idaapi leave_insn", - "virtual int idaapi leave_expr", - - # ctree_parentee_t - "virtual int idaapi visit_insn", - "virtual int idaapi visit_expr", - "virtual int idaapi leave_insn", - "virtual int idaapi leave_expr", - - # cfunc_parentee_t - "virtual int idaapi visit_insn", - "virtual int idaapi visit_expr", - "virtual int idaapi leave_insn", - "virtual int idaapi leave_expr", - - # enum_member_visitor_t - "virtual int idaapi visit_enum_member", - - # struct_field_visitor_t - "virtual int idaapi visit_field", - - # tinfo_visitor_t - "virtual int idaapi visit_type", - - # aloc_visitor_t - "virtual int idaapi visit_location", - - # const_aloc_visitor_t - "virtual int idaapi visit_location", - - # area_visitor2_t - "virtual int idaapi visit_area", - - # highlighter_cbs_t - "virtual void idaapi set_style", - "virtual int32 idaapi prev_block_state", - "virtual int32 idaapi cur_block_state", - "virtual void idaapi set_block_state", - ] - - path = opts.path - outlines = [] - outpath = "%s.cc" % path - with open(path, "r") as f: - lines = f.readlines() - for line in lines: - for patch in patches: - from_text = patch.replace("idaapi ", "") - if line.find(from_text) > -1: - line = line.replace(from_text, patch) - patches.remove(patch) - break - outlines.append(line) - with open(outpath, "w") as f: - f.writelines(outlines) - shutil.move(outpath, path) diff --git a/pydoc_injections.txt b/pydoc_injections.txt new file mode 100644 index 0000000..224b348 --- /dev/null +++ b/pydoc_injections.txt @@ -0,0 +1,214 @@ +### Processing allins.i +### Processing area.i +### Processing auto.i +### Processing bytes.i +fix_fun: found info for visit_patched_bytes +fix_fun: found info for nextthat +fix_fun: found info for get_many_bytes +fix_fun: found info for get_ascii_contents2 +fix_fun: found info for get_ascii_contents +fix_fun: found info for register_custom_data_type +fix_fun: found info for unregister_custom_data_type +fix_fun: found info for register_custom_data_format +fix_fun: found info for unregister_custom_data_format +fix_fun: found info for get_custom_data_format +fix_fun: found info for get_custom_data_type +### Processing dbg.i +fix_fun: found info for get_manual_regions +fix_fun: found info for dbg_is_loaded +fix_fun: found info for refresh_debugger_memory +fix_fun: found info for move_bpt_to_grp +fix_fun: found info for internal_get_sreg_base +### Processing diskio.i +fix_fun: found info for enumerate_files +### Processing entry.i +### Processing enum.i +### Processing expr.i +### Processing fixup.i +### Processing fpro.i +fix_class: found info for qfile_t +fix_method: found info for __init__ +fix_method: found info for opened +fix_method: found info for open +fix_method: found info for tmpfile +fix_method: found info for seek +fix_method: found info for tell +fix_method: found info for readbytes +fix_method: found info for read +fix_method: found info for gets +fix_method: found info for writebytes +fix_method: found info for write +fix_method: found info for flush +fix_method: found info for put_char +### Processing frame.i +fix_fun: found info for add_stkvar3 +fix_fun: found info for get_stkvar +### Processing funcs.i +fix_fun: found info for get_fchunk_referer +fix_fun: found info for get_idasgn_desc +fix_fun: found info for get_idasgn_desc_with_matches +fix_fun: found info for get_func_cmt +### Processing gdl.i +### Processing graph.i +### Processing hexrays.i +### Processing ida.i +### Processing idaapi.i +fix_fun: found info for get_inf_structure +fix_fun: found info for set_script_timeout +fix_fun: found info for disable_script_timeout +fix_fun: found info for enable_extlang_python +fix_fun: found info for notify_when +fix_class: found info for loader_input_t +fix_method: found info for __init__ +fix_method: found info for open +fix_method: found info for set_linput +fix_method: found info for from_fp +fix_method: found info for open_memory +fix_method: found info for seek +fix_method: found info for tell +fix_method: found info for getz +fix_method: found info for gets +fix_method: found info for read +fix_method: found info for opened +fix_method: found info for readbytes +fix_method: found info for file2base +fix_method: found info for get_char +### Processing idd.i +fix_fun: found info for dbg_get_registers +fix_fun: found info for dbg_get_thread_sreg_base +fix_fun: found info for dbg_read_memory +fix_fun: found info for dbg_write_memory +fix_fun: found info for dbg_get_name +fix_fun: found info for dbg_get_memory_info +fix_fun: found info for dbg_can_query +### Processing idp.i +fix_fun: found info for AssembleLine +fix_fun: found info for assemble +fix_fun: found info for ph_get_id +fix_fun: found info for ph_get_version +fix_fun: found info for ph_get_flag +fix_fun: found info for ph_get_cnbits +fix_fun: found info for ph_get_dnbits +fix_fun: found info for ph_get_regFirstSreg +fix_fun: found info for ph_get_regLastSreg +fix_fun: found info for ph_get_segreg_size +fix_fun: found info for ph_get_regCodeSreg +fix_fun: found info for ph_get_regDataSreg +fix_fun: found info for ph_get_high_fixup_bits +fix_fun: found info for ph_get_icode_return +fix_fun: found info for ph_get_instruc_start +fix_fun: found info for ph_get_instruc_end +fix_fun: found info for ph_get_tbyte_size +fix_fun: found info for ph_get_instruc +fix_fun: found info for ph_get_regnames +fix_fun: found info for ph_get_operand_info +fix_class: found info for IDP_Hooks +fix_method: found info for hook +fix_method: found info for unhook +fix_method: found info for assemble +fix_method: found info for rename +fix_method: found info for closebase +fix_method: found info for load_idasgn +fix_method: found info for may_be_func +fix_method: found info for is_sane_insn +fix_method: found info for custom_ana +fix_method: found info for custom_out +fix_method: found info for custom_emu +fix_method: found info for custom_outop +fix_method: found info for custom_mnem +fix_method: found info for undefine +fix_method: found info for make_code +fix_method: found info for make_data +fix_method: found info for is_call_insn +fix_method: found info for is_ret_insn +fix_method: found info for savebase +fix_method: found info for renamed +fix_method: found info for add_func +fix_method: found info for del_func +### Processing ints.i +### Processing kernwin.i +fix_fun: found info for register_timer +fix_fun: found info for unregister_timer +fix_fun: found info for choose_idasgn +fix_fun: found info for get_highlighted_identifier +fix_fun: found info for umsg +fix_fun: found info for msg +fix_fun: found info for asktext +fix_fun: found info for str2ea +fix_fun: found info for str2user +fix_fun: found info for process_ui_action +fix_fun: found info for del_menu_item +fix_fun: found info for del_hotkey +fix_fun: found info for add_hotkey +fix_fun: found info for add_menu_item +fix_fun: found info for execute_sync +fix_fun: found info for execute_ui_requests +fix_class: found info for UI_Hooks +fix_method: found info for hook +fix_method: found info for unhook +fix_method: found info for saving +fix_method: found info for saved +fix_method: found info for term +fix_method: found info for get_ea_hint +fix_method: found info for preprocess +fix_method: found info for postprocess +fix_method: found info for updating_actions +fix_method: found info for updated_actions +fix_method: found info for populating_tform_popup +fix_method: found info for finish_populating_tform_popup +fix_fun: found info for set_nav_colorizer +fix_fun: found info for call_nav_colorizer +fix_fun: found info for set_dock_pos +fix_fun: found info for free_custom_icon +fix_fun: found info for is_idaq +fix_fun: found info for readsel2 +### Processing lines.i +fix_fun: found info for set_user_defined_prefix +fix_fun: found info for tag_remove +fix_fun: found info for generate_disassembly +### Processing loader.i +fix_fun: found info for mem2base +fix_fun: found info for load_plugin +fix_fun: found info for run_plugin +### Processing moves.i +### Processing nalt.i +fix_fun: found info for get_import_module_name +fix_fun: found info for get_switch_info_ex +fix_fun: found info for set_switch_info_ex +fix_fun: found info for del_switch_info_ex +fix_fun: found info for enum_import_names +### Processing name.i +### Processing netnode.i +### Processing offset.i +### Processing pro.i +### Processing queue.i +### Processing registry.i +### Processing search.i +### Processing segment.i +### Processing srarea.i +### Processing strlist.i +### Processing struct.i +### Processing typeinf.i +fix_fun: found info for calc_type_size +fix_fun: found info for apply_type +fix_fun: found info for print_type +fix_fun: found info for unpack_object_from_bv +fix_fun: found info for pack_object_to_idb +fix_fun: found info for pack_object_to_bv +fix_fun: found info for get_named_type +fix_fun: found info for apply_type_to_stkarg +### Processing ua.i +fix_fun: found info for init_output_buffer +fix_fun: found info for term_output_buffer +fix_fun: found info for decode_preceding_insn +fix_fun: found info for OutValue +fix_fun: found info for OutImmChar +fix_fun: found info for ua_stkvar2 +fix_fun: found info for ua_add_off_drefs +fix_fun: found info for ua_add_off_drefs2 +fix_fun: found info for out_name_expr +fix_fun: found info for construct_macro +### Processing xref.i +fix_fun: found info for create_switch_xrefs +fix_fun: found info for calc_switch_cases +fix_fun: found info for create_switch_table diff --git a/python.cfg b/python.cfg index 1ecd270..b2a1857 100644 --- a/python.cfg +++ b/python.cfg @@ -8,3 +8,7 @@ REMOVE_CWD_SYS_PATH = YES // Script timeout (in seconds) // (A value of 0 disables the timeout) SCRIPT_TIMEOUT = 3 + +// Should the plugin automatically load a backward-compatibility-providing +// 'idaapi' wrapper module? +AUTOIMPORT_COMPAT_IDAAPI = YES diff --git a/python.cpp b/python.cpp index 879f278..712c862 100644 --- a/python.cpp +++ b/python.cpp @@ -32,13 +32,8 @@ #include #include -#ifdef WITH_HEXRAYS -//-V::730 Not all members of a class are initialized inside the constructor -#include -hexdsp_t *hexdsp = NULL; -#endif - #include "pywraps.hpp" +#include "pywraps.cpp" //------------------------------------------------------------------------- // Defines and constants @@ -54,7 +49,6 @@ hexdsp_t *hexdsp = NULL; #define S_IDAPYTHON "IDAPython" #define S_INIT_PY "init.py" static const char S_IDC_ARGS_VARNAME[] = "ARGV"; -static const char S_MAIN[] = "__main__"; static const char S_IDC_RUNPYTHON_STATEMENT[] = "RunPythonStatement"; static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data"; @@ -80,9 +74,9 @@ static char g_idapython_dir[QMAXPATH]; //------------------------------------------------------------------------- // Prototypes and forward declarations -// Alias to SWIG_Init -//lint -esym(526,init_idaapi) not defined -extern "C" void init_idaapi(void); +// // Alias to SWIG_Init +// //lint -esym(526,init_idaapi) not defined +// extern "C" void init_idaapi(void); // Plugin run() callback void idaapi run(int arg); @@ -117,40 +111,186 @@ int tracefunc(PyObject *obj, _frame *frame, int what, PyObject *arg) //------------------------------------------------------------------------- // Helper routines to make Python script execution breakable from IDA -static int ninsns = 0; // number of times trace function was called -static bool box_displayed; // has the wait box been displayed? -static time_t start_time; // the start time of the execution -static int script_timeout = 2; static bool g_ui_ready = false; static bool g_alert_auto_scripts = true; static bool g_remove_cwd_sys_path = false; static bool g_use_local_python = false; +static bool g_autoimport_compat_idaapi = true; -static void end_execution(void); -static void begin_execution(void); +// Allowing the user to interrupt a script is not entirely trivial. +// Imagine the following script, that is run in an IDB that uses +// an IDAPython processor module (important!) : +// --- +// while True: +// gen_disasm_text(ea, ea + 4, dtext, False) +// --- +// This script will call the processor module's out/outop functions in +// order to generate the text. If the processor module behaves +// correctly (i.e., doesn't take forever to generate said text), if the +// user presses 'Cancel' once the wait dialog box shows, what we want +// to cancel is _this_ script above: we don't want to interrupt the +// processor module while it's doing its thing! +// In order to do that, we will have to remember the time-of-entry of +// various entry points: +// - IDAPython_extlang_compile_file +// - IDAPython_RunStatement +// - ... and more importantly in this case: +// - IDAPython_extlang_call_method (called by the IDA kernel to generate text) +// +// Of course, in case the processor module's out/outop misbehaves, we still +// want the ability to cancel that operation. The following code allows for +// that, too. + +//------------------------------------------------------------------------- +struct exec_entry_t +{ + time_t etime; + exec_entry_t() { etime = time(NULL); } +}; +DECLARE_TYPE_AS_MOVABLE(exec_entry_t); +typedef qvector exec_entries_t; + +//------------------------------------------------------------------------- +struct execution_t +{ + exec_entries_t entries; + int timeout; + uint32 steps_before_action; + bool waitdialog_shown; + + execution_t() + : timeout(2), + steps_before_action(0), + waitdialog_shown(false) + { + reset_steps(); + } + void reset_steps(); + void push(); + void pop(); + bool can_interrupt_current(time_t now) const; + void stop_tracking(); + void sync_to_present_time(); + void maybe_hide_waitdialog(); + static int on_trace(PyObject *obj, _frame *frame, int what, PyObject *arg); +}; +static execution_t execution; + +//#define LOG_EXEC 1 +#ifdef LOG_EXEC +#define LEXEC(Format, ...) msg("IDAPython exec: " Format, __VA_ARGS__) +#else +#define LEXEC(Format, ...) +#endif + +//------------------------------------------------------------------------- +void execution_t::reset_steps() +{ + // we want to trace/check the time about every 10 steps. But we don't + // want it to be exactly 10 steps, or we might never make important + // checks because the tracing happens always at the wrong point. + // E.g., imagine the following loop: + // --- + // while True: + // gen_disasm_text(ea, ea + 4, dtext, False) + // --- + // If we never hit the 'trace' callback while in the 'while True' loop + // but always when performing the call to the processor module's 'out/outop' + // then the loop will never stop. That was happening on windows (optimized.) + steps_before_action = 1 + rand() % 20; +} + +//------------------------------------------------------------------------- +void execution_t::push() +{ + if ( entries.empty() ) + PyEval_SetTrace(execution_t::on_trace, NULL); + entries.push_back(); + LEXEC("push() (now: %d entries)\n", int(entries.size())); +} + +//------------------------------------------------------------------------- +void execution_t::pop() +{ + entries.pop_back(); + if ( entries.empty() ) + stop_tracking(); + LEXEC("pop() (now: %d entries)\n", int(entries.size())); +} + +//------------------------------------------------------------------------- +void execution_t::stop_tracking() +{ + PyEval_SetTrace(NULL, NULL); + maybe_hide_waitdialog(); +} + +//------------------------------------------------------------------------- +void execution_t::sync_to_present_time() +{ + time_t now = time(NULL); + for ( size_t i = 0, n = entries.size(); i < n; ++i ) + entries[i].etime = now; + maybe_hide_waitdialog(); +} + +//------------------------------------------------------------------------- +void execution_t::maybe_hide_waitdialog() +{ + if ( waitdialog_shown ) + { + hide_wait_box(); + waitdialog_shown = false; + } +} + +//------------------------------------------------------------------------- +bool execution_t::can_interrupt_current(time_t now) const +{ + LEXEC("can_interrupt_current(): nentries: %d\n", int(entries.size())); + if ( entries.empty() || timeout <= 0 ) + return false; + const exec_entry_t &last = entries.back(); + bool can = (now - last.etime) > timeout; + LEXEC("can_interrupt_current(): last: %d, now: %d (-> %d)\n", + int(last.etime), int(now), can); + return can; +} //------------------------------------------------------------------------ -// This callback is called on various interpreter events -static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg) +int execution_t::on_trace(PyObject *obj, _frame *frame, int what, PyObject *arg) { - if ( wasBreak() ) - { - // User pressed Cancel in the waitbox; send KeyboardInterrupt exception - PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted"); - return -1; - } - else if ( !box_displayed && ++ninsns > 10 ) - { - // We check the timer once every 10 calls - ninsns = 0; + LEXEC("on_trace() (steps=%d, nentries=%d)\n", + int(execution.steps_before_action), int(execution.entries.size())); + // we don't want to query for time at every trace event + if ( execution.steps_before_action-- > 0 ) + return 0; - // Timeout disabled or elapsed? - if ( script_timeout != 0 && (time(NULL) - start_time > script_timeout) ) + execution.reset_steps(); + time_t now = time(NULL); + LEXEC("on_trace()::now: %d\n", int(now)); + bool can_interrupt = execution.can_interrupt_current(now); + if ( can_interrupt ) + { + LEXEC("on_trace()::can_interrupt. Waitdialog shown? %d\n", + int(execution.waitdialog_shown)); + if ( execution.waitdialog_shown ) { - box_displayed = true; + if ( wasBreak() ) + { + LEXEC("on_trace()::INTERRUPTING\n"); + PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted"); + return -1; + } + } + else + { + LEXEC("on_trace()::showing wait dialog\n"); show_wait_box("Running Python script"); + execution.waitdialog_shown = true; } } + #ifdef ENABLE_PYTHON_PROFILING return tracefunc(obj, frame, what, arg); #else @@ -162,84 +302,50 @@ static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg) #endif } -//------------------------------------------------------------------------ -static void reset_execution_time() +//------------------------------------------------------------------------- +//lint -esym(1788, new_execution_t) is referenced only by its constructor or destructor +struct new_execution_t { - start_time = time(NULL); - ninsns = 0; -} - -//------------------------------------------------------------------------ -// Prepare for Python execution -static void begin_execution() -{ - if ( !g_ui_ready || script_timeout == 0 ) - return; - - PYW_GIL_CHECK_LOCKED_SCOPE(); - end_execution(); - reset_execution_time(); - PyEval_SetTrace(break_check, NULL); -} - -//--------------------------------------------------------------------------- -static void hide_script_waitbox() -{ - if ( box_displayed ) + bool created; + new_execution_t() { - hide_wait_box(); - box_displayed = false; + created = g_ui_ready && execution.timeout > 0; + if ( created ) + { + PYW_GIL_CHECK_LOCKED_SCOPE(); + execution.push(); + } } -} - -//------------------------------------------------------------------------ -// Called after Python execution finishes -static void end_execution() -{ - hide_script_waitbox(); - PYW_GIL_CHECK_LOCKED_SCOPE(); -#ifdef ENABLE_PYTHON_PROFILING - PyEval_SetTrace(tracefunc, NULL); -#else - PyEval_SetTrace(NULL, NULL); -#endif -} - -//------------------------------------------------------------------------- -pycall_res_t::pycall_res_t(PyObject *pyo) - : result(pyo) -{ - PYGLOG("return code: %p\n", result.o); -} - -//------------------------------------------------------------------------- -pycall_res_t::~pycall_res_t() -{ - if ( PyErr_Occurred() ) - PyErr_Print(); -} + ~new_execution_t() + { + if ( created ) + { + PYW_GIL_CHECK_LOCKED_SCOPE(); + execution.pop(); + } + } +}; //------------------------------------------------------------------------- //lint -esym(714,disable_script_timeout) Symbol not referenced -void disable_script_timeout() +idaman void ida_export disable_script_timeout() { // Clear timeout - script_timeout = 0; + execution.timeout = 0; // Uninstall the trace function and hide the waitbox (if it was shown) - end_execution(); + execution.stop_tracking(); } //------------------------------------------------------------------------- //lint -esym(714,set_script_timeout) Symbol not referenced -int set_script_timeout(int timeout) +idaman int ida_export set_script_timeout(int timeout) { // Update the timeout - qswap(timeout, script_timeout); + qswap(timeout, execution.timeout); // Reset the execution time and hide the waitbox (so it is shown again after timeout elapses) - reset_execution_time(); - hide_script_waitbox(); + execution.sync_to_present_time(); return timeout; } @@ -347,16 +453,17 @@ static bool idaapi IDAPython_extlang_run_statements( { errbuf[0] = '\0'; PyErr_Clear(); - begin_execution(); - newref_t result(PyRun_String( - str, - Py_file_input, - globals, - globals)); - end_execution(); - ok = result != NULL && !PyErr_Occurred(); - if ( !ok ) - handle_python_error(errbuf, errbufsize); + { + new_execution_t exec; + newref_t result(PyRun_String( + str, + Py_file_input, + globals, + globals)); + ok = result != NULL && !PyErr_Occurred(); + if ( !ok ) + handle_python_error(errbuf, errbufsize); + } } if ( !ok && errbuf[0] == '\0' ) qstrncpy(errbuf, "internal error", errbufsize); @@ -384,9 +491,10 @@ static error_t idaapi idc_runpythonstatement( //-------------------------------------------------------------------------- static const cfgopt_t opts[] = { - cfgopt_t("SCRIPT_TIMEOUT", &script_timeout, 0, INT_MAX), + cfgopt_t("SCRIPT_TIMEOUT", &execution.timeout, 0, INT_MAX), cfgopt_t("ALERT_AUTO_SCRIPTS", &g_alert_auto_scripts, true), cfgopt_t("REMOVE_CWD_SYS_PATH", &g_remove_cwd_sys_path, true), + cfgopt_t("AUTOIMPORT_COMPAT_IDAAPI", &g_autoimport_compat_idaapi, true), }; //------------------------------------------------------------------------- @@ -397,11 +505,11 @@ static bool check_python_dir() { S_IDC_MODNAME ".py", S_INIT_PY, - "idaapi.py", + "ida_idaapi.py", "idautils.py" }; char filepath[QMAXPATH]; - for ( size_t i=0; iis_zero() ) { errbuf[0] = '\0'; ok = false; } - end_execution(); return ok; } @@ -842,10 +949,8 @@ static bool idaapi IDAPython_extlang_unloadprocmod( size_t errbufsize) { PYW_GIL_GET; - begin_execution(); - bool ok = IDAPython_ExecFile(filename, errbuf, errbufsize, S_IDAAPI_UNLOADPROCMOD); - end_execution(); - return ok; + new_execution_t exec; + return IDAPython_ExecFile(filename, errbuf, errbufsize, S_IDAAPI_UNLOADPROCMOD); } //------------------------------------------------------------------------- @@ -1076,9 +1181,10 @@ bool idaapi IDAPython_extlang_calcexpr( ref_t result; if ( ok ) { - begin_execution(); - result = newref_t(PyRun_String(expr, Py_eval_input, globals, globals)); - end_execution(); + { + new_execution_t exec; + result = newref_t(PyRun_String(expr, Py_eval_input, globals, globals)); + } ok = return_python_result(rv, result, errbuf, errbufsize); } return ok; @@ -1105,7 +1211,8 @@ bool idaapi IDAPython_extlang_call_method( // Behave like run() else if ( idc_obj == NULL && method_name != NULL ) { - return IDAPython_extlang_run(method_name, nargs, args, result, errbuf, errbufsize); + new_execution_t exec; + return IDAPython_extlang_run(method_name, nargs, args, result, errbuf, errbufsize); } // Holds conversion status of input object @@ -1135,8 +1242,11 @@ bool idaapi IDAPython_extlang_call_method( if ( !ok ) break; - newref_t py_res(PyObject_CallObject(py_method.o, pargs.empty() ? NULL : pargs[0].o)); - ok = return_python_result(result, py_res, errbuf, errbufsize); + { + new_execution_t exec; + newref_t py_res(PyObject_CallObject(py_method.o, pargs.empty() ? NULL : pargs[0].o)); + ok = return_python_result(result, py_res, errbuf, errbufsize); + } } while ( false ); return ok; @@ -1196,7 +1306,7 @@ const extlang_t extlang_python = }; //------------------------------------------------------------------------- -void enable_extlang_python(bool enable) +idaman void ida_export enable_extlang_python(bool enable) { if ( enable ) select_extlang(&extlang_python); @@ -1247,9 +1357,10 @@ bool idaapi IDAPython_cli_execute_line(const char *line) line = s.c_str(); } while (false); - begin_execution(); - PythonEvalOrExec(line); - end_execution(); + { + new_execution_t exec; + PythonEvalOrExec(line); + } return true; } @@ -1294,7 +1405,7 @@ static const cli_t cli_python = //------------------------------------------------------------------------- // Control the Python CLI status -void enable_python_cli(bool enable) +idaman void ida_export enable_python_cli(bool enable) { if ( enable ) install_command_interpreter(&cli_python); @@ -1302,14 +1413,6 @@ void enable_python_cli(bool enable) remove_command_interpreter(&cli_python); } -//------------------------------------------------------------------------- -// Prints the IDAPython copyright banner -void py_print_banner() -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - PyRun_SimpleString("print_banner()"); -} - //------------------------------------------------------------------------ // Parse plugin options void parse_plugin_options() @@ -1362,37 +1465,25 @@ void convert_idc_args() PyObject_SetAttrString(py_mod.o, S_IDC_ARGS_VARNAME, py_args.o); } -#ifdef WITH_HEXRAYS -//------------------------------------------------------------------------- -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; -} -#endif - - //------------------------------------------------------------------------ //lint -esym(715,va) Symbol not referenced -static int idaapi on_ui_notification(void *, int code, va_list va) +static int idaapi on_ui_notification(void *, int code, va_list) { -#ifdef WITH_HEXRAYS - qnotused(va); -#endif switch ( code ) { - case ui_ready_to_run: + case ui_term: { PYW_GIL_GET; // This hook gets called from the kernel. Ensure we hold the GIL. - g_ui_ready = true; - py_print_banner(); + // Let's make sure there are no non-Free()d forms. + free_compiled_form_instances(); + } + break; + case ui_ready_to_run: + { + PYW_GIL_GET; // See above + g_ui_ready = true; + PyRun_SimpleString("print_banner()"); if ( g_run_when == run_on_ui_ready ) RunScript(g_run_script); } @@ -1400,50 +1491,13 @@ static int idaapi on_ui_notification(void *, int code, va_list va) case ui_database_inited: { - PYW_GIL_GET; // This hook gets called from the kernel. Ensure we hold the GIL. + PYW_GIL_GET; // See above convert_idc_args(); if ( g_run_when == run_on_db_open ) RunScript(g_run_script); } break; - case ui_term: - { - PYW_GIL_GET; - // Let's make sure there are no non-Free()d forms. - free_compiled_form_instances(); - } - break; - -#ifdef WITH_HEXRAYS - case ui_plugin_loaded: - if ( hexdsp == NULL ) - { - if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) ) - { - init_hexrays_plugin(0); - if ( hexdsp != NULL ) - msg("IDAPython Hex-Rays bindings initialized.\n"); - } - } - 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; -#endif - default: break; } @@ -1452,7 +1506,6 @@ static int idaapi on_ui_notification(void *, int code, va_list va) //------------------------------------------------------------------------- //lint -esym(526,til_clear_python_tinfo_t_instances) not defined -extern void til_clear_python_tinfo_t_instances(void); static int idaapi on_idp_notification(void *, int code, va_list) { switch ( code ) @@ -1462,6 +1515,8 @@ static int idaapi on_idp_notification(void *, int code, va_list) // through all the tinfo_t objects that are embedded in SWIG wrappers, // (i.e., that were created from Python) and clear those. til_clear_python_tinfo_t_instances(); + // Same thing for live python timers + clear_python_timer_instances(); break; } return 0; @@ -1498,8 +1553,9 @@ static int idaapi ui_debug_handler_cb(void *, int code, va_list) #endif //------------------------------------------------------------------------- -// remove current directory (empty entry) from the sys.path -static void sanitize_path() +// - remove current directory (empty entry) from the sys.path +// - add idadir("python") +static void prepare_sys_path() { char buf[QMAXPATH]; qstrncpy(buf, Py_GetPath(), sizeof(buf)); @@ -1517,6 +1573,9 @@ static void sanitize_path() newpath.append(DELIMITER); newpath.append(d0); } + if ( !newpath.empty() ) + newpath.append(DELIMITER); + newpath.append(idadir("python")); PySys_SetPath(newpath.begin()); } @@ -1540,6 +1599,26 @@ static bool initsite(void) return true; } +//------------------------------------------------------------------------- +static void init_ida_modules() +{ + // char buf[QMAXPATH]; + // // IDA_MODULES must be passed as a define + // qstrncpy(buf, IDA_MODULES, sizeof(buf)); + // char *ctx; + // for ( char *module = qstrtok(buf, ",", &ctx); + // module != NULL; + // module = qstrtok(NULL, DELIMITER, &ctx) ) + // { + // deb(IDA_DEBUG_PLUGIN, "Initializing \"ida_%s\"\n", module); + // } + + // Load the 'ida_idaapi' module, that contains some important bits of code + // ref_t ida_idaapi(PyW_TryImportModule(S_PY_IDA_IDAAPI_MODNAME)); + + // ref_t sys(PyW_TryImportModule("sys")); +} + //------------------------------------------------------------------------- // Initialize the Python environment bool IDAPython_Init(void) @@ -1629,7 +1708,7 @@ bool IDAPython_Init(void) } // remove current directory - sanitize_path(); + prepare_sys_path(); // import "site" if ( !g_use_local_python && !initsite() ) @@ -1642,8 +1721,7 @@ bool IDAPython_Init(void) if ( !PyEval_ThreadsInitialized() ) PyEval_InitThreads(); - // Init the SWIG wrapper - init_idaapi(); + init_ida_modules(); #ifdef Py_DEBUG msg("HexraysPython: Python compiled with DEBUG enabled.\n"); @@ -1654,13 +1732,23 @@ bool IDAPython_Init(void) tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n" - "IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n", + "IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n" + "IDAPYTHON_DYNLOAD_BASE = r\"%s\"\n" + "IDAPYTHON_DYNLOAD_RELPATH = \"ida_%d\"\n" + "IDAPYTHON_COMPAT_AUTOIMPORT_MODULES = %s\n", VER_MAJOR, VER_MINOR, VER_PATCH, VER_STATUS, VER_SERIAL, - g_remove_cwd_sys_path ? "True" : "False"); + g_remove_cwd_sys_path ? "True" : "False", + idadir(NULL), +#ifdef __EA64__ + 64, +#else + 32, +#endif + g_autoimport_compat_idaapi ? "True" : "False"); PyRun_SimpleString(tmp); // Install extlang. Needs to be done before running init.py diff --git a/python/idaapi.py b/python/idaapi.py new file mode 100644 index 0000000..8e39a09 --- /dev/null +++ b/python/idaapi.py @@ -0,0 +1,42 @@ + +import sys + +${IMPORTS} + +class idaapi_Cvar(object): + def __init__(self): + # prevent endless recursion + object.__setattr__(self, "modules", "${MODULES}".split(",")) + object.__setattr__(self, "cvars_entries", dict()) + + def _get_module_cvar(self, modname): + mod = sys.modules["ida_%s" % modname] + cv, entries = None, None + if hasattr(mod, "cvar"): + cv = getattr(mod, "cvar") + entries = [] + if cv: + if modname in self.cvars_entries.keys(): + entries = self.cvars_entries[modname] + else: + # Parse 'str' version of cvar. Although this is braindeader than + # braindead, I'm not sure there's another way to do it. + entries_s = str(cv) + entries = entries_s[1:len(entries_s)-1].split(", ") + self.cvars_entries[modname] = entries + return cv, entries + + def __getattr__(self, attr): + for mod in self.modules: + cv, entries = self._get_module_cvar(mod) + if cv and attr in entries: + return getattr(cv, attr) + + def __setattr__(self, attr, value): + for mod in self.modules: + cv, entries = self._get_module_cvar(mod) + if cv and attr in entries: + setattr(cv, attr, value) + + +cvar = idaapi_Cvar() diff --git a/python/idautils.py b/python/idautils.py old mode 100644 new mode 100755 index 65baa5f..91bd75f --- a/python/idautils.py +++ b/python/idautils.py @@ -11,7 +11,22 @@ """ idautils.py - High level utility functions for IDA """ -import idaapi +import ida_bytes +import ida_dbg +import ida_entry +import ida_funcs +import ida_ida +import ida_idaapi +import ida_idd +import ida_idp +import ida_kernwin +import ida_loader +import ida_nalt +import ida_name +import ida_segment +import ida_strlist +import ida_ua +import ida_xref import idc import types import os @@ -22,7 +37,7 @@ def refs(ea, funcfirst, funcnext): Generic reference collector - INTERNAL USE ONLY. """ ref = funcfirst(ea) - while ref != idaapi.BADADDR: + while ref != ida_idaapi.BADADDR: yield ref ref = funcnext(ea, ref) @@ -43,9 +58,9 @@ def CodeRefsTo(ea, flow): print ref """ if flow == 1: - return refs(ea, idaapi.get_first_cref_to, idaapi.get_next_cref_to) + return refs(ea, ida_xref.get_first_cref_to, ida_xref.get_next_cref_to) else: - return refs(ea, idaapi.get_first_fcref_to, idaapi.get_next_fcref_to) + return refs(ea, ida_xref.get_first_fcref_to, ida_xref.get_next_fcref_to) def CodeRefsFrom(ea, flow): @@ -64,9 +79,9 @@ def CodeRefsFrom(ea, flow): print ref """ if flow == 1: - return refs(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from) + return refs(ea, ida_xref.get_first_cref_from, ida_xref.get_next_cref_from) else: - return refs(ea, idaapi.get_first_fcref_from, idaapi.get_next_fcref_from) + return refs(ea, ida_xref.get_first_fcref_from, ida_xref.get_next_fcref_from) def DataRefsTo(ea): @@ -82,7 +97,7 @@ def DataRefsTo(ea): for ref in DataRefsTo(ScreenEA()): print ref """ - return refs(ea, idaapi.get_first_dref_to, idaapi.get_next_dref_to) + return refs(ea, ida_xref.get_first_dref_to, ida_xref.get_next_dref_to) def DataRefsFrom(ea): @@ -98,7 +113,7 @@ def DataRefsFrom(ea): for ref in DataRefsFrom(ScreenEA()): print ref """ - return refs(ea, idaapi.get_first_dref_from, idaapi.get_next_dref_from) + return refs(ea, ida_xref.get_first_dref_from, ida_xref.get_next_dref_from) def XrefTypeName(typecode): @@ -141,14 +156,14 @@ def XrefsFrom(ea, flags=0): Return all references from address 'ea' @param ea: Reference address - @param flags: any of idaapi.XREF_* flags + @param flags: any of ida_xref.XREF_* flags Example:: for xref in XrefsFrom(here(), 0): print xref.type, XrefTypeName(xref.type), \ 'from', hex(xref.frm), 'to', hex(xref.to) """ - xref = idaapi.xrefblk_t() + xref = ida_xref.xrefblk_t() if xref.first_from(ea, flags): yield _copy_xref(xref) while xref.next_from(): @@ -160,14 +175,14 @@ def XrefsTo(ea, flags=0): Return all references to address 'ea' @param ea: Reference address - @param flags: any of idaapi.XREF_* flags + @param flags: any of ida_xref.XREF_* flags Example:: for xref in XrefsTo(here(), 0): print xref.type, XrefTypeName(xref.type), \ 'from', hex(xref.frm), 'to', hex(xref.to) """ - xref = idaapi.xrefblk_t() + xref = ida_xref.xrefblk_t() if xref.first_to(ea, flags): yield _copy_xref(xref) while xref.next_to(): @@ -189,15 +204,15 @@ def Heads(start=None, end=None): @return: list of heads between start and end """ - if not start: start = idaapi.cvar.inf.minEA - if not end: end = idaapi.cvar.inf.maxEA + if not start: start = ida_ida.cvar.inf.minEA + if not end: end = ida_ida.cvar.inf.maxEA ea = start if not idc.isHead(idc.GetFlags(ea)): - ea = idaapi.next_head(ea, end) - while ea != idaapi.BADADDR: + ea = ida_bytes.next_head(ea, end) + while ea != ida_idaapi.BADADDR: yield ea - ea = idaapi.next_head(ea, end) + ea = ida_bytes.next_head(ea, end) def Functions(start=None, end=None): @@ -214,21 +229,21 @@ def Functions(start=None, end=None): in multiple segments will be reported multiple times, once in each segment as they are listed. """ - if not start: start = idaapi.cvar.inf.minEA - if not end: end = idaapi.cvar.inf.maxEA + if not start: start = ida_ida.cvar.inf.minEA + if not end: end = ida_ida.cvar.inf.maxEA # find first function head chunk in the range - chunk = idaapi.get_fchunk(start) + chunk = ida_funcs.get_fchunk(start) if not chunk: - chunk = idaapi.get_next_fchunk(start) - while chunk and chunk.startEA < end and (chunk.flags & idaapi.FUNC_TAIL) != 0: - chunk = idaapi.get_next_fchunk(chunk.startEA) + chunk = ida_funcs.get_next_fchunk(start) + while chunk and chunk.startEA < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: + chunk = ida_funcs.get_next_fchunk(chunk.startEA) func = chunk while func and func.startEA < end: startea = func.startEA yield startea - func = idaapi.get_next_func(startea) + func = ida_funcs.get_next_func(startea) def Chunks(start): @@ -240,7 +255,7 @@ def Chunks(start): @return: list of funcion chunks (tuples of the form (start_ea, end_ea)) belonging to the function """ - func_iter = idaapi.func_tail_iterator_t( idaapi.get_func( start ) ) + func_iter = ida_funcs.func_tail_iterator_t( ida_funcs.get_func( start ) ) status = func_iter.main() while status: chunk = func_iter.chunk() @@ -252,11 +267,11 @@ def Modules(): """ Returns a list of module objects with name,size,base and the rebase_to attributes """ - mod = idaapi.module_info_t() - result = idaapi.get_first_module(mod) + mod = ida_idd.module_info_t() + result = ida_dbg.get_first_module(mod) while result: - yield idaapi.object_t(name=mod.name, size=mod.size, base=mod.base, rebase_to=mod.rebase_to) - result = idaapi.get_next_module(mod) + yield ida_idaapi.object_t(name=mod.name, size=mod.size, base=mod.base, rebase_to=mod.rebase_to) + result = ida_dbg.get_next_module(mod) def Names(): @@ -265,9 +280,9 @@ def Names(): @return: List of tuples (ea, name) """ - for i in xrange(idaapi.get_nlist_size()): - ea = idaapi.get_nlist_ea(i) - name = idaapi.get_nlist_name(i) + for i in xrange(ida_name.get_nlist_size()): + ea = ida_name.get_nlist_ea(i) + name = ida_name.get_nlist_name(i) yield (ea, name) @@ -277,8 +292,8 @@ def Segments(): @return: List of segment start addresses. """ - for n in xrange(idaapi.get_segm_qty()): - seg = idaapi.getnseg(n) + for n in xrange(ida_segment.get_segm_qty()): + seg = ida_segment.getnseg(n) if seg: yield seg.startEA @@ -289,11 +304,11 @@ def Entries(): @return: List of tuples (index, ordinal, ea, name) """ - n = idaapi.get_entry_qty() + n = ida_entry.get_entry_qty() for i in xrange(0, n): - ordinal = idaapi.get_entry_ordinal(i) - ea = idaapi.get_entry(ordinal) - name = idaapi.get_entry_name(ordinal) + ordinal = ida_entry.get_entry_ordinal(i) + ea = ida_entry.get_entry(ordinal) + name = ida_entry.get_entry_name(ordinal) yield (i, ordinal, ea, name) @@ -305,10 +320,10 @@ def FuncItems(start): @return: ea of each item in the function """ - func = idaapi.get_func(start) + func = ida_funcs.get_func(start) if not func: return - fii = idaapi.func_item_iterator_t() + fii = ida_funcs.func_item_iterator_t() ok = fii.set(func) while ok: yield fii.current() @@ -322,7 +337,7 @@ def Structs(): @return: List of tuples (idx, sid, name) """ idx = idc.GetFirstStrucIdx() - while idx != idaapi.BADADDR: + while idx != ida_idaapi.BADADDR: sid = idc.GetStrucId(idx) yield (idx, sid, idc.GetStrucName(sid)) idx = idc.GetNextStrucIdx(idx) @@ -344,7 +359,7 @@ def StructMembers(sid): m = idc.GetFirstMember(sid) if m == -1: raise Exception("No structure with ID: 0x%x" % sid) - while (m != idaapi.BADADDR): + while (m != ida_idaapi.BADADDR): name = idc.GetMemberName(sid, m) if name: yield (m, name, idc.GetMemberSize(sid, m)) @@ -359,11 +374,11 @@ def DecodePrecedingInstruction(ea): @return: (None or the decode instruction, farref) farref will contain 'true' if followed an xref, false otherwise """ - prev_addr, farref = idaapi.decode_preceding_insn(ea) - if prev_addr == idaapi.BADADDR: + prev_addr, farref = ida_ua.decode_preceding_insn(ea) + if prev_addr == ida_idaapi.BADADDR: return (None, False) else: - return (idaapi.cmd.copy(), farref) + return (ida_ua.cmd.copy(), farref) @@ -374,11 +389,11 @@ def DecodePreviousInstruction(ea): @param ea: address to decode @return: None or a new insn_t instance """ - prev_addr = idaapi.decode_prev_insn(ea) - if prev_addr == idaapi.BADADDR: + prev_addr = ida_ua.decode_prev_insn(ea) + if prev_addr == ida_idaapi.BADADDR: return None - return idaapi.cmd.copy() + return ida_ua.cmd.copy() def DecodeInstruction(ea): @@ -388,11 +403,11 @@ def DecodeInstruction(ea): @param ea: address to decode @return: None or a new insn_t instance """ - inslen = idaapi.decode_insn(ea) + inslen = ida_ua.decode_insn(ea) if inslen == 0: return None - return idaapi.cmd.copy() + return ida_ua.cmd.copy() def GetDataList(ea, count, itemsize=1): @@ -400,13 +415,13 @@ def GetDataList(ea, count, itemsize=1): Get data list - INTERNAL USE ONLY """ if itemsize == 1: - getdata = idaapi.get_byte + getdata = ida_bytes.get_byte elif itemsize == 2: - getdata = idaapi.get_word + getdata = ida_bytes.get_word elif itemsize == 4: - getdata = idaapi.get_long + getdata = ida_bytes.get_long elif itemsize == 8: - getdata = idaapi.get_qword + getdata = ida_bytes.get_qword else: raise ValueError, "Invalid data size! Must be 1, 2, 4 or 8" @@ -424,11 +439,11 @@ def PutDataList(ea, datalist, itemsize=1): putdata = None if itemsize == 1: - putdata = idaapi.patch_byte + putdata = ida_bytes.patch_byte if itemsize == 2: - putdata = idaapi.patch_word + putdata = ida_bytes.patch_word if itemsize == 4: - putdata = idaapi.patch_long + putdata = ida_bytes.patch_long assert putdata, "Invalid data size! Must be 1, 2 or 4" @@ -488,22 +503,22 @@ class Strings(object): return not self.is_2_bytes_encoding() and not self.is_4_bytes_encoding() def is_2_bytes_encoding(self): - return (self.type & 7) in [idaapi.ASCSTR_UTF16, idaapi.ASCSTR_ULEN2, idaapi.ASCSTR_ULEN4] + return (self.type & 7) in [ida_nalt.ASCSTR_UTF16, ida_nalt.ASCSTR_ULEN2, ida_nalt.ASCSTR_ULEN4] def is_4_bytes_encoding(self): - return (self.type & 7) == idaapi.ASCSTR_UTF32 + return (self.type & 7) == ida_nalt.ASCSTR_UTF32 def _toseq(self, as_unicode): if self.is_2_bytes_encoding(): - conv = idaapi.ACFOPT_UTF16 + conv = ida_bytes.ACFOPT_UTF16 pyenc = "utf-16" elif self.is_4_bytes_encoding(): - conv = idaapi.ACFOPT_UTF8 + conv = ida_bytes.ACFOPT_UTF8 pyenc = "utf-8" else: - conv = idaapi.ACFOPT_ASCII + conv = ida_bytes.ACFOPT_ASCII pyenc = 'ascii' - strbytes = idaapi.get_ascii_contents2(self.ea, self.length, self.type, conv) + strbytes = ida_bytes.get_ascii_contents2(self.ea, self.length, self.type, conv) return unicode(strbytes, pyenc, 'replace') if as_unicode else strbytes def __str__(self): @@ -544,17 +559,17 @@ class Strings(object): else: self.refresh() - self._si = idaapi.string_info_t() + self._si = ida_strlist.string_info_t() def refresh(self, ea1=None, ea2=None): """Refreshes the strings list""" if ea1 is None: - ea1 = idaapi.cvar.inf.minEA + ea1 = ida_ida.cvar.inf.minEA if ea2 is None: - ea2 = idaapi.cvar.inf.maxEA + ea2 = ida_ida.cvar.inf.maxEA - idaapi.refresh_strlist(ea1, ea2) - self.size = idaapi.get_strlist_qty() + ida_strlist.refresh_strlist(ea1, ea2) + self.size = ida_strlist.get_strlist_qty() def setup(self, @@ -567,26 +582,26 @@ class Strings(object): display_only_existing_strings = False): if ea1 is None: - ea1 = idaapi.cvar.inf.minEA + ea1 = ida_ida.cvar.inf.minEA if ea2 is None: - ea2 = idaapi.cvar.inf.maxEA + ea2 = ida_ida.cvar.inf.maxEA - t = idaapi.strwinsetup_t() + t = ida_strlist.strwinsetup_t() t.strtypes = strtypes t.minlen = minlen t.only_7bit = only_7bit t.ea1 = ea1 t.ea2 = ea2 t.display_only_existing_strings = display_only_existing_strings - idaapi.set_strlist_options(t) + ida_strlist.set_strlist_options(t) # Automatically refreshes self.refresh() def _get_item(self, index): - if not idaapi.get_strlist_item(index, self._si): + if not ida_strlist.get_strlist_item(index, self._si): return None else: return Strings.StringItem(self._si) @@ -610,17 +625,17 @@ def GetIdbDir(): This function returns directory path of the current IDB database """ - return os.path.dirname(idaapi.cvar.database_idb) + os.sep + return os.path.dirname(ida_loader.cvar.database_idb) + os.sep # ----------------------------------------------------------------------- def GetRegisterList(): """Returns the register list""" - return idaapi.ph_get_regnames() + return ida_idp.ph_get_regnames() # ----------------------------------------------------------------------- def GetInstructionList(): """Returns the instruction list of the current processor module""" - return [i[0] for i in idaapi.ph_get_instruc() if i[0]] + return [i[0] for i in ida_idp.ph_get_instruc() if i[0]] # ----------------------------------------------------------------------- def _Assemble(ea, line): @@ -633,11 +648,11 @@ def _Assemble(ea, line): lines = line ret = [] for line in lines: - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return (False, "No segment at ea") - ip = ea - (idaapi.ask_selector(seg.sel) << 4) - buf = idaapi.AssembleLine(ea, seg.sel, ip, seg.bitness, line) + ip = ea - (ida_segment.ask_selector(seg.sel) << 4) + buf = ida_idp.AssembleLine(ea, seg.sel, ip, seg.bitness, line) if not buf: return (False, "Assembler failed: " + line) ea += len(buf) @@ -705,10 +720,10 @@ class _reg_dtyp_t(object): class _procregs(object): """Utility class allowing the users to identify registers in a decoded instruction""" def __getattr__(self, attr): - ri = idaapi.reg_info_t() - if not idaapi.parse_reg_name(attr, ri): + ri = ida_idp.reg_info_t() + if not ida_idp.parse_reg_name(attr, ri): raise AttributeError() - r = _reg_dtyp_t(ri.reg, ord(idaapi.get_dtyp_by_size(ri.size))) + r = _reg_dtyp_t(ri.reg, ord(ida_ua.get_dtyp_by_size(ri.size))) self.__dict__[attr] = r return r @@ -754,7 +769,7 @@ class __process_ui_actions_helper(object): return False # Execute one action - idaapi.process_ui_action( + ida_kernwin.process_ui_action( self.__action_list[self.__idx], self.__flags) @@ -775,7 +790,7 @@ def ProcessUiActions(actions, flags=0): # Instantiate a helper helper = __process_ui_actions_helper(actions, flags) - return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,)) + return False if len(helper) < 1 else ida_kernwin.execute_ui_requests((helper,)) # ----------------------------------------------------------------------- @@ -786,15 +801,15 @@ class peutils_t(object): Constants from pe.h """ PE_NODE = "$ PE header" # netnode name for PE header - PE_ALT_DBG_FPOS = idaapi.BADADDR & -1 # altval() -> translated fpos of debuginfo - PE_ALT_IMAGEBASE = idaapi.BADADDR & -2 # altval() -> loading address (usually pe.imagebase) - PE_ALT_PEHDR_OFF = idaapi.BADADDR & -3 # altval() -> offset of PE header - PE_ALT_NEFLAGS = idaapi.BADADDR & -4 # altval() -> neflags - PE_ALT_TDS_LOADED = idaapi.BADADDR & -5 # altval() -> tds already loaded(1) or invalid(-1) - PE_ALT_PSXDLL = idaapi.BADADDR & -6 # altval() -> if POSIX(x86) imports from PSXDLL netnode + PE_ALT_DBG_FPOS = ida_idaapi.BADADDR & -1 # altval() -> translated fpos of debuginfo + PE_ALT_IMAGEBASE = ida_idaapi.BADADDR & -2 # altval() -> loading address (usually pe.imagebase) + PE_ALT_PEHDR_OFF = ida_idaapi.BADADDR & -3 # altval() -> offset of PE header + PE_ALT_NEFLAGS = ida_idaapi.BADADDR & -4 # altval() -> neflags + PE_ALT_TDS_LOADED = ida_idaapi.BADADDR & -5 # altval() -> tds already loaded(1) or invalid(-1) + PE_ALT_PSXDLL = ida_idaapi.BADADDR & -6 # altval() -> if POSIX(x86) imports from PSXDLL netnode def __init__(self): - self.__penode = idaapi.netnode() + self.__penode = ida_netnode.netnode() self.__penode.create(peutils_t.PE_NODE) imagebase = property( diff --git a/python/idc.py b/python/idc.py old mode 100644 new mode 100755 index e2be3d1..c0fe5bf --- a/python/idc.py +++ b/python/idc.py @@ -27,10 +27,40 @@ SetFlags() function is strongly discouraged. This file is subject to change without any notice. Future versions of IDA may use other definitions. """ -try: - import idaapi -except ImportError: - print "Could not import idaapi. Running in 'pydoc mode'." +# FIXME: Perhaps those should be loaded on-demand +import ida_idaapi +import ida_auto +import ida_dbg +import ida_diskio +import ida_entry +import ida_enum +import ida_expr +import ida_fixup +import ida_frame +import ida_funcs +import ida_funcs +import ida_gdl +import ida_ida +import ida_bytes +import ida_idd +import ida_idp +import ida_kernwin +import ida_lines +import ida_loader +import ida_nalt +import ida_name +import ida_netnode +import ida_offset +import ida_pro +import ida_search +import ida_segment +import ida_srarea +import ida_struct +import ida_typeinf +import ida_ua +import ida_xref + +import _ida_idaapi import os import re @@ -38,7 +68,7 @@ import struct import time import types -__EA64__ = idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL +__EA64__ = ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL WORDMASK = 0xFFFFFFFFFFFFFFFF if __EA64__ else 0xFFFFFFFF class DeprecatedIDCError(Exception): """ @@ -74,15 +104,15 @@ def _IDC_SetAttr(obj, attrmap, attroffs, value): raise KeyError, errormsg -BADADDR = idaapi.BADADDR # Not allowed address value -BADSEL = idaapi.BADSEL # Not allowed selector value/number -MAXADDR = idaapi.MAXADDR & WORDMASK -SIZE_MAX = idaapi.SIZE_MAX +BADADDR = ida_idaapi.BADADDR # Not allowed address value +BADSEL = ida_idaapi.BADSEL # Not allowed selector value/number +MAXADDR = ida_ida.MAXADDR & WORDMASK +SIZE_MAX = _ida_idaapi.SIZE_MAX # # Flag bit definitions (for GetFlags()) # -MS_VAL = idaapi.MS_VAL # Mask for byte value -FF_IVL = idaapi.FF_IVL # Byte has value ? +MS_VAL = ida_bytes.MS_VAL # Mask for byte value +FF_IVL = ida_bytes.FF_IVL # Byte has value ? # Do flags contain byte value? (i.e. has the byte a value?) # if not, the byte is uninitialized. @@ -102,11 +132,11 @@ def isLoaded(ea): """Is the byte initialized?""" return hasValue(GetFlags(ea)) # any defined value? -MS_CLS = idaapi.MS_CLS # Mask for typing -FF_CODE = idaapi.FF_CODE # Code ? -FF_DATA = idaapi.FF_DATA # Data ? -FF_TAIL = idaapi.FF_TAIL # Tail ? -FF_UNK = idaapi.FF_UNK # Unknown ? +MS_CLS = ida_bytes.MS_CLS # Mask for typing +FF_CODE = ida_bytes.FF_CODE # Code ? +FF_DATA = ida_bytes.FF_DATA # Data ? +FF_TAIL = ida_bytes.FF_TAIL # Tail ? +FF_UNK = ida_bytes.FF_UNK # Unknown ? def isCode(F): return ((F & MS_CLS) == FF_CODE) # is code byte? def isData(F): return ((F & MS_CLS) == FF_DATA) # is data byte? @@ -117,14 +147,14 @@ def isHead(F): return ((F & FF_DATA) != 0) # is start of code/data? # # Common bits # -MS_COMM = idaapi.MS_COMM # Mask of common bits -FF_COMM = idaapi.FF_COMM # Has comment? -FF_REF = idaapi.FF_REF # has references? -FF_LINE = idaapi.FF_LINE # Has next or prev cmt lines ? -FF_NAME = idaapi.FF_NAME # Has user-defined name ? -FF_LABL = idaapi.FF_LABL # Has dummy name? -FF_FLOW = idaapi.FF_FLOW # Exec flow from prev instruction? -FF_VAR = idaapi.FF_VAR # Is byte variable ? +MS_COMM = ida_bytes.MS_COMM # Mask of common bits +FF_COMM = ida_bytes.FF_COMM # Has comment? +FF_REF = ida_bytes.FF_REF # has references? +FF_LINE = ida_bytes.FF_LINE # Has next or prev cmt lines ? +FF_NAME = ida_bytes.FF_NAME # Has user-defined name ? +FF_LABL = ida_bytes.FF_LABL # Has dummy name? +FF_FLOW = ida_bytes.FF_FLOW # Exec flow from prev instruction? +FF_VAR = ida_bytes.FF_VAR # Is byte variable ? FF_ANYNAME = FF_LABL | FF_NAME def isFlow(F): return ((F & FF_FLOW) != 0) @@ -134,33 +164,33 @@ def isRef(F): return ((F & FF_REF) != 0) def hasName(F): return ((F & FF_NAME) != 0) def hasUserName(F): return ((F & FF_ANYNAME) == FF_NAME) -MS_0TYPE = idaapi.MS_0TYPE # Mask for 1st arg typing -FF_0VOID = idaapi.FF_0VOID # Void (unknown)? -FF_0NUMH = idaapi.FF_0NUMH # Hexadecimal number? -FF_0NUMD = idaapi.FF_0NUMD # Decimal number? -FF_0CHAR = idaapi.FF_0CHAR # Char ('x')? -FF_0SEG = idaapi.FF_0SEG # Segment? -FF_0OFF = idaapi.FF_0OFF # Offset? -FF_0NUMB = idaapi.FF_0NUMB # Binary number? -FF_0NUMO = idaapi.FF_0NUMO # Octal number? -FF_0ENUM = idaapi.FF_0ENUM # Enumeration? -FF_0FOP = idaapi.FF_0FOP # Forced operand? -FF_0STRO = idaapi.FF_0STRO # Struct offset? -FF_0STK = idaapi.FF_0STK # Stack variable? +MS_0TYPE = ida_bytes.MS_0TYPE # Mask for 1st arg typing +FF_0VOID = ida_bytes.FF_0VOID # Void (unknown)? +FF_0NUMH = ida_bytes.FF_0NUMH # Hexadecimal number? +FF_0NUMD = ida_bytes.FF_0NUMD # Decimal number? +FF_0CHAR = ida_bytes.FF_0CHAR # Char ('x')? +FF_0SEG = ida_bytes.FF_0SEG # Segment? +FF_0OFF = ida_bytes.FF_0OFF # Offset? +FF_0NUMB = ida_bytes.FF_0NUMB # Binary number? +FF_0NUMO = ida_bytes.FF_0NUMO # Octal number? +FF_0ENUM = ida_bytes.FF_0ENUM # Enumeration? +FF_0FOP = ida_bytes.FF_0FOP # Forced operand? +FF_0STRO = ida_bytes.FF_0STRO # Struct offset? +FF_0STK = ida_bytes.FF_0STK # Stack variable? -MS_1TYPE = idaapi.MS_1TYPE # Mask for 2nd arg typing -FF_1VOID = idaapi.FF_1VOID # Void (unknown)? -FF_1NUMH = idaapi.FF_1NUMH # Hexadecimal number? -FF_1NUMD = idaapi.FF_1NUMD # Decimal number? -FF_1CHAR = idaapi.FF_1CHAR # Char ('x')? -FF_1SEG = idaapi.FF_1SEG # Segment? -FF_1OFF = idaapi.FF_1OFF # Offset? -FF_1NUMB = idaapi.FF_1NUMB # Binary number? -FF_1NUMO = idaapi.FF_1NUMO # Octal number? -FF_1ENUM = idaapi.FF_1ENUM # Enumeration? -FF_1FOP = idaapi.FF_1FOP # Forced operand? -FF_1STRO = idaapi.FF_1STRO # Struct offset? -FF_1STK = idaapi.FF_1STK # Stack variable? +MS_1TYPE = ida_bytes.MS_1TYPE # Mask for 2nd arg typing +FF_1VOID = ida_bytes.FF_1VOID # Void (unknown)? +FF_1NUMH = ida_bytes.FF_1NUMH # Hexadecimal number? +FF_1NUMD = ida_bytes.FF_1NUMD # Decimal number? +FF_1CHAR = ida_bytes.FF_1CHAR # Char ('x')? +FF_1SEG = ida_bytes.FF_1SEG # Segment? +FF_1OFF = ida_bytes.FF_1OFF # Offset? +FF_1NUMB = ida_bytes.FF_1NUMB # Binary number? +FF_1NUMO = ida_bytes.FF_1NUMO # Octal number? +FF_1ENUM = ida_bytes.FF_1ENUM # Enumeration? +FF_1FOP = ida_bytes.FF_1FOP # Forced operand? +FF_1STRO = ida_bytes.FF_1STRO # Struct offset? +FF_1STK = ida_bytes.FF_1STK # Stack variable? # The following macros answer questions like # 'is the 1st (or 2nd) operand of instruction or data of the given type'? @@ -194,20 +224,20 @@ def isStkvar1(F): return ((F & MS_1TYPE) == FF_1STK) # # Bits for DATA bytes # -DT_TYPE = idaapi.DT_TYPE & 0xFFFFFFFF # Mask for DATA typing +DT_TYPE = ida_bytes.DT_TYPE & 0xFFFFFFFF # Mask for DATA typing -FF_BYTE = idaapi.FF_BYTE & 0xFFFFFFFF # byte -FF_WORD = idaapi.FF_WORD & 0xFFFFFFFF # word -FF_DWRD = idaapi.FF_DWRD & 0xFFFFFFFF # dword -FF_QWRD = idaapi.FF_QWRD & 0xFFFFFFFF # qword -FF_TBYT = idaapi.FF_TBYT & 0xFFFFFFFF # tbyte -FF_ASCI = idaapi.FF_ASCI & 0xFFFFFFFF # ASCII ? -FF_STRU = idaapi.FF_STRU & 0xFFFFFFFF # Struct ? -FF_OWRD = idaapi.FF_OWRD & 0xFFFFFFFF # octaword (16 bytes) -FF_FLOAT = idaapi.FF_FLOAT & 0xFFFFFFFF # float -FF_DOUBLE = idaapi.FF_DOUBLE & 0xFFFFFFFF # double -FF_PACKREAL = idaapi.FF_PACKREAL & 0xFFFFFFFF # packed decimal real -FF_ALIGN = idaapi.FF_ALIGN & 0xFFFFFFFF # alignment directive +FF_BYTE = ida_bytes.FF_BYTE & 0xFFFFFFFF # byte +FF_WORD = ida_bytes.FF_WORD & 0xFFFFFFFF # word +FF_DWRD = ida_bytes.FF_DWRD & 0xFFFFFFFF # dword +FF_QWRD = ida_bytes.FF_QWRD & 0xFFFFFFFF # qword +FF_TBYT = ida_bytes.FF_TBYT & 0xFFFFFFFF # tbyte +FF_ASCI = ida_bytes.FF_ASCI & 0xFFFFFFFF # ASCII ? +FF_STRU = ida_bytes.FF_STRU & 0xFFFFFFFF # Struct ? +FF_OWRD = ida_bytes.FF_OWRD & 0xFFFFFFFF # octaword (16 bytes) +FF_FLOAT = ida_bytes.FF_FLOAT & 0xFFFFFFFF # float +FF_DOUBLE = ida_bytes.FF_DOUBLE & 0xFFFFFFFF # double +FF_PACKREAL = ida_bytes.FF_PACKREAL & 0xFFFFFFFF # packed decimal real +FF_ALIGN = ida_bytes.FF_ALIGN & 0xFFFFFFFF # alignment directive def isByte(F): return (isData(F) and (F & DT_TYPE) == FF_BYTE) def isWord(F): return (isData(F) and (F & DT_TYPE) == FF_WORD) @@ -225,24 +255,24 @@ def isAlign(F): return (isData(F) and (F & DT_TYPE) == FF_ALIGN) # # Bits for CODE bytes # -MS_CODE = idaapi.MS_CODE & 0xFFFFFFFF -FF_FUNC = idaapi.FF_FUNC & 0xFFFFFFFF # function start? -FF_IMMD = idaapi.FF_IMMD & 0xFFFFFFFF # Has Immediate value ? -FF_JUMP = idaapi.FF_JUMP & 0xFFFFFFFF # Has jump table +MS_CODE = ida_bytes.MS_CODE & 0xFFFFFFFF +FF_FUNC = ida_bytes.FF_FUNC & 0xFFFFFFFF # function start? +FF_IMMD = ida_bytes.FF_IMMD & 0xFFFFFFFF # Has Immediate value ? +FF_JUMP = ida_bytes.FF_JUMP & 0xFFFFFFFF # Has jump table # # Loader flags # -NEF_SEGS = idaapi.NEF_SEGS # Create segments -NEF_RSCS = idaapi.NEF_RSCS # Load resources -NEF_NAME = idaapi.NEF_NAME # Rename entries -NEF_MAN = idaapi.NEF_MAN # Manual load -NEF_FILL = idaapi.NEF_FILL # Fill segment gaps -NEF_IMPS = idaapi.NEF_IMPS # Create imports section -NEF_FIRST = idaapi.NEF_FIRST # This is the first file loaded -NEF_CODE = idaapi.NEF_CODE # for load_binary_file: -NEF_RELOAD = idaapi.NEF_RELOAD # reload the file at the same place: -NEF_FLAT = idaapi.NEF_FLAT # Autocreated FLAT group (PE) +NEF_SEGS = ida_loader.NEF_SEGS # Create segments +NEF_RSCS = ida_loader.NEF_RSCS # Load resources +NEF_NAME = ida_loader.NEF_NAME # Rename entries +NEF_MAN = ida_loader.NEF_MAN # Manual load +NEF_FILL = ida_loader.NEF_FILL # Fill segment gaps +NEF_IMPS = ida_loader.NEF_IMPS # Create imports section +NEF_FIRST = ida_loader.NEF_FIRST # This is the first file loaded +NEF_CODE = ida_loader.NEF_CODE # for load_binary_file: +NEF_RELOAD = ida_loader.NEF_RELOAD # reload the file at the same place: +NEF_FLAT = ida_loader.NEF_FLAT # Autocreated FLAT group (PE) # List of built-in functions # -------------------------- @@ -366,7 +396,7 @@ def AddHotkey(hotkey, idcfunc): @return: None """ - return idaapi.add_idc_hotkey(hotkey, idcfunc) + return ida_kernwin.add_idc_hotkey(hotkey, idcfunc) def DelHotkey(hotkey): @@ -375,7 +405,7 @@ def DelHotkey(hotkey): @param hotkey: hotkey code to delete """ - return idaapi.del_idc_hotkey(hotkey) + return ida_kernwin.del_idc_hotkey(hotkey) def Jump(ea): @@ -384,7 +414,7 @@ def Jump(ea): @param ea: linear address """ - return idaapi.jumpto(ea) + return ida_kernwin.jumpto(ea) def Wait(): @@ -395,7 +425,7 @@ def Wait(): @note: This function will suspend execution of the calling script till the autoanalysis queue is empty. """ - return idaapi.autoWait() + return ida_auto.autoWait() def CompileEx(input, isfile): @@ -413,9 +443,9 @@ def CompileEx(input, isfile): @return: 0 - ok, otherwise it returns an error message """ if isfile: - res = idaapi.Compile(input) + res = ida_expr.Compile(input) else: - res = idaapi.CompileLine(input) + res = ida_expr.CompileLine(input) if res: return res @@ -434,9 +464,9 @@ def Eval(expr): @note: Python implementation evaluates IDC only, while IDC can call other registered languages """ - rv = idaapi.idc_value_t() + rv = ida_expr.idc_value_t() - err = idaapi.calc_idc_expr(BADADDR, expr, rv) + err = ida_expr.calc_idc_expr(BADADDR, expr, rv) if err: return "IDC_FAILURE: "+err else: @@ -467,26 +497,26 @@ def SaveBase(idbname, flags=0): @param idbname: name of the idb file. if empty, the current idb file will be used. - @param flags: combination of idaapi.DBFL_... bits or 0 + @param flags: combination of ida_loader.DBFL_... bits or 0 """ if len(idbname) == 0: idbname = GetIdbPath() - saveflags = idaapi.cvar.database_flags - mask = idaapi.DBFL_KILL | idaapi.DBFL_COMP | idaapi.DBFL_BAK - idaapi.cvar.database_flags &= ~mask - idaapi.cvar.database_flags |= flags & mask - res = idaapi.save_database(idbname, 0) - idaapi.cvar.database_flags = saveflags + saveflags = ida_loader.cvar.database_flags + mask = ida_loader.DBFL_KILL | ida_loader.DBFL_COMP | ida_loader.DBFL_BAK + ida_loader.cvar.database_flags &= ~mask + ida_loader.cvar.database_flags |= flags & mask + res = ida_loader.save_database(idbname, 0) + ida_loader.cvar.database_flags = saveflags return res -DBFL_BAK = idaapi.DBFL_BAK # for compatiblity with older versions, eventually delete this +DBFL_BAK = ida_loader.DBFL_BAK # for compatiblity with older versions, eventually delete this def ValidateNames(): """ check consistency of IDB name records @return: number of inconsistent name records """ - return idaapi.validate_idb_names() + return ida_nalt.validate_idb_names() def Exit(code): """ @@ -496,7 +526,7 @@ def Exit(code): @return: - """ - idaapi.qexit(code) + ida_pro.qexit(code) def Exec(command): @@ -535,7 +565,7 @@ def RunPlugin(name, arg): @return: 0 if could not load the plugin, 1 if ok """ - return idaapi.load_and_run_plugin(name, arg) + return ida_loader.load_and_run_plugin(name, arg) def ApplySig(name): @@ -546,7 +576,7 @@ def ApplySig(name): @return: 0 if could not load the signature file, !=0 otherwise """ - return idaapi.plan_to_apply_idasgn(name) + return ida_funcs.plan_to_apply_idasgn(name) #---------------------------------------------------------------------------- @@ -559,25 +589,25 @@ def DeleteAll(): Delete all segments, instructions, comments, i.e. everything except values of bytes. """ - ea = idaapi.cvar.inf.minEA + ea = ida_ida.cvar.inf.minEA # Brute-force nuke all info from all the heads - while ea != BADADDR and ea <= idaapi.cvar.inf.maxEA: - idaapi.del_local_name(ea) - idaapi.del_global_name(ea) - func = idaapi.get_func(ea) + while ea != BADADDR and ea <= ida_ida.cvar.inf.maxEA: + ida_name.del_local_name(ea) + ida_name.del_global_name(ea) + func = ida_funcs.get_func(ea) if func: - idaapi.del_func_cmt(func, False) - idaapi.del_func_cmt(func, True) - idaapi.del_func(ea) - idaapi.del_hidden_area(ea) - seg = idaapi.getseg(ea) + ida_funcs.del_func_cmt(func, False) + ida_funcs.del_func_cmt(func, True) + ida_funcs.del_func(ea) + ida_bytes.del_hidden_area(ea) + seg = ida_segment.getseg(ea) if seg: - idaapi.del_segment_cmt(seg, False) - idaapi.del_segment_cmt(seg, True) - idaapi.del_segm(ea, idaapi.SEGDEL_KEEP | idaapi.SEGDEL_SILENT) + ida_segment.del_segment_cmt(seg, False) + ida_segment.del_segment_cmt(seg, True) + ida_segment.del_segm(ea, ida_segment.SEGDEL_KEEP | ida_segment.SEGDEL_SILENT) - ea = idaapi.next_head(ea, idaapi.cvar.inf.maxEA) + ea = ida_bytes.next_head(ea, ida_ida.cvar.inf.maxEA) def MakeCode(ea): @@ -590,7 +620,7 @@ def MakeCode(ea): would overlap with existing items, etc) otherwise returns length of the instruction in bytes """ - return idaapi.create_insn(ea) + return ida_ua.create_insn(ea) def AnalyzeArea(sEA, eEA): @@ -602,7 +632,7 @@ def AnalyzeArea(sEA, eEA): @return: 1-ok, 0-Ctrl-Break was pressed. """ - return idaapi.analyze_area(sEA, eEA) + return ida_auto.analyze_area(sEA, eEA) def MakeNameEx(ea, name, flags): @@ -615,32 +645,32 @@ def MakeNameEx(ea, name, flags): @return: 1-ok, 0-failure """ - return idaapi.set_name(ea, name, flags) + return ida_name.set_name(ea, name, flags) -SN_CHECK = idaapi.SN_CHECK # Fail if the name contains invalid - # characters - # If this bit is clear, all invalid chars - # (those !is_ident_char()) will be replaced - # by SubstChar (usually '_') - # List of valid characters is defined in - # ida.cfg -SN_NOCHECK = idaapi.SN_NOCHECK # Replace invalid chars with SubstChar -SN_PUBLIC = idaapi.SN_PUBLIC # if set, make name public -SN_NON_PUBLIC = idaapi.SN_NON_PUBLIC # if set, make name non-public -SN_WEAK = idaapi.SN_WEAK # if set, make name weak -SN_NON_WEAK = idaapi.SN_NON_WEAK # if set, make name non-weak -SN_AUTO = idaapi.SN_AUTO # if set, make name autogenerated -SN_NON_AUTO = idaapi.SN_NON_AUTO # if set, make name non-autogenerated -SN_NOLIST = idaapi.SN_NOLIST # if set, exclude name from the list - # if not set, then include the name into - # the list (however, if other bits are set, - # the name might be immediately excluded - # from the list) -SN_NOWARN = idaapi.SN_NOWARN # don't display a warning if failed -SN_LOCAL = idaapi.SN_LOCAL # create local name. a function should exist. - # local names can't be public or weak. - # also they are not included into the list - # of names they can't have dummy prefixes +SN_CHECK = ida_name.SN_CHECK # Fail if the name contains invalid + # characters + # If this bit is clear, all invalid chars + # (those !is_ident_char()) will be replaced + # by SubstChar (usually '_') + # List of valid characters is defined in + # ida.cfg +SN_NOCHECK = ida_name.SN_NOCHECK # Replace invalid chars with SubstChar +SN_PUBLIC = ida_name.SN_PUBLIC # if set, make name public +SN_NON_PUBLIC = ida_name.SN_NON_PUBLIC # if set, make name non-public +SN_WEAK = ida_name.SN_WEAK # if set, make name weak +SN_NON_WEAK = ida_name.SN_NON_WEAK # if set, make name non-weak +SN_AUTO = ida_name.SN_AUTO # if set, make name autogenerated +SN_NON_AUTO = ida_name.SN_NON_AUTO # if set, make name non-autogenerated +SN_NOLIST = ida_name.SN_NOLIST # if set, exclude name from the list + # if not set, then include the name into + # the list (however, if other bits are set, + # the name might be immediately excluded + # from the list) +SN_NOWARN = ida_name.SN_NOWARN # don't display a warning if failed +SN_LOCAL = ida_name.SN_LOCAL # create local name. a function should exist. + # local names can't be public or weak. + # also they are not included into the list + # of names they can't have dummy prefixes def MakeComm(ea, comment): """ @@ -651,7 +681,7 @@ def MakeComm(ea, comment): @return: None """ - return idaapi.set_cmt(ea, comment, 0) + return ida_bytes.set_cmt(ea, comment, 0) def MakeRptCmt(ea, comment): @@ -663,7 +693,7 @@ def MakeRptCmt(ea, comment): @return: None """ - return idaapi.set_cmt(ea, comment, 1) + return ida_bytes.set_cmt(ea, comment, 1) def MakeArray(ea, nitems): @@ -677,24 +707,24 @@ def MakeArray(ea, nitems): the type of the item at 'ea'. If the byte at 'ea' is undefined, then this function will create an array of bytes. """ - flags = idaapi.getFlags(ea) + flags = ida_bytes.getFlags(ea) - if idaapi.isCode(flags) or idaapi.isTail(flags) or idaapi.isAlign(flags): + if ida_bytes.isCode(flags) or ida_bytes.isTail(flags) or ida_bytes.isAlign(flags): return False - if idaapi.isUnknown(flags): - flags = idaapi.FF_BYTE + if ida_bytes.isUnknown(flags): + flags = ida_bytes.FF_BYTE - if idaapi.isStruct(flags): - ti = idaapi.opinfo_t() - assert idaapi.get_opinfo(ea, 0, flags, ti), "get_opinfo() failed" - itemsize = idaapi.get_data_elsize(ea, flags, ti) + if ida_bytes.isStruct(flags): + ti = ida_nalt.opinfo_t() + assert ida_bytes.get_opinfo(ea, 0, flags, ti), "get_opinfo() failed" + itemsize = ida_bytes.get_data_elsize(ea, flags, ti) tid = ti.tid else: - itemsize = idaapi.get_item_size(ea) + itemsize = ida_bytes.get_item_size(ea) tid = BADADDR - return idaapi.do_data_ex(ea, flags, itemsize*nitems, tid) + return ida_bytes.do_data_ex(ea, flags, itemsize*nitems, tid) def MakeStr(ea, endea): @@ -713,7 +743,7 @@ def MakeStr(ea, endea): @note: The type of an existing string is returned by GetStringType() """ - return idaapi.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE)) + return ida_bytes.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE)) def MakeData(ea, flags, size, tid): @@ -727,7 +757,7 @@ def MakeData(ea, flags, size, tid): @return: 1-ok, 0-failure """ - return idaapi.do_data_ex(ea, flags, size, tid) + return ida_bytes.do_data_ex(ea, flags, size, tid) def MakeByte(ea): @@ -738,7 +768,7 @@ def MakeByte(ea): @return: 1-ok, 0-failure """ - return idaapi.doByte(ea, 1) + return ida_bytes.doByte(ea, 1) def MakeWord(ea): @@ -749,7 +779,7 @@ def MakeWord(ea): @return: 1-ok, 0-failure """ - return idaapi.doWord(ea, 2) + return ida_bytes.doWord(ea, 2) def MakeDword(ea): @@ -760,7 +790,7 @@ def MakeDword(ea): @return: 1-ok, 0-failure """ - return idaapi.doDwrd(ea, 4) + return ida_bytes.doDwrd(ea, 4) def MakeQword(ea): @@ -771,7 +801,7 @@ def MakeQword(ea): @return: 1-ok, 0-failure """ - return idaapi.doQwrd(ea, 8) + return ida_bytes.doQwrd(ea, 8) def MakeOword(ea): @@ -782,7 +812,7 @@ def MakeOword(ea): @return: 1-ok, 0-failure """ - return idaapi.doOwrd(ea, 16) + return ida_bytes.doOwrd(ea, 16) def MakeYword(ea): @@ -793,7 +823,7 @@ def MakeYword(ea): @return: 1-ok, 0-failure """ - return idaapi.doYwrd(ea, 32) + return ida_bytes.doYwrd(ea, 32) def MakeFloat(ea): @@ -804,7 +834,7 @@ def MakeFloat(ea): @return: 1-ok, 0-failure """ - return idaapi.doFloat(ea, 4) + return ida_bytes.doFloat(ea, 4) def MakeDouble(ea): @@ -815,7 +845,7 @@ def MakeDouble(ea): @return: 1-ok, 0-failure """ - return idaapi.doDouble(ea, 8) + return ida_bytes.doDouble(ea, 8) def MakePackReal(ea): @@ -826,7 +856,7 @@ def MakePackReal(ea): @return: 1-ok, 0-failure """ - return idaapi.doPackReal(ea, idaapi.ph_get_tbyte_size()) + return ida_bytes.doPackReal(ea, ida_idp.ph_get_tbyte_size()) def MakeTbyte(ea): @@ -837,7 +867,7 @@ def MakeTbyte(ea): @return: 1-ok, 0-failure """ - return idaapi.doTbyt(ea, idaapi.ph_get_tbyte_size()) + return ida_bytes.doTbyt(ea, ida_idp.ph_get_tbyte_size()) def MakeStructEx(ea, size, strname): @@ -851,12 +881,12 @@ def MakeStructEx(ea, size, strname): @return: 1-ok, 0-failure """ - strid = idaapi.get_struc_id(strname) + strid = ida_struct.get_struc_id(strname) if size == -1: - size = idaapi.get_struc_size(strid) + size = ida_struct.get_struc_size(strid) - return idaapi.doStruct(ea, size, strid) + return ida_bytes.doStruct(ea, size, strid) def MakeCustomDataEx(ea, size, dtid, fid): @@ -870,7 +900,7 @@ def MakeCustomDataEx(ea, size, dtid, fid): @return: 1-ok, 0-failure """ - return idaapi.doCustomData(ea, size, dtid, fid) + return ida_bytes.doCustomData(ea, size, dtid, fid) @@ -886,7 +916,7 @@ def MakeAlign(ea, count, align): @return: 1-ok, 0-failure """ - return idaapi.doAlign(ea, count, align) + return ida_bytes.doAlign(ea, count, align) def MakeLocal(start, end, location, name): @@ -906,7 +936,7 @@ def MakeLocal(start, end, location, name): If there is no function at 'start' then this function. will fail. """ - func = idaapi.get_func(start) + func = ida_funcs.get_func(start) if not func: return 0 @@ -917,35 +947,35 @@ def MakeLocal(start, end, location, name): if m: # Location in the form of [bp+xx] - register = idaapi.str2reg(m.group(1)) + register = ida_idp.str2reg(m.group(1)) offset = int(m.group(2), 0) - frame = idaapi.get_frame(func) + frame = ida_frame.get_frame(func) if register == -1 or not frame: return 0 offset += func.frsize - member = idaapi.get_member(frame, offset) + member = ida_struct.get_member(frame, offset) if member: # Member already exists, rename it - if idaapi.set_member_name(frame, offset, name): + if ida_struct.set_member_name(frame, offset, name): return 1 else: return 0 else: # No member at the offset, create a new one - if idaapi.add_struc_member(frame, - name, - offset, - idaapi.byteflag(), - None, 1) == 0: + if ida_struct.add_struc_member(frame, + name, + offset, + ida_bytes.byteflag(), + None, 1) == 0: return 1 else: return 0 else: # Location as simple register name - return idaapi.add_regvar(func, start, end, location, name, None) + return ida_frame.add_regvar(func, start, end, location, name, None) def MakeUnkn(ea, flags): @@ -957,7 +987,7 @@ def MakeUnkn(ea, flags): @return: None """ - return idaapi.do_unknown(ea, flags) + return ida_bytes.do_unknown(ea, flags) def MakeUnknown(ea, size, flags): @@ -970,16 +1000,16 @@ def MakeUnknown(ea, size, flags): @return: None """ - return idaapi.do_unknown_range(ea, size, flags) + return ida_bytes.do_unknown_range(ea, size, flags) -DOUNK_SIMPLE = idaapi.DOUNK_SIMPLE # simply undefine the specified item -DOUNK_EXPAND = idaapi.DOUNK_EXPAND # propogate undefined items, for example - # if removing an instruction removes all - # references to the next instruction, then - # plan to convert to unexplored the next - # instruction too. -DOUNK_DELNAMES = idaapi.DOUNK_DELNAMES # delete any names at the specified address(es) +DOUNK_SIMPLE = ida_bytes.DOUNK_SIMPLE # simply undefine the specified item +DOUNK_EXPAND = ida_bytes.DOUNK_EXPAND # propogate undefined items, for example + # if removing an instruction removes all + # references to the next instruction, then + # plan to convert to unexplored the next + # instruction too. +DOUNK_DELNAMES = ida_bytes.DOUNK_DELNAMES # delete any names at the specified address(es) def SetArrayFormat(ea, flags, litems, align): @@ -1022,7 +1052,7 @@ def OpBinary(ea, n): @note: the data items use only the type of the first operand """ - return idaapi.op_bin(ea, n) + return ida_bytes.op_bin(ea, n) def OpOctal(ea, n): @@ -1035,7 +1065,7 @@ def OpOctal(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_oct(ea, n) + return ida_bytes.op_oct(ea, n) def OpDecimal(ea, n): @@ -1048,7 +1078,7 @@ def OpDecimal(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_dec(ea, n) + return ida_bytes.op_dec(ea, n) def OpHex(ea, n): @@ -1061,7 +1091,7 @@ def OpHex(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_hex(ea, n) + return ida_bytes.op_hex(ea, n) def OpChr(ea, n): @@ -1072,7 +1102,7 @@ def OpChr(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_chr(ea, n) + return ida_bytes.op_chr(ea, n) def OpOff(ea, n, base): @@ -1114,10 +1144,10 @@ def OpOff(ea, n, base): @param base: base of the offset as a linear address If base == BADADDR then the current operand becomes non-offset """ - return idaapi.set_offset(ea, n, base) + return ida_offset.set_offset(ea, n, base) -OPND_OUTER = idaapi.OPND_OUTER # outer offset base +OPND_OUTER = ida_bytes.OPND_OUTER # outer offset base def OpOffEx(ea, n, reftype, target, base, tdelta): @@ -1148,19 +1178,19 @@ def OpOffEx(ea, n, reftype, target, base, tdelta): @return: success (boolean) """ - return idaapi.op_offset(ea, n, reftype, target, base, tdelta) + return ida_offset.op_offset(ea, n, reftype, target, base, tdelta) -REF_OFF8 = idaapi.REF_OFF8 # 8bit full offset -REF_OFF16 = idaapi.REF_OFF16 # 16bit full offset -REF_OFF32 = idaapi.REF_OFF32 # 32bit full offset -REF_LOW8 = idaapi.REF_LOW8 # low 8bits of 16bit offset -REF_LOW16 = idaapi.REF_LOW16 # low 16bits of 32bit offset -REF_HIGH8 = idaapi.REF_HIGH8 # high 8bits of 16bit offset -REF_HIGH16 = idaapi.REF_HIGH16 # high 16bits of 32bit offset -REF_VHIGH = idaapi.REF_VHIGH # high ph.high_fixup_bits of 32bit offset (processor dependent) -REF_VLOW = idaapi.REF_VLOW # low (32-ph.high_fixup_bits) of 32bit offset (processor dependent) -REF_OFF64 = idaapi.REF_OFF64 # 64bit full offset +REF_OFF8 = ida_nalt.REF_OFF8 # 8bit full offset +REF_OFF16 = ida_nalt.REF_OFF16 # 16bit full offset +REF_OFF32 = ida_nalt.REF_OFF32 # 32bit full offset +REF_LOW8 = ida_nalt.REF_LOW8 # low 8bits of 16bit offset +REF_LOW16 = ida_nalt.REF_LOW16 # low 16bits of 32bit offset +REF_HIGH8 = ida_nalt.REF_HIGH8 # high 8bits of 16bit offset +REF_HIGH16 = ida_nalt.REF_HIGH16 # high 16bits of 32bit offset +REF_VHIGH = ida_nalt.REF_VHIGH # high ph.high_fixup_bits of 32bit offset (processor dependent) +REF_VLOW = ida_nalt.REF_VLOW # low (32-ph.high_fixup_bits) of 32bit offset (processor dependent) +REF_OFF64 = ida_nalt.REF_OFF64 # 64bit full offset REFINFO_RVA = 0x10 # based reference (rva) REFINFO_PASTEND = 0x20 # reference past an item it may point to an nonexistitng # do not destroy alignment dirs @@ -1184,7 +1214,7 @@ def OpSeg(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_seg(ea, n) + return ida_bytes.op_seg(ea, n) def OpNumber(ea, n): @@ -1197,7 +1227,7 @@ def OpNumber(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_num(ea, n) + return ida_bytes.op_num(ea, n) def OpFloat(ea, n): @@ -1212,7 +1242,7 @@ def OpFloat(ea, n): @return: 1-ok, 0-failure """ - return idaapi.op_flt(ea, n) + return ida_bytes.op_flt(ea, n) def OpAlt(ea, n, opstr): @@ -1229,7 +1259,7 @@ def OpAlt(ea, n, opstr): @note: IDA will not check the specified operand, it will simply display it instead of the orginal representation of the operand. """ - return idaapi.set_forced_operand(ea, n, opstr) + return ida_bytes.set_forced_operand(ea, n, opstr) def OpSign(ea, n): @@ -1242,7 +1272,7 @@ def OpSign(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.toggle_sign(ea, n) + return ida_bytes.toggle_sign(ea, n) def OpNot(ea, n): @@ -1255,7 +1285,7 @@ def OpNot(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - idaapi.toggle_bnot(ea, n) + ida_bytes.toggle_bnot(ea, n) return True @@ -1277,7 +1307,7 @@ def OpEnumEx(ea, n, enumid, serial): There could be 256 symbolic constants with the same value in the enumeration. """ - return idaapi.op_enum(ea, n, enumid, serial) + return ida_bytes.op_enum(ea, n, enumid, serial) def OpStroffEx(ea, n, strid, delta): @@ -1294,9 +1324,9 @@ def OpStroffEx(ea, n, strid, delta): between the structure base and the pointer into the structure. """ - path = idaapi.tid_array(1) + path = ida_pro.tid_array(1) path[0] = strid - return idaapi.op_stroff(ea, n, path.cast(), 1, delta) + return ida_bytes.op_stroff(ea, n, path.cast(), 1, delta) def OpStkvar(ea, n): @@ -1309,7 +1339,7 @@ def OpStkvar(ea, n): - 1 - the second, third and all other operands - -1 - all operands """ - return idaapi.op_stkvar(ea, n) + return ida_bytes.op_stkvar(ea, n) def OpHigh(ea, n, target): @@ -1326,7 +1356,7 @@ def OpHigh(ea, n, target): - -1 - all operands @param target: the full value (all 32bits) of the offset """ - return idaapi.op_offset(ea, n, idaapi.REF_HIGH16, target) + return ida_offset.op_offset(ea, n, ida_nalt.REF_HIGH16, target) def MakeVar(ea): @@ -1341,7 +1371,7 @@ def MakeVar(ea): Nothing else, no additional analysis is performed. This function may disappear in the future. """ - idaapi.doVar(ea, 1) + ida_bytes.doVar(ea, 1) def ExtLinA(ea, n, line): @@ -1359,8 +1389,8 @@ def ExtLinA(ea, n, line): additional line #149, your line will not be displayed. MAX_ITEM_LINES is defined in IDA.CFG """ - idaapi.update_extra_cmt(ea, idaapi.E_PREV + n, line) - idaapi.doExtra(ea) + ida_lines.update_extra_cmt(ea, ida_lines.E_PREV + n, line) + ida_bytes.doExtra(ea) def ExtLinB(ea, n, line): @@ -1378,8 +1408,8 @@ def ExtLinB(ea, n, line): and there is no additional line #149, your line will not be displayed. MAX_ITEM_LINES is defined in IDA.CFG """ - idaapi.update_extra_cmt(ea, idaapi.E_NEXT + n, line) - idaapi.doExtra(ea) + ida_lines.update_extra_cmt(ea, ida_lines.E_NEXT + n, line) + ida_bytes.doExtra(ea) def DelExtLnA(ea, n): @@ -1391,7 +1421,7 @@ def DelExtLnA(ea, n): @return: None """ - idaapi.del_extra_cmt(ea, idaapi.E_PREV + n) + ida_lines.del_extra_cmt(ea, ida_lines.E_PREV + n) def DelExtLnB(ea, n): @@ -1403,7 +1433,7 @@ def DelExtLnB(ea, n): @return: None """ - idaapi.del_extra_cmt(ea, idaapi.E_NEXT + n) + ida_lines.del_extra_cmt(ea, ida_lines.E_NEXT + n) def SetManualInsn(ea, insn): @@ -1416,7 +1446,7 @@ def SetManualInsn(ea, insn): @note: IDA will not check the specified instruction, it will simply display it instead of the orginal representation. """ - return idaapi.set_manual_insn(ea, insn) + return ida_bytes.set_manual_insn(ea, insn) def GetManualInsn(ea): @@ -1427,7 +1457,7 @@ def GetManualInsn(ea): @note: This function returns value set by SetManualInsn earlier. """ - return idaapi.get_manual_insn(ea) + return ida_bytes.get_manual_insn(ea) def PatchDbgByte(ea,value): @@ -1439,7 +1469,7 @@ def PatchDbgByte(ea,value): @return: 1 if successful, 0 if not """ - return idaapi.put_dbg_byte(ea, value) + return ida_dbg.put_dbg_byte(ea, value) def PatchByte(ea, value): @@ -1456,7 +1486,7 @@ def PatchByte(ea, value): or the debugger is not running, and the IDB has value 'value' at address 'ea already. """ - return idaapi.patch_byte(ea, value) + return ida_bytes.patch_byte(ea, value) def PatchWord(ea, value): @@ -1472,7 +1502,7 @@ def PatchWord(ea, value): or the debugger is not running, and the IDB has value 'value' at address 'ea already. """ - return idaapi.patch_word(ea, value) + return ida_bytes.patch_word(ea, value) def PatchDword(ea, value): @@ -1488,7 +1518,7 @@ def PatchDword(ea, value): or the debugger is not running, and the IDB has value 'value' at address 'ea already. """ - return idaapi.patch_long(ea, value) + return ida_bytes.patch_long(ea, value) def PatchQword(ea, value): @@ -1504,7 +1534,7 @@ def PatchQword(ea, value): or the debugger is not running, and the IDB has value 'value' at address 'ea already. """ - return idaapi.patch_qword(ea, value) + return ida_bytes.patch_qword(ea, value) def SetFlags(ea, flags): @@ -1517,7 +1547,7 @@ def SetFlags(ea, flags): @param ea: adress @param flags: new flags value """ - return idaapi.setFlags(ea, flags) + return ida_bytes.setFlags(ea, flags) def SetRegEx(ea, reg, value, tag): """ @@ -1534,9 +1564,9 @@ def SetRegEx(ea, reg, value, tag): See also SetReg() compatibility macro. """ - reg = idaapi.str2reg(reg); + reg = ida_idp.str2reg(reg); if reg >= 0: - return idaapi.splitSRarea1(ea, reg, value, tag) + return ida_srarea.splitSRarea1(ea, reg, value, tag) else: return False @@ -1554,14 +1584,14 @@ def AutoMark2(start, end, queuetype): it. There are several autoanalysis queue types. IDA will process all queries from the first queue and then switch to the second queue, etc. """ - return idaapi.auto_mark_range(start, end, queuetype) + return ida_auto.auto_mark_range(start, end, queuetype) def AutoUnmark(start, end, queuetype): """ Remove range of addresses from a queue. """ - return idaapi.autoUnmark(start, end, queuetype) + return ida_auto.autoUnmark(start, end, queuetype) def AutoMark(ea,qtype): @@ -1570,12 +1600,12 @@ def AutoMark(ea,qtype): """ return AutoMark2(ea,ea+1,qtype) -AU_UNK = idaapi.AU_UNK # make unknown -AU_CODE = idaapi.AU_CODE # convert to instruction -AU_PROC = idaapi.AU_PROC # make function -AU_USED = idaapi.AU_USED # reanalyze -AU_LIBF = idaapi.AU_LIBF # apply a flirt signature (the current signature!) -AU_FINAL = idaapi.AU_FINAL # coagulate unexplored items +AU_UNK = ida_auto.AU_UNK # make unknown +AU_CODE = ida_auto.AU_CODE # convert to instruction +AU_PROC = ida_auto.AU_PROC # make function +AU_USED = ida_auto.AU_USED # reanalyze +AU_LIBF = ida_auto.AU_LIBF # apply a flirt signature (the current signature!) +AU_FINAL = ida_auto.AU_FINAL # coagulate unexplored items #---------------------------------------------------------------------------- @@ -1596,33 +1626,33 @@ def GenerateFile(filetype, path, ea1, ea2, flags): -1 if an error occured OFILE_EXE: 0-can't generate exe file, 1-ok """ - f = idaapi.fopenWT(path) + f = ida_diskio.fopenWT(path) if f: - retval = idaapi.gen_file(filetype, f, ea1, ea2, flags) - idaapi.eclose(f) + retval = ida_loader.gen_file(filetype, f, ea1, ea2, flags) + ida_diskio.eclose(f) return retval else: return -1 # output file types: -OFILE_MAP = idaapi.OFILE_MAP -OFILE_EXE = idaapi.OFILE_EXE -OFILE_IDC = idaapi.OFILE_IDC -OFILE_LST = idaapi.OFILE_LST -OFILE_ASM = idaapi.OFILE_ASM -OFILE_DIF = idaapi.OFILE_DIF +OFILE_MAP = ida_loader.OFILE_MAP +OFILE_EXE = ida_loader.OFILE_EXE +OFILE_IDC = ida_loader.OFILE_IDC +OFILE_LST = ida_loader.OFILE_LST +OFILE_ASM = ida_loader.OFILE_ASM +OFILE_DIF = ida_loader.OFILE_DIF # output control flags: -GENFLG_MAPSEG = idaapi.GENFLG_MAPSEG # map: generate map of segments -GENFLG_MAPNAME = idaapi.GENFLG_MAPNAME # map: include dummy names -GENFLG_MAPDMNG = idaapi.GENFLG_MAPDMNG # map: demangle names -GENFLG_MAPLOC = idaapi.GENFLG_MAPLOC # map: include local names -GENFLG_IDCTYPE = idaapi.GENFLG_IDCTYPE # idc: gen only information about types -GENFLG_ASMTYPE = idaapi.GENFLG_ASMTYPE # asm&lst: gen information about types too -GENFLG_GENHTML = idaapi.GENFLG_GENHTML # asm&lst: generate html (gui version only) -GENFLG_ASMINC = idaapi.GENFLG_ASMINC # asm&lst: gen information only about types +GENFLG_MAPSEG = ida_loader.GENFLG_MAPSEG # map: generate map of segments +GENFLG_MAPNAME = ida_loader.GENFLG_MAPNAME # map: include dummy names +GENFLG_MAPDMNG = ida_loader.GENFLG_MAPDMNG # map: demangle names +GENFLG_MAPLOC = ida_loader.GENFLG_MAPLOC # map: include local names +GENFLG_IDCTYPE = ida_loader.GENFLG_IDCTYPE # idc: gen only information about types +GENFLG_ASMTYPE = ida_loader.GENFLG_ASMTYPE # asm&lst: gen information about types too +GENFLG_GENHTML = ida_loader.GENFLG_GENHTML # asm&lst: generate html (gui version only) +GENFLG_ASMINC = ida_loader.GENFLG_ASMINC # asm&lst: gen information only about types def GenFuncGdl(outfile, title, ea1, ea2, flags): """ @@ -1637,7 +1667,7 @@ def GenFuncGdl(outfile, title, ea1, ea2, flags): @note: If ea2 == BADADDR then ea1 is treated as an address within a function. That function will be flow charted. """ - return idaapi.gen_flow_graph(outfile, title, None, ea1, ea2, flags) + return ida_gdl.gen_flow_graph(outfile, title, None, ea1, ea2, flags) CHART_PRINT_NAMES = 0x1000 # print labels for each block? @@ -1654,7 +1684,7 @@ def GenCallGdl(outfile, title, flags): @param title: graph title @param flags: combination of CHART_GEN_GDL, CHART_WINGRAPH, CHART_NOLIBFUNCS """ - return idaapi.gen_simple_call_chart(outfile, "Generating chart", title, flags) + return ida_gdl.gen_simple_call_chart(outfile, "Generating chart", title, flags) #---------------------------------------------------------------------------- @@ -1666,7 +1696,7 @@ def GetIdaDirectory(): This function returns the directory where IDA.EXE resides """ - return idaapi.idadir("") + return ida_diskio.idadir("") def GetInputFile(): @@ -1675,7 +1705,7 @@ def GetInputFile(): This function returns name of the file being disassembled """ - return idaapi.get_root_filename() + return ida_nalt.get_root_filename() def GetInputFilePath(): @@ -1684,7 +1714,7 @@ def GetInputFilePath(): This function returns the full path of the file being disassembled """ - return idaapi.get_input_file_path() + return ida_nalt.get_input_file_path() def SetInputFilePath(path): @@ -1697,7 +1727,7 @@ def SetInputFilePath(path): @param path: new input file path """ - return idaapi.set_root_filename(path) + return ida_nalt.set_root_filename(path) def GetIdbPath(): @@ -1706,7 +1736,7 @@ def GetIdbPath(): This function returns full path of the current IDB database """ - return idaapi.as_cstr(idaapi.cvar.database_idb) + return ida_idaapi.as_cstr(ida_loader.cvar.database_idb) def GetInputMD5(): @@ -1715,7 +1745,7 @@ def GetInputMD5(): @return: MD5 string or None on error """ - return idaapi.retrieve_input_file_md5() + return ida_nalt.retrieve_input_file_md5() def GetFlags(ea): @@ -1727,7 +1757,7 @@ def GetFlags(ea): @return: 32-bit value of internal flags. See start of IDC.IDC file for explanations. """ - return idaapi.getFlags(ea) + return ida_bytes.getFlags(ea) def IdbByte(ea): @@ -1741,7 +1771,7 @@ def IdbByte(ea): @note: If the current byte size is different from 8 bits, then the returned value may have more 1's. To check if a byte has a value, use this expr: hasValue(GetFlags(ea)) """ - return idaapi.get_db_byte(ea) + return ida_bytes.get_db_byte(ea) def GetManyBytes(ea, size, use_dbg = False): @@ -1758,9 +1788,9 @@ def GetManyBytes(ea, size, use_dbg = False): otherwise a string containing the read bytes """ if use_dbg: - return idaapi.dbg_read_memory(ea, size) + return ida_idd.dbg_read_memory(ea, size) else: - return idaapi.get_many_bytes(ea, size) + return ida_bytes.get_many_bytes(ea, size) def Byte(ea): @@ -1774,14 +1804,14 @@ def Byte(ea): might have more 1's. To check if a byte has a value, use functions hasValue(GetFlags(ea)) """ - return idaapi.get_full_byte(ea) + return ida_bytes.get_full_byte(ea) def __DbgValue(ea, len): - if len not in idaapi.__struct_unpack_table: + if len not in ida_idaapi.__struct_unpack_table: return None - r = idaapi.dbg_read_memory(ea, len) - return None if r is None else struct.unpack((">" if idaapi.cvar.inf.mf else "<") + idaapi.__struct_unpack_table[len][1], r)[0] + r = ida_idd.dbg_read_memory(ea, len) + return None if r is None else struct.unpack((">" if ida_ida.cvar.inf.mf else "<") + ida_idaapi.__struct_unpack_table[len][1], r)[0] def DbgByte(ea): @@ -1834,7 +1864,7 @@ def DbgRead(ea, size): Thread-safe function (may be called only from the main thread and debthread) """ - return idaapi.dbg_read_memory(ea, size) + return ida_idd.dbg_read_memory(ea, size) def DbgWrite(ea, data): @@ -1847,10 +1877,10 @@ def DbgWrite(ea, data): Thread-safe function (may be called only from the main thread and debthread) """ - if not idaapi.dbg_can_query(): + if not ida_idd.dbg_can_query(): return -1 elif len(data) > 0: - return idaapi.dbg_write_memory(ea, data) + return ida_idd.dbg_write_memory(ea, data) def GetOriginalByte(ea): @@ -1861,7 +1891,7 @@ def GetOriginalByte(ea): @return: the original value of byte before any patch applied to it """ - return idaapi.get_original_byte(ea) + return ida_bytes.get_original_byte(ea) def Word(ea): @@ -1874,7 +1904,7 @@ def Word(ea): If the current byte size is different from 8 bits, then the returned value might have more 1's. """ - return idaapi.get_full_word(ea) + return ida_bytes.get_full_word(ea) def Dword(ea): @@ -1885,7 +1915,7 @@ def Dword(ea): @return: the value of the double word. If failed returns -1 """ - return idaapi.get_full_long(ea) + return ida_bytes.get_full_long(ea) def Qword(ea): @@ -1896,7 +1926,7 @@ def Qword(ea): @return: the value of the quadro word. If failed, returns -1 """ - return idaapi.get_qword(ea) + return ida_bytes.get_qword(ea) def GetFloat(ea): @@ -1936,7 +1966,7 @@ def LocByName(name): @return: address of the name BADADDR - No such name """ - return idaapi.get_name_ea(BADADDR, name) + return ida_name.get_name_ea(BADADDR, name) def LocByNameEx(fromaddr, name): @@ -1954,7 +1984,7 @@ def LocByNameEx(fromaddr, name): @note: Dummy names (like byte_xxxx where xxxx are hex digits) are parsed by this function to obtain the address. The database is not consulted for them. """ - return idaapi.get_name_ea(fromaddr, name) + return ida_name.get_name_ea(fromaddr, name) def SegByBase(base): @@ -1966,8 +1996,8 @@ def SegByBase(base): @return: linear address of the start of the segment or BADADDR if no such segment """ - sel = idaapi.find_selector(base) - seg = idaapi.get_segm_by_sel(sel) + sel = ida_segment.find_selector(base) + seg = ida_segment.get_segm_by_sel(sel) if seg: return seg.startEA @@ -1979,7 +2009,7 @@ def ScreenEA(): """ Get linear address of cursor """ - return idaapi.get_screen_ea() + return ida_kernwin.get_screen_ea() def GetCurrentLine(): @@ -1988,7 +2018,7 @@ def GetCurrentLine(): @return: string """ - return idaapi.tag_remove(idaapi.get_curline()) + return ida_lines.tag_remove(ida_kernwin.get_curline()) def SelStart(): @@ -1996,7 +2026,7 @@ def SelStart(): Get start address of the selected area returns BADADDR - the user has not selected an area """ - selection, startaddr, endaddr = idaapi.read_selection() + selection, startaddr, endaddr = ida_kernwin.read_selection() if selection == 1: return startaddr @@ -2010,7 +2040,7 @@ def SelEnd(): @return: BADADDR - the user has not selected an area """ - selection, startaddr, endaddr = idaapi.read_selection() + selection, startaddr, endaddr = ida_kernwin.read_selection() if selection == 1: return endaddr @@ -2031,9 +2061,9 @@ def GetReg(ea, reg): so to get paragraph pointed to by the segment register you need to call AskSelector() function. """ - reg = idaapi.str2reg(reg); + reg = ida_idp.str2reg(reg); if reg >= 0: - return idaapi.getSR(ea, reg) + return ida_srarea.getSR(ea, reg) else: return -1 @@ -2045,7 +2075,7 @@ def NextAddr(ea): @return: BADADDR - the specified address in the last used address """ - return idaapi.nextaddr(ea) + return ida_bytes.nextaddr(ea) def PrevAddr(ea): @@ -2056,7 +2086,7 @@ def PrevAddr(ea): @return: BADADDR - the specified address in the first address """ - return idaapi.prevaddr(ea) + return ida_bytes.prevaddr(ea) def NextHead(ea, maxea=BADADDR): @@ -2069,7 +2099,7 @@ def NextHead(ea, maxea=BADADDR): @return: BADADDR - no (more) defined items """ - return idaapi.next_head(ea, maxea) + return ida_bytes.next_head(ea, maxea) def PrevHead(ea, minea=0): @@ -2082,7 +2112,7 @@ def PrevHead(ea, minea=0): @return: BADADDR - no (more) defined items """ - return idaapi.prev_head(ea, minea) + return ida_bytes.prev_head(ea, minea) def NextNotTail(ea): @@ -2095,7 +2125,7 @@ def NextNotTail(ea): @return: BADADDR - no (more) not-tail addresses """ - return idaapi.next_not_tail(ea) + return ida_bytes.next_not_tail(ea) def PrevNotTail(ea): @@ -2108,7 +2138,7 @@ def PrevNotTail(ea): @return: BADADDR - no (more) not-tail addresses """ - return idaapi.prev_not_tail(ea) + return ida_bytes.prev_not_tail(ea) def ItemHead(ea): @@ -2120,7 +2150,7 @@ def ItemHead(ea): @return: the starting address of the item if the current address is unexplored, returns 'ea' """ - return idaapi.get_item_head(ea) + return ida_bytes.get_item_head(ea) def ItemEnd(ea): @@ -2131,7 +2161,7 @@ def ItemEnd(ea): @return: address past end of the item at 'ea' """ - return idaapi.get_item_end(ea) + return ida_bytes.get_item_end(ea) def ItemSize(ea): @@ -2142,7 +2172,7 @@ def ItemSize(ea): @return: 1..n """ - return idaapi.get_item_end(ea) - ea + return ida_bytes.get_item_end(ea) - ea def NameEx(fromaddr, ea): @@ -2162,7 +2192,7 @@ def NameEx(fromaddr, ea): @return: "" - byte has no name """ - name = idaapi.get_name(fromaddr, ea) + name = ida_name.get_name(fromaddr, ea) if not name: return "" @@ -2183,7 +2213,7 @@ def GetTrueNameEx(fromaddr, ea): @return: "" - byte has no name """ - name = idaapi.get_true_name(fromaddr, ea) + name = ida_name.get_true_name(fromaddr, ea) if not name: return "" @@ -2203,7 +2233,7 @@ def Demangle(name, disable_mask): @return: a demangled name If the input name cannot be demangled, returns None """ - return idaapi.demangle_name(name, disable_mask) + return ida_name.demangle_name(name, disable_mask) def GetDisasmEx(ea, flags): @@ -2219,20 +2249,20 @@ def GetDisasmEx(ea, flags): @note: this function may not return exactly the same mnemonics as you see on the screen. """ - text = idaapi.generate_disasm_line(ea, flags) + text = ida_lines.generate_disasm_line(ea, flags) if text: - return idaapi.tag_remove(text) + return ida_lines.tag_remove(text) else: return "" # flags for GetDisasmEx # generate a disassembly line as if # there is an instruction at 'ea' -GENDSM_FORCE_CODE = idaapi.GENDSM_FORCE_CODE +GENDSM_FORCE_CODE = ida_lines.GENDSM_FORCE_CODE # if the instruction consists of several lines, # produce all of them (useful for parallel instructions) -GENDSM_MULTI_LINE = idaapi.GENDSM_MULTI_LINE +GENDSM_MULTI_LINE = ida_lines.GENDSM_MULTI_LINE def GetDisasm(ea): """ @@ -2258,7 +2288,7 @@ def GetMnem(ea): @note: this function may not return exactly the same mnemonics as you see on the screen. """ - res = idaapi.ua_mnem(ea) + res = ida_ua.ua_mnem(ea) if not res: return "" @@ -2278,15 +2308,15 @@ def GetOpnd(ea, n): @return: the current text representation of operand or "" """ - if not isCode(idaapi.get_flags_novalue(ea)): + if not isCode(ida_bytes.get_flags_novalue(ea)): return "" - res = idaapi.ua_outop2(ea, n) + res = ida_ua.ua_outop2(ea, n) if not res: return "" else: - return idaapi.tag_remove(res) + return ida_lines.tag_remove(res) def GetOpType(ea, n): @@ -2300,49 +2330,49 @@ def GetOpType(ea, n): @return: any of o_* constants or -1 on error """ - inslen = idaapi.decode_insn(ea) - return -1 if inslen == 0 else idaapi.cmd.Operands[n].type + inslen = ida_ua.decode_insn(ea) + return -1 if inslen == 0 else ida_ua.cmd.Operands[n].type -o_void = idaapi.o_void # No Operand ---------- -o_reg = idaapi.o_reg # General Register (al,ax,es,ds...) reg -o_mem = idaapi.o_mem # Direct Memory Reference (DATA) addr -o_phrase = idaapi.o_phrase # Memory Ref [Base Reg + Index Reg] phrase -o_displ = idaapi.o_displ # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr -o_imm = idaapi.o_imm # Immediate Value value -o_far = idaapi.o_far # Immediate Far Address (CODE) addr -o_near = idaapi.o_near # Immediate Near Address (CODE) addr -o_idpspec0 = idaapi.o_idpspec0 # Processor specific type -o_idpspec1 = idaapi.o_idpspec1 # Processor specific type -o_idpspec2 = idaapi.o_idpspec2 # Processor specific type -o_idpspec3 = idaapi.o_idpspec3 # Processor specific type -o_idpspec4 = idaapi.o_idpspec4 # Processor specific type -o_idpspec5 = idaapi.o_idpspec5 # Processor specific type +o_void = ida_ua.o_void # No Operand ---------- +o_reg = ida_ua.o_reg # General Register (al,ax,es,ds...) reg +o_mem = ida_ua.o_mem # Direct Memory Reference (DATA) addr +o_phrase = ida_ua.o_phrase # Memory Ref [Base Reg + Index Reg] phrase +o_displ = ida_ua.o_displ # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr +o_imm = ida_ua.o_imm # Immediate Value value +o_far = ida_ua.o_far # Immediate Far Address (CODE) addr +o_near = ida_ua.o_near # Immediate Near Address (CODE) addr +o_idpspec0 = ida_ua.o_idpspec0 # Processor specific type +o_idpspec1 = ida_ua.o_idpspec1 # Processor specific type +o_idpspec2 = ida_ua.o_idpspec2 # Processor specific type +o_idpspec3 = ida_ua.o_idpspec3 # Processor specific type +o_idpspec4 = ida_ua.o_idpspec4 # Processor specific type +o_idpspec5 = ida_ua.o_idpspec5 # Processor specific type # There can be more processor specific types # x86 -o_trreg = idaapi.o_idpspec0 # trace register -o_dbreg = idaapi.o_idpspec1 # debug register -o_crreg = idaapi.o_idpspec2 # control register -o_fpreg = idaapi.o_idpspec3 # floating point register -o_mmxreg = idaapi.o_idpspec4 # mmx register -o_xmmreg = idaapi.o_idpspec5 # xmm register +o_trreg = ida_ua.o_idpspec0 # trace register +o_dbreg = ida_ua.o_idpspec1 # debug register +o_crreg = ida_ua.o_idpspec2 # control register +o_fpreg = ida_ua.o_idpspec3 # floating point register +o_mmxreg = ida_ua.o_idpspec4 # mmx register +o_xmmreg = ida_ua.o_idpspec5 # xmm register # arm -o_reglist = idaapi.o_idpspec1 # Register list (for LDM/STM) -o_creglist = idaapi.o_idpspec2 # Coprocessor register list (for CDP) -o_creg = idaapi.o_idpspec3 # Coprocessor register (for LDC/STC) -o_fpreg_arm = idaapi.o_idpspec4 # Floating point register -o_fpreglist = idaapi.o_idpspec5 # Floating point register list -o_text = (idaapi.o_idpspec5+1) # Arbitrary text stored in the operand +o_reglist = ida_ua.o_idpspec1 # Register list (for LDM/STM) +o_creglist = ida_ua.o_idpspec2 # Coprocessor register list (for CDP) +o_creg = ida_ua.o_idpspec3 # Coprocessor register (for LDC/STC) +o_fpreg_arm = ida_ua.o_idpspec4 # Floating point register +o_fpreglist = ida_ua.o_idpspec5 # Floating point register list +o_text = (ida_ua.o_idpspec5+1) # Arbitrary text stored in the operand # ppc -o_spr = idaapi.o_idpspec0 # Special purpose register -o_twofpr = idaapi.o_idpspec1 # Two FPRs -o_shmbme = idaapi.o_idpspec2 # SH & MB & ME -o_crf = idaapi.o_idpspec3 # crfield x.reg -o_crb = idaapi.o_idpspec4 # crbit x.reg -o_dcr = idaapi.o_idpspec5 # Device control register +o_spr = ida_ua.o_idpspec0 # Special purpose register +o_twofpr = ida_ua.o_idpspec1 # Two FPRs +o_shmbme = ida_ua.o_idpspec2 # SH & MB & ME +o_crf = ida_ua.o_idpspec3 # crfield x.reg +o_crb = ida_ua.o_idpspec4 # crbit x.reg +o_dcr = ida_ua.o_idpspec5 # Device control register def GetOperandValue(ea, n): """ @@ -2361,20 +2391,20 @@ def GetOperandValue(ea, n): operand is a register phrase => phrase number otherwise => -1 """ - inslen = idaapi.decode_insn(ea) + inslen = ida_ua.decode_insn(ea) if inslen == 0: return -1 - op = idaapi.cmd.Operands[n] + op = ida_ua.cmd.Operands[n] if not op: return -1 - if op.type in [ idaapi.o_mem, idaapi.o_far, idaapi.o_near, idaapi.o_displ ]: + if op.type in [ ida_ua.o_mem, ida_ua.o_far, ida_ua.o_near, ida_ua.o_displ ]: value = op.addr - elif op.type == idaapi.o_reg: + elif op.type == ida_ua.o_reg: value = op.reg - elif op.type == idaapi.o_imm: + elif op.type == ida_ua.o_imm: value = op.value - elif op.type == idaapi.o_phrase: + elif op.type == ida_ua.o_phrase: value = op.phrase else: value = -1 @@ -2391,7 +2421,7 @@ def LineA(ea, num): @return: anterior line string """ - return idaapi.get_extra_cmt(ea, idaapi.E_PREV + num) + return ida_lines.get_extra_cmt(ea, ida_lines.E_PREV + num) def LineB(ea, num): @@ -2403,7 +2433,7 @@ def LineB(ea, num): @return: posterior line string """ - return idaapi.get_extra_cmt(ea, idaapi.E_NEXT + num) + return ida_lines.get_extra_cmt(ea, ida_lines.E_NEXT + num) def GetCommentEx(ea, repeatable): @@ -2416,7 +2446,7 @@ def GetCommentEx(ea, repeatable): @return: string or None if it fails """ - return idaapi.get_cmt(ea, repeatable) + return ida_bytes.get_cmt(ea, repeatable) def CommentEx(ea, repeatable): @@ -2443,16 +2473,16 @@ def AltOp(ea, n): @return: string or None if it fails """ - return idaapi.get_forced_operand(ea, n) + return ida_bytes.get_forced_operand(ea, n) -ASCSTR_C = idaapi.ASCSTR_TERMCHR # C-style ASCII string -ASCSTR_PASCAL = idaapi.ASCSTR_PASCAL # Pascal-style ASCII string (length byte) -ASCSTR_LEN2 = idaapi.ASCSTR_LEN2 # Pascal-style, length is 2 bytes -ASCSTR_UNICODE = idaapi.ASCSTR_UNICODE # Unicode string -ASCSTR_LEN4 = idaapi.ASCSTR_LEN4 # Pascal-style, length is 4 bytes -ASCSTR_ULEN2 = idaapi.ASCSTR_ULEN2 # Pascal-style Unicode, length is 2 bytes -ASCSTR_ULEN4 = idaapi.ASCSTR_ULEN4 # Pascal-style Unicode, length is 4 bytes -ASCSTR_LAST = idaapi.ASCSTR_LAST # Last string type +ASCSTR_C = ida_nalt.ASCSTR_TERMCHR # C-style ASCII string +ASCSTR_PASCAL = ida_nalt.ASCSTR_PASCAL # Pascal-style ASCII string (length byte) +ASCSTR_LEN2 = ida_nalt.ASCSTR_LEN2 # Pascal-style, length is 2 bytes +ASCSTR_UNICODE = ida_nalt.ASCSTR_UNICODE # Unicode string +ASCSTR_LEN4 = ida_nalt.ASCSTR_LEN4 # Pascal-style, length is 4 bytes +ASCSTR_ULEN2 = ida_nalt.ASCSTR_ULEN2 # Pascal-style Unicode, length is 2 bytes +ASCSTR_ULEN4 = ida_nalt.ASCSTR_ULEN4 # Pascal-style Unicode, length is 4 bytes +ASCSTR_LAST = ida_nalt.ASCSTR_LAST # Last string type def GetString(ea, length = -1, strtype = ASCSTR_C): """ @@ -2464,9 +2494,9 @@ def GetString(ea, length = -1, strtype = ASCSTR_C): @return: string contents or empty string """ if length == -1: - length = idaapi.get_max_ascii_length(ea, strtype, idaapi.ALOPT_IGNHEADS) + length = ida_bytes.get_max_ascii_length(ea, strtype, ida_bytes.ALOPT_IGNHEADS) - return idaapi.get_ascii_contents2(ea, length, strtype) + return ida_bytes.get_ascii_contents2(ea, length, strtype) def GetStringType(ea): @@ -2477,9 +2507,9 @@ def GetStringType(ea): @return: One of ASCSTR_... constants """ - ti = idaapi.opinfo_t() + ti = ida_nalt.opinfo_t() - if idaapi.get_opinfo(ea, 0, GetFlags(ea), ti): + if ida_bytes.get_opinfo(ea, 0, GetFlags(ea), ti): return ti.strtype else: return None @@ -2489,22 +2519,22 @@ def GetStringType(ea): # flag is combination of the following bits # returns BADADDR - not found -def FindVoid (ea, flag): return idaapi.find_void(ea, flag) -def FindCode (ea, flag): return idaapi.find_code(ea, flag) -def FindData (ea, flag): return idaapi.find_data(ea, flag) -def FindUnexplored (ea, flag): return idaapi.find_unknown(ea, flag) -def FindExplored (ea, flag): return idaapi.find_defined(ea, flag) -def FindImmediate (ea, flag, value): return idaapi.find_imm(ea, flag, value) +def FindVoid (ea, flag): return ida_search.find_void(ea, flag) +def FindCode (ea, flag): return ida_search.find_code(ea, flag) +def FindData (ea, flag): return ida_search.find_data(ea, flag) +def FindUnexplored (ea, flag): return ida_search.find_unknown(ea, flag) +def FindExplored (ea, flag): return ida_search.find_defined(ea, flag) +def FindImmediate (ea, flag, value): return ida_search.find_imm(ea, flag, value) -SEARCH_UP = idaapi.SEARCH_UP # search backward -SEARCH_DOWN = idaapi.SEARCH_DOWN # search forward -SEARCH_NEXT = idaapi.SEARCH_NEXT # start the search at the next/prev item - # useful only for FindText() and FindBinary() -SEARCH_CASE = idaapi.SEARCH_CASE # search case-sensitive - # (only for bin&txt search) -SEARCH_REGEX = idaapi.SEARCH_REGEX # enable regular expressions (only for text) -SEARCH_NOBRK = idaapi.SEARCH_NOBRK # don't test ctrl-break -SEARCH_NOSHOW = idaapi.SEARCH_NOSHOW # don't display the search progress +SEARCH_UP = ida_search.SEARCH_UP # search backward +SEARCH_DOWN = ida_search.SEARCH_DOWN # search forward +SEARCH_NEXT = ida_search.SEARCH_NEXT # start the search at the next/prev item + # useful only for FindText() and FindBinary() +SEARCH_CASE = ida_search.SEARCH_CASE # search case-sensitive + # (only for bin&txt search) +SEARCH_REGEX = ida_search.SEARCH_REGEX # enable regular expressions (only for text) +SEARCH_NOBRK = ida_search.SEARCH_NOBRK # don't test ctrl-break +SEARCH_NOSHOW = ida_search.SEARCH_NOSHOW # don't display the search progress def FindText(ea, flag, y, x, searchstr): """ @@ -2516,7 +2546,7 @@ def FindText(ea, flag, y, x, searchstr): @return: ea of result or BADADDR if not found """ - return idaapi.find_text(ea, y, x, searchstr, flag) + return ida_search.find_text(ea, y, x, searchstr, flag) def FindBinary(ea, flag, searchstr, radix=16): @@ -2530,8 +2560,8 @@ def FindBinary(ea, flag, searchstr, radix=16): @note: Example: "41 42" - find 2 bytes 41h,42h (radix is 16) """ - endea = flag & 1 and idaapi.cvar.inf.maxEA or idaapi.cvar.inf.minEA - return idaapi.find_binary(ea, endea, searchstr, radix, flag) + endea = flag & 1 and ida_ida.cvar.inf.maxEA or ida_ida.cvar.inf.minEA + return ida_search.find_binary(ea, endea, searchstr, radix, flag) #---------------------------------------------------------------------------- @@ -2545,7 +2575,7 @@ def ChangeConfig(directive): @note: If the directives are erroneous, a fatal error will be generated. The settings are permanent: effective for the current session and the next ones """ - return Eval('ChangeConfig("%s")' % idaapi.str2user(directive)) + return Eval('ChangeConfig("%s")' % ida_kernwin.str2user(directive)) # The following functions allow you to set/get common parameters. @@ -2554,10 +2584,10 @@ def ChangeConfig(directive): def GetLongPrm(offset): """ """ - val = _IDC_GetAttr(idaapi.cvar.inf, _INFMAP, offset) + val = _IDC_GetAttr(ida_ida.cvar.inf, _INFMAP, offset) if offset == INF_PROCNAME: # procName is a character array - val = idaapi.as_cstr(val) + val = ida_idaapi.as_cstr(val) return val def GetShortPrm(offset): @@ -2568,20 +2598,24 @@ def GetCharPrm (offset): return GetLongPrm(offset) -def SetLongPrm (offset, value): - """ - """ +def _invoke_idc_setprm(vtype, offset, value): if offset == INF_PROCNAME: - raise NotImplementedError, "Please use idaapi.set_processor_type() to change processor" - return _IDC_SetAttr(idaapi.cvar.inf, _INFMAP, offset, value) + raise NotImplementedError, "Please use ida_idp.set_processor_type() to change processor" + # We really want to go through IDC's equivalent, because it might + # have side-effects (i.e., send a notification, etc...) + return Eval("Set%sPrm(%d, %d)" % (vtype, offset, value)) + + +def SetLongPrm (offset, value): + return _invoke_idc_setprm("Long", offset, value) def SetShortPrm(offset, value): - SetLongPrm(offset, value) + return _invoke_idc_setprm("Short", offset, value) def SetCharPrm (offset, value): - SetLongPrm(offset, value) + return _invoke_idc_setprm("Char", offset, value) INF_VERSION = 3 # short; Version of database @@ -2594,8 +2628,6 @@ LFLG_64BIT = 0x04 # 64-bit program? LFLG_DBG_NOPATH = 0x08 # do not store input full path LFLG_SNAPSHOT = 0x10 # is memory snapshot? # in debugger process options -LFLG_8ALIGN4 = 0x40 # 4 byte alignment for 8byte scalars - # (__int64/double) inside structures INF_DEMNAMES = 14 # char; display demangled names as: DEMNAM_CMNT = 0 # comments DEMNAM_NAME = 1 # regular names @@ -2819,7 +2851,15 @@ INF_SIZEOF_SHORT = 189 INF_SIZEOF_LONG = 190 INF_SIZEOF_LLONG = 191 INF_CHANGE_COUNTER = 192 # database change counter; keeps track of byte and segment modifications -INF_SIZEOF_LDBL = 196 # uchar; sizeof(long double) +INF_SIZEOF_LDBL = 196 # uchar; sizeof(long double) +INF_ABINAME = 201 # char[16]; ABI name +INF_ABIBITS = 217 # uint32; ABI features: +ABI_8ALIGN4 = 0x00000001 # 4 byte alignment for 8byte scalars (__int64/double) inside structures? +ABI_PACK_STKARGS = 0x00000002 # do not align stack arguments to stack slots +ABI_BIGARG_ALIGN = 0x00000004 # use natural type alignment for argument if the alignment exceeds native word size (e.g. __int64 argument should be 8byte aligned on some 32bit platforms) +ABI_STACK_LDBL = 0x00000008 # long double areuments are passed on stack +ABI_STACK_VARARGS = 0x00000010 # varargs are always passed on stack (even when there are free registers) +ABI_HARD_FLOAT = 0x00000020 # use the floating-point register set INF_REFCMTS = 221 # uchar; number of comment lines to generate for refs # to ASCII string or demangled name # 0 - such comments won't be generated at all @@ -2966,7 +3006,7 @@ INF_MARGIN : (False, 'margin'), # ushort; max length of data lines INF_LENXREF : (False, 'lenxref'), # ushort; max length of line with xrefs INF_LPREFIX : (False, 'lprefix'), # char[16];prefix of local names INF_LPREFIXLEN : (False, 'lprefixlen'), # uchar; length of the lprefix -INF_COMPILER : (False, 'cc') # uchar; compiler +INF_COMPILER : (False, 'cc'), # uchar; compiler #INF_MODEL = 184 # uchar; memory model & calling convention #INF_SIZEOF_INT = 185 # uchar; sizeof(int) @@ -2976,6 +3016,7 @@ INF_COMPILER : (False, 'cc') # uchar; compiler #INF_SIZEOF_SHORT = 189 #INF_SIZEOF_LONG = 190 #INF_SIZEOF_LLONG = 191 +INF_ABIBITS : (False, 'abibits') # uint32; ABI features } @@ -2995,7 +3036,7 @@ def SetProcessorType (processor, level): means that if the processor type can't be set, IDA should display an error message and exit. """ - return idaapi.set_processor_type(processor, level) + return ida_idp.set_processor_type(processor, level) def SetTargetAssembler(asmidx): """ @@ -3005,12 +3046,12 @@ def SetTargetAssembler(asmidx): @return: 1-ok, 0-failed """ - return idaapi.set_target_assembler(asmidx) + return ida_idp.set_target_assembler(asmidx) -SETPROC_COMPAT = idaapi.SETPROC_COMPAT -SETPROC_ALL = idaapi.SETPROC_ALL -SETPROC_USER = idaapi.SETPROC_USER -SETPROC_FATAL = idaapi.SETPROC_FATAL +SETPROC_COMPAT = ida_idp.SETPROC_COMPAT +SETPROC_ALL = ida_idp.SETPROC_ALL +SETPROC_USER = ida_idp.SETPROC_USER +SETPROC_FATAL = ida_idp.SETPROC_FATAL def SetPrcsr(processor): return SetProcessorType(processor, SETPROC_COMPAT) @@ -3025,8 +3066,8 @@ def Batch(batch): @return: old balue of batch flag """ - batch_prev = idaapi.cvar.batch - idaapi.cvar.batch = batch + batch_prev = ida_kernwin.cvar.batch + ida_kernwin.cvar.batch = batch return batch_prev @@ -3043,7 +3084,7 @@ def AskStr(defval, prompt): @return: the entered string or None. """ - return idaapi.askstr(0, defval, prompt) + return ida_kernwin.askstr(0, defval, prompt) def AskFile(forsave, mask, prompt): @@ -3056,7 +3097,7 @@ def AskFile(forsave, mask, prompt): @return: the selected file or None. """ - return idaapi.askfile_c(forsave, mask, prompt) + return ida_kernwin.askfile_c(forsave, mask, prompt) def AskAddr(defval, prompt): @@ -3069,7 +3110,7 @@ def AskAddr(defval, prompt): @return: the entered address or BADADDR. """ - return idaapi.askaddr(defval, prompt) + return ida_kernwin.askaddr(defval, prompt) def AskLong(defval, prompt): @@ -3082,7 +3123,7 @@ def AskLong(defval, prompt): @return: the entered number or -1. """ - return idaapi.asklong(defval, prompt) + return ida_kernwin.asklong(defval, prompt) def ProcessUiAction(name, flags=0): @@ -3093,7 +3134,7 @@ def ProcessUiAction(name, flags=0): @param flags: Reserved. Must be zero @return: Boolean """ - return idaapi.process_ui_action(name, flags) + return ida_kernwin.process_ui_action(name, flags) def AskSeg(defval, prompt): @@ -3106,7 +3147,7 @@ def AskSeg(defval, prompt): @return: the entered segment selector or BADSEL. """ - return idaapi.askseg(defval, prompt) + return ida_kernwin.askseg(defval, prompt) def AskIdent(defval, prompt): @@ -3119,7 +3160,7 @@ def AskIdent(defval, prompt): @return: the entered identifier or None. """ - return idaapi.askident(defval, prompt) + return ida_kernwin.askident(defval, prompt) def AskYN(defval, prompt): @@ -3132,7 +3173,7 @@ def AskYN(defval, prompt): @return: -1:cancel,0-no,1-ok """ - return idaapi.askyn_c(defval, prompt) + return ida_kernwin.askyn_c(defval, prompt) def Message(msg): @@ -3143,7 +3184,7 @@ def Message(msg): This function can be used to debug IDC scripts """ - idaapi.msg(msg) + ida_kernwin.msg(msg) def UMessage(msg): @@ -3157,7 +3198,7 @@ def UMessage(msg): This function can be used to debug IDC scripts """ - idaapi.umsg(msg) + ida_kernwin.umsg(msg) def Warning(msg): @@ -3170,7 +3211,7 @@ def Warning(msg): The user will be able to hide messages if they appear twice in a row on the screen """ - idaapi.warning(msg) + ida_kernwin.warning(msg) def Fatal(format): @@ -3179,7 +3220,7 @@ def Fatal(format): @param format: message to print """ - idaapi.error(format) + ida_kernwin.error(format) def SetStatus(status): @@ -3190,7 +3231,7 @@ def SetStatus(status): @return: the previous status. """ - return idaapi.setStat(status) + return ida_auto.setStat(status) IDA_STATUS_READY = 0 # READY IDA is idle @@ -3203,14 +3244,14 @@ def Refresh(): """ Refresh all disassembly views """ - idaapi.refresh_idaview_anyway() + ida_kernwin.refresh_idaview_anyway() def RefreshLists(): """ Refresh all list views (names, functions, etc) """ - idaapi.refresh_lists() + ida_kernwin.refresh_lists() #---------------------------------------------------------------------------- @@ -3227,9 +3268,9 @@ def AskSelector(sel): @note: selector values are always in paragraphs """ - s = idaapi.sel_pointer() - base = idaapi.ea_pointer() - res,tmp = idaapi.getn_selector(sel, s.cast(), base.cast()) + s = ida_pro.sel_pointer() + base = ida_pro.ea_pointer() + res,tmp = ida_segment.getn_selector(sel, s.cast(), base.cast()) if not res: return sel @@ -3248,7 +3289,7 @@ def FindSelector(val): @note: selector values are always in paragraphs """ - return idaapi.find_selector(val) & 0xFFFF + return ida_segment.find_selector(val) & 0xFFFF def SetSelector(sel, value): @@ -3264,7 +3305,7 @@ def SetSelector(sel, value): if 'sel' == 'val' then the selector is destroyed because it has no significance """ - return idaapi.set_selector(sel, value) + return ida_segment.set_selector(sel, value) def DelSelector(sel): @@ -3277,7 +3318,7 @@ def DelSelector(sel): @note: if the selector is found, it will be deleted """ - return idaapi.del_selector(sel) + return ida_segment.del_selector(sel) def FirstSeg(): @@ -3287,7 +3328,7 @@ def FirstSeg(): @return: address of the start of the first segment BADADDR - no segments are defined """ - seg = idaapi.get_first_seg() + seg = ida_segment.get_first_seg() if not seg: return BADADDR else: @@ -3303,7 +3344,7 @@ def NextSeg(ea): @return: start of the next segment BADADDR - no next segment """ - nextseg = idaapi.get_next_seg(ea) + nextseg = ida_segment.get_next_seg(ea) if not nextseg: return BADADDR else: @@ -3321,7 +3362,7 @@ def SegStart(ea): @return: start of segment BADADDR - the specified address doesn't belong to any segment """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return BADADDR @@ -3338,7 +3379,7 @@ def SegEnd(ea): @return: end of segment (an address past end of the segment) BADADDR - the specified address doesn't belong to any segment """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return BADADDR @@ -3354,12 +3395,12 @@ def SegName(ea): @return: "" - no segment at the specified address """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return "" else: - name = idaapi.get_true_segm_name(seg) + name = ida_segment.get_true_segm_name(seg) if not name: return "" @@ -3386,31 +3427,31 @@ def AddSegEx(startea, endea, base, use32, align, comb, flags): @return: 0-failed, 1-ok """ - s = idaapi.segment_t() + s = ida_segment.segment_t() s.startEA = startea s.endEA = endea - s.sel = idaapi.setup_selector(base) + s.sel = ida_segment.setup_selector(base) s.bitness = use32 s.align = align s.comb = comb - return idaapi.add_segm_ex(s, "", "", flags) + return ida_segment.add_segm_ex(s, "", "", flags) -ADDSEG_NOSREG = idaapi.ADDSEG_NOSREG # set all default segment register values - # to BADSELs - # (undefine all default segment registers) -ADDSEG_OR_DIE = idaapi. ADDSEG_OR_DIE # qexit() if can't add a segment -ADDSEG_NOTRUNC = idaapi.ADDSEG_NOTRUNC # don't truncate the new segment at the beginning - # of the next segment if they overlap. - # destroy/truncate old segments instead. -ADDSEG_QUIET = idaapi.ADDSEG_QUIET # silent mode, no "Adding segment..." in the messages window -ADDSEG_FILLGAP = idaapi.ADDSEG_FILLGAP # If there is a gap between the new segment - # and the previous one, and this gap is less - # than 64K, then fill the gap by extending the - # previous segment and adding .align directive - # to it. This way we avoid gaps between segments. - # Too many gaps lead to a virtual array failure. - # It can not hold more than ~1000 gaps. -ADDSEG_SPARSE = idaapi.ADDSEG_SPARSE # Use sparse storage method for the new segment +ADDSEG_NOSREG = ida_segment.ADDSEG_NOSREG # set all default segment register values + # to BADSELs + # (undefine all default segment registers) +ADDSEG_OR_DIE = ida_segment. ADDSEG_OR_DIE # qexit() if can't add a segment +ADDSEG_NOTRUNC = ida_segment.ADDSEG_NOTRUNC # don't truncate the new segment at the beginning + # of the next segment if they overlap. + # destroy/truncate old segments instead. +ADDSEG_QUIET = ida_segment.ADDSEG_QUIET # silent mode, no "Adding segment..." in the messages window +ADDSEG_FILLGAP = ida_segment.ADDSEG_FILLGAP # If there is a gap between the new segment + # and the previous one, and this gap is less + # than 64K, then fill the gap by extending the + # previous segment and adding .align directive + # to it. This way we avoid gaps between segments. + # Too many gaps lead to a virtual array failure. + # It can not hold more than ~1000 gaps. +ADDSEG_SPARSE = ida_segment.ADDSEG_SPARSE # Use sparse storage method for the new segment def AddSeg(startea, endea, base, use32, align, comb): return AddSegEx(startea, endea, base, use32, align, comb, ADDSEG_NOSREG) @@ -3424,12 +3465,12 @@ def DelSeg(ea, flags): @return: boolean success """ - return idaapi.del_segm(ea, flags) + return ida_segment.del_segm(ea, flags) -SEGMOD_KILL = idaapi.SEGMOD_KILL # disable addresses if segment gets +SEGMOD_KILL = ida_segment.SEGMOD_KILL # disable addresses if segment gets # shrinked or deleted -SEGMOD_KEEP = idaapi.SEGMOD_KEEP # keep information (code & data, etc) -SEGMOD_SILENT = idaapi.SEGMOD_SILENT # be silent +SEGMOD_KEEP = ida_segment.SEGMOD_KEEP # keep information (code & data, etc) +SEGMOD_SILENT = ida_segment.SEGMOD_SILENT # be silent def SetSegBounds(ea, startea, endea, flags): @@ -3443,8 +3484,8 @@ def SetSegBounds(ea, startea, endea, flags): @return: boolean success """ - return idaapi.set_segm_start(ea, startea, flags) & \ - idaapi.set_segm_end(ea, endea, flags) + return ida_segment.set_segm_start(ea, startea, flags) & \ + ida_segment.set_segm_end(ea, endea, flags) def RenameSeg(ea, name): @@ -3456,12 +3497,12 @@ def RenameSeg(ea, name): @return: success (boolean) """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return False - return idaapi.set_segm_name(seg, name) + return ida_segment.set_segm_name(seg, name) def SetSegClass(ea, segclass): @@ -3473,12 +3514,12 @@ def SetSegClass(ea, segclass): @return: success (boolean) """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return False - return idaapi.set_segm_class(seg, segclass) + return ida_segment.set_segm_class(seg, segclass) def SegAlign(ea, alignment): @@ -3493,22 +3534,22 @@ def SegAlign(ea, alignment): return SetSegmentAttr(ea, SEGATTR_ALIGN, alignment) -saAbs = idaapi.saAbs # Absolute segment. -saRelByte = idaapi.saRelByte # Relocatable, byte aligned. -saRelWord = idaapi.saRelWord # Relocatable, word (2-byte, 16-bit) aligned. -saRelPara = idaapi.saRelPara # Relocatable, paragraph (16-byte) aligned. -saRelPage = idaapi.saRelPage # Relocatable, aligned on 256-byte boundary - # (a "page" in the original Intel specification). -saRelDble = idaapi.saRelDble # Relocatable, aligned on a double word - # (4-byte) boundary. This value is used by - # the PharLap OMF for the same alignment. -saRel4K = idaapi.saRel4K # This value is used by the PharLap OMF for - # page (4K) alignment. It is not supported - # by LINK. -saGroup = idaapi.saGroup # Segment group -saRel32Bytes = idaapi.saRel32Bytes # 32 bytes -saRel64Bytes = idaapi.saRel64Bytes # 64 bytes -saRelQword = idaapi.saRelQword # 8 bytes +saAbs = ida_segment.saAbs # Absolute segment. +saRelByte = ida_segment.saRelByte # Relocatable, byte aligned. +saRelWord = ida_segment.saRelWord # Relocatable, word (2-byte, 16-bit) aligned. +saRelPara = ida_segment.saRelPara # Relocatable, paragraph (16-byte) aligned. +saRelPage = ida_segment.saRelPage # Relocatable, aligned on 256-byte boundary + # (a "page" in the original Intel specification). +saRelDble = ida_segment.saRelDble # Relocatable, aligned on a double word + # (4-byte) boundary. This value is used by + # the PharLap OMF for the same alignment. +saRel4K = ida_segment.saRel4K # This value is used by the PharLap OMF for + # page (4K) alignment. It is not supported + # by LINK. +saGroup = ida_segment.saGroup # Segment group +saRel32Bytes = ida_segment.saRel32Bytes # 32 bytes +saRel64Bytes = ida_segment.saRel64Bytes # 64 bytes +saRelQword = ida_segment.saRelQword # 8 bytes def SegComb(segea, comb): @@ -3523,15 +3564,15 @@ def SegComb(segea, comb): return SetSegmentAttr(segea, SEGATTR_COMB, comb) -scPriv = idaapi.scPriv # Private. Do not combine with any other program - # segment. -scPub = idaapi.scPub # Public. Combine by appending at an offset that - # meets the alignment requirement. -scPub2 = idaapi.scPub2 # As defined by Microsoft, same as C=2 (public). -scStack = idaapi.scStack # Stack. Combine as for C=2. This combine type - # forces byte alignment. -scCommon = idaapi.scCommon # Common. Combine by overlay using maximum size. -scPub3 = idaapi.scPub3 # As defined by Microsoft, same as C=2 (public). +scPriv = ida_segment.scPriv # Private. Do not combine with any other program + # segment. +scPub = ida_segment.scPub # Public. Combine by appending at an offset that + # meets the alignment requirement. +scPub2 = ida_segment.scPub2 # As defined by Microsoft, same as C=2 (public). +scStack = ida_segment.scStack # Stack. Combine as for C=2. This combine type + # forces byte alignment. +scCommon = ida_segment.scCommon # Common. Combine by overlay using maximum size. +scPub3 = ida_segment.scPub3 # As defined by Microsoft, same as C=2 (public). def SetSegAddressing(ea, bitness): @@ -3543,7 +3584,7 @@ def SetSegAddressing(ea, bitness): @return: success (boolean) """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return False @@ -3561,7 +3602,7 @@ def SegByName(segname): @return: segment selector or BADADDR """ - seg = idaapi.get_segm_by_name(segname) + seg = ida_segment.get_segm_by_name(segname) if not seg: return BADADDR @@ -3579,11 +3620,11 @@ def SetSegDefReg(ea, reg, value): @param reg: name of segment register @param value: default value of the segment register. -1-undefined. """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) - reg = idaapi.str2reg(reg); + reg = ida_idp.str2reg(reg); if seg and reg >= 0: - return idaapi.SetDefaultRegisterValue(seg, reg, value) + return ida_srarea.SetDefaultRegisterValue(seg, reg, value) else: return False @@ -3597,7 +3638,7 @@ def SetSegmentType(segea, segtype): @return: !=0 - ok """ - seg = idaapi.getseg(segea) + seg = ida_segment.getseg(segea) if not seg: return False @@ -3606,22 +3647,22 @@ def SetSegmentType(segea, segtype): return seg.update() -SEG_NORM = idaapi.SEG_NORM -SEG_XTRN = idaapi.SEG_XTRN # * segment with 'extern' definitions - # no instructions are allowed -SEG_CODE = idaapi.SEG_CODE # pure code segment -SEG_DATA = idaapi.SEG_DATA # pure data segment -SEG_IMP = idaapi.SEG_IMP # implementation segment -SEG_GRP = idaapi.SEG_GRP # * group of segments - # no instructions are allowed -SEG_NULL = idaapi.SEG_NULL # zero-length segment -SEG_UNDF = idaapi.SEG_UNDF # undefined segment type -SEG_BSS = idaapi.SEG_BSS # uninitialized segment -SEG_ABSSYM = idaapi.SEG_ABSSYM # * segment with definitions of absolute symbols - # no instructions are allowed -SEG_COMM = idaapi.SEG_COMM # * segment with communal definitions - # no instructions are allowed -SEG_IMEM = idaapi.SEG_IMEM # internal processor memory & sfr (8051) +SEG_NORM = ida_segment.SEG_NORM +SEG_XTRN = ida_segment.SEG_XTRN # * segment with 'extern' definitions + # no instructions are allowed +SEG_CODE = ida_segment.SEG_CODE # pure code segment +SEG_DATA = ida_segment.SEG_DATA # pure data segment +SEG_IMP = ida_segment.SEG_IMP # implementation segment +SEG_GRP = ida_segment.SEG_GRP # * group of segments + # no instructions are allowed +SEG_NULL = ida_segment.SEG_NULL # zero-length segment +SEG_UNDF = ida_segment.SEG_UNDF # undefined segment type +SEG_BSS = ida_segment.SEG_BSS # uninitialized segment +SEG_ABSSYM = ida_segment.SEG_ABSSYM # * segment with definitions of absolute symbols + # no instructions are allowed +SEG_COMM = ida_segment.SEG_COMM # * segment with communal definitions + # no instructions are allowed +SEG_IMEM = ida_segment.SEG_IMEM # internal processor memory & sfr (8051) def GetSegmentAttr(segea, attr): @@ -3631,10 +3672,10 @@ def GetSegmentAttr(segea, attr): @param segea: any address within segment @param attr: one of SEGATTR_... constants """ - seg = idaapi.getseg(segea) + seg = ida_segment.getseg(segea) assert seg, "could not find segment at 0x%x" % segea if attr in [ SEGATTR_ES, SEGATTR_CS, SEGATTR_SS, SEGATTR_DS, SEGATTR_FS, SEGATTR_GS ]: - return idaapi.get_defsr(seg, _SEGATTRMAP[attr][1]) + return ida_segment.get_defsr(seg, _SEGATTRMAP[attr][1]) else: return _IDC_GetAttr(seg, _SEGATTRMAP, attr) @@ -3650,10 +3691,10 @@ def SetSegmentAttr(segea, attr, value): Also some of them should be modified using special functions like SetSegAddressing, etc. """ - seg = idaapi.getseg(segea) + seg = ida_segment.getseg(segea) assert seg, "could not find segment at 0x%x" % segea if attr in [ SEGATTR_ES, SEGATTR_CS, SEGATTR_SS, SEGATTR_DS, SEGATTR_FS, SEGATTR_GS ]: - idaapi.set_defsr(seg, _SEGATTRMAP[attr][1], value) + ida_segment.set_defsr(seg, _SEGATTRMAP[attr][1], value) else: _IDC_SetAttr(seg, _SEGATTRMAP, attr, value) return seg.update() @@ -3742,10 +3783,10 @@ def MoveSegm(ea, to, flags): @returns: MOVE_SEGM_... error code """ - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if not seg: return MOVE_SEGM_PARAM - return idaapi.move_segm(seg, to, flags) + return ida_segment.move_segm(seg, to, flags) MSF_SILENT = 0x0001 # don't display a "please wait" box on the screen @@ -3773,7 +3814,7 @@ def rebase_program(delta, flags): @returns: error code MOVE_SEGM_... """ - return idaapi.rebase_program(delta, flags) + return ida_segment.rebase_program(delta, flags) def SetStorageType(startEA, endEA, stt): @@ -3786,7 +3827,7 @@ def SetStorageType(startEA, endEA, stt): @returns: 0 - ok, otherwise internal error code """ - return idaapi.change_storage_type(startEA, endEA, stt) + return ida_bytes.change_storage_type(startEA, endEA, stt) STT_VA = 0 # regular storage: virtual arrays, an explicit flag for each byte @@ -3811,7 +3852,7 @@ XREF_USER = 32 # All user-specified xref types def AddCodeXref(From, To, flowtype): """ """ - return idaapi.add_cref(From, To, flowtype) + return ida_xref.add_cref(From, To, flowtype) def DelCodeXref(From, To, undef): @@ -3822,7 +3863,7 @@ def DelCodeXref(From, To, undef): @returns: 1 - planned to be made undefined """ - return idaapi.del_cref(From, To, undef) + return ida_xref.del_cref(From, To, undef) # The following functions include the ordinary flows: @@ -3831,28 +3872,28 @@ def Rfirst(From): """ Get first code xref from 'From' """ - return idaapi.get_first_cref_from(From) + return ida_xref.get_first_cref_from(From) def Rnext(From, current): """ Get next code xref from """ - return idaapi.get_next_cref_from(From, current) + return ida_xref.get_next_cref_from(From, current) def RfirstB(To): """ Get first code xref to 'To' """ - return idaapi.get_first_cref_to(To) + return ida_xref.get_first_cref_to(To) def RnextB(To, current): """ Get next code xref to 'To' """ - return idaapi.get_next_cref_to(To, current) + return ida_xref.get_next_cref_to(To, current) # The following functions don't take into account the ordinary flows: @@ -3860,78 +3901,78 @@ def Rfirst0(From): """ Get first xref from 'From' """ - return idaapi.get_first_fcref_from(From) + return ida_xref.get_first_fcref_from(From) def Rnext0(From, current): """ Get next xref from """ - return idaapi.get_next_fcref_from(From, current) + return ida_xref.get_next_fcref_from(From, current) def RfirstB0(To): """ Get first xref to 'To' """ - return idaapi.get_first_fcref_to(To) + return ida_xref.get_first_fcref_to(To) def RnextB0(To, current): """ Get next xref to 'To' """ - return idaapi.get_next_fcref_to(To, current) + return ida_xref.get_next_fcref_to(To, current) # Data reference types (combine with XREF_USER!): -dr_O = idaapi.dr_O # Offset -dr_W = idaapi.dr_W # Write -dr_R = idaapi.dr_R # Read -dr_T = idaapi.dr_T # Text (names in manual operands) -dr_I = idaapi.dr_I # Informational +dr_O = ida_xref.dr_O # Offset +dr_W = ida_xref.dr_W # Write +dr_R = ida_xref.dr_R # Read +dr_T = ida_xref.dr_T # Text (names in manual operands) +dr_I = ida_xref.dr_I # Informational def add_dref(From, To, drefType): """ Create Data Ref """ - return idaapi.add_dref(From, To, drefType) + return ida_xref.add_dref(From, To, drefType) def del_dref(From, To): """ Unmark Data Ref """ - return idaapi.del_dref(From, To) + return ida_xref.del_dref(From, To) def Dfirst(From): """ Get first data xref from 'From' """ - return idaapi.get_first_dref_from(From) + return ida_xref.get_first_dref_from(From) def Dnext(From, current): """ Get next data xref from 'From' """ - return idaapi.get_next_dref_from(From, current) + return ida_xref.get_next_dref_from(From, current) def DfirstB(To): """ Get first data xref to 'To' """ - return idaapi.get_first_dref_to(To) + return ida_xref.get_first_dref_to(To) def DnextB(To, current): """ Get next data xref to 'To' """ - return idaapi.get_next_dref_to(To, current) + return ida_xref.get_next_dref_to(To, current) def XrefType(): @@ -3974,11 +4015,11 @@ def LoadFile(filepath, pos, ea, size): @return: 0 - error, 1 - ok """ - li = idaapi.open_linput(filepath, False) + li = ida_diskio.open_linput(filepath, False) if li: - retval = idaapi.file2base(li, pos, ea, ea+size, False) - idaapi.close_linput(li) + retval = ida_loader.file2base(li, pos, ea, ea+size, False) + ida_diskio.close_linput(li) return retval else: return 0 @@ -3998,14 +4039,14 @@ def SaveFile(filepath, pos, ea, size): @return: 0 - error, 1 - ok """ if ( os.path.isfile(filepath) ): - of = idaapi.fopenM(filepath) + of = ida_diskio.fopenM(filepath) else: - of = idaapi.fopenWB(filepath) + of = ida_diskio.fopenWB(filepath) if of: - retval = idaapi.base2file(of, pos, ea, ea+size) - idaapi.eclose(of) + retval = ida_loader.base2file(of, pos, ea, ea+size) + ida_diskio.eclose(of) return retval else: return 0 @@ -4044,7 +4085,7 @@ def writestr(handle, s): # F U N C T I O N S # ---------------------------------------------------------------------------- -def MakeFunction(start, end = idaapi.BADADDR): +def MakeFunction(start, end = ida_idaapi.BADADDR): """ Create a function @@ -4060,7 +4101,7 @@ def MakeFunction(start, end = idaapi.BADADDR): @note: an instruction should be present at the start address """ - return idaapi.add_func(start, end) + return ida_funcs.add_func(start, end) def DelFunction(ea): @@ -4071,7 +4112,7 @@ def DelFunction(ea): @return: !=0 - ok """ - return idaapi.del_func(ea) + return ida_funcs.del_func(ea) def SetFunctionEnd(ea, end): @@ -4083,7 +4124,7 @@ def SetFunctionEnd(ea, end): @return: !=0 - ok """ - return idaapi.func_setend(ea, end) + return ida_funcs.func_setend(ea, end) def NextFunction(ea): @@ -4095,7 +4136,7 @@ def NextFunction(ea): @return: BADADDR - no more functions otherwise returns the next function start address """ - func = idaapi.get_next_func(ea) + func = ida_funcs.get_next_func(ea) if not func: return BADADDR @@ -4112,7 +4153,7 @@ def PrevFunction(ea): @return: BADADDR - no more functions otherwise returns the previous function start address """ - func = idaapi.get_prev_func(ea) + func = ida_funcs.get_prev_func(ea) if not func: return BADADDR @@ -4129,7 +4170,7 @@ def GetFunctionAttr(ea, attr): @return: BADADDR - error otherwise returns the attribute value """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) return _IDC_GetAttr(func, _FUNCATTRMAP, attr) if func else BADADDR @@ -4144,11 +4185,11 @@ def SetFunctionAttr(ea, attr, value): @return: 1-ok, 0-failed """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if func: _IDC_SetAttr(func, _FUNCATTRMAP, attr, value) - return idaapi.update_func(func) + return ida_funcs.update_func(func) return 0 @@ -4202,7 +4243,7 @@ def GetFunctionFlags(ea): @return: -1 - function doesn't exist otherwise returns the flags """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return -1 @@ -4210,33 +4251,33 @@ def GetFunctionFlags(ea): return func.flags -FUNC_NORET = idaapi.FUNC_NORET # function doesn't return -FUNC_FAR = idaapi.FUNC_FAR # far function -FUNC_LIB = idaapi.FUNC_LIB # library function -FUNC_STATIC = idaapi.FUNC_STATICDEF # static function -FUNC_FRAME = idaapi.FUNC_FRAME # function uses frame pointer (BP) -FUNC_USERFAR = idaapi.FUNC_USERFAR # user has specified far-ness - # of the function -FUNC_HIDDEN = idaapi.FUNC_HIDDEN # a hidden function -FUNC_THUNK = idaapi.FUNC_THUNK # thunk (jump) function -FUNC_BOTTOMBP = idaapi.FUNC_BOTTOMBP # BP points to the bottom of the stack frame -FUNC_NORET_PENDING = idaapi.FUNC_NORET_PENDING # Function 'non-return' analysis - # must be performed. This flag is - # verified upon func_does_return() -FUNC_SP_READY = idaapi.FUNC_SP_READY # SP-analysis has been performed - # If this flag is on, the stack - # change points should not be not - # modified anymore. Currently this - # analysis is performed only for PC -FUNC_PURGED_OK = idaapi.FUNC_PURGED_OK # 'argsize' field has been validated. - # If this bit is clear and 'argsize' - # is 0, then we do not known the real - # number of bytes removed from - # the stack. This bit is handled - # by the processor module. -FUNC_TAIL = idaapi.FUNC_TAIL # This is a function tail. - # Other bits must be clear - # (except FUNC_HIDDEN) +FUNC_NORET = ida_funcs.FUNC_NORET # function doesn't return +FUNC_FAR = ida_funcs.FUNC_FAR # far function +FUNC_LIB = ida_funcs.FUNC_LIB # library function +FUNC_STATIC = ida_funcs.FUNC_STATICDEF # static function +FUNC_FRAME = ida_funcs.FUNC_FRAME # function uses frame pointer (BP) +FUNC_USERFAR = ida_funcs.FUNC_USERFAR # user has specified far-ness + # of the function +FUNC_HIDDEN = ida_funcs.FUNC_HIDDEN # a hidden function +FUNC_THUNK = ida_funcs.FUNC_THUNK # thunk (jump) function +FUNC_BOTTOMBP = ida_funcs.FUNC_BOTTOMBP # BP points to the bottom of the stack frame +FUNC_NORET_PENDING = ida_funcs.FUNC_NORET_PENDING # Function 'non-return' analysis + # must be performed. This flag is + # verified upon func_does_return() +FUNC_SP_READY = ida_funcs.FUNC_SP_READY # SP-analysis has been performed + # If this flag is on, the stack + # change points should not be not + # modified anymore. Currently this + # analysis is performed only for PC +FUNC_PURGED_OK = ida_funcs.FUNC_PURGED_OK # 'argsize' field has been validated. + # If this bit is clear and 'argsize' + # is 0, then we do not known the real + # number of bytes removed from + # the stack. This bit is handled + # by the processor module. +FUNC_TAIL = ida_funcs.FUNC_TAIL # This is a function tail. + # Other bits must be clear + # (except FUNC_HIDDEN) def SetFunctionFlags(ea, flags): @@ -4248,13 +4289,13 @@ def SetFunctionFlags(ea, flags): @return: !=0 - ok """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return 0 else: func.flags = flags - idaapi.update_func(func) + ida_funcs.update_func(func) return 1 @@ -4267,7 +4308,7 @@ def GetFunctionName(ea): @return: null string - function doesn't exist otherwise returns function name """ - name = idaapi.get_func_name(ea) + name = ida_funcs.get_func_name(ea) if not name: return "" @@ -4285,12 +4326,12 @@ def GetFunctionCmt(ea, repeatable): @return: function comment string """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return "" else: - comment = idaapi.get_func_cmt(func, repeatable) + comment = ida_funcs.get_func_cmt(func, repeatable) if not comment: return "" @@ -4307,12 +4348,12 @@ def SetFunctionCmt(ea, cmt, repeatable): @param repeatable: 1: get repeatable comment 0: get regular comment """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return None else: - return idaapi.set_func_cmt(func, cmt, repeatable) + return ida_funcs.set_func_cmt(func, cmt, repeatable) def ChooseFunction(title): @@ -4326,7 +4367,7 @@ def ChooseFunction(title): @return: -1 - user refused to select a function otherwise returns the selected function start address """ - f = idaapi.choose_func(title, idaapi.BADADDR) + f = ida_kernwin.choose_func(title, ida_idaapi.BADADDR) return BADADDR if f is None else f.startEA @@ -4340,7 +4381,7 @@ def GetFuncOffset(ea): formed as 'name+offset' where 'name' is a function name 'offset' is offset within the function else return null string """ - return idaapi.a2funcoff(ea) + return ida_funcs.a2funcoff(ea) def FindFuncEnd(ea): @@ -4353,11 +4394,11 @@ def FindFuncEnd(ea): If a function end cannot be determined, the return BADADDR otherwise return the end address of the new function """ - func = idaapi.func_t() + func = ida_funcs.func_t() - res = idaapi.find_func_bounds(ea, func, idaapi.FIND_FUNC_DEFINE) + res = ida_funcs.find_func_bounds(ea, func, ida_funcs.FIND_FUNC_DEFINE) - if res == idaapi.FIND_FUNC_UNDEF: + if res == ida_funcs.FIND_FUNC_UNDEF: return BADADDR else: return func.endEA @@ -4373,7 +4414,7 @@ def GetFrame(ea): you need to use structure member manipulaion functions with the obtained ID. """ - frame = idaapi.get_frame(ea) + frame = ida_frame.get_frame(ea) if frame: return frame.id @@ -4434,12 +4475,12 @@ def GetFrameSize(ea): function return address in the stack. If the function does't exist, return 0 """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return 0 else: - return idaapi.get_frame_size(func) + return ida_frame.get_frame_size(func) def MakeFrame(ea, lvsize, frregs, argsize): @@ -4455,14 +4496,14 @@ def MakeFrame(ea, lvsize, frregs, argsize): If the function did not have a frame, the frame will be created. Otherwise the frame will be modified """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if func is None: return -1 - frameid = idaapi.add_frame(func, lvsize, frregs, argsize) + frameid = ida_frame.add_frame(func, lvsize, frregs, argsize) if not frameid: - if not idaapi.set_frame_size(func, lvsize, frregs, argsize): + if not ida_frame.set_frame_size(func, lvsize, frregs, argsize): return -1 return func.frame @@ -4478,12 +4519,12 @@ def GetSpd(ea): @return: The difference between the original SP upon entering the function and SP for the specified address """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return None - return idaapi.get_spd(func, ea) + return ida_frame.get_spd(func, ea) def GetSpDiff(ea): @@ -4497,12 +4538,12 @@ def GetSpDiff(ea): If the specified location doesn't contain a SP change point, return 0 Otherwise return delta of SP modification """ - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if not func: return None - return idaapi.get_sp_delta(func, ea) + return ida_frame.get_sp_delta(func, ea) def SetSpDiff(ea, delta): @@ -4515,7 +4556,7 @@ def SetSpDiff(ea, delta): @return: 1-ok, 0-failed """ - return idaapi.add_user_stkpnt(ea, delta) + return ida_frame.add_user_stkpnt(ea, delta) # ---------------------------------------------------------------------------- @@ -4532,10 +4573,10 @@ def AddAutoStkPnt2(func_ea, ea, delta): @param delta: difference between old and new values of SP @return: 1-ok, 0-failed """ - pfn = idaapi.get_func(func_ea) + pfn = ida_funcs.get_func(func_ea) if not pfn: return 0 - return idaapi.add_auto_stkpnt2(pfn, ea, delta) + return ida_frame.add_auto_stkpnt2(pfn, ea, delta) def AddUserStkPnt(ea, delta): """ @@ -4546,7 +4587,7 @@ def AddUserStkPnt(ea, delta): @return: 1-ok, 0-failed """ - return idaapi.add_user_stkpnt(ea, delta); + return ida_frame.add_user_stkpnt(ea, delta); def DelStkPnt(func_ea, ea): """ @@ -4556,10 +4597,10 @@ def DelStkPnt(func_ea, ea): @param ea: linear address @return: 1-ok, 0-failed """ - pfn = idaapi.get_func(func_ea) + pfn = ida_funcs.get_func(func_ea) if not pfn: return 0 - return idaapi.del_stkpnt(pfn, ea) + return ida_frame.del_stkpnt(pfn, ea) def GetMinSpd(func_ea): """ @@ -4569,10 +4610,10 @@ def GetMinSpd(func_ea): @param func_ea: function start @return: BADDADDR - no such function """ - pfn = idaapi.get_func(func_ea) + pfn = ida_funcs.get_func(func_ea) if not pfn: return BADADDR - return idaapi.get_min_spd_ea(pfn) + return ida_frame.get_min_spd_ea(pfn) def RecalcSpd(cur_ea): """ @@ -4581,7 +4622,7 @@ def RecalcSpd(cur_ea): @param cur_ea: linear address of the current instruction @return: 1 - new stkpnt is added, 0 - nothing is changed """ - return idaapi.recalc_spd(cur_ea) + return ida_frame.recalc_spd(cur_ea) @@ -4597,7 +4638,7 @@ def GetEntryPointQty(): @returns: number of entry points """ - return idaapi.get_entry_qty() + return ida_entry.get_entry_qty() def AddEntryPoint(ordinal, ea, name, makecode): @@ -4616,7 +4657,7 @@ def AddEntryPoint(ordinal, ea, name, makecode): @return: 0 - entry point with the specifed ordinal already exists 1 - ok """ - return idaapi.add_entry(ordinal, ea, name, makecode) + return ida_entry.add_entry(ordinal, ea, name, makecode) def GetEntryOrdinal(index): @@ -4628,7 +4669,7 @@ def GetEntryOrdinal(index): @return: 0 if entry point doesn't exist otherwise entry point ordinal """ - return idaapi.get_entry_ordinal(index) + return ida_entry.get_entry_ordinal(index) def GetEntryPoint(ordinal): @@ -4643,7 +4684,7 @@ def GetEntryPoint(ordinal): If entry point address is equal to its ordinal number, then the entry point has no ordinal. """ - return idaapi.get_entry(ordinal) + return ida_entry.get_entry(ordinal) def GetEntryName(ordinal): @@ -4654,7 +4695,7 @@ def GetEntryName(ordinal): @return: entry point name or None """ - return idaapi.get_entry_name(ordinal) + return ida_entry.get_entry_name(ordinal) def RenameEntryPoint(ordinal, name): @@ -4666,7 +4707,7 @@ def RenameEntryPoint(ordinal, name): @return: !=0 - ok """ - return idaapi.rename_entry(ordinal, name) + return ida_entry.rename_entry(ordinal, name) # ---------------------------------------------------------------------------- @@ -4681,7 +4722,7 @@ def GetNextFixupEA(ea): @return: BADADDR - no more fixups otherwise returns the next address with fixup information """ - return idaapi.get_next_fixup_ea(ea) + return ida_fixup.get_next_fixup_ea(ea) def GetPrevFixupEA(ea): @@ -4693,7 +4734,7 @@ def GetPrevFixupEA(ea): @return: BADADDR - no more fixups otherwise returns the previous address with fixup information """ - return idaapi.get_prev_fixup_ea(ea) + return ida_fixup.get_prev_fixup_ea(ea) def GetFixupTgtType(ea): @@ -4705,9 +4746,9 @@ def GetFixupTgtType(ea): @return: -1 - no fixup at the specified address otherwise returns fixup target type: """ - fd = idaapi.fixup_data_t() + fd = ida_fixup.fixup_data_t() - if not idaapi.get_fixup(ea, fd): + if not ida_fixup.get_fixup(ea, fd): return -1 return fd.type @@ -4751,9 +4792,9 @@ def GetFixupTgtSel(ea): @return: -1 - no fixup at the specified address otherwise returns fixup target selector """ - fd = idaapi.fixup_data_t() + fd = ida_fixup.fixup_data_t() - if not idaapi.get_fixup(ea, fd): + if not ida_fixup.get_fixup(ea, fd): return -1 return fd.sel @@ -4768,9 +4809,9 @@ def GetFixupTgtOff(ea): @return: -1 - no fixup at the specified address otherwise returns fixup target offset """ - fd = idaapi.fixup_data_t() + fd = ida_fixup.fixup_data_t() - if not idaapi.get_fixup(ea, fd): + if not ida_fixup.get_fixup(ea, fd): return -1 return fd.off @@ -4785,9 +4826,9 @@ def GetFixupTgtDispl(ea): @return: -1 - no fixup at the specified address otherwise returns fixup target displacement """ - fd = idaapi.fixup_data_t() + fd = ida_fixup.fixup_data_t() - if not idaapi.get_fixup(ea, fd): + if not ida_fixup.get_fixup(ea, fd): return -1 return fd.displacement @@ -4806,13 +4847,13 @@ def SetFixup(ea, fixuptype, targetsel, targetoff, displ): @return: none """ - fd = idaapi.fixup_data_t() + fd = ida_fixup.fixup_data_t() fd.type = fixuptype fd.sel = targetsel fd.off = targetoff fd.displacement = displ - idaapi.set_fixup(ea, fd) + ida_fixup.set_fixup(ea, fd) def DelFixup(ea): @@ -4823,7 +4864,7 @@ def DelFixup(ea): @return: None """ - idaapi.del_fixup(ea) + ida_fixup.del_fixup(ea) #---------------------------------------------------------------------------- @@ -4845,7 +4886,7 @@ def MarkPosition(ea, lnnum, x, y, slot, comment): @return: None """ - curloc = idaapi.curloc() + curloc = ida_moves.curloc() curloc.ea = ea curloc.lnnum = lnnum curloc.x = x @@ -4863,8 +4904,8 @@ def GetMarkedPos(slot): @return: BADADDR - the slot doesn't contain a marked address otherwise returns the marked address """ - curloc = idaapi.curloc() - intp = idaapi.int_pointer() + curloc = ida_moves.curloc() + intp = ida_pro.int_pointer() intp.assign(slot) return curloc.markedpos(intp) @@ -4878,7 +4919,7 @@ def GetMarkComment(slot): @return: None if the slot doesn't contain a marked address otherwise returns the marked address comment """ - curloc = idaapi.curloc() + curloc = ida_moves.curloc() return curloc.markdesc(slot) @@ -4892,7 +4933,7 @@ def GetStrucQty(): @return: number of structure types """ - return idaapi.get_struc_qty() + return ida_struct.get_struc_qty() def GetFirstStrucIdx(): @@ -4913,7 +4954,7 @@ def GetFirstStrucIdx(): can't be changed. Even when the structure type gets deleted, its ID won't be resued in the future. """ - return idaapi.get_first_struc_idx() + return ida_struct.get_first_struc_idx() def GetLastStrucIdx(): @@ -4925,7 +4966,7 @@ def GetLastStrucIdx(): See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - return idaapi.get_last_struc_idx() + return ida_struct.get_last_struc_idx() def GetNextStrucIdx(index): @@ -4939,7 +4980,7 @@ def GetNextStrucIdx(index): See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - return idaapi.get_next_struc_idx(index) + return ida_struct.get_next_struc_idx(index) def GetPrevStrucIdx(index): @@ -4953,7 +4994,7 @@ def GetPrevStrucIdx(index): See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - return idaapi.get_prev_struc_idx(index) + return ida_struct.get_prev_struc_idx(index) def GetStrucIdx(sid): @@ -4967,7 +5008,7 @@ def GetStrucIdx(sid): See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - return idaapi.get_struc_idx(sid) + return ida_struct.get_struc_idx(sid) def GetStrucId(index): @@ -4980,7 +5021,7 @@ def GetStrucId(index): @note: See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - return idaapi.get_struc_by_idx(index) + return ida_struct.get_struc_by_idx(index) def GetStrucIdByName(name): @@ -4992,7 +5033,7 @@ def GetStrucIdByName(name): @return: BADADDR if bad structure type name is passed otherwise returns structure ID. """ - return idaapi.get_struc_id(name) + return ida_struct.get_struc_id(name) def GetStrucName(sid): @@ -5004,7 +5045,7 @@ def GetStrucName(sid): @return: None if bad structure type ID is passed otherwise returns structure type name. """ - return idaapi.get_struc_name(sid) + return ida_struct.get_struc_name(sid) def GetStrucComment(sid, repeatable): @@ -5018,7 +5059,7 @@ def GetStrucComment(sid, repeatable): @return: None if bad structure type ID is passed otherwise returns comment. """ - return idaapi.get_struc_cmt(sid, repeatable) + return ida_struct.get_struc_cmt(sid, repeatable) def GetStrucSize(sid): @@ -5030,7 +5071,7 @@ def GetStrucSize(sid): @return: 0 if bad structure type ID is passed otherwise returns size of structure in bytes. """ - return idaapi.get_struc_size(sid) + return ida_struct.get_struc_size(sid) def GetMemberQty(sid): @@ -5046,7 +5087,7 @@ def GetMemberQty(sid): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) return -1 if not s else s.memqty @@ -5063,11 +5104,11 @@ def GetMemberId(sid, member_offset): no member at the specified offset. otherwise returns the member id. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return -1 @@ -5082,7 +5123,7 @@ def GetStrucPrevOff(sid, offset): @param offset: current offset @return: -1 if bad structure type ID is passed, - idaapi.BADADDR if no (more) offsets in the structure, + ida_idaapi.BADADDR if no (more) offsets in the structure, otherwise returns previous offset in a structure. @note: IDA allows 'holes' between members of a @@ -5096,11 +5137,11 @@ def GetStrucPrevOff(sid, offset): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - return idaapi.get_struc_prev_offset(s, offset) + return ida_struct.get_struc_prev_offset(s, offset) def GetStrucNextOff(sid, offset): @@ -5111,7 +5152,7 @@ def GetStrucNextOff(sid, offset): @param offset: current offset @return: -1 if bad structure type ID is passed, - idaapi.BADADDR if no (more) offsets in the structure, + ida_idaapi.BADADDR if no (more) offsets in the structure, otherwise returns next offset in a structure. @note: IDA allows 'holes' between members of a @@ -5125,8 +5166,8 @@ def GetStrucNextOff(sid, offset): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) - return -1 if not s else idaapi.get_struc_next_offset(s, offset) + s = ida_struct.get_struc(sid) + return -1 if not s else ida_struct.get_struc_next_offset(s, offset) def GetFirstMember(sid): @@ -5136,7 +5177,7 @@ def GetFirstMember(sid): @param sid: structure type ID @return: -1 if bad structure type ID is passed, - idaapi.BADADDR if structure has no members, + ida_idaapi.BADADDR if structure has no members, otherwise returns offset of the first member. @note: IDA allows 'holes' between members of a @@ -5147,11 +5188,11 @@ def GetFirstMember(sid): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - return idaapi.get_struc_first_offset(s) + return ida_struct.get_struc_first_offset(s) def GetLastMember(sid): @@ -5161,7 +5202,7 @@ def GetLastMember(sid): @param sid: structure type ID @return: -1 if bad structure type ID is passed, - idaapi.BADADDR if structure has no members, + ida_idaapi.BADADDR if structure has no members, otherwise returns offset of the last member. @note: IDA allows 'holes' between members of a @@ -5172,11 +5213,11 @@ def GetLastMember(sid): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - return idaapi.get_struc_last_offset(s) + return ida_struct.get_struc_last_offset(s) def GetMemberOffset(sid, member_name): @@ -5194,11 +5235,11 @@ def GetMemberOffset(sid, member_name): at subsequent byte offsets: member 0 -> offset 0x0, member 1 -> offset 0x1, etc... """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - m = idaapi.get_member_by_name(s, member_name) + m = ida_struct.get_member_by_name(s, member_name) if not m: return -1 @@ -5220,15 +5261,15 @@ def GetMemberName(sid, member_offset): or no such member in the structure otherwise returns name of the specified member. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return None - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return None - return idaapi.get_member_name(m.id) + return ida_struct.get_member_name(m.id) def GetMemberComment(sid, member_offset, repeatable): @@ -5248,15 +5289,15 @@ def GetMemberComment(sid, member_offset, repeatable): or no such member in the structure otherwise returns comment of the specified member. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return None - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return None - return idaapi.get_member_cmt(m.id, repeatable) + return ida_struct.get_member_cmt(m.id, repeatable) def GetMemberSize(sid, member_offset): @@ -5275,15 +5316,15 @@ def GetMemberSize(sid, member_offset): otherwise returns size of the specified member in bytes. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return None - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return None - return idaapi.get_member_size(m) + return ida_struct.get_member_size(m) def GetMemberFlag(sid, member_offset): @@ -5304,11 +5345,11 @@ def GetMemberFlag(sid, member_offset): then function GetMemberStrid() should be used to get the structure type id. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) return -1 if not m else m.flag @@ -5327,15 +5368,15 @@ def GetMemberStrId(sid, member_offset): otherwise returns structure id of the member. If the current member is not a structure, returns -1. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return -1 - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return -1 - cs = idaapi.get_sptr(m) + cs = ida_struct.get_sptr(m) if cs: return cs.id else: @@ -5353,7 +5394,7 @@ def IsUnion(sid): @note: Unions are a special kind of structures """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 @@ -5384,7 +5425,7 @@ def AddStrucEx(index, name, is_union): if index == -1: index = BADADDR - return idaapi.add_struc(index, name, is_union) + return ida_struct.add_struc(index, name, is_union) def DelStruc(sid): @@ -5399,11 +5440,11 @@ def DelStruc(sid): deleted structure type will be displayed as array of bytes. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - return idaapi.del_struc(s) + return ida_struct.del_struc(s) def SetStrucIdx(sid, index): @@ -5418,11 +5459,11 @@ def SetStrucIdx(sid, index): @note: See GetFirstStrucIdx() for the explanation of structure indices and IDs. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - return idaapi.set_struc_idx(s, index) + return ida_struct.set_struc_idx(s, index) def SetStrucName(sid, name): @@ -5434,7 +5475,7 @@ def SetStrucName(sid, name): @return: != 0 - ok """ - return idaapi.set_struc_name(sid, name) + return ida_struct.set_struc_name(sid, name) def SetStrucComment(sid, comment, repeatable): @@ -5447,7 +5488,7 @@ def SetStrucComment(sid, comment, repeatable): 0: change regular comment @return: != 0 - ok """ - return idaapi.set_struc_cmt(sid, comment, repeatable) + return ida_struct.set_struc_cmt(sid, comment, repeatable) def AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, reftype=REF_OFF32): @@ -5481,10 +5522,10 @@ def AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, """ if isOff0(flag): - return Eval('AddStrucMember(%d, "%s", %d, %d, %d, %d, %d, %d, %d);' % (sid, idaapi.str2user(name), offset, flag, typeid, nbytes, + return Eval('AddStrucMember(%d, "%s", %d, %d, %d, %d, %d, %d, %d);' % (sid, ida_kernwin.str2user(name), offset, flag, typeid, nbytes, target, tdelta, reftype)) else: - return Eval('AddStrucMember(%d, "%s", %d, %d, %d, %d);' % (sid, idaapi.str2user(name), offset, flag, typeid, nbytes)) + return Eval('AddStrucMember(%d, "%s", %d, %d, %d, %d);' % (sid, ida_kernwin.str2user(name), offset, flag, typeid, nbytes)) STRUC_ERROR_MEMBER_NAME = -1 # already has member with this name (bad name) @@ -5509,11 +5550,11 @@ def DelStrucMember(sid, member_offset): structure. It treats these 'holes' as unnamed arrays of bytes. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - return idaapi.del_struc_member(s, member_offset) + return ida_struct.del_struc_member(s, member_offset) def SetMemberName(sid, member_offset, name): @@ -5526,11 +5567,11 @@ def SetMemberName(sid, member_offset, name): @return: != 0 - ok. """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - return idaapi.set_member_name(s, member_offset, name) + return ida_struct.set_member_name(s, member_offset, name) def SetMemberType(sid, member_offset, flag, typeid, nitems, target=-1, tdelta=0, reftype=REF_OFF32): @@ -5579,15 +5620,15 @@ def SetMemberComment(sid, member_offset, comment, repeatable): @return: != 0 - ok """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - m = idaapi.get_member(s, member_offset) + m = ida_struct.get_member(s, member_offset) if not m: return 0 - return idaapi.set_member_cmt(m, comment, repeatable) + return ida_struct.set_member_cmt(m, comment, repeatable) def ExpandStruc(sid, offset, delta, recalc): @@ -5600,11 +5641,11 @@ def ExpandStruc(sid, offset, delta, recalc): type is used @return: != 0 - ok """ - s = idaapi.get_struc(sid) + s = ida_struct.get_struc(sid) if not s: return 0 - return idaapi.expand_struc(s, offset, delta, recalc) + return ida_struct.expand_struc(s, offset, delta, recalc) def GetFchunkAttr(ea, attr): @@ -5616,7 +5657,7 @@ def GetFchunkAttr(ea, attr): @return: desired attribute or -1 """ - func = idaapi.get_fchunk(ea) + func = ida_funcs.get_fchunk(ea) return _IDC_GetAttr(func, _FUNCATTRMAP, attr) if func else BADADDR @@ -5631,10 +5672,10 @@ def SetFchunkAttr(ea, attr, value): @return: 0 if failed, 1 if success """ if attr in [ FUNCATTR_START, FUNCATTR_END, FUNCATTR_OWNER ]: - chunk = idaapi.get_fchunk(ea) + chunk = ida_funcs.get_fchunk(ea) if chunk: _IDC_SetAttr(chunk, _FUNCATTRMAP, attr, value) - return idaapi.update_func(chunk) + return ida_funcs.update_func(chunk) return 0 @@ -5647,7 +5688,7 @@ def GetFchunkReferer(ea, idx): @return: referer address or BADADDR """ - return idaapi.get_fchunk_referer(ea, idx) + return ida_funcs.get_fchunk_referer(ea, idx) def NextFchunk(ea): @@ -5660,7 +5701,7 @@ def NextFchunk(ea): @note: This function enumerates all chunks of all functions in the database """ - func = idaapi.get_next_fchunk(ea) + func = ida_funcs.get_next_fchunk(ea) if func: return func.startEA @@ -5678,7 +5719,7 @@ def PrevFchunk(ea): @note: This function enumerates all chunks of all functions in the database """ - func = idaapi.get_prev_fchunk(ea) + func = ida_funcs.get_prev_fchunk(ea) if func: return func.startEA @@ -5698,12 +5739,12 @@ def AppendFchunk(funcea, ea1, ea2): @note: If a chunk exists at the specified addresses, it must have exactly the specified boundaries """ - func = idaapi.get_func(funcea) + func = ida_funcs.get_func(funcea) if not func: return 0 else: - return idaapi.append_func_tail(func, ea1, ea2) + return ida_funcs.append_func_tail(func, ea1, ea2) def RemoveFchunk(funcea, tailea): @@ -5715,12 +5756,12 @@ def RemoveFchunk(funcea, tailea): @return: 0 if failed, 1 if success """ - func = idaapi.get_func(funcea) + func = ida_funcs.get_func(funcea) if not func: return 0 else: - return idaapi.remove_func_tail(func, tailea) + return ida_funcs.remove_func_tail(func, tailea) def SetFchunkOwner(tailea, funcea): @@ -5730,16 +5771,16 @@ def SetFchunkOwner(tailea, funcea): @param tailea: any address in the function chunk @param funcea: the starting address of the new owner - @return: 0 if failed, 1 if success + @return: False if failed, True if success @note: The new owner must already have the chunk appended before the call """ - tail = idaapi.get_func(tailea) + tail = ida_funcs.get_fchunk(tailea) if not tail: - return 0 + return False else: - return idaapi.set_tail_owner(tail, funcea) + return ida_funcs.set_tail_owner(tail, funcea) def FirstFuncFchunk(funcea): @@ -5752,8 +5793,8 @@ def FirstFuncFchunk(funcea): @note: This function returns the first (main) chunk of the specified function """ - func = idaapi.get_func(funcea) - fci = idaapi.func_tail_iterator_t(func, funcea) + func = ida_funcs.get_func(funcea) + fci = ida_funcs.func_tail_iterator_t(func, funcea) if fci.main(): return fci.chunk().startEA else: @@ -5771,8 +5812,8 @@ def NextFuncFchunk(funcea, tailea): @note: This function returns the next chunk of the specified function """ - func = idaapi.get_func(funcea) - fci = idaapi.func_tail_iterator_t(func, funcea) + func = ida_funcs.get_func(funcea) + fci = ida_funcs.func_tail_iterator_t(func, funcea) if not fci.main(): return BADADDR @@ -5802,7 +5843,7 @@ def GetEnumQty(): @return: number of enumerations """ - return idaapi.get_enum_qty() + return ida_enum.get_enum_qty() def GetnEnum(idx): @@ -5813,7 +5854,7 @@ def GetnEnum(idx): @return: ID of enum or -1 if error """ - return idaapi.getn_enum(idx) + return ida_enum.getn_enum(idx) def GetEnumIdx(enum_id): @@ -5824,7 +5865,7 @@ def GetEnumIdx(enum_id): @return: (0..GetEnumQty()-1) or -1 if error """ - return idaapi.get_enum_idx(enum_id) + return ida_enum.get_enum_idx(enum_id) def GetEnum(name): @@ -5836,7 +5877,7 @@ def GetEnum(name): returns: ID of enum or -1 if no such enum exists """ - return idaapi.get_enum(name) + return ida_enum.get_enum(name) def GetEnumName(enum_id): @@ -5847,7 +5888,7 @@ def GetEnumName(enum_id): @return: name of enum or empty string """ - return idaapi.get_enum_name(enum_id) + return ida_enum.get_enum_name(enum_id) def GetEnumCmt(enum_id, repeatable): @@ -5860,7 +5901,7 @@ def GetEnumCmt(enum_id, repeatable): @return: comment of enum """ - return idaapi.get_enum_cmt(enum_id, repeatable) + return ida_enum.get_enum_cmt(enum_id, repeatable) def GetEnumSize(enum_id): @@ -5872,7 +5913,7 @@ def GetEnumSize(enum_id): @return: number of constants in the enum Returns 0 if enum_id is bad. """ - return idaapi.get_enum_size(enum_id) + return ida_enum.get_enum_size(enum_id) def GetEnumWidth(enum_id): @@ -5886,7 +5927,7 @@ def GetEnumWidth(enum_id): 1-1byte,2-2bytes,3-4bytes,4-8bytes,etc Returns 0 if enum_id is bad or the width is unknown. """ - return idaapi.get_enum_width(enum_id) + return ida_enum.get_enum_width(enum_id) def GetEnumFlag(enum_id): @@ -5901,7 +5942,7 @@ def GetEnumFlag(enum_id): more information about flags. Returns 0 if enum_id is bad. """ - return idaapi.get_enum_flag(enum_id) + return ida_enum.get_enum_flag(enum_id) def GetConstByName(name): @@ -5912,7 +5953,7 @@ def GetConstByName(name): @return: ID of constant or -1 """ - return idaapi.get_enum_member_by_name(name) + return ida_enum.get_enum_member_by_name(name) def GetConstValue(const_id): @@ -5923,7 +5964,7 @@ def GetConstValue(const_id): @return: value of constant or 0 """ - return idaapi.get_enum_member_value(const_id) + return ida_enum.get_enum_member_value(const_id) def GetConstBmask(const_id): @@ -5935,7 +5976,7 @@ def GetConstBmask(const_id): @return: bitmask of constant or 0 ordinary enums have bitmask = -1 """ - return idaapi.get_enum_member_bmask(const_id) + return ida_enum.get_enum_member_bmask(const_id) def GetConstEnum(const_id): @@ -5947,7 +5988,7 @@ def GetConstEnum(const_id): @return: id of enum the constant belongs to. -1 if const_id is bad. """ - return idaapi.get_enum_member_enum(const_id) + return ida_enum.get_enum_member_enum(const_id) def GetConstEx(enum_id, value, serial, bmask): @@ -5965,7 +6006,7 @@ def GetConstEx(enum_id, value, serial, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_enum_member(enum_id, value, serial, bmask) + return ida_enum.get_enum_member(enum_id, value, serial, bmask) def GetFirstBmask(enum_id): @@ -5979,7 +6020,7 @@ def GetFirstBmask(enum_id): All bitmasks are sorted by their values as unsigned longs. """ - return idaapi.get_first_bmask(enum_id) + return ida_enum.get_first_bmask(enum_id) def GetLastBmask(enum_id): @@ -5991,7 +6032,7 @@ def GetLastBmask(enum_id): @return: the biggest bitmask or -1 no bitmasks are defined yet All bitmasks are sorted by their values as unsigned longs. """ - return idaapi.get_last_bmask(enum_id) + return ida_enum.get_last_bmask(enum_id) def GetNextBmask(enum_id, value): @@ -6006,7 +6047,7 @@ def GetNextBmask(enum_id, value): All bitmasks are sorted by their values as unsigned longs. """ - return idaapi.get_next_bmask(enum_id, value) + return ida_enum.get_next_bmask(enum_id, value) def GetPrevBmask(enum_id, value): @@ -6020,7 +6061,7 @@ def GetPrevBmask(enum_id, value): value. -1 no such bitmasks exist. All bitmasks are sorted by their values as unsigned longs. """ - return idaapi.get_prev_bmask(enum_id, value) + return ida_enum.get_prev_bmask(enum_id, value) def GetBmaskName(enum_id, bmask): @@ -6034,7 +6075,7 @@ def GetBmaskName(enum_id, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_bmask_name(enum_id, bmask) + return ida_enum.get_bmask_name(enum_id, bmask) def GetBmaskCmt(enum_id, bmask, repeatable): @@ -6049,7 +6090,7 @@ def GetBmaskCmt(enum_id, bmask, repeatable): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_bmask_cmt(enum_id, bmask, repeatable) + return ida_enum.get_bmask_cmt(enum_id, bmask, repeatable) def SetBmaskName(enum_id, bmask, name): @@ -6064,7 +6105,7 @@ def SetBmaskName(enum_id, bmask, name): """ if bmask < 0: bmask &= BADADDR - return idaapi.set_bmask_name(enum_id, bmask, name) + return ida_enum.set_bmask_name(enum_id, bmask, name) def SetBmaskCmt(enum_id, bmask, cmt, repeatable): @@ -6080,7 +6121,7 @@ def SetBmaskCmt(enum_id, bmask, cmt, repeatable): """ if bmask < 0: bmask &= BADADDR - return idaapi.set_bmask_cmt(enum_id, bmask, cmt, repeatable) + return ida_enum.set_bmask_cmt(enum_id, bmask, cmt, repeatable) def GetFirstConst(enum_id, bmask): @@ -6095,7 +6136,7 @@ def GetFirstConst(enum_id, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_first_enum_member(enum_id, bmask) + return ida_enum.get_first_enum_member(enum_id, bmask) def GetLastConst(enum_id, bmask): @@ -6111,7 +6152,7 @@ def GetLastConst(enum_id, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_last_enum_member(enum_id, bmask) + return ida_enum.get_last_enum_member(enum_id, bmask) def GetNextConst(enum_id, value, bmask): @@ -6128,7 +6169,7 @@ def GetNextConst(enum_id, value, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_next_enum_member(enum_id, value, bmask) + return ida_enum.get_next_enum_member(enum_id, value, bmask) def GetPrevConst(enum_id, value, bmask): @@ -6146,7 +6187,7 @@ def GetPrevConst(enum_id, value, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.get_prev_enum_member(enum_id, value, bmask) + return ida_enum.get_prev_enum_member(enum_id, value, bmask) def GetConstName(const_id): @@ -6157,7 +6198,7 @@ def GetConstName(const_id): Returns: name of constant """ - name = idaapi.get_enum_member_name(const_id) + name = ida_enum.get_enum_member_name(const_id) if not name: return "" @@ -6174,7 +6215,7 @@ def GetConstCmt(const_id, repeatable): @return: comment string """ - cmt = idaapi.get_enum_member_cmt(const_id, repeatable) + cmt = ida_enum.get_enum_member_cmt(const_id, repeatable) if not cmt: return "" @@ -6205,7 +6246,7 @@ def AddEnum(idx, name, flag): """ if idx < 0: idx = idx & SIZE_MAX - return idaapi.add_enum(idx, name, flag) + return ida_enum.add_enum(idx, name, flag) def DelEnum(enum_id): @@ -6216,7 +6257,7 @@ def DelEnum(enum_id): @return: None """ - idaapi.del_enum(enum_id) + ida_enum.del_enum(enum_id) def SetEnumIdx(enum_id, idx): @@ -6236,7 +6277,7 @@ def SetEnumIdx(enum_id, idx): @return: comment string """ - return idaapi.set_enum_idx(enum_id, idx) + return ida_enum.set_enum_idx(enum_id, idx) def SetEnumName(enum_id, name): @@ -6248,7 +6289,7 @@ def SetEnumName(enum_id, name): @return: 1-ok,0-failed """ - return idaapi.set_enum_name(enum_id, name) + return ida_enum.set_enum_name(enum_id, name) def SetEnumCmt(enum_id, cmt, repeatable): @@ -6263,7 +6304,7 @@ def SetEnumCmt(enum_id, cmt, repeatable): @return: 1-ok,0-failed """ - return idaapi.set_enum_cmt(enum_id, cmt, repeatable) + return ida_enum.set_enum_cmt(enum_id, cmt, repeatable) def SetEnumFlag(enum_id, flag): @@ -6276,7 +6317,7 @@ def SetEnumFlag(enum_id, flag): @return: 1-ok,0-failed """ - return idaapi.set_enum_flag(enum_id, flag) + return ida_enum.set_enum_flag(enum_id, flag) def SetEnumBf(enum_id, flag): @@ -6290,7 +6331,7 @@ def SetEnumBf(enum_id, flag): @return: 1-ok,0-failed """ - return idaapi.set_enum_bf(enum_id, flag) + return ida_enum.set_enum_bf(enum_id, flag) def SetEnumWidth(enum_id, width): @@ -6304,7 +6345,7 @@ def SetEnumWidth(enum_id, width): @return: 1-ok, 0-failed """ - return idaapi.set_enum_width(enum_id, width) + return ida_enum.set_enum_width(enum_id, width) def IsBitfield(enum_id): @@ -6315,7 +6356,7 @@ def IsBitfield(enum_id): @return: 1-yes, 0-no, ordinary enum """ - return idaapi.is_bf(enum_id) + return ida_enum.is_bf(enum_id) def AddConstEx(enum_id, name, value, bmask): @@ -6333,14 +6374,14 @@ def AddConstEx(enum_id, name, value, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.add_enum_member(enum_id, name, value, bmask) + return ida_enum.add_enum_member(enum_id, name, value, bmask) -ENUM_MEMBER_ERROR_NAME = idaapi.ENUM_MEMBER_ERROR_NAME # already have member with this name (bad name) -ENUM_MEMBER_ERROR_VALUE = idaapi.ENUM_MEMBER_ERROR_VALUE # already have member with this value -ENUM_MEMBER_ERROR_ENUM = idaapi.ENUM_MEMBER_ERROR_ENUM # bad enum id -ENUM_MEMBER_ERROR_MASK = idaapi.ENUM_MEMBER_ERROR_MASK # bad bmask -ENUM_MEMBER_ERROR_ILLV = idaapi.ENUM_MEMBER_ERROR_ILLV # bad bmask and value combination (~bmask & value != 0) +ENUM_MEMBER_ERROR_NAME = ida_enum.ENUM_MEMBER_ERROR_NAME # already have member with this name (bad name) +ENUM_MEMBER_ERROR_VALUE = ida_enum.ENUM_MEMBER_ERROR_VALUE # already have member with this value +ENUM_MEMBER_ERROR_ENUM = ida_enum.ENUM_MEMBER_ERROR_ENUM # bad enum id +ENUM_MEMBER_ERROR_MASK = ida_enum.ENUM_MEMBER_ERROR_MASK # bad bmask +ENUM_MEMBER_ERROR_ILLV = ida_enum.ENUM_MEMBER_ERROR_ILLV # bad bmask and value combination (~bmask & value != 0) def DelConstEx(enum_id, value, serial, bmask): @@ -6358,7 +6399,7 @@ def DelConstEx(enum_id, value, serial, bmask): """ if bmask < 0: bmask &= BADADDR - return idaapi.del_enum_member(enum_id, value, serial, bmask) + return ida_enum.del_enum_member(enum_id, value, serial, bmask) def SetConstName(const_id, name): @@ -6370,7 +6411,7 @@ def SetConstName(const_id, name): @return: 1-ok, 0-failed """ - return idaapi.set_enum_member_name(const_id, name) + return ida_enum.set_enum_member_name(const_id, name) def SetConstCmt(const_id, cmt, repeatable): @@ -6385,7 +6426,7 @@ def SetConstCmt(const_id, cmt, repeatable): @return: 1-ok, 0-failed """ - return idaapi.set_enum_member_cmt(const_id, cmt, repeatable) + return ida_enum.set_enum_member_cmt(const_id, cmt, repeatable) #---------------------------------------------------------------------------- # A R R A Y S I N I D C @@ -6398,17 +6439,17 @@ def __l2m1(v): 'signed long' version of -1, then return -1. Otherwise, return 'v'. """ - if v == idaapi.BADNODE: + if v == ida_netnode.BADNODE: return -1 else: return v -AR_LONG = idaapi.atag +AR_LONG = ida_netnode.atag """Array of longs""" -AR_STR = idaapi.stag +AR_STR = ida_netnode.stag """Array of strings""" @@ -6471,7 +6512,7 @@ def __GetArrayById(array_id): @param array_id: A positive, valid array ID. """ try: - node = idaapi.netnode(array_id) + node = ida_netnode.netnode(array_id) nodename = node.name() if nodename is None or not nodename.startswith(_IDC_ARRAY_PREFIX): return __dummy_netnode.instance @@ -6489,7 +6530,7 @@ def CreateArray(name): @return: -1 in case of failure, a valid array_id otherwise. """ - node = idaapi.netnode() + node = ida_netnode.netnode() res = node.create(_IDC_ARRAY_PREFIX + name) if res == False: return -1 @@ -6506,7 +6547,7 @@ def GetArrayId(name): @return: -1 in case of failure (i.e., no array with that name exists), a valid array_id otherwise. """ - return __l2m1(idaapi.netnode(_IDC_ARRAY_PREFIX + name, 0, False).index()) + return __l2m1(ida_netnode.netnode(_IDC_ARRAY_PREFIX + name, 0, False).index()) def RenameArray(array_id, newname): @@ -6820,7 +6861,7 @@ def AddSourceFile(ea1, ea2, filename): Each source file is represented by a range of addresses. A source file may contains several address ranges. """ - return idaapi.add_sourcefile(ea1, ea2, filename) + return ida_lines.add_sourcefile(ea1, ea2, filename) def GetSourceFile(ea): @@ -6832,7 +6873,7 @@ def GetSourceFile(ea): @return: NULL - source file information is not found otherwise returns pointer to file name """ - return idaapi.get_sourcefile(ea) + return ida_lines.get_sourcefile(ea) def DelSourceFile(ea): @@ -6844,7 +6885,7 @@ def DelSourceFile(ea): @return: NULL - source file information is not found otherwise returns pointer to file name """ - return idaapi.del_sourcefile(ea) + return ida_lines.del_sourcefile(ea) def SetLineNumber(ea, lnnum): @@ -6856,7 +6897,7 @@ def SetLineNumber(ea, lnnum): @return: None """ - idaapi.set_source_linnum(ea, lnnum) + ida_nalt.set_source_linnum(ea, lnnum) def GetLineNumber(ea): @@ -6867,7 +6908,7 @@ def GetLineNumber(ea): @return: number of line in the source file or -1 """ - return idaapi.get_source_linnum(ea) + return ida_nalt.get_source_linnum(ea) def DelLineNumber(ea): @@ -6878,7 +6919,7 @@ def DelLineNumber(ea): @return: None """ - idaapi.del_source_linnum(ea) + ida_nalt.del_source_linnum(ea) #---------------------------------------------------------------------------- @@ -6892,8 +6933,7 @@ def LoadTil(name): @param name: name of type library. @return: 1-ok, 0-failed. """ - til = idaapi.add_til2(name, idaapi.ADDTIL_DEFAULT) - + til = ida_typeinf.add_til2(name, ida_typeinf.ADDTIL_DEFAULT) if til: return 1 else: @@ -6912,7 +6952,7 @@ def Til2Idb(idx, type_name): @return: BADNODE-failed, otherwise the type id (structure id or enum id) """ - return idaapi.import_type(idaapi.cvar.idati, idx, type_name) + return ida_typeinf.import_type(ida_typeinf.cvar.idati, idx, type_name) def GetType(ea): @@ -6923,7 +6963,7 @@ def GetType(ea): @return: type string or None if failed """ - return idaapi.idc_get_type(ea) + return ida_typeinf.idc_get_type(ea) def SizeOf(typestr): """ @@ -6931,7 +6971,7 @@ def SizeOf(typestr): Use name, tp, fld = idc.ParseType() ; SizeOf(tp) to retrieve the size @return: -1 if typestring is not valid otherwise the size of the type """ - return idaapi.calc_type_size(idaapi.cvar.idati, typestr) + return ida_typeinf.calc_type_size(ida_typeinf.cvar.idati, typestr) def GetTinfo(ea): """ @@ -6940,7 +6980,7 @@ def GetTinfo(ea): @param ea: the address of the object @return: None on failure, or (type, fields) tuple. """ - return idaapi.idc_get_type_raw(ea) + return ida_typeinf.idc_get_type_raw(ea) def GetLocalTinfo(ordinal): """ @@ -6949,7 +6989,7 @@ def GetLocalTinfo(ordinal): @param ordinal: slot number (1...NumberOfLocalTypes) @return: None on failure, or (type, fields, name) tuple. """ - return idaapi.idc_get_local_type_raw(ordinal) + return ida_typeinf.idc_get_local_type_raw(ordinal) def GuessType(ea): """ @@ -6959,7 +6999,7 @@ def GuessType(ea): @return: type string or None if failed """ - return idaapi.idc_guess_type(ea) + return ida_typeinf.idc_guess_type(ea) TINFO_GUESSED = 0x0000 # this is a guessed type TINFO_DEFINITE = 0x0001 # this is a definite type @@ -6971,7 +7011,7 @@ def ApplyType(ea, py_type, flags = TINFO_DEFINITE): """ Apply the specified type to the address - @param ti: Type info. 'idaapi.cvar.idati' can be passed. + @param ti: Type info. 'ida_typeinf.cvar.idati' can be passed. @param py_type: typeinfo tuple (type, fields) as GetTinfo() returns or tuple (name, type, fields) as ParseType() returns or None @@ -6991,7 +7031,7 @@ def ApplyType(ea, py_type, flags = TINFO_DEFINITE): pt = py_type[1:] # skip name component else: pt = py_type - return idaapi.apply_type(idaapi.cvar.idati, pt[0], pt[1], ea, flags) + return ida_typeinf.apply_type(ida_typeinf.cvar.idati, pt[0], pt[1], ea, flags) def SetType(ea, newtype): """ @@ -7025,7 +7065,7 @@ def ParseType(inputtype, flags): """ if len(inputtype) != 0 and inputtype[-1] != ';': inputtype = inputtype + ';' - return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags) + return ida_typeinf.idc_parse_decl(ida_typeinf.cvar.idati, inputtype, flags) def ParseTypes(inputtype, flags = 0): """ @@ -7036,7 +7076,7 @@ def ParseTypes(inputtype, flags = 0): @return: number of parsing errors (0 no errors) """ - return idaapi.idc_parse_types(inputtype, flags) + return ida_typeinf.idc_parse_types(inputtype, flags) PT_FILE = 0x0001 # input if a file name (otherwise contains type declarations) @@ -7061,10 +7101,10 @@ def PrintLocalTypes(ordinals, flags): @return: string containing the type definitions """ - class def_sink(idaapi.text_sink_t): + class def_sink(ida_typeinf.text_sink_t): def __init__(self): - idaapi.text_sink_t.__init__(self) + ida_typeinf.text_sink_t.__init__(self) self.text = "" def _print(self, defstr): @@ -7073,7 +7113,7 @@ def PrintLocalTypes(ordinals, flags): sink = def_sink() py_ordinals = map(lambda l : int(l), ordinals.split(",")) - idaapi.print_decls(sink, idaapi.cvar.idati, py_ordinals, flags) + ida_typeinf.print_decls(sink, ida_typeinf.cvar.idati, py_ordinals, flags) return sink.text @@ -7090,7 +7130,7 @@ def GetMaxLocalType(): @return: value >= 1. 1 means that there are no local types. """ - return idaapi.get_ordinal_qty(idaapi.cvar.idati) + return ida_typeinf.get_ordinal_qty(ida_typeinf.cvar.idati) def SetLocalType(ordinal, input, flags): @@ -7105,7 +7145,7 @@ def SetLocalType(ordinal, input, flags): @return: slot number or 0 if error """ - return idaapi.idc_set_local_type(ordinal, input, flags) + return ida_typeinf.idc_set_local_type(ordinal, input, flags) def GetLocalType(ordinal, flags): @@ -7117,7 +7157,7 @@ def GetLocalType(ordinal, flags): (type, fields) = GetLocalTinfo(ordinal) if type: name = GetLocalTypeName(ordinal) - return idaapi.idc_print_type(type, fields, name, flags) + return ida_typeinf.idc_print_type(type, fields, name, flags) return "" PRTYPE_1LINE = 0x0000 # print to one line @@ -7134,7 +7174,7 @@ def GetLocalTypeName(ordinal): returns: local type name or None """ - return idaapi.idc_get_local_type_name(ordinal) + return ida_typeinf.idc_get_local_type_name(ordinal) # ---------------------------------------------------------------------------- @@ -7155,7 +7195,7 @@ def HideArea(start, end, description, header, footer, color): @returns: !=0 - ok """ - return idaapi.add_hidden_area(start, end, description, header, footer, color) + return ida_bytes.add_hidden_area(start, end, description, header, footer, color) def SetHiddenArea(ea, visible): @@ -7167,13 +7207,13 @@ def SetHiddenArea(ea, visible): @return: != 0 - ok """ - ha = idaapi.get_hidden_area(ea) + ha = ida_bytes.get_hidden_area(ea) if not ha: return 0 else: ha.visible = visible - return idaapi.update_hidden_area(ha) + return ida_bytes.update_hidden_area(ha) def DelHiddenArea(ea): @@ -7183,7 +7223,7 @@ def DelHiddenArea(ea): @param ea: any address belonging to the hidden area @returns: != 0 - ok """ - return idaapi.del_hidden_area(ea) + return ida_bytes.del_hidden_area(ea) #-------------------------------------------------------------------------- @@ -7199,7 +7239,7 @@ def LoadDebugger(dbgname, use_remote): @note: This function is needed only when running idc scripts from the command line. In other cases IDA loads the debugger module automatically. """ - return idaapi.load_debugger(dbgname, use_remote) + return ida_dbg.load_debugger(dbgname, use_remote) def StartDebugger(path, args, sdir): @@ -7215,7 +7255,7 @@ def StartDebugger(path, args, sdir): @note: For all args: if empty, the default value from the database will be used See the important note to the StepInto() function """ - return idaapi.start_process(path, args, sdir) + return ida_dbg.start_process(path, args, sdir) def StopDebugger(): @@ -7225,7 +7265,7 @@ def StopDebugger(): @return: success """ - return idaapi.exit_process() + return ida_dbg.exit_process() def PauseProcess(): @@ -7239,14 +7279,14 @@ def PauseProcess(): @note: To resume a suspended process use the GetDebuggerEvent function. See the important note to the StepInto() function """ - return idaapi.suspend_process() + return ida_dbg.suspend_process() def GetProcessQty(): """ Take a snapshot of running processes and return their number. """ - return idaapi.get_process_qty() + return ida_dbg.get_process_qty() def GetProcessPid(idx): @@ -7257,9 +7297,9 @@ def GetProcessPid(idx): @return: 0 if failure """ - pinfo = idaapi.process_info_t() - pid = idaapi.get_process_info(idx, pinfo) - if pid != idaapi.NO_PROCESS: + pinfo = ida_idd.process_info_t() + pid = ida_dbg.get_process_info(idx, pinfo) + if pid != ida_idd.NO_PROCESS: return pinfo.pid else: return 0 @@ -7273,9 +7313,9 @@ def GetProcessName(idx): @return: None if failure """ - pinfo = idaapi.process_info_t() - pid = idaapi.get_process_info(idx, pinfo) - return None if pid == idaapi.NO_PROCESS else pinfo.name + pinfo = ida_idd.process_info_t() + pid = ida_dbg.get_process_info(idx, pinfo) + return None if pid == ida_idd.NO_PROCESS else pinfo.name def AttachProcess(pid, event_id): @@ -7294,7 +7334,7 @@ def AttachProcess(pid, event_id): - 1: the debugger properly attached to the process @note: See the important note to the StepInto() function """ - return idaapi.attach_process(pid, event_id) + return ida_dbg.attach_process(pid, event_id) def DetachProcess(): @@ -7303,7 +7343,7 @@ def DetachProcess(): @return: success """ - return idaapi.detach_process() + return ida_dbg.detach_process() def GetThreadQty(): @@ -7312,7 +7352,7 @@ def GetThreadQty(): @return: number of threads """ - return idaapi.get_thread_qty() + return ida_dbg.get_thread_qty() def GetThreadId(idx): @@ -7323,7 +7363,7 @@ def GetThreadId(idx): @return: -1 if failure """ - return idaapi.getn_thread(idx) + return ida_dbg.getn_thread(idx) def GetCurrentThreadId(): @@ -7332,7 +7372,7 @@ def GetCurrentThreadId(): @return: -1 if failure """ - return idaapi.get_current_thread() + return ida_dbg.get_current_thread() def SelectThread(tid): @@ -7345,7 +7385,7 @@ def SelectThread(tid): @note: The process must be suspended to select a new thread. """ - return idaapi.select_thread(tid) + return ida_dbg.select_thread(tid) def SuspendThread(tid): @@ -7359,7 +7399,7 @@ def SuspendThread(tid): @note: Suspending a thread may deadlock the whole application if the suspended was owning some synchronization objects. """ - return idaapi.suspend_thread(tid) + return ida_dbg.suspend_thread(tid) def ResumeThread(tid): @@ -7370,18 +7410,18 @@ def ResumeThread(tid): @return: -1:network error, 0-failed, 1-ok """ - return idaapi.resume_thread(tid) + return ida_dbg.resume_thread(tid) def _get_modules(): """ INTERNAL: Enumerate process modules """ - module = idaapi.module_info_t() - result = idaapi.get_first_module(module) + module = ida_idd.module_info_t() + result = ida_dbg.get_first_module(module) while result: yield module - result = idaapi.get_next_module(module) + result = ida_dbg.get_next_module(module) def GetFirstModule(): @@ -7458,7 +7498,7 @@ def StepInto(): This remark applies to all execution control functions. The event codes depend on the issued command. """ - return idaapi.step_into() + return ida_dbg.step_into() def StepOver(): @@ -7470,7 +7510,7 @@ def StepOver(): @return: success """ - return idaapi.step_over() + return ida_dbg.step_over() def RunTo(ea): @@ -7481,7 +7521,7 @@ def RunTo(ea): @return: success """ - return idaapi.run_to(ea) + return ida_dbg.run_to(ea) def StepUntilRet(): @@ -7493,7 +7533,7 @@ def StepUntilRet(): @return: success """ - return idaapi.step_until_ret() + return ida_dbg.step_until_ret() def GetDebuggerEvent(wfne, timeout): @@ -7507,7 +7547,7 @@ def GetDebuggerEvent(wfne, timeout): @return: debugger event codes, see below """ - return idaapi.wait_for_next_event(wfne, timeout) + return ida_dbg.wait_for_next_event(wfne, timeout) def ResumeProcess(): @@ -7518,7 +7558,7 @@ def SendDbgCommand(cmd): An exception will be raised if the debugger is not running or the current debugger does not export the 'SendDbgCommand' IDC command. """ - s = Eval('SendDbgCommand("%s");' % idaapi.str2user(cmd)) + s = Eval('SendDbgCommand("%s");' % ida_kernwin.str2user(cmd)) if s.startswith("IDC_FAILURE"): raise Exception, "Debugger command is available only when the debugger is active!" return s @@ -7567,7 +7607,7 @@ def RefreshDebuggerMemory(): information, memory contents, or names of a non-suspended process. This is an expensive call. """ - return idaapi.refresh_debugger_memory() + return ida_dbg.refresh_debugger_memory() def TakeMemorySnapshot(only_loader_segs): @@ -7577,7 +7617,7 @@ def TakeMemorySnapshot(only_loader_segs): @param only_loader_segs: 0-copy all segments to idb 1-copy only SFL_LOADER segments """ - return idaapi.take_memory_snapshot(only_loader_segs) + return ida_segment.take_memory_snapshot(only_loader_segs) def GetProcessState(): @@ -7586,7 +7626,7 @@ def GetProcessState(): @return: one of the DBG_... constants (see below) """ - return idaapi.get_process_state() + return ida_dbg.get_process_state() DSTATE_SUSP = -1 # process is suspended DSTATE_NOTASK = 0 # no process is currently debugged @@ -7609,7 +7649,7 @@ def GetEventId(): @return: event ID """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.eid @@ -7620,7 +7660,7 @@ def GetEventPid(): @return: process ID """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.pid @@ -7631,7 +7671,7 @@ def GetEventTid(): @return: type ID """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.tid @@ -7642,7 +7682,7 @@ def GetEventEa(): @return: ea """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.ea @@ -7653,7 +7693,7 @@ def IsEventHandled(): @return: boolean """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.handled @@ -7666,9 +7706,9 @@ def GetEventModuleName(): @return: module name """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_module_name(ev) + return ida_idd.get_event_module_name(ev) def GetEventModuleBase(): @@ -7677,9 +7717,9 @@ def GetEventModuleBase(): @return: module base """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_module_base(ev) + return ida_idd.get_event_module_base(ev) def GetEventModuleSize(): @@ -7688,9 +7728,9 @@ def GetEventModuleSize(): @return: module size """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_module_size(ev) + return ida_idd.get_event_module_size(ev) def GetEventExitCode(): @@ -7699,7 +7739,7 @@ def GetEventExitCode(): @return: exit code for PROCESS_EXIT, THREAD_EXIT events """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" return ev.exit_code @@ -7711,9 +7751,9 @@ def GetEventInfo(): @return: event info: for LIBRARY_UNLOAD (unloaded library name) for INFORMATION (message to display) """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_info(ev) + return ida_idd.get_event_info(ev) def GetEventBptHardwareEa(): @@ -7722,9 +7762,9 @@ def GetEventBptHardwareEa(): @return: hardware address """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_bpt_hea(ev) + return ida_idd.get_event_bpt_hea(ev) def GetEventExceptionCode(): @@ -7733,9 +7773,9 @@ def GetEventExceptionCode(): @return: exception code """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_exc_code(ev) + return ida_idd.get_event_exc_code(ev) def GetEventExceptionEa(): @@ -7744,9 +7784,9 @@ def GetEventExceptionEa(): @return: adress of exception """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_exc_ea(ev) + return ida_idd.get_event_exc_ea(ev) def CanExceptionContinue(): @@ -7755,9 +7795,9 @@ def CanExceptionContinue(): @return: boolean """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.can_exc_continue(ev) + return ida_idd.can_exc_continue(ev) def GetEventExceptionInfo(): @@ -7766,9 +7806,9 @@ def GetEventExceptionInfo(): @return: info string """ - ev = idaapi.get_debug_event() + ev = ida_dbg.get_debug_event() assert ev, "Could not retrieve debug event" - return idaapi.get_event_exc_info(ev) + return ida_idd.get_event_exc_info(ev) def SetDebuggerOptions(opt): @@ -7779,7 +7819,7 @@ def SetDebuggerOptions(opt): @return: old options """ - return idaapi.set_debugger_options(opt) + return ida_dbg.set_debugger_options(opt) DOPT_SEGM_MSGS = 0x00000001 # print messages on debugger segments modifications @@ -7807,14 +7847,14 @@ def GetDebuggerEventCondition(): """ Return the debugger event condition """ - return idaapi.get_debugger_event_cond() + return ida_dbg.get_debugger_event_cond() def SetDebuggerEventCondition(cond): """ Set the debugger event condition """ - return idaapi.set_debugger_event_cond(cond) + return ida_dbg.set_debugger_event_cond(cond) def SetRemoteDebugger(hostname, password, portnum): @@ -7827,48 +7867,9 @@ def SetRemoteDebugger(hostname, password, portnum): @return: nothing """ - return idaapi.set_remote_debugger(hostname, password, portnum) + return ida_dbg.set_remote_debugger(hostname, password, portnum) -def GetExceptionQty(): - """ - Get number of defined exception codes - """ - return idaapi.get_exception_qty() - - -def GetExceptionCode(idx): - """ - Get exception code - - @param idx: number of exception in the vector (0..GetExceptionQty()-1) - - @return: exception code (0 - error) - """ - return idaapi.get_exception_code(idx) - - -def GetExceptionName(code): - """ - Get exception information - - @param code: exception code - - @return: "" on error - """ - return idaapi.get_exception_name(code) - - -def GetExceptionFlags(code): - """ - Get exception information - - @param code: exception code - - @return: -1 on error - """ - return idaapi.get_exception_flags(code) - def DefineException(code, name, desc, flags): """ Add exception handling information @@ -7880,31 +7881,12 @@ def DefineException(code, name, desc, flags): @return: failure description or "" """ - return idaapi.define_exception(code, name, desc, flags) + return ida_dbg.define_exception(code, name, desc, flags) EXC_BREAK = 0x0001 # break on the exception EXC_HANDLE = 0x0002 # should be handled by the debugger? -def SetExceptionFlags(code, flags): - """ - Set exception flags - - @param code: exception code - @param flags: exception flags (combination of EXC_...) - """ - return idaapi.set_exception_flags(code, flags) - - -def ForgetException(code): - """ - Delete exception handling information - - @param code: exception code - """ - return idaapi.forget_exception(code) - - def GetRegValue(name): """ Get register value @@ -7918,8 +7900,8 @@ def GetRegValue(name): @return: register value (integer or floating point) """ - rv = idaapi.regval_t() - res = idaapi.get_reg_val(name, rv) + rv = ida_idd.regval_t() + res = ida_dbg.get_reg_val(name, rv) assert res, "get_reg_val() failed, bogus register name ('%s') perhaps?" % name return rv.ival @@ -7935,7 +7917,7 @@ def SetRegValue(value, name): It is not necessary to use this function to set register values. A register name in the left side of an assignment will do too. """ - rv = idaapi.regval_t() + rv = ida_idd.regval_t() if type(value) == types.StringType: value = int(value, 16) elif type(value) != types.IntType and type(value) != types.LongType: @@ -7947,7 +7929,7 @@ def SetRegValue(value, name): value &= 0xFFFFFFFF rv.ival = value - return idaapi.set_reg_val(name, rv) + return ida_dbg.set_reg_val(name, rv) def GetBptQty(): @@ -7956,7 +7938,7 @@ def GetBptQty(): @return: number of breakpoints """ - return idaapi.get_bpt_qty() + return ida_dbg.get_bpt_qty() def GetBptEA(n): @@ -7967,9 +7949,9 @@ def GetBptEA(n): @return: addresss of the breakpoint or BADADDR """ - bpt = idaapi.bpt_t() + bpt = ida_dbg.bpt_t() - if idaapi.getn_bpt(n, bpt): + if ida_dbg.getn_bpt(n, bpt): return bpt.ea else: return BADADDR @@ -7984,9 +7966,9 @@ def GetBptAttr(ea, bptattr): @return: the desired attribute value or -1 """ - bpt = idaapi.bpt_t() + bpt = ida_dbg.bpt_t() - if not idaapi.get_bpt(ea, bpt): + if not ida_dbg.get_bpt(ea, bpt): return -1 else: if bptattr == BPTATTR_EA: @@ -8056,9 +8038,9 @@ def SetBptAttr(address, bptattr, value): @return: success """ - bpt = idaapi.bpt_t() + bpt = ida_dbg.bpt_t() - if not idaapi.get_bpt(address, bpt): + if not ida_dbg.get_bpt(address, bpt): return False else: if bptattr not in [ BPTATTR_SIZE, BPTATTR_TYPE, BPTATTR_FLAGS, BPTATTR_COUNT ]: @@ -8072,7 +8054,7 @@ def SetBptAttr(address, bptattr, value): if bptattr == BPTATTR_FLAGS: bpt.flags = value - return idaapi.update_bpt(bpt) + return ida_dbg.update_bpt(bpt) def SetBptCndEx(ea, cnd, is_lowcnd): """ @@ -8084,9 +8066,9 @@ def SetBptCndEx(ea, cnd, is_lowcnd): @return: success """ - bpt = idaapi.bpt_t() + bpt = ida_dbg.bpt_t() - if not idaapi.get_bpt(ea, bpt): + if not ida_dbg.get_bpt(ea, bpt): return False bpt.condition = cnd @@ -8095,7 +8077,7 @@ def SetBptCndEx(ea, cnd, is_lowcnd): else: bpt.flags &= ~BPT_LOWCND - return idaapi.update_bpt(bpt) + return ida_dbg.update_bpt(bpt) def SetBptCnd(ea, cnd): @@ -8122,7 +8104,7 @@ def AddBptEx(ea, size, bpttype): @note: Only one breakpoint can exist at a given address. """ - return idaapi.add_bpt(ea, size, bpttype) + return ida_dbg.add_bpt(ea, size, bpttype) def AddBpt(ea): @@ -8137,7 +8119,7 @@ def DelBpt(ea): @return: success """ - return idaapi.del_bpt(ea) + return ida_dbg.del_bpt(ea) def EnableBpt(ea, enable): @@ -8150,7 +8132,7 @@ def EnableBpt(ea, enable): @note: Disabled breakpoints are not written to the process memory """ - return idaapi.enable_bpt(ea, enable) + return ida_dbg.enable_bpt(ea, enable) def CheckBpt(ea): @@ -8161,7 +8143,7 @@ def CheckBpt(ea): @return: one of BPTCK_... constants """ - return idaapi.check_bpt(ea) + return ida_dbg.check_bpt(ea) BPTCK_NONE = -1 # breakpoint does not exist BPTCK_NO = 0 # breakpoint is disabled @@ -8182,13 +8164,13 @@ def EnableTracing(trace_level, enable): "trace_level must be one of TRACE_* constants" if trace_level == TRACE_STEP: - return idaapi.enable_step_trace(enable) + return ida_dbg.enable_step_trace(enable) if trace_level == TRACE_INSN: - return idaapi.enable_insn_trace(enable) + return ida_dbg.enable_insn_trace(enable) if trace_level == TRACE_FUNC: - return idaapi.enable_func_trace(enable) + return ida_dbg.enable_func_trace(enable) return False @@ -8203,7 +8185,7 @@ def GetStepTraceOptions(): @return: a combination of ST_... constants """ - return idaapi.get_step_trace_options() + return ida_dbg.get_step_trace_options() def SetStepTraceOptions(options): @@ -8211,7 +8193,7 @@ def SetStepTraceOptions(options): Set step current tracing options. @param options: combination of ST_... constants """ - return idaapi.set_step_trace_options(options) + return ida_dbg.set_step_trace_options(options) ST_OVER_DEBUG_SEG = 0x01 # step tracing will be disabled when IP is in a debugger segment @@ -8224,7 +8206,7 @@ def LoadTraceFile(filename): Load a previously recorded binary trace file @param filename: trace file """ - return idaapi.load_trace_file(filename) + return ida_dbg.load_trace_file(filename) def SaveTraceFile(filename, description): """ @@ -8232,34 +8214,34 @@ def SaveTraceFile(filename, description): @param filename: trace file @param description: trace description """ - return idaapi.save_trace_file(filename, description) + return ida_dbg.save_trace_file(filename, description) def CheckTraceFile(filename): """ Check the given binary trace file @param filename: trace file """ - return idaapi.is_valid_trace_file(filename) + return ida_dbg.is_valid_trace_file(filename) def DiffTraceFile(filename): """ Diff current trace buffer against given trace @param filename: trace file """ - return idaapi.diff_trace_file(filename) + return ida_dbg.diff_trace_file(filename) def ClearTraceFile(filename): """ Clear the current trace buffer """ - return idaapi.clear_trace() + return ida_dbg.clear_trace() def GetTraceDesc(filename): """ Get the trace description of the given binary trace file @param filename: trace file """ - return idaapi.get_trace_file_desc(filename) + return ida_dbg.get_trace_file_desc(filename) def SetTraceDesc(filename, description): """ @@ -8267,20 +8249,20 @@ def SetTraceDesc(filename, description): @param filename: trace file @description: trace description """ - return idaapi.set_trace_file_desc(filename, description) + return ida_dbg.set_trace_file_desc(filename, description) def GetMaxTev(): """ Return the total number of recorded events """ - return idaapi.get_tev_qty() + return ida_dbg.get_tev_qty() def GetTevEa(tev): """ Return the address of the specified event @param tev: event number """ - return idaapi.get_tev_ea(tev) + return ida_dbg.get_tev_ea(tev) TEV_NONE = 0 # no event TEV_INSN = 1 # an instruction trace @@ -8295,14 +8277,14 @@ def GetTevType(tev): Return the type of the specified event (TEV_... constants) @param tev: event number """ - return idaapi.get_tev_type(tev) + return ida_dbg.get_tev_type(tev) def GetTevTid(tev): """ Return the thread id of the specified event @param tev: event number """ - return idaapi.get_tev_tid(tev) + return ida_dbg.get_tev_tid(tev) def GetTevRegVal(tev, reg): """ @@ -8310,7 +8292,7 @@ def GetTevRegVal(tev, reg): @param tev: event number @param reg: register name (like EAX, RBX, ...) """ - return idaapi.get_tev_reg_val(tev, reg) + return ida_dbg.get_tev_reg_val(tev, reg) def GetTevRegMemQty(tev): """ @@ -8320,7 +8302,7 @@ def GetTevRegMemQty(tev): @param tev: event number """ - return idaapi.get_tev_reg_mem_qty(tev) + return ida_dbg.get_tev_reg_mem_qty(tev) def GetTevRegMem(tev, idx): """ @@ -8331,7 +8313,7 @@ def GetTevRegMem(tev, idx): @param tev: event number @param idx: memory address index """ - return idaapi.get_tev_reg_mem(tev, idx) + return ida_dbg.get_tev_reg_mem(tev, idx) def GetTevRegMemEa(tev, idx): """ @@ -8342,28 +8324,28 @@ def GetTevRegMemEa(tev, idx): @param tev: event number @param idx: memory address index """ - return idaapi.get_tev_reg_mem_ea(tev, idx) + return ida_dbg.get_tev_reg_mem_ea(tev, idx) def GetTevCallee(tev): """ Return the address of the callee for the specified event @param tev: event number """ - return idaapi.get_call_tev_callee(tev) + return ida_dbg.get_call_tev_callee(tev) def GetTevReturn(tev): """ Return the return address for the specified event @param tev: event number """ - return idaapi.get_ret_tev_return(tev) + return ida_dbg.get_ret_tev_return(tev) def GetBptTevEa(tev): """ Return the address of the specified TEV_BPT event @param tev: event number """ - return idaapi.get_bpt_tev_ea(tev) + return ida_dbg.get_bpt_tev_ea(tev) #-------------------------------------------------------------------------- @@ -8383,17 +8365,17 @@ def GetColor(ea, what): raise ValueError, "'what' must be one of CIC_ITEM, CIC_FUNC and CIC_SEGM" if what == CIC_ITEM: - return idaapi.get_item_color(ea) + return ida_nalt.get_item_color(ea) if what == CIC_FUNC: - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if func: return func.color else: return DEFCOLOR if what == CIC_SEGM: - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if seg: return seg.color else: @@ -8421,18 +8403,18 @@ def SetColor(ea, what, color): raise ValueError, "'what' must be one of CIC_ITEM, CIC_FUNC and CIC_SEGM" if what == CIC_ITEM: - return idaapi.set_item_color(ea, color) + return ida_nalt.set_item_color(ea, color) if what == CIC_FUNC: - func = idaapi.get_func(ea) + func = ida_funcs.get_func(ea) if func: func.color = color - return bool(idaapi.update_func(func)) + return bool(ida_funcs.update_func(func)) else: return False if what == CIC_SEGM: - seg = idaapi.getseg(ea) + seg = ida_segment.getseg(ea) if seg: seg.color = color return bool(seg.update()) @@ -8546,8 +8528,8 @@ def WriteExe(filepath): return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0) -UTP_STRUCT = idaapi.UTP_STRUCT -UTP_ENUM = idaapi.UTP_ENUM +UTP_STRUCT = ida_typeinf.UTP_STRUCT +UTP_ENUM = ida_typeinf.UTP_ENUM def BeginTypeUpdating(utp): @@ -8559,7 +8541,7 @@ def BeginTypeUpdating(utp): @param utp: one of UTP_xxxx consts @return: None """ - return idaapi.begin_type_updating(utp) + return ida_typeinf.begin_type_updating(utp) def EndTypeUpdating(utp): @@ -8567,13 +8549,13 @@ def EndTypeUpdating(utp): End type updating. Refreshes the type system at the end of type modification operations - @param utp: one of idaapi.UTP_xxxx consts + @param utp: one of ida_typeinf.UTP_xxxx consts @return: None """ - return idaapi.end_type_updating(utp) + return ida_typeinf.end_type_updating(utp) -def AddConst(enum_id, name,value): return AddConstEx(enum_id, name, value, idaapi.BADADDR) +def AddConst(enum_id, name,value): return AddConstEx(enum_id, name, value, ida_idaapi.BADADDR) def AddStruc(index, name): return AddStrucEx(index,name, 0) def AddUnion(index, name): return AddStrucEx(index,name, 1) def OpStroff(ea, n, strid): return OpStroffEx(ea,n,strid, 0) diff --git a/python/init.py b/python/init.py old mode 100644 new mode 100755 index 06b74b4..3649343 --- a/python/init.py +++ b/python/init.py @@ -15,10 +15,21 @@ import os import sys import time import warnings -import _idaapi + +# Prepare sys.path so loading of the shared objects works +sys.path.append(os.path.join(sys.executable, IDAPYTHON_DYNLOAD_BASE, "python", "lib", "python2.7", "lib-dynload", IDAPYTHON_DYNLOAD_RELPATH)) +try: + import ida_idaapi + import ida_kernwin + import ida_diskio +except ImportError as e: + print "Import failed: %s. Current sys.path:" % str(e) + for p in sys.path: + print "\t%s" % p + raise # __EA64__ is set if IDA is running in 64-bit mode -__EA64__ = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL +__EA64__ = ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL # ----------------------------------------------------------------------- # Take over the standard text outputs @@ -30,7 +41,7 @@ class IDAPythonStdOut: def write(self, text): # NB: in case 'text' is Unicode, msg() will decode it # and call umsg() to print it - _idaapi.msg(text) + ida_kernwin.msg(text) def flush(self): pass @@ -49,8 +60,8 @@ def runscript(script): @return: Error string or None on success """ - import idaapi - return idaapi.IDAPython_ExecScript(script, globals()) + import ida_idaapi + return ida_idaapi.IDAPython_ExecScript(script, globals()) # ----------------------------------------------------------------------- def print_banner(): @@ -77,14 +88,14 @@ sys.stdout = sys.stderr = IDAPythonStdOut() import pydoc class IDAPythonHelpPrompter: def readline(self): - return idaapi.askstr(0, '', 'Help topic?') + return ida_kernwin.askstr(0, '', 'Help topic?') help = pydoc.Helper(input = IDAPythonHelpPrompter(), output = sys.stdout) # Assign a default sys.argv sys.argv = [""] # Have to make sure Python finds our modules -sys.path.append(_idaapi.idadir("python")) +sys.path.append(ida_diskio.idadir("python")) # Remove current directory from the top of the patch search if '' in sys.path: # On non Windows, the empty path is added @@ -97,15 +108,16 @@ if os.getcwd() in sys.path: if not IDAPYTHON_REMOVE_CWD_SYS_PATH: sys.path.append(os.getcwd()) -# Import all the required modules -from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall, Form -from idc import * -from idautils import * -import idaapi +if IDAPYTHON_COMPAT_AUTOIMPORT_MODULES: + # Import all the required modules + from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall, Form + from idc import * + from idautils import * + import idaapi # Load the users personal init file -userrc = os.path.join(get_user_idadir(), "idapythonrc.py") +userrc = os.path.join(ida_diskio.get_user_idadir(), "idapythonrc.py") if os.path.exists(userrc): - idaapi.IDAPython_ExecScript(userrc, globals()) + ida_idaapi.IDAPython_ExecScript(userrc, globals()) # All done, ready to rock. diff --git a/pywraps.cpp b/pywraps.cpp new file mode 100644 index 0000000..7cafd3c --- /dev/null +++ b/pywraps.cpp @@ -0,0 +1,2515 @@ + +#include +#include + +#include + +#include "pywraps.hpp" + +//lint -esym(843,pywraps_initialized) could be declared const +//lint -esym(843,g_nw) could be declared const +//lint -esym(844,g_nw) could be declared const +//lint -esym(843,g_use_local_python) could be declared const + +//------------------------------------------------------------------------ +// String constants used +static const char S_PY_IDCCVT_VALUE_ATTR[] = "__idc_cvt_value__"; +static const char S_PY_IDCCVT_ID_ATTR[] = "__idc_cvt_id__"; +static const char S_PY_IDC_OPAQUE_T[] = "py_idc_cvt_helper_t"; +static const char S_PY_IDC_GLOBAL_VAR_FMT[] = "__py_cvt_gvar_%d"; + +// Constants used by get_idaapi_class_reference() +#define PY_CLSID_CVT_INT64 0 +#define PY_CLSID_APPCALL_SKEL_OBJ 1 +#define PY_CLSID_CVT_BYREF 2 +#define PY_CLSID_LAST 3 + +//--------------------------------------------------------------------------- +// Use these macros to define script<->C fields +#define DEFINE_SCFIELDX(name, type, is_opt) { #name, type, qoffsetof(CUR_STRUC, name), is_opt } +#define DEFINE_SCFIELD(name, type) DEFINE_SCFIELDX(name, type, 0) +#define DEFINE_SCFIELD_OPT(name, type) DEFINE_SCFIELDX(name, type, 1) + +//--------------------------------------------------------------------------- +enum scfield_types_t +{ + // Numeric fields + FT_FIRST_NUM, + FT_INT, + FT_SIZET, + FT_SSIZET, + FT_NUM16, + FT_NUM32, + FT_LAST_NUM, + // String field + FT_STR, + FT_CHAR, + // Object fields + FT_ARR, + // Allocated array of strings + FT_STRARR, + // Allocated array of 16bit numbers + FT_NUM16ARR, + // Fixed size character array. The size must be passed in the definition + FT_CHRARR_STATIC, +}; + +//--------------------------------------------------------------------------- +struct scfld_t +{ + const char *field_name; + uint32 field_type; + size_t field_offs; + bool is_optional; +}; + +#define FT_VALUE_MASK 0xFFFF0000 +// Possible return values of conversion functions +#define FT_NOT_FOUND -1 +#define FT_BAD_TYPE -2 +#define FT_OK 1 + +static ref_t get_idaapi_attr_by_id(const int class_id); +static ref_t get_idaapi_attr(const char *attr); + + +//------------------------------------------------------------------------- +static Py_ssize_t pyvar_walk_list( + const ref_t &py_list, + int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud), + void *ud) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + Py_ssize_t size = CIP_FAILED; + do + { + PyObject *o = py_list.o; + if ( !PyList_CheckExact(o) && !PyW_IsSequenceType(o) ) + break; + + bool is_seq = !PyList_CheckExact(o); + size = is_seq ? PySequence_Size(o) : PyList_Size(o); + if ( cb == NULL ) + break; + + Py_ssize_t i; + for ( i=0; i < size; i++ ) + { + // Get the item + ref_t py_item; + if ( is_seq ) + py_item = newref_t(PySequence_GetItem(o, i)); + else + py_item = borref_t(PyList_GetItem(o, i)); + + if ( py_item == NULL || cb(py_item, i, ud) < CIP_OK ) + break; + } + size = i; + } while ( false ); + return size; +} + +//------------------------------------------------------------------------- +Py_ssize_t ida_export pyvar_walk_list( + PyObject *py_list, + int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud), + void *ud) +{ + borref_t r(py_list); + return pyvar_walk_list(r, cb, ud); +} + +//--------------------------------------------------------------------------- +ref_t ida_export PyW_IntVecToPyList(const intvec_t &intvec) +{ + size_t c = intvec.size(); + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t py_list(PyList_New(c)); + for ( size_t i=0; i < c; i++ ) + PyList_SetItem(py_list.o, i, PyInt_FromLong(intvec[i])); + return ref_t(py_list); +} + +//--------------------------------------------------------------------------- +static int idaapi pylist_to_intvec_cb( + const ref_t &py_item, + Py_ssize_t /*index*/, + void *ud) +{ + intvec_t &intvec = *(intvec_t *) ud; + uint64 num; + { + PYW_GIL_CHECK_LOCKED_SCOPE(); + if ( !PyW_GetNumber(py_item.o, &num) ) + num = 0; + } + + intvec.push_back(int(num)); + return CIP_OK; +} + +//--------------------------------------------------------------------------- +bool ida_export PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec) +{ + intvec.clear(); + return pyvar_walk_list(py_list, pylist_to_intvec_cb, &intvec) != CIP_FAILED; +} + +//------------------------------------------------------------------------- +static int idaapi pylist_to_eavec_cb( + const ref_t &py_item, + Py_ssize_t index, + void *ud) +{ + eavec_t &eavec = *(eavec_t *) ud; + ea_t ea = BADADDR; + { + PYW_GIL_CHECK_LOCKED_SCOPE(); + if ( PyInt_Check(py_item.o) ) + { + ea = PyInt_AsUnsignedLongMask(py_item.o); + } + else + { + if ( PyLong_Check(py_item.o) ) + { + ea = ea_t(PyLong_AsUnsignedLongLong(py_item.o)); + } + else + { + qstring m; + m.sprnt("Item #%d cannot be converted to an ea_t", int(index)); + PyErr_SetString(PyExc_ValueError, m.c_str()); + return CIP_FAILED; + } + } + } + + eavec.push_back(ea); + return CIP_OK; +} + +//--------------------------------------------------------------------------- +bool ida_export PyW_PyListToEaVec(PyObject *py_list, eavec_t &eavec) +{ + eavec.clear(); + return pyvar_walk_list(py_list, pylist_to_eavec_cb, &eavec) != CIP_FAILED; +} + +//--------------------------------------------------------------------------- +static int idaapi pylist_to_strvec_cb( + const ref_t &py_item, + Py_ssize_t /*index*/, + void *ud) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + qstrvec_t &strvec = *(qstrvec_t *)ud; + const char *s; + if ( !PyString_Check(py_item.o) ) + s = ""; + else + s = PyString_AsString(py_item.o); + + strvec.push_back(s); + return CIP_OK; +} + +//--------------------------------------------------------------------------- +bool ida_export PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec) +{ + strvec.clear(); + return pyvar_walk_list(py_list, pylist_to_strvec_cb, &strvec) != CIP_FAILED; +} + +//------------------------------------------------------------------------- +bool ida_export PyWStringOrNone_Check(PyObject *tp) +{ + return tp == Py_None || PyString_Check(tp); +} + +//------------------------------------------------------------------------- +PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &areas) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + PyObject *py_list = PyList_New(areas.size()); + meminfo_vec_t::const_iterator it, it_end(areas.end()); + Py_ssize_t i = 0; + for ( it=areas.begin(); it != it_end; ++it, ++i ) + { + const memory_info_t &mi = *it; + // startEA endEA name sclass sbase bitness perm + PyList_SetItem(py_list, i, + Py_BuildValue("(" PY_FMT64 PY_FMT64 "ss" PY_FMT64 "II)", + pyul_t(mi.startEA), + pyul_t(mi.endEA), + mi.name.c_str(), + mi.sclass.c_str(), + pyul_t(mi.sbase), + (unsigned int)(mi.bitness), + (unsigned int)mi.perm)); + } + return py_list; +} + +//------------------------------------------------------------------------- +static qvector py_compiled_form_vec; + +//------------------------------------------------------------------------- +void ida_export PyW_register_compiled_form(PyObject *py_form) +{ + ref_t ref = borref_t(py_form); + if ( !py_compiled_form_vec.has(ref) ) + py_compiled_form_vec.push_back(ref); +} + +//------------------------------------------------------------------------- +void ida_export PyW_unregister_compiled_form(PyObject *py_form) +{ + ref_t ref = borref_t(py_form); + if ( py_compiled_form_vec.has(ref) ) + py_compiled_form_vec.del(ref); +} + +//------------------------------------------------------------------------- +static void free_compiled_form_instances(void) +{ + while ( !py_compiled_form_vec.empty() ) + { + const ref_t &ref = py_compiled_form_vec[0]; + qstring title; + if ( !PyW_GetStringAttr(ref.o, "title", &title) ) + title = ""; + msg("WARNING: Form \"%s\" was not Free()d. Force-freeing.\n", title.c_str()); + // Will call 'py_unregister_compiled_form()', and thus trim the vector down. + newref_t unused(PyObject_CallMethod(ref.o, (char *)"Free", "()")); + } +} + +//------------------------------------------------------------------------- +// Checks if the given py_var is a special PyIdc_cvt_helper object. +// It does that by examining the magic attribute and returns its numeric value. +// It returns -1 if the object is not a recognized helper object. +// Any Python object can be treated as an cvt object if this attribute is created. +static int get_pyidc_cvt_type(PyObject *py_var) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + // Check if this our special by reference object + ref_t attr(PyW_TryGetAttrString(py_var, S_PY_IDCCVT_ID_ATTR)); + if ( attr == NULL || (!PyInt_Check(attr.o) && !PyLong_Check(attr.o)) ) + return -1; + return (int)PyInt_AsLong(attr.o); +} + +//------------------------------------------------------------------------- +// Utility function to convert a python object to an IDC object +// and sets a python exception on failure. +bool ida_export pyvar_to_idcvar_or_error(const ref_t &py_obj, idc_value_t *idc_obj) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + int sn = 0; + bool ok = pyvar_to_idcvar(py_obj, idc_obj, &sn) >= CIP_OK; + if ( !ok ) + PyErr_SetString(PyExc_ValueError, "Could not convert Python object to IDC object!"); + return ok; +} + +//------------------------------------------------------------------------ +static idc_class_t *get_py_idc_cvt_opaque() +{ + return find_idc_class(S_PY_IDC_OPAQUE_T); +} + +//------------------------------------------------------------------------- +// Utility function to create opaque / convertible Python <-> IDC variables +// The referred Python variable will have its reference increased +static bool wrap_PyObject_ptr(const ref_t &py_var, idc_value_t *idc_var) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + // Create an IDC object of this special helper class + if ( VarObject(idc_var, get_py_idc_cvt_opaque()) != eOk ) + return false; + + // Store the CVT id + idc_value_t idc_val; + idc_val.set_long(PY_ICID_OPAQUE); + VarSetAttr(idc_var, S_PY_IDCCVT_ID_ATTR, &idc_val); + + // Store the value as a PVOID referencing the given Python object + py_var.incref(); + idc_val.set_pvoid(py_var.o); + VarSetAttr(idc_var, S_PY_IDCCVT_VALUE_ATTR, &idc_val); + + return true; +} + +//------------------------------------------------------------------------ +// IDC Opaque object destructor: when the IDC object dies we kill the +// opaque Python object along with it +static const char py_idc_cvt_helper_dtor_args[] = { VT_OBJ, 0 }; +static error_t idaapi py_idc_opaque_dtor( + idc_value_t *argv, + idc_value_t * /*res*/) +{ + // This can be called at plugin registration time, when a + // 'script_plugin_t' instance is ::free()'d. It is + // not guaranteed that we have the GIL at that point. + PYW_GIL_GET; + + // Get the value from the object + idc_value_t idc_val; + VarGetAttr(&argv[0], S_PY_IDCCVT_VALUE_ATTR, &idc_val); + + // Extract the Python object reference + PyObject *py_obj = (PyObject *)idc_val.pvoid; + + // Decrease its reference (and eventually destroy it) + Py_DECREF(py_obj); + + return eOk; +} + +//------------------------------------------------------------------------- +// Converts a Python variable into an IDC variable +// This function returns on one CIP_XXXX +int ida_export pyvar_to_idcvar( + const ref_t &py_var, + idc_value_t *idc_var, + int *gvar_sn) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + // None / NULL + if ( py_var == NULL || py_var.o == Py_None ) + { + idc_var->set_long(0); + } + // Numbers? + else if ( PyW_GetNumberAsIDC(py_var.o, idc_var) ) + { + return CIP_OK; + } + // String + else if ( PyString_Check(py_var.o) ) + { + idc_var->_set_string(PyString_AsString(py_var.o), PyString_Size(py_var.o)); + } + // Boolean + else if ( PyBool_Check(py_var.o) ) + { + idc_var->set_long(py_var.o == Py_True ? 1 : 0); + } + // Float + else if ( PyFloat_Check(py_var.o) ) + { + double dresult = PyFloat_AsDouble(py_var.o); + ieee_realcvt((void *)&dresult, idc_var->e, 3); + idc_var->vtype = VT_FLOAT; + } + // void* + else if ( PyCObject_Check(py_var.o) ) + { + idc_var->set_pvoid(PyCObject_AsVoidPtr(py_var.o)); + } + // Python list? + else if ( PyList_CheckExact(py_var.o) || PyW_IsSequenceType(py_var.o) ) + { + // Create the object + VarObject(idc_var); + + // Determine list size and type + bool is_seq = !PyList_CheckExact(py_var.o); + Py_ssize_t size = is_seq ? PySequence_Size(py_var.o) : PyList_Size(py_var.o); + bool ok = true; + qstring attr_name; + + // Convert each item + for ( Py_ssize_t i=0; i < size; i++ ) + { + // Get the item + ref_t py_item; + if ( is_seq ) + py_item = newref_t(PySequence_GetItem(py_var.o, i)); + else + py_item = borref_t(PyList_GetItem(py_var.o, i)); + + // Convert the item into an IDC variable + idc_value_t v; + ok = pyvar_to_idcvar(py_item, &v, gvar_sn) >= CIP_OK; + if ( ok ) + { + // Form the attribute name + newref_t py_int(PyInt_FromSsize_t(i)); + ok = PyW_ObjectToString(py_int.o, &attr_name); + if ( !ok ) + break; + // Store the attribute + VarSetAttr(idc_var, attr_name.c_str(), &v); + } + if ( !ok ) + break; + } + return ok ? CIP_OK : CIP_FAILED; + } + // Dictionary: we convert to an IDC object + else if ( PyDict_Check(py_var.o) ) + { + // Create an empty IDC object + VarObject(idc_var); + + // Get the dict.items() list + newref_t py_items(PyDict_Items(py_var.o)); + + // Get the size of the list + qstring key_name; + bool ok = true; + Py_ssize_t size = PySequence_Size(py_items.o); + for ( Py_ssize_t i=0; i < size; i++ ) + { + // Get item[i] -> (key, value) + PyObject *py_item = PyList_GetItem(py_items.o, i); + + // Extract key/value + newref_t key(PySequence_GetItem(py_item, 0)); + newref_t val(PySequence_GetItem(py_item, 1)); + + // Get key's string representation + PyW_ObjectToString(key.o, &key_name); + + // Convert the attribute into an IDC value + idc_value_t v; + ok = pyvar_to_idcvar(val, &v, gvar_sn) >= CIP_OK; + if ( ok ) + { + // Store the attribute + VarSetAttr(idc_var, key_name.c_str(), &v); + } + if ( !ok ) + break; + } + return ok ? CIP_OK : CIP_FAILED; + } + // Possible function? + else if ( PyCallable_Check(py_var.o) ) + { + idc_var->clear(); + idc_var->vtype = VT_FUNC; + idc_var->funcidx = -1; // Does not apply + return CIP_OK; + } + // Objects: + // - pyidc_cvt objects: int64, byref, opaque + // - other python objects + else + { + // Get the type + int cvt_id = get_pyidc_cvt_type(py_var.o); + switch ( cvt_id ) + { + // + // INT64 + // + case PY_ICID_INT64: + { + // Get the value attribute + ref_t attr(PyW_TryGetAttrString(py_var.o, S_PY_IDCCVT_VALUE_ATTR)); + if ( attr == NULL ) + return false; + idc_var->set_int64(PyLong_AsLongLong(attr.o)); + return CIP_OK; + } + // + // BYREF + // + case PY_ICID_BYREF: + { + // BYREF always require this parameter + if ( gvar_sn == NULL ) + return CIP_FAILED; + + // Get the value attribute + ref_t attr(PyW_TryGetAttrString(py_var.o, S_PY_IDCCVT_VALUE_ATTR)); + if ( attr == NULL ) + return CIP_FAILED; + + // Create a global variable + char buf[MAXSTR]; + qsnprintf(buf, sizeof(buf), S_PY_IDC_GLOBAL_VAR_FMT, *gvar_sn); + idc_value_t *gvar = add_idc_gvar(buf); + // Convert the python value into the IDC global variable + bool ok = pyvar_to_idcvar(attr, gvar, gvar_sn) >= CIP_OK; + if ( ok ) + { + (*gvar_sn)++; + // Create a reference to this global variable + VarRef(idc_var, gvar); + } + return ok ? CIP_OK : CIP_FAILED; + } + // + // OPAQUE + // + case PY_ICID_OPAQUE: + { + if ( !wrap_PyObject_ptr(py_var, idc_var) ) + return CIP_FAILED; + return CIP_OK_OPAQUE; + } + // + // Other objects + // + default: + // A normal object? + newref_t py_dir(PyObject_Dir(py_var.o)); + Py_ssize_t size = PyList_Size(py_dir.o); + if ( py_dir == NULL || !PyList_Check(py_dir.o) || size == 0 ) + return CIP_FAILED; + // Create the IDC object + VarObject(idc_var); + for ( Py_ssize_t i=0; i < size; i++ ) + { + borref_t item(PyList_GetItem(py_dir.o, i)); + const char *field_name = PyString_AsString(item.o); + if ( field_name == NULL ) + continue; + + size_t len = strlen(field_name); + + // Skip private attributes + if ( (len > 2 ) + && (strncmp(field_name, "__", 2) == 0 ) + && (strncmp(field_name+len-2, "__", 2) == 0) ) + { + continue; + } + + idc_value_t v; + // Get the non-private attribute from the object + newref_t attr(PyObject_GetAttrString(py_var.o, field_name)); + if ( attr == NULL + // Convert the attribute into an IDC value + || pyvar_to_idcvar(attr, &v, gvar_sn) < CIP_OK ) + { + return CIP_FAILED; + } + + // Store the attribute + VarSetAttr(idc_var, field_name, &v); + } + } + } + return CIP_OK; +} + +//------------------------------------------------------------------------- +inline PyObject *cvt_to_pylong(int32 v) +{ + return PyLong_FromLong(v); +} + +inline PyObject *cvt_to_pylong(int64 v) +{ + return PyLong_FromLongLong(v); +} + +//------------------------------------------------------------------------- +// Converts an IDC variable to a Python variable +// If py_var points to an existing object then the object will be updated +// If py_var points to an existing immutable object then ZERO is returned +// Returns one of CIP_xxxx. Check pywraps.hpp +int ida_export idcvar_to_pyvar( + const idc_value_t &idc_var, + ref_t *py_var) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + switch ( idc_var.vtype ) + { + case VT_PVOID: + if ( *py_var == NULL ) + { + newref_t nr(PyCObject_FromVoidPtr(idc_var.pvoid, NULL)); + *py_var = nr; + } + else + { + return CIP_IMMUTABLE; + } + break; + + case VT_INT64: + { + // Recycle? + if ( *py_var != NULL ) + { + // Recycling an int64 object? + int t = get_pyidc_cvt_type(py_var->o); + if ( t != PY_ICID_INT64 ) + return CIP_IMMUTABLE; // Cannot recycle immutable object + // Update the attribute + PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64)); + return CIP_OK; + } + ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_INT64)); + if ( py_cls == NULL ) + return CIP_FAILED; + *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, PyLong_FromLongLong(idc_var.i64), NULL)); + if ( PyW_GetError() || *py_var == NULL ) + return CIP_FAILED; + break; + } + +#if !defined(NO_OBSOLETE_FUNCS) || defined(__EXPR_SRC) + case VT_STR: + *py_var = newref_t(PyString_FromString(idc_var.str)); + break; + +#endif + case VT_STR2: + if ( *py_var == NULL ) + { + const qstring &s = idc_var.qstr(); + *py_var = newref_t(PyString_FromStringAndSize(s.begin(), s.length())); + break; + } + else + return CIP_IMMUTABLE; // Cannot recycle immutable object + case VT_LONG: + // Cannot recycle immutable objects + if ( *py_var != NULL ) + return CIP_IMMUTABLE; + *py_var = newref_t(cvt_to_pylong(idc_var.num)); + break; + case VT_FLOAT: + if ( *py_var == NULL ) + { + double x; + if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 ) + INTERR(30160); + + *py_var = newref_t(PyFloat_FromDouble(x)); + break; + } + else + return CIP_IMMUTABLE; + + case VT_REF: + { + if ( *py_var == NULL ) + { + ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_BYREF)); + if ( py_cls == NULL ) + return CIP_FAILED; + + // Create a byref object with None value. We populate it later + *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, Py_None, NULL)); + if ( PyW_GetError() || *py_var == NULL ) + return CIP_FAILED; + } + int t = get_pyidc_cvt_type(py_var->o); + if ( t != PY_ICID_BYREF ) + return CIP_FAILED; + + // Dereference + // (Since we are not using VREF_COPY flag, we can safely const_cast) + idc_value_t *dref_v = VarDeref(const_cast(&idc_var), VREF_LOOP); + if ( dref_v == NULL ) + return CIP_FAILED; + + // Can we recycle the object? + ref_t new_py_val(PyW_TryGetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR)); + if ( new_py_val != NULL ) + { + // Recycle + t = idcvar_to_pyvar(*dref_v, &new_py_val); + + // Success? Nothing more to be done + if ( t == CIP_OK ) + return CIP_OK; + + // Clear it so we don't recycle it + new_py_val = ref_t(); + } + // Try to convert (not recycle) + if ( idcvar_to_pyvar(*dref_v, &new_py_val) != CIP_OK ) + return CIP_FAILED; + + // Update the attribute + PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, new_py_val.o); + break; + } + + // Can convert back into a Python object or Python dictionary + // (Depending if py_var will be recycled and it was a dictionary) + case VT_OBJ: + { + // Check if this IDC object has __cvt_id__ and the __idc_cvt_value__ fields + idc_value_t idc_val; + if ( VarGetAttr(&idc_var, S_PY_IDCCVT_ID_ATTR, &idc_val) == eOk + && VarGetAttr(&idc_var, S_PY_IDCCVT_VALUE_ATTR, &idc_val) == eOk ) + { + // Extract the object + *py_var = borref_t((PyObject *) idc_val.pvoid); + return CIP_OK_OPAQUE; + } + ref_t obj; + bool is_dict = false; + + // Need to create a new object? + if ( *py_var == NULL ) + { + // Get skeleton class reference + ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_APPCALL_SKEL_OBJ)); + if ( py_cls == NULL ) + return CIP_FAILED; + + // Call constructor + obj = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, NULL)); + if ( PyW_GetError() || obj == NULL ) + return CIP_FAILED; + } + else + { + // Recycle existing variable + obj = *py_var; + if ( PyDict_Check(obj.o) ) + is_dict = true; + } + + // Walk the IDC attributes and store into python + for ( const char *attr_name = VarFirstAttr(&idc_var); + attr_name != NULL; + attr_name = VarNextAttr(&idc_var, attr_name) ) + { + // Get the attribute + idc_value_t v; + VarGetAttr(&idc_var, attr_name, &v, true); + + // Convert attribute to a python value (recursively) + ref_t py_attr; + int cvt = idcvar_to_pyvar(v, &py_attr); + if ( cvt <= CIP_IMMUTABLE ) + return CIP_FAILED; + if ( is_dict ) + PyDict_SetItemString(obj.o, attr_name, py_attr.o); + else + PyObject_SetAttrString(obj.o, attr_name, py_attr.o); + } + *py_var = obj; + break; + } + // Unhandled type + default: + *py_var = ref_t(); + return CIP_FAILED; + } + return CIP_OK; +} + +//------------------------------------------------------------------------- +// Converts IDC arguments to Python argument list or just one tuple +// If 'decref' is NULL then 'pargs' will contain one element which is the tuple +bool ida_export pyw_convert_idc_args( + const idc_value_t args[], + int nargs, + ref_vec_t &pargs, + bool as_tupple, + char *errbuf, + size_t errbufsize) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + ref_t py_tuple; + + pargs.qclear(); + + if ( as_tupple ) + { + py_tuple = newref_t(PyTuple_New(nargs)); + if ( py_tuple == NULL ) + { + if ( errbuf != 0 && errbufsize > 0 ) + qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize); + return false; + } + } + + for ( int i=0; i < nargs; i++ ) + { + ref_t py_obj; + int cvt = idcvar_to_pyvar(args[i], &py_obj); + if ( cvt < CIP_OK ) + { + if ( errbuf != 0 && errbufsize > 0 ) + qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype); + return false; + } + + if ( as_tupple ) + { + // PyTuple_SetItem() steals the reference. + py_obj.incref(); + QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0); + } + else + { + pargs.push_back(py_obj); + } + } + + // Add the tuple to the list of args only now. Doing so earlier will + // cause the py_tuple.o->ob_refcnt to be 2 and not 1, and that will + // cause 'PyTuple_SetItem()' to fail. + if ( as_tupple ) + pargs.push_back(py_tuple); + + return true; +} + +//------------------------------------------------------------------------ +static ref_t ida_idaapi_module; +static ref_t compat_idaapi_module; +static bool pywraps_initialized = false; + +#define SWIG_RUNTIME_VERSION "4" + +//------------------------------------------------------------------------ +// check if we have a file which is known to be executed automatically +// by SWIG or Python runtime +static bool pywraps_check_autoscripts(char *buf, size_t bufsize) +{ + static const char *const exts[] = + { + "py", + "pyc", + "pyd", + "pyo", + "pyw", + }; + + static const char *const fns[] = + { + "swig_runtime_data" SWIG_RUNTIME_VERSION, + "sitecustomize", + "usercustomize" + }; + + for ( size_t ifn=0; ifn < qnumber(fns); ++ifn ) + { + // check for a script or module with several possible extensions + for ( size_t iext=0; iext < qnumber(exts); ++iext ) + { + qsnprintf(buf, bufsize, "%s.%s", fns[ifn], exts[iext]); + if ( qfileexist(buf) ) + return true; + } + // check for a subdirectory under current directory + if ( qfileexist(fns[ifn]) ) + { + qstrncpy(buf, fns[ifn], bufsize); + return true; + } + } + return false; +} + +//------------------------------------------------------------------------ +error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char *msg) +{ + // Create exception object + VarObject(res, find_idc_class("exception")); + + // Set the message field + idc_value_t v; + v.set_string(msg); + VarSetAttr(res, "message", &v); + + // Throw exception + return set_qerrno(eExecThrow); +} + +//------------------------------------------------------------------------ +// Calls a Python callable encoded in IDC.pvoid member +static const char idc_py_invoke0_args[] = { VT_PVOID, 0 }; +static error_t idaapi idc_py_invoke0( + idc_value_t *argv, + idc_value_t *res) +{ + PYW_GIL_GET; + PyObject *pyfunc = (PyObject *) argv[0].pvoid; + newref_t py_result(PyObject_CallFunctionObjArgs(pyfunc, NULL)); + + // Report Python error as IDC exception + qstring err; + error_t err_code = eOk; + if ( PyW_GetError(&err) ) + err_code = PyW_CreateIdcException(res, err.c_str()); + return err_code; +} + +//------------------------------------------------------------------------ +// This function must be called on initialization +static bool init_pywraps() +{ + if ( pywraps_initialized ) + return true; + + // Take a reference to the idaapi python module + // (We need it to create instances of certain classes) + if ( ida_idaapi_module == NULL ) + { + // Take a reference to the module so we can create the needed class instances + ida_idaapi_module = PyW_TryImportModule(S_PY_IDA_IDAAPI_MODNAME); + if ( ida_idaapi_module == NULL ) + return false; + } + + // Register the IDC PyInvoke0 method (helper function for add_idc_hotkey()) + if ( !set_idc_func_ex(S_PYINVOKE0, idc_py_invoke0, idc_py_invoke0_args, 0) ) + return false; + + // IDC opaque class not registered? + if ( get_py_idc_cvt_opaque() == NULL ) + { + // Add the class + idc_class_t *idc_cvt_opaque = add_idc_class(S_PY_IDC_OPAQUE_T); + if ( idc_cvt_opaque == NULL ) + return false; + + // Form the dtor name + char dtor_name[MAXSTR]; + qsnprintf(dtor_name, sizeof(dtor_name), "%s.dtor", S_PY_IDC_OPAQUE_T); + + // Register the dtor function + if ( !set_idc_func_ex(dtor_name, py_idc_opaque_dtor, py_idc_cvt_helper_dtor_args, 0) ) + return false; + + // Link the dtor function to the class + set_idc_dtor(idc_cvt_opaque, dtor_name); + } + + pywraps_initialized = true; + return true; +} + +//------------------------------------------------------------------------ +// This function must be called on de-initialization +static void deinit_pywraps() +{ + if ( !pywraps_initialized ) + return; + + pywraps_initialized = false; + + { + PYW_GIL_CHECK_LOCKED_SCOPE(); + ida_idaapi_module = ref_t(); // Deref. + } + + // Unregister the IDC PyInvoke0 method (helper function for add_idc_hotkey()) + set_idc_func_ex(S_PYINVOKE0, NULL, idc_py_invoke0_args, 0); +} + +//------------------------------------------------------------------------ +// Utility function to create linked class instances +ref_t ida_export create_linked_class_instance( + const char *modname, + const char *clsname, + void *lnk) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t py_module(PyImport_ImportModule(modname)); + ref_t result; + if ( py_module != NULL ) + { + ref_t py_class = PyW_TryGetAttrString(py_module.o, clsname); + if ( py_class != NULL ) + { + newref_t py_lnk(PyCObject_FromVoidPtr(lnk, NULL)); + ref_t py_obj = newref_t(PyObject_CallFunctionObjArgs(py_class.o, py_lnk.o, NULL)); + if ( !PyW_GetError() && py_obj != NULL ) + result = py_obj; + } + } + return result; +} + +//------------------------------------------------------------------------ +// Gets a class type reference in idaapi +// With the class type reference we can create a new instance of that type +// This function takes a reference to the idaapi module and keeps the reference +static ref_t get_idaapi_attr_by_id(const int class_id) +{ + if ( class_id >= PY_CLSID_LAST || ida_idaapi_module == NULL ) + return ref_t(); + + // Some class names. The array is parallel with the PY_CLSID_xxx consts + static const char *class_names[]= + { + "PyIdc_cvt_int64__", + "object_t", + "PyIdc_cvt_refclass__" + }; + PYW_GIL_CHECK_LOCKED_SCOPE(); + return newref_t(PyObject_GetAttrString(ida_idaapi_module.o, class_names[class_id])); +} + +//------------------------------------------------------------------------ +// Gets a class reference by name +static ref_t get_idaapi_attr(const char *attrname) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + return ida_idaapi_module == NULL + ? ref_t() + : PyW_TryGetAttrString(ida_idaapi_module.o, attrname); +} + +//------------------------------------------------------------------------ +// Returns a qstring from an object attribute +bool ida_export PyW_GetStringAttr( + PyObject *py_obj, + const char *attr_name, + qstring *str) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + ref_t py_attr(PyW_TryGetAttrString(py_obj, attr_name)); + if ( py_attr == NULL ) + return false; + + bool ok = PyString_Check(py_attr.o); + if ( ok ) + *str = PyString_AsString(py_attr.o); + + return ok; +} + +//------------------------------------------------------------------------ +// Returns an attribute or NULL +// No errors will be set if the attribute did not exist +ref_t ida_export PyW_TryGetAttrString(PyObject *py_obj, const char *attr) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + ref_t o; + if ( PyObject_HasAttrString(py_obj, attr) ) + o = newref_t(PyObject_GetAttrString(py_obj, attr)); + return o; +} + +//------------------------------------------------------------------------ +// Tries to import a module and clears the exception on failure +ref_t ida_export PyW_TryImportModule(const char *name) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t result(PyImport_ImportModule(name)); + if ( result == NULL && PyErr_Occurred() ) + PyErr_Clear(); + return result; +} + +//------------------------------------------------------------------------- +// Converts a Python number into an IDC value (32 or 64bits) +// The function will first try to convert the number into a 32bit value +// If the number does not fit then VT_INT64 will be used +// NB: This function cannot properly detect if the Python value should be +// converted to a VT_INT64 or not. For example: 2**32-1 = 0xffffffff which +// can fit in a C long but Python creates a PyLong object for it. +// And because of that we are confused as to whether to convert to 32 or 64 +bool ida_export PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_var) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + bool rc = true; + do + { + if ( !(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)) ) + { + rc = false; + break; + } + + // Can we convert to C long? + long l = PyInt_AsLong(py_var); + if ( !PyErr_Occurred() ) + { + idc_var->set_long(l); + break; + } + // Clear last error + PyErr_Clear(); + // Can be fit into a C unsigned long? + l = (long) PyLong_AsUnsignedLong(py_var); + if ( !PyErr_Occurred() ) + { + idc_var->set_long(l); + break; + } + PyErr_Clear(); + idc_var->set_int64(PyLong_AsLongLong(py_var)); + } while ( false ); + return rc; +} + +//------------------------------------------------------------------------- +// Parses a Python object as a long or long long +bool ida_export PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + bool rc = true; +#define SETNUM(numexpr, is64_expr) \ + do \ + { \ + if ( num != NULL ) \ + *num = numexpr; \ + if ( is_64 != NULL ) \ + *is_64 = is64_expr; \ + } while ( false ) + + do + { + if ( !(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)) ) + { + rc = false; + break; + } + + // Can we convert to C long? + long l = PyInt_AsLong(py_var); + if ( !PyErr_Occurred() ) + { + SETNUM(uint64(l), false); + break; + } + + // Clear last error + PyErr_Clear(); + + // Can be fit into a C unsigned long? + unsigned long ul = PyLong_AsUnsignedLong(py_var); + if ( !PyErr_Occurred() ) + { + SETNUM(uint64(ul), false); + break; + } + PyErr_Clear(); + + // Try to parse as int64 + PY_LONG_LONG ll = PyLong_AsLongLong(py_var); + if ( !PyErr_Occurred() ) + { + SETNUM(uint64(ll), true); + break; + } + PyErr_Clear(); + + // Try to parse as uint64 + unsigned PY_LONG_LONG ull = PyLong_AsUnsignedLongLong(py_var); + PyObject *err = PyErr_Occurred(); + if ( err == NULL ) + { + SETNUM(uint64(ull), true); + break; + } + // Negative number? _And_ it with uint64(-1) + rc = false; + if ( err == PyExc_TypeError ) + { + newref_t py_mask(Py_BuildValue("K", 0xFFFFFFFFFFFFFFFFull)); + newref_t py_num(PyNumber_And(py_var, py_mask.o)); + if ( py_num != NULL && py_mask != NULL ) + { + PyErr_Clear(); + ull = PyLong_AsUnsignedLongLong(py_num.o); + if ( !PyErr_Occurred() ) + { + SETNUM(uint64(ull), true); + rc = true; + } + } + } + PyErr_Clear(); + } while ( false ); + return rc; +#undef SETNUM +} + +//------------------------------------------------------------------------- +// Checks if a given object is of sequence type +bool ida_export PyW_IsSequenceType(PyObject *obj) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + bool rc = true; + do + { + if ( !PySequence_Check(obj) ) + { + rc = false; + break; + } + + Py_ssize_t sz = PySequence_Size(obj); + if ( sz == -1 || PyErr_Occurred() != NULL ) + { + PyErr_Clear(); + rc = false; + break; + } + } while ( false ); + return rc; +} + +//------------------------------------------------------------------------- +// Returns the string representation of an object +bool ida_export PyW_ObjectToString(PyObject *obj, qstring *out) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t py_str(PyObject_Str(obj)); + bool ok = py_str != NULL; + if ( ok ) + *out = PyString_AsString(py_str.o); + else + out->qclear(); + return ok; +} + +//-------------------------------------------------------------------------- +// Checks if a Python error occured and fills the out parameter with the +// exception string +bool ida_export PyW_GetError(qstring *out, bool clear_err) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + if ( PyErr_Occurred() == NULL ) + return false; + + // Error occurred but details not needed? + if ( out == NULL ) + { + // Just clear the error + if ( clear_err ) + PyErr_Clear(); + return true; + } + + // Get the exception info + PyObject *err_type, *err_value, *err_traceback, *py_ret(NULL); + PyErr_Fetch(&err_type, &err_value, &err_traceback); + + if ( !clear_err ) + PyErr_Restore(err_type, err_value, err_traceback); + + // Resolve FormatExc() + ref_t py_fmtexc(get_idaapi_attr(S_IDAAPI_FORMATEXC)); + + // Helper there? + if ( py_fmtexc != NULL ) + { + // Call helper + py_ret = PyObject_CallFunctionObjArgs( + py_fmtexc.o, + err_type, + err_value, + err_traceback, + NULL); + } + + // Clear the error + if ( clear_err ) + PyErr_Clear(); + + // Helper failed?! + if ( py_ret == NULL ) + { + // Just convert the 'value' part of the original error + py_ret = PyObject_Str(err_value); + } + + // No exception text? + if ( py_ret == NULL ) + { + *out = "IDAPython: unknown error!"; + } + else + { + *out = PyString_AsString(py_ret); + Py_DECREF(py_ret); + } + + if ( clear_err ) + { + Py_XDECREF(err_traceback); + Py_XDECREF(err_value); + Py_XDECREF(err_type); + } + return true; +} + +//------------------------------------------------------------------------- +static bool PyW_GetError(char *buf, size_t bufsz, bool clear_err) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + qstring s; + if ( !PyW_GetError(&s, clear_err) ) + return false; + + qstrncpy(buf, s.c_str(), bufsz); + return true; +} + +//------------------------------------------------------------------------- +// A loud version of PyGetError() which gets the error and displays it +// This method is used to display errors that occurred in a callback +bool ida_export PyW_ShowCbErr(const char *cb_name) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + static qstring err_str; + if ( !PyW_GetError(&err_str) ) + return false; + + msg("IDAPython: Error while calling Python callback <%s>:\n%s", cb_name, err_str.c_str()); + return true; +} + +//--------------------------------------------------------------------------- +void *ida_export pyobj_get_clink(PyObject *pyobj) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + // Try to query the link attribute + ref_t attr(PyW_TryGetAttrString(pyobj, S_CLINK_NAME)); + void *t = attr != NULL && PyCObject_Check(attr.o) ? PyCObject_AsVoidPtr(attr.o) : NULL; + return t; +} + +//------------------------------------------------------------------------ +int idaapi pywraps_notify_when_t::idp_callback(void *ud, int event_id, va_list va) +{ + pywraps_notify_when_t *_this = (pywraps_notify_when_t *)ud; + switch ( event_id ) + { + case processor_t::newfile: + case processor_t::oldfile: + { + // This hook gets called from the kernel. Ensure we hold the GIL. + // Note that PYW_GIL_GET appears in each case of the switch, which is to + // ensure that the GIL is retrieved ONLY when we need it. If PYW_GIL_GET + // appears outside the switch, it will be executed each time this callback + // is called, which results in a huge slowdown (at least on mac). + PYW_GIL_GET; + int old = event_id == processor_t::oldfile ? 1 : 0; + char *dbname = va_arg(va, char *); + _this->notify(NW_OPENIDB_SLOT, old); + } + break; + case processor_t::closebase: + { + PYW_GIL_GET; + _this->notify(NW_CLOSEIDB_SLOT); + } + break; + } + // event not processed, let other plugins or the processor module handle it + return 0; +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::unnotify_when(int when, PyObject *py_callable) +{ + int cnt = 0; + for ( int slot=0; slot < NW_EVENTSCNT; slot++ ) + { + // convert index to flag and see + if ( ((1 << slot) & when) != 0 ) + { + unregister_callback(slot, py_callable); + ++cnt; + } + } + return cnt > 0; +} + +//------------------------------------------------------------------------ +void pywraps_notify_when_t::register_callback(int slot, PyObject *py_callable) +{ + borref_t callable_ref(py_callable); + ref_vec_t &tbl = table[slot]; + ref_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, callable_ref); + + // Already added + if ( it != it_end ) + return; + + // Insert the element + tbl.push_back(callable_ref); +} + +//------------------------------------------------------------------------ +void pywraps_notify_when_t::unregister_callback(int slot, PyObject *py_callable) +{ + borref_t callable_ref(py_callable); + ref_vec_t &tbl = table[slot]; + ref_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, callable_ref); + + // Not found? + if ( it == it_end ) + return; + + // Delete the element + tbl.erase(it); +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::init() +{ + return hook_to_notification_point(HT_IDP, idp_callback, this); +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::deinit() +{ + // Uninstall all objects + ref_vec_t::iterator it, it_end; + for ( int slot=0; slot < NW_EVENTSCNT; slot++ ) + { + for ( it = table[slot].begin(), it_end = table[slot].end(); it != it_end; ++it ) + unregister_callback(slot, it->o); + } + // ...and remove the notification + return unhook_from_notification_point(HT_IDP, idp_callback, this); +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::notify_when(int when, PyObject *py_callable) +{ + // While in notify() do not allow insertion or deletion to happen on the spot + // Instead we will queue them so that notify() will carry the action when it finishes + // dispatching the notification handlers + if ( in_notify ) + { + notify_when_args_t &args = delayed_notify_when_list.push_back(); + args.when = when; + args.py_callable = py_callable; + return true; + } + // Uninstalling the notification? + if ( (when & NW_REMOVE) != 0 ) + return unnotify_when(when & ~NW_REMOVE, py_callable); + + int cnt = 0; + for ( int slot=0; slot < NW_EVENTSCNT; slot++ ) + { + // is this flag set? + if ( ((1 << slot) & when) != 0 ) + { + register_callback(slot, py_callable); + ++cnt; + } + } + return cnt > 0; +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::notify(int slot, ...) +{ + va_list va; + va_start(va, slot); + bool ok = notify_va(slot, va); + va_end(va); + return ok; +} + +//------------------------------------------------------------------------ +bool pywraps_notify_when_t::notify_va(int slot, va_list va) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + // Sanity bounds check! + if ( slot < 0 || slot >= NW_EVENTSCNT ) + return false; + + bool ok = true; + in_notify = true; + int old = slot == NW_OPENIDB_SLOT ? va_arg(va, int) : 0; + + { + for ( ref_vec_t::iterator it = table[slot].begin(), it_end = table[slot].end(); + it != it_end; + ++it ) + { + // Form the notification code + newref_t py_code(PyInt_FromLong(1 << slot)); + ref_t py_result; + switch ( slot ) + { + case NW_CLOSEIDB_SLOT: + case NW_INITIDA_SLOT: + case NW_TERMIDA_SLOT: + { + py_result = newref_t(PyObject_CallFunctionObjArgs(it->o, py_code.o, NULL)); + break; + } + case NW_OPENIDB_SLOT: + { + newref_t py_old(PyInt_FromLong(old)); + py_result = newref_t(PyObject_CallFunctionObjArgs(it->o, py_code.o, py_old.o, NULL)); + } + break; + } + if ( PyW_GetError(&err) || py_result == NULL ) + { + PyErr_Clear(); + warning("notify_when(): Error occured while notifying object.\n%s", err.c_str()); + ok = false; + } + } + } + in_notify = false; + + // Process any delayed notify_when() calls that + if ( !delayed_notify_when_list.empty() ) + { + notify_when_args_vec_t::iterator it, it_end; + for ( it = delayed_notify_when_list.begin(), it_end=delayed_notify_when_list.end(); + it != it_end; + ++it ) + { + notify_when(it->when, it->py_callable); + } + delayed_notify_when_list.qclear(); + } + + return ok; +} + +//------------------------------------------------------------------------- +static pywraps_notify_when_t *g_nw = NULL; + +//------------------------------------------------------------------------- +bool ida_export add_notify_when(int when, PyObject *py_callable) +{ + return g_nw != NULL && g_nw->notify_when(when, py_callable); +} + +//------------------------------------------------------------------------ +// Initializes the notify_when mechanism +// (Normally called by IDAPython plugin.init()) +static bool pywraps_nw_init() +{ + if ( g_nw != NULL ) + return true; + + g_nw = new pywraps_notify_when_t(); + if ( g_nw->init() ) + return true; + + // Things went bad, undo! + delete g_nw; + g_nw = NULL; + return false; +} + +//------------------------------------------------------------------------ +static bool pywraps_nw_notify(int slot, ...) +{ + if ( g_nw == NULL ) + return false; + + // Appears to be called from 'driver_notifywhen.cpp', which + // itself is called from possibly non-python code. + // I.e., we must acquire the GIL. + PYW_GIL_GET; + va_list va; + va_start(va, slot); + bool ok = g_nw->notify_va(slot, va); + va_end(va); + + return ok; +} + +//------------------------------------------------------------------------ +// Deinitializes the notify_when mechanism +static bool pywraps_nw_term() +{ + if ( g_nw == NULL ) + return true; + + // If could not deinitialize then return w/o stopping nw + if ( !g_nw->deinit() ) + return false; + + // Cleanup + delete g_nw; + g_nw = NULL; + return true; +} + +//------------------------------------------------------------------------- +// lookup_info_t +//------------------------------------------------------------------------- +lookup_entry_t &ida_export lookup_info_t_new_entry(lookup_info_t *_this, py_customidamemo_t *py_view) +{ + QASSERT(30454, py_view != NULL && !_this->find_by_py_view(NULL, NULL, py_view)); + lookup_entry_t &e = _this->entries.push_back(); + e.py_view = py_view; + return e; +} + +//------------------------------------------------------------------------- +void ida_export lookup_info_t_commit(lookup_info_t *_this, lookup_entry_t &e, TForm *form, TCustomControl *view) +{ + QASSERT(30455, &e >= _this->entries.begin() && &e < _this->entries.end()); + QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL + && !_this->find_by_form(NULL, NULL, form) + && !_this->find_by_view(NULL, NULL, view) + && _this->find_by_py_view(NULL, NULL, e.py_view)); + e.form = form; + e.view = view; +} + +//------------------------------------------------------------------------- +#define FIND_BY__BODY(self, crit, res1, res2) \ + { \ + for ( lookup_entries_t::const_iterator it = self->entries.begin(); it != self->entries.end(); ++it ) \ + { \ + const lookup_entry_t &e = *it; \ + if ( e.crit == crit ) \ + { \ + if ( out_##res1 != NULL ) \ + *out_##res1 = e.res1; \ + if ( out_##res2 != NULL ) \ + *out_##res2 = e.res2; \ + return true; \ + } \ + } \ + return false; \ + } + +bool ida_export lookup_info_t_find_by_form( + const lookup_info_t *_this, + TCustomControl **out_view, + py_customidamemo_t **out_py_view, + const TForm *form) + FIND_BY__BODY(_this, form, view, py_view); + +bool ida_export lookup_info_t_find_by_py_view( + const lookup_info_t *_this, + TForm **out_form, + TCustomControl **out_view, + const py_customidamemo_t *py_view) + FIND_BY__BODY(_this, py_view, view, form); + +bool lookup_info_t::find_by_view( + TForm **out_form, + py_customidamemo_t **out_py_view, + const TCustomControl *view) const + FIND_BY__BODY(this, view, form, py_view); +#undef FIND_BY__BODY + +//------------------------------------------------------------------------- +bool ida_export lookup_info_t_del_by_py_view( + lookup_info_t *_this, + const py_customidamemo_t *py_view) +{ + for ( lookup_entries_t::iterator it = _this->entries.begin(); it != _this->entries.end(); ++it ) + { + if ( it->py_view == py_view ) + { + _this->entries.erase(it); + return true; + } + } + return false; +} + +//------------------------------------------------------------------------- +lookup_info_t pycim_lookup_info; + +//------------------------------------------------------------------------- +// py_customidamemo_t +//------------------------------------------------------------------------- +void py_customidamemo_t::convert_node_info( + node_info_t *out, + uint32 *out_flags, + ref_t py_nodeinfo) +{ + if ( out_flags != NULL ) + *out_flags = 0; +#define COPY_PROP(checker, converter, pname, flag) \ + do \ + { \ + newref_t pname(PyObject_GetAttrString(py_nodeinfo.o, #pname)); \ + if ( pname != NULL && checker(pname.o) ) \ + { \ + out->pname = converter(pname.o); \ + if ( out_flags != NULL ) \ + *out_flags |= flag; \ + } \ + } while ( false ) +#define COPY_ULONG_PROP(pname, flag) COPY_PROP(PyNumber_Check, PyLong_AsUnsignedLong, pname, flag) +#define COPY_STRING_PROP(pname, flag) COPY_PROP(PyString_Check, PyString_AsString, pname, flag) + COPY_ULONG_PROP(bg_color, NIF_BG_COLOR); + COPY_ULONG_PROP(frame_color, NIF_FRAME_COLOR); + COPY_ULONG_PROP(ea, NIF_EA); + COPY_STRING_PROP(text, NIF_TEXT); +#undef COPY_STRING_PROP +#undef COPY_ULONG_PROP +#undef COPY_PROP +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_ensure_view_callbacks_installed() +{ + static bool installed = false; + if ( !installed ) + { + struct ida_local lambda_t + { + static int idaapi callback(void * /*ud*/, int code, va_list va) + { + py_customidamemo_t *py_view; + if ( pycim_lookup_info.find_by_view(NULL, &py_view, va_arg(va, TCustomControl *)) ) + { + PYW_GIL_GET; + switch ( code ) + { + case view_activated: + py_view->on_view_activated(); + break; + case view_deactivated: + py_view->on_view_deactivated(); + break; + case view_keydown: + { + int key = va_arg(va, int); + int state = va_arg(va, int); + py_view->on_view_keydown(key, state); + } + break; + case obsolete_view_popup: + py_view->on_view_popup(); + break; + case view_click: + case view_dblclick: + { + const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); + if ( code == view_click ) + py_view->on_view_click(event); + else + py_view->on_view_dblclick(event); + } + break; + case view_curpos: + py_view->on_view_curpos(); + break; + case view_close: + py_view->on_view_close(); + delete py_view; + break; + case view_switched: + { + tcc_renderer_type_t rt = (tcc_renderer_type_t) va_arg(va, int); + py_view->on_view_switched(rt); + } + break; + case view_mouse_over: + { + const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); + py_view->on_view_mouse_over(event); + } + break; + } + } + return 0; + } + }; + hook_to_notification_point(HT_VIEW, lambda_t::callback, NULL); + installed = true; + } +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_set_node_info( + py_customidamemo_t *_this, + PyObject *py_node_idx, + PyObject *py_node_info, + PyObject *py_flags) +{ + if ( !PyNumber_Check(py_node_idx) || !PyNumber_Check(py_flags) ) + return; + borref_t py_idx(py_node_idx); + borref_t py_ni(py_node_info); + borref_t py_fl(py_flags); + node_info_t ni; + _this->convert_node_info(&ni, NULL, py_ni); + int idx = PyInt_AsLong(py_idx.o); + uint32 flgs = PyLong_AsLong(py_fl.o); + viewer_set_node_info(_this->view, idx, ni, flgs); +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_set_nodes_infos( + py_customidamemo_t *_this, + PyObject *dict) +{ + if ( !PyDict_Check(dict) ) + return; + Py_ssize_t pos = 0; + PyObject *o_key, *o_value; + while ( PyDict_Next(dict, &pos, &o_key, &o_value) ) + { + borref_t key(o_key); + borref_t value(o_value); + if ( !PyNumber_Check(key.o) ) + continue; + uint32 flags; + node_info_t ni; + _this->convert_node_info(&ni, &flags, value); + int idx = PyInt_AsLong(key.o); + viewer_set_node_info(_this->view, idx, ni, flags); + } +} + +//------------------------------------------------------------------------- +PyObject *ida_export py_customidamemo_t_get_node_info( + py_customidamemo_t *_this, + PyObject *py_node_idx) +{ + if ( !PyNumber_Check(py_node_idx) ) + Py_RETURN_NONE; + node_info_t ni; + if ( !viewer_get_node_info(_this->view, &ni, PyInt_AsLong(py_node_idx)) ) + Py_RETURN_NONE; + return Py_BuildValue("(kkks)", ni.bg_color, ni.frame_color, ni.ea, ni.text.c_str()); +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_del_nodes_infos( + py_customidamemo_t *_this, + PyObject *py_nodes) +{ + if ( !PySequence_Check(py_nodes) ) + return; + Py_ssize_t sz = PySequence_Size(py_nodes); + for ( Py_ssize_t i = 0; i < sz; ++i ) + { + newref_t item(PySequence_GetItem(py_nodes, i)); + if ( !PyNumber_Check(item.o) ) + continue; + int idx = PyInt_AsLong(item.o); + viewer_del_node_info(_this->view, idx); + } +} + +//------------------------------------------------------------------------- +PyObject *ida_export py_customidamemo_t_get_current_renderer_type( + py_customidamemo_t *_this) +{ + tcc_renderer_type_t rt = get_view_renderer_type(_this->view); + return PyLong_FromLong(long(rt)); +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_set_current_renderer_type( + py_customidamemo_t *_this, + PyObject *py_rto) +{ + tcc_renderer_type_t rt = TCCRT_INVALID; + borref_t py_rt(py_rto); + if ( PyNumber_Check(py_rt.o) ) + { + rt = tcc_renderer_type_t(PyLong_AsLong(py_rt.o)); + set_view_renderer_type(_this->view, rt); + } +} + +//------------------------------------------------------------------------- +PyObject *ida_export py_customidamemo_t_create_groups( + py_customidamemo_t *_this, + PyObject *_groups_infos) +{ + if ( !PySequence_Check(_groups_infos) ) + Py_RETURN_NONE; + borref_t groups_infos(_groups_infos); + groups_crinfos_t gis; + Py_ssize_t sz = PySequence_Size(groups_infos.o); + for ( Py_ssize_t i = 0; i < sz; ++i ) + { + newref_t item(PySequence_GetItem(groups_infos.o, i)); + if ( !PyDict_Check(item.o) ) + continue; + borref_t nodes(PyDict_GetItemString(item.o, "nodes")); + if ( nodes.o == NULL || !PySequence_Check(nodes.o) ) + continue; + borref_t text(PyDict_GetItemString(item.o, "text")); + if ( text.o == NULL || !PyString_Check(text.o) ) + continue; + group_crinfo_t gi; + Py_ssize_t nodes_cnt = PySequence_Size(nodes.o); + for ( Py_ssize_t k = 0; k < nodes_cnt; ++k ) + { + newref_t node(PySequence_GetItem(nodes.o, k)); + if ( PyInt_Check(node.o) ) + gi.nodes.add_unique(PyInt_AsLong(node.o)); + } + if ( !gi.nodes.empty() ) + { + gi.text = PyString_AsString(text.o); + gis.push_back(gi); + } + } + intvec_t groups; + if ( gis.empty() || !viewer_create_groups(_this->view, &groups, gis) || groups.empty() ) + Py_RETURN_NONE; + + PyObject *py_groups = PyList_New(0); + for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) + PyList_Append(py_groups, PyInt_FromLong(long(*it))); + return py_groups; +} + +//------------------------------------------------------------------------- +static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes) +{ + Py_ssize_t sz = PySequence_Size(pynodes.o); + for ( Py_ssize_t i = 0; i < sz; ++i ) + { + newref_t item(PySequence_GetItem(pynodes.o, i)); + if ( !PyInt_Check(item.o) ) + continue; + idanodes->add_unique(PyInt_AsLong(item.o)); + } +} + +//------------------------------------------------------------------------- +PyObject *ida_export py_customidamemo_t_delete_groups( + py_customidamemo_t *_this, + PyObject *_groups, + PyObject *_new_current) +{ + if ( !PySequence_Check(_groups) || !PyNumber_Check(_new_current) ) + Py_RETURN_NONE; + borref_t groups(_groups); + borref_t new_current(_new_current); + intvec_t ida_groups; + pynodes_to_idanodes(&ida_groups, groups); + if ( ida_groups.empty() ) + Py_RETURN_NONE; + if ( viewer_delete_groups(_this->view, ida_groups, int(PyInt_AsLong(new_current.o))) ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +//------------------------------------------------------------------------- +PyObject *ida_export py_customidamemo_t_set_groups_visibility( + py_customidamemo_t *_this, + PyObject *_groups, + PyObject *_expand, + PyObject *_new_current) +{ + if ( !PySequence_Check(_groups) + || !PyBool_Check(_expand) + || !PyNumber_Check(_new_current) ) + Py_RETURN_NONE; + borref_t groups(_groups); + borref_t expand(_expand); + borref_t new_current(_new_current); + intvec_t ida_groups; + pynodes_to_idanodes(&ida_groups, groups); + if ( ida_groups.empty() ) + Py_RETURN_NONE; + if ( viewer_set_groups_visibility(_this->view, ida_groups, expand.o == Py_True, int(PyInt_AsLong(new_current.o))) ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +//------------------------------------------------------------------------- +bool ida_export py_customidamemo_t_bind(py_customidamemo_t *_this, PyObject *self, TCustomControl *view) +{ + if ( _this->self != NULL || _this->view != NULL ) + return false; + PYGLOG("%p: py_customidamemo_t::bind(self=%p, view=%p)\n", this, _this->_self, _this->view); + PYW_GIL_CHECK_LOCKED_SCOPE(); + + newref_t py_cobj(PyCObject_FromVoidPtr(_this, NULL)); + PyObject_SetAttrString(self, S_M_THIS, py_cobj.o); + + _this->self = borref_t(self); + _this->view = view; + return true; +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_unbind(py_customidamemo_t *_this, bool clear_view) +{ + if ( _this->self == NULL ) + return; + PYGLOG("%p: py_customidamemo_t::unbind(); self.o=%p, view=%p\n", _this, _this->self.o, _this->view); + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t py_cobj(PyCObject_FromVoidPtr(NULL, NULL)); + PyObject_SetAttrString(_this->self.o, S_M_THIS, py_cobj.o); + _this->self = newref_t(NULL); + if ( clear_view ) + _this->view = NULL; +} + +//------------------------------------------------------------------------- +void idaapi py_customidamemo_t::s_on_view_mouse_moved( + TCustomControl *cv, + int shift, + view_mouse_event_t *e, + void *ud) +{ + PYW_GIL_GET; + py_customidamemo_t *_this = (py_customidamemo_t *) ud; + _this->on_view_mouse_moved(e); +} + +//------------------------------------------------------------------------- +int py_customidamemo_t::get_py_method_arg_count(char *method_name) +{ + newref_t method(PyObject_GetAttrString(self.o, method_name)); + if ( method != NULL && PyCallable_Check(method.o) ) + { + newref_t fc(PyObject_GetAttrString(method.o, "func_code")); + if ( fc != NULL ) + { + newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount")); + if ( ac != NULL ) + return PyInt_AsLong(ac.o); + } + } + return -1; +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_collect_class_callbacks_ids( + py_customidamemo_t *_this, + pycim_callbacks_ids_t *out) +{ + out->add(S_ON_VIEW_ACTIVATED, _this->GRBASE_HAVE_VIEW_ACTIVATED); + out->add(S_ON_VIEW_DEACTIVATED, _this->GRBASE_HAVE_VIEW_DEACTIVATED); + out->add(S_ON_VIEW_KEYDOWN, _this->GRBASE_HAVE_KEYDOWN); + out->add(S_ON_POPUP, _this->GRBASE_HAVE_POPUP); + out->add(S_ON_VIEW_CLICK, _this->GRBASE_HAVE_VIEW_CLICK); + out->add(S_ON_VIEW_DBLCLICK, _this->GRBASE_HAVE_VIEW_DBLCLICK); + out->add(S_ON_VIEW_CURPOS, _this->GRBASE_HAVE_VIEW_CURPOS); + out->add(S_ON_CLOSE, _this->GRBASE_HAVE_CLOSE); + out->add(S_ON_VIEW_SWITCHED, _this->GRBASE_HAVE_VIEW_SWITCHED); + out->add(S_ON_VIEW_MOUSE_OVER, _this->GRBASE_HAVE_VIEW_MOUSE_OVER); + out->add(S_ON_VIEW_MOUSE_MOVED, _this->GRBASE_HAVE_VIEW_MOUSE_MOVED); +} + +//------------------------------------------------------------------------- +bool ida_export py_customidamemo_t_collect_pyobject_callbacks( + py_customidamemo_t *_this, + PyObject *o) +{ + pycim_callbacks_ids_t cbids; + _this->collect_class_callbacks_ids(&cbids); + _this->cb_flags = 0; + for ( pycim_callbacks_ids_t::const_iterator it = cbids.begin(); it != cbids.end(); ++it ) + { + const pycim_callback_id_t &cbid = *it; + ref_t attr(PyW_TryGetAttrString(o, cbid.name.c_str())); + int have = cbid.have; + // Mandatory fields not present? + if ( (attr == NULL && have <= 0) + // Mandatory callback fields present but not callable? + || (attr != NULL && have >= 0 && PyCallable_Check(attr.o) == 0) ) + { + return false; + } + if ( have > 0 && attr != NULL ) + _this->cb_flags |= have; + } + + return true; +} + +//------------------------------------------------------------------------- +void ida_export py_customidamemo_t_install_custom_viewer_handlers( + py_customidamemo_t *_this) +{ + if ( _this->has_callback(_this->GRBASE_HAVE_VIEW_MOUSE_MOVED) ) + { + // Set user-data + set_custom_viewer_handler(_this->view, CVH_USERDATA, (void *)_this); + + // + set_custom_viewer_handler(_this->view, CVH_MOUSEMOVE, (void *) py_customidamemo_t::s_on_view_mouse_moved); + } +} + +//------------------------------------------------------------------------- +#define CHK_EVT(flag_needed) \ + if ( self == NULL || !has_callback(flag_needed) ) \ + return; \ + PYW_GIL_CHECK_LOCKED_SCOPE() + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_activated() +{ + CHK_EVT(GRBASE_HAVE_VIEW_ACTIVATED); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_ACTIVATED, + NULL)); +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_deactivated() +{ + CHK_EVT(GRBASE_HAVE_VIEW_DEACTIVATED); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_DEACTIVATED, + NULL)); +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_keydown(int key, int state) +{ + CHK_EVT(GRBASE_HAVE_KEYDOWN); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_KEYDOWN, + "ii", + key, state)); +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_popup() +{ + CHK_EVT(GRBASE_HAVE_POPUP); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_POPUP, + NULL)); +} + +//------------------------------------------------------------------------- +static PyObject *build_renderer_pos_swig_proxy(const view_mouse_event_t *event) +{ + newref_t py_module(PyImport_ImportModule(S_IDA_KERNWIN_MODNAME)); + ref_t py_result; + if ( py_module != NULL ) + { + ref_t py_class = PyW_TryGetAttrString(py_module.o, "renderer_pos_info_t"); + if ( py_class != NULL ) + { + ref_t py_obj = newref_t(PyObject_CallFunctionObjArgs(py_class.o, NULL)); + if ( py_obj != NULL ) + { + newref_t py_node(PyInt_FromLong(event->renderer_pos.node)); + PyObject_SetAttrString(py_obj.o, "node", py_node.o); + newref_t py_cx(PyInt_FromLong(event->renderer_pos.cx)); + PyObject_SetAttrString(py_obj.o, "cx", py_cx.o); + newref_t py_cy(PyInt_FromLong(event->renderer_pos.cy)); + PyObject_SetAttrString(py_obj.o, "cy", py_cy.o); + newref_t py_sx(PyInt_FromLong(event->renderer_pos.sx)); + PyObject_SetAttrString(py_obj.o, "sx", py_sx.o); + py_result = py_obj; + } + } + } + if ( py_result != NULL ) + { + py_result.incref(); + return py_result.o; + } + else + { + return NULL; + } +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) +{ + CHK_EVT(GRBASE_HAVE_VIEW_CLICK); + if ( ovc_num_args < 0 ) + ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); + if ( ovc_num_args == 6 ) + { + PyObject *rpos = build_renderer_pos_swig_proxy(event); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iiiiO", + event->x, event->y, event->state, event->button, rpos)); + } + else if ( ovc_num_args == 5 ) + { + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iiii", + event->x, event->y, event->state, event->button)); + } + else + { + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iii", + event->x, event->y, event->state)); + } +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event) +{ + CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK); + if ( ovdc_num_args < 0 ) + ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK); + if ( ovdc_num_args == 5 ) + { + PyObject *rpos = build_renderer_pos_swig_proxy(event); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_DBLCLICK, + "iiiO", + event->x, event->y, event->state, rpos)); + } + else + { + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_DBLCLICK, + "iii", + event->x, event->y, event->state)); + } +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_curpos() +{ + CHK_EVT(GRBASE_HAVE_VIEW_CURPOS); + pycall_res_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CURPOS, + NULL)); +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_close() +{ + CHK_EVT(GRBASE_HAVE_CLOSE); + pycall_res_t result(PyObject_CallMethod(self.o, (char *)S_ON_CLOSE, NULL)); +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_switched(tcc_renderer_type_t rt) +{ + CHK_EVT(GRBASE_HAVE_VIEW_SWITCHED); + pycall_res_t result(PyObject_CallMethod(self.o, (char *)S_ON_VIEW_SWITCHED, "i", int(rt))); +} + +//------------------------------------------------------------------------- +static ref_t build_current_graph_item_tuple(int *out_icode, const view_mouse_event_t *event) +{ + const selection_item_t *item = event->location.item; + ref_t tuple; + if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY) + && item != NULL ) + { + if ( item->is_node ) + { + *out_icode = 1; + tuple = newref_t(Py_BuildValue("(i)", item->node)); + } + else + { + *out_icode = 2; + tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst)); + } + } + else + { + *out_icode = 0; + tuple = newref_t(Py_BuildValue("()")); + } + return tuple; +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event) +{ + CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER); + if ( ovmo_num_args < 0 ) + ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER); + if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY ) + return; + + int icode; + ref_t tuple = build_current_graph_item_tuple(&icode, event); + if ( ovmo_num_args == 7 ) + { + PyObject *rpos = build_renderer_pos_swig_proxy(event); + pycall_res_t result(PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_MOUSE_OVER, + "iiiiOO", + event->x, event->y, event->state, icode, tuple.o, rpos)); + } + else + { + pycall_res_t result(PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_MOUSE_OVER, + "iiiiO", + event->x, event->y, event->state, icode, tuple.o)); + } +} + +//------------------------------------------------------------------------- +void py_customidamemo_t::on_view_mouse_moved(const view_mouse_event_t *event) +{ + CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_MOVED); + if ( ovmm_num_args < 0 ) + ovmm_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_MOVED); + + int icode; + ref_t tuple = build_current_graph_item_tuple(&icode, event); + if ( ovmm_num_args == 7 ) + { + PyObject *rpos = build_renderer_pos_swig_proxy(event); + pycall_res_t result(PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_MOUSE_MOVED, + "iiiiOO", + event->x, event->y, event->state, icode, tuple.o, rpos)); + } +} + + +#undef CHK_EVT + +//------------------------------------------------------------------------- +// +//------------------------------------------------------------------------- + +//------------------------------------------------------------------------- +// A set of tinfo_t & details objects that were created from IDAPython. +// This is necessary in order to clear all the "type details" that are +// associated, in the kernel, with the tinfo_t instances. +// +// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is +// closed, but the "type details" must be cleared _before_ the IDB is closed. +static qvector py_tinfo_t_vec; +static qvector py_ptr_type_data_t_vec; +static qvector py_array_type_data_t_vec; +static qvector py_func_type_data_t_vec; +static qvector py_udt_type_data_t_vec; + +static void __clear(tinfo_t *inst) { inst->clear(); } +static void __clear(ptr_type_data_t *inst) { inst->obj_type.clear(); inst->closure.clear(); } +static void __clear(array_type_data_t *inst) { inst->elem_type.clear(); } +static void __clear(func_type_data_t *inst) { inst->clear(); inst->rettype.clear(); } +static void __clear(udt_type_data_t *inst) { inst->clear(); } + +static void til_clear_python_tinfo_t_instances(void) +{ + // Pre-emptive strike: clear all the python-exposed tinfo_t + // (& related types) instances: if that were not done here, + // ~tinfo_t() calls happening as part of the python shutdown + // process will try and clear() their details. ..but the kernel's + // til-related functions will already have deleted those details + // at that point. + // + // NOTE: Don't clear() the arrays of pointers. All the python-exposed + // instances will be deleted through the python shutdown/ref-decrementing + // process anyway (which will cause til_deregister_..() calls), and the + // entries will be properly pulled out of the vector when that happens. +#define BATCH_CLEAR(Type) \ + do \ + { \ + for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \ + __clear(py_##Type##_vec[i]); \ + } while ( false ) + + BATCH_CLEAR(tinfo_t); + BATCH_CLEAR(ptr_type_data_t); + BATCH_CLEAR(array_type_data_t); + BATCH_CLEAR(func_type_data_t); + BATCH_CLEAR(udt_type_data_t); +#undef BATCH_CLEAR +} + +#define DEF_REG_UNREG_REFCOUNTED(Type) \ + void ida_export til_register_python_##Type##_instance(Type *inst) \ + { \ + /* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \ + /* to an object's tinfo_t property will end up trying to register it. */ \ + py_##Type##_vec.add_unique(inst); \ + } \ + \ + void ida_export til_deregister_python_##Type##_instance(Type *inst) \ + { \ + qvector::iterator found = py_##Type##_vec.find(inst); \ + if ( found != py_##Type##_vec.end() ) \ + { \ + __clear(inst); \ + /* tif->clear();*/ \ + py_##Type##_vec.erase(found); \ + } \ + } + +DEF_REG_UNREG_REFCOUNTED(tinfo_t); +DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t); +DEF_REG_UNREG_REFCOUNTED(array_type_data_t); +DEF_REG_UNREG_REFCOUNTED(func_type_data_t); +DEF_REG_UNREG_REFCOUNTED(udt_type_data_t); + +//------------------------------------------------------------------------- +// +//--------------------------------------------------------------------------- +static qvector live_timers; +py_timer_ctx_t *ida_export python_timer_new(PyObject *py_callback) +{ + py_timer_ctx_t *t = new py_timer_ctx_t(); + t->pycallback = py_callback; + Py_INCREF(t->pycallback); + live_timers.push_back(t); + return t; +} + +//------------------------------------------------------------------------- +void ida_export python_timer_del(py_timer_ctx_t *t) +{ + QASSERT(30491, live_timers.del(t)); + Py_DECREF(t->pycallback); + delete t; +} + +//------------------------------------------------------------------------- +static void clear_python_timer_instances(void) +{ + // Pre-emptive strike: clear all the existing python-exposed + // timers, or there's a chance IDA will try and execute some + // python code after IDAPython is removed from memory. + while ( !live_timers.empty() ) + { + py_timer_ctx_t *t = live_timers[0]; + unregister_timer(t->timer_id); + python_timer_del(t); + } +} + +#undef DEF_REG_UNREG_REFCOUNTED diff --git a/pywraps.hpp b/pywraps.hpp index 1e6a138..afe7760 100644 --- a/pywraps.hpp +++ b/pywraps.hpp @@ -1,6 +1,8 @@ #ifndef __PYWRAPS_HPP__ #define __PYWRAPS_HPP__ +#include + //------------------------------------------------------------------------ // Types #ifndef PYUL_DEFINED @@ -14,6 +16,10 @@ #endif #endif +// a few forward decls +class insn_t; +class op_t; +struct switch_info_ex_t; // "A pointer can be explicitly converted to any integral type large // enough to hold it. The mapping function is implementation-defined." @@ -37,6 +43,11 @@ #define PTR2U64(Binding) (uint64(uint32(Binding))) #endif +#if defined(__LINUX__) || defined(__MAC__) +#define exported __attribute__((visibility("default"))) +#else +#define exported +#endif #ifdef __EA64__ #define PY_FMT64 "K" @@ -47,7 +58,10 @@ #endif //------------------------------------------------------------------------ -#define S_IDAAPI_MODNAME "idaapi" +#define S_IDA_IDAAPI_MODNAME "ida_idaapi" +#define S_IDA_NALT_MODNAME "ida_nalt" +#define S_IDA_UA_MODNAME "ida_ua" +#define S_IDA_KERNWIN_MODNAME "ida_kernwin" #define S_IDC_MODNAME "idc" #define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript" #define S_IDAAPI_COMPLETION "IDAPython_Completion" @@ -55,6 +69,83 @@ #define S_IDAAPI_LOADPROCMOD "IDAPython_LoadProcMod" #define S_IDAAPI_UNLOADPROCMOD "IDAPython_UnLoadProcMod" + +//------------------------------------------------------------------------ +// String constants used +static const char S_PYINVOKE0[] = "_py_invoke0"; +static const char S_PY_SWIEX_CLSNAME[] = "switch_info_ex_t"; +static const char S_PY_OP_T_CLSNAME[] = "op_t"; +static const char S_PROPS[] = "props"; +static const char S_NAME[] = "name"; +static const char S_TITLE[] = "title"; +static const char S_ASM_KEYWORD[] = "asm_keyword"; +static const char S_MENU_NAME[] = "menu_name"; +static const char S_HOTKEY[] = "hotkey"; +static const char S_EMBEDDED[] = "embedded"; +static const char S_POPUP_NAMES[] = "popup_names"; +static const char S_FLAGS[] = "flags"; +static const char S_VALUE_SIZE[] = "value_size"; +static const char S_MAY_CREATE_AT[] = "may_create_at"; +static const char S_CALC_ITEM_SIZE[] = "calc_item_size"; +static const char S_ID[] = "id"; +static const char S_PRINTF[] = "printf"; +static const char S_TEXT_WIDTH[] = "text_width"; +static const char S_SCAN[] = "scan"; +static const char S_ANALYZE[] = "analyze"; +static const char S_CBSIZE[] = "cbsize"; +static const char S_ON_CLICK[] = "OnClick"; +static const char S_ON_CLOSE[] = "OnClose"; +static const char S_ON_DBL_CLICK[] = "OnDblClick"; +static const char S_ON_CURSOR_POS_CHANGED[] = "OnCursorPosChanged"; +static const char S_ON_KEYDOWN[] = "OnKeydown"; +static const char S_ON_COMPLETE_LINE[] = "OnCompleteLine"; +static const char S_ON_CREATE[] = "OnCreate"; +static const char S_ON_POPUP[] = "OnPopup"; +static const char S_ON_HINT[] = "OnHint"; +static const char S_ON_POPUP_MENU[] = "OnPopupMenu"; +static const char S_ON_EDIT_LINE[] = "OnEditLine"; +static const char S_ON_INSERT_LINE[] = "OnInsertLine"; +static const char S_ON_GET_LINE[] = "OnGetLine"; +static const char S_ON_DELETE_LINE[] = "OnDeleteLine"; +static const char S_ON_REFRESH[] = "OnRefresh"; +static const char S_ON_REFRESHED[] = "OnRefreshed"; +static const char S_ON_EXECUTE_LINE[] = "OnExecuteLine"; +static const char S_ON_SELECT_LINE[] = "OnSelectLine"; +static const char S_ON_SELECTION_CHANGE[] = "OnSelectionChange"; +static const char S_ON_COMMAND[] = "OnCommand"; +static const char S_ON_GET_ICON[] = "OnGetIcon"; +static const char S_ON_GET_LINE_ATTR[] = "OnGetLineAttr"; +static const char S_ON_GET_SIZE[] = "OnGetSize"; +static const char S_ON_GETTEXT[] = "OnGetText"; +static const char S_ON_ACTIVATE[] = "OnActivate"; +static const char S_ON_DEACTIVATE[] = "OnDeactivate"; +static const char S_ON_SELECT[] = "OnSelect"; +static const char S_ON_CREATING_GROUP[] = "OnCreatingGroup"; +static const char S_ON_DELETING_GROUP[] = "OnDeletingGroup"; +static const char S_ON_GROUP_VISIBILITY[] = "OnGroupVisibility"; +static const char S_M_EDGES[] = "_edges"; +static const char S_M_NODES[] = "_nodes"; +static const char S_M_THIS[] = "_this"; +static const char S_M_TITLE[] = "_title"; +static const char S_CLINK_NAME[] = "__clink__"; +static const char S_ON_VIEW_ACTIVATED[] = "OnViewActivated"; +static const char S_ON_VIEW_DEACTIVATED[] = "OnViewDeactivated"; +static const char S_ON_VIEW_KEYDOWN[] = "OnViewKeydown"; +static const char S_ON_VIEW_CLICK[] = "OnViewClick"; +static const char S_ON_VIEW_DBLCLICK[] = "OnViewDblclick"; +static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos"; +static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched"; +static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver"; +static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved"; +static const char S_MAIN[] = "__main__"; + + +#ifdef __PYWRAPS__ +static const char S_PY_IDA_IDAAPI_MODNAME[] = "__main__"; +#else +static const char S_PY_IDA_IDAAPI_MODNAME[] = S_IDA_IDAAPI_MODNAME; +#endif + //------------------------------------------------------------------------ // PyIdc conversion object IDs #define PY_ICID_INT64 0 @@ -100,6 +191,13 @@ public: // Declare a variable to acquire/release the GIL #define PYW_GIL_GET gil_lock_t lock; +// Let's declare just the relevant bits, in order to not have to force +// including 'kernwin.hpp' in all files +#ifndef __KERNWIN_HPP +idaman uint32 ida_export_data debug; +#define IDA_DEBUG_PLUGIN 0x00000020 +THREAD_SAFE AS_PRINTF(1, 2) inline int msg(const char *format, ...); +#endif // __KERNWIN_HPP #define GIL_CHKCONDFAIL (((debug & IDA_DEBUG_PLUGIN) == IDA_DEBUG_PLUGIN) \ && PyGILState_GetThisThreadState() != _PyThreadState_Current) @@ -128,10 +226,14 @@ struct exc_report_t #define PYW_GIL_GET_AND_REPORT_ERROR PYW_GIL_GET; exc_report_t exc; +// Returns the linked object (void *) from a PyObject +idaman void * ida_export pyobj_get_clink(PyObject *pyobj); + //------------------------------------------------------------------------ // All the exported functions from PyWraps are forward declared here -insn_t *insn_t_get_clink(PyObject *self); -op_t *op_t_get_clink(PyObject *self); +inline insn_t *insn_t_get_clink(PyObject *self) { return (insn_t *)pyobj_get_clink(self); } +inline op_t *op_t_get_clink(PyObject *self) { return (op_t *)pyobj_get_clink(self); } +inline switch_info_ex_t *switch_info_ex_t_get_clink(PyObject *self) { return (switch_info_ex_t *)pyobj_get_clink(self); } //------------------------------------------------------------------------- // The base for a reference. Will automatically increase the reference @@ -265,65 +367,52 @@ struct ref_vec_t : public qvector } }; - -// Returns a new reference to a class -// Return value: New reference. -ref_t get_idaapi_attr(const char *attr); - -// Returns a new reference to a class by its ID -// Return value: New reference. -ref_t get_idaapi_attr_by_id(const int class_id); - // Tries to import a module and swallows the exception if it fails and returns NULL // Return value: New reference. -ref_t PyW_TryImportModule(const char *name); +exported ref_t ida_export PyW_TryImportModule(const char *name); // Tries to get an attribute and swallows the exception if it fails and returns NULL -ref_t PyW_TryGetAttrString(PyObject *py_var, const char *attr); - -// Returns the linked object (void *) from a PyObject -void *pyobj_get_clink(PyObject *pyobj); +exported ref_t ida_export PyW_TryGetAttrString(PyObject *py_var, const char *attr); // Converts a Python number (LONGLONG or normal integer) to an IDC variable (VT_LONG or VT_INT64) -bool PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_var); +exported bool ida_export PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_var); // Returns a qstring from a Python attribute string -bool PyW_GetStringAttr( +exported bool ida_export PyW_GetStringAttr( PyObject *py_obj, const char *attr_name, qstring *str); // Converts a Python number to an uint64 and indicates whether the number was a long number -bool PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL); +exported bool ida_export PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL); // Checks if an Python object can be treated like a sequence -bool PyW_IsSequenceType(PyObject *obj); +exported bool ida_export PyW_IsSequenceType(PyObject *obj); // Returns an error string from the last exception (and clears it) -bool PyW_GetError(qstring *out = NULL, bool clear_err = true); -bool PyW_GetError(char *buf, size_t bufsz, bool clear_err = true); +exported bool ida_export PyW_GetError(qstring *out = NULL, bool clear_err = true); // If an error occured (it calls PyGetError) it displays it and return TRUE // This function is used when calling callbacks -bool PyW_ShowCbErr(const char *cb_name); +exported bool ida_export PyW_ShowCbErr(const char *cb_name); // Utility function to create linked class instances -ref_t create_idaapi_linked_class_instance(const char *clsname, void *lnk); +exported ref_t ida_export create_linked_class_instance(const char *modname, const char *clsname, void *lnk); // Returns the string representation of a PyObject -bool PyW_ObjectToString(PyObject *obj, qstring *out); +exported bool ida_export PyW_ObjectToString(PyObject *obj, qstring *out); // Utility function to convert a python object to an IDC object // and sets a python exception on failure. -bool pyvar_to_idcvar_or_error(const ref_t &py_obj, idc_value_t *idc_obj); +exported bool ida_export pyvar_to_idcvar_or_error(const ref_t &py_obj, idc_value_t *idc_obj); // Creates and initializes an IDC exception -error_t PyW_CreateIdcException(idc_value_t *res, const char *msg); +exported error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char *msg); // // Conversion functions // -bool pyw_convert_idc_args( +exported bool ida_export pyw_convert_idc_args( const idc_value_t args[], int nargs, ref_vec_t &pargs, @@ -333,69 +422,81 @@ bool pyw_convert_idc_args( // Converts Python variable to IDC variable // gvar_sn is used in case the Python object was a created from a call to idcvar_to_pyvar and the IDC object was a VT_REF -int pyvar_to_idcvar( +exported int ida_export pyvar_to_idcvar( const ref_t &py_var, idc_value_t *idc_var, int *gvar_sn = NULL); // Converts from IDC to Python // We support converting VT_REF IDC variable types -int idcvar_to_pyvar( - const idc_value_t &idc_var, - ref_t *py_var); +exported int ida_export idcvar_to_pyvar( + const idc_value_t &idc_var, + ref_t *py_var); // Walks a Python list or Sequence and calls the callback -Py_ssize_t pyvar_walk_list( - const ref_t &py_list, - int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud) = NULL, - void *ud = NULL); -Py_ssize_t pyvar_walk_list( +exported Py_ssize_t ida_export pyvar_walk_list( PyObject *py_list, int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud) = NULL, void *ud = NULL); // Converts an intvec_t to a Python list object -ref_t PyW_IntVecToPyList(const intvec_t &intvec); +exported ref_t ida_export PyW_IntVecToPyList(const intvec_t &intvec); // Converts an Python list to an intvec -bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec); +exported bool ida_export PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec); + +// Converts an Python list to an eavec +exported bool ida_export PyW_PyListToEaVec(PyObject *py_list, eavec_t &eavec); // Converts a Python list to a qstrvec -bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec); +exported bool ida_export PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec); //------------------------------------------------------------------------- -PyObject *qstrvec2pylist(qstrvec_t &vec); +exported bool ida_export PyWStringOrNone_Check(PyObject *tp); //------------------------------------------------------------------------- -inline bool PyWStringOrNone_Check(PyObject *tp) -{ - return tp == Py_None || PyString_Check(tp); -} +#include +exported PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &areas); //------------------------------------------------------------------------- -inline const p_list * PyW_Fields(PyObject *tp) -{ - return tp == Py_None ? NULL : (const p_list *) PyString_AsString(tp); -} +exported void ida_export PyW_register_compiled_form(PyObject *py_form); + +//------------------------------------------------------------------------- +exported void ida_export PyW_unregister_compiled_form(PyObject *py_form); //--------------------------------------------------------------------------- -// // notify_when() -// -bool pywraps_nw_term(); -bool pywraps_nw_notify(int slot, ...); -bool pywraps_nw_init(); +class pywraps_notify_when_t +{ + ref_vec_t table[NW_EVENTSCNT]; + qstring err; + bool in_notify; + struct notify_when_args_t + { + int when; + PyObject *py_callable; + }; + typedef qvector notify_when_args_vec_t; + notify_when_args_vec_t delayed_notify_when_list; -//--------------------------------------------------------------------------- -bool pywraps_check_autoscripts(char *buf, size_t bufsize); + static int idaapi idp_callback(void *ud, int event_id, va_list va); + bool unnotify_when(int when, PyObject *py_callable); + void register_callback(int slot, PyObject *py_callable); + void unregister_callback(int slot, PyObject *py_callable); -// [De]Initializes PyWraps -bool init_pywraps(); -void deinit_pywraps(); +public: + bool init(); + bool deinit(); + bool notify_when(int when, PyObject *py_callable); + bool notify(int slot, ...); + bool notify_va(int slot, va_list va); + pywraps_notify_when_t() : in_notify(false) {} +}; +exported bool ida_export add_notify_when(int when, PyObject *py_callable); -void hexrays_clear_python_cfuncptr_t_references(void); +// void hexrays_clear_python_cfuncptr_t_references(void); -void free_compiled_form_instances(void); +// void free_compiled_form_instances(void); //#define PYGDBG_ENABLED #ifdef PYGDBG_ENABLED @@ -407,8 +508,17 @@ void free_compiled_form_instances(void); //------------------------------------------------------------------------- struct pycall_res_t { - pycall_res_t(PyObject *pyo); - ~pycall_res_t(); + pycall_res_t(PyObject *pyo) + : result(pyo) + { + PYGLOG("return code: %p\n", result.o); + } + + ~pycall_res_t() + { + if ( PyErr_Occurred() ) + PyErr_Print(); + } inline bool success() const { return result.o != NULL; } @@ -418,4 +528,326 @@ private: pycall_res_t(); // No. }; -#endif +//------------------------------------------------------------------------- +// CustomIDAMemo wrappers +//-------------------------------------------------------------------------i +class lookup_info_t; +class py_customidamemo_t; +struct lookup_entry_t +{ + lookup_entry_t() : form(NULL), view(NULL), py_view(NULL) {} + + TForm *form; + TCustomControl *view; + py_customidamemo_t *py_view; +}; +DECLARE_TYPE_AS_MOVABLE(lookup_entry_t); +typedef qvector lookup_entries_t; + +#include +#define PY_LINFO_HLPPRM_new_entry (lookup_info_t *_this, py_customidamemo_t *py_view) +#define PY_LINFO_PARAMS_new_entry (py_customidamemo_t *py_view) +#define PY_LINFO_TRANSM_new_entry (this, py_view) + +#define PY_LINFO_HLPPRM_commit (lookup_info_t *_this, lookup_entry_t &e, TForm *form, TCustomControl *view) +#define PY_LINFO_PARAMS_commit (lookup_entry_t &e, TForm *form, TCustomControl *view) +#define PY_LINFO_TRANSM_commit (this, e, form, view) + +#define PY_LINFO_HLPPRM_find_by_form (const lookup_info_t *_this, TCustomControl **out_view, py_customidamemo_t **out_py_view, const TForm *form) +#define PY_LINFO_PARAMS_find_by_form (TCustomControl **out_view, py_customidamemo_t **out_py_view, const TForm *form) const +#define PY_LINFO_TRANSM_find_by_form (this, out_view, out_py_view, form) + +#define PY_LINFO_HLPPRM_find_by_py_view (const lookup_info_t *_this, TForm **out_form, TCustomControl **out_view, const py_customidamemo_t *py_view) +#define PY_LINFO_PARAMS_find_by_py_view (TForm **out_form, TCustomControl **out_view, const py_customidamemo_t *py_view) const +#define PY_LINFO_TRANSM_find_by_py_view (this, out_form, out_view, py_view) + +#define PY_LINFO_HLPPRM_del_by_py_view (lookup_info_t *_this, const py_customidamemo_t *py_view) +#define PY_LINFO_PARAMS_del_by_py_view (const py_customidamemo_t *py_view) +#define PY_LINFO_TRANSM_del_by_py_view (this, py_view) + +#define DECL_LINFO_HELPER(decl, RType, MName, MParams) \ + decl RType ida_export lookup_info_t_##MName MParams + +#define DECL_LINFO_HELPERS(decl) \ + DECL_LINFO_HELPER(decl, lookup_entry_t&, new_entry, PY_LINFO_HLPPRM_new_entry); \ + DECL_LINFO_HELPER(decl, void, commit, PY_LINFO_HLPPRM_commit); \ + DECL_LINFO_HELPER(decl, bool, find_by_form, PY_LINFO_HLPPRM_find_by_form); \ + DECL_LINFO_HELPER(decl, bool, find_by_py_view, PY_LINFO_HLPPRM_find_by_py_view);\ + DECL_LINFO_HELPER(decl, bool, del_by_py_view, PY_LINFO_HLPPRM_del_by_py_view); + + +DECL_LINFO_HELPERS(idaman); + +class py_customidamemo_t; +class lookup_info_t +{ + DECL_LINFO_HELPERS(friend); + +public: +#define PY_LINFO_TRAMPOLINE(RType, MName, MParams, PNames) \ + RType MName MParams { return lookup_info_t_##MName PNames; } + + PY_LINFO_TRAMPOLINE(lookup_entry_t&, new_entry, PY_LINFO_PARAMS_new_entry, PY_LINFO_TRANSM_new_entry); + PY_LINFO_TRAMPOLINE(void, commit, PY_LINFO_PARAMS_commit, PY_LINFO_TRANSM_commit); + PY_LINFO_TRAMPOLINE(bool, find_by_form, PY_LINFO_PARAMS_find_by_form, PY_LINFO_TRANSM_find_by_form); + PY_LINFO_TRAMPOLINE(bool, find_by_py_view, PY_LINFO_PARAMS_find_by_py_view, PY_LINFO_TRANSM_find_by_py_view); + PY_LINFO_TRAMPOLINE(bool, del_by_py_view, PY_LINFO_PARAMS_del_by_py_view, PY_LINFO_TRANSM_del_by_py_view); +#undef PY_LINFO_TRAMPOLINE + + bool find_by_view(TForm **out_form, py_customidamemo_t **out_py_view, const TCustomControl *view) const; + +private: + lookup_entries_t entries; +}; + +extern exported lookup_info_t ida_export_data pycim_lookup_info; + +//------------------------------------------------------------------------- +struct pycim_callback_id_t +{ + qstring name; + int have; +}; + +struct pycim_callbacks_ids_t : public qvector +{ + void add(const char *_n, int _h) + { + pycim_callback_id_t &o = push_back(); + o.name = _n; + o.have = _h; + } +}; + +//------------------------------------------------------------------------- +// +//------------------------------------------------------------------------- +#define PY_CIM_HLPPRM_set_node_info (py_customidamemo_t *_this, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) +#define PY_CIM_PARAMS_set_node_info (PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) +#define PY_CIM_TRANSM_set_node_info (this, py_node_idx, py_node_info, py_flags) + +#define PY_CIM_HLPPRM_set_nodes_infos (py_customidamemo_t *_this, PyObject *dict) +#define PY_CIM_PARAMS_set_nodes_infos (PyObject *dict) +#define PY_CIM_TRANSM_set_nodes_infos (this, dict) + +#define PY_CIM_HLPPRM_get_node_info (py_customidamemo_t *_this, PyObject *py_node_idx) +#define PY_CIM_PARAMS_get_node_info (PyObject *py_node_idx) +#define PY_CIM_TRANSM_get_node_info (this, py_node_idx) + +#define PY_CIM_HLPPRM_del_nodes_infos (py_customidamemo_t *_this, PyObject *py_nodes) +#define PY_CIM_PARAMS_del_nodes_infos (PyObject *py_nodes) +#define PY_CIM_TRANSM_del_nodes_infos (this, py_nodes) + +#define PY_CIM_HLPPRM_get_current_renderer_type (py_customidamemo_t *_this) +#define PY_CIM_PARAMS_get_current_renderer_type () +#define PY_CIM_TRANSM_get_current_renderer_type (this) + +#define PY_CIM_HLPPRM_set_current_renderer_type (py_customidamemo_t *_this, PyObject *py_rto) +#define PY_CIM_PARAMS_set_current_renderer_type (PyObject *py_rto) +#define PY_CIM_TRANSM_set_current_renderer_type (this, py_rto) + +#define PY_CIM_HLPPRM_create_groups (py_customidamemo_t *_this, PyObject *groups_infos) +#define PY_CIM_PARAMS_create_groups (PyObject *groups_infos) +#define PY_CIM_TRANSM_create_groups (this, groups_infos) + +#define PY_CIM_HLPPRM_delete_groups (py_customidamemo_t *_this, PyObject *groups, PyObject *new_current) +#define PY_CIM_PARAMS_delete_groups (PyObject *groups, PyObject *new_current) +#define PY_CIM_TRANSM_delete_groups (this, groups, new_current) + +#define PY_CIM_HLPPRM_set_groups_visibility (py_customidamemo_t *_this, PyObject *groups, PyObject *expand, PyObject *new_current) +#define PY_CIM_PARAMS_set_groups_visibility (PyObject *groups, PyObject *expand, PyObject *new_current) +#define PY_CIM_TRANSM_set_groups_visibility (this, groups, expand, new_current) + +#define PY_CIM_HLPPRM_collect_pyobject_callbacks (py_customidamemo_t *_this, PyObject *self) +#define PY_CIM_PARAMS_collect_pyobject_callbacks (PyObject *in_self) +#define PY_CIM_TRANSM_collect_pyobject_callbacks (this, in_self) + +#define PY_CIM_HLPPRM_collect_class_callbacks_ids (py_customidamemo_t *_this, pycim_callbacks_ids_t *out) +#define PY_CIM_PARAMS_collect_class_callbacks_ids (pycim_callbacks_ids_t *out) +#define PY_CIM_TRANSM_collect_class_callbacks_ids (this, out) + +#define PY_CIM_HLPPRM_install_custom_viewer_handlers (py_customidamemo_t *_this) +#define PY_CIM_PARAMS_install_custom_viewer_handlers () +#define PY_CIM_TRANSM_install_custom_viewer_handlers (this) + +#define PY_CIM_HLPPRM_bind (py_customidamemo_t *_this, PyObject *self, TCustomControl *view) +#define PY_CIM_PARAMS_bind (PyObject *in_self, TCustomControl *in_view) +#define PY_CIM_TRANSM_bind (this, in_self, in_view) + +#define PY_CIM_HLPPRM_unbind (py_customidamemo_t *_this, bool clear_view) +#define PY_CIM_PARAMS_unbind (bool clear_view) +#define PY_CIM_TRANSM_unbind (this, clear_view) + +#define PY_CIM_HLPPRM_ensure_view_callbacks_installed () + +#define DECL_CIM_HELPER(decl, RType, MName, MParams) \ + decl RType ida_export py_customidamemo_t_##MName MParams + +#define DECL_CIM_HELPERS(decl) \ + DECL_CIM_HELPER(decl, void, set_node_info, PY_CIM_HLPPRM_set_node_info); \ + DECL_CIM_HELPER(decl, void, set_nodes_infos, PY_CIM_HLPPRM_set_nodes_infos); \ + DECL_CIM_HELPER(decl, PyObject*, get_node_info, PY_CIM_HLPPRM_get_node_info); \ + DECL_CIM_HELPER(decl, void, del_nodes_infos, PY_CIM_HLPPRM_del_nodes_infos); \ + DECL_CIM_HELPER(decl, PyObject*, get_current_renderer_type, PY_CIM_HLPPRM_get_current_renderer_type); \ + DECL_CIM_HELPER(decl, void, set_current_renderer_type, PY_CIM_HLPPRM_set_current_renderer_type); \ + DECL_CIM_HELPER(decl, PyObject*, create_groups, PY_CIM_HLPPRM_create_groups); \ + DECL_CIM_HELPER(decl, PyObject*, delete_groups, PY_CIM_HLPPRM_delete_groups); \ + DECL_CIM_HELPER(decl, PyObject*, set_groups_visibility, PY_CIM_HLPPRM_set_groups_visibility);\ + \ + DECL_CIM_HELPER(decl, bool, collect_pyobject_callbacks, PY_CIM_HLPPRM_collect_pyobject_callbacks); \ + DECL_CIM_HELPER(decl, void, collect_class_callbacks_ids, PY_CIM_HLPPRM_collect_class_callbacks_ids); \ + DECL_CIM_HELPER(decl, void, install_custom_viewer_handlers, PY_CIM_HLPPRM_install_custom_viewer_handlers); \ + DECL_CIM_HELPER(decl, bool, bind, PY_CIM_HLPPRM_bind); \ + DECL_CIM_HELPER(decl, void, unbind, PY_CIM_HLPPRM_unbind); \ + DECL_CIM_HELPER(decl, void, ensure_view_callbacks_installed, PY_CIM_HLPPRM_ensure_view_callbacks_installed) + +DECL_CIM_HELPERS(idaman); + +//------------------------------------------------------------------------- +#define PY_CIM_TRAMPOLINE(RType, MName, MParams, PNames) \ + RType MName MParams { return py_customidamemo_t_##MName PNames; } + +class py_customidamemo_t +{ + void convert_node_info( + node_info_t *out, + uint32 *out_flags, + ref_t py_nodeinfo); + + enum + { + GRBASE_HAVE_VIEW_ACTIVATED = 0x001, + GRBASE_HAVE_VIEW_DEACTIVATED = 0x002, + GRBASE_HAVE_KEYDOWN = 0x004, + GRBASE_HAVE_POPUP = 0x008, + GRBASE_HAVE_VIEW_CLICK = 0x010, + GRBASE_HAVE_VIEW_DBLCLICK = 0x020, + GRBASE_HAVE_VIEW_CURPOS = 0x040, + GRBASE_HAVE_CLOSE = 0x080, + GRBASE_HAVE_VIEW_SWITCHED = 0x100, + GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200, + GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400, + }; + + int cb_flags; + // number of arguments for: + int ovc_num_args; // OnViewClick implementation + int ovdc_num_args; // OnViewDblclick implementation + int ovmo_num_args; // OnViewMouseOver implementation + int ovmm_num_args; // OnViewMouseMoved implementation + + // View events + void on_view_activated(); + void on_view_deactivated(); + void on_view_keydown(int key, int state); + void on_view_popup(); + void on_view_click(const view_mouse_event_t *event); + void on_view_dblclick(const view_mouse_event_t *event); + void on_view_curpos(); + void on_view_close(); + void on_view_switched(tcc_renderer_type_t rt); + void on_view_mouse_over(const view_mouse_event_t *event); + void on_view_mouse_moved(const view_mouse_event_t *event); + int get_py_method_arg_count(char *method_name); + + // View events that are bound with 'set_custom_viewer_handler()'. + static void idaapi s_on_view_mouse_moved( + TCustomControl *cv, + int shift, + view_mouse_event_t *e, + void *ud); + + DECL_CIM_HELPERS(friend); + +protected: + ref_t self; + TCustomControl *view; + pycim_callbacks_ids_t cbids; + + PY_CIM_TRAMPOLINE(bool, collect_pyobject_callbacks, PY_CIM_PARAMS_collect_pyobject_callbacks, PY_CIM_TRANSM_collect_pyobject_callbacks); + PY_CIM_TRAMPOLINE(virtual void, collect_class_callbacks_ids, PY_CIM_PARAMS_collect_class_callbacks_ids, PY_CIM_TRANSM_collect_class_callbacks_ids); + PY_CIM_TRAMPOLINE(void, install_custom_viewer_handlers, PY_CIM_PARAMS_install_custom_viewer_handlers, PY_CIM_TRANSM_install_custom_viewer_handlers); + PY_CIM_TRAMPOLINE(bool, bind, PY_CIM_PARAMS_bind, PY_CIM_TRANSM_bind); + PY_CIM_TRAMPOLINE(void, unbind, PY_CIM_PARAMS_unbind, PY_CIM_TRANSM_unbind); + + friend TForm *pycim_get_tform(PyObject *self); + friend TCustomControl *pycim_get_tcustom_control(PyObject *self); + +public: + py_customidamemo_t() + : self(newref_t(NULL)), + view(NULL) + { + PYGLOG("%p: py_customidamemo_t()\n", this); + py_customidamemo_t_ensure_view_callbacks_installed(); + ovc_num_args = -1; + ovdc_num_args = -1; + ovmo_num_args = -1; + ovmm_num_args = -1; + } + virtual ~py_customidamemo_t() + { + PYGLOG("%p: ~py_customidamemo_t()\n", this); + unbind(true); + pycim_lookup_info.del_by_py_view(this); + } + + virtual void refresh() + { + refresh_viewer(view); + } + inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } + + PY_CIM_TRAMPOLINE(void, set_node_info, PY_CIM_PARAMS_set_node_info, PY_CIM_TRANSM_set_node_info); + PY_CIM_TRAMPOLINE(void, set_nodes_infos, PY_CIM_PARAMS_set_nodes_infos, PY_CIM_TRANSM_set_nodes_infos); + PY_CIM_TRAMPOLINE(PyObject*, get_node_info, PY_CIM_PARAMS_get_node_info, PY_CIM_TRANSM_get_node_info); + PY_CIM_TRAMPOLINE(void, del_nodes_infos, PY_CIM_PARAMS_del_nodes_infos, PY_CIM_TRANSM_del_nodes_infos); + PY_CIM_TRAMPOLINE(PyObject*, get_current_renderer_type, PY_CIM_PARAMS_get_current_renderer_type, PY_CIM_TRANSM_get_current_renderer_type); + PY_CIM_TRAMPOLINE(void, set_current_renderer_type, PY_CIM_PARAMS_set_current_renderer_type, PY_CIM_TRANSM_set_current_renderer_type); + PY_CIM_TRAMPOLINE(PyObject*, create_groups, PY_CIM_PARAMS_create_groups, PY_CIM_TRANSM_create_groups); + PY_CIM_TRAMPOLINE(PyObject*, delete_groups, PY_CIM_PARAMS_delete_groups, PY_CIM_TRANSM_delete_groups); + PY_CIM_TRAMPOLINE(PyObject*, set_groups_visibility, PY_CIM_PARAMS_set_groups_visibility, PY_CIM_TRANSM_set_groups_visibility); +}; +#undef PY_CIM_TRAMPOLINE + +#undef DECL_CIM_HELPERS +#undef DECL_CIM_HELPER + + +//------------------------------------------------------------------------- +template +T *view_extract_this(PyObject *self) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + ref_t py_this(PyW_TryGetAttrString(self, S_M_THIS)); + if ( py_this == NULL || !PyCObject_Check(py_this.o) ) + return NULL; + return (T*) PyCObject_AsVoidPtr(py_this.o); +} + +//------------------------------------------------------------------------- +// +//------------------------------------------------------------------------- +#include +#define DECL_REG_UNREG_REFCOUNTED(Type) \ + exported void ida_export til_register_python_##Type##_instance(Type *inst); \ + exported void ida_export til_deregister_python_##Type##_instance(Type *inst); +DECL_REG_UNREG_REFCOUNTED(tinfo_t); +DECL_REG_UNREG_REFCOUNTED(ptr_type_data_t); +DECL_REG_UNREG_REFCOUNTED(array_type_data_t); +DECL_REG_UNREG_REFCOUNTED(func_type_data_t); +DECL_REG_UNREG_REFCOUNTED(udt_type_data_t); +#undef DECL_REG_UNREG_REFCOUNTED + +//------------------------------------------------------------------------- +// Context structure used by register/unregister timer +struct py_timer_ctx_t +{ + py_timer_ctx_t() : timer_id(NULL), pycallback(NULL) {} + qtimer_t timer_id; + PyObject *pycallback; +}; +exported py_timer_ctx_t *ida_export python_timer_new(PyObject *py_callback); +exported void ida_export python_timer_del(py_timer_ctx_t *t); + +#endif // __PYWRAPS_HPP__ diff --git a/pywraps/deploy_all.py b/pywraps/deploy_all.py deleted file mode 100644 index 90f859c..0000000 --- a/pywraps/deploy_all.py +++ /dev/null @@ -1,212 +0,0 @@ -# Please use the same tag for the same .i file -# That means if many insertions are going to happen in one -# given .i file then don't use more than code marking tag - -print "\n-------- DEPLOY started --------------------------------------------------\n" - -deploys = { - "idaapi (common functions, notifywhen)" : { - "tag" : "py_idaapi", - "src" : ["py_cvt.hpp", "py_idaapi.hpp", "py_idaapi.py", "py_notifywhen.hpp", "py_notifywhen.py"], - "tgt" : "../swig/idaapi.i" - }, - - "View (common)" : { - "tag" : "py_view_base", - "src" : ["py_view_base.hpp", "py_view_base.py"], - "tgt" : "../swig/view.i" - }, - - "IDAView" : { - "tag" : "py_idaview", - "src" : ["py_idaview.hpp", "py_idaview.py"], - "tgt" : "../swig/view.i" - }, - - "Graph" : { - "tag" : "py_graph", - "src" : ["py_graph.hpp", "py_graph.py"], - "tgt" : "../swig/graph.i" - }, - - "custview" : { - "tag" : "py_custviewer", - "src" : ["py_custview.py","py_custview.hpp"], - "tgt" : "../swig/kernwin.i.in" - }, - - "plgform" : { - "tag" : "py_plgform", - "src" : ["py_plgform.hpp","py_plgform.py"], - "tgt" : "../swig/kernwin.i.in" - }, - - "expr" : { - "tag" : "py_expr", - "src" : ["py_expr.hpp","py_expr.py"], - "tgt" : "../swig/expr.i" - }, - - "cli" : { - "tag" : "py_cli", - "src" : ["py_cli.py","py_cli.hpp"], - "tgt" : "../swig/kernwin.i.in" - }, - - "Loader" : { - "tag" : "py_loader", - "src" : ["py_loader.hpp"], - "tgt" : "../swig/loader.i" - }, - - "kernwin, choose2, askusingform" : { - "tag" : "py_kernwin", - "src" : ["py_kernwin.hpp","py_kernwin.py","py_choose.hpp","py_choose2.hpp","py_choose2.py","py_askusingform.hpp","py_askusingform.py"], - "tgt" : "../swig/kernwin.i.in" - }, - - "idd" : { - "tag" : "py_idd", - "src" : ["py_dbg.hpp","py_appcall.py"], - "tgt" : "../swig/idd.i" - }, - - "idd (python)" : { - "tag" : "py_idd_2", - "src" : ["py_dbg.py"], - "tgt" : "../swig/idd.i" - }, - - "nalt" : { - "tag" : "py_nalt", - "src" : ["py_nalt.hpp","py_nalt.py"], - "tgt" : "../swig/nalt.i" - }, - - "dbg" : { - "tag" : "py_dbg", - "src" : ["py_dbg.hpp"], - "tgt" : "../swig/dbg.i.in" - }, - - "linput/diskio" : { - "tag" : "py_diskio", - "src" : ["py_linput.hpp","py_diskio.hpp","py_diskio.py"], - "tgt" : "../swig/diskio.i" - }, - - "name" : { - "tag" : "py_name", - "src" : ["py_name.hpp","py_name.py"], - "tgt" : "../swig/name.i" - }, - - "qfile" : { - "tag" : "py_qfile", - "src" : ["py_qfile.hpp"], - "tgt" : "../swig/fpro.i" - }, - - "bytes" : { - "tag" : "py_bytes", - "src" : ["py_bytes.hpp","py_custdata.py","py_custdata.hpp"], - "tgt" : "../swig/bytes.i" - }, - - "typeinf" : { - "tag" : "py_typeinf", - "src" : ["py_typeinf.hpp","py_typeinf.py"], - "tgt" : "../swig/typeinf.i" - }, - - "gdl" : { - "tag" : "py_gdl", - "src" : ["py_gdl.py"], - "tgt" : "../swig/gdl.i" - }, - - "ua" : { - "tag" : "py_ua", - "src" : ["py_ua.hpp","py_ua.py"], - "tgt" : "../swig/ua.i" - }, - - "idp" : { - "tag" : "py_idp", - "src" : ["py_idp.hpp"], - "tgt" : "../swig/idp.i.in" - }, - - "lines" : { - "tag" : "py_lines", - "src" : ["py_lines.hpp","py_lines.py"], - "tgt" : "../swig/lines.i" - }, - - "registry" : { - "tag" : "py_registry", - "src" : ["py_registry.hpp"], - "tgt" : "../swig/registry.i" - }, - - "struct" : { - "tag" : "py_struct", - "src" : ["py_struct.hpp"], - "tgt" : "../swig/struct.i" - }, - - "pc_win32_appcall" : { - "tag" : "appcalltest", - "src" : ["py_appcall.py"], - "tgt" : "../../../tests/input/pc_win32_appcall.pe.hints" - }, - - "ex_custdata example" : { - "tag" : "ex_custdata", - "src" : ["../examples/ex_custdata.py"], - "tgt" : "../../../tests/input/pc_win32_custdata1.pe.hints" - }, - - "ex_choose2" : { - "tag" : "py_choose2ex1", - "src" : ["py_choose2.py"], - "tgt" : "../examples/ex_choose2.py" - }, - - "ex_formchooser" : { - "tag" : "ex_formchooser", - "src" : ["py_askusingform.py"], - "tgt" : "../../formchooser/formchooser.py" - }, - - "ex_askusingform" : { - "tag" : "ex_askusingform", - "src" : ["py_askusingform.py"], - "tgt" : "../examples/ex_askusingform.py" - }, - - "ex_cli example" : { - "tag" : "ex_cli_ex1", - "src" : ["py_cli.py"], - "tgt" : "../examples/ex_cli.py" - }, - - "ex_expr example" : { - "tag" : "ex_expr", - "src" : ["py_expr.py"], - "tgt" : "../examples/ex_expr.py" - }, - - "ex_custview.py example" : { - "tag" : "py_custviewerex1", - "src" : ["py_custview.py"], - "tgt" : "../examples/ex_custview.py" - } - } - -import deploy -for name in deploys: - data = deploys[name] - print "Deploying %s" % name - deploy.deploy(data["tag"], data["src"], data["tgt"]) - diff --git a/pywraps/driver.cpp b/pywraps/driver.cpp new file mode 100644 index 0000000..05412f3 --- /dev/null +++ b/pywraps/driver.cpp @@ -0,0 +1,172 @@ +//-------------------------------------------------------------------------- +// IDA includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------------------- +// PyWraps +#include +#include "pywraps.hpp" +#include "swig_stub.h" +#include "py_cvt.hpp" +#include "py_idaapi.hpp" +#include "py_graph.hpp" +#include "py_typeinf.hpp" +#include "py_bytes.hpp" +#include "py_linput.hpp" +#include "py_qfile.hpp" +#include "py_ua.hpp" +#include "py_custdata.hpp" +#include "py_notifywhen.hpp" +#include "py_dbg.hpp" +#include "py_choose2.hpp" +#include "py_plgform.hpp" +#include "py_cli.hpp" +#include "py_custview.hpp" +#include "py_lines.hpp" +#include "py_nalt.hpp" +#include "py_loader.hpp" +#include "py_idp.hpp" +#include "py_kernwin.hpp" +#include "py_askusingform.hpp" +#include "py_expr.hpp" + +//-------------------------------------------------------------------------- +qvector all_methods; +void driver_add_methods(PyMethodDef *methods) +{ + for ( ; methods->ml_name != NULL; ++methods ) + all_methods.push_back(*methods); +} + +//-------------------------------------------------------------------------- +// Define a class and declare an instance so it gets executed on startup +// It will add the desired methods to the all_methods global variable +#define DRIVER_INIT_METHODS(name) \ + class init_##name##_driver_t \ + { \ + public: \ + init_##name##_driver_t() \ + { \ + driver_add_methods(py_methods_##name##); \ + } \ + } init_##name##_driver; + +//-------------------------------------------------------------------------- +// PyWraps test drivers +//#include "driver_kernwin.cpp" +//#include "driver_chooser.cpp" +#include "driver_expr.cpp" +//#include "driver_custview.cpp" +//#include "driver_notifywhen.cpp" +//#include "driver_custdata.cpp" +//#include "driver_graph.cpp" +//#include "driver_diskio.cpp" +//#include "driver_bytes.cpp" +//#include "driver_dbg.cpp" +//#include "driver_nalt.cpp" +//#include "driver_cli.cpp" + +//-------------------------------------------------------------------------- +//#define DRIVER_FIX + +#ifdef DRIVER_FIX + #define PLUGIN_FLAGS PLUGIN_FIX +#else + #define PLUGIN_FLAGS 0 +#endif + +//-------------------------------------------------------------------------- +void setup_pywraps() +{ + static bool installed = false; + if ( installed ) + { + msg("pywraps already installed\n"); + return; + } + static const PyMethodDef null_method = {0}; + all_methods.push_back(null_method); + Py_InitModule("pywraps", all_methods.begin()); + init_pywraps(); + msg("pywraps installed!\n"); + installed = true; +} + +//-------------------------------------------------------------------------- +void idaapi run(int /*arg*/) +{ + setup_pywraps(); +#ifdef DRIVER_RUN + driver_run(0); +#endif +} + +//-------------------------------------------------------------------------- +// +// Initialize. +// +int idaapi init(void) +{ +#ifndef DRIVER_FIX + setup_pywraps(); +#endif +#ifdef DRIVER_INIT + return driver_init(); +#else + return PLUGIN_KEEP; +#endif +} + +//-------------------------------------------------------------------------- +void idaapi term(void) +{ +#ifdef DRIVER_TERM + driver_term(); +#endif +} + +//-------------------------------------------------------------------------- +// +// PLUGIN DESCRIPTION BLOCK +// +//-------------------------------------------------------------------------- +plugin_t PLUGIN = +{ + IDP_INTERFACE_VERSION, + PLUGIN_FLAGS, // plugin flags + init, // initialize + + term, // terminate. this pointer may be NULL. + + run, // invoke plugin + + // long comment about the plugin + "PyWraps plugin", + + // it could appear in the status line + // or as a hint + "", // multiline help about the plugin + + "pywraps", // the preferred short name of the plugin + "" // the preferred hotkey to run the plugin +}; diff --git a/pywraps/driver_bytes.cpp b/pywraps/driver_bytes.cpp new file mode 100644 index 0000000..cf9446b --- /dev/null +++ b/pywraps/driver_bytes.cpp @@ -0,0 +1,19 @@ +#include "py_bytes.hpp" + +//-------------------------------------------------------------------------- +static PyObject *ex_nextthat(PyObject *self, PyObject *args) +{ + PyObject *callback; + pyul_t addr, bound; + if ( !PyArg_ParseTuple(args, PY_FMT64 PY_FMT64 "O", &addr, &bound, &callback) ) + return NULL; + return Py_BuildValue("i", py_nextthat(pyul_t(addr), pyul_t(bound), callback)); +} + +//-------------------------------------------------------------------------- +static PyMethodDef py_methods_bytes[] = +{ + { "nextthat", ex_nextthat, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } +}; +DRIVER_INIT_METHODS(bytes); \ No newline at end of file diff --git a/pywraps/driver_chooser.cpp b/pywraps/driver_chooser.cpp new file mode 100644 index 0000000..f3775dc --- /dev/null +++ b/pywraps/driver_chooser.cpp @@ -0,0 +1,109 @@ +#include "py_choose2.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_find(PyObject *self, PyObject *args) +{ + char *title; + if ( !PyArg_ParseTuple(args, "s", &title) ) + return NULL; + else + return choose2_find(title); +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_create(PyObject *self, PyObject *args) +{ + PyObject *obj; + int embedded; + if ( !PyArg_ParseTuple(args, "Oi", &obj, &embedded) ) + return NULL; + else + return PyInt_FromLong(choose2_create(obj, embedded == 1 ? true : false)); +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_activate(PyObject *self, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + + choose2_activate(obj); + Py_RETURN_NONE; +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_close(PyObject *self, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + + choose2_close(obj); + Py_RETURN_NONE; +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_refresh(PyObject *self, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + + choose2_refresh(obj); + Py_RETURN_NONE; +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_add_command(PyObject *self, PyObject *args) +{ + PyObject *obj; + char *caption; + int flags, menu_index, icon; + if ( !PyArg_ParseTuple(args, "Osiii", &obj, &caption, &flags, &menu_index, &icon) ) + return NULL; + else + return PyInt_FromLong(choose2_add_command(obj, caption, flags, menu_index, icon)); +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_get_test_embedded(PyObject *self, PyObject *args) +{ + return PyLong_FromSize_t(choose2_get_test_embedded()); +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_get_embedded(PyObject *self, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + else + return choose2_get_embedded(obj); +} + +//------------------------------------------------------------------------- +static PyObject *ex_choose2_get_embedded_selection(PyObject *self, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + else + return choose2_get_embedded_selection(obj); +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_chooser[] = +{ + { "py_choose2_find", ex_choose2_find, METH_VARARGS, "" }, + { "py_choose2_create", ex_choose2_create, METH_VARARGS, "" }, + { "py_choose2_close", ex_choose2_close, METH_VARARGS, "" }, + { "py_choose2_activate", ex_choose2_activate, METH_VARARGS, "" }, + { "py_choose2_refresh", ex_choose2_refresh, METH_VARARGS, "" }, + { "py_choose2_add_command", ex_choose2_add_command, METH_VARARGS, "" }, + { "py_choose2_get_test_embedded", ex_choose2_get_test_embedded, METH_VARARGS, "" }, + { "py_choose2_get_embedded", ex_choose2_get_embedded, METH_VARARGS, "" }, + { "py_choose2_get_embedded_selection", ex_choose2_get_embedded_selection, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } // End of methods +}; +DRIVER_INIT_METHODS(chooser); diff --git a/pywraps/driver_cli.cpp b/pywraps/driver_cli.cpp new file mode 100644 index 0000000..208c81d --- /dev/null +++ b/pywraps/driver_cli.cpp @@ -0,0 +1,29 @@ +#include "py_custview.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_install_command_interpreter(PyObject *self, PyObject *args) +{ + PyObject *py_obj; + if ( !PyArg_ParseTuple(args, "O", &py_obj) ) + return NULL; + return PyInt_FromLong(py_install_command_interpreter(py_obj)); +} + +//------------------------------------------------------------------------- +static PyObject *ex_remove_command_interpreter(PyObject *self, PyObject *args) +{ + int cli_idx; + if ( !PyArg_ParseTuple(args, "i", &cli_idx) ) + return NULL; + py_remove_command_interpreter(cli_idx); + Py_RETURN_NONE; +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_cli[] = +{ + { "install_command_interpreter", ex_install_command_interpreter, METH_VARARGS, "" }, + { "remove_command_interpreter", ex_remove_command_interpreter, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } +}; +DRIVER_INIT_METHODS(cli); \ No newline at end of file diff --git a/pywraps/driver_custview.cpp b/pywraps/driver_custview.cpp new file mode 100644 index 0000000..fec3d8c --- /dev/null +++ b/pywraps/driver_custview.cpp @@ -0,0 +1,384 @@ +#include "py_custview.hpp" + +//-------------------------------------------------------------------------- +class my_custviewer: public customviewer_t +{ +private: + cvdata_simpleline_t data; + size_t id_n; + virtual bool on_popup_menu(size_t menu_id) + { + if ( menu_id == id_n ) + msg("popup menu N chosen!\n"); + return true; + } + virtual bool on_click(int shift) + { + msg("onclick; shift=%d\n", shift); + return true; + } + virtual void on_close() + { + id_n = 0; + msg("closed...\n"); + } + virtual bool on_keydown(int key, int shift) + { + switch ( key ) + { + case 'N': + warning("The hotkey 'N' has been pressed"); + return true; + case 'I': + { + int x, y; + place_t *pl = get_place(false, &x, &y); + if ( pl == NULL ) + return false; + msg("x=%d y=%d\n", x, y); + simpleline_t sl = *data.get_line(pl); + sl.bgcolor = bgcolor_t(~uint32(sl.bgcolor)); + data.set_line(data.to_lineno(pl), sl); + refresh_current(); + return true; + } + case 'A': + { + char buf[100]; + qsnprintf(buf, sizeof(buf), "This is line %d\n", data.count()); + data.add_line(buf); + msg("Added one more line...\n"); + return true; + } + case 'S': + { + twinpos_t p1, p2; + ::readsel2(_cv, &p1, &p2); + size_t y1 = data.to_lineno(p1.at); + size_t y2 = data.to_lineno(p2.at); + int x1 = p1.x; + int x2 = p2.x; + msg("(x1=%d y1=%d) (x2=%d y2=%d)", x1, y1, x2, y2); + return true; + } + case 'X': + data.set_minmax(); + return true; + case 'R': + refresh(); + msg("refreshing!\n"); + return true; + case IK_ESCAPE: + close(); + return true; + } + return false; + } + virtual void on_curpos_changed() + { + qstring word; + if ( get_current_word(false, word) ) + msg("Current word is: %s\n", word.c_str()); + } + virtual bool on_hint(place_t *place, int *important_lines, qstring &hint) + { + simpleline_t *line = data.get_line(place); + if ( line == NULL ) + return false; + *important_lines = 1; + hint = line->line; + return true; + } + +public: + void init_sample_lines() + { + strvec_t &lines = data.get_lines(); + static struct + { + const char *text; + bgcolor_t color; + } const sample_lines[] = + { + { "This is a sample text", 0xFFFFFF }, + { "It will be displayed in the custom view", 0xFFC0C0 }, + { COLSTR("This line will be colored as erroneous", SCOLOR_ERROR), 0xC0FFC0 }, + { COLSTR("Every", SCOLOR_AUTOCMT) " " + COLSTR("word", SCOLOR_DNAME) " " + COLSTR("can", SCOLOR_IMPNAME) " " + COLSTR("be", SCOLOR_NUMBER) " " + COLSTR("colored!", SCOLOR_EXTRA), 0xC0C0FF }, + { " No limit on the number of lines.", 0xC0FFFF }, + }; + for ( int i=0; i < qnumber(sample_lines); i++ ) + { + lines.push_back(simpleline_t("")); // add empty line + lines.push_back(simpleline_t(sample_lines[i].text)); + lines.back().bgcolor = sample_lines[i].color; + } + } + my_custviewer() + { + id_n = 0; + init_sample_lines(); + data.set_minmax(); + } + bool init(const char *title) + { + if ( id_n != 0 ) + return true; + if ( !create(title, HAVE_HINT | HAVE_CLICK | HAVE_KEYDOWN | HAVE_CURPOS, &data) ) + return false; + id_n = add_popup_menu("Do this", "N"); + return true; + } +}; + +my_custviewer *g_cv; + +//------------------------------------------------------------------------- +static PyObject *ex_pyscv_init(PyObject *self, PyObject *args) +{ + const char *title; + PyObject *py_link; + if ( !PyArg_ParseTuple(args, "Os", &py_link, &title) ) + return NULL; + return pyscv_init(py_link, title); +} + +static PyObject *ex_pyscv_add_line(PyObject *self, PyObject *args) +{ + PyObject *py_this, *py_sl; + if ( !PyArg_ParseTuple(args, "OO", &py_this, &py_sl) ) + return NULL; + return Py_BuildValue("i", pyscv_add_line(py_this, py_sl)); +} + +static PyObject *ex_pyscv_delete(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return Py_BuildValue("i", pyscv_delete(py_this)); +} + +static PyObject *ex_pyscv_show(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return Py_BuildValue("i", pyscv_show(py_this)); +} + +static PyObject *ex_pyscv_refresh(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return Py_BuildValue("i", pyscv_refresh(py_this)); +} + +static PyObject *ex_pyscv_close(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + pyscv_close(py_this); + Py_RETURN_NONE; +} + +static PyObject *ex_pyscv_clear_popup_menu(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + pyscv_clear_popup_menu(py_this); + Py_RETURN_NONE; +} + +static PyObject *ex_pyscv_del_line(PyObject *self, PyObject *args) +{ + PyObject *py_this; + size_t nline; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64, &py_this, &nline) ) + return NULL; + return Py_BuildValue("i", pyscv_del_line(py_this, nline)); +} + +static PyObject *ex_pyscv_get_pos(PyObject *self, PyObject *args) +{ + PyObject *py_this; + int mouse; + if ( !PyArg_ParseTuple(args, "Oi", &py_this, &mouse) ) + return NULL; + return pyscv_get_pos(py_this, mouse == 0 ? false : true); +} + +static PyObject *ex_pyscv_refresh_current(PyObject *self, PyObject *args) +{ + PyObject *py_this; + int mouse; + if ( !PyArg_ParseTuple(args, "Oi", &py_this, &mouse) ) + return NULL; + return Py_BuildValue("i", pyscv_refresh_current(py_this)); +} + +static PyObject *ex_pyscv_get_current_line(PyObject *self, PyObject *args) +{ + PyObject *py_this; + int mouse, notags; + if ( !PyArg_ParseTuple(args, "Oii", &py_this, &mouse, ¬ags) ) + return NULL; + return pyscv_get_current_line(py_this, mouse == 0 ? false : true, notags == 0 ? false : true); +} + +static PyObject *ex_pyscv_is_focused(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return Py_BuildValue("i", pyscv_is_focused(py_this)); +} + +static PyObject *ex_pyscv_add_popup_menu(PyObject *self, PyObject *args) +{ + PyObject *py_this; + const char *title, *hotkey; + if ( !PyArg_ParseTuple(args, "Oss", &py_this, &title, &hotkey) ) + return NULL; + return Py_BuildValue("i", pyscv_add_popup_menu(py_this, title, hotkey)); +} + +static PyObject *ex_pyscv_get_line(PyObject *self, PyObject *args) +{ + PyObject *py_this; + size_t nline; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64, &py_this, &nline) ) + return NULL; + return pyscv_get_line(py_this, nline); +} + +static PyObject *ex_pyscv_jumpto(PyObject *self, PyObject *args) +{ + PyObject *py_this; + int x, y; + size_t lineno; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64 "ii", &py_this, &lineno, &x, &y) ) + return NULL; + return Py_BuildValue("i", pyscv_jumpto(py_this, lineno, x, y)); +} + +static PyObject *ex_pyscv_edit_line(PyObject *self, PyObject *args) +{ + PyObject *py_this, *py_sl; + size_t lineno; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64 "O", &py_this, &lineno, &py_sl) ) + return NULL; + return Py_BuildValue("i", pyscv_edit_line(py_this, lineno, py_sl)); +} + +static PyObject *ex_pyscv_insert_line(PyObject *self, PyObject *args) +{ + PyObject *py_this, *py_sl; + size_t lineno; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64 "O", &py_this, &lineno, &py_sl) ) + return NULL; + return Py_BuildValue("i", pyscv_insert_line(py_this, lineno, py_sl)); +} + +static PyObject *ex_pyscv_patch_line(PyObject *self, PyObject *args) +{ + PyObject *py_this; + size_t lineno, offs; + int value; + if ( !PyArg_ParseTuple(args, "O" PY_FMT64 PY_FMT64 "i", &py_this, &lineno, &offs, &value) ) + return NULL; + return Py_BuildValue("i", pyscv_patch_line(py_this, lineno, offs, value)); +} + +static PyObject *ex_pyscv_count(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return Py_BuildValue(PY_FMT64, pyscv_count(py_this)); +} + +static PyObject *ex_pyscv_get_selection(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return pyscv_get_selection(py_this); +} + +static PyObject *ex_pyscv_get_current_word(PyObject *self, PyObject *args) +{ + PyObject *py_this; + int mouse; + if ( !PyArg_ParseTuple(args, "Oi", &py_this, &mouse) ) + return NULL; + return pyscv_get_current_word(py_this, mouse != 0); +} + +static PyObject *ex_pyscv_clear_lines(PyObject *self, PyObject *args) +{ + PyObject *py_this; + if ( !PyArg_ParseTuple(args, "O", &py_this) ) + return NULL; + return pyscv_clear_lines(py_this); +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_custview[] = +{ + { "pyscv_init", ex_pyscv_init, METH_VARARGS, "" }, + { "pyscv_close", ex_pyscv_close, METH_VARARGS, "" }, + { "pyscv_add_line", ex_pyscv_add_line, METH_VARARGS, "" }, + { "pyscv_delete", ex_pyscv_delete, METH_VARARGS, "" }, + { "pyscv_refresh", ex_pyscv_refresh, METH_VARARGS, "" }, + { "pyscv_clear_lines", ex_pyscv_clear_lines, METH_VARARGS, "" }, + { "pyscv_show", ex_pyscv_show, METH_VARARGS, "" }, + { "pyscv_clear_popup_menu", ex_pyscv_clear_popup_menu, METH_VARARGS, "" }, + { "pyscv_del_line", ex_pyscv_del_line, METH_VARARGS, "" }, + { "pyscv_get_pos", ex_pyscv_get_pos, METH_VARARGS, "" }, + { "pyscv_refresh_current", ex_pyscv_refresh_current, METH_VARARGS, "" }, + { "pyscv_get_current_line", ex_pyscv_get_current_line, METH_VARARGS, "" }, + { "pyscv_is_focused", ex_pyscv_is_focused, METH_VARARGS, "" }, + { "pyscv_add_popup_menu", ex_pyscv_add_popup_menu, METH_VARARGS, "" }, + { "pyscv_get_line", ex_pyscv_get_line, METH_VARARGS, "" }, + { "pyscv_jumpto", ex_pyscv_jumpto, METH_VARARGS, "" }, + { "pyscv_edit_line", ex_pyscv_edit_line, METH_VARARGS, "" }, + { "pyscv_insert_line", ex_pyscv_insert_line, METH_VARARGS, "" }, + { "pyscv_count", ex_pyscv_count, METH_VARARGS, "" }, + { "pyscv_patch_line", ex_pyscv_patch_line, METH_VARARGS, "" }, + { "pyscv_get_selection", ex_pyscv_get_selection, METH_VARARGS, "" }, + { "pyscv_get_current_word", ex_pyscv_get_current_word, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(custview); + +#define DRIVER_RUN +void driver_run(int) +{ + if ( !g_cv->init("My sample viewer!") ) + { + msg("Failed to create cv\n!"); + return; + } + g_cv->show(); +} + +#define DRIVER_INIT +int driver_init() +{ + g_cv = new my_custviewer(); + return PLUGIN_KEEP; +} + +#define DRIVER_TERM +void driver_term() +{ + g_cv->close(); + delete g_cv; +} diff --git a/pywraps/driver_dbg.cpp b/pywraps/driver_dbg.cpp new file mode 100644 index 0000000..f2ff86e --- /dev/null +++ b/pywraps/driver_dbg.cpp @@ -0,0 +1,79 @@ +#include "py_dbg.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_getthreadsregbase(PyObject * /*self*/, PyObject *args) +{ + PyObject *py_tid, *py_sreg_value; + if ( !PyArg_ParseTuple(args, "OO", &py_tid, &py_sreg_value) ) + return NULL; + return dbg_get_thread_sreg_base(py_tid, py_sreg_value); +} + +//------------------------------------------------------------------------- +static PyObject *ex_readmemory(PyObject * /*self*/, PyObject *args) +{ + PyObject *py_ea, *py_size; + if ( !PyArg_ParseTuple(args, "OO", &py_ea, &py_size) ) + return NULL; + return dbg_read_memory(py_ea, py_size); +} + +//------------------------------------------------------------------------- +static PyObject *ex_writememory(PyObject * /*self*/, PyObject *args) +{ + PyObject *py_ea, *py_buf; + if ( !PyArg_ParseTuple(args, "OO", &py_ea, &py_buf) ) + return NULL; + return dbg_write_memory(py_ea, py_buf); +} + +//------------------------------------------------------------------------- +static PyObject *ex_getmeminfo(PyObject * /*self*/, PyObject *args) +{ + return dbg_get_memory_info(); +} + +//------------------------------------------------------------------------- +static PyObject *ex_getregs(PyObject *self, PyObject *args) +{ + return dbg_get_registers(); +} + +//------------------------------------------------------------------------- +static PyObject *ex_appcall(PyObject * /*self*/, PyObject *args) +{ + PyObject *app_args, *type, *fields; + int func_ea, tid; + if ( !PyArg_ParseTuple(args, "iiOOO", &func_ea, &tid, &type, &fields, &app_args) ) + return NULL; + return py_appcall(func_ea, tid, type, fields, app_args); +} + +//------------------------------------------------------------------------- +static PyObject *ex_pytoidc( + PyObject *self, + PyObject *args) +{ + if ( !PyArg_ParseTuple(args, "O", &self) ) + return NULL; + idc_value_t v; + int sn = 0; + borref_t self_ref(self); + if ( pyvar_to_idcvar(self_ref, &v, &sn) < CIP_OK ) + Py_RETURN_NONE; + Py_RETURN_TRUE; +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_dbg[] = +{ + { "getregs", ex_getregs, METH_VARARGS, "" }, + { "getmeminfo", ex_getmeminfo, METH_VARARGS, "" }, + { "readmemory", ex_readmemory, METH_VARARGS, "" }, + { "writememory", ex_writememory, METH_VARARGS, "" }, + { "getthreadsregbase", ex_getthreadsregbase, METH_VARARGS, "" }, + { "appcall", ex_appcall, METH_VARARGS, "" }, + { "pytoidc", ex_pytoidc, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(dbg); diff --git a/pywraps/driver_diskio.cpp b/pywraps/driver_diskio.cpp new file mode 100644 index 0000000..8f99dda --- /dev/null +++ b/pywraps/driver_diskio.cpp @@ -0,0 +1,47 @@ +#include "py_diskio.hpp" + +static PyObject *ex_enumfiles(PyObject * /*self*/, PyObject *args) +{ + PyObject *path, *fname, *callback; + if ( !PyArg_ParseTuple(args, "OOO", &path, &fname, &callback) ) + return NULL; + return py_enumerate_files(path, fname, callback); +} + +// +//static PyObject *ex_linput_close(PyObject * /*self*/, PyObject *args) +//{ +// PyObject *obj; +// if ( !PyArg_ParseTuple(args, "O", &obj) ) +// return NULL; +// pyl_close(obj); +// Py_RETURN_NONE; +//} +// +//static PyObject *ex_linput_open(PyObject *self, PyObject *args) +//{ +// PyObject *obj, *py_filename, *py_remote; +// if ( !PyArg_ParseTuple(args, "OOO", &obj, &py_filename, &py_remote) ) +// return NULL; +// return pyl_open(obj, py_filename, py_remote); +//} +// +//static PyObject *ex_linput_read(PyObject *self, PyObject *args) +//{ +// PyObject *obj, *py_size; +// if ( !PyArg_ParseTuple(args, "OO", &obj, &py_size) ) +// return NULL; +// return pyl_read(obj, py_size); +//} + +static PyMethodDef py_methods_diskio[] = +{ + { "enumfiles", ex_enumfiles, METH_VARARGS, "" }, + //{ "tell", ex_linput_tell, METH_VARARGS, "" }, + //{ "open", ex_linput_open, METH_VARARGS, "" }, + //{ "size", ex_linput_tell, METH_VARARGS, "" }, + //{ "read", ex_linput_read, METH_VARARGS, "" }, + //{ "close", ex_linput_close, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(diskio); \ No newline at end of file diff --git a/pywraps/driver_expr.cpp b/pywraps/driver_expr.cpp new file mode 100644 index 0000000..c636adb --- /dev/null +++ b/pywraps/driver_expr.cpp @@ -0,0 +1,56 @@ +#include "py_expr.hpp" + +#pragma warning(push) +#pragma warning(disable: 4244) + +//--------------------------------------------------------------------------- +static PyObject *ex_pyw_register_idc_func(PyObject *self, PyObject *args) +{ + char *name, *arg; + PyObject *py_fp; + if ( !PyArg_ParseTuple(args, "ssO", &name, &arg, &py_fp) ) + return NULL; + else + return PyLong_FromUnsignedLongLong(pyw_register_idc_func(name, arg, py_fp)); +} + +//--------------------------------------------------------------------------- +static PyObject *ex_pyw_unregister_idc_func(PyObject *self, PyObject *args) +{ + unsigned PY_LONG_LONG ctxptr; + if ( !PyArg_ParseTuple(args, "K", &ctxptr) ) + return NULL; + return PyLong_FromLong(pyw_unregister_idc_func(ctxptr)); +} + +static PyObject *ex_py_set_idc_func_ex(PyObject *self, PyObject *pyargs) +{ + const char *name; + unsigned PY_LONG_LONG fp_ptr; + const char *args; + int flags; + if ( !PyArg_ParseTuple(pyargs, "sKsi", &name, &fp_ptr, &args, &flags) ) + return NULL; + else + return PyLong_FromLong(py_set_idc_func_ex(name, fp_ptr, args, flags)); +} + +//--------------------------------------------------------------------------- +static PyObject *ex_py_get_call_idc_func(PyObject *self, PyObject *args) +{ + return PyLong_FromUnsignedLongLong(py_get_call_idc_func()); +} + +//------------------------------------------------------------------------- +#pragma warning(pop) + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_expr[] = +{ + { "pyw_register_idc_func", ex_pyw_register_idc_func, METH_VARARGS, "" }, + { "pyw_unregister_idc_func", ex_pyw_unregister_idc_func, METH_VARARGS, "" }, + { "py_get_call_idc_func", ex_py_get_call_idc_func, METH_VARARGS, "" }, + { "py_set_idc_func_ex", ex_py_set_idc_func_ex, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } // End of methods +}; +DRIVER_INIT_METHODS(expr); diff --git a/pywraps/driver_graph.cpp b/pywraps/driver_graph.cpp new file mode 100644 index 0000000..6216c78 --- /dev/null +++ b/pywraps/driver_graph.cpp @@ -0,0 +1,44 @@ +#include "py_graph.hpp" + +//-------------------------------------------------------------------------- +//py_choose2_t *last_c2 = NULL; +static PyObject *ex_graph_show(PyObject * /*self*/, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + + py_graph_t *ret = py_graph_t::Show(obj); + return PyBool_FromLong(ret == NULL ? 0 : 1); +} + +//-------------------------------------------------------------------------- +static PyObject *ex_graph_refresh(PyObject * /*self*/, PyObject *args) +{ + PyObject *obj; + if ( !PyArg_ParseTuple(args, "O", &obj) ) + return NULL; + py_graph_t::Refresh(obj); + Py_RETURN_NONE; +} + +//-------------------------------------------------------------------------- +static PyObject *ex_graph_addcmd(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *title, *hotkey; + if ( !PyArg_ParseTuple(args, "Oss", &obj, &title, &hotkey) ) + return NULL; + Py_ssize_t r = py_graph_t::AddCommand(obj, title, hotkey); + return Py_BuildValue("n", r); +} + +//-------------------------------------------------------------------------- +static PyMethodDef py_methods_graph[] = +{ + { "show", ex_graph_show, METH_VARARGS, "" }, + { "refresh", ex_graph_refresh, METH_VARARGS, "" }, + { "addcmd", ex_graph_addcmd, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(graph); \ No newline at end of file diff --git a/pywraps/driver_kernwin.cpp b/pywraps/driver_kernwin.cpp new file mode 100644 index 0000000..1c28e45 --- /dev/null +++ b/pywraps/driver_kernwin.cpp @@ -0,0 +1,78 @@ +#include "py_kernwin.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_add_menu_item(PyObject *self, PyObject *args) +{ + const char *menupath, *name, *hotkey; + PyObject *pyfunc, *pyargs; + int flags; + if ( !PyArg_ParseTuple(args, "sssiOO", &menupath, &name, &hotkey, &flags, &pyfunc, &pyargs) ) + return NULL; + return py_add_menu_item(menupath, name, hotkey, flags, pyfunc, pyargs); +} + +//------------------------------------------------------------------------- +static PyObject *ex_del_menu_item(PyObject *self, PyObject *args) +{ + if ( !PyArg_ParseTuple(args, "O", &self) ) + return NULL; + if ( py_del_menu_item(self) ) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +//------------------------------------------------------------------------- +static PyObject *ex_execute_sync(PyObject *self, PyObject *args) +{ + PyObject *pycall; + int reqf; + if ( !PyArg_ParseTuple(args, "Oi", &pycall, &reqf) ) + return NULL; + return PyInt_FromLong(py_execute_sync(pycall, reqf)); +} + +//------------------------------------------------------------------------- +static PyObject *ex_add_hotkey(PyObject *self, PyObject *args) +{ + PyObject *pyfunc; + const char *hotkey; + if ( !PyArg_ParseTuple(args, "sO", &hotkey, &pyfunc) ) + return NULL; + else + return py_add_hotkey(hotkey, pyfunc); +} + +//------------------------------------------------------------------------- +static PyObject *ex_del_hotkey(PyObject *self, PyObject *args) +{ + PyObject *pyctx; + if ( !PyArg_ParseTuple(args, "O", &pyctx) ) + return NULL; + else + return PyInt_FromLong(py_del_hotkey(pyctx) ? 1 : 0); +} + +//------------------------------------------------------------------------- +static PyObject *ex_execute_ui_request(PyObject *self, PyObject *args) +{ + PyObject *py_list; + if ( !PyArg_ParseTuple(args, "O", &py_list) ) + return NULL; + else + return PyBool_FromLong(py_execute_ui_requests(py_list) ? 1 : 0); +} + + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_kernwin[] = +{ + { "py_del_menu_item", ex_del_menu_item, METH_VARARGS, "" }, + { "py_add_menu_item", ex_add_menu_item, METH_VARARGS, "" }, + { "py_execute_sync", ex_execute_sync, METH_VARARGS, "" }, + { "py_add_hotkey", ex_add_hotkey, METH_VARARGS, "" }, + { "py_del_hotkey", ex_del_hotkey, METH_VARARGS, "" }, + { "py_execute_ui_request", ex_execute_ui_request, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(kernwin); \ No newline at end of file diff --git a/pywraps/driver_nalt.cpp b/pywraps/driver_nalt.cpp new file mode 100644 index 0000000..395d18b --- /dev/null +++ b/pywraps/driver_nalt.cpp @@ -0,0 +1,18 @@ +#include "py_nalt.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_get_switch_info_ex(PyObject *self, PyObject *args) +{ + pyul_t ea; + if ( !PyArg_ParseTuple(args, PY_FMT64, &ea) ) + return NULL; + return py_get_switch_info_ex(ea_t(ea)); +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_nalt[] = +{ + { "get_switch_info_ex", ex_get_switch_info_ex, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } +}; +DRIVER_INIT_METHODS(nalt); diff --git a/pywraps/driver_notifywhen.cpp b/pywraps/driver_notifywhen.cpp new file mode 100644 index 0000000..662fe77 --- /dev/null +++ b/pywraps/driver_notifywhen.cpp @@ -0,0 +1,36 @@ +#include "py_notifywhen.hpp" + +//------------------------------------------------------------------------- +static PyObject *ex_notify_when(PyObject *self, PyObject *args) +{ + int when; + PyObject *py_callable; + if ( !PyArg_ParseTuple(args, "IO", &when, &py_callable) ) + return NULL; + return Py_BuildValue("i", notify_when(when, py_callable)); +} + +//------------------------------------------------------------------------- +static PyMethodDef py_methods_nw[] = +{ + { "notify_when", ex_notify_when, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; +DRIVER_INIT_METHODS(nw); + +#define DRIVER_INIT +int driver_init() +{ + bool ok = pywraps_nw_init(); + if ( !ok ) + return PLUGIN_SKIP; + pywraps_nw_notify(NW_INITIDA_SLOT); + return PLUGIN_KEEP; +} + +#define DRIVER_TERM +void driver_term() +{ + pywraps_nw_notify(NW_TERMIDA_SLOT); + pywraps_nw_term(); +} diff --git a/pywraps/link_gen.py b/pywraps/link_gen.py deleted file mode 100755 index 1ff7608..0000000 --- a/pywraps/link_gen.py +++ /dev/null @@ -1,336 +0,0 @@ -import types - -C_TO_PY_CAST = { - 'b' : 'char', - 'i' : 'int', - 'H' : 'uint16', - 'h' : 'int16', - 'B' : 'uchar', -} -# -------------------------------------------------------------------------------------------- -class gen_fmt(object): - def __init__(self, fields, tp = None, bv = None, cast=None, cmt = None): - self.fields = fields - self.tp = tp - # Format to be passed to Py_BuildValue - if not bv: - self.bv = "XXX" - else: - if bv == "K": - self.bv = "PY_FMT64" - else: - self.bv = '"%s"' % bv - - if not cast: - if bv == "K": - cast = "pyul_t" - elif bv in C_TO_PY_CAST: - cast = C_TO_PY_CAST[bv] - - self.cast = "" if not cast else "(%s)" % cast - self.cmt = cmt - if bv == "K": - self.setcvt = "uint64 v(0); PyGetNumber(value, &v);" - elif bv == 'i': - self.setcvt = "int v = PyInt_AsLong(value);" - else: - self.setcvt = "uint64 v = %sPyInt_AsLong(value);" % self.cast - - -# -------------------------------------------------------------------------------------------- -switch_info_ex_t_gen = [ - gen_fmt('regdtyp', bv = 'b', cmt = 'size of the switch expression register as dtyp'), - gen_fmt('flags2', bv = 'i'), - gen_fmt('jcases', bv = 'i', cmt = 'number of entries in the jump table (SWI2_INDIRECT)'), - gen_fmt('regnum', bv = 'i', cmt = 'the switch expression as a register number'), - gen_fmt('flags', bv = 'H', cmt = 'the switch expression as a register number'), - gen_fmt('ncases', bv = 'H', cmt = 'number of cases (excluding default)'), - gen_fmt('defjump', bv = 'K', cmt = 'default jump address'), - gen_fmt('jumps', bv = 'K', cmt = 'jump table address'), - gen_fmt('elbase', bv = 'K', cmt = 'element base'), - gen_fmt('startea', bv = 'K', cmt = 'start of switch idiom'), - gen_fmt('custom', bv = 'K', cmt = 'information for custom tables (filled and used by modules)'), - gen_fmt('ind_lowcase', bv = 'K'), - gen_fmt(['values', 'lowcase'], bv = 'K'), -] - -op_t_gen = [ - gen_fmt('n', bv = 'b'), - gen_fmt('type', bv = 'B'), - gen_fmt('offb', bv = 'b'), - gen_fmt('offo', bv = 'b'), - gen_fmt('flags', bv = 'B'), - gen_fmt('dtyp', bv = 'b'), - gen_fmt(['reg', 'phrase'], bv = 'H'), - gen_fmt('value', bv = 'K'), - gen_fmt('addr', bv = 'K'), - gen_fmt('specval', bv = 'K'), - gen_fmt('specflag1', bv = 'b'), - gen_fmt('specflag2', bv = 'b'), - gen_fmt('specflag3', bv = 'b'), - gen_fmt('specflag4', bv = 'b') -] - -insn_t_gen = [ - gen_fmt('cs', bv = 'K'), - gen_fmt('ip', bv = 'K'), - gen_fmt('ea', bv = 'K'), - gen_fmt('itype', bv = 'H'), - gen_fmt('size', bv = 'H'), - gen_fmt('auxpref', bv = 'H'), - gen_fmt('segpref', bv = 'b'), - gen_fmt('insnpref', bv = 'b'), - gen_fmt('Op1', tp = 'op_t'), - gen_fmt('Op2', tp = 'op_t'), - gen_fmt('Op3', tp = 'op_t'), - gen_fmt('Op4', tp = 'op_t'), - gen_fmt('Op5', tp = 'op_t'), - gen_fmt('Op6', tp = 'op_t'), - gen_fmt('flags', bv = 'b') -] - -regval_t_gen = [ - gen_fmt('rvtype', bv = 'i'), - gen_fmt('ival', bv = 'K'), - gen_fmt('fval', bv = 'd'), - gen_fmt('bytes', bv = 's'), -] - -# -------------------------------------------------------------------------------------------- -S_LINK_ATTR = 'S_CLINK_NAME' # If the name is a literal, make sure you specify double quotations -S_CMOD_NAME = '_idaapi' - -# -------------------------------------------------------------------------------------------- -def gen_stub(gen, name, cname = None, tabs=4, gen_py_file = False, gen_c_file = False): - # Assume C type name same as python type name - if not cname: - cname = name - - # Python property lines - prop_body = [] - - # Python get/set bodies - getset_body = [] - - # C get/set bodies - cgetset_body = [] - - # some spacing constants - spc = ' ' * tabs - spc2 = spc * 2 - nspc = '\n' + spc - nspc2 = '\n' + spc2 - - cget_link = '%s_get_clink' % cname - - # - # Process fields - # - for g in gen: - # a union will be represented by a list - if type(g.fields) != types.ListType: - fields = [g.fields] - else: - fields = g.fields - - # join all field names (in case of a union) - flds_name = '_'.join(fields) - - # form the method and variable names - set_method = '__set_%s__' % flds_name - get_method = '__get_%s__' % flds_name - cset_method = '%s_set_%s' % (name, flds_name) - cget_method = '%s_get_%s' % (name, flds_name) - fld_name = '__%s__' % flds_name - - basic_type = not g.tp - - vars = { - 'get': get_method, - 'set': set_method, - 'l': S_LINK_ATTR, - 'fld' : fld_name, - 'cmod' : S_CMOD_NAME, - 'cget': cget_method, - 'cset': cset_method, - 'csetcvt': g.setcvt, - 'cname': cname, - 'cgetlink': cget_link, - 'cfield1': fields[0], - 'bv': g.bv, - 'bvcast': g.cast - } - - # - # Python code - # - - # basic type? - # For basic types we need to create property and get/set methods - if basic_type: - for fld in fields: - prop_body.append('%s = property(%s, %s)' % (fld, get_method, set_method)) - if g.cmt: - prop_body.append('"""%s"""' % g.cmt) - - # - code = '\n'.join([ - # get method - 'def %(get)s(self):', - spc2 + 'return %(cmod)s.%(cget)s(self)', - # set method - spc + 'def %(set)s(self, v):', - spc2 + '%(cmod)s.%(cset)s(self, v)', - ]) % vars - - getset_body.append(code) - - # - # C code - # - if basic_type: - code = '\n'.join([ -"""static PyObject *%(cget)s(PyObject *self) -{ - %(cname)s *link = %(cgetlink)s(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(%(bv)s, %(bvcast)slink->%(cfield1)s); -} -static void %(cset)s(PyObject *self, PyObject *value) -{ - %(cname)s *link = %(cgetlink)s(self); - if ( link == NULL ) - return; - %(csetcvt)s - link->%(cfield1)s = %(bvcast)sv; -} - -""" - ]) % vars - - cgetset_body.append(code) - -# print 'prop_body->\n\t', '\n\t'.join(prop_body), '\n<' -# print 'getset_body->\n', '\n'.join(getset_body), '\n<' -# print 'cgetset_body->\n', '\n'.join(cgetset_body), '\n<' - - vars = { - 'name': name, - 'cname': cname, - 'getlink': cget_link, - 'l': S_LINK_ATTR, - 'cmod' : S_CMOD_NAME - } - - # - # Form the complete Python code - # - py = '\n'.join([ - 'class %(name)s(py_clinked_object_t):', - - # init() code - spc + 'def __init__(self, lnk = None):', - spc2 + 'py_clinked_object_t.__init__(self, lnk)', - '', - spc + 'def _create_clink(self):', - spc2 + 'return _idaapi.%(name)s_create()', - '', - spc + 'def _del_clink(self, lnk):', - spc2 + 'return _idaapi.%(name)s_destroy(lnk)', - '', - spc + 'def assign(self, other):', - spc2 + 'return _idaapi.%(name)s_assign(self, other)', - '', - '', - spc + '#', - spc + '# Autogenerated', - spc + '#', - # get/set code - spc + nspc.join(getset_body), - # props code - spc + nspc.join(prop_body), - ]) % vars - - # - # Form the Python to C conversion function - # - - # - # Form the complete C code - # - ccode = '\n'.join([ - # Form the C get link code -"""%(cname)s *%(getlink)s(PyObject *self) -{ - if ( !PyObject_HasAttrString(self, %(l)s) ) - return NULL; - %(cname)s *r; - PyObject *attr = PyObject_GetAttrString(self, %(l)s); - if ( PyCObject_Check(attr) ) - r = (%(cname)s *) PyCObject_AsVoidPtr(attr); - else - r = NULL; - Py_DECREF(attr); - return r; -} - -static PyObject *%(cname)s_create() -{ - %(cname)s *inst = new %(cname)s(); - return PyCObject_FromVoidPtr(inst, NULL); -} - -static bool %(cname)s_destroy(PyObject *py_obj) -{ - if ( !PyCObject_Check(py_obj) ) - return false; - %(cname)s *inst = (%(cname)s *) PyCObject_AsVoidPtr(py_obj); - delete inst; - return true; -} - -static bool %(cname)s_assign(PyObject *self, PyObject *other) -{ - %(cname)s *lhs = %(cname)s_get_clink(self); - %(cname)s *rhs = %(cname)s_get_clink(other); - if (lhs == NULL || rhs == NULL) - return false; - - *lhs = *rhs; - return true; -} - -//------------------------------------------------------------------------- -// Auto generated - begin -// -""", - # Form C get/set functions - ''.join(cgetset_body), -"""// -// Auto generated - end -// -//-------------------------------------------------------------------------""" - ]) % vars - - # write the Python file - if gen_py_file: - f = open(name + '.py', 'w') - f.write(py) - f.close() - - # write C file - if gen_c_file: - f = open(name + '.cpp', 'w') - f.write(ccode) - f.close() - -# -------------------------------------------------------------------------------------------- -def main(): - files = [ - ('switch_info_ex_t', switch_info_ex_t_gen), - ] - for (n, g) in files: - gen_stub(g, n, gen_py_file = True, gen_c_file = True) - -main() \ No newline at end of file diff --git a/pywraps/py_area.hpp b/pywraps/py_area.hpp new file mode 100644 index 0000000..85c5a4b --- /dev/null +++ b/pywraps/py_area.hpp @@ -0,0 +1,11 @@ + +// +enum areacb_type_t +{ + AREACB_TYPE_UNKNOWN, + AREACB_TYPE_FUNC, + AREACB_TYPE_SEGMENT, + AREACB_TYPE_HIDDEN_AREA, + AREACB_TYPE_SRAREA, +}; +// diff --git a/pywraps/py_custdata.hpp b/pywraps/py_bytes_custdata.hpp similarity index 98% rename from pywraps/py_custdata.hpp rename to pywraps/py_bytes_custdata.hpp index edc4bc0..369bd9e 100644 --- a/pywraps/py_custdata.hpp +++ b/pywraps/py_bytes_custdata.hpp @@ -1,7 +1,7 @@ -#ifndef __PY_IDA_CUSTDATA__ -#define __PY_IDA_CUSTDATA__ +#ifndef __PY_IDA_BYTES_CUSTDATA__ +#define __PY_IDA_BYTES_CUSTDATA__ -// +// class py_custom_data_type_t { data_type_t dt; @@ -445,7 +445,7 @@ public: } py_custom_data_format_t *find(int dtid, int dfid, POS *loc = NULL) { - for ( POS it=entries.begin(), it_end = entries.end(); it!=it_end; ++it ) + for ( POS it=entries.begin(), it_end = entries.end(); it != it_end; ++it ) { if ( it->dfid == dfid && it->dtid == dtid ) { @@ -492,10 +492,10 @@ static PyObject *py_data_format_to_py_dict(const data_format_t *df) S_MENU_NAME, df->menu_name == NULL ? "" : df->menu_name, S_HOTKEY, df->hotkey == NULL ? "" : df->hotkey); } -// +// //------------------------------------------------------------------------ -// +// //------------------------------------------------------------------------ /* @@ -676,6 +676,6 @@ static PyObject *py_get_custom_data_type(int dtid) return py_data_type_to_py_dict(dt); } -// +// -#endif +#endif // __PY_IDA_BYTES_CUSTDATA__ diff --git a/pywraps/py_custdata.py b/pywraps/py_bytes_custdata.py similarity index 87% rename from pywraps/py_custdata.py rename to pywraps/py_bytes_custdata.py index a0405d4..6595424 100755 --- a/pywraps/py_custdata.py +++ b/pywraps/py_bytes_custdata.py @@ -1,34 +1,6 @@ # ----------------------------------------------------------------------- -# Standalone and testing code -import sys -try: - import pywraps - pywraps_there = True - print "Using pywraps" -except: - pywraps_there = False - print "Not using pywraps" - -try: - import _idaapi -except: - print "Please try me from inside IDA" - sys.exit(0) - -import struct - -if pywraps_there: - _idaapi.register_custom_data_type = pywraps.register_custom_data_type - _idaapi.unregister_custom_data_type = pywraps.unregister_custom_data_type - _idaapi.register_custom_data_format = pywraps.register_custom_data_format - _idaapi.unregister_custom_data_format = pywraps.unregister_custom_data_format - _idaapi.get_custom_data_format = pywraps.get_custom_data_format - _idaapi.get_custom_data_type = pywraps.get_custom_data_type - -# ----------------------------------------------------------------------- -# +# DTP_NODUP = 0x0001 - class data_type_t(object): """ Custom data type definition. All data types should inherit from this class. @@ -48,7 +20,7 @@ class data_type_t(object): def register(self): """Registers the data type and returns the type id or < 0 on failure""" - return _idaapi.register_custom_data_type(self) + return _ida_bytes.register_custom_data_type(self) def unregister(self): """Unregisters the data type and returns True on success""" @@ -57,7 +29,7 @@ class data_type_t(object): return True # Try to unregister - r = _idaapi.unregister_custom_data_type(self.id) + r = _ida_bytes.unregister_custom_data_type(self.id) # Clear the ID if r: @@ -111,7 +83,7 @@ class data_format_t(object): def register(self, dtid): """Registers the data format with the given data type id and returns the type id or < 0 on failure""" - return _idaapi.register_custom_data_format(dtid, self) + return _ida_bytes.register_custom_data_format(dtid, self) def unregister(self, dtid): """Unregisters the data format with the given data type id""" @@ -121,7 +93,7 @@ class data_format_t(object): return True # Unregister - r = _idaapi.unregister_custom_data_format(dtid, self.id) + r = _ida_bytes.unregister_custom_data_format(dtid, self.id) # Clear the ID if r: @@ -243,5 +215,5 @@ def unregister_data_types_and_formats(formats): ok = __walk_types_and_formats(formats, __unreg_type, __unreg_format, False) return 1 if ok else -1 -# +# # ----------------------------------------------------------------------- diff --git a/pywraps/py_dbg.hpp b/pywraps/py_dbg.hpp index 750a8ea..7aaa64b 100644 --- a/pywraps/py_dbg.hpp +++ b/pywraps/py_dbg.hpp @@ -2,7 +2,6 @@ #define __PYDBG__ // -static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas); // // @@ -90,25 +89,6 @@ public: } // hookgenDBG:methods -virtual void dbg_process_start(pid_t pid, thid_t tid, ea_t ea, const char * modinfo_name, ea_t modinfo_base, asize_t modinfo_size) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(modinfo_name); qnotused(modinfo_base); qnotused(modinfo_size); } -virtual void dbg_process_exit(pid_t pid, thid_t tid, ea_t ea, int exit_code) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(exit_code); } -virtual void dbg_process_attach(pid_t pid, thid_t tid, ea_t ea, const char * modinfo_name, ea_t modinfo_base, asize_t modinfo_size) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(modinfo_name); qnotused(modinfo_base); qnotused(modinfo_size); } -virtual void dbg_process_detach(pid_t pid, thid_t tid, ea_t ea) {qnotused(pid); qnotused(tid); qnotused(ea); } -virtual void dbg_thread_start(pid_t pid, thid_t tid, ea_t ea) {qnotused(pid); qnotused(tid); qnotused(ea); } -virtual void dbg_thread_exit(pid_t pid, thid_t tid, ea_t ea, int exit_code) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(exit_code); } -virtual void dbg_library_load(pid_t pid, thid_t tid, ea_t ea, const char * modinfo_name, ea_t modinfo_base, asize_t modinfo_size) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(modinfo_name); qnotused(modinfo_base); qnotused(modinfo_size); } -virtual void dbg_library_unload(pid_t pid, thid_t tid, ea_t ea, const char * info) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(info); } -virtual void dbg_information(pid_t pid, thid_t tid, ea_t ea, const char * info) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(info); } -virtual int dbg_exception(pid_t pid, thid_t tid, ea_t ea, int exc_code, bool exc_can_cont, ea_t exc_ea, const char * exc_info) {qnotused(pid); qnotused(tid); qnotused(ea); qnotused(exc_code); qnotused(exc_can_cont); qnotused(exc_ea); qnotused(exc_info); return 0;} -virtual void dbg_suspend_process() {} -virtual int dbg_bpt(thid_t tid, ea_t bptea) {qnotused(tid); qnotused(bptea); return 0;} -virtual int dbg_trace(thid_t tid, ea_t ip) {qnotused(tid); qnotused(ip); return 0;} -virtual void dbg_request_error(int failed_command, int failed_dbg_notification) {qnotused(failed_command); qnotused(failed_dbg_notification); } -virtual void dbg_step_into() {} -virtual void dbg_step_over() {} -virtual void dbg_run_to(pid_t pid, thid_t tid, ea_t ea) {qnotused(pid); qnotused(tid); qnotused(ea); } -virtual void dbg_step_until_ret() {} -virtual void dbg_bpt_changed(int bptev_code, bpt_t * bpt) {qnotused(bptev_code); qnotused(bpt); } }; int idaapi DBG_Callback(void *ud, int notification_code, va_list va) @@ -125,151 +105,6 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va) switch ( notification_code ) { // hookgenDBG:notifications -case dbg_process_start: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_process_start(event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); -} -break; - -case dbg_process_exit: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_process_exit(event->pid, event->tid, event->ea, event->exit_code); -} -break; - -case dbg_process_attach: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_process_attach(event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); -} -break; - -case dbg_process_detach: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_process_detach(event->pid, event->tid, event->ea); -} -break; - -case dbg_thread_start: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_thread_start(event->pid, event->tid, event->ea); -} -break; - -case dbg_thread_exit: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_thread_exit(event->pid, event->tid, event->ea, event->exit_code); -} -break; - -case dbg_library_load: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_library_load(event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); -} -break; - -case dbg_library_unload: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_library_unload(event->pid, event->tid, event->ea, event->info); -} -break; - -case dbg_information: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_information(event->pid, event->tid, event->ea, event->info); -} -break; - -case dbg_exception: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - int * warn = va_arg(va, int *); - int _tmp = proxy->dbg_exception(event->pid, event->tid, event->ea, event->exc.code, event->exc.can_cont, event->exc.ea, event->exc.info); - ret = DBG_Hooks::store_int(_tmp, event, warn); -} -break; - -case dbg_suspend_process: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - qnotused(event); - proxy->dbg_suspend_process(); -} -break; - -case dbg_bpt: -{ - thid_t tid = va_arg(va, thid_t); - ea_t bptea = va_arg(va, ea_t); - int * warn = va_arg(va, int *); - int _tmp = proxy->dbg_bpt(tid, bptea); - ret = DBG_Hooks::store_int(_tmp, tid, bptea, warn); -} -break; - -case dbg_trace: -{ - thid_t tid = va_arg(va, thid_t); - ea_t ip = va_arg(va, ea_t); - ret = proxy->dbg_trace(tid, ip); -} -break; - -case dbg_request_error: -{ - ui_notification_t failed_command = ui_notification_t(va_arg(va, int)); - dbg_notification_t failed_dbg_notification = dbg_notification_t(va_arg(va, int)); - proxy->dbg_request_error((int) failed_command, (int) failed_dbg_notification); -} -break; - -case dbg_step_into: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - qnotused(event); - proxy->dbg_step_into(); -} -break; - -case dbg_step_over: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - qnotused(event); - proxy->dbg_step_over(); -} -break; - -case dbg_run_to: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - proxy->dbg_run_to(event->pid, event->tid, event->ea); -} -break; - -case dbg_step_until_ret: -{ - const debug_event_t * event = va_arg(va, const debug_event_t *); - qnotused(event); - proxy->dbg_step_until_ret(); -} -break; - -case dbg_bpt_changed: -{ - int bptev_code = va_arg(va, int); - bpt_t * bpt = va_arg(va, bpt_t *); - proxy->dbg_bpt_changed(bptev_code, bpt); -} -break; - } } catch (Swig::DirectorException &e) @@ -338,26 +173,5 @@ static ea_t py_internal_get_sreg_base(thid_t tid, int sreg_value) : answer; } -//------------------------------------------------------------------------- -static PyObject *py_get_tev_reg_mem(int tev, int reg) -{ - tev_info_t ti; - memreg_infos_t mis; - bool ok = get_tev_info(tev, &ti) - && get_insn_tev_reg_mem(tev, &mis) - && reg >= 0 && reg < mis.size(); - if ( ok ) - { - PyObject *py_str = PyString_FromStringAndSize( - (const char *) mis[reg].bytes.begin(), - mis[reg].bytes.size()); - return py_str; - } - else - { - Py_RETURN_NONE; - } -} - // #endif diff --git a/pywraps/py_dbg.py b/pywraps/py_dbg.py new file mode 100644 index 0000000..4cacdaf --- /dev/null +++ b/pywraps/py_dbg.py @@ -0,0 +1,8 @@ + +# +def get_tev_reg_mem(tev, idx): + mis = memreg_infos_t() + if get_insn_tev_reg_mem(tev, mis): + if idx < mis.size(): + return mis[idx].bytes +# diff --git a/pywraps/py_expr.hpp b/pywraps/py_expr.hpp index 71d64d9..e6bdcaa 100644 --- a/pywraps/py_expr.hpp +++ b/pywraps/py_expr.hpp @@ -44,9 +44,10 @@ static error_t py_call_idc_func( pargs.empty() ? NULL : pargs[0].o)); error_t err; - if ( PyW_GetError(errbuf, sizeof(errbuf)) ) + qstring qerrbuf; + if ( PyW_GetError(&qerrbuf) ) { - err = PyW_CreateIdcException(r, errbuf); + err = PyW_CreateIdcException(r, qerrbuf.c_str()); } else { diff --git a/pywraps/py_expr.py b/pywraps/py_expr.py index aefdd13..c5838bb 100644 --- a/pywraps/py_expr.py +++ b/pywraps/py_expr.py @@ -1,28 +1,3 @@ -# -------------------------------------------------------------------------- -import os -import sys - -import idaapi -import _idaapi -from sys import getrefcount -import gc - -try: - import pywraps - pywraps_there = True - _idaapi.pyw_register_idc_func = pywraps.pyw_register_idc_func - _idaapi.pyw_unregister_idc_func = pywraps.pyw_unregister_idc_func - _idaapi.py_get_call_idc_func = pywraps.py_get_call_idc_func - _idaapi.py_set_idc_func_ex = pywraps.py_set_idc_func_ex - - -except Exception as e: - pywraps_there = False - print("exception: %s" % str(e)) - - -print("Using PyWraps: %s" % pywraps_there) - # -------------------------------------------------------------------------- # try: @@ -34,13 +9,13 @@ try: # A trampoline function that is called from idcfunc_t that will # call the Python callback with the argv and r properly serialized to python - call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_call_idc_func()) + call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long)(_ida_expr.py_get_call_idc_func()) except: def call_idc_func__(*args): warning("IDC extensions need ctypes library in order to work") return 0 try: - _IDCFUNC_CB_T = CFUNCTYPE(c_int, c_void_p, c_void_p) + _IDCFUNC_CB_T = CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) except: _IDCFUNC_CB_T = None @@ -107,7 +82,7 @@ def set_idc_func_ex(name, fp=None, args=(), flags=0): del __IDC_FUNC_CTXS[name] # Delete the context and unregister the function - return _idaapi.pyw_unregister_idc_func(f.ctxptr) + return _ida_expr.pyw_unregister_idc_func(f.ctxptr) # Registering a function that is already registered? if f is not None: @@ -118,7 +93,7 @@ def set_idc_func_ex(name, fp=None, args=(), flags=0): args = "".join([chr(x) for x in args]) # Create a context - ctxptr = _idaapi.pyw_register_idc_func(name, args, fp) + ctxptr = _ida_expr.pyw_register_idc_func(name, args, fp) if ctxptr == 0: return False @@ -129,7 +104,7 @@ def set_idc_func_ex(name, fp=None, args=(), flags=0): __IDC_FUNC_CTXS[name] = f # Register IDC function with a callback - return _idaapi.py_set_idc_func_ex( + return _ida_expr.py_set_idc_func_ex( name, f.fp_ptr, args, diff --git a/pywraps/py_frame.hpp b/pywraps/py_frame.hpp new file mode 100644 index 0000000..ba3ad67 --- /dev/null +++ b/pywraps/py_frame.hpp @@ -0,0 +1,59 @@ +// +//------------------------------------------------------------------------- +/* +header: frame.hpp +# +def add_stkvar3(op, v, flags): + """ + Automatically add stack variable if doesn't exist + Processor modules should use ua_stkvar2() + @param op: reference to instruction operand + @param v: immediate value in the operand (usually op.addr) + @param flags: combination of STKVAR_... constants + @return: Boolean + """ + pass +# +*/ +bool py_add_stkvar3(PyObject *py_op, PyObject *py_v, int flags) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + op_t *op = op_t_get_clink(py_op); + uint64 v; + return ( op == NULL || !PyW_GetNumber(py_v, &v) || !add_stkvar3(*op, sval_t(v), flags)) ? false : true; +} + +//------------------------------------------------------------------------- +/* +# +def get_stkvar(op, v): + """ + Get pointer to stack variable + @param op: reference to instruction operand + @param v: immediate value in the operand (usually op.addr) + @return: + - None on failure + - tuple(member_t, actval) + where actval: actual value used to fetch stack variable + """ + pass +# +*/ +PyObject *py_get_stkvar(PyObject *py_op, PyObject *py_v) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + op_t *op = op_t_get_clink(py_op); + uint64 v; + if ( op == NULL || !PyW_GetNumber(py_v, &v) ) + Py_RETURN_NONE; + + sval_t actval; + member_t *member = get_stkvar(*op, sval_t(v), &actval); + if ( member == NULL ) + Py_RETURN_NONE; + + return Py_BuildValue("(O" PY_SFMT64 ")", + SWIG_NewPointerObj(SWIG_as_voidptr(member), SWIGTYPE_p_member_t, 0), + pyl_t(actval)); +} +// diff --git a/pywraps/py_gdl.py b/pywraps/py_gdl.py index 32604ec..f503ef9 100755 --- a/pywraps/py_gdl.py +++ b/pywraps/py_gdl.py @@ -1,4 +1,6 @@ # +import _ida_idaapi +import types # ----------------------------------------------------------------------- class BasicBlock(object): """Basic block class. It is returned by the Flowchart class""" @@ -52,7 +54,7 @@ class FlowChart(object): raise Exception("Please specifiy either a function or start/end pair") if bounds is None: - bounds = (BADADDR, BADADDR) + bounds = (_ida_idaapi.BADADDR, _ida_idaapi.BADADDR) # Create the flowchart self._q = qflow_chart_t("", f, bounds[0], bounds[1], flags) @@ -61,7 +63,7 @@ class FlowChart(object): """Number of blocks in the flow chart""" - def refresh(): + def refresh(self): """Refreshes the flow chart""" self._q.refresh() diff --git a/pywraps/py_graph.hpp b/pywraps/py_graph.hpp index c608bc3..43d3b9b 100644 --- a/pywraps/py_graph.hpp +++ b/pywraps/py_graph.hpp @@ -7,7 +7,7 @@ class py_graph_t : public py_customidamemo_t typedef py_customidamemo_t inherited; protected: - void collect_class_callbacks_ids(callbacks_ids_t *out); + void collect_class_callbacks_ids(pycim_callbacks_ids_t *out); private: enum @@ -74,7 +74,7 @@ private: void clear(py_graph_t *pyg) { iterator e = end(); - for ( iterator it=begin(); it!=end(); ) + for ( iterator it=begin(); it != end(); ) { if ( it->second == pyg ) { @@ -104,7 +104,7 @@ private: // static callback static int idaapi s_callback(void *obj, int code, va_list va) { - QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj)); + QASSERT(30453, pycim_lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj)); PYW_GIL_GET; return ((py_graph_t *)obj)->gr_callback(code, va); } @@ -288,7 +288,7 @@ private: void show() { TForm *form; - if ( lookup_info.find_by_py_view(&form, NULL, this) ) + if ( pycim_lookup_info.find_by_py_view(&form, NULL, this) ) open_tform(form, FORM_TAB|FORM_MENU|FORM_QWIDGET); } @@ -330,7 +330,7 @@ private: TForm *form = create_tform(title, &hwnd); if ( hwnd != NULL ) // Created new tform { - lookup_info_t::entry_t &e = lookup_info.new_entry(this); + lookup_entry_t &e = pycim_lookup_info.new_entry(this); // get a unique graph id netnode id; char grnode[MAXSTR]; @@ -345,7 +345,7 @@ private: viewer_fit_window(pview); bind(self, pview); install_custom_viewer_handlers(); - lookup_info.commit(e, form, view); + pycim_lookup_info.commit(e, form, view); } else { @@ -387,7 +387,7 @@ public: return; py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) ) + if ( _this == NULL || !pycim_lookup_info.find_by_py_view(NULL, NULL, _this) ) return; _this->jump_to_node(nid); @@ -396,7 +396,7 @@ public: static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey) { py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) ) + if ( _this == NULL || !pycim_lookup_info.find_by_py_view(NULL, NULL, _this) ) return 0; return _this->add_command(title, hotkey); @@ -406,7 +406,7 @@ public: { TForm *form; py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !lookup_info.find_by_py_view(&form, NULL, _this) ) + if ( _this == NULL || !pycim_lookup_info.find_by_py_view(&form, NULL, _this) ) return; close_tform(form, FORM_CLOSE_LATER); } @@ -429,7 +429,7 @@ public: graph_viewer_t *found_view; TForm *form = find_tform(title.c_str()); if ( form != NULL ) - lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_graph, form); + pycim_lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_graph, form); if ( py_graph == NULL ) { @@ -456,7 +456,7 @@ public: }; //------------------------------------------------------------------------- -void py_graph_t::collect_class_callbacks_ids(callbacks_ids_t *out) +void py_graph_t::collect_class_callbacks_ids(pycim_callbacks_ids_t *out) { inherited::collect_class_callbacks_ids(out); out->add(S_ON_REFRESH, 0); @@ -507,7 +507,7 @@ void py_graph_t::on_user_refresh(mutable_graph_t *g) node_cache.clear(); // Get the edges - for ( int i=(int)PyList_Size(edges.o)-1; i>=0; i-- ) + for ( int i=(int)PyList_Size(edges.o)-1; i >= 0; i-- ) { // Each list item is a sequence (id1, id2) borref_t item(PyList_GetItem(edges.o, i)); @@ -517,7 +517,7 @@ void py_graph_t::on_user_refresh(mutable_graph_t *g) // Get and validate each of the two elements in the sequence int edge_ids[2]; int j; - for ( j=0; j -class GraphViewer(CustomIDAMemo): +import ida_idaapi +class GraphViewer(ida_idaapi.CustomIDAMemo): """This class wraps the user graphing facility provided by the graph.hpp file""" def __init__(self, title, close_open = False): """ @@ -50,7 +51,7 @@ class GraphViewer(CustomIDAMemo): Closes the graph. It is possible to call Show() again (which will recreate the graph) """ - _idaapi.pyg_close(self) + _ida_graph.pyg_close(self) def Show(self): """ @@ -59,14 +60,14 @@ class GraphViewer(CustomIDAMemo): @return: Boolean """ if self._close_open: - frm = _idaapi.find_tform(self._title) + frm = _ida_kernwin.find_tform(self._title) if frm: - _idaapi.close_tform(frm, 0) - return _idaapi.pyg_show(self) + _ida_kernwin.close_tform(frm, 0) + return _ida_graph.pyg_show(self) def Select(self, node_id): """Selects a node on the graph""" - _idaapi.pyg_select_node(self, node_id) + _ida_graph.pyg_select_node(self, node_id) def AddCommand(self, title, hotkey): """ @@ -74,7 +75,7 @@ class GraphViewer(CustomIDAMemo): - register_action() - attach_action_to_popup() """ - return _idaapi.pyg_add_command(self, title, hotkey) + return _ida_graph.pyg_add_command(self, title, hotkey) def OnRefresh(self): """ diff --git a/pywraps/py_hexrays.hpp b/pywraps/py_hexrays.hpp new file mode 100644 index 0000000..719c018 --- /dev/null +++ b/pywraps/py_hexrays.hpp @@ -0,0 +1,439 @@ +//------------------------------------------------------------------------- +// +#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); +// diff --git a/pywraps/py_hexrays.py b/pywraps/py_hexrays.py new file mode 100644 index 0000000..3f32205 --- /dev/null +++ b/pywraps/py_hexrays.py @@ -0,0 +1,419 @@ +# ----------------------------------------------------------------------- +# +import ida_funcs + +hexrays_failure_t.__str__ = lambda self: str(self.str) + +# --------------------------------------------------------------------- +class DecompilationFailure(Exception): + """ Raised on a decompilation error. + + The associated hexrays_failure_t object is stored in the + 'info' member of this exception. """ + + def __init__(self, info): + Exception.__init__(self, 'Decompilation failed: %s' % (str(info), )) + self.info = info + return + +# --------------------------------------------------------------------- +def decompile(ea, hf=None): + if isinstance(ea, (int, long)): + func = ida_funcs.get_func(ea) + if not func: return + elif type(ea) == ida_funcs.func_t: + func = ea + else: + raise RuntimeError('arg 1 of decompile expects either ea_t or cfunc_t argument') + + if hf is None: + hf = hexrays_failure_t() + + ptr = _decompile(func, hf) + + if ptr.__deref__() is None: + raise DecompilationFailure(hf) + + return ptr + +# --------------------------------------------------------------------- +# stringify all string types +#qtype.__str__ = qtype.c_str +#qstring.__str__ = qstring.c_str +#citem_cmt_t.__str__ = citem_cmt_t.c_str + +# --------------------------------------------------------------------- +# listify all list types +import ida_idaapi +ida_idaapi._listify_types( + cinsnptrvec_t, + ctree_items_t, + qvector_lvar_t, + qvector_carg_t, + qvector_ccase_t, + hexwarns_t, + history_t, + lvar_saved_infos_t) + +def citem_to_specific_type(self): + """ cast the citem_t object to its more specific type, either cexpr_t or cinsn_t. """ + + if self.op >= cot_empty and self.op <= cot_last: + return self.cexpr + elif self.op >= cit_empty and self.op < cit_end: + return self.cinsn + + raise RuntimeError('unknown op type %s' % (repr(self.op), )) +citem_t.to_specific_type = property(citem_to_specific_type) + +""" array used for translating cinsn_t->op type to their names. """ +cinsn_t.op_to_typename = {} +for k in dir(_ida_hexrays): + if k.startswith('cit_'): + cinsn_t.op_to_typename[getattr(_ida_hexrays, k)] = k[4:] + +""" array used for translating cexpr_t->op type to their names. """ +cexpr_t.op_to_typename = {} +for k in dir(_ida_hexrays): + if k.startswith('cot_'): + cexpr_t.op_to_typename[getattr(_ida_hexrays, k)] = k[4:] + +def property_op_to_typename(self): + return self.op_to_typename[self.op] +cinsn_t.opname = property(property_op_to_typename) +cexpr_t.opname = property(property_op_to_typename) + +def cexpr_operands(self): + """ return a dictionary with the operands of a cexpr_t. """ + + if self.op >= cot_comma and self.op <= cot_asgumod or \ + self.op >= cot_lor and self.op <= cot_fdiv or \ + self.op == cot_idx: + return {'x': self.x, 'y': self.y} + + elif self.op == cot_tern: + return {'x': self.x, 'y': self.y, 'z': self.z} + + elif self.op in [cot_fneg, cot_neg, cot_sizeof] or \ + self.op >= cot_lnot and self.op <= cot_predec: + return {'x': self.x} + + elif self.op == cot_cast: + return {'type': self.type, 'x': self.x} + + elif self.op == cot_call: + return {'x': self.x, 'a': self.a} + + elif self.op in [cot_memref, cot_memptr]: + return {'x': self.x, 'm': self.m} + + elif self.op == cot_num: + return {'n': self.n} + + elif self.op == cot_fnum: + return {'fpc': self.fpc} + + elif self.op == cot_str: + return {'string': self.string} + + elif self.op == cot_obj: + return {'obj_ea': self.obj_ea} + + elif self.op == cot_var: + return {'v': self.v} + + elif self.op == cot_helper: + return {'helper': self.helper} + + raise RuntimeError('unknown op type %s' % self.opname) +cexpr_t.operands = property(cexpr_operands) + +def cinsn_details(self): + """ return the details pointer for the cinsn_t object depending on the value of its op member. \ + this is one of the cblock_t, cif_t, etc. objects. """ + + if self.op not in self.op_to_typename: + raise RuntimeError('unknown item->op type') + + opname = self.opname + if opname == 'empty': + return self + + if opname in ['break', 'continue']: + return None + + return getattr(self, 'c' + opname) +cinsn_t.details = property(cinsn_details) + +def cblock_iter(self): + + iter = self.begin() + for i in range(self.size()): + yield iter.cur + iter.next() + + return +cblock_t.__iter__ = cblock_iter +cblock_t.__len__ = cblock_t.size + +# cblock.find(cinsn_t) -> returns the iterator positioned at the given item +def cblock_find(self, item): + + iter = self.begin() + for i in range(self.size()): + if iter.cur == item: + return iter + iter.next() + + return +cblock_t.find = cblock_find + +# cblock.index(cinsn_t) -> returns the index of the given item +def cblock_index(self, item): + + iter = self.begin() + for i in range(self.size()): + if iter.cur == item: + return i + iter.next() + + return +cblock_t.index = cblock_index + +# cblock.at(int) -> returns the item at the given index index +def cblock_at(self, index): + + iter = self.begin() + for i in range(self.size()): + if i == index: + return iter.cur + iter.next() + + return +cblock_t.at = cblock_at + +# cblock.remove(cinsn_t) +def cblock_remove(self, item): + + iter = self.find(item) + self.erase(iter) + + return +cblock_t.remove = cblock_remove + +# cblock.insert(index, cinsn_t) +def cblock_insert(self, index, item): + + pos = self.at(index) + iter = self.find(pos) + self.insert(iter, item) + + return +cblock_t.insert = cblock_insert + +cfuncptr_t.__str__ = lambda self: str(self.__deref__()) + +import ida_typeinf +def cfunc_type(self): + """ Get the function's return type tinfo_t object. """ + tif = ida_typeinf.tinfo_t() + result = self.get_func_type(tif) + if not result: + return + return tif +cfunc_t.type = property(cfunc_type) +cfuncptr_t.type = property(lambda self: self.__deref__().type) + +cfunc_t.arguments = property(lambda self: [o for o in self.lvars if o.is_arg_var]) +cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments) + +cfunc_t.lvars = property(cfunc_t.get_lvars) +cfuncptr_t.lvars = property(lambda self: self.__deref__().lvars) +cfunc_t.warnings = property(cfunc_t.get_warnings) +cfuncptr_t.warnings = property(lambda self: self.__deref__().warnings) +cfunc_t.pseudocode = property(cfunc_t.get_pseudocode) +cfuncptr_t.pseudocode = property(lambda self: self.__deref__().get_pseudocode()) +cfunc_t.eamap = property(cfunc_t.get_eamap) +cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap()) +cfunc_t.boundaries = property(cfunc_t.get_boundaries) +cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries()) + +#pragma SWIG nowarn=+503 + +lvar_t.used = property(lvar_t.used) +lvar_t.typed = property(lvar_t.typed) +lvar_t.mreg_done = property(lvar_t.mreg_done) +lvar_t.has_nice_name = property(lvar_t.has_nice_name) +lvar_t.is_unknown_width = property(lvar_t.is_unknown_width) +lvar_t.has_user_info = property(lvar_t.has_user_info) +lvar_t.has_user_name = property(lvar_t.has_user_name) +lvar_t.has_user_type = property(lvar_t.has_user_type) +lvar_t.is_result_var = property(lvar_t.is_result_var) +lvar_t.is_arg_var = property(lvar_t.is_arg_var) +lvar_t.is_fake_var = property(lvar_t.is_fake_var) +lvar_t.is_overlapped_var = property(lvar_t.is_overlapped_var) +lvar_t.is_floating_var = property(lvar_t.is_floating_var) +lvar_t.is_spoiled_var = property(lvar_t.is_spoiled_var) +lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var) + +# dictify all dict-like types + +def _map___getitem__(self, key): + """ Returns the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of key should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + return self.second(self.find(key)) + +def _map___setitem__(self, key, value): + """ Returns the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if not isinstance(value, self.valuetype): + raise KeyError('type of `value` should be ' + repr(self.valuetype) + ' but got ' + type(value)) + self.insert(key, value) + return + +def _map___delitem__(self, key): + """ Removes the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + self.erase(self.find(key)) + return + +def _map___contains__(self, key): + """ Returns true if the specified key exists in the . """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if self.find(key) != self.end(): + return True + return False + +def _map_clear(self): + self.clear() + return + +def _map_copy(self): + ret = {} + for k in self.iterkeys(): + ret[k] = self[k] + return ret + +def _map_get(self, key, default=None): + if key in self: + return self[key] + return default + +def _map_iterkeys(self): + iter = self.begin() + while iter != self.end(): + yield self.first(iter) + iter = self.next(iter) + return + +def _map_itervalues(self): + iter = self.begin() + while iter != self.end(): + yield self.second(iter) + iter = self.next(iter) + return + +def _map_iteritems(self): + iter = self.begin() + while iter != self.end(): + yield (self.first(iter), self.second(iter)) + iter = self.next(iter) + return + +def _map_keys(self): + return list(self.iterkeys()) + +def _map_values(self): + return list(self.itervalues()) + +def _map_items(self): + return list(self.iteritems()) + +def _map_has_key(self, key): + return key in self + +def _map_pop(self, key): + """ Sets the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + ret = self[key] + del self[key] + return ret + +def _map_popitem(self): + """ Sets the value associated with the provided key. """ + if len(self) == 0: + raise KeyError('key not found') + key = self.keys()[0] + return (key, self.pop(key)) + +def _map_setdefault(self, key, default=None): + """ Sets the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key in self: + return self[key] + self[key] = default + return default + +def _map_as_dict(maptype, name, keytype, valuetype): + + maptype.keytype = keytype + maptype.valuetype = valuetype + + for fctname in ['begin', 'end', 'first', 'second', 'next', \ + 'find', 'insert', 'erase', 'clear', 'size']: + fct = getattr(_ida_hexrays, name + '_' + fctname) + setattr(maptype, '__' + fctname, fct) + + maptype.__len__ = maptype.size + maptype.__getitem__ = maptype.at + + maptype.begin = lambda self, *args: self.__begin(self, *args) + maptype.end = lambda self, *args: self.__end(self, *args) + maptype.first = lambda self, *args: self.__first(*args) + maptype.second = lambda self, *args: self.__second(*args) + maptype.next = lambda self, *args: self.__next(*args) + maptype.find = lambda self, *args: self.__find(self, *args) + maptype.insert = lambda self, *args: self.__insert(self, *args) + maptype.erase = lambda self, *args: self.__erase(self, *args) + maptype.clear = lambda self, *args: self.__clear(self, *args) + maptype.size = lambda self, *args: self.__size(self, *args) + maptype.__getitem__ = _map___getitem__ + maptype.__setitem__ = _map___setitem__ + maptype.__delitem__ = _map___delitem__ + maptype.__contains__ = _map___contains__ + maptype.clear = _map_clear + maptype.copy = _map_copy + maptype.get = _map_get + maptype.iterkeys = _map_iterkeys + maptype.itervalues = _map_itervalues + maptype.iteritems = _map_iteritems + maptype.keys = _map_keys + maptype.values = _map_values + maptype.items = _map_items + maptype.has_key = _map_has_key + maptype.pop = _map_pop + maptype.popitem = _map_popitem + maptype.setdefault = _map_setdefault + +#_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring) +_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t) +_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t) +_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, (int, long)) +import ida_pro +_map_as_dict(user_unions_t, 'user_unions', (int, long), ida_pro.intvec_t) +_map_as_dict(eamap_t, 'eamap', long, cinsnptrvec_t) +#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t) + +# diff --git a/pywraps/py_idaapi.hpp b/pywraps/py_idaapi.hpp index f3cf3fa..6ac3971 100644 --- a/pywraps/py_idaapi.hpp +++ b/pywraps/py_idaapi.hpp @@ -2,1639 +2,122 @@ #define __PY_IDAAPI__ // - -//------------------------------------------------------------------------ -// String constants used -static const char S_PY_IDCCVT_VALUE_ATTR[] = "__idc_cvt_value__"; -static const char S_PY_IDCCVT_ID_ATTR[] = "__idc_cvt_id__"; -static const char S_PY_IDC_OPAQUE_T[] = "py_idc_cvt_helper_t"; -static const char S_PY_IDC_GLOBAL_VAR_FMT[] = "__py_cvt_gvar_%d"; - -// Constants used by get_idaapi_class_reference() -#define PY_CLSID_CVT_INT64 0 -#define PY_CLSID_APPCALL_SKEL_OBJ 1 -#define PY_CLSID_CVT_BYREF 2 -#define PY_CLSID_LAST 3 - -//--------------------------------------------------------------------------- -// Use these macros to define script<->C fields -#define DEFINE_SCFIELDX(name, type, is_opt) { #name, type, qoffsetof(CUR_STRUC, name), is_opt } -#define DEFINE_SCFIELD(name, type) DEFINE_SCFIELDX(name, type, 0) -#define DEFINE_SCFIELD_OPT(name, type) DEFINE_SCFIELDX(name, type, 1) - -//--------------------------------------------------------------------------- -enum scfield_types_t -{ - // Numeric fields - FT_FIRST_NUM, - FT_INT, - FT_SIZET, - FT_SSIZET, - FT_NUM16, - FT_NUM32, - FT_LAST_NUM, - // String field - FT_STR, - FT_CHAR, - // Object fields - FT_ARR, - // Allocated array of strings - FT_STRARR, - // Allocated array of 16bit numbers - FT_NUM16ARR, - // Fixed size character array. The size must be passed in the definition - FT_CHRARR_STATIC, -}; - -//--------------------------------------------------------------------------- -struct scfld_t -{ - const char *field_name; - uint32 field_type; - size_t field_offs; - bool is_optional; -}; - -#define FT_VALUE_MASK 0xFFFF0000 -// Possible return values of conversion functions -#define FT_NOT_FOUND -1 -#define FT_BAD_TYPE -2 -#define FT_OK 1 - //------------------------------------------------------------------------- -Py_ssize_t pyvar_walk_list( - const ref_t &py_list, - int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud), - void *ud) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - Py_ssize_t size = CIP_FAILED; - do - { - PyObject *o = py_list.o; - if ( !PyList_CheckExact(o) && !PyW_IsSequenceType(o) ) - break; - - bool is_seq = !PyList_CheckExact(o); - size = is_seq ? PySequence_Size(o) : PyList_Size(o); - if ( cb == NULL ) - break; - - Py_ssize_t i; - for ( i=0; i= CIP_OK; - if ( !ok ) - PyErr_SetString(PyExc_ValueError, "Could not convert Python object to IDC object!"); - return ok; -} - -//------------------------------------------------------------------------ -static idc_class_t *get_py_idc_cvt_opaque() -{ - return find_idc_class(S_PY_IDC_OPAQUE_T); -} - -//------------------------------------------------------------------------- -// Utility function to create opaque / convertible Python <-> IDC variables -// The referred Python variable will have its reference increased -static bool wrap_PyObject_ptr(const ref_t &py_var, idc_value_t *idc_var) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Create an IDC object of this special helper class - if ( VarObject(idc_var, get_py_idc_cvt_opaque()) != eOk ) - return false; - - // Store the CVT id - idc_value_t idc_val; - idc_val.set_long(PY_ICID_OPAQUE); - VarSetAttr(idc_var, S_PY_IDCCVT_ID_ATTR, &idc_val); - - // Store the value as a PVOID referencing the given Python object - py_var.incref(); - idc_val.set_pvoid(py_var.o); - VarSetAttr(idc_var, S_PY_IDCCVT_VALUE_ATTR, &idc_val); - - return true; -} - -//------------------------------------------------------------------------ -// IDC Opaque object destructor: when the IDC object dies we kill the -// opaque Python object along with it -static const char py_idc_cvt_helper_dtor_args[] = { VT_OBJ, 0 }; -static error_t idaapi py_idc_opaque_dtor( - idc_value_t *argv, - idc_value_t * /*res*/) -{ - // This can be called at plugin registration time, when a - // 'script_plugin_t' instance is ::free()'d. It is - // not guaranteed that we have the GIL at that point. - PYW_GIL_GET; - - // Get the value from the object - idc_value_t idc_val; - VarGetAttr(&argv[0], S_PY_IDCCVT_VALUE_ATTR, &idc_val); - - // Extract the Python object reference - PyObject *py_obj = (PyObject *)idc_val.pvoid; - - // Decrease its reference (and eventually destroy it) - Py_DECREF(py_obj); - - return eOk; -} - -//------------------------------------------------------------------------- -// Converts a Python variable into an IDC variable -// This function returns on one CIP_XXXX -int pyvar_to_idcvar( - const ref_t &py_var, - idc_value_t *idc_var, - int *gvar_sn) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // None / NULL - if ( py_var == NULL || py_var.o == Py_None ) - { - idc_var->set_long(0); - } - // Numbers? - else if ( PyW_GetNumberAsIDC(py_var.o, idc_var) ) - { - return CIP_OK; - } - // String - else if ( PyString_Check(py_var.o) ) - { - idc_var->_set_string(PyString_AsString(py_var.o), PyString_Size(py_var.o)); - } - // Boolean - else if ( PyBool_Check(py_var.o) ) - { - idc_var->set_long(py_var.o == Py_True ? 1 : 0); - } - // Float - else if ( PyFloat_Check(py_var.o) ) - { - double dresult = PyFloat_AsDouble(py_var.o); - ieee_realcvt((void *)&dresult, idc_var->e, 3); - idc_var->vtype = VT_FLOAT; - } - // void* - else if ( PyCObject_Check(py_var.o) ) - { - idc_var->set_pvoid(PyCObject_AsVoidPtr(py_var.o)); - } - // Python list? - else if ( PyList_CheckExact(py_var.o) || PyW_IsSequenceType(py_var.o) ) - { - // Create the object - VarObject(idc_var); - - // Determine list size and type - bool is_seq = !PyList_CheckExact(py_var.o); - Py_ssize_t size = is_seq ? PySequence_Size(py_var.o) : PyList_Size(py_var.o); - bool ok = true; - qstring attr_name; - - // Convert each item - for ( Py_ssize_t i=0; i= CIP_OK; - if ( ok ) - { - // Form the attribute name - newref_t py_int(PyInt_FromSsize_t(i)); - ok = PyW_ObjectToString(py_int.o, &attr_name); - if ( !ok ) - break; - // Store the attribute - VarSetAttr(idc_var, attr_name.c_str(), &v); - } - if ( !ok ) - break; - } - return ok ? CIP_OK : CIP_FAILED; - } - // Dictionary: we convert to an IDC object - else if ( PyDict_Check(py_var.o) ) - { - // Create an empty IDC object - VarObject(idc_var); - - // Get the dict.items() list - newref_t py_items(PyDict_Items(py_var.o)); - - // Get the size of the list - qstring key_name; - bool ok = true; - Py_ssize_t size = PySequence_Size(py_items.o); - for ( Py_ssize_t i=0; i (key, value) - PyObject *py_item = PyList_GetItem(py_items.o, i); - - // Extract key/value - newref_t key(PySequence_GetItem(py_item, 0)); - newref_t val(PySequence_GetItem(py_item, 1)); - - // Get key's string representation - PyW_ObjectToString(key.o, &key_name); - - // Convert the attribute into an IDC value - idc_value_t v; - ok = pyvar_to_idcvar(val, &v, gvar_sn) >= CIP_OK; - if ( ok ) - { - // Store the attribute - VarSetAttr(idc_var, key_name.c_str(), &v); - } - if ( !ok ) - break; - } - return ok ? CIP_OK : CIP_FAILED; - } - // Possible function? - else if ( PyCallable_Check(py_var.o) ) - { - idc_var->clear(); - idc_var->vtype = VT_FUNC; - idc_var->funcidx = -1; // Does not apply - return CIP_OK; - } - // Objects: - // - pyidc_cvt objects: int64, byref, opaque - // - other python objects - else - { - // Get the type - int cvt_id = get_pyidc_cvt_type(py_var.o); - switch ( cvt_id ) - { - // - // INT64 - // - case PY_ICID_INT64: - { - // Get the value attribute - ref_t attr(PyW_TryGetAttrString(py_var.o, S_PY_IDCCVT_VALUE_ATTR)); - if ( attr == NULL ) - return false; - idc_var->set_int64(PyLong_AsLongLong(attr.o)); - return CIP_OK; - } - // - // BYREF - // - case PY_ICID_BYREF: - { - // BYREF always require this parameter - if ( gvar_sn == NULL ) - return CIP_FAILED; - - // Get the value attribute - ref_t attr(PyW_TryGetAttrString(py_var.o, S_PY_IDCCVT_VALUE_ATTR)); - if ( attr == NULL ) - return CIP_FAILED; - - // Create a global variable - char buf[MAXSTR]; - qsnprintf(buf, sizeof(buf), S_PY_IDC_GLOBAL_VAR_FMT, *gvar_sn); - idc_value_t *gvar = add_idc_gvar(buf); - // Convert the python value into the IDC global variable - bool ok = pyvar_to_idcvar(attr, gvar, gvar_sn) >= CIP_OK; - if ( ok ) - { - (*gvar_sn)++; - // Create a reference to this global variable - VarRef(idc_var, gvar); - } - return ok ? CIP_OK : CIP_FAILED; - } - // - // OPAQUE - // - case PY_ICID_OPAQUE: - { - if ( !wrap_PyObject_ptr(py_var, idc_var) ) - return CIP_FAILED; - return CIP_OK_OPAQUE; - } - // - // Other objects - // - default: - // A normal object? - newref_t py_dir(PyObject_Dir(py_var.o)); - Py_ssize_t size = PyList_Size(py_dir.o); - if ( py_dir == NULL || !PyList_Check(py_dir.o) || size == 0 ) - return CIP_FAILED; - // Create the IDC object - VarObject(idc_var); - for ( Py_ssize_t i=0; i 2 ) - && (strncmp(field_name, "__", 2) == 0 ) - && (strncmp(field_name+len-2, "__", 2) == 0) ) - { - continue; - } - - idc_value_t v; - // Get the non-private attribute from the object - newref_t attr(PyObject_GetAttrString(py_var.o, field_name)); - if ( attr == NULL - // Convert the attribute into an IDC value - || pyvar_to_idcvar(attr, &v, gvar_sn) < CIP_OK ) - { - return CIP_FAILED; - } - - // Store the attribute - VarSetAttr(idc_var, field_name, &v); - } - } - } - return CIP_OK; -} - -//------------------------------------------------------------------------- -inline PyObject *cvt_to_pylong(int32 v) -{ - return PyLong_FromLong(v); -} - -inline PyObject *cvt_to_pylong(int64 v) -{ - return PyLong_FromLongLong(v); -} - -//------------------------------------------------------------------------- -// Converts an IDC variable to a Python variable -// If py_var points to an existing object then the object will be updated -// If py_var points to an existing immutable object then ZERO is returned -// Returns one of CIP_xxxx. Check pywraps.hpp -int idcvar_to_pyvar( - const idc_value_t &idc_var, - ref_t *py_var) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - switch ( idc_var.vtype ) - { - case VT_PVOID: - if ( *py_var == NULL ) - { - newref_t nr(PyCObject_FromVoidPtr(idc_var.pvoid, NULL)); - *py_var = nr; - } - else - { - return CIP_IMMUTABLE; - } - break; - - case VT_INT64: - { - // Recycle? - if ( *py_var != NULL ) - { - // Recycling an int64 object? - int t = get_pyidc_cvt_type(py_var->o); - if ( t != PY_ICID_INT64 ) - return CIP_IMMUTABLE; // Cannot recycle immutable object - // Update the attribute - PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64)); - return CIP_OK; - } - ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_INT64)); - if ( py_cls == NULL ) - return CIP_FAILED; - *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, PyLong_FromLongLong(idc_var.i64), NULL)); - if ( PyW_GetError() || *py_var == NULL ) - return CIP_FAILED; - break; - } - -#if !defined(NO_OBSOLETE_FUNCS) || defined(__EXPR_SRC) - case VT_STR: - *py_var = newref_t(PyString_FromString(idc_var.str)); - break; - -#endif - case VT_STR2: - if ( *py_var == NULL ) - { - const qstring &s = idc_var.qstr(); - *py_var = newref_t(PyString_FromStringAndSize(s.begin(), s.length())); - break; - } - else - return CIP_IMMUTABLE; // Cannot recycle immutable object - case VT_LONG: - // Cannot recycle immutable objects - if ( *py_var != NULL ) - return CIP_IMMUTABLE; - *py_var = newref_t(cvt_to_pylong(idc_var.num)); - break; - case VT_FLOAT: - if ( *py_var == NULL ) - { - double x; - if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 ) - INTERR(30160); - - *py_var = newref_t(PyFloat_FromDouble(x)); - break; - } - else - return CIP_IMMUTABLE; - - case VT_REF: - { - if ( *py_var == NULL ) - { - ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_BYREF)); - if ( py_cls == NULL ) - return CIP_FAILED; - - // Create a byref object with None value. We populate it later - *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, Py_None, NULL)); - if ( PyW_GetError() || *py_var == NULL ) - return CIP_FAILED; - } - int t = get_pyidc_cvt_type(py_var->o); - if ( t != PY_ICID_BYREF ) - return CIP_FAILED; - - // Dereference - // (Since we are not using VREF_COPY flag, we can safely const_cast) - idc_value_t *dref_v = VarDeref(const_cast(&idc_var), VREF_LOOP); - if ( dref_v == NULL ) - return CIP_FAILED; - - // Can we recycle the object? - ref_t new_py_val(PyW_TryGetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR)); - if ( new_py_val != NULL ) - { - // Recycle - t = idcvar_to_pyvar(*dref_v, &new_py_val); - - // Success? Nothing more to be done - if ( t == CIP_OK ) - return CIP_OK; - - // Clear it so we don't recycle it - new_py_val = ref_t(); - } - // Try to convert (not recycle) - if ( idcvar_to_pyvar(*dref_v, &new_py_val) != CIP_OK ) - return CIP_FAILED; - - // Update the attribute - PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, new_py_val.o); - break; - } - - // Can convert back into a Python object or Python dictionary - // (Depending if py_var will be recycled and it was a dictionary) - case VT_OBJ: - { - // Check if this IDC object has __cvt_id__ and the __idc_cvt_value__ fields - idc_value_t idc_val; - if ( VarGetAttr(&idc_var, S_PY_IDCCVT_ID_ATTR, &idc_val) == eOk - && VarGetAttr(&idc_var, S_PY_IDCCVT_VALUE_ATTR, &idc_val) == eOk ) - { - // Extract the object - *py_var = borref_t((PyObject *) idc_val.pvoid); - return CIP_OK_OPAQUE; - } - ref_t obj; - bool is_dict = false; - - // Need to create a new object? - if ( *py_var == NULL ) - { - // Get skeleton class reference - ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_APPCALL_SKEL_OBJ)); - if ( py_cls == NULL ) - return CIP_FAILED; - - // Call constructor - obj = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, NULL)); - if ( PyW_GetError() || obj == NULL ) - return CIP_FAILED; - } - else - { - // Recycle existing variable - obj = *py_var; - if ( PyDict_Check(obj.o) ) - is_dict = true; - } - - // Walk the IDC attributes and store into python - for ( const char *attr_name = VarFirstAttr(&idc_var); - attr_name != NULL; - attr_name = VarNextAttr(&idc_var, attr_name) ) - { - // Get the attribute - idc_value_t v; - VarGetAttr(&idc_var, attr_name, &v, true); - - // Convert attribute to a python value (recursively) - ref_t py_attr; - int cvt = idcvar_to_pyvar(v, &py_attr); - if ( cvt <= CIP_IMMUTABLE ) - return CIP_FAILED; - if ( is_dict ) - PyDict_SetItemString(obj.o, attr_name, py_attr.o); - else - PyObject_SetAttrString(obj.o, attr_name, py_attr.o); - } - *py_var = obj; - break; - } - // Unhandled type - default: - *py_var = ref_t(); - return CIP_FAILED; - } - return CIP_OK; -} - -//------------------------------------------------------------------------- -// Converts IDC arguments to Python argument list or just one tuple -// If 'decref' is NULL then 'pargs' will contain one element which is the tuple -bool pyw_convert_idc_args( - const idc_value_t args[], - int nargs, - ref_vec_t &pargs, - bool as_tupple, - char *errbuf, - size_t errbufsize) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - ref_t py_tuple; - - pargs.qclear(); - - if ( as_tupple ) - { - py_tuple = newref_t(PyTuple_New(nargs)); - if ( py_tuple == NULL ) - { - if ( errbuf != 0 && errbufsize > 0 ) - qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize); - return false; - } - } - - for ( int i=0; i 0 ) - qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype); - return false; - } - - if ( as_tupple ) - { - // PyTuple_SetItem() steals the reference. - py_obj.incref(); - QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0); - } - else - { - pargs.push_back(py_obj); - } - } - - // Add the tuple to the list of args only now. Doing so earlier will - // cause the py_tuple.o->ob_refcnt to be 2 and not 1, and that will - // cause 'PyTuple_SetItem()' to fail. - if ( as_tupple ) - pargs.push_back(py_tuple); - - return true; -} - -//------------------------------------------------------------------------ -// String constants used -static const char S_PYINVOKE0[] = "_py_invoke0"; -static const char S_PY_SWIEX_CLSNAME[] = "switch_info_ex_t"; -static const char S_PY_OP_T_CLSNAME[] = "op_t"; -static const char S_PROPS[] = "props"; -static const char S_NAME[] = "name"; -static const char S_TITLE[] = "title"; -static const char S_ASM_KEYWORD[] = "asm_keyword"; -static const char S_MENU_NAME[] = "menu_name"; -static const char S_HOTKEY[] = "hotkey"; -static const char S_EMBEDDED[] = "embedded"; -static const char S_POPUP_NAMES[] = "popup_names"; -static const char S_FLAGS[] = "flags"; -static const char S_VALUE_SIZE[] = "value_size"; -static const char S_MAY_CREATE_AT[] = "may_create_at"; -static const char S_CALC_ITEM_SIZE[] = "calc_item_size"; -static const char S_ID[] = "id"; -static const char S_PRINTF[] = "printf"; -static const char S_TEXT_WIDTH[] = "text_width"; -static const char S_SCAN[] = "scan"; -static const char S_ANALYZE[] = "analyze"; -static const char S_CBSIZE[] = "cbsize"; -static const char S_ON_CLICK[] = "OnClick"; -static const char S_ON_CLOSE[] = "OnClose"; -static const char S_ON_DBL_CLICK[] = "OnDblClick"; -static const char S_ON_CURSOR_POS_CHANGED[] = "OnCursorPosChanged"; -static const char S_ON_KEYDOWN[] = "OnKeydown"; -static const char S_ON_COMPLETE_LINE[] = "OnCompleteLine"; -static const char S_ON_CREATE[] = "OnCreate"; -static const char S_ON_POPUP[] = "OnPopup"; -static const char S_ON_HINT[] = "OnHint"; -static const char S_ON_POPUP_MENU[] = "OnPopupMenu"; -static const char S_ON_EDIT_LINE[] = "OnEditLine"; -static const char S_ON_INSERT_LINE[] = "OnInsertLine"; -static const char S_ON_GET_LINE[] = "OnGetLine"; -static const char S_ON_DELETE_LINE[] = "OnDeleteLine"; -static const char S_ON_REFRESH[] = "OnRefresh"; -static const char S_ON_REFRESHED[] = "OnRefreshed"; -static const char S_ON_EXECUTE_LINE[] = "OnExecuteLine"; -static const char S_ON_SELECT_LINE[] = "OnSelectLine"; -static const char S_ON_SELECTION_CHANGE[] = "OnSelectionChange"; -static const char S_ON_COMMAND[] = "OnCommand"; -static const char S_ON_GET_ICON[] = "OnGetIcon"; -static const char S_ON_GET_LINE_ATTR[] = "OnGetLineAttr"; -static const char S_ON_GET_SIZE[] = "OnGetSize"; -static const char S_ON_GETTEXT[] = "OnGetText"; -static const char S_ON_ACTIVATE[] = "OnActivate"; -static const char S_ON_DEACTIVATE[] = "OnDeactivate"; -static const char S_ON_SELECT[] = "OnSelect"; -static const char S_ON_CREATING_GROUP[] = "OnCreatingGroup"; -static const char S_ON_DELETING_GROUP[] = "OnDeletingGroup"; -static const char S_ON_GROUP_VISIBILITY[] = "OnGroupVisibility"; -static const char S_M_EDGES[] = "_edges"; -static const char S_M_NODES[] = "_nodes"; -static const char S_M_THIS[] = "_this"; -static const char S_M_TITLE[] = "_title"; -static const char S_CLINK_NAME[] = "__clink__"; -static const char S_ON_VIEW_ACTIVATED[] = "OnViewActivated"; -static const char S_ON_VIEW_DEACTIVATED[] = "OnViewDeactivated"; -static const char S_ON_VIEW_KEYDOWN[] = "OnViewKeydown"; -static const char S_ON_VIEW_CLICK[] = "OnViewClick"; -static const char S_ON_VIEW_DBLCLICK[] = "OnViewDblclick"; -static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos"; -static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched"; -static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver"; -static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved"; - - -#ifdef __PYWRAPS__ -static const char S_PY_IDAAPI_MODNAME[] = "__main__"; -#else -static const char S_PY_IDAAPI_MODNAME[] = S_IDAAPI_MODNAME; -#endif - -//------------------------------------------------------------------------ -static ref_t py_cvt_helper_module; -static bool pywraps_initialized = false; - -//--------------------------------------------------------------------------- -// Context structure used by add|del_menu_item() -struct py_add_del_menu_item_ctx -{ - qstring menupath; - PyObject *cb_data; -}; - -//--------------------------------------------------------------------------- -// Context structure used by add|del_idc_hotkey() -struct py_idchotkey_ctx_t -{ - qstring hotkey; - PyObject *pyfunc; -}; - -//--------------------------------------------------------------------------- -// Context structure used by register/unregister timer -struct py_timer_ctx_t -{ - qtimer_t timer_id; - PyObject *pycallback; -}; - -//------------------------------------------------------------------------ -// check if we have a file which is known to be executed automatically -// by SWIG or Python runtime -bool pywraps_check_autoscripts(char *buf, size_t bufsize) -{ - static const char *const exts[] = - { - "py", - "pyc", - "pyd", - "pyo", - "pyw", - }; - - static const char *const fns[] = - { - "swig_runtime_data" SWIG_RUNTIME_VERSION, - "sitecustomize", - "usercustomize" - }; - - for ( size_t ifn=0; ifn < qnumber(fns); ++ifn ) - { - // check for a script or module with several possible extensions - for ( size_t iext=0; iext < qnumber(exts); ++iext ) - { - qsnprintf(buf, bufsize, "%s.%s", fns[ifn], exts[iext]); - if ( qfileexist(buf) ) - return true; - } - // check for a subdirectory under current directory - if ( qfileexist(fns[ifn]) ) - { - qstrncpy(buf, fns[ifn], bufsize); - return true; - } - } - return false; -} - -//------------------------------------------------------------------------ -error_t PyW_CreateIdcException(idc_value_t *res, const char *msg) -{ - // Create exception object - VarObject(res, find_idc_class("exception")); - - // Set the message field - idc_value_t v; - v.set_string(msg); - VarSetAttr(res, "message", &v); - - // Throw exception - return set_qerrno(eExecThrow); -} - -//------------------------------------------------------------------------ -// Calls a Python callable encoded in IDC.pvoid member -static const char idc_py_invoke0_args[] = { VT_PVOID, 0 }; -static error_t idaapi idc_py_invoke0( - idc_value_t *argv, - idc_value_t *res) -{ - PYW_GIL_GET; - PyObject *pyfunc = (PyObject *) argv[0].pvoid; - newref_t py_result(PyObject_CallFunctionObjArgs(pyfunc, NULL)); - - // Report Python error as IDC exception - qstring err; - error_t err_code = eOk; - if ( PyW_GetError(&err) ) - err_code = PyW_CreateIdcException(res, err.c_str()); - return err_code; -} - -//------------------------------------------------------------------------ -// This function must be called on initialization -bool init_pywraps() -{ - if ( pywraps_initialized ) - return true; - - // Take a reference to the idaapi python module - // (We need it to create instances of certain classes) - if ( py_cvt_helper_module == NULL ) - { - // Take a reference to the module so we can create the needed class instances - py_cvt_helper_module = PyW_TryImportModule(S_PY_IDAAPI_MODNAME); - if ( py_cvt_helper_module == NULL ) - return false; - } - - // Register the IDC PyInvoke0 method (helper function for add_idc_hotkey()) - if ( !set_idc_func_ex(S_PYINVOKE0, idc_py_invoke0, idc_py_invoke0_args, 0) ) - return false; - - // IDC opaque class not registered? - if ( get_py_idc_cvt_opaque() == NULL ) - { - // Add the class - idc_class_t *idc_cvt_opaque = add_idc_class(S_PY_IDC_OPAQUE_T); - if ( idc_cvt_opaque == NULL ) - return false; - - // Form the dtor name - char dtor_name[MAXSTR]; - qsnprintf(dtor_name, sizeof(dtor_name), "%s.dtor", S_PY_IDC_OPAQUE_T); - - // Register the dtor function - if ( !set_idc_func_ex(dtor_name, py_idc_opaque_dtor, py_idc_cvt_helper_dtor_args, 0) ) - return false; - - // Link the dtor function to the class - set_idc_dtor(idc_cvt_opaque, dtor_name); - } - - pywraps_initialized = true; - return true; -} - -//------------------------------------------------------------------------ -// This function must be called on de-initialization -void deinit_pywraps() -{ - if ( !pywraps_initialized ) +#define GET_THIS() py_customidamemo_t *_this = view_extract_this(self) +#define CHK_THIS() \ + GET_THIS(); \ + if ( _this == NULL ) \ return; +#define CHK_THIS_OR_NULL() \ + GET_THIS(); \ + if ( _this == NULL ) \ + return NULL; +#define CHK_THIS_OR_NONE() \ + GET_THIS(); \ + if ( _this == NULL ) \ + Py_RETURN_NONE - pywraps_initialized = false; - { - PYW_GIL_CHECK_LOCKED_SCOPE(); - py_cvt_helper_module = ref_t(); // Deref. - } - - // Unregister the IDC PyInvoke0 method (helper function for add_idc_hotkey()) - set_idc_func_ex(S_PYINVOKE0, NULL, idc_py_invoke0_args, 0); -} - -//------------------------------------------------------------------------ -// Utility function to create linked class instances -ref_t create_idaapi_linked_class_instance( - const char *clsname, - void *lnk) +//------------------------------------------------------------------------- +void pygc_refresh(PyObject *self) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - ref_t py_cls(get_idaapi_attr(clsname)); - if ( py_cls == NULL ) - return ref_t(); - - newref_t py_lnk(PyCObject_FromVoidPtr(lnk, NULL)); - ref_t py_obj = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, py_lnk.o, NULL)); - if ( PyW_GetError() || py_obj == NULL ) - py_obj = ref_t(); - return py_obj; -} - -//------------------------------------------------------------------------ -// Gets a class type reference in idaapi -// With the class type reference we can create a new instance of that type -// This function takes a reference to the idaapi module and keeps the reference -ref_t get_idaapi_attr_by_id(const int class_id) -{ - if ( class_id >= PY_CLSID_LAST || py_cvt_helper_module == NULL ) - return ref_t(); - - // Some class names. The array is parallel with the PY_CLSID_xxx consts - static const char *class_names[]= - { - "PyIdc_cvt_int64__", - "object_t", - "PyIdc_cvt_refclass__" - }; - PYW_GIL_CHECK_LOCKED_SCOPE(); - return newref_t(PyObject_GetAttrString(py_cvt_helper_module.o, class_names[class_id])); -} - -//------------------------------------------------------------------------ -// Gets a class reference by name -ref_t get_idaapi_attr(const char *attrname) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return py_cvt_helper_module == NULL - ? ref_t() - : PyW_TryGetAttrString(py_cvt_helper_module.o, attrname); -} - -//------------------------------------------------------------------------ -// Returns a qstring from an object attribute -bool PyW_GetStringAttr( - PyObject *py_obj, - const char *attr_name, - qstring *str) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - ref_t py_attr(PyW_TryGetAttrString(py_obj, attr_name)); - if ( py_attr == NULL ) - return false; - - bool ok = PyString_Check(py_attr.o) != 0; - if ( ok ) - *str = PyString_AsString(py_attr.o); - - return ok; -} - -//------------------------------------------------------------------------ -// Returns an attribute or NULL -// No errors will be set if the attribute did not exist -ref_t PyW_TryGetAttrString(PyObject *py_obj, const char *attr) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - ref_t o; - if ( PyObject_HasAttrString(py_obj, attr) ) - o = newref_t(PyObject_GetAttrString(py_obj, attr)); - return o; -} - -//------------------------------------------------------------------------ -// Tries to import a module and clears the exception on failure -ref_t PyW_TryImportModule(const char *name) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t result(PyImport_ImportModule(name)); - if ( result == NULL && PyErr_Occurred() ) - PyErr_Clear(); - return result; + CHK_THIS(); + _this->refresh(); } //------------------------------------------------------------------------- -// Converts a Python number into an IDC value (32 or 64bits) -// The function will first try to convert the number into a 32bit value -// If the number does not fit then VT_INT64 will be used -// NB: This function cannot properly detect if the Python value should be -// converted to a VT_INT64 or not. For example: 2**32-1 = 0xffffffff which -// can fit in a C long but Python creates a PyLong object for it. -// And because of that we are confused as to whether to convert to 32 or 64 -bool PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_var) +void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - bool rc = true; - do - { - if ( !(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)) ) - { - rc = false; - break; - } - - // Can we convert to C long? - long l = PyInt_AsLong(py_var); - if ( !PyErr_Occurred() ) - { - idc_var->set_long(l); - break; - } - // Clear last error - PyErr_Clear(); - // Can be fit into a C unsigned long? - l = (long) PyLong_AsUnsignedLong(py_var); - if ( !PyErr_Occurred() ) - { - idc_var->set_long(l); - break; - } - PyErr_Clear(); - idc_var->set_int64(PyLong_AsLongLong(py_var)); - } while ( false ); - return rc; + CHK_THIS(); + _this->set_node_info(py_node_idx, py_node_info, py_flags); } //------------------------------------------------------------------------- -// Parses a Python object as a long or long long -bool PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64) +void pygc_set_nodes_infos(PyObject *self, PyObject *values) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - bool rc = true; -#define SETNUM(numexpr, is64_expr) \ - do \ - { \ - if ( num != NULL ) \ - *num = numexpr; \ - if ( is_64 != NULL ) \ - *is_64 = is64_expr; \ - } while ( false ) - - do - { - if ( !(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)) ) - { - rc = false; - break; - } - - // Can we convert to C long? - long l = PyInt_AsLong(py_var); - if ( !PyErr_Occurred() ) - { - SETNUM(uint64(l), false); - break; - } - - // Clear last error - PyErr_Clear(); - - // Can be fit into a C unsigned long? - unsigned long ul = PyLong_AsUnsignedLong(py_var); - if ( !PyErr_Occurred() ) - { - SETNUM(uint64(ul), false); - break; - } - PyErr_Clear(); - - // Try to parse as int64 - PY_LONG_LONG ll = PyLong_AsLongLong(py_var); - if ( !PyErr_Occurred() ) - { - SETNUM(uint64(ll), true); - break; - } - PyErr_Clear(); - - // Try to parse as uint64 - unsigned PY_LONG_LONG ull = PyLong_AsUnsignedLongLong(py_var); - PyObject *err = PyErr_Occurred(); - if ( err == NULL ) - { - SETNUM(uint64(ull), true); - break; - } - // Negative number? _And_ it with uint64(-1) - rc = false; - if ( err == PyExc_TypeError ) - { - newref_t py_mask(Py_BuildValue("K", 0xFFFFFFFFFFFFFFFFull)); - newref_t py_num(PyNumber_And(py_var, py_mask.o)); - if ( py_num != NULL && py_mask != NULL ) - { - PyErr_Clear(); - ull = PyLong_AsUnsignedLongLong(py_num.o); - if ( !PyErr_Occurred() ) - { - SETNUM(uint64(ull), true); - rc = true; - } - } - } - PyErr_Clear(); - } while ( false ); - return rc; -#undef SETNUM + CHK_THIS(); + _this->set_nodes_infos(values); } //------------------------------------------------------------------------- -// Checks if a given object is of sequence type -bool PyW_IsSequenceType(PyObject *obj) +PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - bool rc = true; - do - { - if ( !PySequence_Check(obj) ) - { - rc = false; - break; - } - - Py_ssize_t sz = PySequence_Size(obj); - if ( sz == -1 || PyErr_Occurred() != NULL ) - { - PyErr_Clear(); - rc = false; - break; - } - } while ( false ); - return rc; -} - -//------------------------------------------------------------------------- -// Returns the string representation of an object -bool PyW_ObjectToString(PyObject *obj, qstring *out) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t py_str(PyObject_Str(obj)); - bool ok = py_str != NULL; - if ( ok ) - *out = PyString_AsString(py_str.o); + GET_THIS(); + if ( _this != NULL ) + return _this->get_node_info(py_node_idx); else - out->qclear(); - return ok; + Py_RETURN_NONE; } -//-------------------------------------------------------------------------- -// Checks if a Python error occured and fills the out parameter with the -// exception string -bool PyW_GetError(qstring *out, bool clear_err) +//------------------------------------------------------------------------- +void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes) { - PYW_GIL_CHECK_LOCKED_SCOPE(); + CHK_THIS(); + _this->del_nodes_infos(py_nodes); +} - if ( PyErr_Occurred() == NULL ) - return false; - - // Error occurred but details not needed? - if ( out == NULL ) - { - // Just clear the error - if ( clear_err ) - PyErr_Clear(); - return true; - } - - // Get the exception info - PyObject *err_type, *err_value, *err_traceback, *py_ret(NULL); - PyErr_Fetch(&err_type, &err_value, &err_traceback); - - if ( !clear_err ) - PyErr_Restore(err_type, err_value, err_traceback); - - // Resolve FormatExc() - ref_t py_fmtexc(get_idaapi_attr(S_IDAAPI_FORMATEXC)); - - // Helper there? - if ( py_fmtexc != NULL ) - { - // Call helper - py_ret = PyObject_CallFunctionObjArgs( - py_fmtexc.o, - err_type, - err_value, - err_traceback, - NULL); - } - - // Clear the error - if ( clear_err ) - PyErr_Clear(); - - // Helper failed?! - if ( py_ret == NULL ) - { - // Just convert the 'value' part of the original error - py_ret = PyObject_Str(err_value); - } - - // No exception text? - if ( py_ret == NULL ) - { - *out = "IDAPython: unknown error!"; - } +//------------------------------------------------------------------------- +PyObject *pygc_get_current_renderer_type(PyObject *self) +{ + GET_THIS(); + if ( _this != NULL ) + return _this->get_current_renderer_type(); else - { - *out = PyString_AsString(py_ret); - Py_DECREF(py_ret); - } - - if ( clear_err ) - { - Py_XDECREF(err_traceback); - Py_XDECREF(err_value); - Py_XDECREF(err_type); - } - return true; + Py_RETURN_NONE; } //------------------------------------------------------------------------- -bool PyW_GetError(char *buf, size_t bufsz, bool clear_err) +void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - qstring s; - if ( !PyW_GetError(&s, clear_err) ) - return false; - - qstrncpy(buf, s.c_str(), bufsz); - return true; + CHK_THIS(); + _this->set_current_renderer_type(py_rt); } //------------------------------------------------------------------------- -// A loud version of PyGetError() which gets the error and displays it -// This method is used to display errors that occurred in a callback -bool PyW_ShowCbErr(const char *cb_name) +PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - static qstring err_str; - if ( !PyW_GetError(&err_str) ) - return false; - - msg("IDAPython: Error while calling Python callback <%s>:\n%s", cb_name, err_str.c_str()); - return true; + CHK_THIS_OR_NONE(); + return _this->create_groups(groups_infos); } -//--------------------------------------------------------------------------- -void *pyobj_get_clink(PyObject *pyobj) +//------------------------------------------------------------------------- +PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Try to query the link attribute - ref_t attr(PyW_TryGetAttrString(pyobj, S_CLINK_NAME)); - void *t = attr != NULL && PyCObject_Check(attr.o) ? PyCObject_AsVoidPtr(attr.o) : NULL; - return t; + CHK_THIS_OR_NONE(); + return _this->delete_groups(groups, new_current); } -//------------------------------------------------------------------------ -class pywraps_notify_when_t +//------------------------------------------------------------------------- +PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current) { - ref_vec_t table[NW_EVENTSCNT]; - qstring err; - bool in_notify; - struct notify_when_args_t - { - int when; - PyObject *py_callable; - }; - typedef qvector notify_when_args_vec_t; - notify_when_args_vec_t delayed_notify_when_list; - - //------------------------------------------------------------------------ - static int idaapi idp_callback(void *ud, int event_id, va_list va) - { - pywraps_notify_when_t *_this = (pywraps_notify_when_t *)ud; - switch ( event_id ) - { - case processor_t::newfile: - case processor_t::oldfile: - { - // This hook gets called from the kernel. Ensure we hold the GIL. - // Note that PYW_GIL_GET appears in each case of the switch, which is to - // ensure that the GIL is retrieved ONLY when we need it. If PYW_GIL_GET - // appears outside the switch, it will be executed each time this callback - // is called, which results in a huge slowdown (at least on mac). - PYW_GIL_GET; - int old = event_id == processor_t::oldfile ? 1 : 0; - char *dbname = va_arg(va, char *); - _this->notify(NW_OPENIDB_SLOT, old); - } - break; - case processor_t::closebase: - { - PYW_GIL_GET; - _this->notify(NW_CLOSEIDB_SLOT); - } - break; - } - // event not processed, let other plugins or the processor module handle it - return 0; - } - - //------------------------------------------------------------------------ - bool unnotify_when(int when, PyObject *py_callable) - { - int cnt = 0; - for ( int slot=0; slot 0; - } - - //------------------------------------------------------------------------ - void register_callback(int slot, PyObject *py_callable) - { - borref_t callable_ref(py_callable); - ref_vec_t &tbl = table[slot]; - ref_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, callable_ref); - - // Already added - if ( it != it_end ) - return; - - // Insert the element - tbl.push_back(callable_ref); - } - - //------------------------------------------------------------------------ - void unregister_callback(int slot, PyObject *py_callable) - { - borref_t callable_ref(py_callable); - ref_vec_t &tbl = table[slot]; - ref_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, callable_ref); - - // Not found? - if ( it == it_end ) - return; - - // Delete the element - tbl.erase(it); - } - -public: - //------------------------------------------------------------------------ - bool init() - { - return hook_to_notification_point(HT_IDP, idp_callback, this); - } - - //------------------------------------------------------------------------ - bool deinit() - { - // Uninstall all objects - ref_vec_t::iterator it, it_end; - for ( int slot=0; sloto); - } - // ...and remove the notification - return unhook_from_notification_point(HT_IDP, idp_callback, this); - } - - //------------------------------------------------------------------------ - bool notify_when(int when, PyObject *py_callable) - { - // While in notify() do not allow insertion or deletion to happen on the spot - // Instead we will queue them so that notify() will carry the action when it finishes - // dispatching the notification handlers - if ( in_notify ) - { - notify_when_args_t &args = delayed_notify_when_list.push_back(); - args.when = when; - args.py_callable = py_callable; - return true; - } - // Uninstalling the notification? - if ( (when & NW_REMOVE) != 0 ) - return unnotify_when(when & ~NW_REMOVE, py_callable); - - int cnt = 0; - for ( int slot=0; slot 0; - } - - //------------------------------------------------------------------------ - bool notify(int slot, ...) - { - va_list va; - va_start(va, slot); - bool ok = notify_va(slot, va); - va_end(va); - return ok; - } - - //------------------------------------------------------------------------ - bool notify_va(int slot, va_list va) - { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Sanity bounds check! - if ( slot < 0 || slot >= NW_EVENTSCNT ) - return false; - - bool ok = true; - in_notify = true; - int old = slot == NW_OPENIDB_SLOT ? va_arg(va, int) : 0; - - { - for ( ref_vec_t::iterator it = table[slot].begin(), it_end = table[slot].end(); - it != it_end; - ++it ) - { - // Form the notification code - newref_t py_code(PyInt_FromLong(1 << slot)); - ref_t py_result; - switch ( slot ) - { - case NW_CLOSEIDB_SLOT: - case NW_INITIDA_SLOT: - case NW_TERMIDA_SLOT: - { - py_result = newref_t(PyObject_CallFunctionObjArgs(it->o, py_code.o, NULL)); - break; - } - case NW_OPENIDB_SLOT: - { - newref_t py_old(PyInt_FromLong(old)); - py_result = newref_t(PyObject_CallFunctionObjArgs(it->o, py_code.o, py_old.o, NULL)); - } - break; - } - if ( PyW_GetError(&err) || py_result == NULL ) - { - PyErr_Clear(); - warning("notify_when(): Error occured while notifying object.\n%s", err.c_str()); - ok = false; - } - } - } - in_notify = false; - - // Process any delayed notify_when() calls that - if ( !delayed_notify_when_list.empty() ) - { - notify_when_args_vec_t::iterator it, it_end; - for ( it = delayed_notify_when_list.begin(), it_end=delayed_notify_when_list.end(); - it != it_end; - ++it ) - { - notify_when(it->when, it->py_callable); - } - delayed_notify_when_list.qclear(); - } - - return ok; - } - - //------------------------------------------------------------------------ - pywraps_notify_when_t() - { - in_notify = false; - } -}; - -static pywraps_notify_when_t *g_nw = NULL; - -//------------------------------------------------------------------------ -// Initializes the notify_when mechanism -// (Normally called by IDAPython plugin.init()) -bool pywraps_nw_init() -{ - if ( g_nw != NULL ) - return true; - - g_nw = new pywraps_notify_when_t(); - if ( g_nw->init() ) - return true; - - // Things went bad, undo! - delete g_nw; - g_nw = NULL; - return false; + CHK_THIS_OR_NONE(); + return _this->set_groups_visibility(groups, expand, new_current); } -//------------------------------------------------------------------------ -bool pywraps_nw_notify(int slot, ...) +//------------------------------------------------------------------------- +TForm *pycim_get_tform(PyObject *self) { - if ( g_nw == NULL ) - return false; - - // Appears to be called from 'driver_notifywhen.cpp', which - // itself is called from possibly non-python code. - // I.e., we must acquire the GIL. - PYW_GIL_GET; - va_list va; - va_start(va, slot); - bool ok = g_nw->notify_va(slot, va); - va_end(va); - - return ok; + CHK_THIS_OR_NULL(); + TForm *form = NULL; + if ( !pycim_lookup_info.find_by_py_view(&form, NULL, _this) ) + return NULL; + return form; } -//------------------------------------------------------------------------ -// Deinitializes the notify_when mechanism -bool pywraps_nw_term() +//------------------------------------------------------------------------- +TCustomControl *pycim_get_tcustom_control(PyObject *self) { - if ( g_nw == NULL ) - return true; - - // If could not deinitialize then return w/o stopping nw - if ( !g_nw->deinit() ) - return false; - - // Cleanup - delete g_nw; - g_nw = NULL; - return true; + CHK_THIS_OR_NULL(); + TCustomControl *tcc = NULL; + if ( !pycim_lookup_info.find_by_py_view(NULL, &tcc, _this) ) + return NULL; + return tcc; } - +#undef CHK_THIS_OR_NONE +#undef CHK_THIS_OR_NULL +#undef CHK_THIS +#undef GET_THIS // @@ -1694,7 +177,7 @@ def set_script_timeout(timeout): pass # */ -int set_script_timeout(int timeout); +idaman int ida_export set_script_timeout(int timeout); /* # @@ -1708,7 +191,7 @@ def disable_script_timeout(): pass # */ -void disable_script_timeout(); +idaman void ida_export disable_script_timeout(); /* # @@ -1721,8 +204,8 @@ def enable_extlang_python(enable): pass # */ -void enable_extlang_python(bool enable); -void enable_python_cli(bool enable); +idaman void ida_export enable_extlang_python(bool enable); +idaman void ida_export enable_python_cli(bool enable); /* # @@ -1737,111 +220,6 @@ def RunPythonStatement(stmt): # */ -//--------------------------------------------------------------------------- -// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py) -//--------------------------------------------------------------------------- -static bool qstrvec_t_assign(PyObject *self, PyObject *other) -{ - qstrvec_t *lhs = qstrvec_t_get_clink(self); - qstrvec_t *rhs = qstrvec_t_get_clink(other); - if ( lhs == NULL || rhs == NULL ) - return false; - *lhs = *rhs; - return true; -} - -static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL || idx >= sv->size() ) - Py_RETURN_NONE; - else - return PyLong_FromUnsignedLongLong(size_t(&sv->at(idx))); -} - - -static bool qstrvec_t_set( - PyObject *self, - size_t idx, - const char *s) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL || idx >= sv->size() ) - return false; - (*sv)[idx] = s; - return true; -} - -static bool qstrvec_t_from_list( - PyObject *self, - PyObject *py_list) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - qstrvec_t *sv = qstrvec_t_get_clink(self); - return sv == NULL ? false : PyW_PyListToStrVec(py_list, *sv); -} - -static size_t qstrvec_t_size(PyObject *self) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - return sv == NULL ? 0 : sv->size(); -} - -static PyObject *qstrvec_t_get(PyObject *self, size_t idx) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL || idx >= sv->size() ) - Py_RETURN_NONE; - return PyString_FromString(sv->at(idx).c_str()); -} - -static bool qstrvec_t_add(PyObject *self, const char *s) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL ) - return false; - sv->push_back(s); - return true; -} - -static bool qstrvec_t_clear(PyObject *self, bool qclear) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL ) - return false; - - if ( qclear ) - sv->qclear(); - else - sv->clear(); - - return true; -} - -static bool qstrvec_t_insert( - PyObject *self, - size_t idx, - const char *s) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL || idx >= sv->size() ) - return false; - sv->insert(sv->begin() + idx, s); - return true; -} - -static bool qstrvec_t_remove(PyObject *self, size_t idx) -{ - qstrvec_t *sv = qstrvec_t_get_clink(self); - if ( sv == NULL || idx >= sv->size() ) - return false; - - sv->erase(sv->begin()+idx); - return true; -} - //------------------------------------------------------------------------ /* # @@ -1862,10 +240,21 @@ def notify_when(when, callback): static bool notify_when(int when, PyObject *py_callable) { PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( g_nw == NULL || !PyCallable_Check(py_callable) ) - return false; - return g_nw->notify_when(when, py_callable); + return PyCallable_Check(py_callable) && add_notify_when(when, py_callable); } + +void pygc_refresh(PyObject *self); +void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags); +void pygc_set_nodes_infos(PyObject *self, PyObject *values); +PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx); +void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes); +PyObject *pygc_get_current_renderer_type(PyObject *self); +void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt); +PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos); +PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current); +PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current); +TForm *pycim_get_tform(PyObject *self); +TCustomControl *pycim_get_tcustom_control(PyObject *self); // #endif diff --git a/pywraps/py_idaapi.py b/pywraps/py_idaapi.py index a500a04..789c8d3 100755 --- a/pywraps/py_idaapi.py +++ b/pywraps/py_idaapi.py @@ -5,7 +5,7 @@ try: except: pywraps_there = False -import _idaapi +import _ida_idaapi import random import operator import datetime @@ -241,82 +241,6 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__): def __rmul__(self, other): return self.__op(2, other, True) def __rdiv__(self, other): return self.__op(3, other, True) -# ----------------------------------------------------------------------- -# qstrvec_t clinked object -class _qstrvec_t(py_clinked_object_t): - """ - WARNING: It is very unlikely an IDAPython user should ever, ever - have to use this type. It should only be used for IDAPython internals. - - For example, in py_askusingform.py, we ctypes-expose to the IDA - kernel & UI a qstrvec instance, in case a DropdownListControl is - constructed. - That's because that's what AskUsingForm expects, and we have no - choice but to make a DropdownListControl hold a qstrvec_t. - This is, afaict, the only situation where a Python - _qstrvec_t is required. - """ - - def __init__(self, items=None): - py_clinked_object_t.__init__(self) - # Populate the list if needed - if items: - self.from_list(items) - - def _create_clink(self): - return _idaapi.qstrvec_t_create() - - def _del_clink(self, lnk): - return _idaapi.qstrvec_t_destroy(lnk) - - def _get_clink_ptr(self): - return _idaapi.qstrvec_t_get_clink_ptr(self) - - def assign(self, other): - """Copies the contents of 'other' to 'self'""" - return _idaapi.qstrvec_t_assign(self, other) - - def __setitem__(self, idx, s): - """Sets string at the given index""" - return _idaapi.qstrvec_t_set(self, idx, s) - - def __getitem__(self, idx): - """Gets the string at the given index""" - return _idaapi.qstrvec_t_get(self, idx) - - def __get_size(self): - return _idaapi.qstrvec_t_size(self) - - size = property(__get_size) - """Returns the count of elements""" - - def addressof(self, idx): - """Returns the address (as number) of the qstring at the given index""" - return _idaapi.qstrvec_t_addressof(self, idx) - - def add(self, s): - """Add a string to the vector""" - return _idaapi.qstrvec_t_add(self, s) - - def from_list(self, lst): - """Populates the vector from a Python string list""" - return _idaapi.qstrvec_t_from_list(self, lst) - - def clear(self, qclear=False): - """ - Clears all strings from the vector. - @param qclear: Just reset the size but do not actually free the memory - """ - return _idaapi.qstrvec_t_clear(self, qclear) - - def insert(self, idx, s): - """Insert a string into the vector""" - return _idaapi.qstrvec_t_insert(self, idx, s) - - def remove(self, idx): - """Removes a string from the vector""" - return _idaapi.qstrvec_t_remove(self, idx) - # ----------------------------------------------------------------------- class PyIdc_cvt_refclass__(pyidc_cvt_helper__): """Helper class for representing references to immutable objects""" @@ -344,7 +268,8 @@ def as_cstr(val): def as_unicode(s): """Convenience function to convert a string into appropriate unicode format""" # use UTF16 big/little endian, depending on the environment? - return unicode(s).encode("UTF-16" + ("BE" if _idaapi.cvar.inf.mf else "LE")) + import _ida_ida + return unicode(s).encode("UTF-16" + ("BE" if _ida_ida.cvar.inf.mf else "LE")) # ----------------------------------------------------------------------- def as_uint32(v): @@ -619,4 +544,127 @@ NW_TERMIDA = 0x0008 NW_REMOVE = 0x0010 """Use this flag with other flags to uninstall a notifywhen callback""" +# ----------------------------------------------------------------------- +# CustomIDAMemo +# ----------------------------------------------------------------------- +class CustomIDAMemo(object): + def Refresh(self): + """ + Refreshes the graph. This causes the OnRefresh() to be called + """ + ida_idaapi.pygc_refresh(self) + + def GetCurrentRendererType(self): + return ida_idaapi.pygc_get_current_renderer_type(self) + + def SetCurrentRendererType(self, rtype): + """ + Set the current view's renderer. + + @param rtype: The renderer type. Should be one of the idaapi.TCCRT_* values. + """ + ida_idaapi.pygc_set_current_renderer_type(self, rtype) + + def SetNodeInfo(self, node_index, node_info, flags): + """ + Set the properties for the given node. + + Example usage (set second nodes's bg color to red): + inst = ... + p = idaapi.node_info_t() + p.bg_color = 0x00ff0000 + inst.SetNodeInfo(1, p, idaapi.NIF_BG_COLOR) + + @param node_index: The node index. + @param node_info: An idaapi.node_info_t instance. + @param flags: An OR'ed value of NIF_* values. + """ + ida_idaapi.pygc_set_node_info(self, node_index, node_info, flags) + + def SetNodesInfos(self, values): + """ + Set the properties for the given nodes. + + Example usage (set first three nodes's bg color to purple): + inst = ... + p = idaapi.node_info_t() + p.bg_color = 0x00ff00ff + inst.SetNodesInfos({0 : p, 1 : p, 2 : p}) + + @param values: A dictionary of 'int -> node_info_t' objects. + """ + ida_idaapi.pygc_set_nodes_infos(self, values) + + def GetNodeInfo(self, node): + """ + Get the properties for the given node. + + @param node: The index of the node. + @return: A tuple (bg_color, frame_color, ea, text), or None. + """ + return ida_idaapi.pygc_get_node_info(self, node) + + def DelNodesInfos(self, *nodes): + """ + Delete the properties for the given node(s). + + @param nodes: A list of node IDs + """ + return ida_idaapi.pygc_del_nodes_infos(self, nodes) + + def CreateGroups(self, groups_infos): + """ + Send a request to modify the graph by creating a + (set of) group(s), and perform an animation. + + Each object in the 'groups_infos' list must be of the format: + { + "nodes" : [, , , ...] # The list of nodes to group + "text" : # The synthetic text for that group + } + + @param groups_infos: A list of objects that describe those groups. + @return: A [, , ...] list of group nodes, or None (failure). + """ + return ida_idaapi.pygc_create_groups(self, groups_infos) + + def DeleteGroups(self, groups, new_current = -1): + """ + Send a request to delete the specified groups in the graph, + and perform an animation. + + @param groups: A list of group node numbers. + @param new_current: A node to focus on after the groups have been deleted + @return: True on success, False otherwise. + """ + return ida_idaapi.pygc_delete_groups(self, groups, new_current) + + def SetGroupsVisibility(self, groups, expand, new_current = -1): + """ + Send a request to expand/collapse the specified groups in the graph, + and perform an animation. + + @param groups: A list of group node numbers. + @param expand: True to expand the group, False otherwise. + @param new_current: A node to focus on after the groups have been expanded/collapsed. + @return: True on success, False otherwise. + """ + return ida_idaapi.pygc_set_groups_visibility(self, groups, expand, new_current) + + def GetTForm(self): + """ + Return the TForm hosting this view. + + @return: The TForm that hosts this view, or None. + """ + return ida_idaapi.pycim_get_tform(self) + + def GetTCustomControl(self): + """ + Return the TCustomControl underlying this view. + + @return: The TCustomControl underlying this view, or None. + """ + return ida_idaapi.pycim_get_tcustom_control(self) + # diff --git a/pywraps/py_linput.hpp b/pywraps/py_idaapi_loader_input.hpp similarity index 98% rename from pywraps/py_linput.hpp rename to pywraps/py_idaapi_loader_input.hpp index 3144878..de0e5b0 100644 --- a/pywraps/py_linput.hpp +++ b/pywraps/py_idaapi_loader_input.hpp @@ -1,8 +1,8 @@ -#ifndef __PY_IDA_LINPUT__ -#define __PY_IDA_LINPUT__ +#ifndef __PY_IDAAPI_LOADER_INPUT__ +#define __PY_IDAAPI_LOADER_INPUT__ //-------------------------------------------------------------------------- -// +// /* # class loader_input_t(pyidc_opaque_object_t): @@ -412,6 +412,6 @@ public: return Py_BuildValue("c", ch); } }; -// +// -#endif +#endif // __PY_IDAAPI_LOADER_INPUT__ diff --git a/pywraps/py_idbhooks.hpp b/pywraps/py_idbhooks.hpp deleted file mode 100644 index 8ae422b..0000000 --- a/pywraps/py_idbhooks.hpp +++ /dev/null @@ -1,640 +0,0 @@ - - -// - -//--------------------------------------------------------------------------- -// 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); - } - - // hookgenIDB:methods -virtual int byte_patched(ea_t ea, uint32 old_value) {qnotused(ea); qnotused(old_value); return 0;} -virtual int cmt_changed(ea_t ea, bool repeatable_cmt) {qnotused(ea); qnotused(repeatable_cmt); return 0;} -virtual int ti_changed(ea_t ea, const type_t * type, const p_list * fnames) {qnotused(ea); qnotused(type); qnotused(fnames); return 0;} -virtual int op_ti_changed(ea_t ea, int n, const type_t * type, const p_list * fnames) {qnotused(ea); qnotused(n); qnotused(type); qnotused(fnames); return 0;} -virtual int op_type_changed(ea_t ea, int n) {qnotused(ea); qnotused(n); return 0;} -virtual int enum_created(enum_t id) {qnotused(id); return 0;} -virtual int enum_deleted(enum_t id) {qnotused(id); return 0;} -virtual int enum_bf_changed(enum_t id) {qnotused(id); return 0;} -virtual int enum_renamed(tid_t id) {qnotused(id); return 0;} -virtual int enum_cmt_changed(tid_t id, bool repeatable) {qnotused(id); qnotused(repeatable); return 0;} -virtual int enum_member_created(enum_t id, const_t cid) {qnotused(id); qnotused(cid); return 0;} -virtual int enum_member_deleted(enum_t id, const_t cid) {qnotused(id); qnotused(cid); return 0;} -virtual int struc_created(tid_t struc_id) {qnotused(struc_id); return 0;} -virtual int struc_deleted(tid_t struc_id) {qnotused(struc_id); return 0;} -virtual int struc_renamed(struc_t * sptr) {qnotused(sptr); return 0;} -virtual int struc_expanded(struc_t * sptr) {qnotused(sptr); return 0;} -virtual int struc_cmt_changed(tid_t struc_id, bool repeatable_cmt) {qnotused(struc_id); qnotused(repeatable_cmt); return 0;} -virtual int struc_member_created(struc_t * sptr, member_t * mptr) {qnotused(sptr); qnotused(mptr); return 0;} -virtual int struc_member_deleted(struc_t * sptr, tid_t member_id, ea_t offset) {qnotused(sptr); qnotused(member_id); qnotused(offset); return 0;} -virtual int struc_member_renamed(struc_t * sptr, member_t * mptr) {qnotused(sptr); qnotused(mptr); return 0;} -virtual int struc_member_changed(struc_t * sptr, member_t * mptr) {qnotused(sptr); qnotused(mptr); return 0;} -virtual int thunk_func_created(func_t * pfn) {qnotused(pfn); return 0;} -virtual int func_tail_appended(func_t * pfn, func_t * tail) {qnotused(pfn); qnotused(tail); return 0;} -virtual int func_tail_removed(func_t * pfn, ea_t tail_ea) {qnotused(pfn); qnotused(tail_ea); return 0;} -virtual int tail_owner_changed(func_t * tail, ea_t owner_func, ea_t old_owner) {qnotused(tail); qnotused(owner_func); qnotused(old_owner); return 0;} -virtual int func_noret_changed(func_t * pfn) {qnotused(pfn); return 0;} -virtual int segm_added(segment_t * s) {qnotused(s); return 0;} -virtual int segm_deleted(ea_t startEA, ea_t endEA) {qnotused(startEA); qnotused(endEA); return 0;} -virtual int segm_start_changed(segment_t * s, ea_t oldstart) {qnotused(s); qnotused(oldstart); return 0;} -virtual int segm_end_changed(segment_t * s, ea_t oldend) {qnotused(s); qnotused(oldend); return 0;} -virtual int segm_moved(ea_t from, ea_t to, asize_t size) {qnotused(from); qnotused(to); qnotused(size); return 0;} -virtual int area_cmt_changed(areacb_t * cb, const area_t * a, const char * cmt, bool repeatable) {qnotused(cb); qnotused(a); qnotused(cmt); qnotused(repeatable); return 0;} -virtual int changing_cmt(ea_t ea, bool repeatable_cmt, const char * newcmt) {qnotused(ea); qnotused(repeatable_cmt); qnotused(newcmt); return 0;} -virtual int changing_ti(ea_t ea, const type_t * new_type, const p_list * new_fnames) {qnotused(ea); qnotused(new_type); qnotused(new_fnames); return 0;} -virtual int changing_op_ti(ea_t ea, int n, const type_t * new_type, const p_list * new_fnames) {qnotused(ea); qnotused(n); qnotused(new_type); qnotused(new_fnames); return 0;} -virtual int changing_op_type(ea_t ea, int n) {qnotused(ea); qnotused(n); return 0;} -virtual int deleting_enum(enum_t id) {qnotused(id); return 0;} -virtual int changing_enum_bf(enum_t id, bool new_bf) {qnotused(id); qnotused(new_bf); return 0;} -virtual int renaming_enum(tid_t id, bool is_enum, const char * newname) {qnotused(id); qnotused(is_enum); qnotused(newname); return 0;} -virtual int changing_enum_cmt(tid_t id, bool repeatable, const char * newcmt) {qnotused(id); qnotused(repeatable); qnotused(newcmt); return 0;} -virtual int deleting_enum_const() {return 0;} -virtual int deleting_struc(struc_t * sptr) {qnotused(sptr); return 0;} -virtual int renaming_struc(tid_t id, const char * oldname, const char * newname) {qnotused(id); qnotused(oldname); qnotused(newname); return 0;} -virtual int expanding_struc(struc_t * sptr, ea_t offset, adiff_t delta) {qnotused(sptr); qnotused(offset); qnotused(delta); return 0;} -virtual int changing_struc_cmt(tid_t struc_id, bool repeatable, const char * newcmt) {qnotused(struc_id); qnotused(repeatable); qnotused(newcmt); return 0;} -virtual int deleting_struc_member(struc_t * sptr, member_t * mptr) {qnotused(sptr); qnotused(mptr); return 0;} -virtual int renaming_struc_member(struc_t * sptr, member_t * mptr, const char * newname) {qnotused(sptr); qnotused(mptr); qnotused(newname); return 0;} -virtual int changing_struc_member(struc_t * sptr, member_t * mptr, flags_t flag, const opinfo_t * ti, asize_t nbytes) {qnotused(sptr); qnotused(mptr); qnotused(flag); qnotused(ti); qnotused(nbytes); return 0;} -virtual int removing_func_tail(func_t * pfn, const area_t * tail) {qnotused(pfn); qnotused(tail); return 0;} -virtual int deleting_segm(ea_t startEA) {qnotused(startEA); return 0;} -virtual int changing_segm_start(segment_t * s, ea_t new_start, int segmod_flags) {qnotused(s); qnotused(new_start); qnotused(segmod_flags); return 0;} -virtual int changing_segm_end(segment_t * s, ea_t new_end, int segmod_flags) {qnotused(s); qnotused(new_end); qnotused(segmod_flags); return 0;} -virtual int changing_area_cmt(areacb_t * cb, const area_t * a, const char * cmt, bool repeatable) {qnotused(cb); qnotused(a); qnotused(cmt); qnotused(repeatable); return 0;} -virtual int changing_segm_name(segment_t * s, const char * oldname) {qnotused(s); qnotused(oldname); return 0;} -virtual int changing_segm_class(segment_t * s) {qnotused(s); return 0;} -virtual int segm_name_changed(segment_t * s, const char * name) {qnotused(s); qnotused(name); return 0;} -virtual int segm_class_changed(segment_t * s, const char * sclass) {qnotused(s); qnotused(sclass); return 0;} -virtual int destroyed_items(ea_t ea1, ea_t ea2, bool will_disable_range) {qnotused(ea1); qnotused(ea2); qnotused(will_disable_range); return 0;} -virtual int changed_stkpnts(func_t * pfn) {qnotused(pfn); return 0;} -virtual int extra_cmt_changed(ea_t ea, int line_idx, const char * cmt) {qnotused(ea); qnotused(line_idx); qnotused(cmt); return 0;} -virtual int changing_struc(struc_t * sptr) {qnotused(sptr); return 0;} -virtual int changed_struc(struc_t * sptr) {qnotused(sptr); return 0;} -virtual int local_types_changed() {return 0;} -virtual int segm_attrs_changed(segment_t * s) {qnotused(s); return 0;} -virtual int allsegs_moved(segm_move_infos_t * info) {qnotused(info); return 0;} -}; -// - - -// -//--------------------------------------------------------------------------- -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; - int ret = 0; - try - { - switch ( notification_code ) - { - // hookgenIDB:notifications -case idb_event::byte_patched: -{ - ea_t ea = va_arg(va, ea_t); - uint32 old_value = va_arg(va, uint32); - ret = proxy->byte_patched(ea, old_value); -} -break; - -case idb_event::cmt_changed: -{ - ea_t ea = va_arg(va, ea_t); - bool repeatable_cmt = bool(va_arg(va, int)); - ret = proxy->cmt_changed(ea, repeatable_cmt); -} -break; - -case idb_event::ti_changed: -{ - ea_t ea = va_arg(va, ea_t); - const type_t * type = va_arg(va, const type_t *); - const p_list * fnames = va_arg(va, const p_list *); - ret = proxy->ti_changed(ea, type, fnames); -} -break; - -case idb_event::op_ti_changed: -{ - ea_t ea = va_arg(va, ea_t); - int n = va_arg(va, int); - const type_t * type = va_arg(va, const type_t *); - const p_list * fnames = va_arg(va, const p_list *); - ret = proxy->op_ti_changed(ea, n, type, fnames); -} -break; - -case idb_event::op_type_changed: -{ - ea_t ea = va_arg(va, ea_t); - int n = va_arg(va, int); - ret = proxy->op_type_changed(ea, n); -} -break; - -case idb_event::enum_created: -{ - enum_t id = va_arg(va, enum_t); - ret = proxy->enum_created(id); -} -break; - -case idb_event::enum_deleted: -{ - enum_t id = va_arg(va, enum_t); - ret = proxy->enum_deleted(id); -} -break; - -case idb_event::enum_bf_changed: -{ - enum_t id = va_arg(va, enum_t); - ret = proxy->enum_bf_changed(id); -} -break; - -case idb_event::enum_renamed: -{ - tid_t id = va_arg(va, tid_t); - ret = proxy->enum_renamed(id); -} -break; - -case idb_event::enum_cmt_changed: -{ - tid_t id = va_arg(va, tid_t); - bool repeatable = bool(va_arg(va, int)); - ret = proxy->enum_cmt_changed(id, repeatable); -} -break; - -case idb_event::enum_const_created: -{ - enum_t id = va_arg(va, enum_t); - const_t cid = va_arg(va, const_t); - ret = proxy->enum_member_created(id, cid); -} -break; - -case idb_event::enum_const_deleted: -{ - enum_t id = va_arg(va, enum_t); - const_t cid = va_arg(va, const_t); - ret = proxy->enum_member_deleted(id, cid); -} -break; - -case idb_event::struc_created: -{ - tid_t struc_id = va_arg(va, tid_t); - ret = proxy->struc_created(struc_id); -} -break; - -case idb_event::struc_deleted: -{ - tid_t struc_id = va_arg(va, tid_t); - ret = proxy->struc_deleted(struc_id); -} -break; - -case idb_event::struc_renamed: -{ - struc_t * sptr = va_arg(va, struc_t *); - ret = proxy->struc_renamed(sptr); -} -break; - -case idb_event::struc_expanded: -{ - struc_t * sptr = va_arg(va, struc_t *); - ret = proxy->struc_expanded(sptr); -} -break; - -case idb_event::struc_cmt_changed: -{ - tid_t struc_id = va_arg(va, tid_t); - bool repeatable_cmt = bool(va_arg(va, int)); - ret = proxy->struc_cmt_changed(struc_id, repeatable_cmt); -} -break; - -case idb_event::struc_member_created: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - ret = proxy->struc_member_created(sptr, mptr); -} -break; - -case idb_event::struc_member_deleted: -{ - struc_t * sptr = va_arg(va, struc_t *); - tid_t member_id = va_arg(va, tid_t); - ea_t offset = va_arg(va, ea_t); - ret = proxy->struc_member_deleted(sptr, member_id, offset); -} -break; - -case idb_event::struc_member_renamed: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - ret = proxy->struc_member_renamed(sptr, mptr); -} -break; - -case idb_event::struc_member_changed: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - ret = proxy->struc_member_changed(sptr, mptr); -} -break; - -case idb_event::thunk_func_created: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->thunk_func_created(pfn); -} -break; - -case idb_event::func_tail_appended: -{ - func_t * pfn = va_arg(va, func_t *); - func_t * tail = va_arg(va, func_t *); - ret = proxy->func_tail_appended(pfn, tail); -} -break; - -case idb_event::func_tail_removed: -{ - func_t * pfn = va_arg(va, func_t *); - ea_t tail_ea = va_arg(va, ea_t); - ret = proxy->func_tail_removed(pfn, tail_ea); -} -break; - -case idb_event::tail_owner_changed: -{ - func_t * tail = va_arg(va, func_t *); - ea_t owner_func = va_arg(va, ea_t); - ea_t old_owner = va_arg(va, ea_t); - ret = proxy->tail_owner_changed(tail, owner_func, old_owner); -} -break; - -case idb_event::func_noret_changed: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->func_noret_changed(pfn); -} -break; - -case idb_event::segm_added: -{ - segment_t * s = va_arg(va, segment_t *); - ret = proxy->segm_added(s); -} -break; - -case idb_event::segm_deleted: -{ - ea_t startEA = va_arg(va, ea_t); - ea_t endEA = va_arg(va, ea_t); - ret = proxy->segm_deleted(startEA, endEA); -} -break; - -case idb_event::segm_start_changed: -{ - segment_t * s = va_arg(va, segment_t *); - ea_t oldstart = va_arg(va, ea_t); - ret = proxy->segm_start_changed(s, oldstart); -} -break; - -case idb_event::segm_end_changed: -{ - segment_t * s = va_arg(va, segment_t *); - ea_t oldend = va_arg(va, ea_t); - ret = proxy->segm_end_changed(s, oldend); -} -break; - -case idb_event::segm_moved: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - asize_t size = va_arg(va, asize_t); - ret = proxy->segm_moved(from, to, size); -} -break; - -case idb_event::area_cmt_changed: -{ - areacb_t * cb = va_arg(va, areacb_t *); - const area_t * a = va_arg(va, const area_t *); - const char * cmt = va_arg(va, const char *); - bool repeatable = bool(va_arg(va, int)); - ret = proxy->area_cmt_changed(cb, a, cmt, repeatable); -} -break; - -case idb_event::changing_cmt: -{ - ea_t ea = va_arg(va, ea_t); - bool repeatable_cmt = bool(va_arg(va, int)); - const char * newcmt = va_arg(va, const char *); - ret = proxy->changing_cmt(ea, repeatable_cmt, newcmt); -} -break; - -case idb_event::changing_ti: -{ - ea_t ea = va_arg(va, ea_t); - const type_t * new_type = va_arg(va, const type_t *); - const p_list * new_fnames = va_arg(va, const p_list *); - ret = proxy->changing_ti(ea, new_type, new_fnames); -} -break; - -case idb_event::changing_op_ti: -{ - ea_t ea = va_arg(va, ea_t); - int n = va_arg(va, int); - const type_t * new_type = va_arg(va, const type_t *); - const p_list * new_fnames = va_arg(va, const p_list *); - ret = proxy->changing_op_ti(ea, n, new_type, new_fnames); -} -break; - -case idb_event::changing_op_type: -{ - ea_t ea = va_arg(va, ea_t); - int n = va_arg(va, int); - ret = proxy->changing_op_type(ea, n); -} -break; - -case idb_event::deleting_enum: -{ - enum_t id = va_arg(va, enum_t); - ret = proxy->deleting_enum(id); -} -break; - -case idb_event::changing_enum_bf: -{ - enum_t id = va_arg(va, enum_t); - bool new_bf = bool(va_arg(va, int)); - ret = proxy->changing_enum_bf(id, new_bf); -} -break; - -case idb_event::renaming_enum: -{ - tid_t id = va_arg(va, tid_t); - bool is_enum = bool(va_arg(va, int)); - const char * newname = va_arg(va, const char *); - ret = proxy->renaming_enum(id, is_enum, newname); -} -break; - -case idb_event::changing_enum_cmt: -{ - tid_t id = va_arg(va, tid_t); - bool repeatable = bool(va_arg(va, int)); - const char * newcmt = va_arg(va, const char *); - ret = proxy->changing_enum_cmt(id, repeatable, newcmt); -} -break; - -case idb_event::deleting_enum_const: -{ - ret = proxy->deleting_enum_const(); -} -break; - -case idb_event::deleting_struc: -{ - struc_t * sptr = va_arg(va, struc_t *); - ret = proxy->deleting_struc(sptr); -} -break; - -case idb_event::renaming_struc: -{ - tid_t id = va_arg(va, tid_t); - const char * oldname = va_arg(va, const char *); - const char * newname = va_arg(va, const char *); - ret = proxy->renaming_struc(id, oldname, newname); -} -break; - -case idb_event::expanding_struc: -{ - struc_t * sptr = va_arg(va, struc_t *); - ea_t offset = va_arg(va, ea_t); - adiff_t delta = va_arg(va, adiff_t); - ret = proxy->expanding_struc(sptr, offset, delta); -} -break; - -case idb_event::changing_struc_cmt: -{ - tid_t struc_id = va_arg(va, tid_t); - bool repeatable = bool(va_arg(va, int)); - const char * newcmt = va_arg(va, const char *); - ret = proxy->changing_struc_cmt(struc_id, repeatable, newcmt); -} -break; - -case idb_event::deleting_struc_member: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - ret = proxy->deleting_struc_member(sptr, mptr); -} -break; - -case idb_event::renaming_struc_member: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - const char * newname = va_arg(va, const char *); - ret = proxy->renaming_struc_member(sptr, mptr, newname); -} -break; - -case idb_event::changing_struc_member: -{ - struc_t * sptr = va_arg(va, struc_t *); - member_t * mptr = va_arg(va, member_t *); - flags_t flag = va_arg(va, flags_t); - const opinfo_t * ti = va_arg(va, const opinfo_t *); - asize_t nbytes = va_arg(va, asize_t); - ret = proxy->changing_struc_member(sptr, mptr, flag, ti, nbytes); -} -break; - -case idb_event::removing_func_tail: -{ - func_t * pfn = va_arg(va, func_t *); - const area_t * tail = va_arg(va, const area_t *); - ret = proxy->removing_func_tail(pfn, tail); -} -break; - -case idb_event::deleting_segm: -{ - ea_t startEA = va_arg(va, ea_t); - ret = proxy->deleting_segm(startEA); -} -break; - -case idb_event::changing_segm_start: -{ - segment_t * s = va_arg(va, segment_t *); - ea_t new_start = va_arg(va, ea_t); - int segmod_flags = va_arg(va, int); - ret = proxy->changing_segm_start(s, new_start, segmod_flags); -} -break; - -case idb_event::changing_segm_end: -{ - segment_t * s = va_arg(va, segment_t *); - ea_t new_end = va_arg(va, ea_t); - int segmod_flags = va_arg(va, int); - ret = proxy->changing_segm_end(s, new_end, segmod_flags); -} -break; - -case idb_event::changing_area_cmt: -{ - areacb_t * cb = va_arg(va, areacb_t *); - const area_t * a = va_arg(va, const area_t *); - const char * cmt = va_arg(va, const char *); - bool repeatable = bool(va_arg(va, int)); - ret = proxy->changing_area_cmt(cb, a, cmt, repeatable); -} -break; - -case idb_event::changing_segm_name: -{ - segment_t * s = va_arg(va, segment_t *); - const char * oldname = va_arg(va, const char *); - ret = proxy->changing_segm_name(s, oldname); -} -break; - -case idb_event::changing_segm_class: -{ - segment_t * s = va_arg(va, segment_t *); - ret = proxy->changing_segm_class(s); -} -break; - -case idb_event::segm_name_changed: -{ - segment_t * s = va_arg(va, segment_t *); - const char * name = va_arg(va, const char *); - ret = proxy->segm_name_changed(s, name); -} -break; - -case idb_event::segm_class_changed: -{ - segment_t * s = va_arg(va, segment_t *); - const char * sclass = va_arg(va, const char *); - ret = proxy->segm_class_changed(s, sclass); -} -break; - -case idb_event::destroyed_items: -{ - ea_t ea1 = va_arg(va, ea_t); - ea_t ea2 = va_arg(va, ea_t); - bool will_disable_range = bool(va_arg(va, int)); - ret = proxy->destroyed_items(ea1, ea2, will_disable_range); -} -break; - -case idb_event::changed_stkpnts: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->changed_stkpnts(pfn); -} -break; - -case idb_event::extra_cmt_changed: -{ - ea_t ea = va_arg(va, ea_t); - int line_idx = va_arg(va, int); - const char * cmt = va_arg(va, const char *); - ret = proxy->extra_cmt_changed(ea, line_idx, cmt); -} -break; - -case idb_event::changing_struc: -{ - struc_t * sptr = va_arg(va, struc_t *); - ret = proxy->changing_struc(sptr); -} -break; - -case idb_event::changed_struc: -{ - struc_t * sptr = va_arg(va, struc_t *); - ret = proxy->changed_struc(sptr); -} -break; - -case idb_event::local_types_changed: -{ - ret = proxy->local_types_changed(); -} -break; - -case idb_event::segm_attrs_changed: -{ - segment_t * s = va_arg(va, segment_t *); - ret = proxy->segm_attrs_changed(s); -} -break; - -case idb_event::allsegs_moved: -{ - segm_move_infos_t * info = va_arg(va, segm_move_infos_t *); - ret = proxy->allsegs_moved(info); -} -break; - - } - } - 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; -} -// diff --git a/pywraps/py_idd.hpp b/pywraps/py_idd.hpp index 7ed17c5..0443002 100644 --- a/pywraps/py_idd.hpp +++ b/pywraps/py_idd.hpp @@ -9,31 +9,6 @@ static bool dbg_can_query() return dbg != NULL && (dbg->may_disturb() || get_process_state() < DSTATE_NOTASK); } -//------------------------------------------------------------------------- -static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - PyObject *py_list = PyList_New(areas.size()); - meminfo_vec_t::const_iterator it, it_end(areas.end()); - Py_ssize_t i = 0; - for ( it=areas.begin(); it!=it_end; ++it, ++i ) - { - const memory_info_t &mi = *it; - // startEA endEA name sclass sbase bitness perm - PyList_SetItem(py_list, i, - Py_BuildValue("(" PY_FMT64 PY_FMT64 "ss" PY_FMT64 "II)", - pyul_t(mi.startEA), - pyul_t(mi.endEA), - mi.name.c_str(), - mi.sclass.c_str(), - pyul_t(mi.sbase), - (unsigned int)(mi.bitness), - (unsigned int)mi.perm)); - } - return py_list; -} - //------------------------------------------------------------------------- PyObject *py_appcall( ea_t func_ea, @@ -56,7 +31,7 @@ PyObject *py_appcall( Py_ssize_t nargs = PyList_Size(arg_list); idc_args.resize(nargs); bool ok = true; - for ( Py_ssize_t i=0; iob_refcnt == 1); if ( (debug & IDA_DEBUG_APPCALL) != 0 ) { msg("return var:\n" @@ -207,7 +181,7 @@ static PyObject *dbg_get_registers() PyObject *py_list = PyList_New(dbg->registers_size); - for ( int i=0; iregisters_size; i++ ) + for ( int i=0; i < dbg->registers_size; i++ ) { register_info_t &ri = dbg->registers(i); PyObject *py_bits; @@ -218,7 +192,7 @@ static PyObject *dbg_get_registers() { int nbits = (int)b2a_width((int)get_dtyp_size(ri.dtyp), 0) * 4; py_bits = PyList_New(nbits); - for ( int i=0; i diff --git a/pywraps/py_idp.hpp b/pywraps/py_idp.hpp index e2cb0c2..fcb9bea 100644 --- a/pywraps/py_idp.hpp +++ b/pywraps/py_idp.hpp @@ -352,7 +352,7 @@ 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 @@ -908,944 +782,6 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va) switch ( notification_code ) { // hookgenIDP:notifications -case processor_t::init: -{ - const char * idp_modname = va_arg(va, const char *); - ret = proxy->init(idp_modname); -} -break; - -case processor_t::term: -{ - ret = proxy->term(); -} -break; - -case processor_t::newprc: -{ - int pnum = va_arg(va, int); - ret = proxy->newprc(pnum); -} -break; - -case processor_t::newasm: -{ - int asmnum = va_arg(va, int); - ret = proxy->newasm(asmnum); -} -break; - -case processor_t::newfile: -{ - char * fname = va_arg(va, char *); - ret = proxy->newfile(fname); -} -break; - -case processor_t::oldfile: -{ - char * fname = va_arg(va, char *); - ret = proxy->oldfile(fname); -} -break; - -case processor_t::newbinary: -{ - char * filename = va_arg(va, char *); - uint32 fileoff = va_arg(va, uint32); - ea_t basepara = va_arg(va, ea_t); - ea_t binoff = va_arg(va, ea_t); - uint32 nbytes = va_arg(va, uint32); - ret = proxy->newbinary(filename, fileoff, basepara, binoff, nbytes); -} -break; - -case processor_t::endbinary: -{ - bool ok = bool(va_arg(va, int)); - ret = proxy->endbinary(ok); -} -break; - -case processor_t::newseg: -{ - segment_t * seg = va_arg(va, segment_t *); - ret = proxy->newseg(seg); -} -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 = bool(va_arg(va, int)); - const char * line = va_arg(va, const char *); - uchar * bin = va_arg(va, uchar *); - PyObject * _tmp = proxy->assemble(ea, cs, ip, use32, line); - ret = IDP_Hooks::handle_assemble_output(_tmp, ea, cs, ip, use32, line, bin); -} -break; - -case processor_t::obsolete_makemicro: -{ - mblock_t * block = va_arg(va, mblock_t *); - ret = proxy->obsolete_makemicro(block); -} -break; - -case processor_t::outlabel: -{ - ea_t ea = va_arg(va, ea_t); - const char * colored_name = va_arg(va, const char *); - ret = proxy->outlabel(ea, colored_name); -} -break; - -case processor_t::rename: -{ - ea_t ea = va_arg(va, ea_t); - const char * new_name = va_arg(va, const char *); - int flags = va_arg(va, int); - qnotused(flags); - ret = proxy->rename(ea, new_name); -} -break; - -case processor_t::may_show_sreg: -{ - ea_t current_ea = va_arg(va, ea_t); - ret = proxy->may_show_sreg(current_ea); -} -break; - -case processor_t::closebase: -{ - ret = proxy->closebase(); -} -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::coagulate: -{ - ea_t start_ea = va_arg(va, ea_t); - ret = proxy->coagulate(start_ea); -} -break; - -case processor_t::auto_empty: -{ - proxy->auto_empty(); -} -break; - -case processor_t::auto_queue_empty: -{ - atype_t type = va_arg(va, atype_t); - ret = proxy->auto_queue_empty(type); -} -break; - -case processor_t::func_bounds: -{ - int * possible_return_code = va_arg(va, int *); - func_t * pfn = va_arg(va, func_t *); - ea_t max_func_end_ea = va_arg(va, ea_t); - proxy->func_bounds(possible_return_code, pfn, max_func_end_ea); -} -break; - -case processor_t::may_be_func: -{ - int state = va_arg(va, int); - ret = proxy->may_be_func(state); -} -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::is_jump_func: -{ - func_t * pfn = va_arg(va, func_t *); - ea_t * jump_target = va_arg(va, ea_t *); - ea_t * func_pointer = va_arg(va, ea_t *); - ret = proxy->is_jump_func(pfn, jump_target, func_pointer); -} -break; - -case processor_t::gen_regvar_def: -{ - regvar_t * v = va_arg(va, regvar_t *); - ret = proxy->gen_regvar_def(v); -} -break; - -case processor_t::setsgr: -{ - ea_t startEA = va_arg(va, ea_t); - ea_t endEA = va_arg(va, ea_t); - int regnum = va_arg(va, int); - sel_t value = va_arg(va, sel_t); - sel_t old_value = va_arg(va, sel_t); - uchar tag = uchar(va_arg(va, int)); - ret = proxy->setsgr(startEA, endEA, regnum, value, old_value, tag); -} -break; - -case processor_t::set_compiler: -{ - ret = proxy->set_compiler(); -} -break; - -case processor_t::is_basic_block_end: -{ - bool call_insn_stops_block = bool(va_arg(va, int)); - ret = proxy->is_basic_block_end(call_insn_stops_block); -} -break; - -case processor_t::reglink: -{ - ret = proxy->reglink(); -} -break; - -case processor_t::get_vxd_name: -{ - int vxdnum = va_arg(va, int); - int funcnum = va_arg(va, int); - char * outbuf = va_arg(va, char *); - proxy->get_vxd_name(vxdnum, funcnum, outbuf); -} -break; - -case processor_t::custom_ana: -{ - bool _tmp = proxy->custom_ana(); - ret = IDP_Hooks::bool_to_cmdsize(_tmp); -} -break; - -case processor_t::custom_out: -{ - bool _tmp = proxy->custom_out(); - ret = IDP_Hooks::bool_to_2or0(_tmp); -} -break; - -case processor_t::custom_emu: -{ - bool _tmp = proxy->custom_emu(); - ret = IDP_Hooks::bool_to_2or0(_tmp); -} -break; - -case processor_t::custom_outop: -{ - op_t * op = va_arg(va, op_t *); - ref_t clinked_op = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op); - if ( clinked_op == NULL ) - break; - bool _tmp = proxy->custom_outop(clinked_op.o); - ret = IDP_Hooks::bool_to_2or0(_tmp); -} -break; - -case processor_t::custom_mnem: -{ - char * buf = va_arg(va, char *); - size_t bufsize = va_arg(va, size_t); - PyObject * _tmp = proxy->custom_mnem(); - ret = IDP_Hooks::handle_custom_mnem_output(_tmp, buf, bufsize); -} -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::moving_segm: -{ - segment_t * seg = va_arg(va, segment_t *); - ea_t to = va_arg(va, ea_t); - int flags = va_arg(va, int); - ret = proxy->moving_segm(seg, to, flags); -} -break; - -case processor_t::move_segm: -{ - ea_t from = va_arg(va, ea_t); - segment_t * seg = va_arg(va, segment_t *); - proxy->move_segm(from, seg); -} -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 = bool(va_arg(va, int)); - ret = proxy->is_ret_insn(ea, strict); -} -break; - -case processor_t::get_stkvar_scale_factor: -{ - ret = proxy->get_stkvar_scale_factor(); -} -break; - -case processor_t::create_flat_group: -{ - ea_t image_base = va_arg(va, ea_t); - int bitness = va_arg(va, int); - sel_t dataseg_sel = va_arg(va, sel_t); - ret = proxy->create_flat_group(image_base, bitness, dataseg_sel); -} -break; - -case processor_t::kernel_config_loaded: -{ - proxy->kernel_config_loaded(); -} -break; - -case processor_t::might_change_sp: -{ - ea_t ea = va_arg(va, ea_t); - ret = proxy->might_change_sp(ea); -} -break; - -case processor_t::is_alloca_probe: -{ - ea_t ea = va_arg(va, ea_t); - ret = proxy->is_alloca_probe(ea); -} -break; - -case processor_t::out_3byte: -{ - ea_t dataea = va_arg(va, ea_t); - uint32 value = va_arg(va, uint32); - bool analyze_only = bool(va_arg(va, int)); - ret = proxy->out_3byte(dataea, value, analyze_only); -} -break; - -case processor_t::get_reg_name: -{ - int reg = va_arg(va, int); - size_t width = va_arg(va, size_t); - char * buf = va_arg(va, char *); - size_t bufsize = va_arg(va, size_t); - int reghi = va_arg(va, int); - PyObject * _tmp = proxy->get_reg_name(reg, width, reghi); - ret = IDP_Hooks::handle_get_reg_name_output(_tmp, reg, width, buf, bufsize, reghi); -} -break; - -case processor_t::savebase: -{ - proxy->savebase(); -} -break; - -case processor_t::gen_asm_or_lst: -{ - bool starting = bool(va_arg(va, int)); - FILE * fp = va_arg(va, FILE *); - bool is_asm = bool(va_arg(va, int)); - int flags = va_arg(va, int); - gen_outline_t ** outline = va_arg(va, gen_outline_t **); - proxy->gen_asm_or_lst(starting, fp, is_asm, flags, outline); -} -break; - -case processor_t::out_src_file_lnnum: -{ - ret = proxy->out_src_file_lnnum(); -} -break; - -case processor_t::get_autocmt: -{ - char * buf = va_arg(va, char *); - size_t bufsize = va_arg(va, size_t); - ret = proxy->get_autocmt(buf, bufsize); -} -break; - -case processor_t::is_insn_table_jump: -{ - ret = proxy->is_insn_table_jump(); -} -break; - -case processor_t::auto_empty_finally: -{ - proxy->auto_empty_finally(); -} -break; - -case processor_t::loader_finished: -{ - linput_t * li = va_arg(va, linput_t *); - uint16 neflags = uint16(va_arg(va, int)); - const char * filetypename = va_arg(va, const char *); - ret = proxy->loader_finished(li, neflags, filetypename); -} -break; - -case processor_t::loader_elf_machine: -{ - linput_t * li = va_arg(va, linput_t *); - int machine_type = va_arg(va, int); - const char ** p_procname = va_arg(va, const char **); - proc_def ** p_pd = va_arg(va, proc_def **); - set_elf_reloc_t * set_reloc = va_arg(va, set_elf_reloc_t *); - ret = proxy->loader_elf_machine(li, machine_type, p_procname, p_pd, set_reloc); -} -break; - -case processor_t::is_indirect_jump: -{ - ret = proxy->is_indirect_jump(); -} -break; - -case processor_t::verify_noreturn: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->verify_noreturn(pfn); -} -break; - -case processor_t::verify_sp: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->verify_sp(pfn); -} -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 = bool(va_arg(va, int)); - proxy->renamed(ea, new_name, local_name); -} -break; - -case processor_t::add_func: -{ - func_t * pfn = va_arg(va, func_t *); - proxy->add_func(pfn); -} -break; - -case processor_t::del_func: -{ - func_t * pfn = va_arg(va, func_t *); - ret = proxy->del_func(pfn); -} -break; - -case processor_t::set_func_start: -{ - func_t * pfn = va_arg(va, func_t *); - ea_t new_start = va_arg(va, ea_t); - ret = proxy->set_func_start(pfn, new_start); -} -break; - -case processor_t::set_func_end: -{ - func_t * pfn = va_arg(va, func_t *); - ea_t new_end = va_arg(va, ea_t); - ret = proxy->set_func_end(pfn, new_end); -} -break; - -case processor_t::treat_hindering_item: -{ - ea_t hindering_item_ea = va_arg(va, ea_t); - flags_t new_item_flags = va_arg(va, flags_t); - ea_t new_item_ea = va_arg(va, ea_t); - asize_t new_item_length = va_arg(va, asize_t); - ret = proxy->treat_hindering_item(hindering_item_ea, new_item_flags, new_item_ea, new_item_length); -} -break; - -case processor_t::str2reg: -{ - const char * regname = va_arg(va, const char *); - ret = proxy->str2reg(regname); -} -break; - -case processor_t::create_switch_xrefs: -{ - ea_t jumpea = va_arg(va, ea_t); - switch_info_ex_t * si = va_arg(va, switch_info_ex_t *); - ret = proxy->create_switch_xrefs(jumpea, si); -} -break; - -case processor_t::calc_switch_cases: -{ - ea_t insn_ea = va_arg(va, ea_t); - switch_info_ex_t * si = va_arg(va, switch_info_ex_t *); - casevec_t * casevec = va_arg(va, casevec_t *); - eavec_t * targets = va_arg(va, eavec_t *); - ret = proxy->calc_switch_cases(insn_ea, si, casevec, targets); -} -break; - -case processor_t::determined_main: -{ - ea_t main = va_arg(va, ea_t); - proxy->determined_main(main); -} -break; - -case processor_t::preprocess_chart: -{ - qflow_chart_t * fc = va_arg(va, qflow_chart_t *); - proxy->preprocess_chart(fc); -} -break; - -case processor_t::get_bg_color: -{ - ea_t ea = va_arg(va, ea_t); - bgcolor_t color = va_arg(va, bgcolor_t); - ret = proxy->get_bg_color(ea, color); -} -break; - -case processor_t::validate_flirt_func: -{ - ea_t start_ea = va_arg(va, ea_t); - const char * funcname = va_arg(va, const char *); - ret = proxy->validate_flirt_func(start_ea, funcname); -} -break; - -case processor_t::get_operand_string: -{ - int opnum = va_arg(va, int); - char * buf = va_arg(va, char *); - size_t buflen = va_arg(va, size_t); - ret = proxy->get_operand_string(opnum, buf, buflen); -} -break; - -case processor_t::add_cref: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - cref_t type = cref_t(va_arg(va, int)); - ret = proxy->add_cref(from, to, type); -} -break; - -case processor_t::add_dref: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - dref_t type = dref_t(va_arg(va, int)); - ret = proxy->add_dref(from, to, type); -} -break; - -case processor_t::del_cref: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - bool expand = bool(va_arg(va, int)); - ret = proxy->del_cref(from, to, expand); -} -break; - -case processor_t::del_dref: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - ret = proxy->del_dref(from, to); -} -break; - -case processor_t::coagulate_dref: -{ - ea_t from = va_arg(va, ea_t); - ea_t to = va_arg(va, ea_t); - bool may_define = bool(va_arg(va, int)); - ea_t * code_ea = va_arg(va, ea_t *); - ret = proxy->coagulate_dref(from, to, may_define, code_ea); -} -break; - -case processor_t::register_custom_fixup: -{ - const char * name = va_arg(va, const char *); - ret = proxy->register_custom_fixup(name); -} -break; - -case processor_t::custom_refinfo: -{ - ea_t ea = va_arg(va, ea_t); - int numop = va_arg(va, int); - ea_t * opval = va_arg(va, ea_t *); - const refinfo_t* ri = va_arg(va, const refinfo_t*); - char * buf = va_arg(va, char *); - size_t bufsize = va_arg(va, size_t); - ea_t * target = va_arg(va, ea_t *); - ea_t * fullvalue = va_arg(va, ea_t *); - ea_t from = va_arg(va, ea_t); - int getn_flags = va_arg(va, int); - ret = proxy->custom_refinfo(ea, numop, opval, ri, buf, bufsize, target, fullvalue, from, getn_flags); -} -break; - -case processor_t::set_proc_options: -{ - const char * options = va_arg(va, const char *); - ret = proxy->set_proc_options(options); -} -break; - -case processor_t::adjust_libfunc_ea: -{ - const idasgn_t * sig = va_arg(va, const idasgn_t *); - const libfunc_t * libfun = va_arg(va, const libfunc_t *); - ea_t * ea = va_arg(va, ea_t *); - ret = proxy->adjust_libfunc_ea(sig, libfun, ea); -} -break; - -case processor_t::extlang_changed: -{ - int kind = va_arg(va, int); - const extlang_t * el = va_arg(va, const extlang_t *); - proxy->extlang_changed(kind, el); -} -break; - -case processor_t::delay_slot_insn: -{ - ea_t * ea = va_arg(va, ea_t *); - ret = proxy->delay_slot_insn(ea); -} -break; - -case processor_t::obsolete_get_operand_info: -{ - ret = proxy->obsolete_get_operand_info(); -} -break; - -case processor_t::get_jump_target: -{ - ea_t ea = va_arg(va, ea_t); - int tid = va_arg(va, int); - processor_t::regval_getter_t getreg = va_arg(va, processor_t::regval_getter_t); - const regval_t * regvalues = va_arg(va, const regval_t *); - ea_t * target = va_arg(va, ea_t *); - ret = proxy->get_jump_target(ea, tid, getreg, regvalues, target); -} -break; - -case processor_t::calc_step_over: -{ - ea_t ip = va_arg(va, ea_t); - ea_t * target = va_arg(va, ea_t *); - ret = proxy->calc_step_over(ip, target); -} -break; - -case processor_t::get_macro_insn_head: -{ - ea_t ip = va_arg(va, ea_t); - ea_t * head = va_arg(va, ea_t *); - ret = proxy->get_macro_insn_head(ip, head); -} -break; - -case processor_t::get_dbr_opnum: -{ - ea_t ea = va_arg(va, ea_t); - int * opnum = va_arg(va, int *); - ret = proxy->get_dbr_opnum(ea, opnum); -} -break; - -case processor_t::insn_reads_tbit: -{ - ea_t ea = va_arg(va, ea_t); - processor_t::regval_getter_t getreg = va_arg(va, processor_t::regval_getter_t); - const regval_t * regvalues = va_arg(va, const regval_t *); - ret = proxy->insn_reads_tbit(ea, getreg, regvalues); -} -break; - -case processor_t::get_operand_info: -{ - ea_t ea = va_arg(va, ea_t); - int n = va_arg(va, int); - int thread_id = va_arg(va, int); - processor_t::regval_getter_t getreg = va_arg(va, processor_t::regval_getter_t); - const regval_t * regvalues = va_arg(va, const regval_t *); - idd_opinfo_t * opinf = va_arg(va, idd_opinfo_t *); - ret = proxy->get_operand_info(ea, n, thread_id, getreg, regvalues, opinf); -} -break; - -case processor_t::calc_next_eas: -{ - bool over = bool(va_arg(va, int)); - ea_t * res = va_arg(va, ea_t *); - int * nsubcalls = va_arg(va, int *); - ret = proxy->calc_next_eas(over, res, nsubcalls); -} -break; - -case processor_t::clean_tbit: -{ - ea_t ea = va_arg(va, ea_t); - processor_t::regval_getter_t getreg = va_arg(va, processor_t::regval_getter_t); - const regval_t * regvalues = va_arg(va, const regval_t *); - ret = proxy->clean_tbit(ea, getreg, regvalues); -} -break; - -case processor_t::get_reg_info2: -{ - const char * regname = va_arg(va, const char *); - const char ** main_regname = va_arg(va, const char **); - bitrange_t * bitrange = va_arg(va, bitrange_t *); - ret = proxy->get_reg_info2(regname, main_regname, bitrange); -} -break; - -case processor_t::setup_til: -{ - proxy->setup_til(); -} -break; - -case processor_t::based_ptr: -{ - unsigned ptrt = va_arg(va, unsigned); - const char ** ptrname = va_arg(va, const char **); - ret = proxy->based_ptr(ptrt, ptrname); -} -break; - -case processor_t::max_ptr_size: -{ - ret = proxy->max_ptr_size(); -} -break; - -case processor_t::get_default_enum_size: -{ - cm_t cm = cm_t(va_arg(va, int)); - ret = proxy->get_default_enum_size(cm); -} -break; - -case processor_t::calc_cdecl_purged_bytes2: -{ - ret = proxy->calc_cdecl_purged_bytes2(); -} -break; - -case processor_t::get_stkarg_offset2: -{ - ret = proxy->get_stkarg_offset2(); -} -break; - -case processor_t::til_for_file: -{ - ret = proxy->til_for_file(); -} -break; - -case processor_t::equal_reglocs: -{ - argloc_t * a1 = va_arg(va, argloc_t *); - argloc_t * a2 = va_arg(va, argloc_t *); - ret = proxy->equal_reglocs(a1, a2); -} -break; - -case processor_t::decorate_name3: -{ - qstring * outbuf = va_arg(va, qstring *); - const char * name = va_arg(va, const char *); - bool mangle = bool(va_arg(va, int)); - cm_t cc = cm_t(va_arg(va, int)); - PyObject * _tmp = proxy->decorate_name3(name, mangle, IDP_Hooks::cm_t_to_int(cc)); - ret = IDP_Hooks::handle_decorate_name3_output(_tmp, outbuf, name, mangle, cc); -} -break; - -case processor_t::calc_retloc3: -{ - const tinfo_t * rettype = va_arg(va, const tinfo_t *); - cm_t cc = cm_t(va_arg(va, int)); - argloc_t * retloc = va_arg(va, argloc_t *); - ret = proxy->calc_retloc3(rettype, cc, retloc); -} -break; - -case processor_t::calc_varglocs3: -{ - const func_type_data_t * ftd = va_arg(va, const func_type_data_t *); - regobjs_t * regs = va_arg(va, regobjs_t *); - relobj_t * stkargs = va_arg(va, relobj_t *); - int nfixed = va_arg(va, int); - ret = proxy->calc_varglocs3(ftd, regs, stkargs, nfixed); -} -break; - -case processor_t::calc_arglocs3: -{ - func_type_data_t * fti = va_arg(va, func_type_data_t *); - ret = proxy->calc_arglocs3(fti); -} -break; - -case processor_t::use_stkarg_type3: -{ - ea_t ea = va_arg(va, ea_t); - const funcarg_t * arg = va_arg(va, const funcarg_t *); - ret = proxy->use_stkarg_type3(ea, arg); -} -break; - -case processor_t::use_regarg_type3: -{ - int * idx = va_arg(va, int *); - ea_t ea = va_arg(va, ea_t); - const funcargvec_t * rargs = va_arg(va, const funcargvec_t *); - ret = proxy->use_regarg_type3(idx, ea, rargs); -} -break; - -case processor_t::use_arg_types3: -{ - ea_t ea = va_arg(va, ea_t); - func_type_data_t * fti = va_arg(va, func_type_data_t *); - funcargvec_t * rargs = va_arg(va, funcargvec_t *); - ret = proxy->use_arg_types3(ea, fti, rargs); -} -break; - -case processor_t::calc_purged_bytes3: -{ - int * p_purged_bytes = va_arg(va, int *); - const func_type_data_t * fti = va_arg(va, const func_type_data_t *); - ret = proxy->calc_purged_bytes3(p_purged_bytes, fti); -} -break; - -case processor_t::shadow_args_size: -{ - int * shadow_args_size = va_arg(va, int *); - func_t * pfn = va_arg(va, func_t *); - ret = proxy->shadow_args_size(shadow_args_size, pfn); -} -break; - -case processor_t::get_varcall_regs3: -{ - callregs_t * regs = va_arg(va, callregs_t *); - ret = proxy->get_varcall_regs3(regs); -} -break; - -case processor_t::get_fastcall_regs3: -{ - callregs_t * regs = va_arg(va, callregs_t *); - ret = proxy->get_fastcall_regs3(regs); -} -break; - -case processor_t::get_thiscall_regs3: -{ - callregs_t * regs = va_arg(va, callregs_t *); - ret = proxy->get_thiscall_regs3(regs); -} -break; - -case processor_t::get_func_cvtarg_map: -{ - const func_type_data_t * fti = va_arg(va, const func_type_data_t *); - intvec_t * argnums = va_arg(va, intvec_t *); - ret = proxy->get_func_cvtarg_map(fti, argnums); -} -break; - -case processor_t::get_simd_types: -{ - const simd_info_t * simd_attrs = va_arg(va, const simd_info_t *); - const argloc_t * argloc = va_arg(va, const argloc_t *); - simd_info_vec_t * out = va_arg(va, simd_info_vec_t *); - bool create_tifs = bool(va_arg(va, int)); - ret = proxy->get_simd_types(simd_attrs, argloc, out, create_tifs); -} -break; - -case processor_t::loader: -{ - ret = proxy->loader(); -} -break; - } } catch (Swig::DirectorException &e) @@ -1871,7 +807,6 @@ static const regval_t *idaapi _py_getreg( static regval_t rv; return &rv; } - //------------------------------------------------------------------------- // //------------------------------------------------------------------------- diff --git a/pywraps/py_idp.py b/pywraps/py_idp.py new file mode 100644 index 0000000..0c3ea17 --- /dev/null +++ b/pywraps/py_idp.py @@ -0,0 +1,232 @@ +# + +#---------------------------------------------------------------------------- +# P R O C E S S O R M O D U L E S C O N S T A N T S +#---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------- +# processor_t related constants + +CUSTOM_CMD_ITYPE = 0x8000 +REG_SPOIL = 0x80000000 + +REAL_ERROR_FORMAT = -1 # not supported format for current .idp +REAL_ERROR_RANGE = -2 # number too big (small) for store (mem NOT modifyed) +REAL_ERROR_BADDATA = -3 # illegal real data for load (IEEE data not filled) + +# +# Check whether the operand is relative to stack pointer or frame pointer. +# This function is used to determine how to output a stack variable +# This function may be absent. If it is absent, then all operands +# are sp based by default. +# Define this function only if some stack references use frame pointer +# instead of stack pointer. +# returns flags: +OP_FP_BASED = 0x00000000 # operand is FP based +OP_SP_BASED = 0x00000001 # operand is SP based +OP_SP_ADD = 0x00000000 # operand value is added to the pointer +OP_SP_SUB = 0x00000002 # operand value is substracted from the pointer + +# processor_t.id +PLFM_386 = 0 # Intel 80x86 +PLFM_Z80 = 1 # 8085, Z80 +PLFM_I860 = 2 # Intel 860 +PLFM_8051 = 3 # 8051 +PLFM_TMS = 4 # Texas Instruments TMS320C5x +PLFM_6502 = 5 # 6502 +PLFM_PDP = 6 # PDP11 +PLFM_68K = 7 # Motoroal 680x0 +PLFM_JAVA = 8 # Java +PLFM_6800 = 9 # Motorola 68xx +PLFM_ST7 = 10 # SGS-Thomson ST7 +PLFM_MC6812 = 11 # Motorola 68HC12 +PLFM_MIPS = 12 # MIPS +PLFM_ARM = 13 # Advanced RISC Machines +PLFM_TMSC6 = 14 # Texas Instruments TMS320C6x +PLFM_PPC = 15 # PowerPC +PLFM_80196 = 16 # Intel 80196 +PLFM_Z8 = 17 # Z8 +PLFM_SH = 18 # Renesas (formerly Hitachi) SuperH +PLFM_NET = 19 # Microsoft Visual Studio.Net +PLFM_AVR = 20 # Atmel 8-bit RISC processor(s) +PLFM_H8 = 21 # Hitachi H8/300, H8/2000 +PLFM_PIC = 22 # Microchip's PIC +PLFM_SPARC = 23 # SPARC +PLFM_ALPHA = 24 # DEC Alpha +PLFM_HPPA = 25 # Hewlett-Packard PA-RISC +PLFM_H8500 = 26 # Hitachi H8/500 +PLFM_TRICORE = 27 # Tasking Tricore +PLFM_DSP56K = 28 # Motorola DSP5600x +PLFM_C166 = 29 # Siemens C166 family +PLFM_ST20 = 30 # SGS-Thomson ST20 +PLFM_IA64 = 31 # Intel Itanium IA64 +PLFM_I960 = 32 # Intel 960 +PLFM_F2MC = 33 # Fujistu F2MC-16 +PLFM_TMS320C54 = 34 # Texas Instruments TMS320C54xx +PLFM_TMS320C55 = 35 # Texas Instruments TMS320C55xx +PLFM_TRIMEDIA = 36 # Trimedia +PLFM_M32R = 37 # Mitsubishi 32bit RISC +PLFM_NEC_78K0 = 38 # NEC 78K0 +PLFM_NEC_78K0S = 39 # NEC 78K0S +PLFM_M740 = 40 # Mitsubishi 8bit +PLFM_M7700 = 41 # Mitsubishi 16bit +PLFM_ST9 = 42 # ST9+ +PLFM_FR = 43 # Fujitsu FR Family +PLFM_MC6816 = 44 # Motorola 68HC16 +PLFM_M7900 = 45 # Mitsubishi 7900 +PLFM_TMS320C3 = 46 # Texas Instruments TMS320C3 +PLFM_KR1878 = 47 # Angstrem KR1878 +PLFM_AD218X = 48 # Analog Devices ADSP 218X +PLFM_OAKDSP = 49 # Atmel OAK DSP +PLFM_TLCS900 = 50 # Toshiba TLCS-900 +PLFM_C39 = 51 # Rockwell C39 +PLFM_CR16 = 52 # NSC CR16 +PLFM_MN102L00 = 53 # Panasonic MN10200 +PLFM_TMS320C1X = 54 # Texas Instruments TMS320C1x +PLFM_NEC_V850X = 55 # NEC V850 and V850ES/E1/E2 +PLFM_SCR_ADPT = 56 # Processor module adapter for processor modules written in scripting languages +PLFM_EBC = 57 # EFI Bytecode +PLFM_MSP430 = 58 # Texas Instruments MSP430 +PLFM_SPU = 59 # Cell Broadband Engine Synergistic Processor Unit + +# +# processor_t.flag +# +PR_SEGS = 0x000001 # has segment registers? +PR_USE32 = 0x000002 # supports 32-bit addressing? +PR_DEFSEG32 = 0x000004 # segments are 32-bit by default +PR_RNAMESOK = 0x000008 # allow to user register names for location names +PR_ADJSEGS = 0x000020 # IDA may adjust segments moving their starting/ending addresses. +PR_DEFNUM = 0x0000C0 # default number representation: +PRN_HEX = 0x000000 # hex +PRN_OCT = 0x000040 # octal +PRN_DEC = 0x000080 # decimal +PRN_BIN = 0x0000C0 # binary +PR_WORD_INS = 0x000100 # instruction codes are grouped 2bytes in binrary line prefix +PR_NOCHANGE = 0x000200 # The user can't change segments and code/data attributes (display only) +PR_ASSEMBLE = 0x000400 # Module has a built-in assembler and understands IDP_ASSEMBLE +PR_ALIGN = 0x000800 # All data items should be aligned properly +PR_TYPEINFO = 0x001000 # the processor module supports + # type information callbacks + # ALL OF THEM SHOULD BE IMPLEMENTED! + # (the ones >= decorate_name) +PR_USE64 = 0x002000 # supports 64-bit addressing? +PR_SGROTHER = 0x004000 # the segment registers don't contain + # the segment selectors, something else +PR_STACK_UP = 0x008000 # the stack grows up +PR_BINMEM = 0x010000 # the processor module provides correct + # segmentation for binary files + # (i.e. it creates additional segments) + # The kernel will not ask the user + # to specify the RAM/ROM sizes +PR_SEGTRANS = 0x020000 # the processor module supports + # the segment translation feature + # (it means it calculates the code + # addresses using the codeSeg() function) +PR_CHK_XREF = 0x040000 # don't allow near xrefs between segments + # with different bases +PR_NO_SEGMOVE = 0x080000 # the processor module doesn't support move_segm() + # (i.e. the user can't move segments) +PR_FULL_HIFXP = 0x100000 # REF_VHIGH operand value contains full operand + # not only the high bits. Meaningful if ph.high_fixup_bits +PR_USE_ARG_TYPES = 0x200000 # use ph.use_arg_types callback +PR_SCALE_STKVARS = 0x400000 # use ph.get_stkvar_scale callback +PR_DELAYED = 0x800000 # has delayed jumps and calls +PR_ALIGN_INSN = 0x1000000 # allow ida to create alignment instructions + # arbirtrarily. Since these instructions + # might lead to other wrong instructions + # and spoil the listing, IDA does not create + # them by default anymore +PR_PURGING = 0x2000000 # there are calling conventions which may + # purge bytes from the stack +PR_CNDINSNS = 0x4000000 # has conditional instructions +PR_USE_TBYTE = 0x8000000 # BTMT_SPECFLT means _TBYTE type +PR_DEFSEG64 = 0x10000000 # segments are 64-bit by default + + +# ---------------------------------------------------------------------- +# instruc_t related constants + +# +# instruc_t.feature +# +CF_STOP = 0x00001 # Instruction doesn't pass execution to the next instruction +CF_CALL = 0x00002 # CALL instruction (should make a procedure here) +CF_CHG1 = 0x00004 # The instruction modifies the first operand +CF_CHG2 = 0x00008 # The instruction modifies the second operand +CF_CHG3 = 0x00010 # The instruction modifies the third operand +CF_CHG4 = 0x00020 # The instruction modifies 4 operand +CF_CHG5 = 0x00040 # The instruction modifies 5 operand +CF_CHG6 = 0x00080 # The instruction modifies 6 operand +CF_USE1 = 0x00100 # The instruction uses value of the first operand +CF_USE2 = 0x00200 # The instruction uses value of the second operand +CF_USE3 = 0x00400 # The instruction uses value of the third operand +CF_USE4 = 0x00800 # The instruction uses value of the 4 operand +CF_USE5 = 0x01000 # The instruction uses value of the 5 operand +CF_USE6 = 0x02000 # The instruction uses value of the 6 operand +CF_JUMP = 0x04000 # The instruction passes execution using indirect jump or call (thus needs additional analysis) +CF_SHFT = 0x08000 # Bit-shift instruction (shl,shr...) +CF_HLL = 0x10000 # Instruction may be present in a high level language function. + +# +# Set IDP options constants +# +IDPOPT_STR = 1 # string constant +IDPOPT_NUM = 2 # number +IDPOPT_BIT = 3 # bit, yes/no +IDPOPT_FLT = 4 # float +IDPOPT_I64 = 5 # 64bit number + +IDPOPT_OK = 0 # ok +IDPOPT_BADKEY = 1 # illegal keyword +IDPOPT_BADTYPE = 2 # illegal type of value +IDPOPT_BADVALUE = 3 # illegal value (bad range, for example) + +# ---------------------------------------------------------------------- +import ida_ua +class processor_t(ida_idaapi.pyidc_opaque_object_t): + """Base class for all processor module scripts""" + def __init__(self): + # Take a reference to 'cmd' + self.cmd = ida_ua.cmd + + def get_idpdesc(self): + """ + This function must be present and should return the list of + short processor names similar to the one in ph.psnames. + This method can be overridden to return to the kernel a different IDP description. + """ + return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames))) + + def get_uFlag(self): + """Use this utility function to retrieve the 'uFlag' global variable""" + return ida_ua.cvar.uFlag + + def get_auxpref(self): + """This function returns cmd.auxpref value""" + return self.cmd.auxpref + + +# ---------------------------------------------------------------------- +class __ph(object): + id = property(lambda self: ph_get_id()) + cnbits = property(lambda self: ph_get_cnbits()) + dnbits = property(lambda self: ph_get_dnbits()) + flag = property(lambda self: ph_get_flag()) + high_fixup_bits = property(lambda self: ph_get_high_fixup_bits()) + icode_return = property(lambda self: ph_get_icode_return()) + instruc = property(lambda self: ph_get_instruc()) + instruc_end = property(lambda self: ph_get_instruc_end()) + instruc_start = property(lambda self: ph_get_instruc_start()) + regCodeSreg = property(lambda self: ph_get_regCodeSreg()) + regDataSreg = property(lambda self: ph_get_regDataSreg()) + regFirstSreg = property(lambda self: ph_get_regFirstSreg()) + regLastSreg = property(lambda self: ph_get_regLastSreg()) + regnames = property(lambda self: ph_get_regnames()) + segreg_size = property(lambda self: ph_get_segreg_size()) + tbyte_size = property(lambda self: ph_get_tbyte_size()) + version = property(lambda self: ph_get_version()) + +ph = __ph() + +# diff --git a/pywraps/py_idp_idbhooks.hpp b/pywraps/py_idp_idbhooks.hpp new file mode 100644 index 0000000..5f40831 --- /dev/null +++ b/pywraps/py_idp_idbhooks.hpp @@ -0,0 +1,51 @@ + +// + +//--------------------------------------------------------------------------- +// 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); + } + + // hookgenIDB:methods +}; +// + + +// +//--------------------------------------------------------------------------- +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; + int ret = 0; + try + { + switch ( notification_code ) + { + // hookgenIDB:notifications + } + } + 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; +} +// diff --git a/pywraps/py_kernwin.hpp b/pywraps/py_kernwin.hpp index 7b6db62..ba66780 100644 --- a/pywraps/py_kernwin.hpp +++ b/pywraps/py_kernwin.hpp @@ -1,6 +1,32 @@ #ifndef __PY_KERNWIN__ #define __PY_KERNWIN__ + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +//--------------------------------------------------------------------------- +// Context structure used by add|del_menu_item() +struct py_add_del_menu_item_ctx +{ + qstring menupath; + PyObject *cb_data; +}; + +//--------------------------------------------------------------------------- +// Context structure used by add|del_idc_hotkey() +struct py_idchotkey_ctx_t +{ + qstring hotkey; + PyObject *pyfunc; +}; + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + + //------------------------------------------------------------------------ // //------------------------------------------------------------------------ @@ -41,27 +67,20 @@ static PyObject *py_register_timer(int interval, PyObject *py_callback) // Timer has been unregistered? if ( ret == -1 ) - { - // Free the context - Py_DECREF(ctx->pycallback); - delete ctx; - } + python_timer_del(ctx); return ret; }; }; - py_timer_ctx_t *ctx = new py_timer_ctx_t(); - ctx->pycallback = py_callback; - Py_INCREF(py_callback); + py_timer_ctx_t *ctx = python_timer_new(py_callback); ctx->timer_id = register_timer( - interval, - tmr_t::callback, - ctx); + interval, + tmr_t::callback, + ctx); if ( ctx->timer_id == NULL ) { - Py_DECREF(py_callback); - delete ctx; + python_timer_del(ctx); Py_RETURN_NONE; } return PyCObject_FromVoidPtr(ctx, NULL); @@ -89,12 +108,11 @@ static PyObject *py_unregister_timer(PyObject *py_timerctx) Py_RETURN_FALSE; py_timer_ctx_t *ctx = (py_timer_ctx_t *) PyCObject_AsVoidPtr(py_timerctx); - if ( !unregister_timer(ctx->timer_id) ) + if ( ctx == NULL || !unregister_timer(ctx->timer_id) ) Py_RETURN_FALSE; - Py_DECREF(ctx->pycallback); - delete ctx; - + python_timer_del(ctx); + PyCObject_SetVoidPtr(py_timerctx, NULL); Py_RETURN_TRUE; } @@ -693,8 +711,6 @@ def execute_sync(callable, reqf): If the current thread not the main thread, then the call is queued and executed afterwards. - @note: The Python version of execute_sync() cannot be called from a different thread - for the time being. @param callable: A python callable object @param reqf: one of MFF_ flags @return: -1 or the return value of the callable @@ -823,9 +839,9 @@ static bool py_execute_ui_requests(PyObject *py_list) bool init(PyObject *py_list) { Py_ssize_t count = pyvar_walk_list( - py_list, - s_py_list_walk_cb, - this); + py_list, + s_py_list_walk_cb, + this); return count > 0; } @@ -1065,31 +1081,6 @@ public: } // hookgenUI:methods -virtual void range() {} -virtual void idcstart() {} -virtual void idcstop() {} -virtual void suspend() {} -virtual void resume() {} -virtual void saving() {} -virtual void saved() {} -virtual void term() {} -virtual int debugger_menu_change(bool enable) {qnotused(enable); return 1;} -virtual void tform_visible(TForm * form, void * HWND) {qnotused(form); qnotused(HWND); } -virtual void tform_invisible(TForm * form, void * HWND) {qnotused(form); qnotused(HWND); } -virtual PyObject * get_ea_hint(ea_t ea) {qnotused(ea); Py_RETURN_NONE;} -virtual PyObject * get_item_hint(ea_t ea, int max_lines) {qnotused(ea); qnotused(max_lines); Py_RETURN_NONE;} -virtual PyObject * get_custom_viewer_hint(TCustomControl* viewer, place_t * place) {qnotused(viewer); qnotused(place); Py_RETURN_NONE;} -virtual void database_inited(int is_new_database, const char * idc_script) {qnotused(is_new_database); qnotused(idc_script); } -virtual void ready_to_run() {} -virtual void preprocess(const char * name) {qnotused(name); } -virtual void postprocess() {} -virtual void updating_actions(action_update_ctx_t * ctx) {qnotused(ctx); } -virtual void updated_actions() {} -virtual void populating_tform_popup(TForm * form, TPopupMenu * popup_handle) {qnotused(form); qnotused(popup_handle); } -virtual void finish_populating_tform_popup(TForm * form, TPopupMenu * popup_handle) {qnotused(form); qnotused(popup_handle); } -virtual void plugin_loaded(const plugin_info_t * plugin_info) {qnotused(plugin_info); } -virtual void plugin_unloading(const plugin_info_t * plugin_info) {qnotused(plugin_info); } -virtual void current_tform_changed(TForm * form, TForm * prev_form) {qnotused(form); qnotused(prev_form); } }; //------------------------------------------------------------------------- @@ -1123,6 +1114,15 @@ bool py_unregister_action(const char *name) return ok; } +//------------------------------------------------------------------------- +PyObject *py_get_registered_actions() +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + qstrvec_t actions; + get_registered_actions(&actions); + return qstrvec2pylist(actions); +} + //------------------------------------------------------------------------- bool py_attach_dynamic_action_to_popup( TForm *form, @@ -1277,11 +1277,12 @@ nav_colorizer_t *py_set_nav_colorizer(PyObject *new_py_colorizer) } }; - bool need_install = py_colorizer == NULL; + // Always perform the call to set_nav_colorizer(): that has side-effects + // (e.g., updating the legend.) + bool first_install = py_colorizer == NULL; py_colorizer = borref_t(new_py_colorizer); - return need_install - ? set_nav_colorizer(lambda_t::call_py_colorizer) - : NULL; + nav_colorizer_t *prev = set_nav_colorizer(lambda_t::call_py_colorizer); + return first_install ? prev : NULL; } //------------------------------------------------------------------------- @@ -1321,187 +1322,6 @@ int idaapi UI_Callback(void *ud, int notification_code, va_list va) switch ( notification_code ) { // hookgenUI:notifications -case ui_range: -{ - proxy->range(); -} -break; - -case ui_idcstart: -{ - proxy->idcstart(); -} -break; - -case ui_idcstop: -{ - proxy->idcstop(); -} -break; - -case ui_suspend: -{ - proxy->suspend(); -} -break; - -case ui_resume: -{ - proxy->resume(); -} -break; - -case ui_saving: -{ - proxy->saving(); -} -break; - -case ui_saved: -{ - proxy->saved(); -} -break; - -case ui_term: -{ - proxy->term(); -} -break; - -case ui_debugger_menu_change: -{ - bool enable = bool(va_arg(va, int)); - ret = proxy->debugger_menu_change(enable); -} -break; - -case ui_tform_visible: -{ - TForm * form = va_arg(va, TForm *); - void * HWND = va_arg(va, void *); - proxy->tform_visible(form, HWND); -} -break; - -case ui_tform_invisible: -{ - TForm * form = va_arg(va, TForm *); - void * HWND = va_arg(va, void *); - proxy->tform_invisible(form, HWND); -} -break; - -case ui_get_ea_hint: -{ - ea_t ea = va_arg(va, ea_t); - char * buf = va_arg(va, char *); - size_t bufsize = va_arg(va, size_t); - PyObject * _tmp = proxy->get_ea_hint(ea); - ret = UI_Hooks::handle_get_ea_hint_output(_tmp, ea, buf, bufsize); -} -break; - -case ui_get_item_hint: -{ - ea_t ea = va_arg(va, ea_t); - int max_lines = va_arg(va, int); - int * important_lines = va_arg(va, int *); - qstring * hint = va_arg(va, qstring *); - PyObject * _tmp = proxy->get_item_hint(ea, max_lines); - ret = UI_Hooks::handle_hint_output(_tmp, ea, max_lines, important_lines, hint); -} -break; - -case ui_get_custom_viewer_hint: -{ - TCustomControl* viewer = va_arg(va, TCustomControl*); - place_t * place = va_arg(va, place_t *); - int * important_lines = va_arg(va, int *); - qstring * hint = va_arg(va, qstring *); - PyObject * _tmp = proxy->get_custom_viewer_hint(viewer, place); - ret = UI_Hooks::handle_hint_output(_tmp, viewer, place, important_lines, hint); -} -break; - -case ui_database_inited: -{ - int is_new_database = va_arg(va, int); - const char * idc_script = va_arg(va, const char *); - proxy->database_inited(is_new_database, idc_script); -} -break; - -case ui_ready_to_run: -{ - proxy->ready_to_run(); -} -break; - -case ui_preprocess: -{ - const char * name = va_arg(va, const char *); - proxy->preprocess(name); -} -break; - -case ui_postprocess: -{ - proxy->postprocess(); -} -break; - -case ui_updating_actions: -{ - action_update_ctx_t * ctx = va_arg(va, action_update_ctx_t *); - proxy->updating_actions(ctx); -} -break; - -case ui_updated_actions: -{ - proxy->updated_actions(); -} -break; - -case ui_populating_tform_popup: -{ - TForm * form = va_arg(va, TForm *); - TPopupMenu * popup_handle = va_arg(va, TPopupMenu *); - proxy->populating_tform_popup(form, popup_handle); -} -break; - -case ui_finish_populating_tform_popup: -{ - TForm * form = va_arg(va, TForm *); - TPopupMenu * popup_handle = va_arg(va, TPopupMenu *); - proxy->finish_populating_tform_popup(form, popup_handle); -} -break; - -case ui_plugin_loaded: -{ - const plugin_info_t * plugin_info = va_arg(va, const plugin_info_t *); - proxy->plugin_loaded(plugin_info); -} -break; - -case ui_plugin_unloading: -{ - const plugin_info_t * plugin_info = va_arg(va, const plugin_info_t *); - proxy->plugin_unloading(plugin_info); -} -break; - -case ui_current_tform_changed: -{ - TForm * form = va_arg(va, TForm *); - TForm * prev_form = va_arg(va, TForm *); - proxy->current_tform_changed(form, prev_form); -} -break; - } } catch (Swig::DirectorException &e) diff --git a/pywraps/py_kernwin.py b/pywraps/py_kernwin.py index cdaa267..7fa5876 100755 --- a/pywraps/py_kernwin.py +++ b/pywraps/py_kernwin.py @@ -1,25 +1,3 @@ -# ----------------------------------------------------------------------- -# Standalone and testing code -import sys -try: - import pywraps - pywraps_there = True - print "Using pywraps" -except: - pywraps_there = False - print "Not using pywraps" - -try: - import _idaapi -except: - print "Please try me from inside IDA" - sys.exit(0) - -if pywraps_there: - _idaapi.execute_sync = pywraps.py_execute_sync - _idaapi.add_hotkey = pywraps.py_add_hotkey - _idaapi.del_hotkey = pywraps.py_del_hotkey - # ----------------------------------------------------------------------- # DP_LEFT = 0x0001 @@ -50,15 +28,15 @@ def load_custom_icon(file_name=None, data=None, format=None): Use free_custom_icon() to free it """ if file_name is not None: - return _idaapi.py_load_custom_icon_fn(file_name) + return _ida_kernwin.py_load_custom_icon_fn(file_name) elif not (data is None and format is None): - return _idaapi.py_load_custom_icon_data(data, format) + return _ida_kernwin.py_load_custom_icon_data(data, format) else: return 0 # ---------------------------------------------------------------------- def asklong(defval, format): - res, val = _idaapi._asklong(defval, format) + res, val = _ida_kernwin._asklong(defval, format) if res == 1: return val @@ -67,7 +45,7 @@ def asklong(defval, format): # ---------------------------------------------------------------------- def askaddr(defval, format): - res, ea = _idaapi._askaddr(defval, format) + res, ea = _ida_kernwin._askaddr(defval, format) if res == 1: return ea @@ -76,7 +54,7 @@ def askaddr(defval, format): # ---------------------------------------------------------------------- def askseg(defval, format): - res, sel = _idaapi._askseg(defval, format) + res, sel = _ida_kernwin._askseg(defval, format) if res == 1: return sel @@ -84,7 +62,7 @@ def askseg(defval, format): return None # ---------------------------------------------------------------------- -class action_handler_t: +class action_handler_t(object): def __init__(self): pass @@ -95,27 +73,3 @@ class action_handler_t: pass # - -# ---------------------------------------------------------------------- -from threading import Thread -import time - -# ---------------------------------------------------------------------- -def myfunction(cnt): - i = 1 - while i <= cnt: - print "i=", i - i += 1 - time.sleep(1) - - print "done!" - -def test_thread(): - t = Thread(target=myfunction, args=(2,)) - - t.start() - t.join() - -# ---------------------------------------------------------------------- -def hotkey_func1(): - print "Hello from hotkey handler in Python!" diff --git a/pywraps/py_askusingform.hpp b/pywraps/py_kernwin_askusingform.hpp similarity index 90% rename from pywraps/py_askusingform.hpp rename to pywraps/py_kernwin_askusingform.hpp index f69ea58..76262e1 100644 --- a/pywraps/py_askusingform.hpp +++ b/pywraps/py_kernwin_askusingform.hpp @@ -1,25 +1,11 @@ -#ifndef __PY_ASKUSINGFORM__ -#define __PY_ASKUSINGFORM__ +#ifndef __PY_KERNWIN_ASKUSINGFORM__ +#define __PY_KERNWIN_ASKUSINGFORM__ -// -static qvector py_compiled_form_vec; -void free_compiled_form_instances(void) -{ - while ( !py_compiled_form_vec.empty() ) - { - const ref_t &ref = py_compiled_form_vec[0]; - qstring title; - if ( !PyW_GetStringAttr(ref.o, "title", &title) ) - title = ""; - msg("WARNING: Form \"%s\" was not Free()d. Force-freeing.\n", title.c_str()); - // Will call 'py_unregister_compiled_form()', and thus trim the vector down. - newref_t unused(PyObject_CallMethod(ref.o, (char *)"Free", "()")); - } -} -// +// +// //--------------------------------------------------------------------------- -// +// #define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa; //--------------------------------------------------------------------------- @@ -384,18 +370,15 @@ static size_t py_get_OpenForm() static void py_register_compiled_form(PyObject *py_form) { - ref_t ref = borref_t(py_form); - if ( !py_compiled_form_vec.has(ref) ) - py_compiled_form_vec.push_back(ref); + PyW_register_compiled_form(py_form); } static void py_unregister_compiled_form(PyObject *py_form) { - ref_t ref = borref_t(py_form); - if ( py_compiled_form_vec.has(ref) ) - py_compiled_form_vec.del(ref); + PyW_unregister_compiled_form(py_form); } +// -// -#endif // __PY_ASKUSINGFORM__ +#endif // __PY_KERNWIN_ASKUSINGFORM__ + diff --git a/pywraps/py_askusingform.py b/pywraps/py_kernwin_askusingform.py similarity index 91% rename from pywraps/py_askusingform.py rename to pywraps/py_kernwin_askusingform.py index f4a8e04..1f7b3c5 100755 --- a/pywraps/py_askusingform.py +++ b/pywraps/py_kernwin_askusingform.py @@ -1,74 +1,8 @@ # -------------------------------------------------------------------------- -import os -import gc -import sys +# +import ida_idaapi, _ida_idaapi +import ida_pro -try: - import _idaapi - from _idaapi import set_script_timeout - import idaapi - from idaapi import py_clinked_object_t - from idaapi import _qstrvec_t - stdalone = False -except: - stdalone = True - -print("Standalone: %s" % stdalone) - -pywraps_there = False - -try: - if stdalone: - class object_t(object): pass - class py_clinked_object_t(object): pass - _idaapi = object_t() - _idaapi.choose2_get_embedded = lambda obj: (id(obj), 0) - _idaapi.choose2_get_embedded_selection = lambda obj: None - - _idaapi.textctrl_info_t_set_text = lambda self, v: None - _idaapi.CHOOSER_POPUP_MENU = 1 - pywraps = object_t() - pywraps.py_get_AskUsingForm = lambda: 0 - pywraps.py_get_OpenForm = lambda: 0 - - class Choose2(object): - CH_MULTI = 1 - def __init__(self, title, cols, flags=0, popup_names=None, - icon=-1, x1=-1, y1=-1, x2=-1, y2=-1, deflt=-1, - embedded=False, width=None, height=None): - pass - - def Close(self): - print("Chooser closing...") - - Embedded = lambda self: 1 - - set_script_timeout = lambda x: x - - else: - import pywraps - pywraps_there = True - from py_choose2 import * - py_clinked_object_t = idaapi.py_clinked_object_t - textctrl_info_t = idaapi.textctrl_info_t - _qstrvec_t = idaapi._qstrvec_t - - _idaapi.BADADDR = 0xFFFFFFFF - _idaapi.MAXSTR = 1024 - set_script_timeout = _idaapi.set_script_timeout - - if not hasattr(_idaapi, 'formchgcbfa_enable_field'): - _idaapi.formchgcbfa_enable_field = pywraps.py_formchgcbfa_enable_field - -except Exception as e: - pass -# print("exception: %s" % str(e)) - - -print("Using PyWraps: %s" % pywraps_there) - -# -------------------------------------------------------------------------- -# #ICON WARNING|QUESTION|INFO|NONE #AUTOHIDE NONE|DATABASE|REGISTRY|SESSION #HIDECANCEL @@ -98,7 +32,7 @@ except: # ----------------------------------------------------------------------- # textctrl_info_t clinked object -class textctrl_info_t(py_clinked_object_t): +class textctrl_info_t(ida_idaapi.py_clinked_object_t): """Class representing textctrl_info_t""" # Some constants @@ -116,7 +50,7 @@ class textctrl_info_t(py_clinked_object_t): """The control uses IDA's fixed font""" def __init__(self, text="", flags=0, tabsize=0): - py_clinked_object_t.__init__(self) + ida_idaapi.py_clinked_object_t.__init__(self) if text: self.text = text if flags: @@ -125,41 +59,41 @@ class textctrl_info_t(py_clinked_object_t): self.tabsize = tabsize def _create_clink(self): - return _idaapi.textctrl_info_t_create() + return _ida_kernwin.textctrl_info_t_create() def _del_clink(self, lnk): - return _idaapi.textctrl_info_t_destroy(lnk) + return _ida_kernwin.textctrl_info_t_destroy(lnk) def _get_clink_ptr(self): - return _idaapi.textctrl_info_t_get_clink_ptr(self) + return _ida_kernwin.textctrl_info_t_get_clink_ptr(self) def assign(self, other): """Copies the contents of 'other' to 'self'""" - return _idaapi.textctrl_info_t_assign(self, other) + return _ida_kernwin.textctrl_info_t_assign(self, other) def __set_text(self, s): """Sets the text value""" - return _idaapi.textctrl_info_t_set_text(self, s) + return _ida_kernwin.textctrl_info_t_set_text(self, s) def __get_text(self): """Sets the text value""" - return _idaapi.textctrl_info_t_get_text(self) + return _ida_kernwin.textctrl_info_t_get_text(self) def __set_flags__(self, flags): """Sets the flags value""" - return _idaapi.textctrl_info_t_set_flags(self, flags) + return _ida_kernwin.textctrl_info_t_set_flags(self, flags) def __get_flags__(self): """Returns the flags value""" - return _idaapi.textctrl_info_t_get_flags(self) + return _ida_kernwin.textctrl_info_t_get_flags(self) def __set_tabsize__(self, tabsize): """Sets the tabsize value""" - return _idaapi.textctrl_info_t_set_tabsize(self, tabsize) + return _ida_kernwin.textctrl_info_t_set_tabsize(self, tabsize) def __get_tabsize__(self): """Returns the tabsize value""" - return _idaapi.textctrl_info_t_get_tabsize(self) + return _ida_kernwin.textctrl_info_t_get_tabsize(self) value = property(__get_text, __set_text) """Alias for the text property""" @@ -218,6 +152,8 @@ class Form(object): """Multi text control - textctrl_info_t""" FT_DROPDOWN_LIST = 'b' """Dropdown list control - Form.DropdownControl""" + FT_HTML_LABEL = 'h' + """HTML label to display (only for GUI version, and for dynamic labels; no input)""" FT_CHKGRP = 'C' FT_CHKGRP2= 'c' @@ -726,7 +662,7 @@ class Form(object): # Get a pointer to the chooser_info_t and the selection vector # (These two parameters are the needed arguments for the AskUsingForm()) - emb, sel = _idaapi.choose2_get_embedded(chooser) + emb, sel = _ida_kernwin.choose2_get_embedded(chooser) # Get a pointer to a c_void_p constructed from an address p_embedded = pointer(c_void_p.from_address(emb)) @@ -751,7 +687,7 @@ class Form(object): def AddCommand(self, caption, - flags = _idaapi.CHOOSER_POPUP_MENU, + flags = _ida_kernwin.CHOOSER_POPUP_MENU, menu_index = -1, icon = -1): """ @@ -777,7 +713,7 @@ class Form(object): Form.Control.free(self) - class DropdownListControl(InputControl, _qstrvec_t): + class DropdownListControl(InputControl, ida_pro._qstrvec_t): """ Dropdown control This control allows manipulating a dropdown control @@ -804,7 +740,7 @@ class Form(object): hlp) # Init the associated qstrvec - _qstrvec_t.__init__(self, items) + ida_pro._qstrvec_t.__init__(self, items) # Remember if readonly or not self.readonly = readonly @@ -815,7 +751,7 @@ class Form(object): val_addr = addressof(self.__selval) else: # Create an strvec with one qstring - self.__selval = _qstrvec_t([selval]) + self.__selval = ida_pro._qstrvec_t([selval]) # Get address of the first element val_addr = self.__selval.addressof(0) @@ -934,7 +870,7 @@ class Form(object): self._reset() # Unregister, so we don't try and free it again at closing-time. - _idaapi.py_unregister_compiled_form(self) + _ida_kernwin.py_unregister_compiled_form(self) def _reset(self): @@ -1180,7 +1116,7 @@ class Form(object): self.__args = self.CompileEx(self.form) # Register this form, to make sure it will be freed at closing-time. - _idaapi.py_register_compiled_form(self) + _ida_kernwin.py_register_compiled_form(self) return (self, self.__args) @@ -1227,7 +1163,7 @@ class Form(object): Enable or disable an input field @return: False - no such control """ - return _idaapi.formchgcbfa_enable_field(self.p_fa, ctrl.id, enable) + return _ida_kernwin.formchgcbfa_enable_field(self.p_fa, ctrl.id, enable) def ShowField(self, ctrl, show): @@ -1235,7 +1171,7 @@ class Form(object): Show or hide an input field @return: False - no such control """ - return _idaapi.formchgcbfa_show_field(self.p_fa, ctrl.id, show) + return _ida_kernwin.formchgcbfa_show_field(self.p_fa, ctrl.id, show) def MoveField(self, ctrl, x, y, w, h): @@ -1244,7 +1180,7 @@ class Form(object): @return: False - no such fiel """ - return _idaapi.formchgcbfa_move_field(self.p_fa, ctrl.id, x, y, w, h) + return _ida_kernwin.formchgcbfa_move_field(self.p_fa, ctrl.id, x, y, w, h) def GetFocusedField(self): @@ -1252,7 +1188,7 @@ class Form(object): Get currently focused input field. @return: None if no field is selected otherwise the control ID """ - id = _idaapi.formchgcbfa_get_focused_field(self.p_fa) + id = _ida_kernwin.formchgcbfa_get_focused_field(self.p_fa) return self.FindControlById(id) @@ -1261,7 +1197,7 @@ class Form(object): Set currently focused input field @return: False - no such control """ - return _idaapi.formchgcbfa_set_focused_field(self.p_fa, ctrl.id) + return _ida_kernwin.formchgcbfa_set_focused_field(self.p_fa, ctrl.id) def RefreshField(self, ctrl): @@ -1269,7 +1205,7 @@ class Form(object): Refresh a field @return: False - no such control """ - return _idaapi.formchgcbfa_refresh_field(self.p_fa, ctrl.id) + return _ida_kernwin.formchgcbfa_refresh_field(self.p_fa, ctrl.id) def Close(self, close_normally): @@ -1280,7 +1216,7 @@ class Form(object): 0: form is closed abnormally as if the user pressed Esc @return: None """ - return _idaapi.formchgcbfa_close(self.p_fa, close_normally) + return _ida_kernwin.formchgcbfa_close(self.p_fa, close_normally) def GetControlValue(self, ctrl): @@ -1296,7 +1232,7 @@ class Form(object): - None: on failure """ tid, sz = self.ControlToFieldTypeIdAndSize(ctrl) - r = _idaapi.formchgcbfa_get_field_value( + r = _ida_kernwin.formchgcbfa_get_field_value( self.p_fa, ctrl.id, tid, @@ -1320,7 +1256,7 @@ class Form(object): @return: Boolean true on success """ tid, _ = self.ControlToFieldTypeIdAndSize(ctrl) - return _idaapi.formchgcbfa_set_field_value( + return _ida_kernwin.formchgcbfa_set_field_value( self.p_fa, ctrl.id, tid, @@ -1346,7 +1282,7 @@ class Form(object): elif isinstance(ctrl, (Form.GroupItemControl, Form.GroupControl)): return (2, 0) elif isinstance(ctrl, Form.StringLabel): - return (3, min(_idaapi.MAXSTR, ctrl.size)) + return (3, min(_ida_kernwin.MAXSTR, ctrl.size)) elif isinstance(ctrl, Form.ColorInput): return (4, 0) elif isinstance(ctrl, Form.NumericInput): @@ -1362,9 +1298,9 @@ class Form(object): try: import ctypes # Setup the numeric argument size - Form.NumericArgument.DefI64 = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL - AskUsingForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_AskUsingForm()) - OpenForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_OpenForm()) + Form.NumericArgument.DefI64 = _ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL + AskUsingForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_ida_kernwin.py_get_AskUsingForm()) + OpenForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_ida_kernwin.py_get_OpenForm()) except: def AskUsingForm__(*args): warning("AskUsingForm() needs ctypes library in order to work") @@ -1379,9 +1315,9 @@ def AskUsingForm(*args): @param: Compiled Arguments obtain through the Form.Compile() function @return: 1 = ok, 0 = cancel """ - old = set_script_timeout(0) + old = _ida_idaapi.set_script_timeout(0) r = AskUsingForm__(*args) - set_script_timeout(old) + _ida_idaapi.set_script_timeout(old) return r def OpenForm(*args): @@ -1389,9 +1325,7 @@ def OpenForm(*args): Calls OpenForm() @param: Compiled Arguments obtain through the Form.Compile() function """ - old = set_script_timeout(0) + old = _ida_idaapi.set_script_timeout(0) r = OpenForm__(*args) - set_script_timeout(old) - - -# + _ida_idaapi.set_script_timeout(old) +# diff --git a/pywraps/py_choose.hpp b/pywraps/py_kernwin_choose.hpp similarity index 92% rename from pywraps/py_choose.hpp rename to pywraps/py_kernwin_choose.hpp index 369d77e..bbce7a0 100644 --- a/pywraps/py_choose.hpp +++ b/pywraps/py_kernwin_choose.hpp @@ -1,8 +1,8 @@ -#ifndef __PY_CHOOSE__ -#define __PY_CHOOSE__ +#ifndef __PY_KERNWIN_CHOOSE__ +#define __PY_KERNWIN_CHOOSE__ //--------------------------------------------------------------------------- -// +// //--------------------------------------------------------------------------- uint32 idaapi choose_sizer(void *self) { @@ -73,6 +73,6 @@ uint32 choose_choose( return r; } -// +// -#endif // __PY_CHOOSE__ +#endif // __PY_KERNWIN_CHOOSE__ diff --git a/pywraps/py_choose.py b/pywraps/py_kernwin_choose.py similarity index 86% rename from pywraps/py_choose.py rename to pywraps/py_kernwin_choose.py index 2cde81a..3924660 100644 --- a/pywraps/py_choose.py +++ b/pywraps/py_kernwin_choose.py @@ -1,6 +1,8 @@ -# -class Choose: +# +import _ida_idaapi + +class Choose(object): """ Choose - class for choose() with callbacks """ @@ -70,8 +72,8 @@ class Choose: """ choose - Display the choose dialogue """ - old = set_script_timeout(0) - n = _idaapi.choose_choose( + old = _ida_idaapi.set_script_timeout(0) + n = _ida_kernwin.choose_choose( self, self.flags, self.x0, @@ -81,6 +83,6 @@ class Choose: self.width, self.deflt, self.icon) - set_script_timeout(old) + _ida_idaapi.set_script_timeout(old) return n -# +# diff --git a/pywraps/py_choose2.hpp b/pywraps/py_kernwin_choose2.hpp similarity index 96% rename from pywraps/py_choose2.hpp rename to pywraps/py_kernwin_choose2.hpp index 6b6693b..a5733d2 100644 --- a/pywraps/py_choose2.hpp +++ b/pywraps/py_kernwin_choose2.hpp @@ -1,7 +1,7 @@ -#ifndef __PY_CHOOSE2__ -#define __PY_CHOOSE2__ +#ifndef __PY_KERNWIN_CHOOSE2__ +#define __PY_KERNWIN_CHOOSE2__ -// +// //------------------------------------------------------------------------ // Some defines @@ -100,9 +100,6 @@ private: //------------------------------------------------------------------------ static int idaapi ui_cb(void *obj, int notification_code, va_list va) { - // This hook gets called from the kernel. Ensure we hold the GIL. - PYW_GIL_GET; - // UI callback to handle chooser items with attributes if ( notification_code != ui_get_chooser_item_attrs ) return 0; @@ -112,6 +109,9 @@ private: if ( obj != chooser_obj ) return 0; + // We will treat the demand. + // This hook gets called from the kernel. Ensure we hold the GIL. + PYW_GIL_GET; int n = int(va_arg(va, uint32)); chooser_item_attrs_t *attr = va_arg(va, chooser_item_attrs_t *); thisobj->on_get_line_attr(n, attr); @@ -181,7 +181,7 @@ private: if ( popup_names == NULL ) return; - for ( int i=0; i=0; i-- ) + for ( int i=ncols-1; i >= 0; i-- ) line_arr[i][0] = '\0'; // Call Python @@ -236,7 +236,7 @@ private: return; // Go over the List returned by Python and convert to C strings - for ( int i=ncols-1; i>=0; i-- ) + for ( int i=ncols-1; i >= 0; i-- ) { borref_t item(PyList_GetItem(list.result.o, Py_ssize_t(i))); if ( item == NULL ) @@ -434,9 +434,7 @@ private: int desired_height, int icon) { - memset(out, 0, sizeof(*out)); out->obj = this; - out->cb = sizeof(*out); out->title = title.c_str(); out->columns = widths.size(); out->deflt = deflt; @@ -564,7 +562,7 @@ public: // Get cols caption and widthes cols.qclear(); - for ( int i=0; iget_self(); } -// +// //--------------------------------------------------------------------------- -// +// PyObject *choose2_find(const char *title); int choose2_add_command(PyObject *self, const char *caption, int flags, int menu_index, int icon); void choose2_refresh(PyObject *self); @@ -883,7 +881,19 @@ int choose2_create(PyObject *self, bool embedded); void choose2_activate(PyObject *self); PyObject *choose2_get_embedded(PyObject *self); PyObject *choose2_get_embedded_selection(PyObject *self); -// + +PyObject *py_get_chooser_data(const char *chooser_caption, uint32 n) +{ + qstrvec_t data; + if ( !get_chooser_data(&data, chooser_caption, n) ) + Py_RETURN_NONE; + PyObject *py_list = PyList_New(data.size()); + for ( size_t i = 0; i < data.size(); ++i ) + PyList_SetItem(py_list, i, PyString_FromString(data[i].c_str())); + return py_list; +} + +// //--------------------------------------------------------------------------- // Testing functions. They belong to PyWraps and won't be copied to IDAPython @@ -899,4 +909,4 @@ static size_t choose2_get_test_embedded() { return (size_t)choose2_test_embedded; } -#endif // __PY_CHOOSE2__ +#endif // __PY_KERNWIN_CHOOSE2__ diff --git a/pywraps/py_choose2.py b/pywraps/py_kernwin_choose2.py similarity index 78% rename from pywraps/py_choose2.py rename to pywraps/py_kernwin_choose2.py index ceb3745..2c949f7 100755 --- a/pywraps/py_choose2.py +++ b/pywraps/py_kernwin_choose2.py @@ -1,41 +1,5 @@ # ----------------------------------------------------------------------- -# Standalone and testing code -from ctypes import * - -try: - import _idaapi -except: - print("Please try me from inside IDA") - sys.exit(0) - -try: - import pywraps - pywraps_there = True - print("Choose2: using pywraps") - - _idaapi.choose2_create = pywraps.py_choose2_create - _idaapi.choose2_activate = pywraps.py_choose2_activate - _idaapi.choose2_refresh = pywraps.py_choose2_refresh - _idaapi.choose2_close = pywraps.py_choose2_close - _idaapi.choose2_add_command = pywraps.py_choose2_add_command - _idaapi.choose2_get_embedded = pywraps.py_choose2_get_embedded - _idaapi.choose2_get_embedded_selection = pywraps.py_choose2_get_embedded_selection - - try: - # Get function address - # void test_embedded(chooser_info_t *) - TEST_EMBEDDED = CFUNCTYPE(c_void_p, c_void_p) - test_embedded = TEST_EMBEDDED(pywraps.py_choose2_get_test_embedded()) - except Exception as e: - test_embedded = None - print("Choose2: Exception: %s" % str(e)) - -except Exception as e: - pywraps_there = False - print("Choose2: Not using pywraps: %s" % str(e)) - -# ----------------------------------------------------------------------- -# +# class Choose2(object): """ Choose2 wrapper class. @@ -105,7 +69,7 @@ class Choose2(object): Creates an embedded chooser (as opposed to Show()) @return: Returns 1 on success """ - return _idaapi.choose2_create(self, True) + return _ida_kernwin.choose2_create(self, True) def GetEmbSelection(self): @@ -116,7 +80,7 @@ class Choose2(object): - None if chooser is not embedded - A list with selection indices (0-based) """ - return _idaapi.choose2_get_embedded_selection(self) + return _ida_kernwin.choose2_get_embedded_selection(self) def Show(self, modal=False): @@ -129,9 +93,9 @@ class Choose2(object): self.flags |= Choose2.CH_MODAL # Disable the timeout - old = _idaapi.set_script_timeout(0) - n = _idaapi.choose2_create(self, False) - _idaapi.set_script_timeout(old) + old = _ida_idaapi.set_script_timeout(0) + n = _ida_kernwin.choose2_create(self, False) + _ida_idaapi.set_script_timeout(old) # Delete the modal chooser instance self.Close() @@ -139,27 +103,27 @@ class Choose2(object): return n else: self.flags &= ~Choose2.CH_MODAL - return _idaapi.choose2_create(self, False) + return _ida_kernwin.choose2_create(self, False) def Activate(self): """Activates a visible chooser""" - return _idaapi.choose2_activate(self) + return _ida_kernwin.choose2_activate(self) def Refresh(self): """Causes the refresh callback to trigger""" - return _idaapi.choose2_refresh(self) + return _ida_kernwin.choose2_refresh(self) def Close(self): """Closes the chooser""" - return _idaapi.choose2_close(self) + return _ida_kernwin.choose2_close(self) def AddCommand(self, caption, - flags = _idaapi.CHOOSER_POPUP_MENU, + flags = _ida_kernwin.CHOOSER_POPUP_MENU, menu_index = -1, icon = -1, emb=None): @@ -172,7 +136,7 @@ class Choose2(object): # Use the 'emb' as a sentinel. It will be passed the correct value from the EmbeddedChooserControl if self.embedded and ((emb is None) or (emb != 2002)): raise RuntimeError("Please add a command through EmbeddedChooserControl.AddCommand()") - return _idaapi.choose2_add_command(self, caption, flags, menu_index, icon) + return _ida_kernwin.choose2_add_command(self, caption, flags, menu_index, icon) # # Implement these methods in the subclass: @@ -273,4 +237,4 @@ class Choose2(object): # """ # return [0x0, CHITEM_BOLD] # -# +# diff --git a/pywraps/py_cli.hpp b/pywraps/py_kernwin_cli.hpp similarity index 98% rename from pywraps/py_cli.hpp rename to pywraps/py_kernwin_cli.hpp index 16b4650..ba78a1f 100644 --- a/pywraps/py_cli.hpp +++ b/pywraps/py_kernwin_cli.hpp @@ -1,7 +1,7 @@ #ifndef __PYWRAPS_CLI__ #define __PYWRAPS_CLI__ -// +// //-------------------------------------------------------------------------- #define MAX_PY_CLI 12 @@ -276,11 +276,11 @@ const py_cli_cbs_t py_cli_t::py_cli_cbs[MAX_PY_CLI] = DECL_PY_CLI_CB(8), DECL_PY_CLI_CB(9), DECL_PY_CLI_CB(10), DECL_PY_CLI_CB(11) }; #undef DECL_PY_CLI_CB -// +// //-------------------------------------------------------------------------- -// +// static int py_install_command_interpreter(PyObject *py_obj) { return py_cli_t::bind(py_obj); @@ -290,6 +290,6 @@ static void py_remove_command_interpreter(int cli_idx) { py_cli_t::unbind(cli_idx); } -// +// //--------------------------------------------------------------------------- #endif // __PYWRAPS_CLI__ diff --git a/pywraps/py_cli.py b/pywraps/py_kernwin_cli.py similarity index 80% rename from pywraps/py_cli.py rename to pywraps/py_kernwin_cli.py index 085874c..205490c 100755 --- a/pywraps/py_cli.py +++ b/pywraps/py_kernwin_cli.py @@ -1,28 +1,8 @@ # ----------------------------------------------------------------------- -# Standalone and testing code -import sys -try: - import pywraps - pywraps_there = True - print "Using pywraps" -except: - pywraps_there = False - print "Using IDAPython" +# +import ida_idaapi -try: - import _idaapi - from idaapi import pyidc_opaque_object_t -except: - print "Please run this script from inside IDA" - sys.exit(0) - -if pywraps_there: - _idaapi.install_command_interpreter = pywraps.install_command_interpreter - _idaapi.remove_command_interpreter = pywraps.remove_command_interpreter - -# ----------------------------------------------------------------------- -# -class cli_t(pyidc_opaque_object_t): +class cli_t(ida_idaapi.pyidc_opaque_object_t): """ cli_t wrapper class. @@ -55,7 +35,7 @@ class cli_t(pyidc_opaque_object_t): if hint is not None: self.hint = hint # Register - self.__cli_idx = _idaapi.install_command_interpreter(self) + self.__cli_idx = _ida_kernwin.install_command_interpreter(self) return False if self.__cli_idx < 0 else True @@ -66,7 +46,7 @@ class cli_t(pyidc_opaque_object_t): if self.__cli_idx < 0: return False - _idaapi.remove_command_interpreter(self.__cli_idx) + _ida_kernwin.remove_command_interpreter(self.__cli_idx) self.__cli_idx = -1 return True @@ -125,4 +105,4 @@ class cli_t(pyidc_opaque_object_t): # return None # -# +# diff --git a/pywraps/py_custview.hpp b/pywraps/py_kernwin_custview.hpp similarity index 99% rename from pywraps/py_custview.hpp rename to pywraps/py_kernwin_custview.hpp index 0a7b83c..0de6ea2 100644 --- a/pywraps/py_custview.hpp +++ b/pywraps/py_kernwin_custview.hpp @@ -1,6 +1,6 @@ #ifndef __PYWRAPS_CUSTVIEWER__ #define __PYWRAPS_CUSTVIEWER__ -// +// //--------------------------------------------------------------------------- // Base class for all custviewer place_t providers class custviewer_data_t @@ -826,7 +826,7 @@ public: }; PYW_GIL_CHECK_LOCKED_SCOPE(); - for ( size_t i=0; i +// //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -// +// // // Pywraps Simple Custom Viewer functions // @@ -1128,6 +1128,6 @@ TCustomControl *pyscv_get_tcustom_control(PyObject *py_this) #undef DECL_THIS -// +// //--------------------------------------------------------------------------- #endif // __PYWRAPS_CUSTVIEWER__ diff --git a/pywraps/py_custview.py b/pywraps/py_kernwin_custview.py similarity index 67% rename from pywraps/py_custview.py rename to pywraps/py_kernwin_custview.py index c97c70f..35c18ea 100755 --- a/pywraps/py_custview.py +++ b/pywraps/py_kernwin_custview.py @@ -1,46 +1,5 @@ # ----------------------------------------------------------------------- -# Standalone and testing code -import sys, struct - -try: - import _idaapi -except: - print "Please try me from inside IDA" - sys.exit(0) - -try: - import pywraps - pywraps_there = True - print "Using pywraps" - - _idaapi.pyscv_init = pywraps.pyscv_init - _idaapi.pyscv_close = pywraps.pyscv_close - _idaapi.pyscv_add_line = pywraps.pyscv_add_line - _idaapi.pyscv_delete = pywraps.pyscv_delete - _idaapi.pyscv_refresh = pywraps.pyscv_refresh - _idaapi.pyscv_show = pywraps.pyscv_show - _idaapi.pyscv_clear_popup_menu = pywraps.pyscv_clear_popup_menu - _idaapi.pyscv_del_line = pywraps.pyscv_del_line - _idaapi.pyscv_get_pos = pywraps.pyscv_get_pos - _idaapi.pyscv_refresh_current = pywraps.pyscv_refresh_current - _idaapi.pyscv_get_current_line = pywraps.pyscv_get_current_line - _idaapi.pyscv_is_focused = pywraps.pyscv_is_focused - _idaapi.pyscv_add_popup_menu = pywraps.pyscv_add_popup_menu - _idaapi.pyscv_get_line = pywraps.pyscv_get_line - _idaapi.pyscv_jumpto = pywraps.pyscv_jumpto - _idaapi.pyscv_edit_line = pywraps.pyscv_edit_line - _idaapi.pyscv_patch_line = pywraps.pyscv_patch_line - _idaapi.pyscv_insert_line = pywraps.pyscv_insert_line - _idaapi.pyscv_count = pywraps.pyscv_count - _idaapi.pyscv_get_selection = pywraps.pyscv_get_selection - _idaapi.pyscv_clear_lines = pywraps.pyscv_clear_lines - _idaapi.pyscv_get_current_word = pywraps.pyscv_get_current_word -except: - pywraps_there = False - print "Not using pywraps" - -# ----------------------------------------------------------------------- -# +# class simplecustviewer_t(object): """The base class for implementing simple custom viewers""" def __init__(self): @@ -49,7 +8,7 @@ class simplecustviewer_t(object): def __del__(self): """Destructor. It also frees the associated C++ object""" try: - _idaapi.pyscv_delete(self.__this) + _ida_kernwin.pyscv_delete(self.__this) except: pass @@ -66,7 +25,7 @@ class simplecustviewer_t(object): In this case better close existing windows """ self.title = title - self.__this = _idaapi.pyscv_init(self, title) + self.__this = _ida_kernwin.pyscv_init(self, title) return True if self.__this else False def Close(self): @@ -76,25 +35,25 @@ class simplecustviewer_t(object): Show() can be called and it will call Create() internally. @return: Boolean """ - return _idaapi.pyscv_close(self.__this) + return _ida_kernwin.pyscv_close(self.__this) def Show(self): """ Shows an already created view. It the view was close, then it will call Create() for you @return: Boolean """ - return _idaapi.pyscv_show(self.__this) + return _ida_kernwin.pyscv_show(self.__this) def Refresh(self): - return _idaapi.pyscv_refresh(self.__this) + return _ida_kernwin.pyscv_refresh(self.__this) def RefreshCurrent(self): """Refreshes the current line only""" - return _idaapi.pyscv_refresh_current(self.__this) + return _ida_kernwin.pyscv_refresh_current(self.__this) def Count(self): """Returns the number of lines in the view""" - return _idaapi.pyscv_count(self.__this) + return _ida_kernwin.pyscv_count(self.__this) def GetSelection(self): """ @@ -103,43 +62,43 @@ class simplecustviewer_t(object): - tuple(x1, y1, x2, y2) - None if no selection """ - return _idaapi.pyscv_get_selection(self.__this) + return _ida_kernwin.pyscv_get_selection(self.__this) def ClearLines(self): """Clears all the lines""" - _idaapi.pyscv_clear_lines(self.__this) + _ida_kernwin.pyscv_clear_lines(self.__this) def AddLine(self, line, fgcolor=None, bgcolor=None): """ Adds a colored line to the view @return: Boolean """ - return _idaapi.pyscv_add_line(self.__this, self.__make_sl_arg(line, fgcolor, bgcolor)) + return _ida_kernwin.pyscv_add_line(self.__this, self.__make_sl_arg(line, fgcolor, bgcolor)) def InsertLine(self, lineno, line, fgcolor=None, bgcolor=None): """ Inserts a line in the given position @return: Boolean """ - return _idaapi.pyscv_insert_line(self.__this, lineno, self.__make_sl_arg(line, fgcolor, bgcolor)) + return _ida_kernwin.pyscv_insert_line(self.__this, lineno, self.__make_sl_arg(line, fgcolor, bgcolor)) def EditLine(self, lineno, line, fgcolor=None, bgcolor=None): """ Edits an existing line. @return: Boolean """ - return _idaapi.pyscv_edit_line(self.__this, lineno, self.__make_sl_arg(line, fgcolor, bgcolor)) + return _ida_kernwin.pyscv_edit_line(self.__this, lineno, self.__make_sl_arg(line, fgcolor, bgcolor)) def PatchLine(self, lineno, offs, value): """Patches an existing line character at the given offset. This is a low level function. You must know what you're doing""" - return _idaapi.pyscv_patch_line(self.__this, lineno, offs, value) + return _ida_kernwin.pyscv_patch_line(self.__this, lineno, offs, value) def DelLine(self, lineno): """ Deletes an existing line @return: Boolean """ - return _idaapi.pyscv_del_line(self.__this, lineno) + return _ida_kernwin.pyscv_del_line(self.__this, lineno) def GetLine(self, lineno): """ @@ -148,7 +107,7 @@ class simplecustviewer_t(object): @return: Returns a tuple (colored_line, fgcolor, bgcolor) or None """ - return _idaapi.pyscv_get_line(self.__this, lineno) + return _ida_kernwin.pyscv_get_line(self.__this, lineno) def GetCurrentWord(self, mouse = 0): """ @@ -156,7 +115,7 @@ class simplecustviewer_t(object): @param mouse: Use mouse position or cursor position @return: None if failed or a String containing the current word at mouse or cursor """ - return _idaapi.pyscv_get_current_word(self.__this, mouse) + return _ida_kernwin.pyscv_get_current_word(self.__this, mouse) def GetCurrentLine(self, mouse = 0, notags = 0): """ @@ -165,7 +124,7 @@ class simplecustviewer_t(object): @param notags: If True then tag_remove() will be called before returning the line @return: Returns the current line (colored or uncolored) or None on failure """ - return _idaapi.pyscv_get_current_line(self.__this, mouse, notags) + return _ida_kernwin.pyscv_get_current_line(self.__this, mouse, notags) def GetPos(self, mouse = 0): """ @@ -173,7 +132,7 @@ class simplecustviewer_t(object): @param mouse: return mouse position @return: Returns a tuple (lineno, x, y) """ - return _idaapi.pyscv_get_pos(self.__this, mouse) + return _ida_kernwin.pyscv_get_pos(self.__this, mouse) def GetLineNo(self, mouse = 0): """Calls GetPos() and returns the current line number or -1 on failure""" @@ -181,16 +140,16 @@ class simplecustviewer_t(object): return -1 if not r else r[0] def Jump(self, lineno, x=0, y=0): - return _idaapi.pyscv_jumpto(self.__this, lineno, x, y) + return _ida_kernwin.pyscv_jumpto(self.__this, lineno, x, y) def AddPopupMenu(self, title, hotkey=""): """ - Adds a popup menu item + Adds a popup menu item, and get its ID (for use in the OnPopupMenu() handler) @param title: The name of the menu item @param hotkey: Hotkey of the item or just empty - @return: Returns the + @return: Returns the id of the registered popup menu item """ - return _idaapi.pyscv_add_popup_menu(self.__this, title, hotkey) + return _ida_kernwin.pyscv_add_popup_menu(self.__this, title, hotkey) def ClearPopupMenu(self): """ @@ -198,11 +157,11 @@ class simplecustviewer_t(object): Use this function if you're generating menu items on the fly (in the OnPopup() callback), and before adding new items """ - _idaapi.pyscv_clear_popup_menu(self.__this) + _ida_kernwin.pyscv_clear_popup_menu(self.__this) def IsFocused(self): """Returns True if the current view is the focused view""" - return _idaapi.pyscv_is_focused(self.__this) + return _ida_kernwin.pyscv_is_focused(self.__this) def GetTForm(self): """ @@ -210,7 +169,7 @@ class simplecustviewer_t(object): @return: The TForm that hosts this view, or None. """ - return _idaapi.pyscv_get_tform(self.__this) + return _ida_kernwin.pyscv_get_tform(self.__this) def GetTCustomControl(self): """ @@ -218,7 +177,7 @@ class simplecustviewer_t(object): @return: The TCustomControl underlying this view, or None. """ - return _idaapi.pyscv_get_tcustom_control(self.__this) + return _ida_kernwin.pyscv_get_tcustom_control(self.__this) @@ -292,4 +251,4 @@ class simplecustviewer_t(object): # print "OnPopupMenu, menu_id=" % menu_id # return True # -# +# diff --git a/pywraps/py_kernwin_idaview.hpp b/pywraps/py_kernwin_idaview.hpp new file mode 100644 index 0000000..b2f5d8b --- /dev/null +++ b/pywraps/py_kernwin_idaview.hpp @@ -0,0 +1,92 @@ + +// +//------------------------------------------------------------------------- +// py_idaview_t +//------------------------------------------------------------------------- +class py_idaview_t : public py_customidamemo_t +{ + typedef py_customidamemo_t inherited; + +public: + static bool Bind(PyObject *self); + static bool Unbind(PyObject *self); +}; + +//------------------------------------------------------------------------- +bool py_idaview_t::Bind(PyObject *self) +{ + // Already a py_idaview_t associated to this object? + py_idaview_t *_this = view_extract_this(self); + if ( _this != NULL ) + return false; + + qstring title; + if ( !PyW_GetStringAttr(self, S_M_TITLE, &title) ) + return false; + + // Get the IDAView associated to this TForm + TForm *tform = find_tform(title.c_str()); + if ( tform == NULL ) + return false; + TCustomControl *v = get_tform_idaview(tform); + if ( v == NULL ) + return false; + + // Get unique py_idaview_t associated to that tform + py_idaview_t *py_view; + TCustomControl *found_view; + if ( pycim_lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_view, tform) ) + { + // If we have a py_idaview_t for that form, ensure it has + // the expected view. + QASSERT(30451, found_view == v); + } + else + { + py_view = new py_idaview_t(); + lookup_entry_t &e = pycim_lookup_info.new_entry(py_view); + pycim_lookup_info.commit(e, tform, v); + } + + // Finally, bind: + // py_idaview_t <=> IDAViewWrapper + // py_idaview_t => TCustomControl + bool ok = py_view->bind(self, v); + if ( ok ) + { + ok = py_view->collect_pyobject_callbacks(self); + if ( ok ) + py_view->install_custom_viewer_handlers(); + else + delete py_view; + } + return ok; +} + +//------------------------------------------------------------------------- +bool py_idaview_t::Unbind(PyObject *self) +{ + py_idaview_t *_this = view_extract_this(self); + if ( _this == NULL ) + return false; + _this->unbind(true); + return true; +} + +//------------------------------------------------------------------------- +bool pyidag_bind(PyObject *self) +{ + return py_idaview_t::Bind(self); +} + +//------------------------------------------------------------------------- +bool pyidag_unbind(PyObject *self) +{ + return py_idaview_t::Unbind(self); +} +// + +// +bool pyidag_bind(PyObject *self); +bool pyidag_unbind(PyObject *self); +// diff --git a/pywraps/py_kernwin_idaview.py b/pywraps/py_kernwin_idaview.py new file mode 100644 index 0000000..b009f57 --- /dev/null +++ b/pywraps/py_kernwin_idaview.py @@ -0,0 +1,25 @@ + +# +#------------------------------------------------------------------------- +# IDAViewWrapper +#------------------------------------------------------------------------- +import ida_idaapi +import _ida_kernwin +class IDAViewWrapper(ida_idaapi.CustomIDAMemo): + """This class wraps access to native IDA views. See kernwin.hpp file""" + def __init__(self, title): + """ + Constructs the IDAViewWrapper object around the view + whose title is 'title'. + + @param title: The title of the existing IDA view. E.g., 'IDA View-A' + """ + self._title = title + + def Bind(self): + return _ida_kernwin.pyidag_bind(self) + + def Unbind(self): + return _ida_kernwin.pyidag_unbind(self) + +# diff --git a/pywraps/py_plgform.hpp b/pywraps/py_kernwin_plgform.hpp similarity index 93% rename from pywraps/py_plgform.hpp rename to pywraps/py_kernwin_plgform.hpp index 7538511..30bf74b 100644 --- a/pywraps/py_plgform.hpp +++ b/pywraps/py_kernwin_plgform.hpp @@ -1,7 +1,7 @@ -#ifndef __PY_PLGFORM__ -#define __PY_PLGFORM__ +#ifndef __PY_KERNWIN_PLGFORM__ +#define __PY_KERNWIN_PLGFORM__ -// +// //--------------------------------------------------------------------------- class plgform_t { @@ -124,9 +124,9 @@ public: delete (plgform_t *)obj; } }; -// +// -// +// //--------------------------------------------------------------------------- #define DECL_PLGFORM PYW_GIL_CHECK_LOCKED_SCOPE(); plgform_t *plgform = (plgform_t *) PyCObject_AsVoidPtr(py_link); static PyObject *plgform_new() @@ -152,6 +152,6 @@ static void plgform_close( plgform->close(options); } #undef DECL_PLGFORM -// +// -#endif // __PY_PLGFORM__ +#endif // __PY_KERNWIN_PLGFORM__ diff --git a/pywraps/py_plgform.py b/pywraps/py_kernwin_plgform.py similarity index 93% rename from pywraps/py_plgform.py rename to pywraps/py_kernwin_plgform.py index fe47a1a..a3d070b 100755 --- a/pywraps/py_plgform.py +++ b/pywraps/py_kernwin_plgform.py @@ -1,6 +1,5 @@ -import _idaapi - -# +# +import sys class PluginForm(object): """ PluginForm class. @@ -27,7 +26,7 @@ class PluginForm(object): def __init__(self): """ """ - self.__clink__ = _idaapi.plgform_new() + self.__clink__ = _ida_kernwin.plgform_new() @@ -39,7 +38,7 @@ class PluginForm(object): @param options: One of PluginForm.FORM_ constants """ options |= PluginForm.FORM_TAB|PluginForm.FORM_MENU|PluginForm.FORM_RESTORE - return _idaapi.plgform_show(self.__clink__, self, caption, options) + return _ida_kernwin.plgform_show(self.__clink__, self, caption, options) @staticmethod @@ -112,7 +111,7 @@ class PluginForm(object): @return: None """ - return _idaapi.plgform_close(self.__clink__, options) + return _ida_kernwin.plgform_close(self.__clink__, options) FORM_SAVE = 0x1 """Save state in desktop config""" @@ -125,7 +124,7 @@ class PluginForm(object): FORM_CLOSE_LATER = 0x8 """This flag should be used when Close() is called from an event handler""" -# +# plg = PluginForm() plg.Show("This is it") diff --git a/pywraps/py_lines.hpp b/pywraps/py_lines.hpp index 2661a34..21ae2a1 100644 --- a/pywraps/py_lines.hpp +++ b/pywraps/py_lines.hpp @@ -114,23 +114,31 @@ PyObject *py_tag_remove(const char *instr) { PYW_GIL_CHECK_LOCKED_SCOPE(); size_t sz = strlen(instr); - char *buf = new char[sz + 5]; - if ( buf == NULL ) - Py_RETURN_NONE; - - ssize_t r = tag_remove(instr, buf, sz); - PyObject *res; - if ( r < 0 ) + // Can't call tag_remove() with a size of 0; debug builds will INTERR 1270 + if ( sz > 0 ) { - Py_INCREF(Py_None); - res = Py_None; + char *buf = new char[sz + 5]; + if ( buf == NULL ) + Py_RETURN_NONE; + + ssize_t r = tag_remove(instr, buf, sz); + PyObject *res; + if ( r < 0 ) + { + Py_INCREF(Py_None); + res = Py_None; + } + else + { + res = PyString_FromString(buf); + } + delete [] buf; + return res; } else { - res = PyString_FromString(buf); + return PyString_FromString(""); } - delete [] buf; - return res; } //------------------------------------------------------------------------- @@ -194,7 +202,7 @@ PyObject *py_generate_disassembly( int nlines = generate_disassembly(ea, lines, max_lines, &lnnum, as_stack); newref_t py_tuple(PyTuple_New(nlines)); - for ( int i=0; i +import _ida_idaapi # ---------------- Color escape sequence defitions ------------------------- -COLOR_ADDR_SIZE = 16 if _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL else 8 +COLOR_ADDR_SIZE = 16 if _ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL else 8 SCOLOR_FG_MAX = '\x28' # Max color number SCOLOR_OPND1 = chr(cvar.COLOR_ADDR+1) # Instruction operand 1 SCOLOR_OPND2 = chr(cvar.COLOR_ADDR+2) # Instruction operand 2 @@ -12,7 +13,7 @@ SCOLOR_OPND6 = chr(cvar.COLOR_ADDR+6) # Instruction operand 6 SCOLOR_UTF8 = chr(cvar.COLOR_ADDR+10) # Following text is UTF-8 encoded # ---------------- Line prefix colors -------------------------------------- -PALETTE_SIZE = (cvar.COLOR_FG_MAX+_idaapi.COLOR_BG_MAX) +PALETTE_SIZE = (cvar.COLOR_FG_MAX+_ida_lines.COLOR_BG_MAX) def requires_color_esc(c): """ diff --git a/pywraps/py_nalt.hpp b/pywraps/py_nalt.hpp index 15be50f..28744be 100644 --- a/pywraps/py_nalt.hpp +++ b/pywraps/py_nalt.hpp @@ -39,18 +39,6 @@ static int idaapi py_import_enum_cb( NULL)); return py_result != NULL && PyObject_IsTrue(py_result.o) ? 1 : 0; } - -//------------------------------------------------------------------------- -switch_info_ex_t *switch_info_ex_t_get_clink(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( !PyObject_HasAttrString(self, S_CLINK_NAME) ) - return NULL; - - switch_info_ex_t *r; - newref_t attr(PyObject_GetAttrString(self, S_CLINK_NAME)); - return PyCObject_Check(attr.o) ? ((switch_info_ex_t *) PyCObject_AsVoidPtr(attr.o)) : NULL; -} // // @@ -94,7 +82,7 @@ PyObject *py_get_switch_info_ex(ea_t ea) ref_t py_obj; PYW_GIL_CHECK_LOCKED_SCOPE(); if ( ::get_switch_info_ex(ea, ex, sizeof(switch_info_ex_t)) <= 0 - || (py_obj = create_idaapi_linked_class_instance(S_PY_SWIEX_CLSNAME, ex)) == NULL ) + || (py_obj = create_linked_class_instance(S_IDA_NALT_MODNAME, S_PY_SWIEX_CLSNAME, ex)) == NULL ) { delete ex; Py_RETURN_NONE; @@ -103,114 +91,6 @@ PyObject *py_get_switch_info_ex(ea_t ea) return py_obj.o; } -//------------------------------------------------------------------------- -/* -# -def create_switch_xrefs(insn_ea, si): - """ - This function creates xrefs from the indirect jump. - - Usually there is no need to call this function directly because the kernel - will call it for switch tables - - Note: Custom switch information are not supported yet. - - @param insn_ea: address of the 'indirect jump' instruction - @param si: switch information - - @return: Boolean - """ - pass -# -*/ -idaman bool ida_export py_create_switch_xrefs( - ea_t insn_ea, - PyObject *py_swi) -{ - switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); - if ( swi == NULL ) - return false; - - create_switch_xrefs(insn_ea, swi); - return true; -} - -//------------------------------------------------------------------------- -struct cases_and_targets_t -{ - casevec_t cases; - eavec_t targets; -}; - -//------------------------------------------------------------------------- -/* -# -def calc_switch_cases(insn_ea, si): - """ - Get information about a switch's cases. - - The returned information can be used as follows: - - for idx in xrange(len(results.cases)): - cur_case = results.cases[idx] - for cidx in xrange(len(cur_case)): - print "case: %d" % cur_case[cidx] - print " goto 0x%x" % results.targets[idx] - - @param insn_ea: address of the 'indirect jump' instruction - @param si: switch information - - @return: a structure with 2 members: 'cases', and 'targets'. - """ - pass -# -*/ -idaman cases_and_targets_t *ida_export py_calc_switch_cases( - ea_t insn_ea, - PyObject *py_swi) -{ - switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); - if ( swi == NULL ) - return NULL; - - cases_and_targets_t *ct = new cases_and_targets_t; - if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) ) - { - delete ct; - return NULL; - } - - return ct; -} - - -//------------------------------------------------------------------------- -/* -# -def create_switch_table(insn_ea, si): - """ - Create switch table from the switch information - - @param insn_ea: address of the 'indirect jump' instruction - @param si: switch information - - @return: Boolean - """ - pass -# -*/ -idaman bool ida_export py_create_switch_table( - ea_t insn_ea, - PyObject *py_swi) -{ - switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); - if ( swi == NULL ) - return false; - - create_switch_table(insn_ea, swi); - return true; -} - //------------------------------------------------------------------------- /* # diff --git a/pywraps/py_nalt.py b/pywraps/py_nalt.py index a27c5a9..08e323b 100755 --- a/pywraps/py_nalt.py +++ b/pywraps/py_nalt.py @@ -1,4 +1,6 @@ # +import _ida_idaapi + SWI_SPARSE = 0x1 """sparse switch ( value table present ) otherwise lowcase present""" SWI_V32 = 0x2 @@ -42,18 +44,18 @@ SWI2_SUBTRACT = 0x0002 """table values are subtracted from the elbase instead of being addded""" # -------------------------------------------------------------------------- -class switch_info_ex_t(py_clinked_object_t): +class switch_info_ex_t(ida_idaapi.py_clinked_object_t): def __init__(self, lnk = None): - py_clinked_object_t.__init__(self, lnk) + ida_idaapi.py_clinked_object_t.__init__(self, lnk) def _create_clink(self): - return _idaapi.switch_info_ex_t_create() + return _ida_nalt.switch_info_ex_t_create() def _del_clink(self, lnk): - return _idaapi.switch_info_ex_t_destroy(lnk) + return _ida_nalt.switch_info_ex_t_destroy(lnk) def assign(self, other): - return _idaapi.switch_info_ex_t_assign(self, other) + return _ida_nalt.switch_info_ex_t_assign(self, other) def is_indirect(self): return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_INDIRECT) != 0 @@ -112,57 +114,57 @@ class switch_info_ex_t(py_clinked_object_t): # Autogenerated # def __get_regdtyp__(self): - return _idaapi.switch_info_ex_t_get_regdtyp(self) + return _ida_nalt.switch_info_ex_t_get_regdtyp(self) def __set_regdtyp__(self, v): - _idaapi.switch_info_ex_t_set_regdtyp(self, v) + _ida_nalt.switch_info_ex_t_set_regdtyp(self, v) def __get_flags2__(self): - return _idaapi.switch_info_ex_t_get_flags2(self) + return _ida_nalt.switch_info_ex_t_get_flags2(self) def __set_flags2__(self, v): - _idaapi.switch_info_ex_t_set_flags2(self, v) + _ida_nalt.switch_info_ex_t_set_flags2(self, v) def __get_jcases__(self): - return _idaapi.switch_info_ex_t_get_jcases(self) + return _ida_nalt.switch_info_ex_t_get_jcases(self) def __set_jcases__(self, v): - _idaapi.switch_info_ex_t_set_jcases(self, v) + _ida_nalt.switch_info_ex_t_set_jcases(self, v) def __get_regnum__(self): - return _idaapi.switch_info_ex_t_get_regnum(self) + return _ida_nalt.switch_info_ex_t_get_regnum(self) def __set_regnum__(self, v): - _idaapi.switch_info_ex_t_set_regnum(self, v) + _ida_nalt.switch_info_ex_t_set_regnum(self, v) def __get_flags__(self): - return _idaapi.switch_info_ex_t_get_flags(self) + return _ida_nalt.switch_info_ex_t_get_flags(self) def __set_flags__(self, v): - _idaapi.switch_info_ex_t_set_flags(self, v) + _ida_nalt.switch_info_ex_t_set_flags(self, v) def __get_ncases__(self): - return _idaapi.switch_info_ex_t_get_ncases(self) + return _ida_nalt.switch_info_ex_t_get_ncases(self) def __set_ncases__(self, v): - _idaapi.switch_info_ex_t_set_ncases(self, v) + _ida_nalt.switch_info_ex_t_set_ncases(self, v) def __get_defjump__(self): - return _idaapi.switch_info_ex_t_get_defjump(self) + return _ida_nalt.switch_info_ex_t_get_defjump(self) def __set_defjump__(self, v): - _idaapi.switch_info_ex_t_set_defjump(self, v) + _ida_nalt.switch_info_ex_t_set_defjump(self, v) def __get_jumps__(self): - return _idaapi.switch_info_ex_t_get_jumps(self) + return _ida_nalt.switch_info_ex_t_get_jumps(self) def __set_jumps__(self, v): - _idaapi.switch_info_ex_t_set_jumps(self, v) + _ida_nalt.switch_info_ex_t_set_jumps(self, v) def __get_elbase__(self): - return _idaapi.switch_info_ex_t_get_elbase(self) + return _ida_nalt.switch_info_ex_t_get_elbase(self) def __set_elbase__(self, v): - _idaapi.switch_info_ex_t_set_elbase(self, v) + _ida_nalt.switch_info_ex_t_set_elbase(self, v) def __get_startea__(self): - return _idaapi.switch_info_ex_t_get_startea(self) + return _ida_nalt.switch_info_ex_t_get_startea(self) def __set_startea__(self, v): - _idaapi.switch_info_ex_t_set_startea(self, v) + _ida_nalt.switch_info_ex_t_set_startea(self, v) def __get_custom__(self): - return _idaapi.switch_info_ex_t_get_custom(self) + return _ida_nalt.switch_info_ex_t_get_custom(self) def __set_custom__(self, v): - _idaapi.switch_info_ex_t_set_custom(self, v) + _ida_nalt.switch_info_ex_t_set_custom(self, v) def __get_ind_lowcase__(self): - return _idaapi.switch_info_ex_t_get_ind_lowcase(self) + return _ida_nalt.switch_info_ex_t_get_ind_lowcase(self) def __set_ind_lowcase__(self, v): - _idaapi.switch_info_ex_t_set_ind_lowcase(self, v) + _ida_nalt.switch_info_ex_t_set_ind_lowcase(self, v) def __get_values_lowcase__(self): - return _idaapi.switch_info_ex_t_get_values_lowcase(self) + return _ida_nalt.switch_info_ex_t_get_values_lowcase(self) def __set_values_lowcase__(self, v): - _idaapi.switch_info_ex_t_set_values_lowcase(self, v) + _ida_nalt.switch_info_ex_t_set_values_lowcase(self, v) regdtyp = property(__get_regdtyp__, __set_regdtyp__) """size of the switch expression register as dtyp""" flags2 = property(__get_flags2__, __set_flags2__) @@ -188,4 +190,4 @@ class switch_info_ex_t(py_clinked_object_t): values = property(__get_values_lowcase__, __set_values_lowcase__) lowcase = property(__get_values_lowcase__, __set_values_lowcase__) -# \ No newline at end of file +# diff --git a/pywraps/py_name.hpp b/pywraps/py_name.hpp index c2cdda5..4da0238 100644 --- a/pywraps/py_name.hpp +++ b/pywraps/py_name.hpp @@ -16,7 +16,7 @@ PyObject *py_get_debug_names(ea_t ea1, ea_t ea2) PyObject *dict = Py_BuildValue("{}"); if ( dict != NULL ) { - for ( ea_name_vec_t::iterator it=names.begin(); it!=names.end(); ++it ) + for ( ea_name_vec_t::iterator it=names.begin(); it != names.end(); ++it ) { PyDict_SetItem(dict, Py_BuildValue(PY_FMT64, it->ea), diff --git a/pywraps/py_name.py b/pywraps/py_name.py index 0cf43cb..9fbbd8c 100644 --- a/pywraps/py_name.py +++ b/pywraps/py_name.py @@ -2,7 +2,7 @@ import bisect # -class NearestName: +class NearestName(object): """ Utility class to help find the nearest name in a given ea/name dictionary """ diff --git a/pywraps/py_pro.hpp b/pywraps/py_pro.hpp new file mode 100644 index 0000000..f67a448 --- /dev/null +++ b/pywraps/py_pro.hpp @@ -0,0 +1,106 @@ +// +//--------------------------------------------------------------------------- +// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py) +//--------------------------------------------------------------------------- +static bool qstrvec_t_assign(PyObject *self, PyObject *other) +{ + qstrvec_t *lhs = qstrvec_t_get_clink(self); + qstrvec_t *rhs = qstrvec_t_get_clink(other); + if ( lhs == NULL || rhs == NULL ) + return false; + *lhs = *rhs; + return true; +} + +static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL || idx >= sv->size() ) + Py_RETURN_NONE; + else + return PyLong_FromUnsignedLongLong(size_t(&sv->at(idx))); +} + + +static bool qstrvec_t_set( + PyObject *self, + size_t idx, + const char *s) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL || idx >= sv->size() ) + return false; + (*sv)[idx] = s; + return true; +} + +static bool qstrvec_t_from_list( + PyObject *self, + PyObject *py_list) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + qstrvec_t *sv = qstrvec_t_get_clink(self); + return sv == NULL ? false : PyW_PyListToStrVec(py_list, *sv); +} + +static size_t qstrvec_t_size(PyObject *self) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + return sv == NULL ? 0 : sv->size(); +} + +static PyObject *qstrvec_t_get(PyObject *self, size_t idx) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL || idx >= sv->size() ) + Py_RETURN_NONE; + return PyString_FromString(sv->at(idx).c_str()); +} + +static bool qstrvec_t_add(PyObject *self, const char *s) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL ) + return false; + sv->push_back(s); + return true; +} + +static bool qstrvec_t_clear(PyObject *self, bool qclear) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL ) + return false; + + if ( qclear ) + sv->qclear(); + else + sv->clear(); + + return true; +} + +static bool qstrvec_t_insert( + PyObject *self, + size_t idx, + const char *s) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL || idx >= sv->size() ) + return false; + sv->insert(sv->begin() + idx, s); + return true; +} + +static bool qstrvec_t_remove(PyObject *self, size_t idx) +{ + qstrvec_t *sv = qstrvec_t_get_clink(self); + if ( sv == NULL || idx >= sv->size() ) + return false; + + sv->erase(sv->begin()+idx); + return true; +} +// diff --git a/pywraps/py_pro.py b/pywraps/py_pro.py new file mode 100644 index 0000000..ffc870e --- /dev/null +++ b/pywraps/py_pro.py @@ -0,0 +1,87 @@ + +# +import ida_idaapi +ida_idaapi._listify_types( + uvalvec_t, + intvec_t, + int64vec_t, + boolvec_t, + strvec_t) + +# ----------------------------------------------------------------------- +# qstrvec_t clinked object +class _qstrvec_t(ida_idaapi.py_clinked_object_t): + """ + WARNING: It is very unlikely an IDAPython user should ever, ever + have to use this type. It should only be used for IDAPython internals. + + For example, in py_askusingform.py, we ctypes-expose to the IDA + kernel & UI a qstrvec instance, in case a DropdownListControl is + constructed. + That's because that's what AskUsingForm expects, and we have no + choice but to make a DropdownListControl hold a qstrvec_t. + This is, afaict, the only situation where a Python + _qstrvec_t is required. + """ + + def __init__(self, items=None): + ida_idaapi.py_clinked_object_t.__init__(self) + # Populate the list if needed + if items: + self.from_list(items) + + def _create_clink(self): + return _ida_pro.qstrvec_t_create() + + def _del_clink(self, lnk): + return _ida_pro.qstrvec_t_destroy(lnk) + + def _get_clink_ptr(self): + return _ida_pro.qstrvec_t_get_clink_ptr(self) + + def assign(self, other): + """Copies the contents of 'other' to 'self'""" + return _ida_pro.qstrvec_t_assign(self, other) + + def __setitem__(self, idx, s): + """Sets string at the given index""" + return _ida_pro.qstrvec_t_set(self, idx, s) + + def __getitem__(self, idx): + """Gets the string at the given index""" + return _ida_pro.qstrvec_t_get(self, idx) + + def __get_size(self): + return _ida_pro.qstrvec_t_size(self) + + size = property(__get_size) + """Returns the count of elements""" + + def addressof(self, idx): + """Returns the address (as number) of the qstring at the given index""" + return _ida_pro.qstrvec_t_addressof(self, idx) + + def add(self, s): + """Add a string to the vector""" + return _ida_pro.qstrvec_t_add(self, s) + + def from_list(self, lst): + """Populates the vector from a Python string list""" + return _ida_pro.qstrvec_t_from_list(self, lst) + + def clear(self, qclear=False): + """ + Clears all strings from the vector. + @param qclear: Just reset the size but do not actually free the memory + """ + return _ida_pro.qstrvec_t_clear(self, qclear) + + def insert(self, idx, s): + """Insert a string into the vector""" + return _ida_pro.qstrvec_t_insert(self, idx, s) + + def remove(self, idx): + """Removes a string from the vector""" + return _ida_pro.qstrvec_t_remove(self, idx) + +# diff --git a/pywraps/py_typeinf.hpp b/pywraps/py_typeinf.hpp index 9441b2f..61788de 100644 --- a/pywraps/py_typeinf.hpp +++ b/pywraps/py_typeinf.hpp @@ -669,82 +669,88 @@ til_t *load_til_header_wrap(const char *tildir, const char *name) PyErr_SetString(PyExc_RuntimeError, errbuf); return res; } + +//------------------------------------------------------------------------- +/* +header: typeinf.hpp +# +def apply_type_to_stkarg(op, v, type, name): + """ + Apply type information to a stack variable + + @param op: reference to instruction operand + @param v: immediate value in the operand (usually op.addr) + @param type: type string. Retrieve from idc.ParseType("type string", flags)[1] + @param name: stack variable name + + @return: Boolean + """ + pass +# +*/ +bool py_apply_type_to_stkarg( + PyObject *py_op, + PyObject *py_uv, + PyObject *py_type, + const char *name) +{ + uint64 v; + PYW_GIL_CHECK_LOCKED_SCOPE(); + op_t *op = op_t_get_clink(py_op); + if ( op == NULL || !PyW_GetNumber(py_uv, &v) || !PyString_Check(py_type) ) + { + return false; + } + else + { + const type_t *t = (type_t *) PyString_AsString(py_type); + tinfo_t tif; + tif.deserialize(idati, &t); + borref_t br(py_op); + bool rc; + Py_BEGIN_ALLOW_THREADS; + rc = apply_tinfo_to_stkarg(*op, uval_t(v), tif, name); + Py_END_ALLOW_THREADS; + return rc; + } +} // // //------------------------------------------------------------------------- -// A set of tinfo_t & details objects that were created from IDAPython. -// This is necessary in order to clear all the "type details" that are -// associated, in the kernel, with the tinfo_t instances. -// -// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is -// closed, but the "type details" must be cleared _before_ the IDB is closed. -static qvector py_tinfo_t_vec; -static qvector py_ptr_type_data_t_vec; -static qvector py_array_type_data_t_vec; -static qvector py_func_type_data_t_vec; -static qvector py_udt_type_data_t_vec; - -static void __clear(tinfo_t *inst) { inst->clear(); } -static void __clear(ptr_type_data_t *inst) { inst->obj_type.clear(); inst->closure.clear(); } -static void __clear(array_type_data_t *inst) { inst->elem_type.clear(); } -static void __clear(func_type_data_t *inst) { inst->clear(); inst->rettype.clear(); } -static void __clear(udt_type_data_t *inst) { inst->clear(); } - -void til_clear_python_tinfo_t_instances(void) +inline const p_list * PyW_Fields(PyObject *tp) { - // Pre-emptive strike: clear all the python-exposed tinfo_t - // (& related types) instances: if that were not done here, - // ~tinfo_t() calls happening as part of the python shutdown - // process will try and clear() their details. ..but the kernel's - // til-related functions will already have deleted those details - // at that point. - // - // NOTE: Don't clear() the arrays of pointers. All the python-exposed - // instances will be deleted through the python shutdown/ref-decrementing - // process anyway (which will cause til_deregister_..() calls), and the - // entries will be properly pulled out of the vector when that happens. -#define BATCH_CLEAR(Type) \ - do \ - { \ - for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \ - __clear(py_##Type##_vec[i]); \ - } while ( false ) - - BATCH_CLEAR(tinfo_t); - BATCH_CLEAR(ptr_type_data_t); - BATCH_CLEAR(array_type_data_t); - BATCH_CLEAR(func_type_data_t); - BATCH_CLEAR(udt_type_data_t); -#undef BATCH_CLEAR + return tp == Py_None ? NULL : (const p_list *) PyString_AsString(tp); } -#define DEF_REG_UNREG_REFCOUNTED(Type) \ - void til_register_python_##Type##_instance(Type *inst) \ - { \ - /* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \ - /* to an object's tinfo_t property will end up trying to register it. */ \ - py_##Type##_vec.add_unique(inst); \ - } \ - \ - void til_deregister_python_##Type##_instance(Type *inst) \ - { \ - qvector::iterator found = py_##Type##_vec.find(inst); \ - if ( found != py_##Type##_vec.end() ) \ - { \ - __clear(inst); \ - /* tif->clear();*/ \ - py_##Type##_vec.erase(found); \ - } \ - } - -DEF_REG_UNREG_REFCOUNTED(tinfo_t); -DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t); -DEF_REG_UNREG_REFCOUNTED(array_type_data_t); -DEF_REG_UNREG_REFCOUNTED(func_type_data_t); -DEF_REG_UNREG_REFCOUNTED(udt_type_data_t); - -#undef DEF_REG_UNREG_REFCOUNTED +//------------------------------------------------------------------------- +// tuple(type_str, fields_str, field_cmts) on success +static PyObject *py_tinfo_t_serialize( + const tinfo_t *tif, + int sudt_flags) +{ + qtype type, fields, fldcmts; + if ( !tif->serialize(&type, &fields, &fldcmts, sudt_flags) ) + Py_RETURN_NONE; + PyObject *tuple = PyTuple_New(3); + int ctr = 0; +#define ADD(Thing) \ + do \ + { \ + PyObject *o = Py_None; \ + if ( (Thing).empty() ) \ + Py_INCREF(Py_None); \ + else \ + o = PyString_FromString((const char *) (Thing).begin()); \ + PyTuple_SetItem(tuple, ctr, o); \ + ++ctr; \ + } while ( false ) + ADD(type); + ADD(fields); + ADD(fldcmts); +#undef ADD + return tuple; +} // diff --git a/pywraps/py_typeinf.py b/pywraps/py_typeinf.py index c8bcc68..9bd7676 100644 --- a/pywraps/py_typeinf.py +++ b/pywraps/py_typeinf.py @@ -12,4 +12,8 @@ def get_type_size0(ti, tp): """ return calc_type_size(ti, tp) +import ida_idaapi +ida_idaapi._listify_types( + reginfovec_t) + # diff --git a/pywraps/py_ua.hpp b/pywraps/py_ua.hpp index 556121d..566fa3e 100644 --- a/pywraps/py_ua.hpp +++ b/pywraps/py_ua.hpp @@ -3,23 +3,10 @@ //------------------------------------------------------------------------- // -//------------------------------------------------------------------------- -insn_t *insn_t_get_clink(PyObject *self) -{ - return (insn_t *)pyobj_get_clink(self); -} - -//------------------------------------------------------------------------- -op_t *op_t_get_clink(PyObject *self) -{ - return (op_t *)pyobj_get_clink(self); -} // //------------------------------------------------------------------------- // - -//------------------------------------------------------------------------- /* # def init_output_buffer(size = MAXSTR): @@ -101,109 +88,6 @@ flags_t py_OutValue(PyObject *x, int outflags=0) return OutValue(*op, outflags); } -//------------------------------------------------------------------------- -/* -# -def get_stkvar(op, v): - """ - Get pointer to stack variable - @param op: reference to instruction operand - @param v: immediate value in the operand (usually op.addr) - @return: - - None on failure - - tuple(member_t, actval) - where actval: actual value used to fetch stack variable - """ - pass -# -*/ -PyObject *py_get_stkvar(PyObject *py_op, PyObject *py_v) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - uint64 v; - if ( op == NULL || !PyW_GetNumber(py_v, &v) ) - Py_RETURN_NONE; - - sval_t actval; - member_t *member = get_stkvar(*op, sval_t(v), &actval); - if ( member == NULL ) - Py_RETURN_NONE; - - return Py_BuildValue("(O" PY_SFMT64 ")", - SWIG_NewPointerObj(SWIG_as_voidptr(member), SWIGTYPE_p_member_t, 0), - pyl_t(actval)); -} - -//------------------------------------------------------------------------- -/* -header: frame.hpp -# -def add_stkvar3(op, v, flags): - """ - Automatically add stack variable if doesn't exist - Processor modules should use ua_stkvar2() - @param op: reference to instruction operand - @param v: immediate value in the operand (usually op.addr) - @param flags: combination of STKVAR_... constants - @return: Boolean - """ - pass -# -*/ -bool py_add_stkvar3(PyObject *py_op, PyObject *py_v, int flags) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - uint64 v; - return ( op == NULL || !PyW_GetNumber(py_v, &v) || !add_stkvar3(*op, sval_t(v), flags)) ? false : true; -} - -//------------------------------------------------------------------------- -/* -header: typeinf.hpp -# -def apply_type_to_stkarg(op, v, type, name): - """ - Apply type information to a stack variable - - @param op: reference to instruction operand - @param v: immediate value in the operand (usually op.addr) - @param type: type string. Retrieve from idc.ParseType("type string", flags)[1] - @param name: stack variable name - - @return: Boolean - """ - pass -# -*/ -bool py_apply_type_to_stkarg( - PyObject *py_op, - PyObject *py_uv, - PyObject *py_type, - const char *name) -{ - uint64 v; - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - if ( op == NULL || !PyW_GetNumber(py_uv, &v) || !PyString_Check(py_type) ) - { - return false; - } - else - { - const type_t *t = (type_t *) PyString_AsString(py_type); - tinfo_t tif; - tif.deserialize(idati, &t); - borref_t br(py_op); - bool rc; - Py_BEGIN_ALLOW_THREADS; - rc = apply_tinfo_to_stkarg(*op, uval_t(v), tif, name); - Py_END_ALLOW_THREADS; - return rc; - } -} - //------------------------------------------------------------------------- /* # diff --git a/pywraps/py_ua.py b/pywraps/py_ua.py index ccee1f3..d9c8ead 100644 --- a/pywraps/py_ua.py +++ b/pywraps/py_ua.py @@ -1,20 +1,21 @@ # +import ida_idaapi # ----------------------------------------------------------------------- -class op_t(py_clinked_object_t): +class op_t(ida_idaapi.py_clinked_object_t): """Class representing operands""" def __init__(self, lnk = None): - py_clinked_object_t.__init__(self, lnk) + ida_idaapi.py_clinked_object_t.__init__(self, lnk) def _create_clink(self): - return _idaapi.op_t_create() + return _ida_ua.op_t_create() def _del_clink(self, lnk): - return _idaapi.op_t_destroy(lnk) + return _ida_ua.op_t_destroy(lnk) def assign(self, other): """Copies the contents of 'other' to 'self'""" - return _idaapi.op_t_assign(self, other) + return _ida_ua.op_t_assign(self, other) def __eq__(self, other): """Checks if two register operands are equal by checking the register number and its dtype""" @@ -32,61 +33,61 @@ class op_t(py_clinked_object_t): # Autogenerated # def __get_n__(self): - return _idaapi.op_t_get_n(self) + return _ida_ua.op_t_get_n(self) def __set_n__(self, v): - _idaapi.op_t_set_n(self, v) + _ida_ua.op_t_set_n(self, v) def __get_type__(self): - return _idaapi.op_t_get_type(self) + return _ida_ua.op_t_get_type(self) def __set_type__(self, v): - _idaapi.op_t_set_type(self, v) + _ida_ua.op_t_set_type(self, v) def __get_offb__(self): - return _idaapi.op_t_get_offb(self) + return _ida_ua.op_t_get_offb(self) def __set_offb__(self, v): - _idaapi.op_t_set_offb(self, v) + _ida_ua.op_t_set_offb(self, v) def __get_offo__(self): - return _idaapi.op_t_get_offo(self) + return _ida_ua.op_t_get_offo(self) def __set_offo__(self, v): - _idaapi.op_t_set_offo(self, v) + _ida_ua.op_t_set_offo(self, v) def __get_flags__(self): - return _idaapi.op_t_get_flags(self) + return _ida_ua.op_t_get_flags(self) def __set_flags__(self, v): - _idaapi.op_t_set_flags(self, v) + _ida_ua.op_t_set_flags(self, v) def __get_dtyp__(self): - return _idaapi.op_t_get_dtyp(self) + return _ida_ua.op_t_get_dtyp(self) def __set_dtyp__(self, v): - _idaapi.op_t_set_dtyp(self, v) + _ida_ua.op_t_set_dtyp(self, v) def __get_reg_phrase__(self): - return _idaapi.op_t_get_reg_phrase(self) + return _ida_ua.op_t_get_reg_phrase(self) def __set_reg_phrase__(self, v): - _idaapi.op_t_set_reg_phrase(self, v) + _ida_ua.op_t_set_reg_phrase(self, v) def __get_value__(self): - return _idaapi.op_t_get_value(self) + return _ida_ua.op_t_get_value(self) def __set_value__(self, v): - _idaapi.op_t_set_value(self, v) + _ida_ua.op_t_set_value(self, v) def __get_addr__(self): - return _idaapi.op_t_get_addr(self) + return _ida_ua.op_t_get_addr(self) def __set_addr__(self, v): - _idaapi.op_t_set_addr(self, v) + _ida_ua.op_t_set_addr(self, v) def __get_specval__(self): - return _idaapi.op_t_get_specval(self) + return _ida_ua.op_t_get_specval(self) def __set_specval__(self, v): - _idaapi.op_t_set_specval(self, v) + _ida_ua.op_t_set_specval(self, v) def __get_specflag1__(self): - return _idaapi.op_t_get_specflag1(self) + return _ida_ua.op_t_get_specflag1(self) def __set_specflag1__(self, v): - _idaapi.op_t_set_specflag1(self, v) + _ida_ua.op_t_set_specflag1(self, v) def __get_specflag2__(self): - return _idaapi.op_t_get_specflag2(self) + return _ida_ua.op_t_get_specflag2(self) def __set_specflag2__(self, v): - _idaapi.op_t_set_specflag2(self, v) + _ida_ua.op_t_set_specflag2(self, v) def __get_specflag3__(self): - return _idaapi.op_t_get_specflag3(self) + return _ida_ua.op_t_get_specflag3(self) def __set_specflag3__(self, v): - _idaapi.op_t_set_specflag3(self, v) + _ida_ua.op_t_set_specflag3(self, v) def __get_specflag4__(self): - return _idaapi.op_t_get_specflag4(self) + return _ida_ua.op_t_get_specflag4(self) def __set_specflag4__(self, v): - _idaapi.op_t_set_specflag4(self, v) + _ida_ua.op_t_set_specflag4(self, v) n = property(__get_n__, __set_n__) type = property(__get_type__, __set_type__) @@ -104,11 +105,18 @@ class op_t(py_clinked_object_t): specflag3 = property(__get_specflag3__, __set_specflag3__) specflag4 = property(__get_specflag4__, __set_specflag4__) +# ---------------------------------------------------------------------- +# +# Misc constants +# +UA_MAXOP = 6 +"""The maximum number of operands in the insn_t structure""" + # ----------------------------------------------------------------------- -class insn_t(py_clinked_object_t): +class insn_t(ida_idaapi.py_clinked_object_t): """Class representing instructions""" def __init__(self, lnk = None): - py_clinked_object_t.__init__(self, lnk) + ida_idaapi.py_clinked_object_t.__init__(self, lnk) # Create linked operands self.Operands = [] @@ -125,7 +133,7 @@ class insn_t(py_clinked_object_t): def assign(self, other): """Copies the contents of 'other' to 'self'""" - return _idaapi.insn_t_assign(self, other) + return _ida_ua.insn_t_assign(self, other) # # def copy(self): @@ -134,11 +142,11 @@ class insn_t(py_clinked_object_t): # def _create_clink(self): - return _idaapi.insn_t_create() + return _ida_ua.insn_t_create() def _del_clink(self, lnk): - return _idaapi.insn_t_destroy(lnk) + return _ida_ua.insn_t_destroy(lnk) def __iter__(self): @@ -159,53 +167,53 @@ class insn_t(py_clinked_object_t): return self.flags & INSN_MACRO != 0 def is_canon_insn(self): - return _idaapi.insn_t_is_canon_insn(self.itype) + return _ida_ua.insn_t_is_canon_insn(self.itype) def get_canon_feature(self): - return _idaapi.insn_t_get_canon_feature(self.itype) + return _ida_ua.insn_t_get_canon_feature(self.itype) def get_canon_mnem(self): - return _idaapi.insn_t_get_canon_mnem(self.itype) + return _ida_ua.insn_t_get_canon_mnem(self.itype) # # Autogenerated # def __get_cs__(self): - return _idaapi.insn_t_get_cs(self) + return _ida_ua.insn_t_get_cs(self) def __set_cs__(self, v): - _idaapi.insn_t_set_cs(self, v) + _ida_ua.insn_t_set_cs(self, v) def __get_ip__(self): - return _idaapi.insn_t_get_ip(self) + return _ida_ua.insn_t_get_ip(self) def __set_ip__(self, v): - _idaapi.insn_t_set_ip(self, v) + _ida_ua.insn_t_set_ip(self, v) def __get_ea__(self): - return _idaapi.insn_t_get_ea(self) + return _ida_ua.insn_t_get_ea(self) def __set_ea__(self, v): - _idaapi.insn_t_set_ea(self, v) + _ida_ua.insn_t_set_ea(self, v) def __get_itype__(self): - return _idaapi.insn_t_get_itype(self) + return _ida_ua.insn_t_get_itype(self) def __set_itype__(self, v): - _idaapi.insn_t_set_itype(self, v) + _ida_ua.insn_t_set_itype(self, v) def __get_size__(self): - return _idaapi.insn_t_get_size(self) + return _ida_ua.insn_t_get_size(self) def __set_size__(self, v): - _idaapi.insn_t_set_size(self, v) + _ida_ua.insn_t_set_size(self, v) def __get_auxpref__(self): - return _idaapi.insn_t_get_auxpref(self) + return _ida_ua.insn_t_get_auxpref(self) def __set_auxpref__(self, v): - _idaapi.insn_t_set_auxpref(self, v) + _ida_ua.insn_t_set_auxpref(self, v) def __get_segpref__(self): - return _idaapi.insn_t_get_segpref(self) + return _ida_ua.insn_t_get_segpref(self) def __set_segpref__(self, v): - _idaapi.insn_t_set_segpref(self, v) + _ida_ua.insn_t_set_segpref(self, v) def __get_insnpref__(self): - return _idaapi.insn_t_get_insnpref(self) + return _ida_ua.insn_t_get_insnpref(self) def __set_insnpref__(self, v): - _idaapi.insn_t_set_insnpref(self, v) + _ida_ua.insn_t_set_insnpref(self, v) def __get_flags__(self): - return _idaapi.insn_t_get_flags(self) + return _ida_ua.insn_t_get_flags(self) def __set_flags__(self, v): - _idaapi.insn_t_set_flags(self, v) + _ida_ua.insn_t_set_flags(self, v) cs = property(__get_cs__, __set_cs__) ip = property(__get_ip__, __set_ip__) @@ -218,186 +226,11 @@ class insn_t(py_clinked_object_t): flags = property(__get_flags__, __set_flags__) -#---------------------------------------------------------------------------- -# P R O C E S S O R M O D U L E S C O N S T A N T S -#---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------- -# processor_t related constants - -CUSTOM_CMD_ITYPE = 0x8000 -REG_SPOIL = 0x80000000 - -REAL_ERROR_FORMAT = -1 # not supported format for current .idp -REAL_ERROR_RANGE = -2 # number too big (small) for store (mem NOT modifyed) -REAL_ERROR_BADDATA = -3 # illegal real data for load (IEEE data not filled) - -# -# Check whether the operand is relative to stack pointer or frame pointer. -# This function is used to determine how to output a stack variable -# This function may be absent. If it is absent, then all operands -# are sp based by default. -# Define this function only if some stack references use frame pointer -# instead of stack pointer. -# returns flags: -OP_FP_BASED = 0x00000000 # operand is FP based -OP_SP_BASED = 0x00000001 # operand is SP based -OP_SP_ADD = 0x00000000 # operand value is added to the pointer -OP_SP_SUB = 0x00000002 # operand value is substracted from the pointer - -# processor_t.id -PLFM_386 = 0 # Intel 80x86 -PLFM_Z80 = 1 # 8085, Z80 -PLFM_I860 = 2 # Intel 860 -PLFM_8051 = 3 # 8051 -PLFM_TMS = 4 # Texas Instruments TMS320C5x -PLFM_6502 = 5 # 6502 -PLFM_PDP = 6 # PDP11 -PLFM_68K = 7 # Motoroal 680x0 -PLFM_JAVA = 8 # Java -PLFM_6800 = 9 # Motorola 68xx -PLFM_ST7 = 10 # SGS-Thomson ST7 -PLFM_MC6812 = 11 # Motorola 68HC12 -PLFM_MIPS = 12 # MIPS -PLFM_ARM = 13 # Advanced RISC Machines -PLFM_TMSC6 = 14 # Texas Instruments TMS320C6x -PLFM_PPC = 15 # PowerPC -PLFM_80196 = 16 # Intel 80196 -PLFM_Z8 = 17 # Z8 -PLFM_SH = 18 # Renesas (formerly Hitachi) SuperH -PLFM_NET = 19 # Microsoft Visual Studio.Net -PLFM_AVR = 20 # Atmel 8-bit RISC processor(s) -PLFM_H8 = 21 # Hitachi H8/300, H8/2000 -PLFM_PIC = 22 # Microchip's PIC -PLFM_SPARC = 23 # SPARC -PLFM_ALPHA = 24 # DEC Alpha -PLFM_HPPA = 25 # Hewlett-Packard PA-RISC -PLFM_H8500 = 26 # Hitachi H8/500 -PLFM_TRICORE = 27 # Tasking Tricore -PLFM_DSP56K = 28 # Motorola DSP5600x -PLFM_C166 = 29 # Siemens C166 family -PLFM_ST20 = 30 # SGS-Thomson ST20 -PLFM_IA64 = 31 # Intel Itanium IA64 -PLFM_I960 = 32 # Intel 960 -PLFM_F2MC = 33 # Fujistu F2MC-16 -PLFM_TMS320C54 = 34 # Texas Instruments TMS320C54xx -PLFM_TMS320C55 = 35 # Texas Instruments TMS320C55xx -PLFM_TRIMEDIA = 36 # Trimedia -PLFM_M32R = 37 # Mitsubishi 32bit RISC -PLFM_NEC_78K0 = 38 # NEC 78K0 -PLFM_NEC_78K0S = 39 # NEC 78K0S -PLFM_M740 = 40 # Mitsubishi 8bit -PLFM_M7700 = 41 # Mitsubishi 16bit -PLFM_ST9 = 42 # ST9+ -PLFM_FR = 43 # Fujitsu FR Family -PLFM_MC6816 = 44 # Motorola 68HC16 -PLFM_M7900 = 45 # Mitsubishi 7900 -PLFM_TMS320C3 = 46 # Texas Instruments TMS320C3 -PLFM_KR1878 = 47 # Angstrem KR1878 -PLFM_AD218X = 48 # Analog Devices ADSP 218X -PLFM_OAKDSP = 49 # Atmel OAK DSP -PLFM_TLCS900 = 50 # Toshiba TLCS-900 -PLFM_C39 = 51 # Rockwell C39 -PLFM_CR16 = 52 # NSC CR16 -PLFM_MN102L00 = 53 # Panasonic MN10200 -PLFM_TMS320C1X = 54 # Texas Instruments TMS320C1x -PLFM_NEC_V850X = 55 # NEC V850 and V850ES/E1/E2 -PLFM_SCR_ADPT = 56 # Processor module adapter for processor modules written in scripting languages -PLFM_EBC = 57 # EFI Bytecode -PLFM_MSP430 = 58 # Texas Instruments MSP430 -PLFM_SPU = 59 # Cell Broadband Engine Synergistic Processor Unit - -# -# processor_t.flag -# -PR_SEGS = 0x000001 # has segment registers? -PR_USE32 = 0x000002 # supports 32-bit addressing? -PR_DEFSEG32 = 0x000004 # segments are 32-bit by default -PR_RNAMESOK = 0x000008 # allow to user register names for location names -PR_ADJSEGS = 0x000020 # IDA may adjust segments moving their starting/ending addresses. -PR_DEFNUM = 0x0000C0 # default number representation: -PRN_HEX = 0x000000 # hex -PRN_OCT = 0x000040 # octal -PRN_DEC = 0x000080 # decimal -PRN_BIN = 0x0000C0 # binary -PR_WORD_INS = 0x000100 # instruction codes are grouped 2bytes in binrary line prefix -PR_NOCHANGE = 0x000200 # The user can't change segments and code/data attributes (display only) -PR_ASSEMBLE = 0x000400 # Module has a built-in assembler and understands IDP_ASSEMBLE -PR_ALIGN = 0x000800 # All data items should be aligned properly -PR_TYPEINFO = 0x001000 # the processor module supports - # type information callbacks - # ALL OF THEM SHOULD BE IMPLEMENTED! - # (the ones >= decorate_name) -PR_USE64 = 0x002000 # supports 64-bit addressing? -PR_SGROTHER = 0x004000 # the segment registers don't contain - # the segment selectors, something else -PR_STACK_UP = 0x008000 # the stack grows up -PR_BINMEM = 0x010000 # the processor module provides correct - # segmentation for binary files - # (i.e. it creates additional segments) - # The kernel will not ask the user - # to specify the RAM/ROM sizes -PR_SEGTRANS = 0x020000 # the processor module supports - # the segment translation feature - # (it means it calculates the code - # addresses using the codeSeg() function) -PR_CHK_XREF = 0x040000 # don't allow near xrefs between segments - # with different bases -PR_NO_SEGMOVE = 0x080000 # the processor module doesn't support move_segm() - # (i.e. the user can't move segments) -PR_FULL_HIFXP = 0x100000 # REF_VHIGH operand value contains full operand - # not only the high bits. Meaningful if ph.high_fixup_bits -PR_USE_ARG_TYPES = 0x200000 # use ph.use_arg_types callback -PR_SCALE_STKVARS = 0x400000 # use ph.get_stkvar_scale callback -PR_DELAYED = 0x800000 # has delayed jumps and calls -PR_ALIGN_INSN = 0x1000000 # allow ida to create alignment instructions - # arbirtrarily. Since these instructions - # might lead to other wrong instructions - # and spoil the listing, IDA does not create - # them by default anymore -PR_PURGING = 0x2000000 # there are calling conventions which may - # purge bytes from the stack -PR_CNDINSNS = 0x4000000 # has conditional instructions -PR_USE_TBYTE = 0x8000000 # BTMT_SPECFLT means _TBYTE type -PR_DEFSEG64 = 0x10000000 # segments are 64-bit by default - - -# ---------------------------------------------------------------------- -# -# Misc constants -# -UA_MAXOP = 6 -"""The maximum number of operands in the insn_t structure""" - # Create 'cmd' into the global scope -cmd = insn_t(_idaapi.py_get_global_cmd_link()) +cmd = insn_t(_ida_ua.py_get_global_cmd_link()) """cmd is a global variable of type insn_t. It is contains information about the last decoded instruction. This variable is also filled by processor modules when they decode instructions.""" -# ---------------------------------------------------------------------- -# instruc_t related constants - -# -# instruc_t.feature -# -CF_STOP = 0x00001 # Instruction doesn't pass execution to the next instruction -CF_CALL = 0x00002 # CALL instruction (should make a procedure here) -CF_CHG1 = 0x00004 # The instruction modifies the first operand -CF_CHG2 = 0x00008 # The instruction modifies the second operand -CF_CHG3 = 0x00010 # The instruction modifies the third operand -CF_CHG4 = 0x00020 # The instruction modifies 4 operand -CF_CHG5 = 0x00040 # The instruction modifies 5 operand -CF_CHG6 = 0x00080 # The instruction modifies 6 operand -CF_USE1 = 0x00100 # The instruction uses value of the first operand -CF_USE2 = 0x00200 # The instruction uses value of the second operand -CF_USE3 = 0x00400 # The instruction uses value of the third operand -CF_USE4 = 0x00800 # The instruction uses value of the 4 operand -CF_USE5 = 0x01000 # The instruction uses value of the 5 operand -CF_USE6 = 0x02000 # The instruction uses value of the 6 operand -CF_JUMP = 0x04000 # The instruction passes execution using indirect jump or call (thus needs additional analysis) -CF_SHFT = 0x08000 # Bit-shift instruction (shl,shr...) -CF_HLL = 0x10000 # Instruction may be present in a high level language function. - # ---------------------------------------------------------------------- # op_t related constants @@ -458,64 +291,4 @@ OF_SHOW = 0x08 # should the operand be displayed? if clear, the operand is hidd INSN_MACRO = 0x01 # macro instruction INSN_MODMAC = 0x02 # macros: may modify the database to make room for the macro insn -# -# Set IDP options constants -# -IDPOPT_STR = 1 # string constant -IDPOPT_NUM = 2 # number -IDPOPT_BIT = 3 # bit, yes/no -IDPOPT_FLT = 4 # float -IDPOPT_I64 = 5 # 64bit number - -IDPOPT_OK = 0 # ok -IDPOPT_BADKEY = 1 # illegal keyword -IDPOPT_BADTYPE = 2 # illegal type of value -IDPOPT_BADVALUE = 3 # illegal value (bad range, for example) - -# ---------------------------------------------------------------------- -class processor_t(pyidc_opaque_object_t): - """Base class for all processor module scripts""" - def __init__(self): - # Take a reference to 'cmd' - self.cmd = cmd - - def get_idpdesc(self): - """ - This function must be present and should return the list of - short processor names similar to the one in ph.psnames. - This method can be overridden to return to the kernel a different IDP description. - """ - return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames))) - - def get_uFlag(self): - """Use this utility function to retrieve the 'uFlag' global variable""" - return _idaapi.cvar.uFlag - - def get_auxpref(self): - """This function returns cmd.auxpref value""" - return self.cmd.auxpref - - -# ---------------------------------------------------------------------- -class __ph(object): - id = property(lambda self: ph_get_id()) - cnbits = property(lambda self: ph_get_cnbits()) - dnbits = property(lambda self: ph_get_dnbits()) - flag = property(lambda self: ph_get_flag()) - high_fixup_bits = property(lambda self: ph_get_high_fixup_bits()) - icode_return = property(lambda self: ph_get_icode_return()) - instruc = property(lambda self: ph_get_instruc()) - instruc_end = property(lambda self: ph_get_instruc_end()) - instruc_start = property(lambda self: ph_get_instruc_start()) - regCodeSreg = property(lambda self: ph_get_regCodeSreg()) - regDataSreg = property(lambda self: ph_get_regDataSreg()) - regFirstSreg = property(lambda self: ph_get_regFirstSreg()) - regLastSreg = property(lambda self: ph_get_regLastSreg()) - regnames = property(lambda self: ph_get_regnames()) - segreg_size = property(lambda self: ph_get_segreg_size()) - tbyte_size = property(lambda self: ph_get_tbyte_size()) - version = property(lambda self: ph_get_version()) - -ph = __ph() - # diff --git a/pywraps/py_view.hpp b/pywraps/py_view.hpp deleted file mode 100644 index 4d78738..0000000 --- a/pywraps/py_view.hpp +++ /dev/null @@ -1,1052 +0,0 @@ - -// -//------------------------------------------------------------------------- -class py_customidamemo_t; -class lookup_info_t -{ -public: - struct entry_t - { - entry_t() : form(NULL), view(NULL), py_view(NULL) {} - private: - TForm *form; - TCustomControl *view; - py_customidamemo_t *py_view; - friend class lookup_info_t; - }; - - entry_t &new_entry(py_customidamemo_t *py_view) - { - QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view)); - entry_t &e = entries.push_back(); - e.py_view = py_view; - return e; - } - - void commit(entry_t &e, TForm *form, TCustomControl *view) - { - QASSERT(30455, &e >= entries.begin() && &e < entries.end()); - QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL - && !find_by_form(NULL, NULL, form) - && !find_by_view(NULL, NULL, view) - && find_by_py_view(NULL, NULL, e.py_view)); - e.form = form; - e.view = view; - } - -#define FIND_BY__BODY(crit, res1, res2) \ - { \ - for ( entries_t::const_iterator it = entries.begin(); it != entries.end(); ++it ) \ - { \ - const entry_t &e = *it; \ - if ( e.crit == crit ) \ - { \ - if ( out_##res1 != NULL ) \ - *out_##res1 = e.res1; \ - if ( out_##res2 != NULL ) \ - *out_##res2 = e.res2; \ - return true; \ - } \ - } \ - return false; \ - } - bool find_by_form(TCustomControl **out_view, py_customidamemo_t **out_py_view, const TForm *form) const FIND_BY__BODY(form, view, py_view); - bool find_by_view(TForm **out_form, py_customidamemo_t **out_py_view, const TCustomControl *view) const FIND_BY__BODY(view, form, py_view); - bool find_by_py_view(TForm **out_form, TCustomControl **out_view, const py_customidamemo_t *py_view) const FIND_BY__BODY(py_view, view, form); -#undef FIND_BY__BODY - - bool del_by_py_view(const py_customidamemo_t *py_view) - { - for ( entries_t::iterator it = entries.begin(); it != entries.end(); ++it ) - { - if ( it->py_view == py_view ) - { - entries.erase(it); - return true; - } - } - return false; - } - -private: - typedef qvector entries_t; - entries_t entries; -}; - -//------------------------------------------------------------------------- -template -T *view_extract_this(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - ref_t py_this(PyW_TryGetAttrString(self, S_M_THIS)); - if ( py_this == NULL || !PyCObject_Check(py_this.o) ) - return NULL; - return (T*) PyCObject_AsVoidPtr(py_this.o); -} - -//------------------------------------------------------------------------- -class py_customidamemo_t -{ - void convert_node_info( - node_info_t *out, - uint32 *out_flags, - ref_t py_nodeinfo) - { - if ( out_flags != NULL ) - *out_flags = 0; -#define COPY_PROP(checker, converter, pname, flag) \ - do \ - { \ - newref_t pname(PyObject_GetAttrString(py_nodeinfo.o, #pname)); \ - if ( pname != NULL && checker(pname.o) ) \ - { \ - out->pname = converter(pname.o); \ - if ( out_flags != NULL ) \ - *out_flags |= flag; \ - } \ - } while ( false ) -#define COPY_ULONG_PROP(pname, flag) COPY_PROP(PyNumber_Check, PyLong_AsUnsignedLong, pname, flag) -#define COPY_STRING_PROP(pname, flag) COPY_PROP(PyString_Check, PyString_AsString, pname, flag) - COPY_ULONG_PROP(bg_color, NIF_BG_COLOR); - COPY_ULONG_PROP(frame_color, NIF_FRAME_COLOR); - COPY_ULONG_PROP(ea, NIF_EA); - COPY_STRING_PROP(text, NIF_TEXT); -#undef COPY_STRING_PROP -#undef COPY_ULONG_PROP -#undef COPY_PROP - } - - enum - { - GRBASE_HAVE_VIEW_ACTIVATED = 0x001, - GRBASE_HAVE_VIEW_DEACTIVATED = 0x002, - GRBASE_HAVE_KEYDOWN = 0x004, - GRBASE_HAVE_POPUP = 0x008, - GRBASE_HAVE_VIEW_CLICK = 0x010, - GRBASE_HAVE_VIEW_DBLCLICK = 0x020, - GRBASE_HAVE_VIEW_CURPOS = 0x040, - GRBASE_HAVE_CLOSE = 0x080, - GRBASE_HAVE_VIEW_SWITCHED = 0x100, - GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200, - GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400, - }; - - static void ensure_view_callbacks_installed(); - int cb_flags; - // number of arguments for: - int ovc_num_args; // OnViewClick implementation - int ovdc_num_args; // OnViewDblclick implementation - int ovmo_num_args; // OnViewMouseOver implementation - int ovmm_num_args; // OnViewMouseMoved implementation - -protected: - ref_t self; - TCustomControl *view; - - struct callback_id_t - { - qstring name; - int have; - }; - struct callbacks_ids_t : public qvector - { - void add(const char *_n, int _h) - { - callback_id_t &o = push_back(); - o.name = _n; - o.have = _h; - } - }; - callbacks_ids_t cbids; - - bool collect_pyobject_callbacks(PyObject *self); - virtual void collect_class_callbacks_ids(callbacks_ids_t *out); - - void install_custom_viewer_handlers(); - - // Bi-directionally bind/unbind the Python object and this controller. - bool bind(PyObject *_self, TCustomControl *view); - void unbind(bool clear_view); - - static lookup_info_t lookup_info; - friend TForm *pycim_get_tform(PyObject *self); - friend TCustomControl *pycim_get_tcustom_control(PyObject *self); - -public: - py_customidamemo_t(); - virtual ~py_customidamemo_t(); - virtual void refresh() - { - refresh_viewer(view); - } - void set_node_info(PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags); - void set_nodes_infos(PyObject *dict); - PyObject *get_node_info(PyObject *py_node_idx); - void del_nodes_infos(PyObject *py_nodes); - PyObject *get_current_renderer_type(); - void set_current_renderer_type(PyObject *py_rto); - PyObject *create_groups(PyObject *groups_infos); - PyObject *delete_groups(PyObject *groups, PyObject *new_current); - PyObject *set_groups_visibility(PyObject *groups, PyObject *expand, PyObject *new_current); - - // View events - void on_view_activated(); - void on_view_deactivated(); - void on_view_keydown(int key, int state); - void on_view_popup(); - void on_view_click(const view_mouse_event_t *event); - void on_view_dblclick(const view_mouse_event_t *event); - void on_view_curpos(); - void on_view_close(); - void on_view_switched(tcc_renderer_type_t rt); - void on_view_mouse_over(const view_mouse_event_t *event); - void on_view_mouse_moved(const view_mouse_event_t *event); - inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } - int get_py_method_arg_count(char *method_name); - - // View events that are bound with 'set_custom_viewer_handler()'. - static void idaapi s_on_view_mouse_moved( - TCustomControl *cv, - int shift, - view_mouse_event_t *e, - void *ud); -}; - -//------------------------------------------------------------------------- -py_customidamemo_t::py_customidamemo_t() - : self(newref_t(NULL)), - view(NULL) -{ - PYGLOG("%p: py_customidamemo_t()\n", this); - ensure_view_callbacks_installed(); - ovc_num_args = -1; - ovdc_num_args = -1; - ovmo_num_args = -1; - ovmm_num_args = -1; -} - -//------------------------------------------------------------------------- -py_customidamemo_t::~py_customidamemo_t() -{ - PYGLOG("%p: ~py_customidamemo_t()\n", this); - unbind(true); - lookup_info.del_by_py_view(this); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::ensure_view_callbacks_installed() -{ - static bool installed = false; - if ( !installed ) - { - struct ida_local lambda_t - { - static int idaapi callback(void * /*ud*/, int code, va_list va) - { - py_customidamemo_t *py_view; - if ( lookup_info.find_by_view(NULL, &py_view, va_arg(va, TCustomControl *)) ) - { - PYW_GIL_GET; - switch ( code ) - { - case view_activated: - py_view->on_view_activated(); - break; - case view_deactivated: - py_view->on_view_deactivated(); - break; - case view_keydown: - { - int key = va_arg(va, int); - int state = va_arg(va, int); - py_view->on_view_keydown(key, state); - } - break; - case obsolete_view_popup: - py_view->on_view_popup(); - break; - case view_click: - case view_dblclick: - { - const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); - if ( code == view_click ) - py_view->on_view_click(event); - else - py_view->on_view_dblclick(event); - } - break; - case view_curpos: - py_view->on_view_curpos(); - break; - case view_close: - py_view->on_view_close(); - delete py_view; - break; - case view_switched: - { - tcc_renderer_type_t rt = (tcc_renderer_type_t) va_arg(va, int); - py_view->on_view_switched(rt); - } - break; - case view_mouse_over: - { - const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); - py_view->on_view_mouse_over(event); - } - break; - } - } - return 0; - } - }; - hook_to_notification_point(HT_VIEW, lambda_t::callback, NULL); - installed = true; - } -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::set_node_info( - PyObject *py_node_idx, - PyObject *py_node_info, - PyObject *py_flags) -{ - if ( !PyNumber_Check(py_node_idx) || !PyNumber_Check(py_flags) ) - return; - borref_t py_idx(py_node_idx); - borref_t py_ni(py_node_info); - borref_t py_fl(py_flags); - node_info_t ni; - convert_node_info(&ni, NULL, py_ni); - int idx = PyInt_AsLong(py_idx.o); - uint32 flgs = PyLong_AsLong(py_fl.o); - viewer_set_node_info(view, idx, ni, flgs); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::set_nodes_infos(PyObject *dict) -{ - if ( !PyDict_Check(dict) ) - return; - Py_ssize_t pos = 0; - PyObject *o_key, *o_value; - while ( PyDict_Next(dict, &pos, &o_key, &o_value) ) - { - borref_t key(o_key); - borref_t value(o_value); - if ( !PyNumber_Check(key.o) ) - continue; - uint32 flags; - node_info_t ni; - convert_node_info(&ni, &flags, value); - int idx = PyInt_AsLong(key.o); - viewer_set_node_info(view, idx, ni, flags); - } -} - -//------------------------------------------------------------------------- -PyObject *py_customidamemo_t::get_node_info(PyObject *py_node_idx) -{ - if ( !PyNumber_Check(py_node_idx) ) - Py_RETURN_NONE; - node_info_t ni; - if ( !viewer_get_node_info(view, &ni, PyInt_AsLong(py_node_idx)) ) - Py_RETURN_NONE; - return Py_BuildValue("(kkks)", ni.bg_color, ni.frame_color, ni.ea, ni.text.c_str()); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::del_nodes_infos(PyObject *py_nodes) -{ - if ( !PySequence_Check(py_nodes) ) - return; - Py_ssize_t sz = PySequence_Size(py_nodes); - for ( Py_ssize_t i = 0; i < sz; ++i ) - { - newref_t item(PySequence_GetItem(py_nodes, i)); - if ( !PyNumber_Check(item.o) ) - continue; - int idx = PyInt_AsLong(item.o); - viewer_del_node_info(view, idx); - } -} - -//------------------------------------------------------------------------- -PyObject *py_customidamemo_t::get_current_renderer_type() -{ - tcc_renderer_type_t rt = get_view_renderer_type(view); - return PyLong_FromLong(long(rt)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::set_current_renderer_type(PyObject *py_rto) -{ - tcc_renderer_type_t rt = TCCRT_INVALID; - borref_t py_rt(py_rto); - if ( PyNumber_Check(py_rt.o) ) - { - rt = tcc_renderer_type_t(PyLong_AsLong(py_rt.o)); - set_view_renderer_type(view, rt); - } -} - -//------------------------------------------------------------------------- -PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) -{ - if ( !PySequence_Check(_groups_infos) ) - Py_RETURN_NONE; - borref_t groups_infos(_groups_infos); - groups_crinfos_t gis; - Py_ssize_t sz = PySequence_Size(groups_infos.o); - for ( Py_ssize_t i = 0; i < sz; ++i ) - { - newref_t item(PySequence_GetItem(groups_infos.o, i)); - if ( !PyDict_Check(item.o) ) - continue; - borref_t nodes(PyDict_GetItemString(item.o, "nodes")); - if ( nodes.o == NULL || !PySequence_Check(nodes.o) ) - continue; - borref_t text(PyDict_GetItemString(item.o, "text")); - if ( text.o == NULL || !PyString_Check(text.o) ) - continue; - group_crinfo_t gi; - Py_ssize_t nodes_cnt = PySequence_Size(nodes.o); - for ( Py_ssize_t k = 0; k < nodes_cnt; ++k ) - { - newref_t node(PySequence_GetItem(nodes.o, k)); - if ( PyInt_Check(node.o) ) - gi.nodes.add_unique(PyInt_AsLong(node.o)); - } - if ( !gi.nodes.empty() ) - { - gi.text = PyString_AsString(text.o); - gis.push_back(gi); - } - } - intvec_t groups; - if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() ) - Py_RETURN_NONE; - - PyObject *py_groups = PyList_New(0); - for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) - PyList_Append(py_groups, PyInt_FromLong(long(*it))); - return py_groups; -} - -//------------------------------------------------------------------------- -static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes) -{ - Py_ssize_t sz = PySequence_Size(pynodes.o); - for ( Py_ssize_t i = 0; i < sz; ++i ) - { - newref_t item(PySequence_GetItem(pynodes.o, i)); - if ( !PyInt_Check(item.o) ) - continue; - idanodes->add_unique(PyInt_AsLong(item.o)); - } -} - -//------------------------------------------------------------------------- -PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_current) -{ - if ( !PySequence_Check(_groups) || !PyNumber_Check(_new_current) ) - Py_RETURN_NONE; - borref_t groups(_groups); - borref_t new_current(_new_current); - intvec_t ida_groups; - pynodes_to_idanodes(&ida_groups, groups); - if ( ida_groups.empty() ) - Py_RETURN_NONE; - if ( viewer_delete_groups(view, ida_groups, int(PyInt_AsLong(new_current.o))) ) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -//------------------------------------------------------------------------- -PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject *_expand, PyObject *_new_current) -{ - if ( !PySequence_Check(_groups) - || !PyBool_Check(_expand) - || !PyNumber_Check(_new_current) ) - Py_RETURN_NONE; - borref_t groups(_groups); - borref_t expand(_expand); - borref_t new_current(_new_current); - intvec_t ida_groups; - pynodes_to_idanodes(&ida_groups, groups); - if ( ida_groups.empty() ) - Py_RETURN_NONE; - if ( viewer_set_groups_visibility(view, ida_groups, expand.o == Py_True, int(PyInt_AsLong(new_current.o))) ) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -//------------------------------------------------------------------------- -bool py_customidamemo_t::bind(PyObject *_self, TCustomControl *view) -{ - if ( this->self != NULL || this->view != NULL ) - return false; - PYGLOG("%p: py_customidamemo_t::bind(_self=%p, view=%p)\n", this, _self, view); - PYW_GIL_CHECK_LOCKED_SCOPE(); - - newref_t py_cobj(PyCObject_FromVoidPtr(this, NULL)); - PyObject_SetAttrString(_self, S_M_THIS, py_cobj.o); - - this->self = borref_t(_self); - this->view = view; - return true; -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::unbind(bool clear_view) -{ - if ( self == NULL ) - return; - PYGLOG("%p: py_customidamemo_t::unbind(); self.o=%p, view=%p\n", this, self.o, view); - PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t py_cobj(PyCObject_FromVoidPtr(NULL, NULL)); - PyObject_SetAttrString(self.o, S_M_THIS, py_cobj.o); - self = newref_t(NULL); - if ( clear_view ) - view = NULL; -} - -//------------------------------------------------------------------------- -void idaapi py_customidamemo_t::s_on_view_mouse_moved( - TCustomControl *cv, - int shift, - view_mouse_event_t *e, - void *ud) -{ - PYW_GIL_GET; - py_customidamemo_t *_this = (py_customidamemo_t *) ud; - _this->on_view_mouse_moved(e); -} - -//------------------------------------------------------------------------- -int py_customidamemo_t::get_py_method_arg_count(char *method_name) -{ - newref_t method(PyObject_GetAttrString(self.o, method_name)); - if ( method != NULL && PyCallable_Check(method.o) ) - { - newref_t fc(PyObject_GetAttrString(method.o, "func_code")); - if ( fc != NULL ) - { - newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount")); - if ( ac != NULL ) - return PyInt_AsLong(ac.o); - } - } - return -1; -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out) -{ - out->add(S_ON_VIEW_ACTIVATED, GRBASE_HAVE_VIEW_ACTIVATED); - out->add(S_ON_VIEW_DEACTIVATED, GRBASE_HAVE_VIEW_DEACTIVATED); - out->add(S_ON_VIEW_KEYDOWN, GRBASE_HAVE_KEYDOWN); - out->add(S_ON_POPUP, GRBASE_HAVE_POPUP); - out->add(S_ON_VIEW_CLICK, GRBASE_HAVE_VIEW_CLICK); - out->add(S_ON_VIEW_DBLCLICK, GRBASE_HAVE_VIEW_DBLCLICK); - out->add(S_ON_VIEW_CURPOS, GRBASE_HAVE_VIEW_CURPOS); - out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE); - out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED); - out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER); - out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED); -} - -//------------------------------------------------------------------------- -bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o) -{ - callbacks_ids_t cbids; - collect_class_callbacks_ids(&cbids); - cb_flags = 0; - for ( callbacks_ids_t::const_iterator it = cbids.begin(); it != cbids.end(); ++it ) - { - const callback_id_t &cbid = *it; - ref_t attr(PyW_TryGetAttrString(o, cbid.name.c_str())); - int have = cbid.have; - // Mandatory fields not present? - if ( (attr == NULL && have <= 0) - // Mandatory callback fields present but not callable? - || (attr != NULL && have >= 0 && PyCallable_Check(attr.o) == 0) ) - { - return false; - } - if ( have > 0 && attr != NULL ) - cb_flags |= have; - } - - return true; -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::install_custom_viewer_handlers() -{ - if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) ) - { - // Set user-data - set_custom_viewer_handler(view, CVH_USERDATA, (void *)this); - - // - set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved); - } -} - -//------------------------------------------------------------------------- -#define CHK_EVT(flag_needed) \ - if ( self == NULL || !has_callback(flag_needed) ) \ - return; \ - PYW_GIL_CHECK_LOCKED_SCOPE() - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_activated() -{ - CHK_EVT(GRBASE_HAVE_VIEW_ACTIVATED); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_ACTIVATED, - NULL)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_deactivated() -{ - CHK_EVT(GRBASE_HAVE_VIEW_DEACTIVATED); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_DEACTIVATED, - NULL)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_keydown(int key, int state) -{ - CHK_EVT(GRBASE_HAVE_KEYDOWN); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_KEYDOWN, - "ii", - key, state)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_popup() -{ - CHK_EVT(GRBASE_HAVE_POPUP); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_POPUP, - NULL)); -} - -//------------------------------------------------------------------------- -static PyObject *build_renderer_pos_swig_proxy(const view_mouse_event_t *event) -{ - return SWIG_NewPointerObj( - SWIG_as_voidptr(&event->renderer_pos), - SWIGTYPE_p_renderer_pos_info_t, - 0); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) -{ - CHK_EVT(GRBASE_HAVE_VIEW_CLICK); - if ( ovc_num_args < 0 ) - ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); - if ( ovc_num_args == 6 ) - { - PyObject *rpos = build_renderer_pos_swig_proxy(event); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CLICK, - "iiiiO", - event->x, event->y, event->state, event->button, rpos)); - } - else if ( ovc_num_args == 5 ) - { - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CLICK, - "iiii", - event->x, event->y, event->state, event->button)); - } - else - { - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CLICK, - "iii", - event->x, event->y, event->state)); - } -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event) -{ - CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK); - if ( ovdc_num_args < 0 ) - ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK); - if ( ovdc_num_args == 5 ) - { - PyObject *rpos = build_renderer_pos_swig_proxy(event); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_DBLCLICK, - "iiiO", - event->x, event->y, event->state, rpos)); - } - else - { - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_DBLCLICK, - "iii", - event->x, event->y, event->state)); - } -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_curpos() -{ - CHK_EVT(GRBASE_HAVE_VIEW_CURPOS); - pycall_res_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CURPOS, - NULL)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_close() -{ - CHK_EVT(GRBASE_HAVE_CLOSE); - pycall_res_t result(PyObject_CallMethod(self.o, (char *)S_ON_CLOSE, NULL)); -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_switched(tcc_renderer_type_t rt) -{ - CHK_EVT(GRBASE_HAVE_VIEW_SWITCHED); - pycall_res_t result(PyObject_CallMethod(self.o, (char *)S_ON_VIEW_SWITCHED, "i", int(rt))); -} - -//------------------------------------------------------------------------- -static ref_t build_current_graph_item_tuple(int *out_icode, const view_mouse_event_t *event) -{ - const selection_item_t *item = event->location.item; - ref_t tuple; - if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY) - && item != NULL ) - { - if ( item->is_node ) - { - *out_icode = 1; - tuple = newref_t(Py_BuildValue("(i)", item->node)); - } - else - { - *out_icode = 2; - tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst)); - } - } - else - { - *out_icode = 0; - tuple = newref_t(Py_BuildValue("()")); - } - return tuple; -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event) -{ - CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER); - if ( ovmo_num_args < 0 ) - ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER); - if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY ) - return; - - int icode; - ref_t tuple = build_current_graph_item_tuple(&icode, event); - if ( ovmo_num_args == 7 ) - { - PyObject *rpos = build_renderer_pos_swig_proxy(event); - pycall_res_t result(PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_MOUSE_OVER, - "iiiiOO", - event->x, event->y, event->state, icode, tuple.o, rpos)); - } - else - { - pycall_res_t result(PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_MOUSE_OVER, - "iiiiO", - event->x, event->y, event->state, icode, tuple.o)); - } -} - -//------------------------------------------------------------------------- -void py_customidamemo_t::on_view_mouse_moved(const view_mouse_event_t *event) -{ - CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_MOVED); - if ( ovmm_num_args < 0 ) - ovmm_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_MOVED); - - int icode; - ref_t tuple = build_current_graph_item_tuple(&icode, event); - if ( ovmm_num_args == 7 ) - { - PyObject *rpos = build_renderer_pos_swig_proxy(event); - pycall_res_t result(PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_MOUSE_MOVED, - "iiiiOO", - event->x, event->y, event->state, icode, tuple.o, rpos)); - } -} - - -#undef CHK_EVT - -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- - -#define GET_THIS() py_customidamemo_t *_this = view_extract_this(self) -#define CHK_THIS() \ - GET_THIS(); \ - if ( _this == NULL ) \ - return; -#define CHK_THIS_OR_NULL() \ - GET_THIS(); \ - if ( _this == NULL ) \ - return NULL; -#define CHK_THIS_OR_NONE() \ - GET_THIS(); \ - if ( _this == NULL ) \ - Py_RETURN_NONE - -//------------------------------------------------------------------------- -void pygc_refresh(PyObject *self) -{ - CHK_THIS(); - _this->refresh(); -} - -//------------------------------------------------------------------------- -void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) -{ - CHK_THIS(); - _this->set_node_info(py_node_idx, py_node_info, py_flags); -} - -//------------------------------------------------------------------------- -void pygc_set_nodes_infos(PyObject *self, PyObject *values) -{ - CHK_THIS(); - _this->set_nodes_infos(values); -} - -//------------------------------------------------------------------------- -PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx) -{ - GET_THIS(); - if ( _this != NULL ) - return _this->get_node_info(py_node_idx); - else - Py_RETURN_NONE; -} - -//------------------------------------------------------------------------- -void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes) -{ - CHK_THIS(); - _this->del_nodes_infos(py_nodes); -} - -//------------------------------------------------------------------------- -PyObject *pygc_get_current_renderer_type(PyObject *self) -{ - GET_THIS(); - if ( _this != NULL ) - return _this->get_current_renderer_type(); - else - Py_RETURN_NONE; -} - -//------------------------------------------------------------------------- -void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt) -{ - CHK_THIS(); - _this->set_current_renderer_type(py_rt); -} - -//------------------------------------------------------------------------- -PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos) -{ - CHK_THIS_OR_NONE(); - return _this->create_groups(groups_infos); -} - -//------------------------------------------------------------------------- -PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current) -{ - CHK_THIS_OR_NONE(); - return _this->delete_groups(groups, new_current); -} - -//------------------------------------------------------------------------- -PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current) -{ - CHK_THIS_OR_NONE(); - return _this->set_groups_visibility(groups, expand, new_current); -} - -//------------------------------------------------------------------------- -TForm *pycim_get_tform(PyObject *self) -{ - CHK_THIS_OR_NULL(); - TForm *form = NULL; - if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) ) - return NULL; - return form; -} - -//------------------------------------------------------------------------- -TCustomControl *pycim_get_tcustom_control(PyObject *self) -{ - CHK_THIS_OR_NULL(); - TCustomControl *tcc = NULL; - if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) ) - return NULL; - return tcc; -} - -#undef CHK_THIS_OR_NONE -#undef CHK_THIS_OR_NULL -#undef CHK_THIS -#undef GET_THIS - -//------------------------------------------------------------------------- -lookup_info_t py_customidamemo_t::lookup_info; - -//------------------------------------------------------------------------- -// py_idaview_t -//------------------------------------------------------------------------- -class py_idaview_t : public py_customidamemo_t -{ - typedef py_customidamemo_t inherited; - -public: - static bool Bind(PyObject *self); - static bool Unbind(PyObject *self); -}; - -//------------------------------------------------------------------------- -bool py_idaview_t::Bind(PyObject *self) -{ - // Already a py_idaview_t associated to this object? - py_idaview_t *_this = view_extract_this(self); - if ( _this != NULL ) - return false; - - qstring title; - if ( !PyW_GetStringAttr(self, S_M_TITLE, &title) ) - return false; - - // Get the IDAView associated to this TForm - TForm *tform = find_tform(title.c_str()); - if ( tform == NULL ) - return false; - TCustomControl *v = get_tform_idaview(tform); - if ( v == NULL ) - return false; - - // Get unique py_idaview_t associated to that tform - py_idaview_t *py_view; - TCustomControl *found_view; - if ( lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_view, tform) ) - { - // If we have a py_idaview_t for that form, ensure it has - // the expected view. - QASSERT(30451, found_view == v); - } - else - { - py_view = new py_idaview_t(); - lookup_info_t::entry_t &e = lookup_info.new_entry(py_view); - lookup_info.commit(e, tform, v); - } - - // Finally, bind: - // py_idaview_t <=> IDAViewWrapper - // py_idaview_t => TCustomControl - bool ok = py_view->bind(self, v); - if ( ok ) - { - ok = py_view->collect_pyobject_callbacks(self); - if ( ok ) - py_view->install_custom_viewer_handlers(); - else - delete py_view; - } - return ok; -} - -//------------------------------------------------------------------------- -bool py_idaview_t::Unbind(PyObject *self) -{ - py_idaview_t *_this = view_extract_this(self); - if ( _this == NULL ) - return false; - _this->unbind(true); - return true; -} - -//------------------------------------------------------------------------- -bool pyidag_bind(PyObject *self) -{ - return py_idaview_t::Bind(self); -} - -//------------------------------------------------------------------------- -bool pyidag_unbind(PyObject *self) -{ - return py_idaview_t::Unbind(self); -} -// - -// -void pygc_refresh(PyObject *self); -void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags); -void pygc_set_nodes_infos(PyObject *self, PyObject *values); -PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx); -void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes); -PyObject *pygc_get_current_renderer_type(PyObject *self); -void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt); -PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos); -PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current); -PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current); -TForm *pycim_get_tform(PyObject *self); -TCustomControl *pycim_get_tcustom_control(PyObject *self); - -//------------------------------------------------------------------------- -// py_idaview_t -//------------------------------------------------------------------------- -bool pyidag_bind(PyObject *self); -bool pyidag_unbind(PyObject *self); -// diff --git a/pywraps/py_view.py b/pywraps/py_view.py deleted file mode 100644 index b2d22d5..0000000 --- a/pywraps/py_view.py +++ /dev/null @@ -1,144 +0,0 @@ - -# -class CustomIDAMemo(object): - def Refresh(self): - """ - Refreshes the graph. This causes the OnRefresh() to be called - """ - _idaapi.pygc_refresh(self) - - def GetCurrentRendererType(self): - return _idaapi.pygc_get_current_renderer_type(self) - - def SetCurrentRendererType(self, rtype): - """ - Set the current view's renderer. - - @param rtype: The renderer type. Should be one of the idaapi.TCCRT_* values. - """ - _idaapi.pygc_set_current_renderer_type(self, rtype) - - def SetNodeInfo(self, node_index, node_info, flags): - """ - Set the properties for the given node. - - Example usage (set second nodes's bg color to red): - inst = ... - p = idaapi.node_info_t() - p.bg_color = 0x00ff0000 - inst.SetNodeInfo(1, p, idaapi.NIF_BG_COLOR) - - @param node_index: The node index. - @param node_info: An idaapi.node_info_t instance. - @param flags: An OR'ed value of NIF_* values. - """ - _idaapi.pygc_set_node_info(self, node_index, node_info, flags) - - def SetNodesInfos(self, values): - """ - Set the properties for the given nodes. - - Example usage (set first three nodes's bg color to purple): - inst = ... - p = idaapi.node_info_t() - p.bg_color = 0x00ff00ff - inst.SetNodesInfos({0 : p, 1 : p, 2 : p}) - - @param values: A dictionary of 'int -> node_info_t' objects. - """ - _idaapi.pygc_set_nodes_infos(self, values) - - def GetNodeInfo(self, node): - """ - Get the properties for the given node. - - @param node: The index of the node. - @return: A tuple (bg_color, frame_color, ea, text), or None. - """ - return _idaapi.pygc_get_node_info(self, node) - - def DelNodesInfos(self, *nodes): - """ - Delete the properties for the given node(s). - - @param nodes: A list of node IDs - """ - return _idaapi.pygc_del_nodes_infos(self, nodes) - - def CreateGroups(self, groups_infos): - """ - Send a request to modify the graph by creating a - (set of) group(s), and perform an animation. - - Each object in the 'groups_infos' list must be of the format: - { - "nodes" : [, , , ...] # The list of nodes to group - "text" : # The synthetic text for that group - } - - @param groups_infos: A list of objects that describe those groups. - @return: A [, , ...] list of group nodes, or None (failure). - """ - return _idaapi.pygc_create_groups(self, groups_infos) - - def DeleteGroups(self, groups, new_current = -1): - """ - Send a request to delete the specified groups in the graph, - and perform an animation. - - @param groups: A list of group node numbers. - @param new_current: A node to focus on after the groups have been deleted - @return: True on success, False otherwise. - """ - return _idaapi.pygc_delete_groups(self, groups, new_current) - - def SetGroupsVisibility(self, groups, expand, new_current = -1): - """ - Send a request to expand/collapse the specified groups in the graph, - and perform an animation. - - @param groups: A list of group node numbers. - @param expand: True to expand the group, False otherwise. - @param new_current: A node to focus on after the groups have been expanded/collapsed. - @return: True on success, False otherwise. - """ - return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current) - - def GetTForm(self): - """ - Return the TForm hosting this view. - - @return: The TForm that hosts this view, or None. - """ - return _idaapi.pycim_get_tform(self) - - def GetTCustomControl(self): - """ - Return the TCustomControl underlying this view. - - @return: The TCustomControl underlying this view, or None. - """ - return _idaapi.pycim_get_tcustom_control(self) - - -#------------------------------------------------------------------------- -# IDAViewWrapper -#------------------------------------------------------------------------- -class IDAViewWrapper(CustomIDAMemo): - """This class wraps access to native IDA views. See kernwin.hpp file""" - def __init__(self, title): - """ - Constructs the IDAViewWrapper object around the view - whose title is 'title'. - - @param title: The title of the existing IDA view. E.g., 'IDA View-A' - """ - self._title = title - - def Bind(self): - return _idaapi.pyidag_bind(self) - - def Unbind(self): - return _idaapi.pyidag_unbind(self) - -# diff --git a/pywraps/py_xref.hpp b/pywraps/py_xref.hpp new file mode 100644 index 0000000..c5fcdbd --- /dev/null +++ b/pywraps/py_xref.hpp @@ -0,0 +1,118 @@ + +//------------------------------------------------------------------------- +// + +// important for SWiG to generate properly-wrapped vector classes +typedef qvector svalvec_t; +typedef qvector casevec_t; +typedef qvector eavec_t; +// + +/* +# +def create_switch_xrefs(insn_ea, si): + """ + This function creates xrefs from the indirect jump. + + Usually there is no need to call this function directly because the kernel + will call it for switch tables + + Note: Custom switch information are not supported yet. + + @param insn_ea: address of the 'indirect jump' instruction + @param si: switch information + + @return: Boolean + """ + pass +# +*/ +idaman bool ida_export py_create_switch_xrefs( + ea_t insn_ea, + PyObject *py_swi) +{ + switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + if ( swi == NULL ) + return false; + + create_switch_xrefs(insn_ea, swi); + return true; +} + + +//------------------------------------------------------------------------- +struct cases_and_targets_t +{ + casevec_t cases; + eavec_t targets; +}; + +//------------------------------------------------------------------------- +/* +# +def calc_switch_cases(insn_ea, si): + """ + Get information about a switch's cases. + + The returned information can be used as follows: + + for idx in xrange(len(results.cases)): + cur_case = results.cases[idx] + for cidx in xrange(len(cur_case)): + print "case: %d" % cur_case[cidx] + print " goto 0x%x" % results.targets[idx] + + @param insn_ea: address of the 'indirect jump' instruction + @param si: switch information + + @return: a structure with 2 members: 'cases', and 'targets'. + """ + pass +# +*/ +idaman cases_and_targets_t *ida_export py_calc_switch_cases( + ea_t insn_ea, + PyObject *py_swi) +{ + switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + if ( swi == NULL ) + return NULL; + + cases_and_targets_t *ct = new cases_and_targets_t; + if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) ) + { + delete ct; + return NULL; + } + + return ct; +} + + +//------------------------------------------------------------------------- +/* +# +def create_switch_table(insn_ea, si): + """ + Create switch table from the switch information + + @param insn_ea: address of the 'indirect jump' instruction + @param si: switch information + + @return: Boolean + """ + pass +# +*/ +idaman bool ida_export py_create_switch_table( + ea_t insn_ea, + PyObject *py_swi) +{ + switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + if ( swi == NULL ) + return false; + + create_switch_table(insn_ea, swi); + return true; +} +// diff --git a/pywraps/py_xref.py b/pywraps/py_xref.py new file mode 100644 index 0000000..fb91ec4 --- /dev/null +++ b/pywraps/py_xref.py @@ -0,0 +1,8 @@ + +# + +import ida_idaapi +ida_idaapi._listify_types( + casevec_t) + +# diff --git a/pywraps/pywraps.vcxproj b/pywraps/pywraps.vcxproj deleted file mode 100644 index f14921d..0000000 --- a/pywraps/pywraps.vcxproj +++ /dev/null @@ -1,663 +0,0 @@ - - - - - Debug - Win32 - - - Rel64 - Win32 - - - Release64 - Win32 - - - Release - Win32 - - - SemiDebugx64 - Win32 - - - SemiDebug - Win32 - - - - {F43D6BB8-B7D6-486A-82E5-BABBA9848525} - pywraps - - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - MultiByte - - - DynamicLibrary - false - MultiByte - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - .\Debug\ - .\Debug\ - true - false - .\Release\ - .\Release\ - false - $(Configuration)\ - $(Configuration)\ - false - $(Configuration)\ - $(Configuration)\ - false - $(Configuration)\ - $(Configuration)\ - false - $(Configuration)\ - $(Configuration)\ - false - - - - _DEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Debug/pywraps.tlb - - - - - Disabled - ..\..\..\include;c:\python26\include;%(AdditionalIncludeDirectories) - _DEBUG;__NT__;__IDP__;MAXSTR=1024;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;__PYWRAPS__;_PYWRAPS_DEBUG;NO_OBSOLETE_FUNCS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - .\Debug/pywraps.pch - .\Debug/ - .\Debug/ - .\Debug/ - Level3 - true - EditAndContinue - Cdecl - 4005;4800;4018;%(DisableSpecificWarnings) - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26_d.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.plw - true - ..\..\..\lib\x86_win_vc_32;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Debug/pywraps.pdb - false - - - .\Debug/pywraps.lib - MachineX86 - - - true - .\Debug/pywraps.bsc - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/pywraps.tlb - - - - - Disabled - OnlyExplicitInline - ..\..\..\include;c:\python26\include;%(AdditionalIncludeDirectories) - NO_OBSOLETE_FUNCS;NDEBUG;WIN32;_WINDOWS;_USRDLL;__NT__;__IDP__;MAXSTR=1024;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - true - MultiThreaded - true - .\Release/pywraps.pch - .\Release/ - .\Release/ - .\Release/ - Level4 - true - ProgramDatabase - Cdecl - - - NDEBUG;%(PreprocessorDefinitions) - 0x0419 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.plw - true - ..\..\..\lib\x86_win_vc_32;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Release/pywraps.pdb - - - - - .\Release/pywraps.lib - MachineX86 - - - true - .\Release/pywraps.bsc - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/pywraps.tlb - - - - - Disabled - OnlyExplicitInline - ..\..\..\include;c:\Python26\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;_USRDLL;__NT__;__IDP__;MAXSTR=1024;_CRT_SECURE_NO_WARNINGS;_PYWRAPS_DEBUG;%(PreprocessorDefinitions) - true - MultiThreaded - true - .\Release/pywraps.pch - .\Release/ - .\Release/ - .\Release/ - Level3 - true - ProgramDatabase - Cdecl - 4005;4800;4018;%(DisableSpecificWarnings) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0419 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.plw - true - ..\..\..\lib\x86_win_vc_32;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Release/pywraps.pdb - - - - - .\Release/pywraps.lib - MachineX86 - - - true - .\Release/pywraps.bsc - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/pywraps.tlb - - - - - Disabled - OnlyExplicitInline - ..\..\include;c:\python26\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;_USRDLL;__NT__;__IDP__;MAXSTR=1024;_CRT_SECURE_NO_WARNINGS;_PYWRAPS_DEBUG;__EA64__;%(PreprocessorDefinitions) - true - MultiThreaded - true - .\Release/pywraps.pch - .\Release/ - .\Release/ - .\Release/ - Level3 - true - ProgramDatabase - Cdecl - 4005;4800;4018;%(DisableSpecificWarnings) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0419 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.p64 - true - ..\..\..\lib\vc.w64;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Release/pywraps.pdb - false - - - true - .\Release/pywraps.lib - MachineX86 - - - true - .\Release/pywraps.bsc - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/pywraps.tlb - - - - - Disabled - OnlyExplicitInline - ..\..\..\include;c:\python26\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;_USRDLL;__NT__;__IDP__;MAXSTR=1024;_CRT_SECURE_NO_WARNINGS;__EA64__;_PYWRAPS_DEBUG;__PYWRAPS__;%(PreprocessorDefinitions) - true - MultiThreaded - true - .\Release/pywraps.pch - .\Release/ - .\Release/ - .\Release/ - Level4 - true - ProgramDatabase - Cdecl - - - NDEBUG;%(PreprocessorDefinitions) - 0x0419 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.p64 - true - ..\..\..\lib\vc.w64;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Release/pywraps.pdb - - - - - .\Release/pywraps.lib - MachineX86 - - - true - .\Release/pywraps.bsc - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - Win32 - .\Release/pywraps.tlb - - - - - Disabled - OnlyExplicitInline - ..\..\..\include;c:\python26\include;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;_USRDLL;__NT__;__IDP__;MAXSTR=1024;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - true - MultiThreaded - true - .\Release/pywraps.pch - .\Release/ - .\Release/ - .\Release/ - Level4 - true - ProgramDatabase - Cdecl - - - NDEBUG;%(PreprocessorDefinitions) - 0x0419 - - - /export:PLUGIN %(AdditionalOptions) - ida.lib;python26.lib;%(AdditionalDependencies) - ../../../bin/x86_win_vc/plugins/pywraps.plw - true - ..\..\..\lib\x86_win_vc_32;c:\python26\libs;%(AdditionalLibraryDirectories) - true - .\Release/pywraps.pdb - - - - - .\Release/pywraps.lib - MachineX86 - - - true - .\Release/pywraps.bsc - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - true - true - true - true - - - true - true - true - true - true - - - true - true - true - true - true - - - - true - true - true - true - true - - - true - true - true - true - true - - - true - true - true - - - true - true - true - true - true - true - - - true - true - true - true - true - true - - - true - true - true - true - true - true - - - true - true - true - true - true - true - - - true - true - true - true - true - true - - - true - true - true - - - true - true - true - true - true - true - - - true - true - true - true - true - true - - - - - - - - - - - - - - - - - - true - true - true - true - true - true - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pywraps/pywraps.vcxproj.filters b/pywraps/pywraps.vcxproj.filters deleted file mode 100644 index 5b14810..0000000 --- a/pywraps/pywraps.vcxproj.filters +++ /dev/null @@ -1,518 +0,0 @@ - - - - - {9fd646ab-4c34-4457-a88f-0b9efa521a7c} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {c7c2445a-144b-4574-a5a7-4547bf731f79} - - - {a817be2b-11e4-441c-9e1e-ff3825b03d03} - - - {bfbff292-8186-40a9-a90f-09a530e2e5d2} - - - {2ebfadc0-402b-4ef7-b2bf-ab9fb8c5279b} - - - {0ad19987-f808-44a4-865b-985e7f8dca02} - - - {1016cbe2-fa4e-49b5-9e8f-b8fc4a0656d3} - - - {e57b232e-0cdb-4cc6-ad63-80ecfeaa25b9} - - - {cfda7913-ffad-425d-b9ce-295bb647d8e5} - - - {ec48a898-4c2f-443d-9236-c8b58c036050} - - - {12e97676-9f57-4e1f-af42-6bf0cd178ae6} - - - {62308260-bfab-49eb-9b11-7522f7b671d8} - - - {f33949eb-15bb-4926-94e3-1648a4c3bca0} - - - {79a2a07e-7db7-43ac-8c41-fe08777e802c} - - - {714c10e9-2a6f-4b86-a594-b53b28f9fc7e} - - - {22f57328-eb90-4341-bb06-464f6c7b2bd6} - - - {ef594bc3-6670-4e55-a77f-e3bff3193d94} - - - {7092618c-44fe-497b-a229-360bab592f3d} - - - {c5616ba8-8b0d-41a0-bf78-583fdcfb3898} - - - {0cefa3d8-f4b6-4085-b2a2-6b2d97167252} - - - {b21f3b63-396e-4725-83cc-2df9f5b6bb46} - - - {c4a9b8be-70fa-4287-bc47-73db56202dd6} - - - {a103675f-abc2-4f84-a0b8-9ac7403f04db} - - - {ac94c213-e485-48ac-b554-3868e350d671} - - - {833c766e-6e8d-4c00-947f-71a7b34378a6} - - - {8dc47ef4-3da0-4bf8-9ce2-5a9f8896b1b3} - - - {8e65a873-5b8f-4052-a929-e13e9e0f81ac} - - - {b7a7d68d-a3b0-487c-b4d0-bd716dd06280} - - - {959b59d2-acb2-4c89-a828-eece77e502f4} - - - - - py_dbgidd - - - py_dbgidd - - - py_dbgidd - - - py_graph - - - py_graph - - - py_diskio - - - py_diskio - - - py_diskio - - - py_bytes - - - py_bytes - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - deploy\examples - - - py_idaapi - - - py_idaapi - - - py_typeinf - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - swig.i - - - py_gdl - - - py_gdl - - - py_ua - - - py_ua - - - IDAPython - - - IDAPython - - - IDAPython - - - IDAPython - - - py_notifywhen - - - py_lines - - - py_lines - - - py_nalt - - - py_nalt - - - py_loader - - - py_idp - - - py_kernwin - - - py_kernwin - - - py_kernwin\py_custview - - - py_kernwin\py_choose2 - - - py_kernwin\py_cli - - - py_kernwin\py_plgform - - - py_kernwin\py_askusingform - - - py_kernwin\py_askusingform - - - py_kernwin - - - py_kernwin\py_plgform - - - py_kernwin\py_plgform - - - py_idp - - - py_kernwin - - - py_expr - - - - - py_dbgidd - - - py_graph - - - pywraps - - - py_diskio - - - py_bytes - - - py_bytes - - - IDAPython - - - IDAPython - - - py_notifywhen - - - py_nalt - - - py_kernwin - - - py_kernwin\py_custview - - - py_kernwin\py_choose2 - - - py_kernwin\py_cli - - - swig_stub - - - py_expr - - - - - py_dbgidd - - - py_graph - - - pywraps - - - py_diskio - - - py_diskio - - - py_diskio - - - py_bytes - - - py_bytes - - - py_idaapi - - - py_typeinf - - - py_ua - - - py_notifywhen - - - py_lines - - - py_nalt - - - py_loader - - - py_idp - - - py_utils - - - py_kernwin - - - py_kernwin\py_custview - - - py_kernwin\py_choose2 - - - py_kernwin\py_cli - - - py_kernwin\py_plgform - - - py_kernwin\py_askusingform - - - py_kernwin\py_choose - - - swig_stub - - - py_expr - - - - - IDAPython - - - \ No newline at end of file diff --git a/pywraps/sidaapi.py b/pywraps/sidaapi.py deleted file mode 100755 index f3dbf47..0000000 --- a/pywraps/sidaapi.py +++ /dev/null @@ -1,228 +0,0 @@ -import sys -import sidc - -BUF = None - -# ---------------------------------------------------------------------- -def ua_next_byte(): - p = cmd.ea - if p >= len(BUF): - return None - ch = ord(BUF[p]) - ua_seek(p+1) - cmd.size += 1 - return ch - -def ua_next_word(): - b1 = ua_next_byte() - b2 = ua_next_byte() - return (b2 << 8) | b1 - -def ua_next_long(): - w1 = ua_next_word() - w2 = ua_next_word() - return (w2 << 16) | w1 - -def ua_next_qword(): - d1 = ua_next_long() - d2 = ua_next_long() - return (d2 << 32) | d1 - -# ---------------------------------------------------------------------- -def ua_set_data(data): - global BUF - BUF = data - ua_seek(0) - -# ---------------------------------------------------------------------- -def ua_seek(v): - cmd.ea = v - -# ---------------------------------------------------------------------- -def ua_get_seek(): - return cmd.ea - -# ---------------------------------------------------------------------- -def init_file(fn): - global BUF, PTR - try: - f = open(fn, "rb") - BUF = f.read() - ua_seek(0) - f.close() - except Exception, e: - print "init_file()", e - return False - return True - -# ---------------------------------------------------------------------- -class cvar_t: - def __init__(self): - self.uFlag = 0 - self.gl_comm = 1 -# ---------------------------------------------------------------------- -cvar = cvar_t() -cmd = sidc.insn_t() - -# ---------------------------------------------------------------------- -class processor_t(object): - def __init__(self): - # This is an opaque object - self.__idc_cvt_id__ = 2 - - # Take a reference to 'cmd' - self.cmd = cmd - - def get_idpdesc(self): - """ - This function must be present and should return the list of - short processor names similar to the one in ph.psnames - """ - return idpdef['plnames'][0] + ':' + ':'.join(idpdef['psnames']) - - def get_uFlag(self): - """Use this utility function to retrieve the 'uFlag' global variable""" - return _idaapi.cvar.uFlag - - def get_auxpref(self): - return self.cmd.auxpref - -# ---------------------------------------------------------------------- -BADADDR = 0xFFFFFFFFFFFFFFFFL - -# ---------------------------------------------------------------------- -UA_MAXOP = 6 -o_void = 0 -# ---------------------------------------------------------------------- - -""" -# Colors dump - -attrs = [x for x in dir(idaapi) if x.startswith('SCOLOR')] -for x in attrs: - print "%s =%r;" % (x, getattr(idaapi, x)) - -attrs = [x for x in dir(idaapi) if x.startswith('COLOR')] -for x in attrs: - v = getattr(idaapi, x); - if isinstance(v, str): - v = ord(x[0]) - print "%s =%r;" % (x, v) -""" - -SCOLOR_ADDR ='('; -SCOLOR_ALTOP ='\x16'; -SCOLOR_ASMDIR ='\x1b'; -SCOLOR_AUTOCMT ='\x04'; -SCOLOR_BINPREF ='\x14'; -SCOLOR_CHAR ='\n'; -SCOLOR_CNAME ='%'; -SCOLOR_CODNAME ='\x1a'; -SCOLOR_COLLAPSED ="'"; -SCOLOR_CREF ='\x0e'; -SCOLOR_CREFTAIL ='\x10'; -SCOLOR_DATNAME ='\x06'; -SCOLOR_DCHAR ='\x1e'; -SCOLOR_DEFAULT ='\x01'; -SCOLOR_DEMNAME ='\x08'; -SCOLOR_DNAME ='\x07'; -SCOLOR_DNUM ='\x1f'; -SCOLOR_DREF ='\x0f'; -SCOLOR_DREFTAIL ='\x11'; -SCOLOR_DSTR ='\x1d'; -SCOLOR_ERROR ='\x12'; -SCOLOR_ESC ='\x03'; -SCOLOR_EXTRA ='\x15'; -SCOLOR_FG_MAX ='('; -SCOLOR_HIDNAME ='\x17'; -SCOLOR_IMPNAME ='"'; -SCOLOR_INSN ='\x05'; -SCOLOR_INV ='\x04'; -SCOLOR_KEYWORD =' '; -SCOLOR_LIBNAME ='\x18'; -SCOLOR_LOCNAME ='\x19'; -SCOLOR_MACRO ='\x1c'; -SCOLOR_NUMBER ='\x0c'; -SCOLOR_OFF ='\x02'; -SCOLOR_ON ='\x01'; -SCOLOR_OPND1 =')'; -SCOLOR_OPND2 ='*'; -SCOLOR_OPND3 ='+'; -SCOLOR_OPND4 =','; -SCOLOR_OPND5 ='-'; -SCOLOR_OPND6 ='.'; -SCOLOR_PREFIX ='\x13'; -SCOLOR_REG ='!'; -SCOLOR_REGCMT ='\x02'; -SCOLOR_RPTCMT ='\x03'; -SCOLOR_SEGNAME ='#'; -SCOLOR_STRING ='\x0b'; -SCOLOR_SYMBOL ='\t'; -SCOLOR_UNAME ='&'; -SCOLOR_UNKNAME ='$'; -SCOLOR_UTF8 ='2'; -SCOLOR_VOIDOP ='\r'; -COLOR_ADDR =40; -COLOR_ADDR_SIZE =8; -COLOR_ALTOP =22; -COLOR_ASMDIR =27; -COLOR_AUTOCMT =4; -COLOR_BG_MAX =12; -COLOR_BINPREF =20; -COLOR_CHAR =10; -COLOR_CNAME =37; -COLOR_CODE =5; -COLOR_CODNAME =26; -COLOR_COLLAPSED =39; -COLOR_CREF =14; -COLOR_CREFTAIL =16; -COLOR_CURITEM =9; -COLOR_CURLINE =10; -COLOR_DATA =6; -COLOR_DATNAME =6; -COLOR_DCHAR =30; -COLOR_DEFAULT =1; -COLOR_DEMNAME =8; -COLOR_DNAME =7; -COLOR_DNUM =31; -COLOR_DREF =15; -COLOR_DREFTAIL =17; -COLOR_DSTR =29; -COLOR_ERROR =18; -COLOR_ESC =3; -COLOR_EXTERN =8; -COLOR_EXTRA =21; -COLOR_FG_MAX =40; -COLOR_HIDLINE =11; -COLOR_HIDNAME =23; -COLOR_IMPNAME =34; -COLOR_INSN =5; -COLOR_INV =4; -COLOR_KEYWORD =32; -COLOR_LIBFUNC =3; -COLOR_LIBNAME =24; -COLOR_LOCNAME =25; -COLOR_MACRO =28; -COLOR_NUMBER =12; -COLOR_OFF = 2; -COLOR_ON = 1; -COLOR_OPND1 =41; -COLOR_OPND2 =42; -COLOR_OPND3 =43; -COLOR_OPND4 =44; -COLOR_OPND5 =45; -COLOR_OPND6 =46; -COLOR_PREFIX =19; -COLOR_REG =33; -COLOR_REGCMT =2; -COLOR_REGFUNC =4; -COLOR_RPTCMT =3; -COLOR_SEGNAME =35; -COLOR_SELECTED =2; -COLOR_STRING =11; -COLOR_SYMBOL =9; -COLOR_UNAME =38; -COLOR_UNKNAME =36; -COLOR_UNKNOWN =7; -COLOR_UTF8 =50; -COLOR_VOIDOP =13; \ No newline at end of file diff --git a/pywraps/swig_stub.cpp b/pywraps/swig_stub.cpp new file mode 100644 index 0000000..e44b86b --- /dev/null +++ b/pywraps/swig_stub.cpp @@ -0,0 +1,6 @@ +#include "swig_stub.h" + +PyObject *SWIG_NewPointerObj(void *ptr, void *type, int flags) +{ + return PyCObject_FromVoidPtr(ptr, NULL); +} diff --git a/pywraps/swig_stub.h b/pywraps/swig_stub.h new file mode 100644 index 0000000..4752aeb --- /dev/null +++ b/pywraps/swig_stub.h @@ -0,0 +1,25 @@ +#ifndef __SWIG_STUB__ +#define __SWIG_STUB__ + +#include + +#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) + +PyObject *SWIG_NewPointerObj(void *ptr, void *type, int flags); + +namespace Swig +{ + class DirectorException + { + public: + const char *getMessage() const + { + return "NULL"; + } + }; +} + +// Some fake SWIG types +#define SWIGTYPE_p_member_t NULL + +#endif diff --git a/swig/allins.i b/swig/allins.i index 161878f..759533b 100644 --- a/swig/allins.i +++ b/swig/allins.i @@ -1,3 +1,7 @@ +%{ +#include +%} + // Ignore the unnedded externals %ignore Instructions; diff --git a/swig/area.i b/swig/area.i index 591bc51..adf220c 100644 --- a/swig/area.i +++ b/swig/area.i @@ -2,9 +2,6 @@ %ignore ANODE2; %ignore AREA_LONG_COMMENT_TAG; %ignore area_visitor_t; -%ignore areacb_t_link_dont_load; -%ignore add_area_from_cache; -%ignore areacb_t_valid_push_back; // Ignore the private members in areacb_t %ignore areacb_t::areasCode; @@ -37,4 +34,23 @@ %ignore areaset_t::move_chunk; %ignore areaset_t::check_move_args; +%inline %{ +// +// +%} + %include "area.hpp" + +%extend areacb_t { + areacb_type_t get_type() + { + areacb_type_t t = AREACB_TYPE_UNKNOWN; + if ( $self == &funcs ) + t = AREACB_TYPE_FUNC; + else if ( $self == &segs ) + t = AREACB_TYPE_SEGMENT; + else if ( $self == &hidden_areas ) + t = AREACB_TYPE_HIDDEN_AREA; + return t; + } +} diff --git a/swig/askusingform.i b/swig/askusingform.i deleted file mode 100644 index 17f24e3..0000000 --- a/swig/askusingform.i +++ /dev/null @@ -1,17 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/auto.i b/swig/auto.i index 225683e..65ce048 100644 --- a/swig/auto.i +++ b/swig/auto.i @@ -1,17 +1,11 @@ -%ignore queue_weak_code; -%ignore auto_process_all; +%{ +#include +%} + %ignore autoPlanned; %ignore nextPlanned; -%ignore is_planned_ea; -%ignore get_next_planned_ea; -%ignore autoDelCode; %ignore autoPeek; %ignore autoProcess; -%ignore auto_init; -%ignore auto_save; -%ignore auto_term; -%ignore ea_without_xrefs; -%ignore postpone_lastinsn_analysis; %include "auto.hpp" diff --git a/swig/bytes.i b/swig/bytes.i index 0c3018d..1fdd7a6 100644 --- a/swig/bytes.i +++ b/swig/bytes.i @@ -1,13 +1,8 @@ -// Make get_any_cmt() work -%apply unsigned char *OUTPUT { color_t *cmttype }; +%{ +#include +%} -// For get_enum_id() -%apply unsigned char *OUTPUT { uchar *serial }; - -// get_[first|last]_serial_enum_member() won't take serials as input; it'll be present as output -%apply unsigned char *OUTPUT { uchar *out_serial }; -// get_[next|prev]_serial_enum_member() take serials as input, and have the result present as output -%apply unsigned char *INOUT { uchar *in_out_serial }; +%import "area.i" // Unexported and kernel-only declarations %ignore FlagsEnable; @@ -22,7 +17,6 @@ %ignore is_first_visea; %ignore is_last_visea; %ignore is_visible_finally; -%ignore invalidate_visea_cache; %ignore fluFlags; %ignore setFlbits; %ignore clrFlbits; @@ -36,44 +30,11 @@ %ignore del_code_comments; %ignore doFlow; %ignore noFlow; -%ignore doRef; -%ignore noRef; %ignore coagulate; -%ignore coagulate_dref; -%ignore init_hidden_areas; -%ignore save_hidden_areas; -%ignore term_hidden_areas; -%ignore check_move_args; -%ignore movechunk; -%ignore lock_dbgmem_config; -%ignore unlock_dbgmem_config; -%ignore set_op_type_no_event; -%ignore shuffle_tribytes; -%ignore set_stroff_path; -%ignore del_stroff_path; -%ignore set_enum_id; -%ignore del_enum_id; -%ignore enum_encode; -%ignore enum_decode; -%ignore mark_dirty_tof; -%ignore validate_tofs; -%ignore set_flags_nomark; -%ignore set_flbits_nomark; -%ignore clr_flbits_nomark; -%ignore ida_vpagesize; -%ignore ida_vpages; -%ignore ida_npagesize; -%ignore ida_npages; -%ignore max_cache_count; -%ignore fpnum_digits; -%ignore fpnum_length; %ignore FlagsInit; %ignore FlagsTerm; %ignore FlagsReset; -%ignore init_flags; -%ignore term_flags; -%ignore reset_flags; %ignore flush_flags; %ignore get_flags_linput; %ignore data_type_t; @@ -126,3 +87,18 @@ # # %} + +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} diff --git a/swig/choose.i b/swig/choose.i deleted file mode 100644 index 08486fe..0000000 --- a/swig/choose.i +++ /dev/null @@ -1,12 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/choose2.i b/swig/choose2.i deleted file mode 100644 index 199c87d..0000000 --- a/swig/choose2.i +++ /dev/null @@ -1,17 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/cli.i b/swig/cli.i deleted file mode 100644 index abef900..0000000 --- a/swig/cli.i +++ /dev/null @@ -1,17 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/custdata.i b/swig/custdata.i deleted file mode 100644 index 38de684..0000000 --- a/swig/custdata.i +++ /dev/null @@ -1,15 +0,0 @@ - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/custview.i b/swig/custview.i deleted file mode 100644 index 778fa46..0000000 --- a/swig/custview.i +++ /dev/null @@ -1,17 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/dbg.i b/swig/dbg.i index 2929e96..58abf3a 100644 --- a/swig/dbg.i +++ b/swig/dbg.i @@ -1,16 +1,14 @@ -// SWIG chokes on the original declaration so it is replicated here -typedef struct -{ - ulonglong ival; // 8: integer value - ushort fval[6]; // 12: floating point value in the internal representation (see ieee.h) -} regval_t; +%{ +#include +#include +%} + +%import "idd.i" %ignore dbg; %ignore register_srcinfo_provider; %ignore unregister_srcinfo_provider; -%ignore appcall_info_t; %ignore get_manual_regions; -%ignore internal_appcall; %ignore internal_cleanup_appcall; %ignore change_bptlocs; %ignore movbpt_info_t; @@ -28,8 +26,8 @@ typedef struct %ignore bpt_t::set_cnd_elang; %rename (get_manual_regions) py_get_manual_regions; %ignore set_manual_regions; -%ignore inform_idc_about_debthread; -%ignore is_dbgmem_valid; +// TODO: This could be fixed (if needed) +%ignore set_dbgmem_source; %rename (list_bptgrps) py_list_bptgrps; %apply qstring *result { qstring *grp_name }; @@ -41,10 +39,19 @@ typedef struct %ignore qvector::add_unique; %template(bpt_vec_t) qvector; +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; +%ignore memreg_info_t::bytes; +%rename (bytes) memreg_info_t_py_bytes; +%template(memreg_infos_t) qvector; + %ignore internal_get_sreg_base; %rename (internal_get_sreg_base) py_internal_get_sreg_base; -%rename (get_tev_reg_mem) py_get_tev_reg_mem; // We want ALL wrappers around what is declared in dbg.hpp // to release the GIL when calling into the IDA api: those @@ -61,11 +68,15 @@ typedef struct // %} +//------------------------------------------------------------------------- +// bpt_t +//------------------------------------------------------------------------- %extend bpt_t { PyObject *condition; PyObject *elang; } + %{ PyObject *bpt_t_condition_get(bpt_t *bpt) { @@ -100,7 +111,28 @@ void bpt_t_elang_set(bpt_t *bpt, PyObject *val) } %} +//------------------------------------------------------------------------- +// memreg_info_t +//------------------------------------------------------------------------- +%extend memreg_info_t +{ + PyObject *get_bytes() const + { + return PyString_FromStringAndSize( + (const char *) $self->bytes.begin(), + $self->bytes.size()); + } + %pythoncode %{ + bytes = property(get_bytes) + %} +} + %inline %{ // // %} + +%pythoncode %{ +# +# +%} diff --git a/swig/diskio.i b/swig/diskio.i index 82cacf5..d675a63 100644 --- a/swig/diskio.i +++ b/swig/diskio.i @@ -1,8 +1,14 @@ +%{ +#include +#include +#include +#include "../../../pywraps.hpp" +%} + // TODO: These could be wrapped %ignore enumerate_files; %rename (enumerate_files) py_enumerate_files; %ignore enumerate_system_files; -%ignore enumerate_sorted_files; %ignore ioport_bit_t; %ignore ioport_bits_t; %ignore ioport_t; @@ -29,9 +35,6 @@ %ignore qlfile; %ignore make_linput; %ignore unmake_linput; -%ignore create_remote_linput; -%ignore make_filehandle_linput; -%ignore get_default_userdir; // FIXME: These should be wrapped for completeness %ignore eread; diff --git a/swig/entry.i b/swig/entry.i index bebc381..2878980 100644 --- a/swig/entry.i +++ b/swig/entry.i @@ -1,6 +1,5 @@ -%ignore init_entries; -%ignore term_entries; -%ignore move_entries; -%ignore set_entry_name; +%{ +#include +%} %include "entry.hpp" diff --git a/swig/enum.i b/swig/enum.i index 8d357f5..6da8938 100644 --- a/swig/enum.i +++ b/swig/enum.i @@ -1,17 +1,16 @@ +%{ +#include +%} // Kernel only & unexported symbols %ignore enums; %ignore init_enums; %ignore save_enums; %ignore term_enums; %ignore set_enum_flag; -%ignore sync_from_enum; %ignore get_enum_name(tid_t); -%ignore del_all_enum_members; %ignore get_selected_enum; %ignore add_selected_enum; %ignore unmark_selected_enums; -%ignore is_good_bmask; -%ignore get_bmask_enum; %ignore ENUM_REVERSE; %ignore ENUM_SELMEMS; %ignore ENUM_QTY_IDX; diff --git a/swig/expr.i b/swig/expr.i index 7407bf4..cb701e5 100644 --- a/swig/expr.i +++ b/swig/expr.i @@ -12,7 +12,6 @@ %ignore set_idc_getattr; %ignore set_idc_setattr; %ignore set_idc_func_ex; -%ignore run_statements_idc; %ignore VarLong; %ignore VarNum; %ignore extlang_get_attr_exists; @@ -35,25 +34,10 @@ %ignore ExecuteFile; %ignore set_idc_func_body; %ignore get_idc_func_body; -%ignore idc_stacksize; -%ignore idc_calldepth; -%ignore expr_printf; -%ignore expr_uprintf; -%ignore expr_sprintf; -%ignore expr_printfer; -%ignore init_idc; -%ignore term_idc; -%ignore create_default_idc_classes; -%ignore notify_extlang_changed; -%ignore insn_to_idc; -%ignore find_builtin_idc_func; -%ignore idc_mutex; -%ignore idc_lx; %ignore idc_vars; -%ignore idc_resolve_label; -%ignore idc_resolver_ea; %ignore setup_lowcnd_regfuncs; %ignore syntax_highlighter_t; +%ignore get_idptype_and_data; %cstring_output_maxstr_none(char *errbuf, size_t errbufsize); %ignore CompileEx; diff --git a/swig/fixup.i b/swig/fixup.i index 2d31d56..a06ba42 100644 --- a/swig/fixup.i +++ b/swig/fixup.i @@ -1,6 +1,8 @@ +%{ +#include +%} + %ignore apply_fixup; -%ignore convert_fixups; -%ignore move_fixups; %ignore custom_fixup_handler_t; %ignore custom_fixup_handlers_t; %ignore register_custom_fixup; diff --git a/swig/frame.i b/swig/frame.i index 47d9fc5..b76e32c 100644 --- a/swig/frame.i +++ b/swig/frame.i @@ -1,24 +1,15 @@ +%{ +#include +%} + +%import "area.i" + %ignore add_frame_spec_member; %ignore del_stkvars; %ignore calc_frame_offset; -%ignore read_regvars; -%ignore write_regvars; -%ignore del_regvars; -%ignore free_regvar; -%ignore gen_regvar_defs; %ignore set_llabel; %ignore get_llabel_ea; %ignore get_llabel; -%ignore read_llabels; -%ignore write_llabels; -%ignore del_llabels; -%ignore free_llabel; -%ignore read_stkpnts; -%ignore write_stkpnts; -%ignore del_stkpnts; -%ignore rename_frame; -%ignore _set_frame_size; -%ignore add_empty_frame; %ignore get_stkvar; %rename (get_stkvar) py_get_stkvar; @@ -31,4 +22,9 @@ %template(xreflist_t) qvector; +%inline %{ +// +// +%} + %include "frame.hpp" diff --git a/swig/funcs.i b/swig/funcs.i index 505fdd9..0678b01 100644 --- a/swig/funcs.i +++ b/swig/funcs.i @@ -1,3 +1,6 @@ + +%import "area.i" + %cstring_bounded_output_none(char *buf, MAXSTR); %cstring_bounded_output_none(char *optlibs, MAXSTR); @@ -6,27 +9,10 @@ %ignore get_idasgn_header_by_short_name; // Kernel-only & unexported symbols -%ignore del_regargs; -%ignore write_regargs; -%ignore find_regarg; -%ignore free_regarg; %ignore determine_rtl; -%ignore init_signatures; %ignore save_signatures; -%ignore term_signatures; -%ignore init_funcs; -%ignore save_funcs; -%ignore term_funcs; -%ignore move_funcs; -%ignore copy_noret_info; -%ignore recalc_func_noret_flag; -%ignore plan_for_noret_analysis; %ignore invalidate_sp_analysis; -%ignore create_func_eas_array; -%ignore auto_add_func_tails; -%ignore read_tails; - %ignore get_idasgn_desc; %rename (get_idasgn_desc) py_get_idasgn_desc; %rename (get_idasgn_desc_with_matches) py_get_idasgn_desc_with_matches; diff --git a/swig/gdl.i b/swig/gdl.i index bb975b4..3d27551 100644 --- a/swig/gdl.i +++ b/swig/gdl.i @@ -1,3 +1,9 @@ +%{ +#include +%} + +%import "area.i" + %ignore cancellable_graph_t; %ignore gdl_graph_t; diff --git a/swig/graph.i b/swig/graph.i index 6f59647..5cf8440 100644 --- a/swig/graph.i +++ b/swig/graph.i @@ -1,3 +1,6 @@ +%{ +#include +%} %ignore mutable_graph_t; %ignore graph_visitor_t; %ignore abstract_graph_t; diff --git a/swig/hexrays.i b/swig/hexrays.i index cc39bc5..e4aa107 100644 --- a/swig/hexrays.i +++ b/swig/hexrays.i @@ -1,3 +1,23 @@ +%{ +#include +%} + +%import "typeinf.i" + +// KLUDGE: I have no idea how to force SWiG to declare a type for a module, +// unless that type is indeed used. That's why this wrapper exists.. +%{ +static void _kludge_use_TPopupMenu(TPopupMenu *) {} +%} +%inline %{ +namespace Menus +{ + class TPopupMenu; +} +using Menus::TPopupMenu; +static void _kludge_use_TPopupMenu(TPopupMenu *m); +%} + //--------------------------------------------------------------------- // SWIG bindings for Hexray Decompiler's hexrays.hpp // @@ -143,6 +163,8 @@ public: CITEM_MEMBER_REF(return); CITEM_MEMBER_REF(goto); CITEM_MEMBER_REF(asm); + + bool is_epilog() const { return $self == INS_EPILOG; } }; #undef CITEM_MEMBER_REF @@ -320,346 +342,27 @@ void qswap(cinsn_t &a, cinsn_t &b); } %{ - -//------------------------------------------------------------------------- -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; - - // 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; -} - +// +// %} %ignore init_hexrays_plugin; -%rename(init_hexrays_plugin) __init_hexrays_plugin; +%rename(init_hexrays_plugin) py_init_hexrays_plugin; %ignore add_custom_viewer_popup_item; -%rename(add_custom_viewer_popup_item) __add_custom_viewer_popup_item; +%rename(add_custom_viewer_popup_item) py_add_custom_viewer_popup_item; %ignore install_hexrays_callback; -%rename(install_hexrays_callback) __install_hexrays_callback; +%rename(install_hexrays_callback) py_install_hexrays_callback; %ignore remove_hexrays_callback; -%rename(remove_hexrays_callback) __remove_hexrays_callback; +%rename(remove_hexrays_callback) py_remove_hexrays_callback; -%inline %{ +%ignore decompile_many; +%rename (decompile_many) py_decompile_many; -//--------------------------------------------------------------------- -extern hexdsp_t *hexdsp; -bool __init_hexrays_plugin(int flags=0) -{ - // Only initialize one time - if (hexdsp == NULL) - return init_hexrays_plugin(flags); - else - return true; -} - -//--------------------------------------------------------------------- -void __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 __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 __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 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); - } -} - -%} +%ignore get_tform_vdui; +%rename (get_tform_vdui) py_get_tform_vdui; //------------------------------------------------------------------------- #if SWIG_VERSION == 0x20012 @@ -685,23 +388,6 @@ void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp) #error Ensure cfuncptr_t wrapping is compatible with this version of SWIG #endif -%{ -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); -} -%} - -cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf); %ignore decompile; //--------------------------------------------------------------------- @@ -737,422 +423,23 @@ cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf); %enddef %possible_director_exc(ctree_visitor_t::apply_to) %possible_director_exc(ctree_visitor_t::apply_to_exprs) + +%inline %{ +// +// +%} + %include "hexrays.hpp" %exception; // Delete & restore handlers %exception_set_default_handlers(); %pythoncode %{ - -import idaapi - -hexrays_failure_t.__str__ = lambda self: str(self.str) - -# --------------------------------------------------------------------- -class DecompilationFailure(Exception): - """ Raised on a decompilation error. - - The associated hexrays_failure_t object is stored in the - 'info' member of this exception. """ - - def __init__(self, info): - Exception.__init__(self, 'Decompilation failed: %s' % (str(info), )) - self.info = info - return - -# --------------------------------------------------------------------- -def decompile(ea, hf=None): - if isinstance(ea, (int, long)): - func = idaapi.get_func(ea) - if not func: return - elif type(ea) == idaapi.func_t: - func = ea - else: - raise RuntimeError('arg 1 of decompile expects either ea_t or cfunc_t argument') - - if hf is None: - hf = hexrays_failure_t() - - ptr = _decompile(func, hf) - - if ptr.__deref__() is None: - raise DecompilationFailure(hf) - - return ptr - -# --------------------------------------------------------------------- -# stringify all string types -#qtype.__str__ = qtype.c_str -#qstring.__str__ = qstring.c_str -#citem_cmt_t.__str__ = citem_cmt_t.c_str - -# --------------------------------------------------------------------- -# listify all list types -_listify_types(cinsnptrvec_t, - ctree_items_t, - qvector_lvar_t, - qvector_carg_t, - qvector_ccase_t, - hexwarns_t, - history_t, - lvar_saved_infos_t) - -def citem_to_specific_type(self): - """ cast the citem_t object to its more specific type, either cexpr_t or cinsn_t. """ - - if self.op >= cot_empty and self.op <= cot_last: - return self.cexpr - elif self.op >= cit_empty and self.op < cit_end: - return self.cinsn - - raise RuntimeError('unknown op type %s' % (repr(self.op), )) -citem_t.to_specific_type = property(citem_to_specific_type) - -""" array used for translating cinsn_t->op type to their names. """ -cinsn_t.op_to_typename = {} -for k in dir(_idaapi): - if k.startswith('cit_'): - cinsn_t.op_to_typename[getattr(_idaapi, k)] = k[4:] - -""" array used for translating cexpr_t->op type to their names. """ -cexpr_t.op_to_typename = {} -for k in dir(_idaapi): - if k.startswith('cot_'): - cexpr_t.op_to_typename[getattr(_idaapi, k)] = k[4:] - -def property_op_to_typename(self): - return self.op_to_typename[self.op] -cinsn_t.opname = property(property_op_to_typename) -cexpr_t.opname = property(property_op_to_typename) - -def cexpr_operands(self): - """ return a dictionary with the operands of a cexpr_t. """ - - if self.op >= cot_comma and self.op <= cot_asgumod or \ - self.op >= cot_lor and self.op <= cot_fdiv or \ - self.op == cot_idx: - return {'x': self.x, 'y': self.y} - - elif self.op == cot_tern: - return {'x': self.x, 'y': self.y, 'z': self.z} - - elif self.op in [cot_fneg, cot_neg, cot_sizeof] or \ - self.op >= cot_lnot and self.op <= cot_predec: - return {'x': self.x} - - elif self.op == cot_cast: - return {'type': self.type, 'x': self.x} - - elif self.op == cot_call: - return {'x': self.x, 'a': self.a} - - elif self.op in [cot_memref, cot_memptr]: - return {'x': self.x, 'm': self.m} - - elif self.op == cot_num: - return {'n': self.n} - - elif self.op == cot_fnum: - return {'fpc': self.fpc} - - elif self.op == cot_str: - return {'string': self.string} - - elif self.op == cot_obj: - return {'obj_ea': self.obj_ea} - - elif self.op == cot_var: - return {'v': self.v} - - elif self.op == cot_helper: - return {'helper': self.helper} - - raise RuntimeError('unknown op type %s' % self.opname) -cexpr_t.operands = property(cexpr_operands) - -def cinsn_details(self): - """ return the details pointer for the cinsn_t object depending on the value of its op member. \ - this is one of the cblock_t, cif_t, etc. objects. """ - - if self.op not in self.op_to_typename: - raise RuntimeError('unknown item->op type') - - opname = self.opname - if opname == 'empty': - return self - - if opname in ['break', 'continue']: - return None - - return getattr(self, 'c' + opname) -cinsn_t.details = property(cinsn_details) - -def cblock_iter(self): - - iter = self.begin() - for i in range(self.size()): - yield iter.cur - iter.next() - - return -cblock_t.__iter__ = cblock_iter -cblock_t.__len__ = cblock_t.size - -# cblock.find(cinsn_t) -> returns the iterator positioned at the given item -def cblock_find(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return iter - iter.next() - - return -cblock_t.find = cblock_find - -# cblock.index(cinsn_t) -> returns the index of the given item -def cblock_index(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return i - iter.next() - - return -cblock_t.index = cblock_index - -# cblock.at(int) -> returns the item at the given index index -def cblock_at(self, index): - - iter = self.begin() - for i in range(self.size()): - if i == index: - return iter.cur - iter.next() - - return -cblock_t.at = cblock_at - -# cblock.remove(cinsn_t) -def cblock_remove(self, item): - - iter = self.find(item) - self.erase(iter) - - return -cblock_t.remove = cblock_remove - -# cblock.insert(index, cinsn_t) -def cblock_insert(self, index, item): - - pos = self.at(index) - iter = self.find(pos) - self.insert(iter, item) - - return -cblock_t.insert = cblock_insert - -cfuncptr_t.__str__ = lambda self: str(self.__deref__()) - -def cfunc_type(self): - """ Get the function's return type tinfo_t object. """ - tif = tinfo_t() - result = self.get_func_type(tif) - if not result: - return - return tif -cfunc_t.type = property(cfunc_type) -cfuncptr_t.type = property(lambda self: self.__deref__().type) - -cfunc_t.arguments = property(lambda self: [o for o in self.lvars if o.is_arg_var]) -cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments) - -cfunc_t.lvars = property(cfunc_t.get_lvars) -cfuncptr_t.lvars = property(lambda self: self.__deref__().lvars) -cfunc_t.warnings = property(cfunc_t.get_warnings) -cfuncptr_t.warnings = property(lambda self: self.__deref__().warnings) -cfunc_t.pseudocode = property(cfunc_t.get_pseudocode) -cfuncptr_t.pseudocode = property(lambda self: self.__deref__().get_pseudocode()) -cfunc_t.eamap = property(cfunc_t.get_eamap) -cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap()) -cfunc_t.boundaries = property(cfunc_t.get_boundaries) -cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries()) - -#pragma SWIG nowarn=+503 - -lvar_t.used = property(lvar_t.used) -lvar_t.typed = property(lvar_t.typed) -lvar_t.mreg_done = property(lvar_t.mreg_done) -lvar_t.has_nice_name = property(lvar_t.has_nice_name) -lvar_t.is_unknown_width = property(lvar_t.is_unknown_width) -lvar_t.has_user_info = property(lvar_t.has_user_info) -lvar_t.has_user_name = property(lvar_t.has_user_name) -lvar_t.has_user_type = property(lvar_t.has_user_type) -lvar_t.is_result_var = property(lvar_t.is_result_var) -lvar_t.is_arg_var = property(lvar_t.is_arg_var) -lvar_t.is_fake_var = property(lvar_t.is_fake_var) -lvar_t.is_overlapped_var = property(lvar_t.is_overlapped_var) -lvar_t.is_floating_var = property(lvar_t.is_floating_var) -lvar_t.is_spoiled_var = property(lvar_t.is_spoiled_var) -lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var) - -# dictify all dict-like types - -def _map___getitem__(self, key): - """ Returns the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of key should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - return self.second(self.find(key)) - -def _map___setitem__(self, key, value): - """ Returns the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if not isinstance(value, self.valuetype): - raise KeyError('type of `value` should be ' + repr(self.valuetype) + ' but got ' + type(value)) - self.insert(key, value) - return - -def _map___delitem__(self, key): - """ Removes the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - self.erase(self.find(key)) - return - -def _map___contains__(self, key): - """ Returns true if the specified key exists in the . """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if self.find(key) != self.end(): - return True - return False - -def _map_clear(self): - self.clear() - return - -def _map_copy(self): - ret = {} - for k in self.iterkeys(): - ret[k] = self[k] - return ret - -def _map_get(self, key, default=None): - if key in self: - return self[key] - return default - -def _map_iterkeys(self): - iter = self.begin() - while iter != self.end(): - yield self.first(iter) - iter = self.next(iter) - return - -def _map_itervalues(self): - iter = self.begin() - while iter != self.end(): - yield self.second(iter) - iter = self.next(iter) - return - -def _map_iteritems(self): - iter = self.begin() - while iter != self.end(): - yield (self.first(iter), self.second(iter)) - iter = self.next(iter) - return - -def _map_keys(self): - return list(self.iterkeys()) - -def _map_values(self): - return list(self.itervalues()) - -def _map_items(self): - return list(self.iteritems()) - -def _map_has_key(self, key): - return key in self - -def _map_pop(self, key): - """ Sets the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - ret = self[key] - del self[key] - return ret - -def _map_popitem(self): - """ Sets the value associated with the provided key. """ - if len(self) == 0: - raise KeyError('key not found') - key = self.keys()[0] - return (key, self.pop(key)) - -def _map_setdefault(self, key, default=None): - """ Sets the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key in self: - return self[key] - self[key] = default - return default - -def _map_as_dict(maptype, name, keytype, valuetype): - - maptype.keytype = keytype - maptype.valuetype = valuetype - - for fctname in ['begin', 'end', 'first', 'second', 'next', \ - 'find', 'insert', 'erase', 'clear', 'size']: - fct = getattr(_idaapi, name + '_' + fctname) - setattr(maptype, '__' + fctname, fct) - - maptype.__len__ = maptype.size - maptype.__getitem__ = maptype.at - - maptype.begin = lambda self, *args: self.__begin(self, *args) - maptype.end = lambda self, *args: self.__end(self, *args) - maptype.first = lambda self, *args: self.__first(*args) - maptype.second = lambda self, *args: self.__second(*args) - maptype.next = lambda self, *args: self.__next(*args) - maptype.find = lambda self, *args: self.__find(self, *args) - maptype.insert = lambda self, *args: self.__insert(self, *args) - maptype.erase = lambda self, *args: self.__erase(self, *args) - maptype.clear = lambda self, *args: self.__clear(self, *args) - maptype.size = lambda self, *args: self.__size(self, *args) - maptype.__getitem__ = _map___getitem__ - maptype.__setitem__ = _map___setitem__ - maptype.__delitem__ = _map___delitem__ - maptype.__contains__ = _map___contains__ - maptype.clear = _map_clear - maptype.copy = _map_copy - maptype.get = _map_get - maptype.iterkeys = _map_iterkeys - maptype.itervalues = _map_itervalues - maptype.iteritems = _map_iteritems - maptype.keys = _map_keys - maptype.values = _map_values - maptype.items = _map_items - maptype.has_key = _map_has_key - maptype.pop = _map_pop - maptype.popitem = _map_popitem - maptype.setdefault = _map_setdefault - -#_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring) -_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t) -_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t) -_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, (int, long)) -_map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t) -_map_as_dict(eamap_t, 'eamap', long, cinsnptrvec_t) -#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t) - +# +# +%} + +//------------------------------------------------------------------------- +%init %{ +// +// %} diff --git a/swig/ida.i b/swig/ida.i index 0752a56..ab1af4b 100644 --- a/swig/ida.i +++ b/swig/ida.i @@ -1,16 +1,5 @@ // Ignore kernel-only symbols %ignore dual_text_options_t; -%ignore idainfo::init; -%ignore idainfo::init_netnode; -%ignore idainfo::precheck_idb_version; -%ignore idainfo::retrieve; -%ignore idainfo::read; -%ignore idainfo::write; -%ignore idainfo::convert_va_format; -%ignore idainfo::upgrade_approved; -%ignore idainfo::will_upgrade; -%ignore idainfo::approve_upgrade; -%ignore idainfo::show_progress; %ignore idainfo::align_short_demnames; %ignore idainfo::align_strtype; %ignore idainfo::align_long_demnames; @@ -21,6 +10,7 @@ %ignore setflag(uint32 &where,uint32 bit,int value); // Make idainfo::get_proc_name() work +%include "cstring.i" %cstring_bounded_output(char *buf, 8); %ignore BADADDR; diff --git a/swig/idaapi.i b/swig/idaapi.i index ef47c5f..5cfa0c4 100644 --- a/swig/idaapi.i +++ b/swig/idaapi.i @@ -1,163 +1,8 @@ -%module(docstring="IDA Plugin SDK API wrapper",directors="1",threads="1") idaapi -// generate directors for all classes that have virtual methods -%feature("director"); -// exceptions -%feature("nodirector") const_visitor_t; -%feature("nodirector") const_vloc_visitor_t; -%feature("nodirector") enumplace_t; -%feature("nodirector") generic_linput64_t; -%feature("nodirector") generic_linput_t; -%feature("nodirector") place_t; -%feature("nodirector") idaplace_t; -%feature("nodirector") qrefcnt_obj_t; -%feature("nodirector") qstring_printer_t; -%feature("nodirector") simpleline_place_t; -%feature("nodirector") structplace_t; -%feature("nodirector") type_mapper_t; -%feature("nodirector") type_visitor_t; -%feature("nodirector") vc_printer_t; -%feature("nodirector") vd_printer_t; -%feature("nodirector") vloc_visitor_t; -%feature("nodirector") qflow_chart_t; -%feature("nodirector") lowertype_helper_t; -%feature("nodirector") ida_lowertype_helper_t; -%warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended -// * http://swig.10945.n7.nabble.com/How-to-release-Python-GIL-td5027.html -// * http://stackoverflow.com/questions/1576737/releasing-python-gil-in-c-code -// * http://matt.eifelle.com/2007/11/23/enabling-thread-support-in-swig-and-python/ -%nothread; // We don't want SWIG to release the GIL for *every* IDA API call. -// Suppress 'previous definition of XX' warnings -#pragma SWIG nowarn=302 -// and others... -#pragma SWIG nowarn=312 -#pragma SWIG nowarn=325 -#pragma SWIG nowarn=314 -#pragma SWIG nowarn=362 -#pragma SWIG nowarn=383 -#pragma SWIG nowarn=389 -#pragma SWIG nowarn=401 -#pragma SWIG nowarn=451 -#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory -#pragma SWIG nowarn=514 // Director base class 'x' has no virtual destructor. - -%constant size_t SIZE_MAX = size_t(-1); %{ - -#ifndef USE_DANGEROUS_FUNCTIONS - #define USE_DANGEROUS_FUNCTIONS 1 -#endif - -#include - -void raise_python_stl_bad_alloc(const std::bad_alloc &ba) -{ - Py_INCREF(PyExc_MemoryError); - PyErr_SetString(PyExc_MemoryError, "Out of memory (bad_alloc)"); -} - -void raise_python_unknown_exception() -{ - Py_INCREF(PyExc_RuntimeError); - PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); -} - -void raise_python_stl_exception(const std::exception &e) -{ - const char *what = e.what(); - if ( what == NULL || what[0] == '\0' ) - { - raise_python_unknown_exception(); - } - else - { - Py_INCREF(PyExc_RuntimeError); - PyErr_SetString(PyExc_RuntimeError, what); - } -} - -void raise_python_swig_director_exception(const Swig::DirectorException &e) -{ - Py_INCREF(PyExc_RuntimeError); - PyErr_SetString(PyExc_RuntimeError, e.getMessage()); -} - -void raise_python_out_of_range_exception(const std::out_of_range &e) -{ - Py_INCREF(PyExc_RuntimeError); - PyErr_SetString(PyExc_IndexError, e.what()); -} - +#include +#include %} -%define %exception_set_default_handlers() -%exception { - try - { - $action - } - catch ( const std::bad_alloc &ba ) { raise_python_stl_bad_alloc(ba); SWIG_fail; } - catch ( const std::out_of_range &e ) { raise_python_out_of_range_exception(e); SWIG_fail; } - catch ( const std::exception &e ) { raise_python_stl_exception(e); SWIG_fail; } - catch ( const Swig::DirectorException &e ) { raise_python_swig_director_exception(e); SWIG_fail; } - catch ( ... ) { raise_python_unknown_exception(); SWIG_fail; } -} -%enddef -%exception_set_default_handlers(); - -// Enable automatic docstring generation -%feature(autodoc,0); - -%{ -/* strnlen() arrived on OSX at v10.7. Provide it ourselves if needed. */ -#ifdef __MAC__ -#ifndef MAC_OS_X_VERSION_10_7 -#define MAC_OS_X_VERSION_10_7 1070 -#endif -#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) -inline size_t strnlen(const char *s, size_t maxlen) -{ - const char *found = (const char *) memchr(s, 0, maxlen); - return found != NULL ? size_t(found - s) : maxlen; -} -#endif -#endif -%} - -%define SWIG_DECLARE_PY_CLINKED_OBJECT(type) -%inline %{ -static PyObject *type##_create() -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyCObject_FromVoidPtr(new type(), NULL); -} -static bool type##_destroy(PyObject *py_obj) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( !PyCObject_Check(py_obj) ) - return false; - delete (type *)PyCObject_AsVoidPtr(py_obj); - return true; -} -static type *type##_get_clink(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return (type *)pyobj_get_clink(self); -} -static PyObject *type##_get_clink_ptr(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyLong_FromUnsignedLongLong( - PTR2U64(pyobj_get_clink(self))); -} -%} -%enddef - -// We use those special maps because SWIG wraps passed PyObject* with 'SwigPtr_PyObject' and 'SwigVar_PyObject' -// They act like autoptr and decrement the reference of the object when the scope ends -// We need to keep a reference outside SWIG and let the caller manage its references -%typemap(directorin) PyObject * "/*%din%*/Py_XINCREF($1_name);$input = $1_name;" -%typemap(directorout) PyObject * "/*%dout%*/$result = result;Py_XINCREF($result);" - %{ #include @@ -165,75 +10,14 @@ static PyObject *type##_get_clink_ptr(PyObject *self) #define _SSIZE_T_DEFINED 1 #endif -#if defined(__NT__) && !defined(_WINDOWS_) - #define _WINDOWS_ // kernwin.hpp needs it to declare create_tform() - typedef void *HWND; // we don't need to include windows.h for just this definition -#endif - -#include "ida.hpp" -#include "idp.hpp" -#include "allins.hpp" -#include "auto.hpp" -#include "bytes.hpp" -#include "dbg.hpp" -#include "diskio.hpp" -#include "entry.hpp" -#include "enum.hpp" -#include "expr.hpp" -#include "frame.hpp" -#include "fixup.hpp" -#include "funcs.hpp" -#include "gdl.hpp" -#include "idd.hpp" -#include "ints.hpp" -#include "kernwin.hpp" -#include "lines.hpp" -#include "loader.hpp" -#include "moves.hpp" -#include "netnode.hpp" -#include "nalt.hpp" -#include "name.hpp" -#include "offset.hpp" -#include "queue.hpp" -#include "search.hpp" -#include "srarea.hpp" -#include "strlist.hpp" -#include "struct.hpp" -#include "typeinf.hpp" -#include "registry.hpp" -#include "ua.hpp" -#include "xref.hpp" -#include "ieee.h" -#include "err.h" -#include "fpro.h" -#include -#include "graph.hpp" -#ifdef WITH_HEXRAYS -#include "hexrays.hpp" -#endif -#include "pywraps.hpp" - // // %} -// Do not create separate wrappers for default arguments -%feature("compactdefaultargs"); - %constant ea_t BADADDR = ea_t(-1); %constant sel_t BADSEL = sel_t(-1); -%constant nodeidx_t BADNODE = nodeidx_t(-1); - -// Help SWIG to figure out the ulonglong type -#ifdef SWIGWIN -typedef unsigned __int64 ulonglong; -typedef __int64 longlong; -#else -typedef unsigned long long ulonglong; -typedef long long longlong; -#endif - -typedef int error_t; +%constant size_t SIZE_MAX = size_t(-1); +/* %constant nodeidx_t BADNODE = nodeidx_t(-1); */ %include "typemaps.i" @@ -241,108 +25,19 @@ typedef int error_t; %include "carrays.i" %include "cpointer.i" -%include "typeconv.i" - %pythoncode %{ # # %} -%include "pro.i" - -// Do not move this. We need to override the define from pro.h -#define CASSERT(type) - -// Convert all of these -%cstring_output_maxstr_none(char *buf, size_t bufsize); -%binary_output_or_none(void *buf, size_t bufsize); -%binary_output_with_size(void *buf, size_t *bufsize); - -// Accept single Python string for const void * + size input arguments -// For example: put_many_bytes() and patch_many_bytes() -%apply (char *STRING, int LENGTH) { (const void *buf, size_t size) }; -%apply (char *STRING, int LENGTH) { (const void *buf, size_t len) }; -%apply (char *STRING, int LENGTH) { (const void *value, size_t length) }; -%apply (char *STRING, int LENGTH) { (const void *dataptr,size_t len) }; - -// Create wrapper classes for basic type arrays -%array_class(uchar, uchar_array); -%array_class(tid_t, tid_array); -%array_class(ea_t, ea_array); -%array_class(sel_t, sel_array); -%array_class(uval_t, uval_array); -%pointer_class(int, int_pointer); -%pointer_class(ea_t, ea_pointer); -%pointer_class(sval_t, sval_pointer); -%pointer_class(sel_t, sel_pointer); - -%include "ida.i" -%include "idd.i" -%include "idp.i" -%include "idbhooks.i" -%include "netnode.i" -%include "nalt.i" - -%include "allins.i" -%include "area.i" -%include "auto.i" -%include "bytes.i" -%include "custdata.i" -%include "dbg.i" -%include "diskio.i" -%include "linput.i" -%include "entry.i" -%include "enum.i" -%include "expr.i" -%include "fixup.i" -%include "frame.i" -%include "funcs.i" -%include "typeinf.i" -#ifdef WITH_HEXRAYS - %include "hexrays.i" -#endif - -SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t) - -%{ -PyObject *qstrvec2pylist(qstrvec_t &vec) -{ - size_t n = vec.size(); - PyObject *py_list = PyList_New(n); - for ( size_t i=0; i < n; ++i ) - PyList_SetItem(py_list, i, PyString_FromString(vec[i].c_str())); - return py_list; -} -%} %inline %{ // // %} -%include "gdl.i" -%include "ints.i" -%include "kernwin.i" -%include "cli.i" -%include "choose.i" -%include "choose2.i" -%include "plgform.i" -%include "custview.i" -%include "askusingform.i" -%include "lines.i" -%include "loader.i" -%include "moves.i" -%include "name.i" -%include "offset.i" -%include "queue.i" -%include "search.i" -%include "segment.i" -%include "srarea.i" -%include "strlist.i" -%include "struct.i" -%include "ua.i" -%include "xref.i" -%include "view.i" -%include "graph.i" -%include "fpro.i" -%include "registry.i" +//------------------------------------------------------------------------- +%inline %{ +// +// +%} diff --git a/swig/idbhooks.i b/swig/idbhooks.i index 40c8f84..83abeb0 100644 --- a/swig/idbhooks.i +++ b/swig/idbhooks.i @@ -1,3 +1,9 @@ +%{ +#include +#include +%} + +%ignore IDB_Callback; %inline %{ // diff --git a/swig/idd.i b/swig/idd.i index 9436f10..e8942e5 100644 --- a/swig/idd.i +++ b/swig/idd.i @@ -1,3 +1,9 @@ +%{ +#include +#include +#include +%} + %ignore debugger_t; %ignore memory_info_t; %ignore lowcnd_t; @@ -20,6 +26,13 @@ %include "idd.hpp" +// SWIG chokes on the original declaration so it is replicated here +typedef struct +{ + ulonglong ival; // 8: integer value + ushort fval[6]; // 12: floating point value in the internal representation (see ieee.h) +} regval_t; + %clear(char dtyp); %rename (appcall) py_appcall; diff --git a/swig/idp.i b/swig/idp.i index dfcc795..8cd5f3b 100644 --- a/swig/idp.i +++ b/swig/idp.i @@ -1,3 +1,10 @@ +%{ +#include +#include +#include +#include +#include +%} // Ignore the following symbols %ignore WorkReg; %ignore AbstractRegister; @@ -20,15 +27,9 @@ %ignore read_config; %ignore read_config_file; %ignore read_config_string; -%ignore read_kernel_config_file; -%ignore split_path_envvar; -%ignore get_user_idadirs; -%ignore find_cfg_files; %ignore cfgopt_t; %ignore cfgopt_t__apply; %ignore parse_config_value; -%ignore get_idptype_and_data; - %ignore s_preline; %ignore ca_operation_t; @@ -42,37 +43,11 @@ %ignore instruc_t; %ignore processor_t; %ignore ph; -%ignore IDB_Callback; %ignore IDP_Callback; %ignore _py_getreg; -%ignore free_processor_module; -%ignore cfg_compiler_changed; - -%ignore gen_idb_event; -%ignore print_spec_entry; %include "idp.hpp" -%extend areacb_t { - areacb_type_t get_type() - { - areacb_type_t t = AREACB_TYPE_UNKNOWN; - if ( $self == &funcs ) - t = AREACB_TYPE_FUNC; - else if ( $self == &segs ) - t = AREACB_TYPE_SEGMENT; - else if ( $self == &hidden_areas ) - t = AREACB_TYPE_HIDDEN_AREA; - return t; - } -} - -%ignore IDP_Hooks::bool_to_cmdsize; -%ignore IDP_Hooks::bool_to_2or0; -%ignore IDP_Hooks::cm_t_to_int; -%ignore IDP_Hooks::handle_custom_mnem_output; -%ignore IDP_Hooks::handle_assemble_output; - %inline %{ // // @@ -82,3 +57,28 @@ // // %} + +%pythoncode %{ +# +# +%} + + +//------------------------------------------------------------------------- +// IDB_Hooks +//------------------------------------------------------------------------- +%{ +#include +%} + +%ignore IDB_Callback; + +%inline %{ +// +// +%} + +%{ +// +// +%} diff --git a/swig/ints.i b/swig/ints.i index 5a57a31..ae0a682 100644 --- a/swig/ints.i +++ b/swig/ints.i @@ -1,6 +1,2 @@ -// Kernel-only symbols -%ignore init_predefs; -%ignore term_predefs; - %include "ints.i" diff --git a/swig/kernwin.i b/swig/kernwin.i index 0d1e2d1..caccd5a 100644 --- a/swig/kernwin.i +++ b/swig/kernwin.i @@ -1,3 +1,15 @@ +%{ +#include +%} + +%{ +#ifdef __NT__ +idaman __declspec(dllimport) plugin_t PLUGIN; +#else +extern plugin_t PLUGIN; +#endif +%} + // Ignore the va_list functions %ignore AskUsingForm_cv; %ignore AskUsingForm_c; @@ -17,6 +29,9 @@ %ignore choose_idasgn; %rename (choose_idasgn) py_choose_idasgn; +%ignore get_chooser_data; +%rename (get_chooser_data) py_get_chooser_data; + %rename (del_hotkey) py_del_hotkey; %rename (add_hotkey) py_add_hotkey; @@ -26,7 +41,6 @@ %ignore umsg; %rename (umsg) py_umsg; -%ignore textctrl_info_t; %ignore vinfo; %ignore UI_Callback; %ignore vnomem; @@ -38,13 +52,6 @@ %ignore askyn_v; %ignore add_custom_viewer_popup_item; %ignore create_custom_viewer; -%extend qvector< snapshot_t *> { - snapshot_t *at(size_t n) { return self->at(n); } -}; -%ignore qvector< snapshot_t *>::at(size_t) const; -%ignore qvector< snapshot_t *>::at(size_t); -%ignore qvector< snapshot_t *>::grow; -%template(qvector_snapshotvec_t) qvector; %ignore take_database_snapshot; %rename (take_database_snapshot) py_take_database_snapshot; %ignore restore_database_snapshot; @@ -79,6 +86,8 @@ %rename (unregister_action) py_unregister_action; %ignore attach_dynamic_action_to_popup; %rename (attach_dynamic_action_to_popup) py_attach_dynamic_action_to_popup; +%ignore get_registered_actions; +%rename (get_registered_actions) py_get_registered_actions; %include "typemaps.i" @@ -130,19 +139,8 @@ %ignore place_t__deserialize; %ignore register_place_class; -%ignore register_enumplace; -%ignore register_idaplace; -%ignore register_simpleline_place; -%ignore register_structplace; -%ignore unregister_place_class; -%ignore unregister_place_classes_with_owner; -%ignore unregister_enumplace; -%ignore unregister_idaplace; -%ignore unregister_simpleline_place; -%ignore unregister_structplace; %ignore register_loc_converter; %ignore lookup_loc_converter; -%ignore unregister_loc_converters_for_class; %feature("director") UI_Hooks; @@ -211,12 +209,18 @@ void refresh_lists(void) # This is for get_cursor() %apply int *OUTPUT {int *x, int *y}; +%ignore textctrl_info_t; SWIG_DECLARE_PY_CLINKED_OBJECT(textctrl_info_t) %{ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); %} +%{ +// +// +%} + %inline %{ // // @@ -313,3 +317,133 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); # # %} + +//------------------------------------------------------------------------- +// choose +//------------------------------------------------------------------------- +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + +//------------------------------------------------------------------------- +// choose2 +//------------------------------------------------------------------------- +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + +//------------------------------------------------------------------------- +// askusingform +//------------------------------------------------------------------------- +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + + +//------------------------------------------------------------------------- +// cli_t +//------------------------------------------------------------------------- +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + +//------------------------------------------------------------------------- +%init %{ +// +// +%} + + +//------------------------------------------------------------------------- +// IDAView +//------------------------------------------------------------------------- +%{ +// +// + +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + +//------------------------------------------------------------------------- +// simplecustviewer_t +//------------------------------------------------------------------------- +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} + +//------------------------------------------------------------------------- +// PluginForm +//------------------------------------------------------------------------- +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} diff --git a/swig/lines.i b/swig/lines.i index 56e74c7..47e5bb5 100644 --- a/swig/lines.i +++ b/swig/lines.i @@ -12,11 +12,7 @@ %ignore add_long_cmt_v; %ignore describex; // Kernel-only and unexported symbols -%ignore init_sourcefiles; %ignore save_sourcefiles; -%ignore term_sourcefiles; -%ignore move_sourcefiles; -%ignore gen_xref_lines; %ignore ml_getcmt_t; %ignore ml_getnam_t; %ignore ml_genxrf_t; @@ -29,29 +25,13 @@ %ignore save_line_in_array; %ignore init_lines_array; %ignore finish_makeline; -%ignore finish_makeline_ex; -%ignore generate_many_lines_ex; -%ignore MakeNull_ex; -%ignore gen_labeled_line; -%ignore gen_lname_line; %ignore makeline_producer_t; -%ignore set_makeline_producer; %ignore closing_comment; %ignore close_comment; -%ignore copy_extra_cmts; -%ignore gen_extra_cmts; -%ignore Dumper; %ignore init_lines; %ignore save_lines; -%ignore term_lines; -%ignore gl_namedone; -%ignore data_as_stack; -%ignore unhide_hint_text; -%ignore calc_stack_alignment; %ignore align_down_to_stack; %ignore align_up_to_stack; -%ignore remove_spaces; -%ignore prepare_ghost_copy_desc; %ignore bgcolors; %ignore set_user_defined_prefix; diff --git a/swig/loader.i b/swig/loader.i index 19f4ff8..8ea78a8 100644 --- a/swig/loader.i +++ b/swig/loader.i @@ -11,7 +11,6 @@ // TODO: These could be wrapped if needed %ignore load_info_t; -%ignore add_plugin_option; %ignore get_plugins_paths; %ignore build_loaders_list; %ignore free_loaders_list; @@ -40,9 +39,6 @@ %ignore unhook_from_notification_point; %ignore invoke_callbacks; -// Ignore this experimental function -%ignore gen_dev_event; - // Ignore kernel-only & unexported symbols %ignore LDSC; %ignore PLUGIN; @@ -74,43 +70,11 @@ %ignore add_fileregion; %ignore move_fileregions; %ignore del_fileregions; -%ignore local_gen_idc_file; -%ignore print_all_places; -%ignore save_text_line; -%ignore print_all_structs; -%ignore print_all_enums; %ignore enum_processor_modules; %ignore enum_plugins; %ignore database_id0; %ignore is_database_ext; -%ignore ida_database_memory; -%ignore ida_workdir; %ignore is_temp_database; -%ignore pe_create_idata; -%ignore pe_load_resources; -%ignore pe_create_flat_group; -%ignore initializing; -%ignore highest_processor_level; -%ignore dbcheck_t; -%ignore DBCHK_NONE; -%ignore DBCHK_OK; -%ignore DBCHK_BAD; -%ignore DBCHK_NEW; -%ignore check_database; -%ignore open_database; -%ignore get_workbase_fname; -%ignore close_database; -%ignore compress_btree; -%ignore get_input_file_from_archive; -%ignore loader_move_segm; -%ignore generate_ida_copyright; -%ignore clear_plugin_options; -%ignore is_in_loader; -%ignore get_ids_filename; -%ignore is_embedded_dbfile_ext; -%ignore cpp_namespaces; -%ignore max_trusted_idb_count; -%ignore no_disk_space_handler; %ignore mem2base; %rename (mem2base) py_mem2base; @@ -121,6 +85,14 @@ %ignore run_plugin; %rename (run_plugin) py_run_plugin; +%extend qvector< snapshot_t *> { + snapshot_t *at(size_t n) { return self->at(n); } +}; +%ignore qvector< snapshot_t *>::at(size_t) const; +%ignore qvector< snapshot_t *>::at(size_t); +%ignore qvector< snapshot_t *>::grow; +%template(qvector_snapshotvec_t) qvector; + %include "loader.hpp" %inline %{ diff --git a/swig/moves.i b/swig/moves.i index 3413a0c..91078b4 100644 --- a/swig/moves.i +++ b/swig/moves.i @@ -1,17 +1,12 @@ - +%{ +#include +%} // Ignore kernel only symbols -%ignore init_marks; -%ignore term_marks; -%ignore change_jumps_stack_format; %ignore move_marks; %ignore curloc_after_segments_moved; %ignore curloc::rebase_stack; -%ignore loc_gtag; -%ignore write_gli; -%ignore read_gli; %ignore DEFINE_CURLOC_HELPERS; %ignore DEFINE_LOCATION_HELPERS; -%ignore histories_after_segments_moved; %ignore lochist_t::rebase_stack; %ignore location_t::location_t(bool); %ignore lochist_t::is_hexrays68_compat; diff --git a/swig/nalt.i b/swig/nalt.i index 3b945de..afe8bdd 100644 --- a/swig/nalt.i +++ b/swig/nalt.i @@ -1,6 +1,11 @@ -%ignore nmSerEA; -%ignore nmSerN; -%ignore maxSerialName; +%{ +#include +#include +#include +#include +#include "../../../pywraps.hpp" +%} + %ignore get_import_module_name; %rename (get_import_module_name) py_get_import_module_name; %ignore NALT_EA; @@ -14,8 +19,6 @@ %ignore get_strid; %ignore _set_strid; %ignore _del_strid; -%ignore set_strid; -%ignore del_strid; %ignore xrefpos_t; %ignore get_xrefpos; %ignore set_xrefpos; @@ -142,9 +145,6 @@ %rename (get_switch_info_ex) py_get_switch_info_ex; %rename (set_switch_info_ex) py_set_switch_info_ex; %rename (del_switch_info_ex) py_del_switch_info_ex; -%rename (create_switch_xrefs) py_create_switch_xrefs; -%rename (create_switch_table) py_create_switch_table; -%rename (calc_switch_cases) py_calc_switch_cases; %inline %{ // diff --git a/swig/name.i b/swig/name.i index d7bce0a..da18a37 100644 --- a/swig/name.i +++ b/swig/name.i @@ -1,5 +1,4 @@ -%cstring_output_maxstr_none(char *buf, int bufsize); - +%include "cstring.i" %cstring_bounded_output(char *dstname, MAXSTR); %cstring_bounded_output(char *buf, MAXSTR); @@ -9,18 +8,8 @@ // FIXME: These should be fixed %ignore get_struct_operand; %ignore set_debug_names; -%ignore nameVa; // Unexported & kernel-only -%ignore addDummyName; -%ignore convert_debug_names_to_normal; -%ignore convert_name_formats; -%ignore showhide_name; -%ignore clear_lname_bit; -%ignore fix_new_name; -%ignore rename; -%ignore move_names; -%ignore is_noret_name; %ignore is_exit_name; %ignore dummy_name_ea; %ignore calc_gtn_flags; @@ -29,10 +18,6 @@ %ignore get_ea_name; %rename (get_ea_name) py_get_ea_name; -%ignore get_name_value2; -%ignore make_visible_name2; - - // Deprecated functions, w/ duplicate names. // Some are simply aliased (see py_name.py) %ignore get_debug_name(ea_t *, debug_name_how_t, char *, size_t); diff --git a/swig/netnode.i b/swig/netnode.i index d7a99de..4cc4661 100644 --- a/swig/netnode.i +++ b/swig/netnode.i @@ -1,11 +1,4 @@ -// Ignore kernel only & unexported symbols -%ignore netlink; - %ignore RootNode; -%ignore for_all_supvals; -%ignore netErrorHandler; -%ignore netNoDiskSpaceHandler; -%ignore netnode_key_count; %ignore netnode_check; %ignore netnode_kill; @@ -91,6 +84,8 @@ %ignore netnode::operator nodeidx_t; %ignore netnode::validate_names; +%constant nodeidx_t BADNODE = nodeidx_t(-1); + // Renaming one version of hashset() otherwise SWIG will not be able to activate the other one %rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag); diff --git a/swig/offset.i b/swig/offset.i index fb277df..b854afa 100644 --- a/swig/offset.i +++ b/swig/offset.i @@ -1,3 +1,4 @@ -%ignore calc_probable_base; - +%{ +#include +%} %include "offset.hpp" diff --git a/swig/plgform.i b/swig/plgform.i deleted file mode 100644 index 931aa15..0000000 --- a/swig/plgform.i +++ /dev/null @@ -1,17 +0,0 @@ - -// relies on kernwin.i to include kernwin.hpp - -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/pro.i b/swig/pro.i index 2f7e05a..5b36439 100644 --- a/swig/pro.i +++ b/swig/pro.i @@ -1,183 +1,41 @@ -//--------------------------------------------------------------------- -%typemap(out) uint64 { -$result = PyLong_FromUnsignedLongLong((unsigned long long) $1); -} - -//--------------------------------------------------------------------- -%typemap(in) uint64 -{ - uint64 $1_temp; - if ( !PyW_GetNumber($input, &$1_temp) ) - { - PyErr_SetString(PyExc_TypeError, "Expected an uint64 type"); - return NULL; - } - $1 = $1_temp; -} - -//--------------------------------------------------------------------- - -%ignore wchar2char; -%ignore hit_counter_t; -%ignore reg_hit_counter; -%ignore create_hit_counter; -%ignore hit_counter_timer; -%ignore print_all_counters; -%ignore incrementer_t; -%ignore reloc_info_t; // swig under mac chokes on this -%ignore qmutex_create; -%ignore qiterator; -%ignore qmutex_free; -%ignore qmutex_lock; -%ignore qmutex_t; -%ignore qmutex_unlock; -%ignore qsem_create; -%ignore qsem_free; -%ignore qsem_post; -%ignore qsem_wait; -%ignore qsemaphore_t; -%ignore qthread_cb_t; -%ignore qthread_create; -%ignore qthread_free; -%ignore qthread_join; -%ignore qthread_kill; -%ignore qthread_self; -%ignore qthread_same; -%ignore qthread_t; -%ignore qhandle_t; -%ignore qpipe_create; -%ignore qpipe_read; -%ignore qpipe_write; -%ignore qpipe_close; -%ignore qwait_for_handles; -%ignore qstrlen; -%ignore qstrcmp; -%ignore qstrstr; -%ignore qstrchr; -%ignore qstrrchr; -%ignore bytevec_t; -%ignore qstrvec_t; -%ignore reloc_info_t; -%ignore relobj_t; -%ignore wchar2char; -%ignore u2cstr; -%ignore c2ustr; -%ignore base64_encode; -%ignore base64_decode; -%ignore utf8_unicode; -%ignore unicode_utf8; -%ignore win_utf2idb; -%ignore char2oem; -%ignore oem2char; -%ignore set_codepages; -%ignore get_codepages; -%ignore convert_codepage; -%ignore test_bit; -%ignore set_bit; -%ignore clear_bit; -%ignore set_all_bits; -%ignore clear_all_bits; -%ignore interval::overlap; -%ignore interval::includes; -%ignore interval::contains; -%ignore qrotl; -%ignore qrotr; -%ignore setflag; -%ignore read2bytes; -%ignore rotate_left; -//%ignore qswap; -%ignore swap32; -%ignore swap16; -%ignore swap_value; -%ignore qalloc_or_throw; -%ignore qrealloc_or_throw; -%ignore get_buffer_for_sysdir; -%ignore get_buffer_for_winerr; -%ignore call_atexits; -%ignore launch_process_params_t; -%ignore launch_process; -%ignore term_process; -%ignore get_process_exit_code; -%ignore BELOW_NORMAL_PRIORITY_CLASS; -%ignore parse_command_line; -%ignore parse_command_line2; -%ignore parse_command_line3; -%rename (parse_command_line3) py_parse_command_line; -%ignore qgetenv; -%ignore qsetenv; -%ignore qctime; -%ignore qlocaltime; -%ignore qstrftime; -%ignore qstrftime64; -%ignore qstrtok; -%ignore qstrlwr; -%ignore qstrupr; - -void qvector::grow(const unsigned int &x=0); -%ignore qvector::grow; - -void qvector::grow(const long long &x=0); -%ignore qvector::grow; - -%ignore qvector::at(size_t); - -// simpleline_t doesn't implement '=='. Therefore, all these cannot be present in the instantiated template. -%ignore qvector::operator==; -%ignore qvector::operator!=; -%ignore qvector::find; -%ignore qvector::has; -%ignore qvector::del; -%ignore qvector::add_unique; %include "pro.h" -//--------------------------------------------------------------------- -%extend qvector { - inline size_t __len__() const { return $self->size(); } - - // The fact that we are returning a const version of a reference to the - // type is what allows SWIG to generate a wrapper for this method, that - // will build an proper object (int, unsigned int, ...) instead - // of a pointer. Remove the 'const', and you'll see that, in - // SWIGINTERN PyObject *_wrap_uvalvec_t___getitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - // it will produce this: - // resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 ); - // instead of that: - // resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result)); - inline const T& __getitem__(size_t i) const { - if (i >= $self->size() || i < 0) - throw std::out_of_range("out of bounds access"); - return $self->at(i); - } - - inline void __setitem__(size_t i, const T& v) { - if (i >= $self->size() || i < 0) - throw std::out_of_range("out of bounds access"); - $self->at(i) = v; - } - - inline const T&at(size_t i) { - return __getitem__(i); - } - - %pythoncode { - __iter__ = _bounded_getitem_iterator - } -} +// we must include those manually here +%import "ida.hpp" +%import "xref.hpp" +%import "typeinf.hpp" +%import "enum.hpp" +%import "netnode.hpp" +// //--------------------------------------------------------------------- %template(uvalvec_t) qvector; // unsigned values %template(intvec_t) qvector; %template(int64vec_t) qvector; // for EA64 svalvec_t objects %template(boolvec_t) qvector; -%template(casevec_t) qvector >; // signed values %template(strvec_t) qvector; -%pythoncode %{ -_listify_types(uvalvec_t, - intvec_t, - int64vec_t, - boolvec_t, - casevec_t, - strvec_t) +SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t) + +%inline %{ +// +// +%} + +%include "carrays.i" +%include "cpointer.i" +%array_class(uchar, uchar_array); +%array_class(tid_t, tid_array); +%array_class(ea_t, ea_array); +%array_class(sel_t, sel_array); +%array_class(uval_t, uval_array); +%pointer_class(int, int_pointer); +%pointer_class(ea_t, ea_pointer); +%pointer_class(sval_t, sval_pointer); +%pointer_class(sel_t, sel_pointer); + +%pythoncode %{ +# +# %} diff --git a/swig/queue.i b/swig/queue.i index 8e401c9..04fcfeb 100644 --- a/swig/queue.i +++ b/swig/queue.i @@ -1,16 +1,12 @@ +%{ +#include +%} // TODO: This could be wrapped. %ignore QueueGet; // Kernel-only & unexported symbols %ignore QueueDel(ea_t); -%ignore init_queue; -%ignore save_queue; -%ignore term_queue; -%ignore move_problems; -%ignore queue_del; -%ignore mark_rollback; -%ignore get_rollback_type; %ignore mark_ida_decision; %ignore unmark_ida_decision; diff --git a/swig/registry.i b/swig/registry.i index 45b150d..d137b90 100644 --- a/swig/registry.i +++ b/swig/registry.i @@ -1,4 +1,6 @@ - +%{ +#include +%} %ignore reg_bin_op; %ignore reg_str_op; %ignore reg_int_op; diff --git a/swig/search.i b/swig/search.i index a2abf23..65d1501 100644 --- a/swig/search.i +++ b/swig/search.i @@ -1,3 +1,6 @@ +%{ +#include +%} %apply int * OUTPUT { int *opnum }; %ignore search; diff --git a/swig/segment.i b/swig/segment.i index beb54fc..1d259af 100644 --- a/swig/segment.i +++ b/swig/segment.i @@ -1,4 +1,7 @@ // Ignore functions with callbacks + +%import "area.i" + %ignore enumerate_selectors; %ignore enumerate_segments_with_selector; @@ -8,13 +11,6 @@ %ignore term_groups; %ignore vset_segm_name; %ignore get_segm_expr; -%ignore get_based_segm_expr; -%ignore createSegmentation; -%ignore initSegment; -%ignore save_segments; -%ignore termSegment; -%ignore DeleteAllSegments; -%ignore delete_debug_segments; %ignore is_debugger_segm; %ignore is_ephemeral_segm; %ignore correct_address; diff --git a/swig/srarea.i b/swig/srarea.i index 309e888..60f2a36 100644 --- a/swig/srarea.i +++ b/swig/srarea.i @@ -1,42 +1,15 @@ +%{ +#include +%} + +%import "area.i" + // Ignore kernel-only symbols %ignore repairSRarea; -%ignore init_srarea; -%ignore term_srarea; -%ignore reset_srarea; -%ignore add_srarea_from_cache; -%ignore srareas_got_loaded; -%ignore save_srarea; -%ignore create_segment_registers_area; -%ignore set_segment_register_start; -%ignore set_segment_register_end; -%ignore kill_srareras; -%ignore create_srarea; -%ignore del_srareas; -%ignore move_srareas; %ignore delete_v660_segreg_t; %ignore v660_segreg_t; -%ignore SRareas_get_area; -%ignore SRareas_get_area_qty; -%ignore SRareas_getn_area; -%ignore SRareas_update; -%ignore SRareas_get_area_num; -%ignore SRareas_get_next_area; -%ignore SRareas_get_prev_area; -%ignore SRareas_next_area_ptr; -%ignore SRareas_prev_area_ptr; -%ignore SRareas_first_area_ptr; -%ignore SRareas_choose_area2; -%ignore SRareas_may_start_at; -%ignore SRareas_may_end_at; -%ignore SRareas_set_start; -%ignore SRareas_set_end; -%ignore SRareas_prepare_to_create; -%ignore SRareas_create_area; -%ignore SRareas_for_all_areas2; -%ignore SRareas_del_area; - %ignore segreg_t::tag(int n); %ignore segreg_t::reg(int n); diff --git a/swig/strlist.i b/swig/strlist.i index f58f6c1..92cb7b1 100644 --- a/swig/strlist.i +++ b/swig/strlist.i @@ -1,11 +1,9 @@ -// Ignore kernel-only symbol +%{ +#include +%} %ignore strwinsetup_t::setup_strings_window; %ignore strwinsetup_t::save_config; %ignore strwinsetup_t::restore_config; -%ignore move_strings; - - - %include "strlist.hpp" diff --git a/swig/struct.i b/swig/struct.i index 0e822f9..c0e60ba 100644 --- a/swig/struct.i +++ b/swig/struct.i @@ -1,10 +1,11 @@ +%{ +#include +%} // Kernel-only symbols -%ignore init_structs; +%ignore del_ti; %ignore save_structs; -%ignore term_structs; %ignore get_struc_name(tid_t); %ignore get_member_name2(tid_t); -%ignore sync_from_struc; %ignore get_member_by_id(tid_t, struc_t **); // allow version w/ qstring* only //------------------------------------------------------------------------- diff --git a/swig/typeconv.i b/swig/typeconv.i index a9d71bf..ffd5743 100644 --- a/swig/typeconv.i +++ b/swig/typeconv.i @@ -366,7 +366,7 @@ struct wrapped_array_t { } %pythoncode { - __iter__ = _bounded_getitem_iterator + __iter__ = ida_idaapi._bounded_getitem_iterator } } @@ -410,3 +410,55 @@ struct wrapped_array_t { #else #error Ensure tinfo_t wrapping is compatible with this version of SWIG #endif + +// Convert all of these +%cstring_output_maxstr_none(char *buf, size_t bufsize); +%binary_output_or_none(void *buf, size_t bufsize); +%binary_output_with_size(void *buf, size_t *bufsize); + +// Accept single Python string for const void * + size input arguments +// For example: put_many_bytes() and patch_many_bytes() +%apply (char *STRING, int LENGTH) { (const void *buf, size_t size) }; +%apply (char *STRING, int LENGTH) { (const void *buf, size_t len) }; +%apply (char *STRING, int LENGTH) { (const void *value, size_t length) }; +%apply (char *STRING, int LENGTH) { (const void *dataptr,size_t len) }; + +// Create wrapper classes for basic type arrays +%array_class(uchar, uchar_array); +%array_class(tid_t, tid_array); +%array_class(ea_t, ea_array); +%array_class(sel_t, sel_array); +%array_class(uval_t, uval_array); +%pointer_class(int, int_pointer); +%pointer_class(ea_t, ea_pointer); +%pointer_class(sval_t, sval_pointer); +%pointer_class(sel_t, sel_pointer); + + +%{ +PyObject *qstrvec2pylist(qstrvec_t &vec) +{ + size_t n = vec.size(); + PyObject *py_list = PyList_New(n); + for ( size_t i=0; i < n; ++i ) + PyList_SetItem(py_list, i, PyString_FromString(vec[i].c_str())); + return py_list; +} +%} + +//--------------------------------------------------------------------- +%typemap(out) uint64 { +$result = PyLong_FromUnsignedLongLong((unsigned long long) $1); +} + +//--------------------------------------------------------------------- +%typemap(in) uint64 +{ + uint64 $1_temp; + if ( !PyW_GetNumber($input, &$1_temp) ) + { + PyErr_SetString(PyExc_TypeError, "Expected an uint64 type"); + return NULL; + } + $1 = $1_temp; +} diff --git a/swig/typeinf.i b/swig/typeinf.i index 779cc69..20da251 100644 --- a/swig/typeinf.i +++ b/swig/typeinf.i @@ -1,3 +1,10 @@ +%{ +#include +#include +%} + +%import "idp.i" + // Most of these could be wrapped if needed %ignore get_cc; %ignore get_cc_type_size; @@ -68,6 +75,7 @@ %ignore perform_funcarg_conversion; %ignore get_argloc_info; %ignore argloc_t::dstr; +%ignore argpart_t::copy_from; %ignore extract_pstr; %ignore skipName; @@ -90,12 +98,20 @@ %rename (get_named_type64) py_get_named_type64; %rename ("%s") tinfo_t::get_named_type; -%ignore udt_type_data_t::is_last_baseclass; - %rename (print_decls) py_print_decls; %ignore print_decls; -%ignore set_named_type; +// let's get rid of this one, without prohibiting tinfo_t::set_named_type() +%ignore set_named_type( + til_t *, + const char *, + int, + const type_t *, + const p_list *, + const char *, + const p_list *, + const sclass_t *, + const uint32 *); %ignore get_named_type_size; %ignore decorate_name; @@ -173,19 +189,14 @@ // Kernel-only symbols %ignore build_anon_type_name; -%ignore enum_type_data_t::is_signed; -%ignore enum_type_data_t::is_unsigned; -%ignore enum_type_data_t::get_sign; %ignore bitfield_type_data_t::serialize; %ignore func_type_data_t::serialize; %ignore func_type_data_t::deserialize; -%ignore enum_type_data_t::get_enum_base_type; -%ignore enum_type_data_t::serialize_enum; -%ignore enum_type_data_t::deserialize_enum; %ignore valstr_deprecated_t; %ignore valinfo_deprecated_t; %ignore valstr_deprecated2_t; %ignore valinfo_deprecated2_t; +%ignore tinfo_t::serialize(qtype *, qtype *, qtype *, int) const; %ignore custloc_desc_t; %ignore install_custom_argloc; @@ -207,6 +218,12 @@ %extend tinfo_t { + PyObject *serialize( + int sudt_flags=SUDT_FAST|SUDT_TRUNC) const + { + return py_tinfo_t_serialize($self, sudt_flags); + } + bool deserialize( const til_t *til, const type_t *type, @@ -274,6 +291,7 @@ %template(funcargvec_t) qvector; %template(udtmembervec_t) qvector; +%template(reginfovec_t) qvector; %include "typeinf.hpp" diff --git a/swig/ua.i b/swig/ua.i index b3c6915..c585e0d 100644 --- a/swig/ua.i +++ b/swig/ua.i @@ -1,7 +1,11 @@ +%{ +#include +#include +%} + %ignore insn_t; %ignore op_t; %ignore cmd; -%ignore ua_out; %ignore showAsChar; %ignore out_real; %ignore init_output_buffer; @@ -19,12 +23,7 @@ %ignore get_immval; %ignore get_spoiled_reg; %ignore decode_preceding_insn; -%ignore init_ua; -%ignore term_ua; %ignore term_uaterm_ua; -%ignore get_equal_items; -%ignore get_equal_itemsget_equal_items; -%ignore ua_use_fixup; %ignore get_immval; %ignore ua_stkvar; @@ -44,16 +43,16 @@ %rename (ua_add_off_drefs2) py_ua_add_off_drefs2; %rename (decode_preceding_insn) py_decode_preceding_insn; -%inline %{ -// -// -%} - %{ // // %} +%inline %{ +// +// +%} + %pythoncode %{ # # diff --git a/swig/view.i b/swig/view.i deleted file mode 100644 index 7ea2f11..0000000 --- a/swig/view.i +++ /dev/null @@ -1,16 +0,0 @@ - -%{ -// -// - -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# -%} diff --git a/swig/xref.i b/swig/xref.i index 54ebe21..c034baf 100644 --- a/swig/xref.i +++ b/swig/xref.i @@ -1,16 +1,13 @@ // Ignore kernel-only functions and variables %ignore create_xrefs_from; -%ignore create_xrefs_from_data; %ignore delete_all_xrefs_from; -%ignore delete_data_xrefs_from; -%ignore delete_code_xrefs_from; %ignore destroy_if_align; %ignore lastXR; -%ignore has_jump_or_flow_xref; -%ignore has_call_xref; -%ignore destroy_switch_info; %ignore create_switch_xrefs; +%rename (create_switch_xrefs) py_create_switch_xrefs; %ignore create_switch_table; +%rename (create_switch_table) py_create_switch_table; +%ignore calc_switch_cases; %rename (calc_switch_cases) py_calc_switch_cases; // These functions should not be called directly (according to docs) @@ -22,4 +19,16 @@ // 'from' is a reserved Python keyword %rename (frm) from; +%inline %{ +// +// +%} + %include "xref.hpp" + +%template(casevec_t) qvector >; // signed values + +%pythoncode %{ +# +# +%} diff --git a/tools/chkapi.py b/tools/chkapi.py new file mode 100644 index 0000000..ceaa77f --- /dev/null +++ b/tools/chkapi.py @@ -0,0 +1,450 @@ +from __future__ import with_statement + +import sys, optparse, re, pprint + +ignorable_api_contents = [ + "qwait" + ] + +class TextStream: + def __init__(self, text): + self.text = text + self.point = 0 + self.maxpoint = len(self.text) + self.line_nr = 0 + self.char_nr = 0 + self.curline = None + + def line(self): + pt = self.point + self.advance_to_newline() + return self.text[pt : self.point] + + def char(self): + c, self.point = self.text[self.point], self.point + 1 + if c == '\n': + self.line_nr += 1 + self.char_nr = 0 + return c + + def advance_to_newline(self): + p = self.point + while self.text[p] != '\n': + p += 1 + p += 1 + self.line_nr += 1 + self.char_nr = 0 + self.point = p + + def empty(self): + return self.point >= self.maxpoint + + +def check_cpp(opts): + + api_contents = { + "functions" : [] + } + + functions_coherence_base = { + # + # qstrvec_t: Specialized, internal, clink'ed object. + # + "_wrap_qstrvec_t_assign" : { + "mustcall" : "qstrvec_t_assign" + }, + "_wrap_qstrvec_t_addressof" : { + "mustcall" : "qstrvec_t_addressof" + }, + "_wrap_qstrvec_t_set" : { + "mustcall" : "qstrvec_t_set" + }, + "_wrap_qstrvec_t_from_list" : { + "mustcall" : "qstrvec_t_from_list" + }, + "_wrap_qstrvec_t_size" : { + "mustcall" : "qstrvec_t_size" + }, + "_wrap_qstrvec_t_get" : { + "mustcall" : "qstrvec_t_get" + }, + "_wrap_qstrvec_t_add" : { + "mustcall" : "qstrvec_t_add" + }, + "_wrap_qstrvec_t_clear" : { + "mustcall" : "qstrvec_t_clear" + }, + "_wrap_qstrvec_t_insert" : { + "mustcall" : "qstrvec_t_insert" + }, + "_wrap_qstrvec_t_remove" : { + "mustcall" : "qstrvec_t_remove" + }, + + # + # Misc. + # + "_wrap_areacb_t_get_type" : { + "mustcall" : "get_type", + }, + "_wrap_tinfo_t_deserialize__SWIG_2" : { + "mustcall" : "tinfo_t_deserialize__SWIG_2", + }, + "_wrap_get_bpt_group" : { + "mustcall" : "PyString_FromStringAndSize", + }, + "_wrap_get_jumptable_info" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_get_array_parameters" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_read_dbg_memory" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_write_dbg_memory" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_get_grp_bpts" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_generic_linput_t_read" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_generic_linput64_t_read64" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_linput_buffer_t_read" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_get_ptr_object_size" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_tag_strlen" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_get_next_member_idx" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_get_prev_member_idx" : { + "string" : "resultobj = PyLong_FromLongLong(result)", + }, + "_wrap_guess_tinfo2" : { + "mustcall" : "PyW_GetNumber", + }, + "_wrap_IDP_Hooks_adjust_refinfo" : { + "string" : "fixup_data_t", + }, + # char[ANY] out typemap + "_wrap_idainfo_tag_get" : { + "nostring" : " --size;", + }, + # char[ANY] varout typemap + "Swig_var_database_idb_get" : { + "nostring" : " --size;", + }, + + # no autoEnabled present + "SWIG_init" : { + "nostring" : "autoEnabled", + }, + } + + functions_coherence_hexrays = { + "_wrap_cfuncptr_t___str__" : { + "mustcall" : ["cfunc_t___str__", "PyString_FromStringAndSize"], + }, + "_wrap_cfunc_t___str__" : { + "mustcall" : ["cfunc_t___str__", "PyString_FromStringAndSize"], + }, + "_wrap_hexrays_failure_t_desc" : { + "mustcall" : "PyString_FromStringAndSize", + }, + "_wrap_vd_failure_t_desc" : { + "mustcall" : "PyString_FromStringAndSize", + }, + "_wrap_create_field_name" : { + "mustcall" : "PyString_FromStringAndSize", + }, + "delete_qrefcnt_t_Sl_cfunc_t_Sg_" : { + "mustcall" : "hexrays_deregister_python_cfuncptr_t_instance", + }, + "_wrap__decompile" : { + "mustcall" : "hexrays_register_python_cfuncptr_t_instance", + }, + "_wrap_vdui_t_cfunc_get" : { + "mustcall" : "hexrays_register_python_cfuncptr_t_instance", + }, + # + # qvector + # + "_wrap_strvec_t___len__" : { + "mustcall" : "qvector_Sl_simpleline_t_Sg____len__", + }, + "_wrap_strvec_t___setitem__" : { + "mustcall" : "qvector_Sl_simpleline_t_Sg____setitem__", + }, + "_wrap_strvec_t___getitem__" : { + "mustcall" : "qvector_Sl_simpleline_t_Sg____getitem__", + }, + # + # vdui_t::cfunc + # + "_wrap_vdui_t_cfunc_get" : { + "string" : "SWIGTYPE_p_qrefcnt_tT_cfunc_t_t", # proper typemap must be used + }, + } + + functions_coherence = functions_coherence_base.copy() + if opts.with_hexrays: + functions_coherence.update(functions_coherence_hexrays) + + # Mark all functions as not-spotted. + for fname in functions_coherence.keys(): + chk = functions_coherence[fname] + chk["spotted"] = False + + def dbg(msg): + if opts.verbose: + print("DEBUG: %s" % msg) + + def is_fundecl(line): + if len(line) <= 2: + return False + if line[0:1].isspace(): + return False + if line[len(line)-1:] != "{": + return False + if line.find("(") == -1 or line.find(")") == -1: + return False + return True + + def collect_funbody_lines(ts): + pt = ts.point + braces_cnt = 1 + while True: + c = ts.char() + if c == "{": + braces_cnt = braces_cnt + 1 + elif c == "}": + braces_cnt = braces_cnt - 1 + if braces_cnt == 0: + break; + # TODO: Skip strings! + return ts.text[pt : ts.point].split("\n") + + api_fname_regex = re.compile(".*PyObject \\*_wrap_([^\\(]*)\\(.*\\).*") + + KICKME_functions_lines = {} + + # Read and go through lines + for one_file in opts.files.split(","): + with open(one_file, "r") as f: + ts = TextStream(f.read()) + + # Process lines + STATE_UNKNOWN = 0 + STATE_IN_FUN = 1 + state = STATE_UNKNOWN + while not ts.empty(): + line = ts.line().rstrip() + # dbg("Line: '%s'" % line) + if is_fundecl(line): + # dbg("Entering function (from line %d: '%s')" % (ts.line_nr, line)) + state = STATE_IN_FUN + funstart = line + match = api_fname_regex.match(funstart) + if match: + fname = match.group(1) + if fname not in ignorable_api_contents: + api_contents["functions"].append(fname) + funlines = collect_funbody_lines(ts) + KICKME_functions_lines[fname] = funlines + # Do we care about this function? + check_for = None + for fname in functions_coherence.keys(): + if funstart.find(fname + "(") > -1: + check_for = fname + break + if check_for: + dbg("Checking function at line %d: '%s'" % (ts.line_nr, check_for)) + chk = functions_coherence[check_for] + chk["spotted"] = True + def look_for_stuff(stuff, isFuncall, lookForPresence=True): + if isinstance(stuff, str): + stuff = [stuff] + for bit in stuff: + found = False + bit_pat = ("%s(" % bit) if isFuncall else bit + dbg("Thing to look for: '%s'" % bit_pat) + for funline in funlines: + # dbg("Testing line: '%s'" % funline) + if funline.find(bit_pat) > -1: + found = True + break + if lookForPresence: + if not found: + raise Exception("Couldn't find '%s', from function '%s' (lines: %s)" % + (bit_pat, check_for, "\n".join([""] + funlines))) + else: + if found: + raise Exception("Did find unwanted '%s', from function '%s' (lines: %s)" % + (bit_pat, check_for, "\n".join([""] + funlines))) + + if "mustcall" in chk: + look_for_stuff(chk["mustcall"], True) + if "string" in chk: + look_for_stuff(chk["string"], False) + if "nostring" in chk: + look_for_stuff(chk["nostring"], False, lookForPresence=False) + + # Ensure all functions were spotted. + for fname in functions_coherence.keys(): + chk = functions_coherence[fname] + if not chk["spotted"]: + raise Exception("Couldn't spot function '%s'" % fname) + + # Report contents + if opts.report_contents: + # NB: we use "wb" here so that the endlines + # are written as-is, in Unix format + # and so 'diff' does not report bogus changes + # against the file from repository + with open(opts.report_contents, "wb") as f: + api_contents["functions"].sort() + f.write(pprint.pformat(api_contents)) + + # import pickle + # with open("/tmp/funlines.last", "wb") as fo: + # pickle.dump(KICKME_functions_lines, fo) + + +def check_python(opts): + types_coherence_base = { + "func_t" : { "mustinherit" : "ida_area.area_t" }, + "hidden_area_t" : { "mustinherit" : "ida_area.area_t" }, + "qbasic_block_t" : { "mustinherit" : "ida_area.area_t" }, + "regvar_t" : { "mustinherit" : "ida_area.area_t" }, + "segment_t" : { "mustinherit" : "ida_area.area_t" }, + "segreg_area_t" : { "mustinherit" : "ida_area.area_t" }, + "segreg_t" : { "mustinherit" : "ida_area.area_t" }, + + "GraphViewer" : { "mustinherit" : "ida_idaapi.CustomIDAMemo" }, + "IDAViewWrapper" : { "mustinherit" : "ida_idaapi.CustomIDAMemo" }, + "PyIdc_cvt_int64__" : { "mustinherit" : "pyidc_cvt_helper__" }, + "PyIdc_cvt_refclass__" : { "mustinherit" : "pyidc_cvt_helper__" }, + "_qstrvec_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, + "action_activation_ctx_t" : { "mustinherit" : "action_ctx_base_t" }, + "action_update_ctx_t" : { "mustinherit" : "action_ctx_base_t" }, + "argpart_t" : { "mustinherit" : "argloc_t" }, + "cli_t" : { "mustinherit" : "ida_idaapi.pyidc_opaque_object_t" }, + "enumplace_t" : { "mustinherit" : "place_t" }, + "func_type_data_t" : { "mustinherit" : "funcargvec_t" }, + "ida_lowertype_helper_t" : { "mustinherit" : "lowertype_helper_t" }, + "idaplace_t" : { "mustinherit" : "place_t" }, + "insn_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, + "location_t" : { "mustinherit" : "curloc" }, + "op_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, + "plugin_t" : { "mustinherit" : "pyidc_opaque_object_t" }, + "processor_t" : { "mustinherit" : "ida_idaapi.pyidc_opaque_object_t" }, + "py_clinked_object_t" : { "mustinherit" : "pyidc_opaque_object_t" }, + "segm_move_infos_t" : { "mustinherit" : "segm_move_info_vec_t" }, + "simpleline_place_t" : { "mustinherit" : "place_t" }, + "structplace_t" : { "mustinherit" : "place_t" }, + "switch_info_ex_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, + "textctrl_info_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, + "udt_type_data_t" : { "mustinherit" : "udtmembervec_t" }, + "varpart_t" : { "mustinherit" : "varloc_t" }, + + # Just look for the presence of those things + "BADNODE" : {}, + } + + types_coherence_hexrays = { + "DecompilationFailure" : { "mustinherit" : "Exception" }, + "carg_t" : { "mustinherit" : "cexpr_t" }, + "carglist_t" : { "mustinherit" : "qvector_carg_t" }, + "cblock_t" : { "mustinherit" : "qlist_cinsn_t" }, + "ccase_t" : { "mustinherit" : "cinsn_t" }, + "ccases_t" : { "mustinherit" : "qvector_ccase_t" }, + "cdo_t" : { "mustinherit" : "cloop_t" }, + "cexpr_t" : { "mustinherit" : "citem_t" }, + "cfor_t" : { "mustinherit" : "cloop_t" }, + "cfunc_parentee_t" : { "mustinherit" : "ctree_parentee_t" }, + "cif_t" : { "mustinherit" : "ceinsn_t" }, + "cinsn_t" : { "mustinherit" : "citem_t" }, + "cloop_t" : { "mustinherit" : "ceinsn_t" }, + "creturn_t" : { "mustinherit" : "ceinsn_t" }, + "cswitch_t" : { "mustinherit" : "ceinsn_t" }, + "ctree_parentee_t" : { "mustinherit" : "ctree_visitor_t" }, + "cwhile_t" : { "mustinherit" : "cloop_t" }, + "history_item_t" : { "mustinherit" : "ctext_position_t" }, + "history_t" : { "mustinherit" : "qvector_history_t" }, + "lvar_t" : { "mustinherit" : "lvar_locator_t" }, + "lvars_t" : { "mustinherit" : "qvector_lvar_t" }, + "qstring_printer_t" : { "mustinherit" : "vc_printer_t" }, + "vc_printer_t" : { "mustinherit" : "vd_printer_t" }, + "vd_interr_t" : { "mustinherit" : "vd_failure_t" }, + } + + types_coherence = types_coherence_base.copy() + if opts.with_hexrays: + types_coherence.update(types_coherence_hexrays) + + # Mark all types as not-spotted. + for tname in types_coherence.keys(): + chk = types_coherence[tname] + chk["spotted"] = False + + class_re = re.compile("^class ([a-zA-Z0-9_]*)\\(([a-zA-Z0-9_\\.]*)\\):") + var_re = re.compile("^([a-zA-Z0-9_]*) = .*") + for one_file in opts.python_files.split(","): + with open(one_file, "r") as f: + ts = TextStream(f.read()) + + while not ts.empty(): + line = ts.line().rstrip() + match = class_re.match(line) + if match: + tname = match.group(1) + parent = match.group(2) + if tname in types_coherence.keys(): + tc = types_coherence[tname] + tc["spotted"] = True + if "mustinherit" in tc: + if tc["mustinherit"] != parent: + raise Exception("Type '%s' should inherit from '%s' (and not '%s')" % + (tname, tc["mustinherit"], parent)) + else: + match = var_re.match(line) + if match: + vname = match.group(1) + if vname in types_coherence.keys(): + tc = types_coherence[vname] + tc["spotted"] = True + + + # Ensure all types were spotted. + for tname in types_coherence.keys(): + chk = types_coherence[tname] + if not chk["spotted"]: + raise Exception("Couldn't spot type '%s'" % tname) + + + +if __name__ == "__main__": + + p = optparse.OptionParser(description='Check the generated idaapi_include.cpp file') + p.add_option('-v', "--verbose", dest="verbose", action="store_true") + p.add_option('-i', "--input", dest="files", type="string") + p.add_option('-p', "--python-input", dest="python_files", type="string") + p.add_option('-x', "--with-hexrays", dest="with_hexrays", action="store_true") + p.add_option('-r', "--report-contents", dest="report_contents", type="string") + opts, _ = p.parse_args(sys.argv[1:]) + + if not opts.files or not opts.python_files: + p.print_help() + sys.exit(1) + + check_cpp(opts) + check_python(opts) diff --git a/tools/deploy.py b/tools/deploy.py index 2acd26b..8c6cc6c 100644 --- a/tools/deploy.py +++ b/tools/deploy.py @@ -4,55 +4,37 @@ Deploy code snips into swig interface files (c) Hex-Rays """ -import sys -import re -import os +import sys, re, os, glob major, minor, micro, _, _ = sys.version_info -if major < 2 or minor < 7: - raise Exception("Expected Python version 2.7.x, but got %s.%s.%s (from %s)" % (major, minor, micro, sys.executable)) -from argparse import ArgumentParser +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + parser = ArgumentParser() parser.add_argument("-t", "--template", required=True) parser.add_argument("-o", "--output", required=True) parser.add_argument("-m", "--module", required=True) parser.add_argument("-w", "--pywraps", required=True) +parser.add_argument("-d", "--interface-dependencies", type=str, required=True) parser.add_argument("-v", "--verbose", default=False, action="store_true") args = parser.parse_args() # creates a regular expression def make_re(tag, module, prefix): - module = "py_%s" % module s = '%(p)s<%(tag)s\(%(m)s\)>(.+?)%(p)s' % {'m': module, 'tag': tag, 'p': prefix} return (s, re.compile(s, re.DOTALL)) + def convert_path(path_in): parts = path_in.split('/') return os.sep.join(parts) -def deploy(module, template, output, pywraps, verbose): - template = convert_path(template) - output = convert_path(output) - # create regular expressions - tags = ( - ('pycode', make_re('pycode', module, '#')), - ('code', make_re('code', module, '//')), - ('inline', make_re('inline', module, '//')) - ) - # read dest file - template_str = "".join(file(template, "r").readlines()) - - # read input file(s) - input_parts = [] - for fname in ["py_%s.%s" % (module, ext) for ext in ["hpp", "py"]]: - path = os.path.join(pywraps, fname) - if os.path.isfile(path): - input_parts.append("".join(file(path, "r").readlines())) - input_str = "".join(input_parts) - - pcount = 0 +def apply_tags(template_str, input_str, tags, verbose): for desc, (expr_str, expr) in tags: # find source pattern matches = expr.findall(input_str) @@ -64,7 +46,8 @@ def deploy(module, template, output, pywraps, verbose): # find pattern in destination dest = expr.search(template_str) if not dest: - raise Exception("Found <%s> for module '%s' in input, but failed to match in destination" % (desc, module)) + raise Exception("Found <%s> for module '%s' in input, but failed to match in destination" % ( + desc, expr)) # accumulate all the strings to be replaced replaces = [] @@ -72,9 +55,54 @@ def deploy(module, template, output, pywraps, verbose): replaces.append(src) template_str = template_str[:dest.start(1)] + "\n".join(replaces) + template_str[dest.end(1):] - pcount += 1 + return template_str + +def deploy(module, template, output, pywraps, iface_deps, verbose): + template = convert_path(template) + output = convert_path(output) + + # read template file + template_str = "".join(file(template, "r").readlines()) + + # read input file(s) + all_files = glob.glob(os.path.join(pywraps, "py_%s.*" % module)) + \ + glob.glob(os.path.join(pywraps, "py_%s_*.*" % module)) + for path in all_files: + fname = os.path.basename(path) + tagname, _ = os.path.splitext(fname) + if verbose: + print("Considering file: '%s' (tagname: '%s')" % (path, tagname)) + + # create regular expressions + tags = ( + ('pycode', make_re('pycode', tagname, '#')), + ('code', make_re('code', tagname, '//')), + ('inline', make_re('inline', tagname, '//')), + ('decls', make_re('decls', tagname, '//')), + ('init', make_re('init', tagname, '//')), + ) + + input_str = "".join(file(path, "r").readlines()) + template_str = apply_tags(template_str, input_str, tags, verbose) + + # write output file with open(output, 'w') as f: + # f.write("""%module(docstring="IDA Plugin SDK API wrapper: {0}",directors="1",threads="1") {1}\n""".format( + # module, + # module if module == "idaapi" else "_ida_%s" % module)) + f.write("""%module(docstring="IDA Plugin SDK API wrapper: {0}",directors="1",threads="1") {1}\n""".format( + module, "ida_%s" % module)) + f.write("#ifndef IDA_MODULE_DEFINED\n") + f.write(""" #define IDA_MODULE_%s\n""" % module.upper()) + f.write("#define IDA_MODULE_DEFINED\n") + f.write("#endif // IDA_MODULE_DEFINED\n") + for dep in [module] + iface_deps.split(","): + if len(dep): + f.write("#ifndef HAS_DEP_ON_INTERFACE_%s\n" % dep.upper()) + f.write(" #define HAS_DEP_ON_INTERFACE_%s\n" % dep.upper()) + f.write("#endif\n") + f.write("%include \"header.i\"\n") f.write(template_str) -deploy(args.module, args.template, args.output, args.pywraps, args.verbose) +deploy(args.module, args.template, args.output, args.pywraps, args.interface_dependencies, args.verbose) diff --git a/tools/deploy/header.i.in b/tools/deploy/header.i.in new file mode 100644 index 0000000..dab5f8b --- /dev/null +++ b/tools/deploy/header.i.in @@ -0,0 +1,830 @@ +%{ +#ifndef USE_DANGEROUS_FUNCTIONS + #define USE_DANGEROUS_FUNCTIONS 1 +#endif +#include +%} + +// Auto-inserted header +// generate directors for all classes that have virtual methods +%feature("director"); +// exceptions +%feature("nodirector") const_visitor_t; +%feature("nodirector") const_vloc_visitor_t; +%feature("nodirector") enumplace_t; +%feature("nodirector") generic_linput64_t; +%feature("nodirector") generic_linput_t; +%feature("nodirector") place_t; +%feature("nodirector") idaplace_t; +%feature("nodirector") qrefcnt_obj_t; +%feature("nodirector") qstring_printer_t; +%feature("nodirector") simpleline_place_t; +%feature("nodirector") structplace_t; +%feature("nodirector") type_mapper_t; +%feature("nodirector") type_visitor_t; +%feature("nodirector") vc_printer_t; +%feature("nodirector") vd_printer_t; +%feature("nodirector") vloc_visitor_t; +%feature("nodirector") qflow_chart_t; +%feature("nodirector") lowertype_helper_t; +%feature("nodirector") ida_lowertype_helper_t; +%warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended +// * http://swig.10945.n7.nabble.com/How-to-release-Python-GIL-td5027.html +// * http://stackoverflow.com/questions/1576737/releasing-python-gil-in-c-code +// * http://matt.eifelle.com/2007/11/23/enabling-thread-support-in-swig-and-python/ +%nothread; // We don't want SWIG to release the GIL for *every* IDA API call. +// Suppress 'previous definition of XX' warnings +#pragma SWIG nowarn=302 +// and others... +#pragma SWIG nowarn=312 +#pragma SWIG nowarn=325 +#pragma SWIG nowarn=314 +#pragma SWIG nowarn=362 +#pragma SWIG nowarn=383 +#pragma SWIG nowarn=389 +#pragma SWIG nowarn=401 +#pragma SWIG nowarn=451 +#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory +#pragma SWIG nowarn=514 // Director base class 'x' has no virtual destructor. + +// Do not create separate wrappers for default arguments +%feature("compactdefaultargs"); + +void qvector::grow(const unsigned int &x=0); +%ignore qvector::grow; + +void qvector::grow(const long long &x=0); +%ignore qvector::grow; + +%ignore qvector::at(size_t); + +// simpleline_t doesn't implement '=='. Therefore, all these cannot be present in the instantiated template. +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; + +%ignore wchar2char; +%ignore hit_counter_t; +%ignore reg_hit_counter; +%ignore create_hit_counter; +%ignore hit_counter_timer; +%ignore print_all_counters; +%ignore incrementer_t; +%ignore reloc_info_t; // swig under mac chokes on this +%ignore qmutex_create; +%ignore qiterator; +%ignore qmutex_free; +%ignore qmutex_lock; +%ignore qmutex_t; +%ignore qmutex_unlock; +%ignore qsem_create; +%ignore qsem_free; +%ignore qsem_post; +%ignore qsem_wait; +%ignore qsemaphore_t; +%ignore qthread_cb_t; +%ignore qthread_create; +%ignore qthread_free; +%ignore qthread_join; +%ignore qthread_kill; +%ignore qthread_self; +%ignore qthread_same; +%ignore qthread_t; +%ignore qhandle_t; +%ignore qpipe_create; +%ignore qpipe_read; +%ignore qpipe_write; +%ignore qpipe_close; +%ignore qwait_for_handles; +%ignore qstrlen; +%ignore qstrcmp; +%ignore qstrstr; +%ignore qstrchr; +%ignore qstrrchr; +%ignore bytevec_t; +%ignore qstrvec_t; +%ignore reloc_info_t; +%ignore relobj_t; +%ignore wchar2char; +%ignore u2cstr; +%ignore c2ustr; +%ignore base64_encode; +%ignore base64_decode; +%ignore utf8_unicode; +%ignore unicode_utf8; +%ignore win_utf2idb; +%ignore char2oem; +%ignore oem2char; +%ignore set_codepages; +%ignore get_codepages; +%ignore convert_codepage; +%ignore test_bit; +%ignore set_bit; +%ignore clear_bit; +%ignore set_all_bits; +%ignore clear_all_bits; +%ignore interval::overlap; +%ignore interval::includes; +%ignore interval::contains; +%ignore qrotl; +%ignore qrotr; +%ignore setflag; +%ignore read2bytes; +%ignore rotate_left; +//%ignore qswap; +%ignore swap32; +%ignore swap16; +%ignore swap_value; +%ignore qalloc_or_throw; +%ignore qrealloc_or_throw; +%ignore get_buffer_for_sysdir; +%ignore get_buffer_for_winerr; +%ignore call_atexits; +%ignore launch_process_params_t; +%ignore launch_process; +%ignore term_process; +%ignore get_process_exit_code; +%ignore BELOW_NORMAL_PRIORITY_CLASS; +%ignore parse_command_line; +%ignore parse_command_line2; +%ignore parse_command_line3; +%rename (parse_command_line3) py_parse_command_line; +%ignore qgetenv; +%ignore qsetenv; +%ignore qctime; +%ignore qlocaltime; +%ignore qstrftime; +%ignore qstrftime64; +%ignore qstrtok; +%ignore qstrlwr; +%ignore qstrupr; + +// Do not move this. We need to override the define from pro.h +#define CASSERT(type) + +// If the module is 'pro', don't import pro.h, or the %include +// at the beginning of pro.i won't have any effect. Same for all +// modules. +${ALL_IMPORTS} + +%pythoncode { +import ida_idaapi +} + +//--------------------------------------------------------------------- +%extend qvector { + inline size_t __len__() const { return $self->size(); } + + // The fact that we are returning a const version of a reference to the + // type is what allows SWIG to generate a wrapper for this method, that + // will build an proper object (int, unsigned int, ...) instead + // of a pointer. Remove the 'const', and you'll see that, in + // SWIGINTERN PyObject *_wrap_uvalvec_t___getitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + // it will produce this: + // resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 ); + // instead of that: + // resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result)); + inline const T& __getitem__(size_t i) const { + if (i >= $self->size() || i < 0) + throw std::out_of_range("out of bounds access"); + return $self->at(i); + } + + inline void __setitem__(size_t i, const T& v) { + if (i >= $self->size() || i < 0) + throw std::out_of_range("out of bounds access"); + $self->at(i) = v; + } + + inline const T&at(size_t i) { + return __getitem__(i); + } + + %pythoncode { + __iter__ = ida_idaapi._bounded_getitem_iterator + } +} + +%{ +static void __raise_ba(const std::bad_alloc &ba) +{ + Py_INCREF(PyExc_MemoryError); + PyErr_SetString(PyExc_MemoryError, "Out of memory (bad_alloc)"); +} + +static void __raise_u() +{ + Py_INCREF(PyExc_RuntimeError); + PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); +} + +static void __raise_e(const std::exception &e) +{ + const char *what = e.what(); + if ( what == NULL || what[0] == '\0' ) + { + __raise_u(); + } + else + { + Py_INCREF(PyExc_RuntimeError); + PyErr_SetString(PyExc_RuntimeError, what); + } +} + +static void __raise_de(const Swig::DirectorException &e) +{ + Py_INCREF(PyExc_RuntimeError); + PyErr_SetString(PyExc_RuntimeError, e.getMessage()); +} + +static void __raise_oor(const std::out_of_range &e) +{ + Py_INCREF(PyExc_RuntimeError); + PyErr_SetString(PyExc_IndexError, e.what()); +} + +%} + +%define %exception_set_default_handlers() +%exception { + try + { + $action + } + catch ( const std::bad_alloc &ba ) { __raise_ba(ba); SWIG_fail; } + catch ( const std::out_of_range &e ) { __raise_oor(e); SWIG_fail; } + catch ( const std::exception &e ) { __raise_e(e); SWIG_fail; } + catch ( const Swig::DirectorException &e ) { __raise_de(e); SWIG_fail; } + catch ( ... ) { __raise_u(); SWIG_fail; } +} +%enddef +%exception_set_default_handlers(); + +// Enable automatic docstring generation +%feature(autodoc,0); + +%{ +/* strnlen() arrived on OSX at v10.7. Provide it ourselves if needed. */ +#ifdef __MAC__ +#ifndef MAC_OS_X_VERSION_10_7 +#define MAC_OS_X_VERSION_10_7 1070 +#endif +#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) +inline size_t strnlen(const char *s, size_t maxlen) +{ + const char *found = (const char *) memchr(s, 0, maxlen); + return found != NULL ? size_t(found - s) : maxlen; +} +#endif +#endif +%} + +%define SWIG_DECLARE_PY_CLINKED_OBJECT(type) +%inline %{ +static PyObject *type##_create() +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + return PyCObject_FromVoidPtr(new type(), NULL); +} +static bool type##_destroy(PyObject *py_obj) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + if ( !PyCObject_Check(py_obj) ) + return false; + delete (type *)PyCObject_AsVoidPtr(py_obj); + return true; +} +static type *type##_get_clink(PyObject *self) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + return (type *)pyobj_get_clink(self); +} +static PyObject *type##_get_clink_ptr(PyObject *self) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + return PyLong_FromUnsignedLongLong( + PTR2U64(pyobj_get_clink(self))); +} +%} +%enddef + +// We use those special maps because SWIG wraps passed PyObject* with 'SwigPtr_PyObject' and 'SwigVar_PyObject' +// They act like autoptr and decrement the reference of the object when the scope ends +// We need to keep a reference outside SWIG and let the caller manage its references +%typemap(directorin) PyObject * "/*%din%*/Py_XINCREF($1_name);$input = $1_name;" +%typemap(directorout) PyObject * "/*%dout%*/$result = result;Py_XINCREF($result);" + +//------------------------------------------------------------------------- +// For some reason, SWIG converts char arrays by computing the size +// from the end of the array, and stops when it encounters a '\0'. +// That doesn't work for us, as our API doesn't guarantee that +// bytes past the length we are interested in will be zeroed-out. +// In other words, the following code should *never* be present +// in idaapi_include.cpp: +// ------------------------- +// while (size && ([size - 1] == '\0')) --size; +// ------------------------- +// +%typemap(out) char [ANY], const char[ANY] +{ + %set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0))); +} + +%typemap(varout) char [ANY], const char[ANY] +{ + %set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0))); +} + + +%typemap(out) ssize_t +{ + $result = PyLong_FromLongLong($1); +} + +//--------------------------------------------------------------------- +// Convert an incoming Python list to a tid_t[] array +%typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) { + int i, len; + + if (!PySequence_Check($input)) + { + PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); + return NULL; + } + + /* Cap the number of elements to copy */ + len = PySequence_Length($input) < $1_dim0 ? PySequence_Length($input) : $1_dim0; + + for (i =0; i < len; i++) + { + newref_t item(PySequence_GetItem($input,i)); + if (!PyLong_Check(item.o)) + { + PyErr_SetString(PyExc_ValueError,"Expecting a sequence of long integers"); + return NULL; + } + + temp[i] = PyLong_AsUnsignedLong(item.o); + } + $1 = &temp[0]; +} + +//------------------------------------------------------------------------- +// Same, but with non-fixed sized arrays. +%typemap(in) (const tid_t *path, int plen) (qvector temp) { + if (!PySequence_Check($input)) + { + PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); + return NULL; + } + int plen = PySequence_Length($input); + if ( plen <= 0 ) + { + PyErr_SetString(PyExc_TypeError, "Sequence must have at least 1 item"); + return NULL; + } + temp.resize(plen); + for ( int i =0; i < plen; ++i ) + { + newref_t item(PySequence_GetItem($input,i)); + if (!PyLong_Check(item.o)) + { + PyErr_SetString(PyExc_ValueError,"Expecting a sequence of long integers"); + return NULL; + } + + temp[i] = PyLong_AsUnsignedLong(item.o); + } + $1 = temp.begin(); + $2 = int(temp.size()); +} + +//--------------------------------------------------------------------- +%define %cstring_output_maxstr_none(TYPEMAP, SIZE) + +%typemap (default) SIZE { + $1 = MAXSTR; + } + +%typemap(in,numinputs=0) (TYPEMAP, SIZE) { + $1 = ($1_ltype) qalloc(MAXSTR+1); +} + +%typemap(argout) (TYPEMAP,SIZE) { + Py_XDECREF(resultobj); + if (result > 0) + { + resultobj = PyString_FromString($1); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } + qfree($1); +} +%enddef + +//--------------------------------------------------------------------- +%define %cstring_bounded_output_none(TYPEMAP,MAX) +%typemap(in, numinputs=0) TYPEMAP(char temp[MAX+1]) { + $1 = ($1_ltype) temp; +} +%typemap(argout,fragment="t_output_helper") TYPEMAP { + PyObject *o; + $1[MAX] = 0; + + if ($1 > 0) + { + o = PyString_FromString($1); + } + else + { + o = Py_None; + Py_INCREF(Py_None); + } + $result = t_output_helper($result,o); +} +%enddef + +//--------------------------------------------------------------------- +%define %binary_output_or_none(TYPEMAP, SIZE) +%typemap (default) SIZE { + $1 = MAXSPECSIZE; +} +%typemap(in,numinputs=0) (TYPEMAP, SIZE) { + $1 = (char *) qalloc(MAXSPECSIZE+1); +} +%typemap(argout) (TYPEMAP,SIZE) { + Py_XDECREF(resultobj); + if (result > 0) + { + resultobj = PyString_FromStringAndSize((char *)$1, result); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } + qfree((void *)$1); +} +%enddef + +//--------------------------------------------------------------------- +%define %binary_output_with_size(TYPEMAP, SIZE) +%typemap (default) SIZE { + size_t ressize = MAXSPECSIZE; + $1 = &ressize; +} +%typemap(in,numinputs=0) (TYPEMAP, SIZE) { + $1 = (char *) qalloc(MAXSPECSIZE+1); +} +%typemap(argout) (TYPEMAP,SIZE) { + Py_XDECREF(resultobj); + if (result) + { + resultobj = PyString_FromStringAndSize((char *)$1, *$2); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } + qfree((void *)$1); +} +%enddef + +//--------------------------------------------------------------------- +// IN/OUT qstring +//--------------------------------------------------------------------- +%typemap(in,numinputs=0) qstring *result (qstring temp) { + $1 = &temp; +} +%typemap(argout) qstring *result { + Py_XDECREF(resultobj); + if (result) + { + resultobj = PyString_FromStringAndSize($1->begin(), $1->length()); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } +} +%typemap(freearg) qstring* result +{ + // Nothing. We certainly don't want 'temp' to be deleted. +} + +//--------------------------------------------------------------------- +// md5/sha256 hash retrieval +%typemap(in, numinputs=0) uchar hash[ANY] (uchar temp[$1_dim0]) +{ + $1 = temp; +} + +%typemap(argout) uchar hash[ANY] +{ + Py_XDECREF(resultobj); + if (result) + { + char buf[2*$1_dim0 + 1]; + get_hex_string(buf, sizeof(buf), $1, $1_dim0); + resultobj = PyString_FromString(buf); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } +} + +// Check that the argument is a callable Python object +//--------------------------------------------------------------------- +%typemap(in) PyObject *pyfunc { + if (!PyCallable_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Expected a callable object"); + return NULL; + } + $1 = $input; +} +// Check that the argument is None or a callable Python object +//--------------------------------------------------------------------- +%typemap(in) PyObject *pyfunc_or_none { + if ($input != Py_None && !PyCallable_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Expected None or a callable object"); + return NULL; + } + $1 = $input; +} +// Check that the argument is None or a tuple +//--------------------------------------------------------------------- +%typemap(in) PyObject *tuple_or_none { + if ($input != Py_None && !PyTuple_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Expected None or a tuple"); + return NULL; + } + $1 = $input; +} +%typemap(in) ea_t +{ + uint64 $1_temp; + if ( !PyW_GetNumber($input, &$1_temp) ) + { + PyErr_SetString(PyExc_TypeError, "Expected an ea_t type"); + return NULL; + } + $1 = ea_t($1_temp); +} +// Use PyLong_FromUnsignedLongLong, because 'long' is 4 bytes on +// windows, and thus the ea_t would be truncated at the +// PyLong_FromUnsignedLong(unsigned int) call time. +%typemap(out) ea_t "$result = PyLong_FromUnsignedLongLong($1);" + +%typemap(in) qtime64_t "$1 = PyLong_AsUnsignedLongLong($input);" +%typemap(out) qtime64_t "$result = PyLong_FromUnsignedLongLong($1);" + +//--------------------------------------------------------------------- +// IN qstring +//--------------------------------------------------------------------- +// This is used to set/retrieve qstring that are structure members. +%typemap(in) qstring* +{ + char *buf; + Py_ssize_t length; + int success = PyString_AsStringAndSize($input, &buf, &length); + if ( success > -1 ) + { + $1 = new qstring(buf, length); + } +} +%typemap(freearg) qstring* +{ + delete $1; +} +%typemap(out) qstring* +{ + $result = PyString_FromStringAndSize($1->c_str(), $1->length()); +} +%typemap(out) qstring +{ + $result = PyString_FromStringAndSize($1.c_str(), $1.length()); +} +%apply qstring { _qstring } +%apply qstring* { _qstring* } + +//--------------------------------------------------------------------- +// varargs (mostly kernwin.hpp) +//--------------------------------------------------------------------- +// This is used for functions like warning(), info() and so on +%typemap(in) (const char *format, ...) +{ + $1 = "%s"; /* Fix format string to %s */ + $2 = (void *) PyString_AsString($input); /* Get string argument */ +}; + +// Help SWIG to figure out the ulonglong type +#ifdef SWIGWIN +typedef unsigned __int64 ulonglong; +typedef __int64 longlong; +#else +typedef unsigned long long ulonglong; +typedef long long longlong; +#endif + +#ifdef __EA64__ +%apply longlong *INOUT { sval_t *value }; +%apply longlong *INOUT { adiff_t *disp }; +%apply ulonglong *INOUT { ea_t *addr }; +%apply ulonglong *INOUT { sel_t *sel }; +%apply ulonglong *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection() +#else +%apply int *INOUT { sval_t *value }; +%apply int *INOUT { adiff_t *disp }; +%apply unsigned int *INOUT { ea_t *addr }; +%apply unsigned int *INOUT { sel_t *sel }; +%apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection() +#endif + +%apply qstring *result { qstring *label }; +%apply qstring *result { qstring *shortcut }; +%apply qstring *result { qstring *tooltip }; +%apply qstring *result { qstring *out }; +%apply int *OUTPUT { int *icon }; +%apply int *OUTPUT { action_state_t *state }; +%apply bool *OUTPUT { bool *checkable }; +%apply bool *OUTPUT { bool *checked }; +%apply bool *OUTPUT { bool *visibility }; + +//------------------------------------------------------------------------- +// The following is to be used to expose an array of items +// to IDAPython. This will not make a copy (on purpose!). +//------------------------------------------------------------------------- +// +// (Very) heavily inspired by: +// http://stackoverflow.com/questions/7713318/nested-structure-array-access-in-python-using-swig?rq=1 +// +%immutable; +%inline %{ +template +struct wrapped_array_t { + Type (&data)[N]; + wrapped_array_t(Type (&data)[N]) : data(data) { } +}; +%} +%mutable; + +%extend wrapped_array_t { + inline size_t __len__() const { return N; } + + inline const Type& __getitem__(size_t i) const throw(std::out_of_range) { + if (i >= N || i < 0) + throw std::out_of_range("out of bounds access"); + return $self->data[i]; + } + + inline void __setitem__(size_t i, const Type& v) throw(std::out_of_range) { + if (i >= N || i < 0) + throw std::out_of_range("out of bounds access"); + $self->data[i] = v; + } + + %pythoncode { + __iter__ = ida_idaapi._bounded_getitem_iterator + } +} + +//------------------------------------------------------------------------- +#if SWIG_VERSION == 0x20012 +%typemap(out) tinfo_t {} +%typemap(ret) tinfo_t +{ + // ret tinfo_t + tinfo_t *ni = new tinfo_t($1); + til_register_python_tinfo_t_instance(ni); + $result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0); +} + + +// KLUDGE: We'll let the compiler (or at worse the runtime) +// decide of the flags to use, depending on the method we are currently +// wrapping: at new-time, a SWIG_POINTER_NEW is required. +%typemap(out) tinfo_t* {} +%typemap(ret) tinfo_t* +{ + // ret tinfo_t* + tinfo_t *ni = new tinfo_t(*($1)); + til_register_python_tinfo_t_instance(ni); + if ( strcmp("new_tinfo_t", "$symname") == 0 ) + { + $result = SWIG_NewPointerObj(SWIG_as_voidptr(ni), $1_descriptor, SWIG_POINTER_NEW | 0); + delete $1; + } + else + { + $result = SWIG_NewPointerObj(SWIG_as_voidptr(ni), $1_descriptor, SWIG_POINTER_OWN | 0); + } +} + +%typemap(check) tinfo_t* +{ + if ( $1 == NULL ) + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); +} +#else +#error Ensure tinfo_t wrapping is compatible with this version of SWIG +#endif + +// Convert all of these +%cstring_output_maxstr_none(char *buf, size_t bufsize); +%cstring_output_maxstr_none(char *buf, int bufsize); +%binary_output_or_none(void *buf, size_t bufsize); +%binary_output_with_size(void *buf, size_t *bufsize); + + +// Accept single Python string for const void * + size input arguments +// For example: put_many_bytes() and patch_many_bytes() +%apply (char *STRING, int LENGTH) { (const void *buf, size_t size) }; +%apply (char *STRING, int LENGTH) { (const void *buf, size_t len) }; +%apply (char *STRING, int LENGTH) { (const void *value, size_t length) }; +%apply (char *STRING, int LENGTH) { (const void *dataptr,size_t len) }; + +// Create wrapper classes for basic type arrays +%array_class(uchar, uchar_array); +%array_class(tid_t, tid_array); +%array_class(ea_t, ea_array); +%array_class(sel_t, sel_array); +%array_class(uval_t, uval_array); +%pointer_class(int, int_pointer); +%pointer_class(ea_t, ea_pointer); +%pointer_class(sval_t, sval_pointer); +%pointer_class(sel_t, sel_pointer); + + +%{ +static PyObject *qstrvec2pylist(qstrvec_t &vec) +{ + size_t n = vec.size(); + PyObject *py_list = PyList_New(n); + for ( size_t i=0; i < n; ++i ) + PyList_SetItem(py_list, i, PyString_FromString(vec[i].c_str())); + return py_list; +} +%} + +//--------------------------------------------------------------------- +%typemap(out) uint64 { +$result = PyLong_FromUnsignedLongLong((unsigned long long) $1); +} + +//--------------------------------------------------------------------- +%typemap(in) uint64 +{ + uint64 $1_temp; + if ( !PyW_GetNumber($input, &$1_temp) ) + { + PyErr_SetString(PyExc_TypeError, "Expected an uint64 type"); + return NULL; + } + $1 = $1_temp; +} + +%inline %{ +namespace Controls +{ + class TWinControl; + class TCustomControl; // ptr to custom ida viewer +} +using Controls::TWinControl; +using Controls::TCustomControl; +%} + +namespace Forms +{ + class TForm; +} +using Forms::TForm; + +// Make get_any_cmt() work +%apply unsigned char *OUTPUT { color_t *cmttype }; + +// For get_enum_id() +%apply unsigned char *OUTPUT { uchar *serial }; + +// get_[first|last]_serial_enum_member() won't take serials as input; it'll be present as output +%apply unsigned char *OUTPUT { uchar *out_serial }; +// get_[next|prev]_serial_enum_member() take serials as input, and have the result present as output +%apply unsigned char *INOUT { uchar *in_out_serial }; + +%{ +#include +#include +#include "../../../pywraps.hpp" +%} + +// END: auto-inserted header diff --git a/hrdoc.cfg b/tools/docs/hrdoc.cfg.in similarity index 98% rename from hrdoc.cfg rename to tools/docs/hrdoc.cfg.in index 2d60bcd..167ce99 100644 --- a/hrdoc.cfg +++ b/tools/docs/hrdoc.cfg.in @@ -2,8 +2,7 @@ # The list of objects to document. Objects can be named using # dotted names, module filenames, or package directory names. # Aliases for this option include "objects" and "values". -modules: idc, idautils, idaapi -#modules: pywraps +modules: idc, idautils, idaapi, %IDA_MODULES% # The type of output that should be generated. Should be one # of: html, text, latex, dvi, ps, pdf. @@ -145,4 +144,4 @@ graph-font: Helvetica # The condition upon which Epydoc should exit with a non-zero # exit status. Possible values are error, warning, docstring_warning -#fail-on: error \ No newline at end of file +#fail-on: error diff --git a/hrdoc.css b/tools/docs/hrdoc.css similarity index 100% rename from hrdoc.css rename to tools/docs/hrdoc.css diff --git a/hrdoc.py b/tools/docs/hrdoc.py similarity index 84% rename from hrdoc.py rename to tools/docs/hrdoc.py index e815e1c..0a1849e 100755 --- a/hrdoc.py +++ b/tools/docs/hrdoc.py @@ -3,9 +3,22 @@ import sys import shutil from glob import glob +try: + import epydoc.apidoc + import epydoc.cli +except ImportError as e: + import idc + import traceback + idc.Message("Couldn't import module %s\n" % traceback.format_exc()) + idc.Exit(-1) + # -------------------------------------------------------------------------- DOC_DIR = 'hr-html' -PYWRAPS_FN = 'idaapi.py' + +# -------------------------------------------------------------------------- +def log(msg): + #print msg + pass # -------------------------------------------------------------------------- def add_footer(lines): @@ -30,20 +43,20 @@ def define_idaapi_resolver(): Whenever a module named \"idaapi_\" is spotted, turn it into \"idaapi\". """ - import epydoc.apidoc dn = epydoc.apidoc.DottedName.__init__ def resolver(piece): if piece is not None and isinstance(piece, basestring) and piece.startswith("idaapi_"): - return "idaapi" + res = "idaapi" else: - return piece + res = piece + log("Resolver '%s' => '%s'" % (piece, res)) + return res def wrapper(self, *pieces, **options): return dn(self, *map(resolver, pieces), **options); epydoc.apidoc.DottedName.__init__ = wrapper # -------------------------------------------------------------------------- def gen_docs(): - import epydoc.cli import swigdocs define_idaapi_resolver() @@ -57,7 +70,7 @@ def gen_docs(): os.unlink(fn) epydoc.cli.optparse.sys.argv = [ 'epydoc', - '--config', '../hrdoc.cfg', + '--config', '../tools/docs/hrdoc.cfg', '--simple-term' ] @@ -66,7 +79,7 @@ def gen_docs(): # -------------------------------------------------------------------------- def patch_docs(): - shutil.copy('../../hrdoc.css', 'epydoc.css') + shutil.copy('../../tools/docs/hrdoc.css', 'epydoc.css') os.system('chmod +w epydoc.css') for fn in glob('*.html'): diff --git a/tools/funlines.py b/tools/funlines.py new file mode 100644 index 0000000..0e37c99 --- /dev/null +++ b/tools/funlines.py @@ -0,0 +1,85 @@ + +import os, sys, pickle, subprocess + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser() +parser.add_argument("-l", "--left", required=True) +parser.add_argument("-r", "--right", required=True) +args = parser.parse_args() + +with open(args.left, "rb") as forig: + with open(args.right, "rb") as fthen: + orig = pickle.load(forig) + then = pickle.load(fthen) + +sk_orig = sorted(orig.keys()) +sk_then = sorted(then.keys()) +for key in sk_orig: + if not key in sk_then: + print "Missing expected key: %s" % key + +for key in sk_then: + if not key in sk_orig: + print "Unexpected key found: %s" % key + +subprocess.check_call(["rm", "-r", "-f", "/tmp/diffs"]) +subprocess.check_call(["mkdir", "/tmp/diffs"]) +for key in sk_orig: + if not key in sk_then: + continue + + lines_orig = orig[key] + # sanitize lines_orig + def san(l): + l = l.replace("raise_python_stl_bad_alloc", "__raise_ba") + l = l.replace("raise_python_out_of_range_exception", "__raise_oor") + l = l.replace("raise_python_stl_exception", "__raise_e") + l = l.replace("raise_python_swig_director_exception", "__raise_de") + l = l.replace("raise_python_unknown_exception", "__raise_u") + return l + lines_orig = map(san, lines_orig) + + lines_then = then[key] + if lines_orig != lines_then: + left_path = "/tmp/left_%s" % key + right_path = "/tmp/right_%s" % key + with open(left_path, "wb") as fleft: + fleft.write("\n".join(lines_orig)) + with open(right_path, "wb") as fright: + fright.write("\n".join(lines_then)) + patch_path = "/tmp/diffs/%s.patch" % key + with open(patch_path, "wb") as fout: + subprocess.call(["diff", "-u", "-w", left_path, right_path], stdout=fout) + # Now, let's see if the patch isn't trivial/acceptable. If it is, + # then we just delete that file + trivial_crap = [ +"""- { +- Py_INCREF(Py_None); +- resultobj = Py_None; +- } ++ resultobj = SWIG_Py_Void();""", + +"""- result = (bool)__init_hexrays_plugin(arg1); ++ result = (bool)py_init_hexrays_plugin(arg1);""", + +"""- result = (bool)__install_hexrays_callback(arg1); ++ result = (bool)py_install_hexrays_callback(arg1);""", + +"""- __add_custom_viewer_popup_item(arg1,(char const *)arg2,(char const *)arg3,arg4); ++ py_add_custom_viewer_popup_item(arg1,(char const *)arg2,(char const *)arg3,arg4);""", + + ] + + with open(patch_path, "rb") as fin: + lines = fin.readlines() + diff_lines = filter(lambda l: (l.startswith("-") and not l.startswith("---")) or (l.startswith("+") and not l.startswith("+++")), lines) + diff_clob = "".join(diff_lines) + # print "\"%s\"" % diff_clob + if diff_clob.strip() in trivial_crap: + # print "Removing trivial patch: %s" % patch_path + os.remove(patch_path) diff --git a/tools/gendocs.py b/tools/gendocs.py deleted file mode 100644 index 927e8ff..0000000 --- a/tools/gendocs.py +++ /dev/null @@ -1,25 +0,0 @@ -#------------------------------------------------------------ -# gendoc.py: Generate an API cross-reference for IDAPython -#------------------------------------------------------------ -__author__ = "Gergely Erdelyi " - -import epydoc.cli - -# This is a small hack to prevent epydoc from exiting the whole -# IDA process in case something goes wrong. -def exit(eval): - print "not exiting" -epydoc.cli.sys.exit = exit - -# Fill in the command-line arguments -epydoc.cli.optparse.sys.argv = [ 'epydoc', - '--no-sourcecode', - '-u', 'http://www.d-dome.net/idapython/', - '--navlink', 'IDAPython Reference', - '--no-private', - '--simple-term', - '-o', 'idapython-reference-%d.%d.%d' % (IDAPYTHON_VERSION[:3]), - '--html', - 'idc', 'idautils', 'idaapi' ] -# Generate the documentation -epydoc.cli.cli() diff --git a/tools/genhooks/genhooks.py b/tools/genhooks/genhooks.py index 085bf49..a0c2120 100644 --- a/tools/genhooks/genhooks.py +++ b/tools/genhooks/genhooks.py @@ -291,8 +291,8 @@ def gen_notifications(out): pass_expr = pname if clinked: - out.write(" ref_t clinked_%s = create_idaapi_linked_class_instance(%s, %s);\n" % - (pname, clinked["class_define"], pname)) + out.write(" ref_t clinked_%s = create_linked_class_instance(%s, %s, %s);\n" % + (pname, clinked["module_define"], clinked["class_define"], pname)) out.write(" if ( clinked_%s == NULL )\n" % pname) out.write(" break;\n") pass_expr = "clinked_%s.o" % pname diff --git a/tools/genhooks/recipe_idphooks.py b/tools/genhooks/recipe_idphooks.py index c7bf03d..24e4b01 100644 --- a/tools/genhooks/recipe_idphooks.py +++ b/tools/genhooks/recipe_idphooks.py @@ -3,6 +3,9 @@ recipe = { "last_cb_before_debugger" : {"ignore" : True}, "last_cb_before_type_callbacks" : {"ignore" : True}, + "get_operand_info" : {"ignore" : True}, + "obsolete_get_operand_info" : {"ignore" : True}, + "loader_elf_machine" : {"ignore" : True}, "custom_ana" : { "return" : { "type" : "bool", @@ -29,6 +32,7 @@ recipe = { "op" : { "type" : "PyObject *", "clinked" : { + "module_define" : "S_IDA_UA_MODNAME", "class_define" : "S_PY_OP_T_CLSNAME", }, }, diff --git a/tools/genidaapi.py b/tools/genidaapi.py new file mode 100644 index 0000000..ca3dfc7 --- /dev/null +++ b/tools/genidaapi.py @@ -0,0 +1,24 @@ + +import sys +import string + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser() +parser.add_argument("-i", "--input", required=True) +parser.add_argument("-o", "--output", required=True) +parser.add_argument("-m", "--modules", required=True) +args = parser.parse_args() + +with open(args.input, "rb") as fin: + with open(args.output, "wb") as fout: + template = string.Template(fin.read()) + kvps = { + "MODULES" : args.modules, + "IMPORTS" : "\n".join([("from ida_%s import *" % mod) for mod in args.modules.split(",")]) + } + fout.write(template.substitute(kvps)) diff --git a/tools/genswigheader.py b/tools/genswigheader.py new file mode 100644 index 0000000..6bc5ee3 --- /dev/null +++ b/tools/genswigheader.py @@ -0,0 +1,42 @@ + +import sys +import os +import glob + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser() +parser.add_argument("-i", "--input", required=True) +parser.add_argument("-o", "--output", required=True) +parser.add_argument("-m", "--modules", required=True) +parser.add_argument("-s", "--sdk", required=True) +args = parser.parse_args() + +with open(args.input, "rb") as fin: + with open(args.output, "wb") as fout: + parts = [] + + def add_imports_from_dep(depname): + DEPNAME = depname.upper() + for dep in glob.glob(os.path.join(args.sdk, "%s.*" % depname)): + parts.append(" #ifndef HAS_DEP_ON_INTERFACE_%s" % DEPNAME) + parts.append(" %import \"{0}\"".format(os.path.basename(dep))) + parts.append(" #endif") + parts.append("") + + parts.append("#if defined(IDA_MODULE_PRO)") + parts.append("// nothing; has to be handled in pro.i") + parts.append("#else") + required_headers = ["pro", "ida", "xref", "typeinf", "enum", "netnode", "area", "lines", "kernwin", "bytes", "auto", "nalt"] + for rh in required_headers: + add_imports_from_dep(rh) + parts.append("#endif") + + # Can't use string.Template here, because it's a nightmare + # to use with a file that has many '$' is it. + template = fin.read() + fout.write(template.replace("${ALL_IMPORTS}", "\n".join(parts))) diff --git a/tools/idapython_implib.def.in b/tools/idapython_implib.def.in new file mode 100644 index 0000000..913ec40 --- /dev/null +++ b/tools/idapython_implib.def.in @@ -0,0 +1,66 @@ +LIBRARY %LIBNAME% +EXPORTS + PyWStringOrNone_Check + PyW_CreateIdcException + PyW_GetError + PyW_GetNumber + PyW_GetNumberAsIDC + PyW_GetStringAttr + PyW_IntVecToPyList + PyW_IsSequenceType + PyW_ObjectToString + PyW_PyListToEaVec + PyW_PyListToIntVec + PyW_PyListToStrVec + PyW_register_compiled_form + PyW_ShowCbErr + PyW_TryGetAttrString + PyW_TryImportModule + PyW_unregister_compiled_form + add_notify_when + create_linked_class_instance + disable_script_timeout + enable_extlang_python + enable_python_cli + idcvar_to_pyvar + lookup_info_t_commit + lookup_info_t_del_by_py_view + lookup_info_t_find_by_form + lookup_info_t_find_by_py_view + lookup_info_t_new_entry + meminfo_vec_t_to_py + py_customidamemo_t_bind + py_customidamemo_t_collect_class_callbacks_ids + py_customidamemo_t_collect_pyobject_callbacks + py_customidamemo_t_create_groups + py_customidamemo_t_del_nodes_infos + py_customidamemo_t_delete_groups + py_customidamemo_t_ensure_view_callbacks_installed + py_customidamemo_t_get_current_renderer_type + py_customidamemo_t_get_node_info + py_customidamemo_t_install_custom_viewer_handlers + py_customidamemo_t_set_current_renderer_type + py_customidamemo_t_set_groups_visibility + py_customidamemo_t_set_node_info + py_customidamemo_t_set_nodes_infos + py_customidamemo_t_unbind + pyobj_get_clink + python_timer_new + python_timer_del + pyvar_to_idcvar + pyvar_to_idcvar_or_error + pyvar_walk_list + pyw_convert_idc_args + set_script_timeout + til_deregister_python_array_type_data_t_instance + til_deregister_python_func_type_data_t_instance + til_deregister_python_ptr_type_data_t_instance + til_deregister_python_tinfo_t_instance + til_deregister_python_udt_type_data_t_instance + til_register_python_array_type_data_t_instance + til_register_python_func_type_data_t_instance + til_register_python_ptr_type_data_t_instance + til_register_python_tinfo_t_instance + til_register_python_udt_type_data_t_instance + pycim_lookup_info DATA + PLUGIN DATA diff --git a/inject_pydoc.py b/tools/inject_pydoc.py similarity index 88% rename from inject_pydoc.py rename to tools/inject_pydoc.py index a6a849d..fd0121a 100644 --- a/inject_pydoc.py +++ b/tools/inject_pydoc.py @@ -10,12 +10,29 @@ # 3) Generating the idaapi_.py file. # -import re +import sys import os -import os.path +import re + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser() +parser.add_argument("-i", "--input", required=True) +parser.add_argument("-w", "--wrapper", required=True) +parser.add_argument("-o", "--output", required=True) +parser.add_argument("-v", "--verbose", default=False, action="store_true") +args = parser.parse_args() DOCSTR_MARKER = "\"\"\"" +def verb(msg): + if args.verbose: + print msg + # -------------------------------------------------------------------------- def split_oneliner_comments(lines): out_lines = [] @@ -97,8 +114,9 @@ class collect_idaapi_pydoc_t(object): state = S_UNKNOWN lines = None - def __init__(self): + def __init__(self, input_path): self.idaapi_pydoc = {"funcs" : {}, "classes" : {}} + self.input_path = input_path def next(self): line = self.lines[0] @@ -195,10 +213,9 @@ class collect_idaapi_pydoc_t(object): elif line.startswith(self.PYDOC_END): self.state = self.S_UNKNOWN - def collect(self, dirpath): - for root, dirs, files in os.walk(dirpath): - for f in files: - self.collect_file_pydoc(os.path.join(root, f)) + def collect(self): + verb("### Processing %s" % os.path.basename(self.input_path)) + self.collect_file_pydoc(self.input_path) return self.idaapi_pydoc @@ -255,6 +272,8 @@ class idaapi_fixer_t(object): else: found = self.get_method_info(class_info, fun_name) if found is not None: + verb("fix_%s: found info for %s" % ( + "method" if class_info else "fun", fun_name)); out.append("\n") for fl in found: out.append(indent + fl) @@ -266,13 +285,14 @@ class idaapi_fixer_t(object): def fix_method(self, class_info, out): return self.fix_fun(out, class_info) - def fix_cls(self, out): + def fix_class(self, out): line = self.copy(out) cls_name = get_class_name(line) - class_info = self.get_class_info(cls_name) - if class_info is None: + found = self.get_class_info(cls_name) + if found is None: return + verb("fix_class: found info for %s" % cls_name); line = self.copy(out) indent = get_indent_string(line) @@ -281,7 +301,7 @@ class idaapi_fixer_t(object): while True: line = self.next() if line.find(DOCSTR_MARKER) > -1: - doc = class_info["doc"] + doc = found["doc"] if doc is not None: out.append("\n") for dl in doc: @@ -300,15 +320,15 @@ class idaapi_fixer_t(object): if line.startswith(indent) or line.strip() == "": if line.startswith(method_start): self.push_front(line) - self.fix_method(class_info, out) + self.fix_method(found, out) else: out.append(line) else: self.push_front(line) break - def fix_file(self, idaapi_filename, out_filename): - with open(idaapi_filename, "rt") as f: + def fix_file(self, input_path, out_path): + with open(input_path, "rt") as f: self.lines = split_oneliner_comments(f.readlines()) out = [] while len(self.lines) > 0: @@ -319,22 +339,16 @@ class idaapi_fixer_t(object): self.fix_fun(out) elif line.startswith("class "): self.push_front(line) - self.fix_cls(out) + self.fix_class(out) else: out.append(line) - with open(out_filename, "wt") as o: + with open(out_path, "wt") as o: for ol in out: o.write(ol) o.write("\n") # -------------------------------------------------------------------------- -if __name__ == '__main__': - import sys - collecter = collect_idaapi_pydoc_t() - collected = collecter.collect(sys.argv[1]) - # import pprint - # pprint.pprint(collected, indent=2) - fixer = idaapi_fixer_t(collected) - target_file = sys.argv[2] - result_file = sys.argv[3] - fixer.fix_file(target_file, result_file) +collecter = collect_idaapi_pydoc_t(args.wrapper) +collected = collecter.collect() +fixer = idaapi_fixer_t(collected) +fixer.fix_file(args.input, args.output) diff --git a/tools/patch_constants.py b/tools/patch_constants.py new file mode 100644 index 0000000..551a234 --- /dev/null +++ b/tools/patch_constants.py @@ -0,0 +1,192 @@ + +import re + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser(description='Patch calling conventions for some functions, so it builds on windows') +parser.add_argument("-f", "--file", required=True) +parser.add_argument("-v", "--verbose", default=False, action="store_true") +args = parser.parse_args() + +outlines = [] +STAT_SEEKING = 1 +STAT_COLLECTING = 2 + +start_collecting_re = re.compile(r"^SWIG_init\(void\)") +end_collecting_re = re.compile(r"^\s*/\* Initialize threading \*/") + +# SWIG_Python_SetConstant(d, "BADADDR",SWIG_From_unsigned_SS_int(static_cast< unsigned int >(ea_t(-1)))); +set_constant_re = re.compile(r"^\s*SWIG_Python_SetConstant\(\s*d\s*,([^,]*),(.*)\);$") + +# Supported types we can simply expression for +# SWIG_From_int(static_cast< int >(0x00C0)) +pyobj_expr_int = re.compile(r"SWIG_From_int\(static_cast<\s*int\s*>\((.*)\)\)") +# SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1u << 16))) +pyobj_expr_uint = re.compile(r"SWIG_From_unsigned_SS_int\(static_cast<\s*unsigned\s+int\s*>\((.*)\)\)") +# SWIG_From_long(static_cast< long >(0x00002000L)) +pyobj_expr_long = re.compile(r"SWIG_From_long\(static_cast<\s*long\s*>\((.*)\)\)") +# SWIG_From_unsigned_SS_long(static_cast< unsigned long >(0xF0000000LU)) +pyobj_expr_ulong = re.compile(r"SWIG_From_unsigned_SS_long\(static_cast<\s*unsigned\s+long\s*>\((.*)\)\)") +# SWIG_FromCharPtr("\22") +pyobj_expr_str = re.compile(r"SWIG_FromCharPtr\((.*)\)") + + +status = STAT_SEEKING +class Foldable(object): + def __init__(self, re, enum, initializer, replacement): + self.re = re + self.enum = enum + self.initializer = initializer + self.replacement = replacement + self.found_any = False + +subexprs = { + "i" : Foldable( + pyobj_expr_int, + "cit_int", + "i", + "SWIG_From_int(static_cast< int >(ci.val.i))"), + "u" : Foldable( + pyobj_expr_uint, + "cit_uint", + "u", + "SWIG_From_unsigned_SS_int(static_cast< unsigned int >(ci.val.u))"), + "l" : Foldable( + pyobj_expr_long, + "cit_long", + "l", + "SWIG_From_long(static_cast< long >(ci.val.l))"), + "ul" : Foldable( + pyobj_expr_ulong, + "cit_ulong", + "ul", + "SWIG_From_unsigned_SS_long(static_cast< unsigned long >(ci.val.ul))"), + "s" : Foldable( + pyobj_expr_str, + "cit_charptr", + "s", + "SWIG_FromCharPtr(ci.val.s)"), +} + +def generate_constants(constants): + # now, generate the array & loop + outlines.append(""" +/* 'SetConstant' replacement */ +union ida_local cival_t +{ + PyObject *o; + int i; + unsigned int u; + long l; + unsigned long ul; + const char *s; +}; + +enum cit_t +{ + cit_int = 1, + cit_uint, + cit_long, + cit_ulong, + cit_charptr, + cit_obj, +}; + +static const ida_local struct ci_t +{ + const char *name; + cival_t val; + cit_t type; +} cis[%d] = { +""" % len(constants)) + + for c in constants: + name = c[0] + expr = c[1] + init = "o" + citype = "cit_obj" + + # Analyze expression. If it is one of the + # supported types, let's simplify the code. + for kind in subexprs.keys(): + subexpr = subexprs[kind] + sematch = subexpr.re.search(expr) + if sematch: + citype = subexpr.enum + expr = sematch.group(1) + init = subexpr.initializer + subexpr.found_any = True + break + outlines.append("\t{%s, {%s: (%s)}, %s},\n" % (name, init, expr, citype)) + + outlines.append(""" +}; + +for ( size_t _cidx = 0; _cidx < qnumber(cis); ++_cidx ) +{ + const ci_t &ci = cis[_cidx]; + PyObject *o = NULL; + switch ( ci.type ) + { +""") + + for kind in subexprs.keys(): + subexpr = subexprs[kind] + if subexpr.found_any: + outlines.append(""" + case %s: + o = %s; + break; + """ % (subexpr.enum, subexpr.replacement)) + + outlines.append(""" + case cit_obj: + o = ci.val.o; + break; + default: INTERR(0); + } + SWIG_Python_SetConstant(d, ci.name, o); +} +""") + +with open(args.file, "rb") as f: + constants = [] + + for line in f: + if status == STAT_SEEKING: + outlines.append(line) + if start_collecting_re.match(line): + status = STAT_COLLECTING + if args.verbose: + print "Starting to collect at line: '%s'" % line + elif status == STAT_COLLECTING: + if end_collecting_re.match(line): + outlines.append(line) + + if len(constants): + generate_constants(constants) + + status = STAT_SEEKING + if args.verbose: + print "Done collecting at line: '%s'" % line + else: + match = set_constant_re.search(line) + if match: + tpl = (match.group(1), match.group(2)) + constants.append(tpl) + if args.verbose: + print "Found 'SetConstant' expression: %s => %s" % tpl + else: + outlines.append(line) + +import tempfile +temp = tempfile.NamedTemporaryFile(delete=False) +temp.write("".join(outlines)) +temp.close() + +import shutil +shutil.move(temp.name, args.file) diff --git a/tools/patch_directors_cc.py b/tools/patch_directors_cc.py new file mode 100644 index 0000000..6af3529 --- /dev/null +++ b/tools/patch_directors_cc.py @@ -0,0 +1,82 @@ + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser(description='Patch calling conventions for some functions, so it builds on windows') +parser.add_argument("-f", "--file", required=True) +parser.add_argument("-v", "--verbose", default=False, action="store_true") +args = parser.parse_args() + +patches = [ + # text_sink_t + "virtual int idaapi print", + + # user_lvar_modifier_t + "virtual bool idaapi modify_lvars", + + # ctree_visitor_t + "virtual int idaapi visit_insn", + "virtual int idaapi visit_expr", + "virtual int idaapi leave_insn", + "virtual int idaapi leave_expr", + + # ctree_parentee_t + "virtual int idaapi visit_insn", + "virtual int idaapi visit_expr", + "virtual int idaapi leave_insn", + "virtual int idaapi leave_expr", + + # cfunc_parentee_t + "virtual int idaapi visit_insn", + "virtual int idaapi visit_expr", + "virtual int idaapi leave_insn", + "virtual int idaapi leave_expr", + + # enum_member_visitor_t + "virtual int idaapi visit_enum_member", + + # struct_field_visitor_t + "virtual int idaapi visit_field", + + # tinfo_visitor_t + "virtual int idaapi visit_type", + + # aloc_visitor_t + "virtual int idaapi visit_location", + + # const_aloc_visitor_t + "virtual int idaapi visit_location", + + # area_visitor2_t + "virtual int idaapi visit_area", + + # highlighter_cbs_t + "virtual void idaapi set_style", + "virtual int32 idaapi prev_block_state", + "virtual int32 idaapi cur_block_state", + "virtual void idaapi set_block_state", +] + + +outlines = [] +with open(args.file, "rb") as f: + lines = f.readlines() + for line in lines: + for patch in patches: + from_text = patch.replace("idaapi ", "") + if line.find(from_text) > -1: + line = line.replace(from_text, patch) + patches.remove(patch) + break + outlines.append(line) + +import tempfile +temp = tempfile.NamedTemporaryFile(delete=False) +temp.writelines(outlines) +temp.close() + +import shutil +shutil.move(temp.name, args.file)