From d99a89369741ce272ba792d6f087d0739a2f8ac7 Mon Sep 17 00:00:00 2001 From: Arnaud Diederen Date: Fri, 13 Oct 2017 15:08:08 +0200 Subject: [PATCH] IDAPython for IDA 7.0: Initial commit, plus bugfixes up to 2017 Oct, 13th. --- CHANGES.txt | 229 -- HOWTO.md | 30 + README.md | 6 +- STATUS.txt | 7 +- Scripts/AsmViewer.py | 4 +- Scripts/CallStackWalk.py | 75 +- Scripts/DbgCmd.py | 8 +- Scripts/DrvsDispatch.py | 45 +- Scripts/ExchainDump.py | 34 +- Scripts/FindInstructions.py | 54 +- Scripts/ImpRef.py | 8 +- Scripts/PteDump.py | 20 +- Scripts/SEHGraph.py | 22 +- Scripts/VaDump.py | 45 +- Scripts/VirusTotal.py | 32 +- Scripts/msdnapihelp.py | 3 +- api_contents.txt | 3493 +++++++++-------- build.py | 6 +- docs/bc695.md | 46 + docs/bc695.sh | 11 + docs/notes.txt | 53 + examples/chooser.py | 50 - examples/colours.py | 12 +- examples/debughook.py | 4 +- examples/ex1.idc | 16 +- examples/ex1_idaapi.py | 10 +- examples/ex1_idautils.py | 8 +- examples/ex_actions.py | 12 +- examples/ex_askusingform.py | 86 +- examples/ex_choose.py | 141 + examples/ex_choose2.py | 128 - examples/ex_choose_multi.py | 40 + examples/ex_custdata.py | 80 +- examples/ex_custview.py | 8 +- examples/ex_dbg.py | 8 +- examples/ex_debug_names.py | 2 +- examples/ex_expr.py | 10 +- examples/ex_func_chooser.py | 51 +- examples/ex_gdl_qflow_chart.py | 16 +- examples/ex_graph.py | 20 +- examples/ex_hexrays.py | 40 + examples/ex_procext.py | 43 + examples/ex_sync_graphs.py | 82 + examples/ex_uihook.py | 8 +- examples/ex_uirequests.py | 2 +- examples/hotkey.py | 6 +- examples/idapythonrc.py | 2 +- examples/structure.py | 38 +- examples/vds3.py | 22 +- examples/vds4.py | 8 +- examples/vds5.py | 308 ++ examples/vds8.py | 94 + examples/vds_create_hint.py | 32 + examples/vds_xrefs.py | 47 +- idapython.vcxproj | 13 +- idapython.vcxproj.filters | 16 +- makefile | 161 +- out_of_tree/parsed_notifications.zip | Bin 574008 -> 579782 bytes pydoc_injections.txt | 99 +- python.cfg | 4 + python.cpp | 516 +-- python/idadex.py | 428 ++ python/idautils.py | 206 +- python/idc.py | 3140 +++++++-------- python/init.py | 29 +- pywraps.cpp | 813 ++-- pywraps.hpp | 240 +- pywraps/driver.cpp | 172 - pywraps/driver_bytes.cpp | 19 - pywraps/driver_chooser.cpp | 109 - pywraps/driver_cli.cpp | 29 - pywraps/driver_custview.cpp | 384 -- pywraps/driver_dbg.cpp | 79 - pywraps/driver_diskio.cpp | 47 - pywraps/driver_expr.cpp | 56 - pywraps/driver_graph.cpp | 44 - pywraps/driver_kernwin.cpp | 78 - pywraps/driver_nalt.cpp | 18 - pywraps/driver_notifywhen.cpp | 36 - pywraps/py_area.hpp | 11 - pywraps/py_auto.py | 14 + pywraps/py_bytes.hpp | 252 +- pywraps/py_bytes.py | 236 +- pywraps/py_bytes_custdata.hpp | 653 ++- pywraps/py_bytes_custdata.py | 239 +- pywraps/py_dbg.hpp | 20 +- pywraps/py_dbg.py | 42 +- pywraps/py_diskio.hpp | 46 + pywraps/py_diskio.py | 9 +- pywraps/py_enum.py | 37 + pywraps/py_expr.hpp | 125 +- pywraps/py_expr.py | 123 +- pywraps/py_fixup.py | 6 + pywraps/py_fpro.hpp | 10 +- pywraps/py_frame.hpp | 36 +- pywraps/py_frame.py | 21 + pywraps/py_funcs.hpp | 44 +- pywraps/py_funcs.py | 25 + pywraps/py_gdl.py | 15 +- pywraps/py_graph.hpp | 180 +- pywraps/py_graph.py | 70 +- pywraps/py_hexrays.hpp | 308 +- pywraps/py_hexrays.py | 67 +- pywraps/py_ida.py | 47 + pywraps/py_idaapi.hpp | 23 +- pywraps/py_idaapi.py | 170 +- pywraps/py_idaapi_loader_input.hpp | 33 +- pywraps/py_idc.hpp | 46 + pywraps/py_idd.hpp | 68 +- pywraps/py_idd.py | 20 +- pywraps/py_idp.hpp | 360 +- pywraps/py_idp.py | 87 +- pywraps/py_idp_idbhooks.hpp | 8 +- pywraps/py_kernwin.hpp | 397 +- pywraps/py_kernwin.py | 422 +- ...skusingform.hpp => py_kernwin_askform.hpp} | 102 +- ..._askusingform.py => py_kernwin_askform.py} | 145 +- pywraps/py_kernwin_choose.hpp | 896 ++++- pywraps/py_kernwin_choose.py | 282 +- pywraps/py_kernwin_choose2.hpp | 912 ----- pywraps/py_kernwin_choose2.py | 237 -- pywraps/py_kernwin_custview.hpp | 172 +- pywraps/py_kernwin_custview.py | 35 +- pywraps/py_kernwin_idaview.hpp | 30 +- pywraps/py_kernwin_idaview.py | 29 +- pywraps/py_kernwin_plgform.hpp | 69 +- pywraps/py_kernwin_plgform.py | 48 +- pywraps/py_kernwin_viewhooks.hpp | 51 + pywraps/py_kernwin_viewhooks.py | 214 + pywraps/py_lines.hpp | 83 +- pywraps/py_lines.py | 6 + pywraps/py_loader.hpp | 2 +- pywraps/py_loader.py | 10 + pywraps/py_moves.hpp | 5 + pywraps/py_nalt.hpp | 201 +- pywraps/py_nalt.py | 228 +- pywraps/py_name.hpp | 16 +- pywraps/py_name.py | 65 +- pywraps/py_netnode.py | 14 + pywraps/py_offset.py | 10 + pywraps/py_pro.hpp | 36 +- pywraps/py_pro.py | 11 +- pywraps/py_problems.py | 32 + pywraps/py_range.hpp | 3 + pywraps/py_range.py | 13 + pywraps/py_registry.hpp | 15 +- pywraps/py_search.py | 4 + pywraps/py_segment.hpp | 24 +- pywraps/py_segment.py | 18 + pywraps/py_segregs.py | 40 + pywraps/py_strlist.py | 4 + pywraps/py_struct.py | 28 + pywraps/py_typeinf.hpp | 249 +- pywraps/py_typeinf.py | 132 +- pywraps/py_ua.hpp | 783 +--- pywraps/py_ua.py | 376 +- pywraps/py_xref.hpp | 12 +- pywraps/pywraps.vcproj | 8 +- pywraps/sidc.py | 30 +- swig/area.i | 56 - swig/auto.i | 5 - swig/bytes.i | 179 +- swig/dbg.i | 2 + swig/diskio.i | 29 +- swig/enum.i | 25 +- swig/expr.i | 80 +- swig/fixup.i | 8 +- swig/frame.i | 5 +- swig/funcs.i | 13 +- swig/gdl.i | 2 +- swig/graph.i | 68 +- swig/hexrays.i | 335 +- swig/ida.i | 36 +- swig/idc.i | 22 + swig/idd.i | 13 +- swig/idp.i | 47 +- swig/ints.i | 2 - swig/kernwin.i | 146 +- swig/lines.i | 26 +- swig/loader.i | 15 +- swig/moves.i | 9 + swig/nalt.i | 70 +- swig/name.i | 19 +- swig/netnode.i | 70 +- swig/pro.i | 29 + swig/problems.i | 5 + swig/queue.i | 13 - swig/range.i | 14 + swig/registry.i | 3 +- swig/segment.i | 18 +- swig/{srarea.i => segregs.i} | 11 +- swig/strlist.i | 54 + swig/struct.i | 3 +- swig/tryblks.i | 14 + swig/typeconv.i | 454 --- swig/typeinf.i | 113 +- swig/ua.i | 160 +- tools/bc695.org | 9 + tools/call_dmpapis.sh | 9 + tools/chkapi.py | 163 +- tools/cmpapi.py | 671 ++++ tools/deploy.py | 62 +- tools/deploy/header.i.in | 181 +- tools/dmpapi.py | 60 + tools/docs/hrdoc.cfg | 147 - tools/docs/hrdoc.py | 13 +- tools/gen_idc_bc695.py | 208 + tools/genhooks/genhooks.py | 11 +- tools/genhooks/recipe_idphooks.py | 118 +- tools/genhooks/recipe_uihooks.py | 7 +- tools/genhooks/recipe_viewhooks.py | 3 + tools/genswigheader.py | 2 +- tools/idapython_implib.def.in | 15 +- tools/patch_codegen.py | 42 +- tools/patch_codegen/hexrays.py | 9 + tools/patch_codegen/kernwin.py | 10 +- tools/patch_codegen/pro.py | 5 - tools/patch_codegen/typeinf.py | 10 + tools/patch_directors_cc.py | 42 +- tools/typemaps-supplement/pymacros.swg | 9 + 220 files changed, 13681 insertions(+), 12649 deletions(-) delete mode 100644 CHANGES.txt create mode 100644 HOWTO.md create mode 100644 docs/bc695.md create mode 100755 docs/bc695.sh create mode 100644 docs/notes.txt delete mode 100644 examples/chooser.py create mode 100644 examples/ex_choose.py delete mode 100644 examples/ex_choose2.py create mode 100644 examples/ex_choose_multi.py create mode 100644 examples/ex_hexrays.py create mode 100644 examples/ex_procext.py create mode 100644 examples/ex_sync_graphs.py create mode 100644 examples/vds5.py create mode 100644 examples/vds8.py create mode 100644 examples/vds_create_hint.py create mode 100644 python/idadex.py delete mode 100644 pywraps/driver.cpp delete mode 100644 pywraps/driver_bytes.cpp delete mode 100644 pywraps/driver_chooser.cpp delete mode 100644 pywraps/driver_cli.cpp delete mode 100644 pywraps/driver_custview.cpp delete mode 100644 pywraps/driver_dbg.cpp delete mode 100644 pywraps/driver_diskio.cpp delete mode 100644 pywraps/driver_expr.cpp delete mode 100644 pywraps/driver_graph.cpp delete mode 100644 pywraps/driver_kernwin.cpp delete mode 100644 pywraps/driver_nalt.cpp delete mode 100644 pywraps/driver_notifywhen.cpp delete mode 100644 pywraps/py_area.hpp create mode 100644 pywraps/py_auto.py create mode 100644 pywraps/py_enum.py create mode 100644 pywraps/py_fixup.py create mode 100644 pywraps/py_frame.py create mode 100644 pywraps/py_funcs.py create mode 100644 pywraps/py_ida.py create mode 100644 pywraps/py_idc.hpp rename pywraps/{py_kernwin_askusingform.hpp => py_kernwin_askform.hpp} (81%) rename pywraps/{py_kernwin_askusingform.py => py_kernwin_askform.py} (92%) mode change 100755 => 100644 delete mode 100644 pywraps/py_kernwin_choose2.hpp delete mode 100644 pywraps/py_kernwin_choose2.py create mode 100644 pywraps/py_kernwin_viewhooks.hpp create mode 100644 pywraps/py_kernwin_viewhooks.py create mode 100644 pywraps/py_loader.py create mode 100644 pywraps/py_moves.hpp create mode 100644 pywraps/py_netnode.py create mode 100644 pywraps/py_offset.py create mode 100644 pywraps/py_problems.py create mode 100644 pywraps/py_range.hpp create mode 100644 pywraps/py_range.py create mode 100644 pywraps/py_search.py create mode 100644 pywraps/py_segment.py create mode 100644 pywraps/py_segregs.py create mode 100644 pywraps/py_strlist.py create mode 100644 pywraps/py_struct.py delete mode 100644 swig/area.i create mode 100644 swig/idc.i delete mode 100644 swig/ints.i create mode 100644 swig/problems.i delete mode 100644 swig/queue.i create mode 100644 swig/range.i rename swig/{srarea.i => segregs.i} (56%) create mode 100644 swig/tryblks.i delete mode 100644 swig/typeconv.i create mode 100644 tools/bc695.org create mode 100755 tools/call_dmpapis.sh create mode 100644 tools/cmpapi.py create mode 100644 tools/dmpapi.py delete mode 100644 tools/docs/hrdoc.cfg create mode 100644 tools/gen_idc_bc695.py create mode 100644 tools/genhooks/recipe_viewhooks.py delete mode 100644 tools/patch_codegen/pro.py create mode 100644 tools/patch_codegen/typeinf.py create mode 100644 tools/typemaps-supplement/pymacros.swg diff --git a/CHANGES.txt b/CHANGES.txt deleted file mode 100644 index 90e355b..0000000 --- a/CHANGES.txt +++ /dev/null @@ -1,229 +0,0 @@ -Please see http://code.google.com/p/idapython/source/list for a detailed list of changes. - -Changes from version 1.5.6 to 1.5.7 ------------------------------------- -- Added '--with-hexrays' switch to the build script so it wrap Hex-Rays Decompiler API -- Experimental: integrated Hex-Rays Decompiler bindings that were contributed by EiNSTeiN: - https://github.com/EiNSTeiN-/hexrays-python -- Added one Hex-Rays decompiler sample: vds1.py -- Fixed small mismatch between SWIG define and CL defines (/DNO_OBSOLETE_FUNCS) -- Use print_type2() instead of the deprecated function print_type() - -Changes from version 1.5.5 to 1.5.6 ------------------------------------- -- IDA Pro 6.4 support - -Changes from version 1.5.4 to 1.5.5 ------------------------------------- -- IDA Pro 6.3 support -- The Functions() generator function now accepts function tail start parameter -- Added into idc.py: DbgRead/DbgWrite/SetTargetAssembler and stack pointer related functions -- Wrapped more type info related functions - -Changes from version 1.5.3 to 1.5.4 ------------------------------------- -- fix for Python autorun script vulnerability reported by Greg MacManus -- remove current directory from sys.path during initialization -- added PyWraps sources. This will facilitate deployment, development and - debugging of IDAPython additions -- bugfix: op_t.is_reg() was buggy -- bugfix: build.py was putting duplicate files into the .zip -- bugfix: added back wrapped version of get_ascii_contents() - -Changes from version 1.5.2 to 1.5.3 ------------------------------------- -- IDA Pro 6.2 support -- added set_idc_func_ex(): it is now possible to add new IDC functions using Python -- added visit_patched_bytes() (see ex_patch.py) -- added support for the multiline text input control in the Form class -- added support for the editable/readonly dropdown list control in the Form class -- added execute_sync() to register a function call into the UI message queue -- added execute_ui_requests() / check ex_uirequests.py -- added add_hotkey() / del_hotkey() to bind Python methods to hotkeys -- added register_timer()/unregister_timer(). Check ex_timer.py -- added the IDC (Arrays) netnode manipulation layer into idc.py -- added idautils.Structs() and StructMembers() generator functions -- removed the "Run Python Statement" menu item. IDA now has a unified dialog. - Use RunPlugin("python", 0) to invoke it manually. -- better error messages for script plugins, loaders and processor modules -- bugfix: Dbg_Hooks.dbg_run_to() was receiving wrong input -- bugfix: A few Enum related functions were not properly working in idc.py -- bugfix: GetIdaDirectory() and GetProcessName() were broken in idc.py -- bugfix: idaapi.get_item_head() / idc.ItemHead() were not working - -Changes from version 1.5.1 to 1.5.2 ------------------------------------- -- added ui_term/ui_save/ui_saved/ui_get_ea_hint UI notifications -- added ph_get_operand_info() to retrieve operand information while debugging -- added PteDump.py script -- bugfix: read/write_dbg_memory() and dbg_get_thread_sreg_base() were not working with all debugger modules -- bugfix: idaapi.netnode.getblob() was limited to MAXSPECSIZE -- bugfix: idc.GetString()/idaapi.get_ascii_contents()/idautils.Strings() were limited to MAXSTR string length -- bugfix: idaapi.del_menu_item() was failing to delete some menu items -- bugfix: dbg_bpt was called instead of dbg_trace for a DBG_Hooks class implementation (old bug from 0.9.x) -- bugfix: Form.GetControlValue() was not working with numeric controls -- bugfix: SetBptCnd() was broken -- bugfix: idaapi.get_func_cmt() was memory leaking - -Changes from version 1.5.0 to 1.5.1 ------------------------------------- -- Introduced the CLI '?' pseudo-command to retrieve doc strings -- Introduced the CLI '!' pseudo-command to shell execute a command -- bugfix: High 64 bit addresses were not parsed correctly in IDA64 -- Added IDP/assemble notification event -- bugfix: AskUsingForm() C function was not wrapped by SWIG -- NextHead()/PrevHead() have optional 2nd parameter now - -Changes from version 1.4.3 to 1.5.0 ------------------------------------- -- IDA Pro 6.1 support -- Added AskUsingForm() with embedded forms support (check ex_askusingform.py example and formchooser.py in the SDK) -- Added idautils.DecodePreviousInstruction() / DecodePrecedingInstruction() -- Added idc.BeginTypeUpdating() / EndTypeUpdating() for fast batch type update operations -- Added more IDP callbacks -- Added UI_Hooks with a few notification events -- Added idaapi.process_ui_action() / idc.ProcessUiAction() -- Added netnode.index() to get netnode number -- Better handling of ea_t values with bitwise negation -- Execute statement hotkey (Ctrl-F3), script timeout, and other options are now configurable with Python.cfg -- bugfix: idaapi.msg() / error() and warning() so they don't accept vararg -- bugfix: processor_t.id constants were incorrect -- bugfix: get_debug_names() was broken with IDA64 -- Various bugfixes -- Added Scripts folder containing various IDAPython scripts - -Changes from version 1.4.2 to 1.4.3 ------------------------------------- -- IDA Pro 6.0 support -- Python CLI now prints expression evaluation result (no need to use print()) -- Changed Alt-8 to Ctrl-F3 (because it conflicts with window switching key Alt+n) -- Added get_highlighted_identifier() -- Added PluginForm class to allow UI development with either PyQt4 or PySide -- Added idautils.Entries() to enum entrypoints - - -Changes from version 1.4.1 to 1.4.2 ------------------------------------- -- Added command completion -- Added necessary changes so it compiles with Python 2.7 -- Wrapped set_user_defined_prefix() - - -Changes from version 1.4.0 to 1.4.1 ------------------------------------- -- Added cli_t -- Added idaapi.ph to access current process fields -- Changed the copyright string to IDAPython Team -- Some platform dependant classes are present but useable only where applicable - - -Changes from version 1.3.0 to 1.4.0 ------------------------------------- -- IDA Pro 5.7 support -- idaapi.cvar.cmd is now accessible via idapi.cmd instead -- Python statement (Alt-8) is now 16kb long -- Dropped script box and File/Python file. IDA has this functionality now. -- Refactored the code -- It is possible to turn off script timeout -- All scripts are executed via 'IDAPython_ExecScript' (check idaapi.i) -- Added '--doc' switch to "build.py" script -- Documented all manually wrapped functions (check 'pywraps' module in the docs) -- Lots of cleanups and fixes - - -Changes from version 1.2.0 to 1.3.0 ------------------------------------- -- IDA Pro 5.6 support -- Added Appcall mechanism -- Added procregs to idautils.py (r254) -- Lots of cleanups and fixes - -Changes from version 1.1.0 to 1.2.0 ------------------------------------- -- 64-bit support (largely untested) -- IDA Pro 5.5 support -- Long running (or inifinitely looping) scripts can now be stopped -- Host of IDC updates and fixes -- netnode.hpp is now mostly wrapped -- idautils use generators instead of lists -- Functions() and GetFchunkAttr() now work properly -- Lots of cleanups and fixes - - -Changes from version 0.9.0 to 1.0.0 ------------------------------------ -- Upgraded IDA Pro base version to 5.1 -- Dropped Python 2.4 support -- Mac OS X support -- IDC compatibility layer is now complete and up to date for IDA 5.1 -- INCOMPATIBLE CHANGE: the idaapi module needs to be imported manually -- Support for IDB and debug notification hooks -- Support for GUI hotkeys (see examples/hotkey.py) -- Simple two-way calling mechanism between IDC and IDAPython -- Significantly better IDA API coverage -- Support for IDB and debug event hooks -- get_current_instruction() deprecated, use the idaapi.cvar.cmd variable -- Tons of IDC fixes -- Tons of other misc fixes - - -Changes from version 0.8.0 to 0.9.0 ------------------------------------ -- Upgraded base version to IDA Pro 5.0 -- Works with IDA Pro 5.1 -- Python 2.4 and 2.5 supported -- Close to complete IDC compatbility layer (in sync with 4.9) -- Significatnly improved IDA SDK API covergage (see STATUS.txt for details) -- IDA SDK patch size reduced to less than half -- Simplified installation (plugins.cfg modification not needed) -- Evaluation window content is saved over IDA restarts (in the database) -- Windows version is built with Microsoft Visual C++ Express Edition -- Build makefile replaced with a Python script -- Cleanups and small fixes - - -Changes from version 0.7.0 to 0.8.0 ------------------------------------ -- Added support for IDA Pro 4.9 -- Dropped support for IDA Pro 4.7 -- NOTE: Windows version is linked against Python 2.4. -- New wrappers: search.hpp, dbg.hpp, loader.hpp, diskio.hpp, nalt.hpp -- idc.py synced up to IDA 4.8 -- Added 38 IDC functions -- Fixed asklong(), askseg() and askaddr() -- Automatically generated cross reference documentation (epydoc) -- User-specific init file support (see README,txt) -- Deprecated some functions that have direct Python equivalents (see idc.py) -- Fixed exception in ScriptBox when invoked empty. -- Lots of cleanups and small fixes - - -Changes from version 0.6.0 to 0.7.0 ------------------------------------ -- Batch execution support (use the option -OIDAPython:yourscript.py) -- Added ScriptBox - lists previously run scripts (Hotkey:Alt-7) -- Added support for IDA Pro 4.8 (both Linux and Windows) -- Dropped support for IDA Pro 4.6 and 4.6SP1 versions -- Wrapped the list chooser (see examples/choose.py) -- A dozen or so IDC functions added -- Lots of char * API calls wrapped -- Added Python error handling in the plugin C layer -- Bunch of misc small cleanups and fixes -- For more details see CHANGES-SWIG.txt and CHANGES-Plugin.txt - -- API CHANGE: {Next|Prev}Function() return BADADDR instead of -1 - - -Changes from version 0.5.0 to 0.6.0 ------------------------------------ -- Added support for IDA Pro 4.7 (both Linux and Windows) -- Dropped support for IDA Pro 4.6SP1 beta on Linux -- Lots of IDC wrapper additions and fixes: - - Added 30+ new wrappers to idc.py - - Most Find*, Ask* and Seg* are now wrapped - - Fixed broken NextAddr(), PrevAddr(), MakeFunction() and MakeName() -- Fixes to the makefile -- Cleanups for the idaapi wrapper -- Bunch of misc small cleanups and fixes -- For more details see CHANGES-SWIG.txt and CHANGES-Plugin.txt - diff --git a/HOWTO.md b/HOWTO.md new file mode 100644 index 0000000..d89e1f8 --- /dev/null +++ b/HOWTO.md @@ -0,0 +1,30 @@ +# HOW-TO + +### How to add new module? + +We use the "zzz" placeholder for a module name in this "how-to". + +1. create file swig/zzz.i +``` +%{ +#include +%} +%include "zzz.hpp" +``` + +2. add zzz to the `MODULES_NAMES` var in makefile + +3. add a line to python/idc.py if you want to autoload this module +``` +import ida_zzz +``` + +4. build + +5. update the content of api_contents.txt + (from obj/.../api_contents.txt.new) + +6. rebuild + +7. update the content of pydoc_injections.txt + (from obj/.../pydoc_injections.txt) diff --git a/README.md b/README.md index abc1566..727e943 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ of Python code from IDC * Invoking IDC from Python -It is possible to use the idc.Eval() to evaluate IDC expressions from Python +It is possible to use the idc.eval() to evaluate IDC expressions from Python * Making Python the default language @@ -99,8 +99,8 @@ Python instead of IDC. In order to do that, please use the following IDC code: -RunPlugin("python", 3) +load_and_run_plugin("python", 3) To disable Python language and revert back to IDC: -RunPlugin("python", 4) +load_and_run_plugin("python", 4) diff --git a/STATUS.txt b/STATUS.txt index 2fbb834..aa4a35d 100644 --- a/STATUS.txt +++ b/STATUS.txt @@ -1,7 +1,7 @@ Status of the IDC layer ----------------------- -The IDC emulation layer is complete and at par with IDA 5.1, +The IDC emulation layer is complete and at par with IDA 5.1, although it would benefit from more testing. @@ -13,7 +13,7 @@ INCOMPLETE: some wrapping or SWIG ifdefs still left EXCLUDED: will not be wrapped allins.hpp - COMPLETE -area.hpp - COMPLETE (necessary SWIGdefs) +range.hpp - COMPLETE (necessary SWIGdefs) auto.hpp - COMPLETE bytes.hpp - COMPLETE (some minor unwrapped) compress.hpp - EXCLUDED @@ -37,7 +37,6 @@ idd.hpp - COMPLETE (necessary SWIGs) idp.hpp - COMPLETE ieee.h - EXCLUDED intel.hpp - EXCLUDED -ints.hpp - COMPLETE kernwin.hpp - INCOMPLETE (SWIGs and lot of fixing to do) lex.hpp - EXCLUDED lines.hpp - INCOMPLETE (few FIXMEs) @@ -56,7 +55,7 @@ regex.h - EXCLUDED search.hpp - COMPLETE segment.hpp - COMPLETE sistack.hpp - EXCLUDED -srarea.hpp - INCOMPLETE (not wrapped at all) +segregs.hpp - INCOMPLETE (not wrapped at all) strlist.hpp - COMPLETE struct.hpp - COMPLETE typeinf.hpp - INCOMPLETE (no SWIGs, lot of fixing to do) diff --git a/Scripts/AsmViewer.py b/Scripts/AsmViewer.py index bcec428..7b78cfe 100644 --- a/Scripts/AsmViewer.py +++ b/Scripts/AsmViewer.py @@ -200,7 +200,7 @@ class asmviewplg(idaapi.plugin_t): def run(self, arg): if self.view: self.Close() - fn = idc.AskFile(0, "*.asm", "Select ASM file to view") + fn = idaapi.ask_file(0, "*.asm", "Select ASM file to view") if not fn: return self.view = asmview_t() @@ -213,4 +213,4 @@ class asmviewplg(idaapi.plugin_t): self.view.Close() def PLUGIN_ENTRY(): - return asmviewplg() \ No newline at end of file + return asmviewplg() diff --git a/Scripts/CallStackWalk.py b/Scripts/CallStackWalk.py index f1fef78..cb63383 100644 --- a/Scripts/CallStackWalk.py +++ b/Scripts/CallStackWalk.py @@ -14,17 +14,18 @@ v1.0.1 - added stack segment bitness detection, thus works with 64bit processes import idaapi import idc import idautils +from ida_kernwin import Choose # ----------------------------------------------------------------------- # class to take a copy of a segment_t class Seg(): def __init__(self, s): - self.startEA = s.startEA - self.endEA = s.endEA - self.perm = s.perm - self.bitness = s.bitness + self.start_ea = s.start_ea + self.end_ea = s.end_ea + self.perm = s.perm + self.bitness = s.bitness def __cmp__(self, other): - return cmp(self.startEA, other.startEA) + return cmp(self.start_ea, other.start_ea) # ----------------------------------------------------------------------- # each item described as: @@ -59,8 +60,10 @@ def IsPrevInsnCall(ea): # get the bytes bytes = [x for x in GetDataList(caller, len(opcodes), 1)] # do we have a match? is it a call instruction? - if bytes == opcodes and idaapi.is_call_insn(caller): - return caller + if bytes == opcodes: + tmp = idaapi.insn_t() + if idaapi.decode_insn(tmp, caller) and idaapi.is_call_insn(tmp): + return caller return None # ----------------------------------------------------------------------- @@ -77,18 +80,15 @@ def CallStackWalk(nn): self.caller = caller self.sp = sp f = idaapi.get_func(caller) - self.displ = "%08x: " % caller + self.displ = "" if f: - self.displ += idc.GetFunctionName(caller) - t = caller - f.startEA + self.displ += idc.get_func_name(caller) + t = caller - f.start_ea if t > 0: self.displ += "+" + hex(t) else: self.displ += hex(caller) self.displ += " [" + hex(sp) + "]" - def __str__(self): - return self.displ - # get stack pointer sp = cpu.Esp seg = idaapi.getseg(sp) @@ -99,7 +99,7 @@ def CallStackWalk(nn): word_size = 2 ** (seg.bitness + 1) callers = [] sp = cpu.Esp - word_size - while sp < stack_seg.endEA: + while sp < stack_seg.end_ea: sp += word_size ptr = idautils.GetDataList(sp, 1, word_size).next() seg = idaapi.getseg(ptr) @@ -121,13 +121,13 @@ def CallStackWalk(nn): f = idaapi.get_func(ea) if not f: # create function - idc.MakeFunction(ea, idaapi.BADADDR) + idc.add_func(ea, idaapi.BADADDR) # get the flags - f = idc.GetFlags(caller) + f = idc.get_flags(caller) # no code there? - if not isCode(f): - MakeCode(caller) + if not is_code(f): + create_insn(caller) callers.append(Result(caller, sp)) # @@ -136,27 +136,38 @@ def CallStackWalk(nn): # ----------------------------------------------------------------------- # Chooser class class CallStackWalkChoose(Choose): - def __init__(self, list, title): - Choose.__init__(self, list, title) - self.width = 250 + def __init__(self, title, items): + Choose.__init__(self, title, [ ["Caller", 16], ["Display", 250] ]) + self.items = items - def enter(self, n): - o = self.list[n-1] - idc.Jump(o.caller) + def OnGetLine(self, n): + o = self.items[n] + line = [] + line.append("%X" % o.caller) + line.append("%s" % o.displ) + return line + + def OnGetSize(self): + return len(self.items) + + def OnSelectLine(self, n): + o = self.items[n] + jumpto(o.caller) + return (Choose.NOTHING_CHANGED, ) # ----------------------------------------------------------------------- def main(): if not idaapi.is_debugger_on(): - idc.Warning("Please run the process first!") + idc.warning("Please run the process first!") return if idaapi.get_process_state() != -1: - idc.Warning("Please suspend the debugger first!") + idc.warning("Please suspend the debugger first!") return # only avail from IdaPython r232 if hasattr(idaapi, "NearestName"): # get all debug names - dn = idaapi.get_debug_names(idaapi.cvar.inf.minEA, idaapi.cvar.inf.maxEA) + dn = idaapi.get_debug_names(idaapi.cvar.inf.min_ea, idaapi.cvar.inf.max_ea) # initiate a nearest name search (using debug names) nn = idaapi.NearestName(dn) else: @@ -164,12 +175,12 @@ def main(): ret, callstack = CallStackWalk(nn) if ret: - title = "Call stack walker (thread %X)" % (GetCurrentThreadId()) + title = "Call stack walker (thread %X)" % (get_current_thread()) idaapi.close_chooser(title) - c = CallStackWalkChoose(callstack, title) - c.choose() + c = CallStackWalkChoose(title, callstack) + c.Show() else: - idc.Warning("Failed to walk the stack:" + callstack) + idc.warning("Failed to walk the stack:" + callstack) # ----------------------------------------------------------------------- -main() \ No newline at end of file +main() diff --git a/Scripts/DbgCmd.py b/Scripts/DbgCmd.py index a15544b..d19e564 100644 --- a/Scripts/DbgCmd.py +++ b/Scripts/DbgCmd.py @@ -9,9 +9,9 @@ from idaapi import simplecustviewer_t def SendDbgCommand(cmd): """Sends a command to the debugger and returns the output string. An exception will be raised if the debugger is not running or the current debugger does not export - the 'SendDbgCommand' IDC command. + the 'send_dbg_command' IDC command. """ - s = Eval('SendDbgCommand("%s");' % cmd) + s = idc.eval('send_dbg_command("%s");' % cmd) if s.startswith("IDC_FAILURE"): raise Exception, "Debugger command is available only when the debugger is active!" return s @@ -32,7 +32,7 @@ class dbgcmd_t(simplecustviewer_t): return True def IssueCommand(self): - s = idaapi.askstr(0, self.last_cmd, "Please enter a debugger command") + s = idaapi.ask_str(self.last_cmd, 0, "Please enter a debugger command") if not s: return @@ -47,7 +47,7 @@ class dbgcmd_t(simplecustviewer_t): for s in r: self.AddLine(idaapi.COLSTR(s, idaapi.SCOLOR_LIBNAME)) except: - self.AddLine(idaapi.COLSTR("Debugger is not active or does not export SendDbgCommand()", idaapi.SCOLOR_ERROR)) + self.AddLine(idaapi.COLSTR("Debugger is not active or does not export send_dbg_command()", idaapi.SCOLOR_ERROR)) self.Refresh() def ResetOutput(self): diff --git a/Scripts/DrvsDispatch.py b/Scripts/DrvsDispatch.py index db984d3..ae7c298 100644 --- a/Scripts/DrvsDispatch.py +++ b/Scripts/DrvsDispatch.py @@ -8,21 +8,22 @@ ALL RIGHTS RESERVED. """ import re -from idaapi import Choose +import idc +from ida_kernwin import Choose # ----------------------------------------------------------------------- def CmdDriverList(): - s = Eval('WinDbgCommand("lm o");') + s = idc.eval('send_dbg_command("lm o");') if "IDC_FAILURE" in s: return False return s # ----------------------------------------------------------------------- def CmdDrvObj(drvname, flag=2): - return Eval('WinDbgCommand("!drvobj %s %d");' % (drvname, flag)) + return idc.eval('send_dbg_command("!drvobj %s %d");' % (drvname, flag)) # ----------------------------------------------------------------------- def CmdReloadForce(): - s = Eval('WinDbgCommand(".reload /f");') + s = idc.eval('send_dbg_command(".reload /f");') if "IDC_FAILURE" in s: return False return True @@ -32,12 +33,9 @@ class DispatchEntry: def __init__(self, addr, name): self.addr = addr self.name = name - def __repr__(self): - return "%08X: %s" % (self.addr, self.name) # ----------------------------------------------------------------------- def GetDriverDispatch(): - # return a list of arrays of the form: [addr, name] ret_list = [] @@ -54,7 +52,7 @@ def GetDriverDispatch(): # get driver list lm_out = CmdDriverList() - if not lm_out: + if not lm_out: return "Failed to get driver list!" # for each line @@ -69,7 +67,7 @@ def GetDriverDispatch(): # execute "drvobj" command tbl_out = CmdDrvObj(drvname) - if not tbl_out: + if not tbl_out: print "Failed to get driver object for", drvname continue @@ -87,19 +85,30 @@ def GetDriverDispatch(): # ----------------------------------------------------------------------- # Chooser class class DispatchChoose(Choose): - def __init__(self, list, title): - Choose.__init__(self, list, title) - self.width = 250 + def __init__(self, title, items): + Choose.__init__(self, title, [ ["Address", 16], ["Name", 250] ]) + self.items = items - def enter(self, n): - o = self.list[n-1] - idc.Jump(o.addr) + def OnGetLine(self, n): + o = self.items[n] + line = [] + line.append("%08X" % o.addr) + line.append("%s" % o.name) + return line + + def OnGetSize(self): + return len(self.items) + + def OnSelectLine(self, n): + o = self.items[n] + Jump(o.addr) + return (Choose.NOTHING_CHANGED, ) # ----------------------------------------------------------------------- # main r = GetDriverDispatch() if r: - c = DispatchChoose(r, "Dispatch table browser") - c.choose() + c = DispatchChoose("Dispatch table browser", r) + c.Show() else: - print "Failed to retrieve dispatchers list!" \ No newline at end of file + print "Failed to retrieve dispatchers list!" diff --git a/Scripts/ExchainDump.py b/Scripts/ExchainDump.py index f8d93b9..75c729d 100644 --- a/Scripts/ExchainDump.py +++ b/Scripts/ExchainDump.py @@ -9,6 +9,8 @@ ALL RIGHTS RESERVED. import idc import re +import ida_kernwin +from ida_kernwin import Choose # class to store parsed results class exchain: @@ -16,22 +18,30 @@ class exchain: self.name = m.group(1) self.addr = int(m.group(2), 16) - def __str__(self): - return "%x: %s" % (self.addr, self.name) - # Chooser class class MyChoose(Choose): - def __init__(self, list, title): - Choose.__init__(self, list, title) - self.width = 250 + def __init__(self, title, items): + Choose.__init__(self, title, [ ["Address", 16], ["Name", 250] ]) + self.items = items - def enter(self, n): - o = self.list[n-1] - idc.Jump(o.addr) + def OnGetLine(self, n): + o = self.items[n] + line = [] + line.append("%08X" % o.addr) + line.append("%s" % o.name) + return line + + def OnGetSize(self): + return len(self.items) + + def OnSelectLine(self, n): + o = self.items[n] + Jump(o.addr) + return (Choose.NOTHING_CHANGED, ) # main def main(): - s = idc.Eval('SendDbgCommand("!exchain")') + s = idc.eval('send_dbg_command("!exchain")') if "IDC_FAILURE" in s: return (False, "Cannot execute the command") @@ -43,9 +53,9 @@ def main(): return (False, "Nothing to display: Could parse the result!") # Get a Choose instance - chooser = MyChoose(L, "Exchain choose") + chooser = MyChoose("Exchain choose", L) # Run the chooser - chooser.choose() + chooser.Show() return (True, "Success!") ok, r = main() if not ok: diff --git a/Scripts/FindInstructions.py b/Scripts/FindInstructions.py index 5bfaac5..d85d67c 100644 --- a/Scripts/FindInstructions.py +++ b/Scripts/FindInstructions.py @@ -21,6 +21,7 @@ v1.0 - initial version import idaapi import idautils import idc +from ida_kernwin import Choose # ----------------------------------------------------------------------- def FindInstructions(instr, asm_where=None): @@ -30,7 +31,7 @@ def FindInstructions(instr, asm_where=None): """ if not asm_where: # get first segment - asm_where = FirstSeg() + asm_where = get_first_seg() if asm_where == idaapi.BADADDR: return (False, "No segments defined") @@ -56,7 +57,7 @@ def FindInstructions(instr, asm_where=None): # join the buffer into one string buf = ''.join(bufs) - + # take total assembled instructions length tlen = len(buf) @@ -65,55 +66,64 @@ def FindInstructions(instr, asm_where=None): # find all binary strings print "Searching for: [%s]" % bin_str - ea = MinEA() + ea = get_inf_attr(INF_MIN_EA) ret = [] while True: - ea = FindBinary(ea, SEARCH_DOWN, bin_str) + ea = find_binary(ea, SEARCH_DOWN, bin_str) if ea == idaapi.BADADDR: break ret.append(ea) - Message(".") + msg(".") ea += tlen if not ret: return (False, "Could not match [%s]" % bin_str) - Message("\n") + msg("\n") return (True, ret) # ----------------------------------------------------------------------- # Chooser class class SearchResultChoose(Choose): - def __init__(self, list, title): - Choose.__init__(self, list, title) - self.width = 250 + def __init__(self, title, items): + Choose.__init__(self, title, [ ["Address", 16], ["Results", 250] ]) + self.items = items - def enter(self, n): - o = self.list[n-1] + def OnGetLine(self, n): + o = self.items[n] + line = [] + line.append("%08X" % o.ea) + line.append("%s" % o.display) + return line + + def OnGetSize(self): + return len(self.items) + + def OnSelectLine(self, n): + o = self.items[n] Jump(o.ea) + return (Choose.NOTHING_CHANGED, ) # ----------------------------------------------------------------------- # class to represent the results class SearchResult: def __init__(self, ea): self.ea = ea - if not isCode(GetFlags(ea)): - MakeCode(ea) + if not is_code(get_flags(ea)): + create_insn(ea) t = idaapi.generate_disasm_line(ea) if t: line = idaapi.tag_remove(t) else: line = "" - func = GetFunctionName(ea) - self.display = hex(ea) + ": " + func = get_func_name(ea) + self.display = "" if func: self.display += func + ": " else: - n = SegName(ea) - if n: self.display += n + ": " + n = get_segm_name(ea) + if n: + self.display += n + ": " self.display += line - def __str__(self): - return self.display - # ----------------------------------------------------------------------- def find(s=None, x=False, asm_where=None): b, ret = FindInstructions(s, asm_where) @@ -130,8 +140,8 @@ def find(s=None, x=False, asm_where=None): results = [SearchResult(ea) for ea in ret] title = "Search result for: [%s]" % s idaapi.close_chooser(title) - c = SearchResultChoose(results, title) - c.choose() + c = SearchResultChoose(title, results) + c.Show() else: print ret diff --git a/Scripts/ImpRef.py b/Scripts/ImpRef.py index 5dc8542..9d9471c 100644 --- a/Scripts/ImpRef.py +++ b/Scripts/ImpRef.py @@ -40,8 +40,8 @@ def find_import_ref(dllname): ea = xref.frm f = idaapi.get_func(ea) if f and (f.flags & idaapi.FUNC_THUNK) != 0: - imports.append([f.startEA, idaapi.get_func_name(f.startEA), 0]) - #print "\t%x %s: from a thunk, parent added %x" % (ea, name, f.startEA) + imports.append([f.start_ea, idaapi.get_func_name(f.start_ea), 0]) + #print "\t%x %s: from a thunk, parent added %x" % (ea, name, f.start_ea) continue # save results @@ -54,7 +54,7 @@ def find_import_ref(dllname): # ----------------------------------------------------------------------- def main(): - dllname = idc.AskStr('kernel32', "Enter module name") + dllname = idaapi.ask_str('kernel32', 0, "Enter module name") if not dllname: print("Cancelled") return @@ -66,4 +66,4 @@ def main(): print("\t%x" % ea) # ----------------------------------------------------------------------- -main() \ No newline at end of file +main() diff --git a/Scripts/PteDump.py b/Scripts/PteDump.py index 1bd20f3..705e7c0 100644 --- a/Scripts/PteDump.py +++ b/Scripts/PteDump.py @@ -1,6 +1,6 @@ import idaapi import idc -from idaapi import Choose2 +from ida_kernwin import Choose def parse_pte(str): try: @@ -15,17 +15,15 @@ def parse_pte(str): r[parse_pte.items[i]] = m.group(i+1) return r -class MyChoose2(Choose2): +class MyChoose(Choose): def __init__(self, title, ea1, ea2): - Choose2.__init__(self, title, [ ["VA", 10], ["PTE attr", 30] ]) + Choose.__init__(self, title, [ ["VA", 10], ["PTE attr", 30] ]) self.ea1 = ea1 self.ea2 = ea2 - self.n = 0 self.icon = 5 self.items = [] self.Refresh() - self.selcount = 0 def OnGetLine(self, n): print("getline %d" % n) @@ -38,7 +36,7 @@ class MyChoose2(Choose2): def OnRefresh(self, n): print("refresh %d" % n) - return n + return None # call standard refresh def Refresh(self): items = [] @@ -46,7 +44,7 @@ class MyChoose2(Choose2): ea1 = self.ea1 npages = (self.ea2 - ea1) / PG for i in range(npages): - r = idc.SendDbgCommand("!pte %x" % ea1) + r = idc.send_dbg_command("!pte %x" % ea1) if not r: return False r = parse_pte(r) @@ -59,7 +57,7 @@ class MyChoose2(Choose2): @staticmethod def Execute(ea1, ea2): - c = MyChoose2("PTE Viewer [%x..%x]" % (ea1, ea2), ea1, ea2) + c = MyChoose("PTE Viewer [%x..%x]" % (ea1, ea2), ea1, ea2) return (c, c.Show()) @@ -68,7 +66,7 @@ def DumpPTE(ea1, ea2): PG = 0x1000 npages = (ea2 - ea1) / PG for i in range(npages): - r = idc.SendDbgCommand("!pte %x" % ea1) + r = idc.send_dbg_command("!pte %x" % ea1) if not r: return False print r @@ -77,9 +75,9 @@ def DumpPTE(ea1, ea2): ea1 += PG def DumpSegPTE(ea): - DumpPTE(idc.SegStart(ea), idc.SegEnd(ea)) + DumpPTE(idc.get_segm_start(ea), idc.get_segm_end(ea)) DumpSegPTE(here()) -#MyChoose2.Execute(0xF718F000, 0xF718F000+0x1000) +#MyChoose.Execute(0xF718F000, 0xF718F000+0x1000) diff --git a/Scripts/SEHGraph.py b/Scripts/SEHGraph.py index 88ab71d..6ad3a0c 100644 --- a/Scripts/SEHGraph.py +++ b/Scripts/SEHGraph.py @@ -22,7 +22,7 @@ from idaapi import GraphViewer # Since Windbg debug module does not support get_thread_sreg_base() # we will call the debugger engine "dg" command and parse its output def WindbgGetRegBase(tid): - s = idc.Eval('WinDbgCommand("dg %x")' % cpu.fs) + s = idc.eval('send_dbg_command("dg %x")' % cpu.fs) if "IDC_FAILURE" in s: return 0 m = re.compile("[0-9a-f]{4} ([0-9a-f]{8})") @@ -33,7 +33,7 @@ def WindbgGetRegBase(tid): # ----------------------------------------------------------------------- def GetFsBase(tid): - idc.SelectThread(tid) + idc.select_thread(tid) base = idaapi.dbg_get_thread_sreg_base(tid, cpu.fs) if base != 0: return base @@ -43,11 +43,11 @@ def GetFsBase(tid): # Walks the SEH chain and returns a list of handlers def GetExceptionChain(tid): fs_base = GetFsBase(tid) - exc_rr = Dword(fs_base) + exc_rr = get_wide_dword(fs_base) result = [] while exc_rr != 0xffffffff: - prev = Dword(exc_rr) - handler = Dword(exc_rr + 4) + prev = get_wide_dword(exc_rr) + handler = get_wide_dword(exc_rr + 4) exc_rr = prev result.append(handler) return result @@ -77,10 +77,10 @@ class SEHGraph(GraphViewer): f = idaapi.get_func(handler) if not f: # create function - idc.MakeFunction(handler, idaapi.BADADDR) + idc.add_func(handler, idaapi.BADADDR) # Node label is function name or address - s = GetFunctionName(handler) + s = get_func_name(handler) if not s: s = "%x" % handler @@ -110,7 +110,7 @@ class SEHGraph(GraphViewer): def OnDblClick(self, node_id): is_thread, value, label = self[node_id] if is_thread: - idc.SelectThread(value) + idc.select_thread(value) self.Show() s = "SEH chain for " + hex(value) t = "-" * len(s) @@ -121,7 +121,7 @@ class SEHGraph(GraphViewer): print "%x: %s" % (handler, self.names[handler]) print t else: - idc.Jump(value) + idc.jumpto(value) return True @@ -132,7 +132,7 @@ def main(): return # Save current thread id - tid = GetCurrentThreadId() + tid = get_current_thread() # Iterate through all function instructions and take only call instructions result = {} @@ -140,7 +140,7 @@ def main(): result[tid] = GetExceptionChain(tid) # Restore previously selected thread - idc.SelectThread(tid) + idc.select_thread(tid) # Build the graph g = SEHGraph("SEH graph", result) diff --git a/Scripts/VaDump.py b/Scripts/VaDump.py index cf606eb..bcb3d33 100644 --- a/Scripts/VaDump.py +++ b/Scripts/VaDump.py @@ -8,7 +8,7 @@ ALL RIGHTS RESERVED. """ import idc -from idaapi import Choose +from ida_kernwin import Choose import re @@ -27,25 +27,40 @@ class memva: else: self.type = 0 self.typestr = "" - def __str__(self): - return "(Base %08X; RegionSize: %08X; State: %08X/%10s; protect: %08X/%10s; type: %08X/%10s)" % ( - self.base, self.regionsize, self.state, - self.statestr, self.protect, - self.protectstr, self.type, self.typestr) # Chooser class class MemChoose(Choose): - def __init__(self, list, title): - Choose.__init__(self, list, title) - self.width = 250 + def __init__(self, title, items): + headers = [] + headers.append(["Base", 10]) + headers.append(["RegionSize", 10]) + headers.append(["State", 20]) + headers.append(["Protect", 20]) + headers.append(["Type", 20]) + Choose.__init__(self, title, headers) + self.items = items - def enter(self, n): - o = self.list[n-1] - idc.Jump(o.base) + def OnGetLine(self, n): + o = self.items[n] + line = [] + line.append("%08X" % o.base) + line.append("%08X" % o.regionsize) + line.append("%08X/%10s" % (o.state, o.statestr)) + line.append("%08X/%10s" % (o.protect, o.protectstr)) + line.append("%08X/%10s" % (o.type, o.typestr)) + return line + + def OnGetSize(self): + return len(self.items) + + def OnSelectLine(self, n): + o = self.items[n] + idc.jumpto(o.base) + return (NOTHING_CHANGED, ) # main def main(): - s = idc.Eval('SendDbgCommand("!vadump")') + s = idc.eval('send_dbg_command("!vadump")') if "IDC_FAILURE" in s: return (False, "Cannot execute the command") @@ -61,9 +76,9 @@ def main(): return (False, "Nothing to display: Could not parse the result!") # Get a Choose instance - chooser = MemChoose(L, "Memory choose") + chooser = MemChoose("Memory choose", L) # Run the chooser - chooser.choose() + chooser.Show() return (True, "Success!") r = main() if not r[0]: diff --git a/Scripts/VirusTotal.py b/Scripts/VirusTotal.py index ca2a86f..8069b3a 100644 --- a/Scripts/VirusTotal.py +++ b/Scripts/VirusTotal.py @@ -9,7 +9,8 @@ # import idaapi import idc -from idaapi import Choose2, plugin_t +from idaapi import plugin_t +from ida_kernwin import Choose import BboeVt as vt import webbrowser import urllib @@ -46,7 +47,7 @@ class VirusTotalConfig(object): def Default(self): - self.md5sum = GetInputMD5() + self.md5sum = retrieve_input_file_md5() self.infile = idaapi.dbg_get_input_path() if not self.infile: self.infile = "" @@ -118,15 +119,15 @@ def VtReport(apikey, filename=None, md5sum=None): # ----------------------------------------------------------------------- -class VirusTotalChooser(Choose2): +class VirusTotalChooser(Choose): """ Chooser class to display results from VT """ def __init__(self, title, items, icon, embedded=False): - Choose2.__init__(self, - title, - [ ["Antivirus", 20], ["Result", 40] ], - embedded=embedded) + Choose.__init__(self, + title, + [ ["Antivirus", 20], ["Result", 40] ], + embedded=embedded) self.items = items self.icon = icon @@ -139,10 +140,6 @@ class VirusTotalChooser(Choose2): self.items = [] if items is None else items - def OnClose(self): - pass - - def OnGetLine(self, n): return self.items[n] @@ -155,6 +152,7 @@ class VirusTotalChooser(Choose2): # Google search for the malware name and the antivirus name s = urllib.urlencode({"q" : " ".join(self.items[n])}) webbrowser.open_new_tab("http://www.google.com/search?%s" % s) + return (NOTHING_CHANGED, ) # -------------------------------------------------------------------------- @@ -224,7 +222,7 @@ Options: # Error? if not ok: - idc.Warning(r) + idc.warning(r) return 1 # Pass the result @@ -245,20 +243,20 @@ Options: if r is None: if as_file: # Propose to upload - if idc.AskYN(0, "HIDECANCEL\nNo previous results. Do you want to submit the file:\n\n'%s'\n\nto VirusTotal?" % input) == 0: + if idc.ask_yn(0, "HIDECANCEL\nNo previous results. Do you want to submit the file:\n\n'%s'\n\nto VirusTotal?" % input) == 0: return 1 try: r = vt.scan_file(input) except Exception as e: - idc.Warning("Exceptio during upload: %s" % str(e)) + idc.warning("Exceptio during upload: %s" % str(e)) else: if r is None: - idc.Warning("Failed to upload the file!") + idc.warning("Failed to upload the file!") else: - idc.Warning("File uploaded. Check again later to get the analysis report. Scan id: %s" % r) + idc.warning("File uploaded. Check again later to get the analysis report. Scan id: %s" % r) else: - idc.Warning("No results found for hash: %s" % input) + idc.warning("No results found for hash: %s" % input) return 1 diff --git a/Scripts/msdnapihelp.py b/Scripts/msdnapihelp.py index 8a90d60..b920c6e 100644 --- a/Scripts/msdnapihelp.py +++ b/Scripts/msdnapihelp.py @@ -36,7 +36,8 @@ class msdnapihelp_plugin_t(idaapi.plugin_t): def run(self, arg): # Get the highlighted identifier - id = idaapi.get_highlighted_identifier() + v = idaapi.get_current_viewer() + id = ida_kernwin.get_highlight(v)[0] if not id: print "No identifier was highlighted" return diff --git a/api_contents.txt b/api_contents.txt index e7f5b5a..092cece 100644 --- a/api_contents.txt +++ b/api_contents.txt @@ -1,7 +1,4 @@ {'functions': ['AssembleLine', - 'Compile', - 'CompileEx', - 'CompileLine', 'DBG_Hooks_dbg_bpt', 'DBG_Hooks_dbg_bpt_changed', 'DBG_Hooks_dbg_exception', @@ -23,33 +20,37 @@ 'DBG_Hooks_dbg_trace', 'DBG_Hooks_hook', 'DBG_Hooks_unhook', - 'ExtraFree', 'IDB_Hooks_allsegs_moved', - 'IDB_Hooks_area_cmt_changed', + 'IDB_Hooks_auto_empty', + 'IDB_Hooks_auto_empty_finally', 'IDB_Hooks_byte_patched', - 'IDB_Hooks_changed_stkpnts', - 'IDB_Hooks_changed_struc', - 'IDB_Hooks_changing_area_cmt', 'IDB_Hooks_changing_cmt', 'IDB_Hooks_changing_enum_bf', 'IDB_Hooks_changing_enum_cmt', 'IDB_Hooks_changing_op_ti', 'IDB_Hooks_changing_op_type', + 'IDB_Hooks_changing_range_cmt', 'IDB_Hooks_changing_segm_class', 'IDB_Hooks_changing_segm_end', 'IDB_Hooks_changing_segm_name', 'IDB_Hooks_changing_segm_start', - 'IDB_Hooks_changing_struc', + 'IDB_Hooks_changing_struc_align', 'IDB_Hooks_changing_struc_cmt', 'IDB_Hooks_changing_struc_member', 'IDB_Hooks_changing_ti', + 'IDB_Hooks_closebase', 'IDB_Hooks_cmt_changed', + 'IDB_Hooks_compiler_changed', 'IDB_Hooks_deleting_enum', - 'IDB_Hooks_deleting_enum_const', + 'IDB_Hooks_deleting_enum_member', + 'IDB_Hooks_deleting_func', + 'IDB_Hooks_deleting_func_tail', 'IDB_Hooks_deleting_segm', 'IDB_Hooks_deleting_struc', 'IDB_Hooks_deleting_struc_member', + 'IDB_Hooks_deleting_tryblks', 'IDB_Hooks_destroyed_items', + 'IDB_Hooks_determined_main', 'IDB_Hooks_enum_bf_changed', 'IDB_Hooks_enum_cmt_changed', 'IDB_Hooks_enum_created', @@ -58,26 +59,43 @@ 'IDB_Hooks_enum_member_deleted', 'IDB_Hooks_enum_renamed', 'IDB_Hooks_expanding_struc', + 'IDB_Hooks_extlang_changed', 'IDB_Hooks_extra_cmt_changed', + 'IDB_Hooks_flow_chart_created', + 'IDB_Hooks_frame_deleted', + 'IDB_Hooks_func_added', 'IDB_Hooks_func_noret_changed', 'IDB_Hooks_func_tail_appended', - 'IDB_Hooks_func_tail_removed', + 'IDB_Hooks_func_tail_deleted', + 'IDB_Hooks_func_updated', 'IDB_Hooks_hook', + 'IDB_Hooks_idasgn_loaded', + 'IDB_Hooks_kernel_config_loaded', + 'IDB_Hooks_loader_finished', 'IDB_Hooks_local_types_changed', + 'IDB_Hooks_make_code', + 'IDB_Hooks_make_data', 'IDB_Hooks_op_ti_changed', 'IDB_Hooks_op_type_changed', - 'IDB_Hooks_removing_func_tail', + 'IDB_Hooks_range_cmt_changed', + 'IDB_Hooks_renamed', 'IDB_Hooks_renaming_enum', 'IDB_Hooks_renaming_struc', 'IDB_Hooks_renaming_struc_member', + 'IDB_Hooks_savebase', 'IDB_Hooks_segm_added', - 'IDB_Hooks_segm_attrs_changed', + 'IDB_Hooks_segm_attrs_updated', 'IDB_Hooks_segm_class_changed', 'IDB_Hooks_segm_deleted', 'IDB_Hooks_segm_end_changed', 'IDB_Hooks_segm_moved', 'IDB_Hooks_segm_name_changed', 'IDB_Hooks_segm_start_changed', + 'IDB_Hooks_set_func_end', + 'IDB_Hooks_set_func_start', + 'IDB_Hooks_sgr_changed', + 'IDB_Hooks_stkpnts_changed', + 'IDB_Hooks_struc_align_changed', 'IDB_Hooks_struc_cmt_changed', 'IDB_Hooks_struc_created', 'IDB_Hooks_struc_deleted', @@ -90,147 +108,136 @@ 'IDB_Hooks_tail_owner_changed', 'IDB_Hooks_thunk_func_created', 'IDB_Hooks_ti_changed', + 'IDB_Hooks_tryblks_updated', 'IDB_Hooks_unhook', - 'IDP_Hooks_add_cref', - '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', - 'IDP_Hooks_auto_queue_empty', - 'IDP_Hooks_based_ptr', - 'IDP_Hooks_calc_arglocs3', - 'IDP_Hooks_calc_cdecl_purged_bytes2', - 'IDP_Hooks_calc_next_eas', - 'IDP_Hooks_calc_purged_bytes3', - 'IDP_Hooks_calc_retloc3', - 'IDP_Hooks_calc_step_over', - 'IDP_Hooks_calc_switch_cases', - 'IDP_Hooks_calc_varglocs3', - 'IDP_Hooks_clean_tbit', - 'IDP_Hooks_closebase', - 'IDP_Hooks_coagulate', - 'IDP_Hooks_coagulate_dref', - 'IDP_Hooks_create_flat_group', - 'IDP_Hooks_create_switch_xrefs', - 'IDP_Hooks_custom_ana', - 'IDP_Hooks_custom_emu', - 'IDP_Hooks_custom_mnem', - 'IDP_Hooks_custom_out', - 'IDP_Hooks_custom_outop', - 'IDP_Hooks_custom_refinfo', - 'IDP_Hooks_decorate_name3', - 'IDP_Hooks_del_cref', - 'IDP_Hooks_del_dref', - 'IDP_Hooks_del_func', - 'IDP_Hooks_delay_slot_insn', - 'IDP_Hooks_determined_main', - 'IDP_Hooks_endbinary', - 'IDP_Hooks_equal_reglocs', - 'IDP_Hooks_extlang_changed', - 'IDP_Hooks_func_bounds', - 'IDP_Hooks_gen_asm_or_lst', - 'IDP_Hooks_gen_regvar_def', - 'IDP_Hooks_get_autocmt', - 'IDP_Hooks_get_bg_color', - 'IDP_Hooks_get_dbr_opnum', - 'IDP_Hooks_get_default_enum_size', - 'IDP_Hooks_get_fastcall_regs3', - 'IDP_Hooks_get_func_cvtarg_map', - 'IDP_Hooks_get_jump_target', - 'IDP_Hooks_get_macro_insn_head', - 'IDP_Hooks_get_operand_string', - 'IDP_Hooks_get_reg_info2', - 'IDP_Hooks_get_reg_name', - 'IDP_Hooks_get_simd_types', - 'IDP_Hooks_get_stkarg_offset2', - 'IDP_Hooks_get_stkvar_scale_factor', - 'IDP_Hooks_get_thiscall_regs3', - 'IDP_Hooks_get_varcall_regs3', - 'IDP_Hooks_get_vxd_name', + 'IDB_Hooks_updating_tryblks', + 'IDB_Hooks_upgraded', + 'IDP_Hooks_ev_add_cref', + 'IDP_Hooks_ev_add_dref', + 'IDP_Hooks_ev_adjust_argloc', + 'IDP_Hooks_ev_adjust_libfunc_ea', + 'IDP_Hooks_ev_adjust_refinfo', + 'IDP_Hooks_ev_ana_insn', + 'IDP_Hooks_ev_arg_addrs_ready', + 'IDP_Hooks_ev_assemble', + 'IDP_Hooks_ev_auto_queue_empty', + 'IDP_Hooks_ev_calc_arglocs', + 'IDP_Hooks_ev_calc_cdecl_purged_bytes', + 'IDP_Hooks_ev_calc_next_eas', + 'IDP_Hooks_ev_calc_purged_bytes', + 'IDP_Hooks_ev_calc_retloc', + 'IDP_Hooks_ev_calc_step_over', + 'IDP_Hooks_ev_calc_switch_cases', + 'IDP_Hooks_ev_calc_varglocs', + 'IDP_Hooks_ev_can_have_type', + 'IDP_Hooks_ev_clean_tbit', + 'IDP_Hooks_ev_cmp_operands', + 'IDP_Hooks_ev_coagulate', + 'IDP_Hooks_ev_coagulate_dref', + 'IDP_Hooks_ev_create_flat_group', + 'IDP_Hooks_ev_create_func_frame', + 'IDP_Hooks_ev_create_switch_xrefs', + 'IDP_Hooks_ev_creating_segm', + 'IDP_Hooks_ev_decorate_name', + 'IDP_Hooks_ev_del_cref', + 'IDP_Hooks_ev_del_dref', + 'IDP_Hooks_ev_delay_slot_insn', + 'IDP_Hooks_ev_demangle_name', + 'IDP_Hooks_ev_emu_insn', + 'IDP_Hooks_ev_endbinary', + 'IDP_Hooks_ev_equal_reglocs', + 'IDP_Hooks_ev_extract_address', + 'IDP_Hooks_ev_func_bounds', + 'IDP_Hooks_ev_gen_asm_or_lst', + 'IDP_Hooks_ev_gen_map_file', + 'IDP_Hooks_ev_gen_regvar_def', + 'IDP_Hooks_ev_gen_src_file_lnnum', + 'IDP_Hooks_ev_gen_stkvar_def', + 'IDP_Hooks_ev_get_abi_info', + 'IDP_Hooks_ev_get_autocmt', + 'IDP_Hooks_ev_get_bg_color', + 'IDP_Hooks_ev_get_cc_regs', + 'IDP_Hooks_ev_get_dbr_opnum', + 'IDP_Hooks_ev_get_default_enum_size', + 'IDP_Hooks_ev_get_frame_retsize', + 'IDP_Hooks_ev_get_macro_insn_head', + 'IDP_Hooks_ev_get_operand_string', + 'IDP_Hooks_ev_get_reg_info', + 'IDP_Hooks_ev_get_reg_name', + 'IDP_Hooks_ev_get_simd_types', + 'IDP_Hooks_ev_get_stkarg_offset', + 'IDP_Hooks_ev_get_stkvar_scale_factor', + 'IDP_Hooks_ev_getreg', + 'IDP_Hooks_ev_init', + 'IDP_Hooks_ev_insn_reads_tbit', + 'IDP_Hooks_ev_is_align_insn', + 'IDP_Hooks_ev_is_alloca_probe', + 'IDP_Hooks_ev_is_basic_block_end', + 'IDP_Hooks_ev_is_call_insn', + 'IDP_Hooks_ev_is_cond_insn', + 'IDP_Hooks_ev_is_far_jump', + 'IDP_Hooks_ev_is_indirect_jump', + 'IDP_Hooks_ev_is_insn_table_jump', + 'IDP_Hooks_ev_is_jump_func', + 'IDP_Hooks_ev_is_ret_insn', + 'IDP_Hooks_ev_is_sane_insn', + 'IDP_Hooks_ev_is_sp_based', + 'IDP_Hooks_ev_is_switch', + 'IDP_Hooks_ev_loader', + 'IDP_Hooks_ev_lower_func_type', + 'IDP_Hooks_ev_max_ptr_size', + 'IDP_Hooks_ev_may_be_func', + 'IDP_Hooks_ev_may_show_sreg', + 'IDP_Hooks_ev_moving_segm', + 'IDP_Hooks_ev_newasm', + 'IDP_Hooks_ev_newbinary', + 'IDP_Hooks_ev_newfile', + 'IDP_Hooks_ev_newprc', + 'IDP_Hooks_ev_next_exec_insn', + 'IDP_Hooks_ev_oldfile', + 'IDP_Hooks_ev_out_assumes', + 'IDP_Hooks_ev_out_data', + 'IDP_Hooks_ev_out_footer', + 'IDP_Hooks_ev_out_header', + 'IDP_Hooks_ev_out_insn', + 'IDP_Hooks_ev_out_label', + 'IDP_Hooks_ev_out_mnem', + 'IDP_Hooks_ev_out_operand', + 'IDP_Hooks_ev_out_segend', + 'IDP_Hooks_ev_out_segstart', + 'IDP_Hooks_ev_out_special_item', + 'IDP_Hooks_ev_realcvt', + 'IDP_Hooks_ev_rename', + 'IDP_Hooks_ev_set_idp_options', + 'IDP_Hooks_ev_set_proc_options', + 'IDP_Hooks_ev_setup_til', + 'IDP_Hooks_ev_shadow_args_size', + 'IDP_Hooks_ev_str2reg', + 'IDP_Hooks_ev_term', + 'IDP_Hooks_ev_treat_hindering_item', + 'IDP_Hooks_ev_undefine', + 'IDP_Hooks_ev_use_arg_types', + 'IDP_Hooks_ev_use_regarg_type', + 'IDP_Hooks_ev_use_stkarg_type', + 'IDP_Hooks_ev_validate_flirt_func', + 'IDP_Hooks_ev_verify_noreturn', + 'IDP_Hooks_ev_verify_sp', 'IDP_Hooks_hook', - 'IDP_Hooks_init', - 'IDP_Hooks_insn_reads_tbit', - 'IDP_Hooks_is_alloca_probe', - 'IDP_Hooks_is_basic_block_end', - 'IDP_Hooks_is_call_insn', - 'IDP_Hooks_is_indirect_jump', - 'IDP_Hooks_is_insn_table_jump', - 'IDP_Hooks_is_jump_func', - 'IDP_Hooks_is_ret_insn', - 'IDP_Hooks_is_sane_insn', - 'IDP_Hooks_kernel_config_loaded', - 'IDP_Hooks_load_idasgn', - 'IDP_Hooks_loader', - 'IDP_Hooks_loader_finished', - 'IDP_Hooks_make_code', - 'IDP_Hooks_make_data', - 'IDP_Hooks_max_ptr_size', - 'IDP_Hooks_may_be_func', - 'IDP_Hooks_may_show_sreg', - 'IDP_Hooks_might_change_sp', - 'IDP_Hooks_move_segm', - 'IDP_Hooks_moving_segm', - 'IDP_Hooks_newasm', - 'IDP_Hooks_newbinary', - 'IDP_Hooks_newfile', - 'IDP_Hooks_newprc', - 'IDP_Hooks_newseg', - 'IDP_Hooks_obsolete_makemicro', - 'IDP_Hooks_oldfile', - 'IDP_Hooks_out_3byte', - 'IDP_Hooks_out_src_file_lnnum', - 'IDP_Hooks_outlabel', - 'IDP_Hooks_preprocess_chart', - 'IDP_Hooks_register_custom_fixup', - 'IDP_Hooks_reglink', - 'IDP_Hooks_rename', - 'IDP_Hooks_renamed', - 'IDP_Hooks_savebase', - 'IDP_Hooks_set_compiler', - 'IDP_Hooks_set_func_end', - 'IDP_Hooks_set_func_start', - 'IDP_Hooks_set_proc_options', - 'IDP_Hooks_setsgr', - 'IDP_Hooks_setup_til', - 'IDP_Hooks_shadow_args_size', - 'IDP_Hooks_str2reg', - 'IDP_Hooks_term', - 'IDP_Hooks_til_for_file', - 'IDP_Hooks_treat_hindering_item', - 'IDP_Hooks_undefine', 'IDP_Hooks_unhook', - 'IDP_Hooks_use_arg_types3', - 'IDP_Hooks_use_regarg_type3', - 'IDP_Hooks_use_stkarg_type3', - 'IDP_Hooks_validate_flirt_func', - 'IDP_Hooks_verify_noreturn', - 'IDP_Hooks_verify_sp', - 'InstrIsSet', - 'MakeBorder', - 'MakeLine', - 'MakeNull', - 'MakeSolidBorder', - 'OutBadInstruction', - 'OutChar', - 'OutImmChar', - 'OutLine', - 'OutLong', - 'OutMnem', - 'OutValue', - 'QueueDel', - 'QueueGetMessage', - 'QueueGetType', - 'QueueIsPresent', - 'QueueMark', - 'QueueSet', - 'SetDefaultRegisterValue', - 'UI_Hooks_current_tform_changed', + 'TPointDouble___eq__', + 'TPointDouble___ne__', + 'TPointDouble_add', + 'TPointDouble_negate', + 'TPointDouble_sub', + 'TPointDouble_x_get', + 'TPointDouble_x_set', + 'TPointDouble_y_get', + 'TPointDouble_y_set', + 'UI_Hooks_current_widget_changed', 'UI_Hooks_database_inited', 'UI_Hooks_debugger_menu_change', - 'UI_Hooks_finish_populating_tform_popup', + 'UI_Hooks_finish_populating_widget_popup', + 'UI_Hooks_get_chooser_item_attrs', 'UI_Hooks_get_custom_viewer_hint', 'UI_Hooks_get_ea_hint', 'UI_Hooks_get_item_hint', @@ -239,9 +246,9 @@ 'UI_Hooks_idcstop', 'UI_Hooks_plugin_loaded', 'UI_Hooks_plugin_unloading', - 'UI_Hooks_populating_tform_popup', - 'UI_Hooks_postprocess', - 'UI_Hooks_preprocess', + 'UI_Hooks_populating_widget_popup', + 'UI_Hooks_postprocess_action', + 'UI_Hooks_preprocess_action', 'UI_Hooks_range', 'UI_Hooks_ready_to_run', 'UI_Hooks_resume', @@ -249,41 +256,46 @@ 'UI_Hooks_saving', 'UI_Hooks_suspend', 'UI_Hooks_term', - 'UI_Hooks_tform_invisible', - 'UI_Hooks_tform_visible', 'UI_Hooks_unhook', 'UI_Hooks_updated_actions', 'UI_Hooks_updating_actions', - 'VarAssign', - 'VarCopy', - 'VarDelAttr', - 'VarDeref', - 'VarFirstAttr', - 'VarGetAttr', - 'VarGetClassName', - 'VarGetSlice', - 'VarInt64', - 'VarLastAttr', - 'VarMove', - 'VarNextAttr', - 'VarObject', - 'VarPrevAttr', - 'VarPrint', - 'VarRef', - 'VarSetAttr', - 'VarSetSlice', - 'VarString2', - 'VarSwap', - '_askaddr', - '_askaddr__varargs__', - '_asklong', - '_asklong__varargs__', - '_askseg', - '_askseg__varargs__', + 'UI_Hooks_widget_closing', + 'UI_Hooks_widget_invisible', + 'UI_Hooks_widget_visible', + 'View_Hooks_hook', + 'View_Hooks_unhook', + 'View_Hooks_view_activated', + 'View_Hooks_view_click', + 'View_Hooks_view_close', + 'View_Hooks_view_created', + 'View_Hooks_view_curpos', + 'View_Hooks_view_dblclick', + 'View_Hooks_view_deactivated', + 'View_Hooks_view_keydown', + 'View_Hooks_view_loc_changed', + 'View_Hooks_view_mouse_moved', + 'View_Hooks_view_mouse_over', + 'View_Hooks_view_switched', + '_ask_addr', + '_ask_addr__varargs__', + '_ask_long', + '_ask_long__varargs__', + '_ask_seg', + '_ask_seg__varargs__', '_decompile', '_kludge_use_TPopupMenu', - 'a2funcoff', + '_ll_call_helper', + '_ll_call_helper__varargs__', + '_ll_create_helper', + '_ll_create_helper__varargs__', + '_ll_dereference', + '_ll_lnot', + '_ll_make_num', + '_ll_make_ref', + '_ll_new_block', 'accepts_udts', + 'action_ctx_base_t__get_form_type', + 'action_ctx_base_t__get_reg', 'action_ctx_base_t_action_get', 'action_ctx_base_t_action_set', 'action_ctx_base_t_chooser_selection_get', @@ -306,16 +318,22 @@ 'action_ctx_base_t_cur_strmem_set', 'action_ctx_base_t_cur_struc_get', 'action_ctx_base_t_cur_struc_set', - 'action_ctx_base_t_form_get', - 'action_ctx_base_t_form_set', - 'action_ctx_base_t_form_title_get', - 'action_ctx_base_t_form_title_set', - 'action_ctx_base_t_form_type_get', - 'action_ctx_base_t_form_type_set', + 'action_ctx_base_t_focus_get', + 'action_ctx_base_t_focus_set', 'action_ctx_base_t_has_flag', + 'action_ctx_base_t_reserved_get', + 'action_ctx_base_t_reserved_set', 'action_ctx_base_t_reset', + 'action_ctx_base_t_widget_get', + 'action_ctx_base_t_widget_set', + 'action_ctx_base_t_widget_title_get', + 'action_ctx_base_t_widget_title_set', + 'action_ctx_base_t_widget_type_get', + 'action_ctx_base_t_widget_type_set', 'action_desc_t_cb_get', 'action_desc_t_cb_set', + 'action_desc_t_flags_get', + 'action_desc_t_flags_set', 'action_desc_t_icon_get', 'action_desc_t_icon_set', 'action_desc_t_label_get', @@ -328,54 +346,47 @@ 'action_desc_t_shortcut_set', 'action_desc_t_tooltip_get', 'action_desc_t_tooltip_set', + 'activate_widget', 'add_auto_stkpnt', - 'add_auto_stkpnt2', 'add_bpt', 'add_bpt__SWIG_0', 'add_bpt__SWIG_1', 'add_byte', - 'add_chooser_command', - 'add_chooser_command__SWIG_0', - 'add_chooser_command__SWIG_1', - 'add_const', 'add_cref', - 'add_custom_viewer_popup_item', - 'add_custom_viewer_popup_item__SWIG_1', 'add_dref', + 'add_dword', 'add_encoding', 'add_entry', 'add_enum', 'add_enum_member', + 'add_extra_cmt', + 'add_extra_cmt__varargs__', + 'add_extra_line', + 'add_extra_line__varargs__', 'add_frame', 'add_func', 'add_func_ex', - 'add_hidden_area', + 'add_hidden_range', 'add_hotkey', 'add_idc_class', 'add_idc_gvar', 'add_idc_hotkey', - 'add_long', - 'add_long_cmt', - 'add_long_cmt__varargs__', - 'add_menu_item', - 'add_output_popup', + 'add_mapping', 'add_pgm_cmt', 'add_pgm_cmt__varargs__', 'add_qword', + 'add_refinfo_dref', 'add_regarg', - 'add_regarg2', 'add_regvar', 'add_segm', 'add_segm_ex', 'add_segment_translation', 'add_sourcefile', 'add_spaces', - 'add_stkvar2', - 'add_stkvar3', 'add_struc', 'add_struc_member', 'add_til', - 'add_til2', + 'add_tryblk', 'add_user_stkpnt', 'add_virt_module', 'add_word', @@ -398,134 +409,28 @@ 'addon_info_t_url_set', 'addon_info_t_version_get', 'addon_info_t_version_set', - 'alignflag', + 'align_flag', 'alloc_type_ordinal', 'alloc_type_ordinals', 'allocate_selector', 'aloc_visitor_t_visit_location', - 'analyze_area', 'analyzer_options', - 'ansi2idb', 'appcall', + 'append_abi_opts', 'append_argloc', 'append_cmt', - 'append_complex_n', - 'append_da', - 'append_de', - 'append_dt', 'append_func_tail', - 'append_name', - 'append_struct_fields2', + 'append_struct_fields', 'append_tinfo_covered', - 'append_varloc', 'apply_callee_tinfo', 'apply_cdecl', - 'apply_cdecl2', - 'apply_idasgn', 'apply_idasgn_to', 'apply_named_type', 'apply_once_tinfo_and_name', - 'apply_once_type_and_name', 'apply_startup_sig', 'apply_tinfo', - 'apply_tinfo2', 'apply_tinfo_to_stkarg', 'apply_type', - 'apply_type2', - 'apply_type_to_stkarg', - 'area_t___eq__', - 'area_t___gt__', - 'area_t___lt__', - 'area_t___ne__', - 'area_t__print', - 'area_t_clear', - 'area_t_compare', - 'area_t_contains', - 'area_t_contains__SWIG_0', - 'area_t_contains__SWIG_1', - 'area_t_empty', - 'area_t_endEA_get', - 'area_t_endEA_set', - 'area_t_extend', - 'area_t_intersect', - 'area_t_overlaps', - 'area_t_print', - 'area_t_size', - 'area_t_startEA_get', - 'area_t_startEA_set', - 'area_visitor2_t_visit_area', - 'areacb_t_create', - 'areacb_t_create_area', - 'areacb_t_del_area', - 'areacb_t_del_area_cmt', - 'areacb_t_first_area_ptr', - 'areacb_t_for_all_areas2', - 'areacb_t_get_area', - 'areacb_t_get_area_cmt', - 'areacb_t_get_area_num', - 'areacb_t_get_area_qty', - 'areacb_t_get_netnode', - 'areacb_t_get_next_area', - 'areacb_t_get_prev_area', - 'areacb_t_get_type', - 'areacb_t_getn_area', - 'areacb_t_kill', - 'areacb_t_last_area_ptr', - 'areacb_t_link', - 'areacb_t_make_hole', - 'areacb_t_may_end_at', - 'areacb_t_may_lock_area', - 'areacb_t_may_start_at', - 'areacb_t_next_area_ptr', - 'areacb_t_prepare_to_create', - 'areacb_t_prev_area_ptr', - 'areacb_t_resize_areas', - 'areacb_t_save', - 'areacb_t_set_area_cmt', - 'areacb_t_set_end', - 'areacb_t_set_start', - 'areacb_t_terminate', - 'areacb_t_update', - 'areacb_t_zero', - 'areaset_t___eq__', - 'areaset_t___ne__', - 'areaset_t__print', - 'areaset_t_add', - 'areaset_t_add__SWIG_0', - 'areaset_t_add__SWIG_1', - 'areaset_t_add__SWIG_2', - 'areaset_t_begin', - 'areaset_t_begin__SWIG_0', - 'areaset_t_begin__SWIG_1', - 'areaset_t_cached_area', - 'areaset_t_clear', - 'areaset_t_contains', - 'areaset_t_contains__SWIG_0', - 'areaset_t_contains__SWIG_1', - 'areaset_t_empty', - 'areaset_t_end', - 'areaset_t_end__SWIG_0', - 'areaset_t_end__SWIG_1', - 'areaset_t_find_area', - 'areaset_t_getarea', - 'areaset_t_has_common', - 'areaset_t_has_common__SWIG_0', - 'areaset_t_has_common__SWIG_1', - 'areaset_t_includes', - 'areaset_t_intersect', - 'areaset_t_is_equal', - 'areaset_t_is_subset_of', - 'areaset_t_lastarea', - 'areaset_t_nareas', - 'areaset_t_next_addr', - 'areaset_t_next_area', - 'areaset_t_prev_addr', - 'areaset_t_prev_area', - 'areaset_t_sub', - 'areaset_t_sub__SWIG_0', - 'areaset_t_sub__SWIG_1', - 'areaset_t_sub__SWIG_2', - 'areaset_t_swap', 'argloc_t___eq__', 'argloc_t___ge__', 'argloc_t___gt__', @@ -600,36 +505,18 @@ 'array_type_data_t_nelems_get', 'array_type_data_t_nelems_set', 'array_type_data_t_swap', - 'asciflag', 'asgop', 'asgop_revert', + 'ask_buttons', + 'ask_buttons__varargs__', + 'ask_file', + 'ask_file__varargs__', 'ask_for_feedback', 'ask_for_feedback__varargs__', - 'ask_selector', - 'askbuttons_c', - 'askbuttons_c__varargs__', - 'askfile2_c', - 'askfile2_c__varargs__', - 'askfile2_cv', - 'askfile_c', - 'askfile_c__varargs__', - 'askident', - 'askident__varargs__', - 'askqstr', - 'askqstr__varargs__', - 'askstr', - 'askstr__varargs__', - 'asktext', - 'askyn_c', - 'askyn_c__varargs__', - 'asm_t_XlatAsciiOutput_get', - 'asm_t_XlatAsciiOutput_set', - 'asm_t__UNUSED1_was_atomprefix_get', - 'asm_t__UNUSED1_was_atomprefix_set', - 'asm_t__UNUSED2_was_checkarg_operations_get', - 'asm_t__UNUSED2_was_checkarg_operations_set', - 'asm_t_a_3byte_get', - 'asm_t_a_3byte_set', + 'ask_str', + 'ask_text', + 'ask_yn', + 'ask_yn__varargs__', 'asm_t_a_align_get', 'asm_t_a_align_set', 'asm_t_a_ascii_get', @@ -698,8 +585,6 @@ 'asm_t_accsep_set', 'asm_t_ascsep_get', 'asm_t_ascsep_set', - 'asm_t_badworks_get', - 'asm_t_badworks_set', 'asm_t_cmnt2_get', 'asm_t_cmnt2_set', 'asm_t_cmnt_get', @@ -737,19 +622,13 @@ 'assemble', 'attach_action_to_menu', 'attach_action_to_popup', - 'attach_action_to_popup__SWIG_0', - 'attach_action_to_popup__SWIG_1', 'attach_action_to_toolbar', + 'attach_custom_data_format', 'attach_dynamic_action_to_popup', 'attach_process', - 'autoCancel', - 'autoGetName', - 'autoIsOk', - 'autoMark', - 'autoStep', - 'autoUnmark', - 'autoWait', + 'auto_apply_tail', 'auto_apply_type', + 'auto_cancel', 'auto_display_t_ea_get', 'auto_display_t_ea_set', 'auto_display_t_state_get', @@ -757,9 +636,14 @@ 'auto_display_t_type_get', 'auto_display_t_type_set', 'auto_get', + 'auto_is_ok', 'auto_make_code', 'auto_make_proc', + 'auto_mark', 'auto_mark_range', + 'auto_recreate_insn', + 'auto_unmark', + 'auto_wait', 'banner', 'base2file', 'beep', @@ -770,8 +654,8 @@ 'bgcolors_t_prolog_color_set', 'bgcolors_t_switch_color_get', 'bgcolors_t_switch_color_set', + 'bin_flag', 'bin_search', - 'binflag', 'bitfield_type_data_t___eq__', 'bitfield_type_data_t___ge__', 'bitfield_type_data_t___gt__', @@ -800,9 +684,6 @@ 'boolvec_t__del', 'boolvec_t_add_unique', 'boolvec_t_at', - 'boolvec_t_back', - 'boolvec_t_back__SWIG_0', - 'boolvec_t_back__SWIG_1', 'boolvec_t_begin', 'boolvec_t_begin__SWIG_0', 'boolvec_t_begin__SWIG_1', @@ -819,9 +700,6 @@ 'boolvec_t_find', 'boolvec_t_find__SWIG_0', 'boolvec_t_find__SWIG_1', - 'boolvec_t_front', - 'boolvec_t_front__SWIG_0', - 'boolvec_t_front__SWIG_1', 'boolvec_t_grow', 'boolvec_t_has', 'boolvec_t_inject', @@ -895,6 +773,7 @@ 'bpt_t_enabled', 'bpt_t_flags_get', 'bpt_t_flags_set', + 'bpt_t_get_cnd_elang_idx', 'bpt_t_get_size', 'bpt_t_is_absbpt', 'bpt_t_is_active', @@ -930,9 +809,6 @@ 'bpt_vec_t___len__', 'bpt_vec_t___setitem__', 'bpt_vec_t_at', - 'bpt_vec_t_back', - 'bpt_vec_t_back__SWIG_0', - 'bpt_vec_t_back__SWIG_1', 'bpt_vec_t_begin', 'bpt_vec_t_begin__SWIG_0', 'bpt_vec_t_begin__SWIG_1', @@ -946,9 +822,6 @@ 'bpt_vec_t_erase__SWIG_0', 'bpt_vec_t_erase__SWIG_1', 'bpt_vec_t_extract', - 'bpt_vec_t_front', - 'bpt_vec_t_front__SWIG_0', - 'bpt_vec_t_front__SWIG_1', 'bpt_vec_t_grow', 'bpt_vec_t_inject', 'bpt_vec_t_insert', @@ -965,46 +838,36 @@ 'bpt_vec_t_swap', 'bpt_vec_t_truncate', 'bring_debugger_to_front', - 'build_array_type', - 'build_func_type', - 'build_func_type2', - 'build_funcarg_info', 'build_snapshot_tree', 'build_stkvar_name', 'build_stkvar_xrefs', - 'byteflag', + 'build_strlist', + 'byte_flag', 'bytesize', - 'calc_argloc_info', + 'calc_basevalue', 'calc_bg_color', - 'calc_c_cpp_name4', + 'calc_c_cpp_name', + 'calc_dataseg', 'calc_def_align', 'calc_default_idaplace_flags', - 'calc_func_nargs', + 'calc_dist', + 'calc_fixup_size', 'calc_idasgn_state', - 'calc_idc_expr', 'calc_max_align', - 'calc_max_children_qty', 'calc_max_item_end', - 'calc_max_number_of_children', 'calc_min_align', 'calc_number_of_children', + 'calc_offset_base', 'calc_prefix_color', 'calc_probable_base_by_value', - 'calc_reference_basevalue', - 'calc_reference_target', + 'calc_reference_data', 'calc_stkvar_struc_offset', 'calc_switch_cases', 'calc_target', 'calc_thunk_func_target', 'calc_tinfo_gaps', 'calc_type_size', - 'calc_varloc_info', - 'calcexpr', - 'call_helper', - 'call_helper__varargs__', - 'call_idc_method', 'call_nav_colorizer', - 'call_script_method', 'call_stack_info_t___eq__', 'call_stack_info_t___ne__', 'call_stack_info_t_callea_get', @@ -1017,8 +880,6 @@ 'call_stack_info_t_funcok_set', 'call_stack_t_dirty_get', 'call_stack_t_dirty_set', - 'call_system', - 'callregs_init_regs', 'callregs_t_fpregs_get', 'callregs_t_fpregs_set', 'callregs_t_gpregs_get', @@ -1033,6 +894,7 @@ 'callregs_t_reset', 'callregs_t_set', 'can_be_off32', + 'can_decode', 'can_define_item', 'can_exc_continue', 'cancel_exec_request', @@ -1069,9 +931,6 @@ 'casevec_t__del', 'casevec_t_add_unique', 'casevec_t_at', - 'casevec_t_back', - 'casevec_t_back__SWIG_0', - 'casevec_t_back__SWIG_1', 'casevec_t_begin', 'casevec_t_begin__SWIG_0', 'casevec_t_begin__SWIG_1', @@ -1088,9 +947,6 @@ 'casevec_t_find', 'casevec_t_find__SWIG_0', 'casevec_t_find__SWIG_1', - 'casevec_t_front', - 'casevec_t_front__SWIG_0', - 'casevec_t_front__SWIG_1', 'casevec_t_grow', 'casevec_t_has', 'casevec_t_inject', @@ -1115,12 +971,57 @@ 'casm_t___ne__', 'casm_t_compare', 'casm_t_one_insn', + 'catch_t_obj_get', + 'catch_t_obj_set', + 'catch_t_type_id_get', + 'catch_t_type_id_set', + 'catchvec_t___eq__', + 'catchvec_t___getitem__', + 'catchvec_t___len__', + 'catchvec_t___ne__', + 'catchvec_t___setitem__', + 'catchvec_t__del', + 'catchvec_t_add_unique', + 'catchvec_t_at', + 'catchvec_t_begin', + 'catchvec_t_begin__SWIG_0', + 'catchvec_t_begin__SWIG_1', + 'catchvec_t_capacity', + 'catchvec_t_clear', + 'catchvec_t_empty', + 'catchvec_t_end', + 'catchvec_t_end__SWIG_0', + 'catchvec_t_end__SWIG_1', + 'catchvec_t_erase', + 'catchvec_t_erase__SWIG_0', + 'catchvec_t_erase__SWIG_1', + 'catchvec_t_extract', + 'catchvec_t_find', + 'catchvec_t_find__SWIG_0', + 'catchvec_t_find__SWIG_1', + 'catchvec_t_grow', + 'catchvec_t_has', + 'catchvec_t_inject', + 'catchvec_t_insert', + 'catchvec_t_pop_back', + 'catchvec_t_push_back', + 'catchvec_t_push_back__SWIG_0', + 'catchvec_t_push_back__SWIG_1', + 'catchvec_t_qclear', + 'catchvec_t_reserve', + 'catchvec_t_resize', + 'catchvec_t_resize__SWIG_0', + 'catchvec_t_resize__SWIG_1', + 'catchvec_t_size', + 'catchvec_t_swap', + 'catchvec_t_truncate', 'cblock_t___eq__', 'cblock_t___ge__', 'cblock_t___gt__', 'cblock_t___le__', 'cblock_t___lt__', 'cblock_t___ne__', + 'cblock_t__deregister', 'cblock_t_compare', 'ccase_t___eq__', 'ccase_t___ge__', @@ -1155,7 +1056,35 @@ 'cexpr_t___le__', 'cexpr_t___lt__', 'cexpr_t___ne__', - 'cexpr_t_a_get', + 'cexpr_t__deregister', + 'cexpr_t__get_a', + 'cexpr_t__get_fpc', + 'cexpr_t__get_helper', + 'cexpr_t__get_insn', + 'cexpr_t__get_m', + 'cexpr_t__get_n', + 'cexpr_t__get_obj_ea', + 'cexpr_t__get_ptrsize', + 'cexpr_t__get_refwidth', + 'cexpr_t__get_string', + 'cexpr_t__get_x', + 'cexpr_t__get_y', + 'cexpr_t__get_z', + 'cexpr_t__register', + 'cexpr_t__replace_by', + 'cexpr_t__set_a', + 'cexpr_t__set_fpc', + 'cexpr_t__set_helper', + 'cexpr_t__set_insn', + 'cexpr_t__set_m', + 'cexpr_t__set_n', + 'cexpr_t__set_obj_ea', + 'cexpr_t__set_ptrsize', + 'cexpr_t__set_refwidth', + 'cexpr_t__set_string', + 'cexpr_t__set_x', + 'cexpr_t__set_y', + 'cexpr_t__set_z', 'cexpr_t_assign', 'cexpr_t_calc_type', 'cexpr_t_cleanup', @@ -1175,16 +1104,14 @@ 'cexpr_t_find_op', 'cexpr_t_find_op__SWIG_0', 'cexpr_t_find_op__SWIG_1', - 'cexpr_t_fpc_get', 'cexpr_t_get_1num_op', 'cexpr_t_get_const_value', 'cexpr_t_get_high_nbit_bound', 'cexpr_t_get_low_nbit_bound', 'cexpr_t_get_ptr_or_array', 'cexpr_t_get_type_sign', + 'cexpr_t_get_v', 'cexpr_t_has_side_effects', - 'cexpr_t_helper_get', - 'cexpr_t_insn_get', 'cexpr_t_is_call_arg_of', 'cexpr_t_is_call_object_of', 'cexpr_t_is_child_of', @@ -1196,30 +1123,22 @@ 'cexpr_t_is_nice_expr', 'cexpr_t_is_non_zero_const', 'cexpr_t_is_odd_lvalue', + 'cexpr_t_is_type_signed', + 'cexpr_t_is_type_unsigned', 'cexpr_t_is_zero_const', - 'cexpr_t_m_get', 'cexpr_t_maybe_ptr', - 'cexpr_t_n_get', 'cexpr_t_numval', - 'cexpr_t_obj_ea_get', 'cexpr_t_print1', - 'cexpr_t_ptrsize_get', 'cexpr_t_put_number', - 'cexpr_t_refwidth_get', - 'cexpr_t_replace_by', 'cexpr_t_requires_lvalue', 'cexpr_t_set_cpadone', - 'cexpr_t_string_get', + 'cexpr_t_set_v', 'cexpr_t_swap', 'cexpr_t_theother', 'cexpr_t_theother__SWIG_0', 'cexpr_t_theother__SWIG_1', 'cexpr_t_type_get', 'cexpr_t_type_set', - 'cexpr_t_v_get', - 'cexpr_t_x_get', - 'cexpr_t_y_get', - 'cexpr_t_z_get', 'cfg_get_cc_header_path', 'cfg_get_cc_parm', 'cfg_get_cc_predefined_macros', @@ -1253,6 +1172,7 @@ 'cfunc_t_get_line_item', 'cfunc_t_get_lvars', 'cfunc_t_get_pseudocode', + 'cfunc_t_get_stkoff_delta', 'cfunc_t_get_user_cmt', 'cfunc_t_get_user_iflags', 'cfunc_t_get_user_union_selection', @@ -1312,6 +1232,7 @@ 'cfuncptr_t_get_line_item', 'cfuncptr_t_get_lvars', 'cfuncptr_t_get_pseudocode', + 'cfuncptr_t_get_stkoff_delta', 'cfuncptr_t_get_user_cmt', 'cfuncptr_t_get_user_iflags', 'cfuncptr_t_get_user_union_selection', @@ -1363,7 +1284,6 @@ 'cgoto_t_compare', 'cgoto_t_label_num_get', 'cgoto_t_label_num_set', - 'change_encoding_name', 'change_segment_status', 'change_storage_type', 'channel_redir_t_fd_get', @@ -1380,44 +1300,42 @@ 'channel_redir_t_length_set', 'channel_redir_t_start_get', 'channel_redir_t_start_set', - 'charflag', + 'char_flag', 'check_bpt', 'check_process_exit', - 'check_skip_type', 'check_type_trait', 'check_type_trait__SWIG_0', 'check_type_trait__SWIG_1', - 'choose2_activate', - 'choose2_add_command', - 'choose2_close', - 'choose2_create', - 'choose2_find', - 'choose2_get_embedded', - 'choose2_get_embedded_selection', - 'choose2_refresh', - 'choose_choose', - 'choose_enter', + 'choose_activate', + 'choose_close', + 'choose_create', 'choose_entry', 'choose_enum', 'choose_enum_by_value', + 'choose_find', 'choose_func', - 'choose_getl', + 'choose_get_embedded', + 'choose_get_embedded_selection', + 'choose_get_widget', 'choose_idasgn', 'choose_local_tinfo', - 'choose_local_type', 'choose_name', - 'choose_named_type2', + 'choose_named_type', + 'choose_refresh', 'choose_segm', - 'choose_segreg', - 'choose_sizer', 'choose_srcp', 'choose_stkvar_xref', 'choose_struc', 'choose_til', 'choose_trace_file', 'choose_xref', - 'chunksize', - 'chunkstart', + 'chooser_item_attrs_t_color_get', + 'chooser_item_attrs_t_color_set', + 'chooser_item_attrs_t_flags_get', + 'chooser_item_attrs_t_flags_set', + 'chooser_item_attrs_t_reset', + 'chunk_size', + 'chunk_start', 'cif_t___eq__', 'cif_t___ge__', 'cif_t___gt__', @@ -1437,15 +1355,31 @@ 'cinsn_t___le__', 'cinsn_t___lt__', 'cinsn_t___ne__', + 'cinsn_t__deregister', + 'cinsn_t__get_casm', + 'cinsn_t__get_cblock', + 'cinsn_t__get_cdo', + 'cinsn_t__get_cexpr', + 'cinsn_t__get_cfor', + 'cinsn_t__get_cgoto', + 'cinsn_t__get_cif', + 'cinsn_t__get_creturn', + 'cinsn_t__get_cswitch', + 'cinsn_t__get_cwhile', 'cinsn_t__print', + 'cinsn_t__register', + 'cinsn_t__replace_by', + 'cinsn_t__set_casm', + 'cinsn_t__set_cblock', + 'cinsn_t__set_cdo', + 'cinsn_t__set_cexpr', + 'cinsn_t__set_cfor', + 'cinsn_t__set_cgoto', + 'cinsn_t__set_cif', + 'cinsn_t__set_creturn', + 'cinsn_t__set_cswitch', + 'cinsn_t__set_cwhile', 'cinsn_t_assign', - 'cinsn_t_casm_get', - 'cinsn_t_cblock_get', - 'cinsn_t_cdo_get', - 'cinsn_t_cexpr_get', - 'cinsn_t_cfor_get', - 'cinsn_t_cgoto_get', - 'cinsn_t_cif_get', 'cinsn_t_cleanup', 'cinsn_t_collect_free_breaks', 'cinsn_t_collect_free_continues', @@ -1454,14 +1388,10 @@ 'cinsn_t_contains_free_continue', 'cinsn_t_contains_insn', 'cinsn_t_create_if', - 'cinsn_t_creturn_get', - 'cinsn_t_cswitch_get', - 'cinsn_t_cwhile_get', - 'cinsn_t_is_epilog', + 'cinsn_t_insn_is_epilog', 'cinsn_t_is_ordinary_flow', 'cinsn_t_new_insn', 'cinsn_t_print1', - 'cinsn_t_replace_by', 'cinsn_t_swap', 'cinsn_t_zero', 'cinsnptrvec_t___eq__', @@ -1472,9 +1402,6 @@ 'cinsnptrvec_t__del', 'cinsnptrvec_t_add_unique', 'cinsnptrvec_t_at', - 'cinsnptrvec_t_back', - 'cinsnptrvec_t_back__SWIG_0', - 'cinsnptrvec_t_back__SWIG_1', 'cinsnptrvec_t_begin', 'cinsnptrvec_t_begin__SWIG_0', 'cinsnptrvec_t_begin__SWIG_1', @@ -1491,9 +1418,6 @@ 'cinsnptrvec_t_find', 'cinsnptrvec_t_find__SWIG_0', 'cinsnptrvec_t_find__SWIG_1', - 'cinsnptrvec_t_front', - 'cinsnptrvec_t_front__SWIG_0', - 'cinsnptrvec_t_front__SWIG_1', 'cinsnptrvec_t_has', 'cinsnptrvec_t_inject', 'cinsnptrvec_t_insert', @@ -1524,6 +1448,9 @@ 'citem_locator_t_ea_set', 'citem_locator_t_op_get', 'citem_locator_t_op_set', + 'citem_t__get_op', + 'citem_t__obj_id', + 'citem_t__set_op', 'citem_t_cexpr_get', 'citem_t_cinsn_get', 'citem_t_contains_label', @@ -1537,17 +1464,14 @@ 'citem_t_is_expr', 'citem_t_label_num_get', 'citem_t_label_num_set', - 'citem_t_op_get', - 'citem_t_op_set', 'citem_t_print1', 'citem_t_swap', 'cleanup_appcall', 'cleanup_name', - 'cleanup_varloc', - 'clearBreak', 'clear_cached_cfuncs', - 'clear_func_struct', + 'clear_refresh_request', 'clear_requests_queue', + 'clear_strlist', 'clear_tinfo_t', 'clear_trace', 'cloop_t_assign', @@ -1557,14 +1481,16 @@ 'close_chooser', 'close_linput', 'close_pseudocode', - 'close_tform', + 'close_widget', 'clr__bnot0', 'clr__bnot1', 'clr__invsign0', 'clr__invsign1', 'clr_abits', 'clr_align_flow', + 'clr_cancelled', 'clr_colored_item', + 'clr_database_flag', 'clr_fixed_spd', 'clr_has_lname', 'clr_has_ti', @@ -1574,9 +1500,11 @@ 'clr_lzero', 'clr_lzero0', 'clr_lzero1', - 'clr_node_info2', + 'clr_node_info', 'clr_noret', 'clr_notcode', + 'clr_notproc', + 'clr_op_type', 'clr_retfp', 'clr_terse_struc', 'clr_tilcmt', @@ -1598,13 +1526,24 @@ 'cnumber_t_nf_get', 'cnumber_t_nf_set', 'cnumber_t_value', - 'codeSeg', - 'codeflag', + 'code_flag', + 'codegen_t_analyze_prolog', + 'codegen_t_gen_micro', + 'codegen_t_ignore_micro_get', + 'codegen_t_ignore_micro_set', + 'codegen_t_insn_get', + 'codegen_t_insn_set', + 'codegen_t_load_operand', + 'codegen_t_mb_get', + 'codegen_t_mb_set', + 'codegen_t_mba_get', + 'codegen_t_mba_set', 'compact_til', 'compare', 'compare', 'compare', - 'compare__SWIG_1', + 'compare__SWIG_10', + 'compare__SWIG_11', 'compare__SWIG_12', 'compare__SWIG_13', 'compare__SWIG_14', @@ -1613,7 +1552,6 @@ 'compare__SWIG_17', 'compare__SWIG_18', 'compare__SWIG_19', - 'compare__SWIG_2', 'compare__SWIG_20', 'compare__SWIG_21', 'compare__SWIG_22', @@ -1624,23 +1562,25 @@ 'compare__SWIG_27', 'compare__SWIG_28', 'compare__SWIG_29', - 'compare__SWIG_3', - 'compare__SWIG_3', 'compare__SWIG_30', - 'compare__SWIG_4', 'compare__SWIG_5', 'compare__SWIG_6', 'compare__SWIG_7', + 'compare__SWIG_7', + 'compare__SWIG_8', + 'compare__SWIG_9', 'compare_tinfo', 'compare_typsrc', - 'compile_script_file', - 'compile_script_func', + 'compile_idc_file', + 'compile_idc_snippet', + 'compile_idc_text', 'compiler_info_t_cm_get', 'compiler_info_t_cm_set', 'compiler_info_t_defalign_get', 'compiler_info_t_defalign_set', 'compiler_info_t_id_get', 'compiler_info_t_id_set', + 'compiler_info_t_set_64bit_pointer_size', 'compiler_info_t_size_b_get', 'compiler_info_t_size_b_set', 'compiler_info_t_size_e_get', @@ -1649,47 +1589,64 @@ 'compiler_info_t_size_i_set', 'compiler_info_t_size_l_get', 'compiler_info_t_size_l_set', + 'compiler_info_t_size_ldbl_get', + 'compiler_info_t_size_ldbl_set', 'compiler_info_t_size_ll_get', 'compiler_info_t_size_ll_set', 'compiler_info_t_size_s_get', 'compiler_info_t_size_s_set', 'const_aloc_visitor_t_visit_location', - 'const_visitor_t_visit_const', - 'const_vloc_visitor_t_visit_location', 'construct_macro', 'contains_fixups', 'continue_process', - 'convert_argloc_to_varloc', - 'convert_encoding', 'convert_pt_flags_to_hti', 'convert_to_user_call', - 'convert_varloc_to_argloc', - 'copy_srareas', + 'copy_idcv', + 'copy_sreg_ranges', 'copy_tinfo_t', - 'copy_varloc', + 'create_16bit_data', + 'create_32bit_data', + 'create_align', + 'create_byte', 'create_bytearray_linput', 'create_code_viewer', - 'create_custom_fixup', - 'create_ea_viewer', + 'create_custdata', + 'create_data', + 'create_disasm_graph', + 'create_disasm_graph__SWIG_0', + 'create_disasm_graph__SWIG_1', + 'create_double', + 'create_dword', + 'create_empty_widget', 'create_field_name', + 'create_float', 'create_generic_linput', - 'create_generic_linput64', - 'create_helper', - 'create_helper__varargs__', + 'create_graph_viewer', + 'create_idcv_ref', 'create_insn', 'create_memory_linput', 'create_menu', + 'create_mutable_graph', 'create_numbered_type_name', - 'create_numbered_type_reference', + 'create_outctx', + 'create_oword', + 'create_packed_real', + 'create_qword', 'create_source_viewer', + 'create_strlit', + 'create_struct', 'create_switch_table', 'create_switch_xrefs', - 'create_tform', + 'create_tbyte', 'create_tinfo', 'create_toolbar', 'create_typedef', 'create_typedef__SWIG_0', 'create_typedef__SWIG_1', + 'create_user_graph_place', + 'create_word', + 'create_yword', + 'create_zword', 'creturn_t___eq__', 'creturn_t___ge__', 'creturn_t___gt__', @@ -1731,18 +1688,18 @@ 'ctree_anchor_t_is_valid_anchor', 'ctree_anchor_t_value_get', 'ctree_anchor_t_value_set', + 'ctree_item_t__get_e', + 'ctree_item_t__get_f', + 'ctree_item_t__get_i', + 'ctree_item_t__get_it', + 'ctree_item_t__get_l', 'ctree_item_t_citype_get', 'ctree_item_t_citype_set', - 'ctree_item_t_e_get', - 'ctree_item_t_f_get', 'ctree_item_t_get_ea', 'ctree_item_t_get_label_num', 'ctree_item_t_get_lvar', 'ctree_item_t_get_memptr', - 'ctree_item_t_i_get', 'ctree_item_t_is_citem', - 'ctree_item_t_it_get', - 'ctree_item_t_l_get', 'ctree_item_t_loc_get', 'ctree_items_t___eq__', 'ctree_items_t___getitem__', @@ -1752,9 +1709,6 @@ 'ctree_items_t__del', 'ctree_items_t_add_unique', 'ctree_items_t_at', - 'ctree_items_t_back', - 'ctree_items_t_back__SWIG_0', - 'ctree_items_t_back__SWIG_1', 'ctree_items_t_begin', 'ctree_items_t_begin__SWIG_0', 'ctree_items_t_begin__SWIG_1', @@ -1771,9 +1725,6 @@ 'ctree_items_t_find', 'ctree_items_t_find__SWIG_0', 'ctree_items_t_find__SWIG_1', - 'ctree_items_t_front', - 'ctree_items_t_front__SWIG_0', - 'ctree_items_t_front__SWIG_1', 'ctree_items_t_has', 'ctree_items_t_inject', 'ctree_items_t_insert', @@ -1811,34 +1762,13 @@ 'ctree_visitor_t_set_restart', 'ctree_visitor_t_visit_expr', 'ctree_visitor_t_visit_insn', - 'curloc_copy_current_location', - 'curloc_ea_get', - 'curloc_ea_set', - 'curloc_flags_get', - 'curloc_flags_set', - 'curloc_get', - 'curloc_get_entry', - 'curloc_hide_if_necessary', - 'curloc_jump', - 'curloc_jump_push', - 'curloc_linkTo', - 'curloc_lnnum_get', - 'curloc_lnnum_set', - 'curloc_mark', - 'curloc_markdesc', - 'curloc_markedpos', - 'curloc_pop', - 'curloc_setx', - 'curloc_size', - 'curloc_target_get', - 'curloc_target_set', - 'curloc_unhide_if_necessary', - 'curloc_x_get', - 'curloc_x_set', - 'curloc_y_get', - 'curloc_y_set', - 'custflag', - 'custfmtflag', + 'cust_flag', + 'custfmt_flag', + 'custom_data_type_ids_fids_array___getitem__', + 'custom_data_type_ids_fids_array___len__', + 'custom_data_type_ids_fids_array___setitem__', + 'custom_data_type_ids_fids_array_data_get', + 'custom_data_type_ids_t___getFids', 'custom_data_type_ids_t_dtid_get', 'custom_data_type_ids_t_dtid_set', 'custom_data_type_ids_t_fids_get', @@ -1851,9 +1781,32 @@ 'cwhile_t___lt__', 'cwhile_t___ne__', 'cwhile_t_compare', - 'dataSeg', - 'dataSeg_op', - 'dataSeg_opreg', + 'data_format_t___get_id', + 'data_format_t_hotkey_get', + 'data_format_t_hotkey_set', + 'data_format_t_menu_name_get', + 'data_format_t_menu_name_set', + 'data_format_t_name_get', + 'data_format_t_name_set', + 'data_format_t_props_get', + 'data_format_t_props_set', + 'data_format_t_text_width_get', + 'data_format_t_text_width_set', + 'data_format_t_value_size_get', + 'data_format_t_value_size_set', + 'data_type_t___get_id', + 'data_type_t_asm_keyword_get', + 'data_type_t_asm_keyword_set', + 'data_type_t_hotkey_get', + 'data_type_t_hotkey_set', + 'data_type_t_menu_name_get', + 'data_type_t_menu_name_set', + 'data_type_t_name_get', + 'data_type_t_name_set', + 'data_type_t_props_get', + 'data_type_t_props_set', + 'data_type_t_value_size_get', + 'data_type_t_value_size_set', 'dbg_add_bpt_tev', 'dbg_add_call_tev', 'dbg_add_debug_event', @@ -1900,14 +1853,15 @@ 'debug_event_t_pid_set', 'debug_event_t_tid_get', 'debug_event_t_tid_set', - 'decflag', + 'dec_flag', 'decode_insn', 'decode_preceding_insn', 'decode_prev_insn', 'decompile_many', + 'deep_copy_idcv', 'default_compiler', 'define_exception', - 'delValue', + 'define_stkvar', 'del_absbase', 'del_aflags', 'del_alignment', @@ -1916,7 +1870,6 @@ 'del_bpt__SWIG_0', 'del_bpt__SWIG_1', 'del_bptgrp', - 'del_const', 'del_cref', 'del_custom_data_type_ids', 'del_debug_names', @@ -1928,47 +1881,50 @@ 'del_fixup', 'del_frame', 'del_func', - 'del_func_cmt', 'del_global_name', - 'del_hidden_area', + 'del_hidden_range', 'del_hotkey', 'del_idasgn', 'del_idc_hotkey', + 'del_idcv_attr', 'del_ind_purged', 'del_item_color', - 'del_jumptable_info', + 'del_items', 'del_local_name', + 'del_mapping', 'del_member_tinfo', - 'del_menu_item', 'del_named_type', - 'del_node_info2', + 'del_node_info', 'del_numbered_type', + 'del_op_tinfo', 'del_refinfo', 'del_regvar', 'del_segm', - 'del_segment_cmt', 'del_segment_translations', 'del_selector', 'del_source_linnum', 'del_sourcefile', - 'del_srarea', + 'del_sreg_range', 'del_stkpnt', + 'del_str_type', 'del_struc', 'del_struc_member', 'del_struc_members', - 'del_switch_info_ex', + 'del_switch_info', 'del_switch_parent', 'del_til', - 'del_tinfo2', - 'del_tinfo2__SWIG_0', - 'del_tinfo2__SWIG_1', + 'del_tinfo', 'del_tinfo_attr', + 'del_tryblks', + 'del_value', 'del_virt_module', 'delay_slot_insn', 'delete_DBG_Hooks', 'delete_IDB_Hooks', 'delete_IDP_Hooks', + 'delete_TPointDouble', 'delete_UI_Hooks', + 'delete_View_Hooks', 'delete___qmutex_t', 'delete___qsemaphore_t', 'delete___qthread_t', @@ -1979,11 +1935,6 @@ 'delete_action_update_ctx_t', 'delete_addon_info_t', 'delete_aloc_visitor_t', - 'delete_area_t', - 'delete_area_visitor2_t', - 'delete_areacb_t', - 'delete_areaset_t', - 'delete_areavec_t', 'delete_argloc_t', 'delete_argpart_t', 'delete_array_parameters_t', @@ -2006,6 +1957,8 @@ 'delete_cases_and_targets_t', 'delete_casevec_t', 'delete_casm_t', + 'delete_catch_t', + 'delete_catchvec_t', 'delete_cblock_t', 'delete_ccase_t', 'delete_ccases_t', @@ -2018,6 +1971,7 @@ 'delete_cfuncptr_t', 'delete_cgoto_t', 'delete_channel_redir_t', + 'delete_chooser_item_attrs_t', 'delete_cif_t', 'delete_cinsn_t', 'delete_cinsnptrvec_t', @@ -2026,10 +1980,9 @@ 'delete_citem_t', 'delete_cloop_t', 'delete_cnumber_t', + 'delete_codegen_t', 'delete_compiler_info_t', 'delete_const_aloc_visitor_t', - 'delete_const_visitor_t', - 'delete_const_vloc_visitor_t', 'delete_creturn_t', 'delete_cswitch_t', 'delete_ctext_position_t', @@ -2038,9 +1991,11 @@ 'delete_ctree_items_t', 'delete_ctree_parentee_t', 'delete_ctree_visitor_t', - 'delete_curloc', + 'delete_custom_data_type_ids_fids_array', 'delete_custom_data_type_ids_t', 'delete_cwhile_t', + 'delete_data_format_t', + 'delete_data_type_t', 'delete_debapp_attrs_t', 'delete_debug_event_t', 'delete_disasm_line_t', @@ -2052,6 +2007,10 @@ 'delete_ea_pointer', 'delete_eamap_iterator_t', 'delete_eamap_t', + 'delete_edge_info_t', + 'delete_edge_layout_point_t', + 'delete_edge_segment_t', + 'delete_edge_t', 'delete_enum_const_t', 'delete_enum_member_t', 'delete_enum_member_visitor_t', @@ -2062,55 +2021,53 @@ 'delete_excvec_t', 'delete_extra_cmts', 'delete_fixup_data_t', + 'delete_fixup_info_t', + 'delete_fnum_array', 'delete_fnumber_t', 'delete_func_item_iterator_t', 'delete_func_parent_iterator_t', 'delete_func_t', 'delete_func_tail_iterator_t', 'delete_func_type_data_t', - 'delete_func_type_info_t', - 'delete_funcarg_info_t', 'delete_funcarg_t', 'delete_funcargvec_t', - 'delete_generic_linput64_t', 'delete_generic_linput_t', - 'delete_get_strmem_t', + 'delete_graph_item_t', 'delete_graph_location_info_t', + 'delete_graph_node_visitor_t', + 'delete_graph_path_visitor_t', + 'delete_graph_visitor_t', + 'delete_group_crinfo_t', 'delete_hexrays_failure_t', 'delete_hexwarn_t', 'delete_hexwarns_t', - 'delete_hidden_area_t', + 'delete_hidden_range_t', 'delete_highlighter_cbs_t', 'delete_history_item_t', 'delete_history_t', - 'delete_ida_false_type', 'delete_ida_lowertype_helper_t', - 'delete_ida_true_type', - 'delete_idainfo', 'delete_idaplace_t', 'delete_idc_global_t', 'delete_idc_value_t', - 'delete_idd_opinfo_old_t', + 'delete_idc_values_t', 'delete_idp_desc_t', 'delete_idp_name_t', - 'delete_ids_array', + 'delete_imports', + 'delete_insn_t', 'delete_instant_dbgopts_t', 'delete_int64vec_t', 'delete_int_pointer', + 'delete_interval_t', 'delete_intvec_t', - 'delete_jumptable_info_t', 'delete_linput_buffer_t', 'delete_llabel_t', 'delete_loader_input_t', 'delete_loader_t', - 'delete_location_t', 'delete_locchange_md_t', 'delete_lochist_entry_t', 'delete_lochist_t', - 'delete_lock_area', 'delete_lock_func', 'delete_lock_segment', - 'delete_lock_segreg', 'delete_lowertype_helper_t', 'delete_lvar_locator_t', 'delete_lvar_mapping_iterator_t', @@ -2126,16 +2083,26 @@ 'delete_menu', 'delete_microcode_filter_t', 'delete_module_info_t', + 'delete_mutable_graph', + 'delete_mutable_graph_t', 'delete_netnode', 'delete_node_info_t', 'delete_node_iterator', + 'delete_node_ordering_t', 'delete_number_format_t', + 'delete_op_t', 'delete_operand_locator_t', + 'delete_operands_array', 'delete_operator_info_t', 'delete_opinfo_t', 'delete_place_t', 'delete_plugin_info_t', + 'delete_point_t', + 'delete_pointseq_t', + 'delete_predicate_t', + 'delete_printop_t', 'delete_process_info_t', + 'delete_procinfo_vec_t', 'delete_ptr_type_data_t', 'delete_qbasic_block_t', 'delete_qfile_t', @@ -2149,6 +2116,11 @@ 'delete_qvector_history_t', 'delete_qvector_lvar_t', 'delete_qvector_snapshotvec_t', + 'delete_range_t', + 'delete_rangeset_t', + 'delete_rangevec_base_t', + 'delete_rangevec_t', + 'delete_rect_t', 'delete_refinfo_t', 'delete_reg_info_t', 'delete_regarg_t', @@ -2157,25 +2129,31 @@ 'delete_regobjs_t', 'delete_regval_t', 'delete_regvar_t', + 'delete_renderer_info_pos_t', 'delete_renderer_info_t', 'delete_renderer_pos_info_t', + 'delete_row_info_t', 'delete_rrel_t', 'delete_scattered_aloc_t', - 'delete_scattered_vloc_t', + 'delete_scattered_segm_t', + 'delete_screen_graph_selection_t', 'delete_segm_move_info_t', 'delete_segm_move_info_vec_t', 'delete_segm_move_infos_t', 'delete_segment_t', - 'delete_segreg_area_t', - 'delete_segreg_t', + 'delete_seh_t', 'delete_sel_array', 'delete_sel_pointer', + 'delete_selection_item_t', 'delete_simd_info_t', 'delete_simpleline_place_t', 'delete_simpleline_t', + 'delete_sizevec_t', 'delete_snapshot_t', + 'delete_sreg_range_t', 'delete_strarray_t', 'delete_string_info_t', + 'delete_strpath_ids_array', 'delete_strpath_t', 'delete_struc_t', 'delete_struct_field_visitor_t', @@ -2184,7 +2162,6 @@ 'delete_strwinsetup_t', 'delete_sval_pointer', 'delete_tev_info_t', - 'delete_text_options_t', 'delete_text_sink_t', 'delete_tid_array', 'delete_til_symbol_t', @@ -2193,13 +2170,13 @@ 'delete_tinfo_visitor_t', 'delete_toolbar', 'delete_treeloc_t', + 'delete_try_handler_t', + 'delete_tryblk_t', + 'delete_tryblks_t', 'delete_twinpos_t', 'delete_type_attr_t', - 'delete_type_mapper_t', + 'delete_type_attrs_t', 'delete_type_mods_t', - 'delete_type_pair_t', - 'delete_type_pair_vec_t', - 'delete_type_visitor_t', 'delete_typedef_type_data_t', 'delete_uchar_array', 'delete_udc_filter_t', @@ -2212,6 +2189,7 @@ 'delete_unreferenced_stkvars', 'delete_user_cmts_iterator_t', 'delete_user_cmts_t', + 'delete_user_graph_place_t', 'delete_user_iflags_iterator_t', 'delete_user_iflags_t', 'delete_user_labels_iterator_t', @@ -2224,34 +2202,28 @@ 'delete_uval_array', 'delete_uvalvec_t', 'delete_valstr_t', - 'delete_valstrs_deprecated2_t', - 'delete_valstrs_deprecated_t', 'delete_valstrs_t', 'delete_var_ref_t', - 'delete_varloc_t', - 'delete_varpart_t', 'delete_vc_printer_t', 'delete_vd_failure_t', 'delete_vd_interr_t', 'delete_vd_printer_t', 'delete_vdloc_t', 'delete_vdui_t', - 'delete_vloc_visitor_t', + 'delete_view_mouse_event_location_t', + 'delete_view_mouse_event_t', 'delete_wrong_stkvar_ops', 'delete_xrefblk_t', 'delete_xreflist_entry_t', 'delete_xreflist_t', 'demangle_name', - 'demangle_name2', + 'deref_idcv', 'deref_ptr', - 'deref_ptr2', - 'dereference', - 'describe', - 'describe__varargs__', 'deserialize_tinfo', 'detach_action_from_menu', 'detach_action_from_popup', 'detach_action_from_toolbar', + 'detach_custom_data_format', 'detach_process', 'diff_trace_file', 'disable_flags', @@ -2270,9 +2242,6 @@ 'disasm_text_t___len__', 'disasm_text_t___setitem__', 'disasm_text_t_at', - 'disasm_text_t_back', - 'disasm_text_t_back__SWIG_0', - 'disasm_text_t_back__SWIG_1', 'disasm_text_t_begin', 'disasm_text_t_begin__SWIG_0', 'disasm_text_t_begin__SWIG_1', @@ -2286,9 +2255,6 @@ 'disasm_text_t_erase__SWIG_0', 'disasm_text_t_erase__SWIG_1', 'disasm_text_t_extract', - 'disasm_text_t_front', - 'disasm_text_t_front__SWIG_0', - 'disasm_text_t_front__SWIG_1', 'disasm_text_t_grow', 'disasm_text_t_inject', 'disasm_text_t_insert', @@ -2308,58 +2274,34 @@ 'disown_IDB_Hooks', 'disown_IDP_Hooks', 'disown_UI_Hooks', + 'disown_View_Hooks', 'disown_aloc_visitor_t', - 'disown_area_visitor2_t', 'disown_cfunc_parentee_t', + 'disown_codegen_t', 'disown_const_aloc_visitor_t', 'disown_ctree_parentee_t', 'disown_ctree_visitor_t', 'disown_enum_member_visitor_t', + 'disown_graph_node_visitor_t', + 'disown_graph_path_visitor_t', + 'disown_graph_visitor_t', 'disown_highlighter_cbs_t', 'disown_microcode_filter_t', + 'disown_mutable_graph_t', + 'disown_predicate_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', - 'display_flow_graph', 'display_gdl', - 'display_simple_call_chart', - 'do16bit', - 'do32bit', - 'do3byte', - 'doASCI', - 'doAlign', - 'doByte', - 'doCustomData', - 'doDouble', - 'doDwrd', - 'doFloat', - 'doImmd', - 'doOwrd', - 'doPackReal', - 'doQwrd', - 'doStruct', - 'doTbyt', - 'doVar', - 'doWord', - 'doYwrd', - 'doZwrd', - 'do_data_ex', - 'do_name_anyway', - 'do_unknown', - 'do_unknown_range', - 'dosysfile', - 'doubleflag', + 'display_widget', + 'double_flag', 'dstr_tinfo', - 'dto_copy_from_inf', - 'dto_copy_to_inf', - 'dto_init', 'dummy_ptrtype', 'dump_func_type_data', - 'dwrdflag', + 'dword_flag', 'e_breakpoint_t_hea_get', 'e_breakpoint_t_hea_set', 'e_breakpoint_t_kea_get', @@ -2372,6 +2314,7 @@ 'e_exception_t_ea_set', 'e_exception_t_info_get', 'e_exception_t_info_set', + 'ea2node', 'ea2str', 'ea_array___getitem__', 'ea_array___setitem__', @@ -2405,12 +2348,48 @@ 'eamap_size', 'eamap_t_at', 'eamap_t_size', - 'echsize', - 'echsize64', 'eclose', - 'ecreate', - 'ecreateT', + 'edge_info_t_color_get', + 'edge_info_t_color_set', + 'edge_info_t_dstoff_get', + 'edge_info_t_dstoff_set', + 'edge_info_t_layout_get', + 'edge_info_t_layout_set', + 'edge_info_t_reverse_layout', + 'edge_info_t_srcoff_get', + 'edge_info_t_srcoff_set', + 'edge_info_t_width_get', + 'edge_info_t_width_set', + 'edge_infos_wrapper_t_clear', + 'edge_infos_wrapper_t_ptr_get', + 'edge_infos_wrapper_t_ptr_set', + 'edge_layout_point_t___eq__', + 'edge_layout_point_t___ne__', + 'edge_layout_point_t_compare', + 'edge_layout_point_t_e_get', + 'edge_layout_point_t_e_set', + 'edge_layout_point_t_pidx_get', + 'edge_layout_point_t_pidx_set', + 'edge_segment_t___lt__', + 'edge_segment_t_e_get', + 'edge_segment_t_e_set', + 'edge_segment_t_length', + 'edge_segment_t_nseg_get', + 'edge_segment_t_nseg_set', + 'edge_segment_t_toright', + 'edge_segment_t_x0_get', + 'edge_segment_t_x0_set', + 'edge_segment_t_x1_get', + 'edge_segment_t_x1_set', + 'edge_t___eq__', + 'edge_t___lt__', + 'edge_t___ne__', + 'edge_t_dst_get', + 'edge_t_dst_set', + 'edge_t_src_get', + 'edge_t_src_set', 'edit_manual_regions', + 'enable_auto', 'enable_bblk_trace', 'enable_bpt', 'enable_bpt__SWIG_0', @@ -2421,7 +2400,6 @@ 'enable_func_trace', 'enable_insn_trace', 'enable_manual_regions', - 'enable_menu_item', 'enable_python_cli', 'enable_step_trace', 'encoding_from_strtype', @@ -2430,6 +2408,7 @@ 'enum_const_t_serial_set', 'enum_const_t_tid_get', 'enum_const_t_tid_set', + 'enum_flag', 'enum_import_names', 'enum_member_t___eq__', 'enum_member_t___ne__', @@ -2456,7 +2435,6 @@ 'enum_type_data_t_taenum_bits_get', 'enum_type_data_t_taenum_bits_set', 'enumerate_files', - 'enumflag', 'enumplace_t_bmask_get', 'enumplace_t_bmask_set', 'enumplace_t_idx_get', @@ -2468,10 +2446,10 @@ 'equal_bytes', 'error', 'error__varargs__', - 'eseek', - 'eseek64', 'eval_ctx_t_ea_get', 'eval_ctx_t_ea_set', + 'eval_expr', + 'eval_idc_expr', 'exception_info_t_break_on', 'exception_info_t_code_get', 'exception_info_t_code_set', @@ -2486,9 +2464,6 @@ 'excvec_t___len__', 'excvec_t___setitem__', 'excvec_t_at', - 'excvec_t_back', - 'excvec_t_back__SWIG_0', - 'excvec_t_back__SWIG_1', 'excvec_t_begin', 'excvec_t_begin__SWIG_0', 'excvec_t_begin__SWIG_1', @@ -2502,9 +2477,6 @@ 'excvec_t_erase__SWIG_0', 'excvec_t_erase__SWIG_1', 'excvec_t_extract', - 'excvec_t_front', - 'excvec_t_front__SWIG_0', - 'excvec_t_front__SWIG_1', 'excvec_t_grow', 'excvec_t_inject', 'excvec_t_insert', @@ -2520,53 +2492,42 @@ 'excvec_t_size', 'excvec_t_swap', 'excvec_t_truncate', - 'execute', + 'exec_idc_script', + 'exec_system_script', 'execute_sync', 'execute_ui_requests', 'exist', + 'exists_fixup', 'exit_process', - 'expand_argv', 'expand_struc', 'extend_sign', - 'extlang_call_method_exists', - 'extlang_compile_file_exists', - 'extlang_run_statements_exists', - 'extlang_set_attr_exists', - 'extlang_unload_procmod', - 'extract_and_convert_old_argloc', + 'extract_argloc', 'extract_module_from_archive', 'extract_name', - 'extract_name2', - 'extract_old_argloc', - 'extract_old_argloc__SWIG_0', - 'extract_old_argloc__SWIG_1', - 'extract_varloc', 'f_any', - 'f_hasRef', 'f_has_dummy_name', 'f_has_name', 'f_has_user_name', - 'f_is3byte', - 'f_isASCII', - 'f_isAlign', - 'f_isByte', - 'f_isCode', - 'f_isCustom', - 'f_isData', - 'f_isDouble', - 'f_isDwrd', - 'f_isFloat', - 'f_isHead', - 'f_isNotTail', - 'f_isOwrd', - 'f_isPackReal', - 'f_isQwrd', - 'f_isStruct', - 'f_isTail', - 'f_isTbyt', - 'f_isUnknown', - 'f_isWord', - 'f_isYwrd', + 'f_has_xref', + 'f_is_align', + 'f_is_byte', + 'f_is_code', + 'f_is_custom', + 'f_is_data', + 'f_is_double', + 'f_is_dword', + 'f_is_float', + 'f_is_head', + 'f_is_not_tail', + 'f_is_oword', + 'f_is_pack_real', + 'f_is_qword', + 'f_is_strlit', + 'f_is_struct', + 'f_is_tail', + 'f_is_tbyte', + 'f_is_word', + 'f_is_yword', 'file2base', 'find_binary', 'find_bpt', @@ -2575,43 +2536,74 @@ 'find_code', 'find_custom_data_format', 'find_custom_data_type', + 'find_custom_fixup', + 'find_custom_refinfo', 'find_data', 'find_defined', 'find_error', - 'find_extlang_by_ext', - 'find_extlang_by_name', 'find_free_selector', 'find_func_bounds', 'find_idc_class', + 'find_idc_func', 'find_idc_gvar', 'find_imm', 'find_not_func', 'find_notype', + 'find_plugin', 'find_regvar', 'find_regvar__SWIG_0', 'find_regvar__SWIG_1', 'find_selector', + 'find_suspop', 'find_text', - 'find_tform', 'find_tinfo_udt_member', 'find_unknown', - 'find_void', + 'find_widget', + 'first_idcv_attr', 'first_named_type', + 'fixup_data_t_calc_size', + 'fixup_data_t_clr_extdef', + 'fixup_data_t_clr_unused', 'fixup_data_t_displacement_get', 'fixup_data_t_displacement_set', + 'fixup_data_t_get', + 'fixup_data_t_get_base', + 'fixup_data_t_get_desc', + 'fixup_data_t_get_flags', + 'fixup_data_t_get_handler', 'fixup_data_t_get_type', + 'fixup_data_t_get_value', + 'fixup_data_t_has_base', 'fixup_data_t_is_custom', + 'fixup_data_t_is_extdef', + 'fixup_data_t_is_unused', 'fixup_data_t_off_get', 'fixup_data_t_off_set', + 'fixup_data_t_patch_value', 'fixup_data_t_sel_get', 'fixup_data_t_sel_set', - 'fixup_data_t_type_get', - 'fixup_data_t_type_set', - 'floatflag', - 'fltflag', + 'fixup_data_t_set', + 'fixup_data_t_set_base', + 'fixup_data_t_set_extdef', + 'fixup_data_t_set_sel', + 'fixup_data_t_set_target_sel', + 'fixup_data_t_set_type', + 'fixup_data_t_set_type_and_flags', + 'fixup_data_t_set_unused', + 'fixup_info_t_ea_get', + 'fixup_info_t_ea_set', + 'fixup_info_t_fd_get', + 'fixup_info_t_fd_set', + 'float_flag', + 'flt_flag', 'flush_buffers', + 'fnum_array___getitem__', + 'fnum_array___len__', + 'fnum_array___setitem__', + 'fnum_array_data_get', 'fnumber_t___eq__', 'fnumber_t___ge__', + 'fnumber_t___get_fnum', 'fnumber_t___gt__', 'fnumber_t___le__', 'fnumber_t___lt__', @@ -2632,11 +2624,9 @@ 'fopenWT', 'for_all_arglocs', 'for_all_const_arglocs', - 'for_all_const_varlocs', - 'for_all_consts', 'for_all_enum_members', - 'for_all_types', - 'for_all_varlocs', + 'force_name', + 'forget_problem', 'formchgcbfa_close', 'formchgcbfa_enable_field', 'formchgcbfa_get_field_value', @@ -2650,10 +2640,10 @@ 'frame_off_lvars', 'frame_off_retaddr', 'frame_off_savregs', - 'free_argv', + 'free_chunk', 'free_custom_icon', + 'free_idcv', 'free_til', - 'freechunk', 'func_contains', 'func_does_return', 'func_has_stkframe_hole', @@ -2682,7 +2672,6 @@ 'func_item_iterator_t_set', 'func_item_iterator_t_set_range', 'func_parent_iterator_set', - 'func_parent_iterator_set2', 'func_parent_iterator_t_first', 'func_parent_iterator_t_last', 'func_parent_iterator_t_next', @@ -2690,8 +2679,6 @@ 'func_parent_iterator_t_prev', 'func_parent_iterator_t_reset_fnt', 'func_parent_iterator_t_set', - 'func_setend', - 'func_setstart', 'func_t_analyzed_sp', 'func_t_argsize_get', 'func_t_argsize_set', @@ -2736,7 +2723,6 @@ 'func_t_tails_get', 'func_t_tails_set', 'func_tail_iterator_set', - 'func_tail_iterator_set2', 'func_tail_iterator_set_ea', 'func_tail_iterator_t_chunk', 'func_tail_iterator_t_first', @@ -2755,6 +2741,8 @@ 'func_type_data_t_get_call_method', 'func_type_data_t_guess_cc', 'func_type_data_t_is_high', + 'func_type_data_t_is_noret', + 'func_type_data_t_is_pure', 'func_type_data_t_is_vararg_cc', 'func_type_data_t_retloc_get', 'func_type_data_t_retloc_set', @@ -2765,30 +2753,6 @@ 'func_type_data_t_stkargs_get', 'func_type_data_t_stkargs_set', 'func_type_data_t_swap', - 'func_type_info_t_basetype_get', - 'func_type_info_t_basetype_set', - 'func_type_info_t_cc_get', - 'func_type_info_t_cc_set', - 'func_type_info_t_flags_get', - 'func_type_info_t_flags_set', - 'func_type_info_t_retfields_get', - 'func_type_info_t_retfields_set', - 'func_type_info_t_retloc_get', - 'func_type_info_t_retloc_set', - 'func_type_info_t_rettype_get', - 'func_type_info_t_rettype_set', - 'func_type_info_t_spoiled_get', - 'func_type_info_t_spoiled_set', - 'func_type_info_t_stkargs_get', - 'func_type_info_t_stkargs_set', - 'funcarg_info_t_argloc_get', - 'funcarg_info_t_argloc_set', - 'funcarg_info_t_fields_get', - 'funcarg_info_t_fields_set', - 'funcarg_info_t_name_get', - 'funcarg_info_t_name_set', - 'funcarg_info_t_type_get', - 'funcarg_info_t_type_set', 'funcarg_t___eq__', 'funcarg_t___ne__', 'funcarg_t_argloc_get', @@ -2809,9 +2773,6 @@ 'funcargvec_t__del', 'funcargvec_t_add_unique', 'funcargvec_t_at', - 'funcargvec_t_back', - 'funcargvec_t_back__SWIG_0', - 'funcargvec_t_back__SWIG_1', 'funcargvec_t_begin', 'funcargvec_t_begin__SWIG_0', 'funcargvec_t_begin__SWIG_1', @@ -2828,9 +2789,6 @@ 'funcargvec_t_find', 'funcargvec_t_find__SWIG_0', 'funcargvec_t_find__SWIG_1', - 'funcargvec_t_front', - 'funcargvec_t_front__SWIG_0', - 'funcargvec_t_front__SWIG_1', 'funcargvec_t_grow', 'funcargvec_t_has', 'funcargvec_t_inject', @@ -2847,48 +2805,28 @@ 'funcargvec_t_size', 'funcargvec_t_swap', 'funcargvec_t_truncate', - 'gen_abssym', - 'gen_cmt_line', - 'gen_cmt_line__varargs__', - 'gen_collapsed_line', - 'gen_collapsed_line__varargs__', + 'gcc_layout', 'gen_complex_call_chart', - 'gen_comvar', - 'gen_decorate_name3', + 'gen_decorate_name', 'gen_disasm_text', 'gen_exe_file', - 'gen_extern', 'gen_file', 'gen_fix_fixups', 'gen_flow_graph', 'gen_gdl', - 'gen_name_decl', 'gen_simple_call_chart', - 'gen_spcdef', 'gen_use_arg_tinfos', - 'generate_big_comment', 'generate_disasm_line', 'generate_disassembly', - 'generate_many_lines', - 'generic_linput64_t_blocksize_get', - 'generic_linput64_t_blocksize_set', - 'generic_linput64_t_filesize_get', - 'generic_linput64_t_filesize_set', - 'generic_linput64_t_read64', 'generic_linput_t_blocksize_get', 'generic_linput_t_blocksize_set', 'generic_linput_t_filesize_get', 'generic_linput_t_filesize_set', 'generic_linput_t_read', - 'getDefaultRadix', - 'getFlags', - 'getRadix', - 'getRadixEA', - 'getSR', 'get_16bit', 'get_32bit', - 'get_3byte', 'get_64bit', + 'get_abi_name', 'get_absbase', 'get_action_checkable', 'get_action_checked', @@ -2903,26 +2841,26 @@ 'get_aflags', 'get_alias_target', 'get_alignment', - 'get_argloc_r1', - 'get_argloc_r2', + 'get_archive_path', + 'get_arg_addrs', 'get_array_parameters', - 'get_ascii_contents', - 'get_ascii_contents2', 'get_asm_inc_file', - 'get_auto_plugins', + 'get_auto_display', + 'get_auto_state', 'get_base_type', 'get_basic_file_type', 'get_bblk_trace_options', 'get_best_fit_member', 'get_bmask_cmt', 'get_bmask_name', - 'get_bmask_node', 'get_bpt', 'get_bpt_group', 'get_bpt_qty', 'get_bpt_tev_ea', 'get_bptloc_string', 'get_byte', + 'get_bytes', + 'get_bytes_and_mask', 'get_c_header_path', 'get_c_macros', 'get_call_tev_callee', @@ -2930,72 +2868,59 @@ 'get_chooser_obj', 'get_cmt', 'get_colored_demangled_name', - 'get_colored_demangled_name__SWIG_0', - 'get_colored_demangled_name__SWIG_1', 'get_colored_long_name', 'get_colored_name', - 'get_colored_name__SWIG_0', - 'get_colored_name__SWIG_1', 'get_colored_short_name', 'get_comp', 'get_compiler_abbr', 'get_compiler_name', 'get_compilers', - 'get_complex_n', - 'get_const', - 'get_const_bmask', - 'get_const_by_name', - 'get_const_cmt', - 'get_const_enum', - 'get_const_name', - 'get_const_serial', - 'get_const_value', 'get_ctype_name', 'get_curline', 'get_current_idasgn', - 'get_current_tform', 'get_current_thread', 'get_current_viewer', + 'get_current_widget', 'get_cursor', 'get_custom_data_format', 'get_custom_data_formats', 'get_custom_data_type', 'get_custom_data_type_ids', 'get_custom_data_types', + 'get_custom_refinfo', 'get_custom_viewer_curline', 'get_custom_viewer_place', 'get_data_elsize', - 'get_data_type_size', 'get_data_value', 'get_db_byte', 'get_dbg_byte', 'get_dbg_memory_info', 'get_debug_event', - 'get_debug_name2', + 'get_debug_name', 'get_debug_name_ea', 'get_debug_names', 'get_debugger_event_cond', 'get_default_encoding_idx', + 'get_default_radix', 'get_default_reftype', 'get_defsr', 'get_demangled_name', - 'get_demangled_name__SWIG_0', - 'get_demangled_name__SWIG_1', - 'get_dtyp_by_size', - 'get_dtyp_flag', - 'get_dtyp_size', + 'get_dtype_by_size', + 'get_dtype_flag', + 'get_dtype_size', + 'get_dword', 'get_ea_name', 'get_ea_viewer_history_info', 'get_effective_spd', + 'get_encoding_bpu', 'get_encoding_name', - 'get_encodings_count', + 'get_encoding_qty', 'get_entry', 'get_entry_forwarder', 'get_entry_name', 'get_entry_ordinal', 'get_entry_qty', 'get_enum', - 'get_enum_base_type', 'get_enum_cmt', 'get_enum_flag', 'get_enum_id', @@ -3005,7 +2930,7 @@ 'get_enum_member_by_name', 'get_enum_member_cmt', 'get_enum_member_enum', - 'get_enum_member_expr2', + 'get_enum_member_expr', 'get_enum_member_name', 'get_enum_member_serial', 'get_enum_member_value', @@ -3022,7 +2947,6 @@ 'get_event_module_base', 'get_event_module_name', 'get_event_module_size', - 'get_extlang_fileext', 'get_extra_cmt', 'get_fchunk', 'get_fchunk_num', @@ -3032,7 +2956,6 @@ 'get_fileregion_ea', 'get_fileregion_offset', 'get_first_bmask', - 'get_first_const', 'get_first_cref_from', 'get_first_cref_to', 'get_first_dref_from', @@ -3042,23 +2965,19 @@ 'get_first_fcref_to', 'get_first_fixup_ea', 'get_first_free_extra_cmtidx', + 'get_first_hidden_range', 'get_first_module', 'get_first_seg', - 'get_first_serial_const', 'get_first_serial_enum_member', 'get_first_struc_idx', 'get_fixup', - 'get_fixup_base', 'get_fixup_desc', - 'get_fixup_extdef_ea', - 'get_fixup_extdef_ea__SWIG_0', - 'get_fixup_extdef_ea__SWIG_1', - 'get_fixup_segdef_sel', - 'get_fixup_segdef_sel__SWIG_0', - 'get_fixup_segdef_sel__SWIG_1', + 'get_fixup_handler', + 'get_fixup_value', + 'get_fixups', + 'get_flags', 'get_flags_by_size', 'get_flags_ex', - 'get_flags_novalue', 'get_float_type', 'get_forced_operand', 'get_frame', @@ -3067,50 +2986,46 @@ 'get_frame_part', 'get_frame_retsize', 'get_frame_size', - 'get_full_byte', 'get_full_data_elsize', - 'get_full_long', + 'get_full_flags', 'get_full_type', - 'get_full_word', 'get_func', 'get_func_bitness', 'get_func_bits', 'get_func_by_frame', 'get_func_bytes', - 'get_func_cc', 'get_func_chunknum', 'get_func_cmt', - 'get_func_cvtarg_map', - 'get_func_limits', 'get_func_name', - 'get_func_name2', - 'get_func_nargs', 'get_func_num', 'get_func_qty', - 'get_func_rettype', + 'get_func_ranges', 'get_func_trace_options', - 'get_funcarg_size', + 'get_gotea', + 'get_graph_viewer', 'get_group_selector', 'get_grp_bpts', 'get_hexdump_ea', 'get_hexrays_version', - 'get_hidden_area', - 'get_hidden_area_num', - 'get_hidden_area_qty', - 'get_highlighted_identifier', + 'get_hidden_range', + 'get_hidden_range_num', + 'get_hidden_range_qty', + 'get_highlight', 'get_ida_subdirs', 'get_idainfo_by_type', - 'get_idainfo_by_type2', - 'get_idainfo_by_type3', 'get_idasgn_desc', 'get_idasgn_desc_with_matches', 'get_idasgn_qty', 'get_idasgn_title', + 'get_idati', 'get_idc_filename', - 'get_idcpath', + 'get_idcv_attr', + 'get_idcv_class_name', + 'get_idcv_slice', 'get_idp_name', 'get_ids_modnode', 'get_imagebase', + 'get_immvals', 'get_import_module_name', 'get_import_module_qty', 'get_ind_purged', @@ -3121,31 +3036,31 @@ 'get_insn_tev_reg_val', 'get_insn_trace_options', 'get_int_type_by_width_and_sign', + 'get_ip_val', 'get_item_color', 'get_item_end', 'get_item_flag', 'get_item_head', 'get_item_size', - 'get_jumptable_info', 'get_kernel_version', 'get_key_code', 'get_last_bmask', - 'get_last_const', 'get_last_enum_member', + 'get_last_hidden_range', 'get_last_seg', - 'get_last_serial_const', 'get_last_serial_enum_member', 'get_last_struc_idx', 'get_linput_type', - 'get_long', 'get_long_name', - 'get_long_queue_name', + 'get_lookback', 'get_manual_insn', 'get_manual_regions', - 'get_many_bytes', - 'get_many_bytes_ex', - 'get_max_ascii_length', + 'get_mapping', + 'get_mappings_qty', + 'get_mark_comment', + 'get_marked_pos', 'get_max_offset', + 'get_max_strlit_length', 'get_member', 'get_member_by_fullname', 'get_member_by_id', @@ -3153,12 +3068,9 @@ 'get_member_cmt', 'get_member_fullname', 'get_member_name', - 'get_member_name2', 'get_member_size', 'get_member_struc', - 'get_member_ti', 'get_member_tinfo', - 'get_member_tinfo2', 'get_member_type', 'get_min_spd_ea', 'get_name', @@ -3166,12 +3078,10 @@ 'get_name_color', 'get_name_ea', 'get_name_expr', - 'get_name_of_named_type', 'get_name_value', 'get_named_type', 'get_named_type64', 'get_next_bmask', - 'get_next_const', 'get_next_cref_from', 'get_next_cref_to', 'get_next_dref_from', @@ -3183,11 +3093,10 @@ 'get_next_fixup_ea', 'get_next_func', 'get_next_func_addr', - 'get_next_hidden_area', + 'get_next_hidden_range', 'get_next_member_idx', 'get_next_module', 'get_next_seg', - 'get_next_serial_const', 'get_next_serial_enum_member', 'get_next_struc_idx', 'get_nice_colored_name', @@ -3196,59 +3105,56 @@ 'get_nlist_name', 'get_nlist_size', 'get_node_info', - 'get_node_info2', 'get_numbered_type', 'get_numbered_type_name', 'get_offbase', 'get_offset_expr', 'get_offset_expression', 'get_op_signness', - 'get_op_tinfo2', - 'get_operand_immvals', + 'get_op_tinfo', 'get_opinfo', 'get_opnum', 'get_optype_flags0', 'get_optype_flags1', 'get_or_guess_member_tinfo', - 'get_or_guess_member_tinfo2', - 'get_or_guess_member_type', 'get_ordinal_from_idb_type', 'get_ordinal_qty', 'get_original_byte', - 'get_original_long', + 'get_original_dword', 'get_original_qword', 'get_original_word', 'get_output_curline', 'get_output_cursor', 'get_output_selected_text', + 'get_path', 'get_place_class', 'get_place_class_id', 'get_place_class_template', 'get_plugin_options', + 'get_predef_insn_cmt', 'get_prev_bmask', - 'get_prev_const', 'get_prev_enum_member', 'get_prev_fchunk', 'get_prev_fixup_ea', 'get_prev_func', 'get_prev_func_addr', - 'get_prev_hidden_area', + 'get_prev_hidden_range', 'get_prev_member_idx', 'get_prev_seg', - 'get_prev_serial_const', 'get_prev_serial_enum_member', - 'get_prev_srarea', + 'get_prev_sreg_range', 'get_prev_struc_idx', - 'get_process_info', + 'get_problem', + 'get_problem_desc', + 'get_problem_name', 'get_process_options', - 'get_process_qty', 'get_process_state', - 'get_ptr_object_size', + 'get_processes', 'get_qword', - 'get_referred_ordinal', + 'get_radix', 'get_refinfo', 'get_reftype_by_size', - 'get_reg_info2', + 'get_reg_info', 'get_reg_name', 'get_reg_val', 'get_reg_vals', @@ -3257,68 +3163,47 @@ 'get_root_filename', 'get_running_notification', 'get_running_request', - 'get_scattered_varloc', + 'get_scalar_bt', 'get_screen_ea', 'get_segm_base', 'get_segm_by_name', 'get_segm_by_sel', 'get_segm_class', 'get_segm_name', - 'get_segm_name__SWIG_0', - 'get_segm_name__SWIG_1', + 'get_segm_num', 'get_segm_para', 'get_segm_qty', 'get_segment_alignment', 'get_segment_cmt', 'get_segment_combination', 'get_segment_translations', - 'get_segreg', 'get_selector_qty', 'get_short_name', - 'get_short_queue_name', - 'get_sig_filename', 'get_source_linnum', 'get_sourcefile', 'get_sp_delta', + 'get_sp_val', 'get_spd', 'get_special_folder', - 'get_spoil_cnt', 'get_sptr', - 'get_srarea', - 'get_srarea2', - 'get_srarea_num', - 'get_srareas_qty', - 'get_srareas_qty2', + 'get_sreg', + 'get_sreg_range', + 'get_sreg_range_num', + 'get_sreg_ranges_qty', 'get_step_trace_options', - 'get_stkarg_offset', 'get_stkvar', 'get_stock_tinfo', 'get_str_encoding_idx', 'get_str_term1', 'get_str_term2', + 'get_str_type', 'get_str_type_code', 'get_strlist_item', + 'get_strlist_options', 'get_strlist_qty', - 'get_strmem', - 'get_strmem2', - 'get_strmem_by_name', - 'get_strmem_t_delta_get', - 'get_strmem_t_delta_set', - 'get_strmem_t_flags_get', - 'get_strmem_t_flags_set', - 'get_strmem_t_fnames_get', - 'get_strmem_t_fnames_set', - 'get_strmem_t_ftype_get', - 'get_strmem_t_ftype_set', - 'get_strmem_t_index_get', - 'get_strmem_t_index_set', - 'get_strmem_t_name_get', - 'get_strmem_t_name_set', - 'get_strmem_t_offset_get', - 'get_strmem_t_offset_set', - 'get_strmem_t_sname_get', - 'get_strmem_t_sname_set', + 'get_strlit_contents', 'get_stroff_path', + 'get_strtype_bpu', 'get_struc', 'get_struc_by_idx', 'get_struc_cmt', @@ -3333,7 +3218,7 @@ 'get_struc_size', 'get_struc_size__SWIG_0', 'get_struc_size__SWIG_1', - 'get_switch_info_ex', + 'get_switch_info', 'get_switch_parent', 'get_tab_size', 'get_tev_ea', @@ -3341,19 +3226,10 @@ 'get_tev_info', 'get_tev_memory_info', 'get_tev_qty', - 'get_tev_reg_mem_ea', - 'get_tev_reg_mem_qty', - 'get_tev_reg_val', 'get_tev_tid', 'get_tev_type', - 'get_tform_idaview', - 'get_tform_title', - 'get_tform_type', - 'get_tform_vdui', 'get_thread_qty', - 'get_tilpath', 'get_tinfo', - 'get_tinfo2', 'get_tinfo_attr', 'get_tinfo_attrs', 'get_tinfo_details', @@ -3363,38 +3239,54 @@ 'get_trace_base_address', 'get_trace_file_desc', 'get_trace_platform', - 'get_true_name', - 'get_true_name__SWIG_0', - 'get_true_name__SWIG_1', - 'get_true_segm_name', + 'get_tryblks', 'get_type', 'get_type_flags', 'get_type_ordinal', - 'get_type_sign', - 'get_typeinfo', 'get_unk_type', 'get_user_idadir', 'get_user_strlist_options', 'get_utf8_char', 'get_view_renderer_type', + 'get_viewer_graph', 'get_viewer_place_type', 'get_viewer_user_data', 'get_visible_name', + 'get_visible_segm_name', + 'get_wide_byte', + 'get_wide_dword', + 'get_wide_word', + 'get_widget_title', + 'get_widget_type', + 'get_widget_vdui', 'get_word', - 'get_zero_areas', - 'getdspace', + 'get_zero_ranges', 'getn_bpt', 'getn_enum', 'getn_fchunk', 'getn_func', - 'getn_hidden_area', + 'getn_hidden_range', 'getn_selector', - 'getn_srarea', - 'getn_srarea2', + 'getn_sreg_range', 'getn_thread', + 'getnode', 'getnseg', 'getseg', 'getsysfile', + 'graph_item_t_b_get', + 'graph_item_t_b_set', + 'graph_item_t_e_get', + 'graph_item_t_e_set', + 'graph_item_t_elp_get', + 'graph_item_t_elp_set', + 'graph_item_t_is_edge', + 'graph_item_t_is_node', + 'graph_item_t_n_get', + 'graph_item_t_n_set', + 'graph_item_t_p_get', + 'graph_item_t_p_set', + 'graph_item_t_type_get', + 'graph_item_t_type_set', 'graph_location_info_t___eq__', 'graph_location_info_t___ne__', 'graph_location_info_t_orgx_get', @@ -3403,32 +3295,50 @@ 'graph_location_info_t_orgy_set', 'graph_location_info_t_zoom_get', 'graph_location_info_t_zoom_set', + 'graph_node_visitor_t_is_forbidden_edge', + 'graph_node_visitor_t_is_visited', + 'graph_node_visitor_t_reinit', + 'graph_node_visitor_t_set_visited', + 'graph_node_visitor_t_visit_node', + 'graph_path_visitor_t_path_get', + 'graph_path_visitor_t_path_set', + 'graph_path_visitor_t_prune_get', + 'graph_path_visitor_t_prune_set', + 'graph_path_visitor_t_walk_backward', + 'graph_path_visitor_t_walk_forward', 'graph_trace', + 'graph_visitor_t_visit_edge', + 'graph_visitor_t_visit_node', + 'group_crinfo_t_nodes_get', + 'group_crinfo_t_nodes_set', + 'group_crinfo_t_text_get', + 'group_crinfo_t_text_set', 'guess_func_cc', - 'guess_func_tinfo', - 'guess_func_tinfo2', 'guess_table_address', 'guess_table_size', 'guess_tinfo', - 'guess_tinfo2', 'handle_debug_event', - 'hasExtra', - 'hasRef', - 'hasValue', 'has_any_name', 'has_auto_name', 'has_cached_cfunc', + 'has_cf_chg', + 'has_cf_use', 'has_cmt', 'has_dummy_name', 'has_external_refs', + 'has_extra_cmts', + 'has_immd', + 'has_insn_feature', 'has_lname', 'has_name', 'has_ti', 'has_ti0', 'has_ti1', 'has_user_name', + 'has_value', + 'has_xref', 'have_set_options', - 'hexflag', + 'hex_flag', 'hexrays_failure_t_code_get', 'hexrays_failure_t_code_set', 'hexrays_failure_t_desc', @@ -3457,9 +3367,6 @@ 'hexwarns_t__del', 'hexwarns_t_add_unique', 'hexwarns_t_at', - 'hexwarns_t_back', - 'hexwarns_t_back__SWIG_0', - 'hexwarns_t_back__SWIG_1', 'hexwarns_t_begin', 'hexwarns_t_begin__SWIG_0', 'hexwarns_t_begin__SWIG_1', @@ -3476,9 +3383,6 @@ 'hexwarns_t_find', 'hexwarns_t_find__SWIG_0', 'hexwarns_t_find__SWIG_1', - 'hexwarns_t_front', - 'hexwarns_t_front__SWIG_0', - 'hexwarns_t_front__SWIG_1', 'hexwarns_t_grow', 'hexwarns_t_has', 'hexwarns_t_inject', @@ -3495,16 +3399,16 @@ 'hexwarns_t_size', 'hexwarns_t_swap', 'hexwarns_t_truncate', - 'hidden_area_t_color_get', - 'hidden_area_t_color_set', - 'hidden_area_t_description_get', - 'hidden_area_t_description_set', - 'hidden_area_t_footer_get', - 'hidden_area_t_footer_set', - 'hidden_area_t_header_get', - 'hidden_area_t_header_set', - 'hidden_area_t_visible_get', - 'hidden_area_t_visible_set', + 'hidden_range_t_color_get', + 'hidden_range_t_color_set', + 'hidden_range_t_description_get', + 'hidden_range_t_description_set', + 'hidden_range_t_footer_get', + 'hidden_range_t_footer_set', + 'hidden_range_t_header_get', + 'hidden_range_t_header_set', + 'hidden_range_t_visible_get', + 'hidden_range_t_visible_set', 'hide_all_bpts', 'hide_border', 'hide_item', @@ -3524,73 +3428,68 @@ 'ida_lowertype_helper_t_func_has_stkframe_hole', 'ida_lowertype_helper_t_get_func_purged_bytes', 'idadir', - 'idainfo_ASCIIbreak_get', - 'idainfo_ASCIIbreak_set', - 'idainfo_ASCIIpref_get', - 'idainfo_ASCIIpref_set', - 'idainfo_ASCIIsernum_get', - 'idainfo_ASCIIsernum_set', - 'idainfo_ASCIIzeroes_get', - 'idainfo_ASCIIzeroes_set', 'idainfo_abibits_get', 'idainfo_abibits_set', - 'idainfo_abiname_get', - 'idainfo_abiname_set', 'idainfo_af2_get', 'idainfo_af2_set', 'idainfo_af_get', 'idainfo_af_set', + 'idainfo_allow_nonmatched_ops', 'idainfo_appcall_options_get', 'idainfo_appcall_options_set', 'idainfo_apptype_get', 'idainfo_apptype_set', - 'idainfo_asciiflags_get', - 'idainfo_asciiflags_set', 'idainfo_asmtype_get', 'idainfo_asmtype_set', 'idainfo_baseaddr_get', 'idainfo_baseaddr_set', - 'idainfo_beginEA_get', - 'idainfo_beginEA_set', 'idainfo_big_arg_align', - 'idainfo_binSize_get', - 'idainfo_binSize_set', + 'idainfo_bin_prefix_size_get', + 'idainfo_bin_prefix_size_set', 'idainfo_cc_get', 'idainfo_cc_set', + 'idainfo_check_manual_ops', 'idainfo_comment_get', 'idainfo_comment_set', - 'idainfo_corestart_get', - 'idainfo_corestart_set', 'idainfo_database_change_count_get', 'idainfo_database_change_count_set', 'idainfo_datatypes_get', 'idainfo_datatypes_set', 'idainfo_demnames_get', 'idainfo_demnames_set', - 'idainfo_fcoresiz_get', - 'idainfo_fcoresiz_set', 'idainfo_filetype_get', 'idainfo_filetype_set', + 'idainfo_gen_lzero', + 'idainfo_gen_null', + 'idainfo_gen_tryblks', + 'idainfo_get_abiname', 'idainfo_get_demname_form', - 'idainfo_get_proc_name', - 'idainfo_graph_view_get', - 'idainfo_graph_view_set', + 'idainfo_get_maxEA', + 'idainfo_get_minEA', + 'idainfo_get_pack_mode', + 'idainfo_get_procName', 'idainfo_highoff_get', 'idainfo_highoff_set', 'idainfo_indent_get', 'idainfo_indent_set', 'idainfo_is_32bit', 'idainfo_is_64bit', + 'idainfo_is_auto_enabled', + 'idainfo_is_be', 'idainfo_is_dll', 'idainfo_is_flat_off32', + 'idainfo_is_graph_view', 'idainfo_is_hard_float', + 'idainfo_is_kernel_mode', 'idainfo_is_mem_aligned4', 'idainfo_is_snapshot', + 'idainfo_is_wide_high_byte_first', 'idainfo_lenxref_get', 'idainfo_lenxref_set', 'idainfo_lflags_get', 'idainfo_lflags_set', 'idainfo_like_binary', + 'idainfo_line_pref_with_seg', 'idainfo_listnames_get', 'idainfo_listnames_set', 'idainfo_loading_idc', @@ -3598,111 +3497,104 @@ 'idainfo_long_demnames_set', 'idainfo_lowoff_get', 'idainfo_lowoff_set', - 'idainfo_lprefix_get', - 'idainfo_lprefix_set', - 'idainfo_lprefixlen_get', - 'idainfo_lprefixlen_set', 'idainfo_main_get', 'idainfo_main_set', 'idainfo_margin_get', 'idainfo_margin_set', - 'idainfo_maxEA_get', - 'idainfo_maxEA_set', + 'idainfo_max_autoname_len_get', + 'idainfo_max_autoname_len_set', + 'idainfo_max_ea_get', + 'idainfo_max_ea_set', 'idainfo_maxref_get', 'idainfo_maxref_set', - 'idainfo_mf_get', - 'idainfo_mf_set', - 'idainfo_minEA_get', - 'idainfo_minEA_set', - 'idainfo_namelen_get', - 'idainfo_namelen_set', + 'idainfo_min_ea_get', + 'idainfo_min_ea_set', 'idainfo_nametype_get', 'idainfo_nametype_set', - 'idainfo_omaxEA_get', - 'idainfo_omaxEA_set', - 'idainfo_ominEA_get', - 'idainfo_ominEA_set', + 'idainfo_omax_ea_get', + 'idainfo_omax_ea_set', + 'idainfo_omin_ea_get', + 'idainfo_omin_ea_set', 'idainfo_ostype_get', 'idainfo_ostype_set', + 'idainfo_outflags_get', + 'idainfo_outflags_set', 'idainfo_pack_stkargs', - 'idainfo_procName_get', - 'idainfo_procName_set', + 'idainfo_procname_get', + 'idainfo_procname_set', 'idainfo_readonly_idb', 'idainfo_refcmtnum_get', 'idainfo_refcmtnum_set', - 'idainfo_reserved_get', - 'idainfo_reserved_set', - 'idainfo_s_assume_get', - 'idainfo_s_assume_set', - 'idainfo_s_auto_get', - 'idainfo_s_auto_set', - 'idainfo_s_checkarg_get', - 'idainfo_s_checkarg_set', 'idainfo_s_cmtflg_get', 'idainfo_s_cmtflg_set', - 'idainfo_s_entab_get', - 'idainfo_s_entab_set', 'idainfo_s_genflags_get', 'idainfo_s_genflags_set', 'idainfo_s_limiter_get', 'idainfo_s_limiter_set', - 'idainfo_s_null_get', - 'idainfo_s_null_set', - 'idainfo_s_org_get', - 'idainfo_s_org_set', - 'idainfo_s_packbase_get', - 'idainfo_s_packbase_set', 'idainfo_s_prefflag_get', 'idainfo_s_prefflag_set', - 'idainfo_s_prefseg_get', - 'idainfo_s_prefseg_set', - 'idainfo_s_reserved5_get', - 'idainfo_s_reserved5_set', - 'idainfo_s_showauto_get', - 'idainfo_s_showauto_set', - 'idainfo_s_showbads_get', - 'idainfo_s_showbads_set', - 'idainfo_s_showpref_get', - 'idainfo_s_showpref_set', - 'idainfo_s_void_get', - 'idainfo_s_void_set', 'idainfo_s_xrefflag_get', 'idainfo_s_xrefflag_set', - 'idainfo_set_proc_name', + 'idainfo_set_64bit', + 'idainfo_set_allow_nonmatched_ops', + 'idainfo_set_auto_enabled', + 'idainfo_set_be', + 'idainfo_set_check_manual_ops', + 'idainfo_set_gen_lzero', + 'idainfo_set_gen_null', + 'idainfo_set_gen_tryblks', + 'idainfo_set_graph_view', + 'idainfo_set_line_pref_with_seg', + 'idainfo_set_maxEA', + 'idainfo_set_minEA', + 'idainfo_set_pack_mode', + 'idainfo_set_show_auto', + 'idainfo_set_show_line_pref', + 'idainfo_set_show_void', + 'idainfo_set_wide_high_byte_first', 'idainfo_short_demnames_get', 'idainfo_short_demnames_set', - 'idainfo_size_ldbl_get', - 'idainfo_size_ldbl_set', + 'idainfo_show_auto', + 'idainfo_show_line_pref', + 'idainfo_show_void', 'idainfo_specsegs_get', 'idainfo_specsegs_set', 'idainfo_stack_ldbl', 'idainfo_stack_varargs', - 'idainfo_startIP_get', - 'idainfo_startIP_set', - 'idainfo_startSP_get', - 'idainfo_startSP_set', 'idainfo_start_cs_get', 'idainfo_start_cs_set', + 'idainfo_start_ea_get', + 'idainfo_start_ea_set', + 'idainfo_start_ip_get', + 'idainfo_start_ip_set', + 'idainfo_start_sp_get', + 'idainfo_start_sp_set', 'idainfo_start_ss_get', 'idainfo_start_ss_set', + 'idainfo_strlit_break_get', + 'idainfo_strlit_break_set', + 'idainfo_strlit_flags_get', + 'idainfo_strlit_flags_set', + 'idainfo_strlit_pref_get', + 'idainfo_strlit_pref_set', + 'idainfo_strlit_sernum_get', + 'idainfo_strlit_sernum_set', + 'idainfo_strlit_zeroes_get', + 'idainfo_strlit_zeroes_set', 'idainfo_strtype_get', 'idainfo_strtype_set', 'idainfo_tag_get', 'idainfo_tag_set', - 'idainfo_tribyte_order_get', - 'idainfo_tribyte_order_set', 'idainfo_type_xrefnum_get', 'idainfo_type_xrefnum_set', 'idainfo_use_allasm', + 'idainfo_use_gcc_layout', 'idainfo_version_get', 'idainfo_version_set', - 'idainfo_wide_high_byte_first_get', - 'idainfo_wide_high_byte_first_set', 'idainfo_xrefnum_get', 'idainfo_xrefnum_set', 'idaplace_t_ea_get', 'idaplace_t_ea_set', - 'idb2scr', 'idc_get_local_type', 'idc_get_local_type_name', 'idc_get_local_type_raw', @@ -3718,11 +3610,6 @@ 'idc_print_type', 'idc_set_local_type', 'idc_value_t__create_empty_string', - 'idc_value_t__set_long', - 'idc_value_t__set_string', - 'idc_value_t__set_string__SWIG_0', - 'idc_value_t__set_string__SWIG_1', - 'idc_value_t__set_string__SWIG_2', 'idc_value_t_c_str', 'idc_value_t_clear', 'idc_value_t_create_empty_string', @@ -3754,18 +3641,48 @@ 'idc_value_t_set_string__SWIG_0', 'idc_value_t_set_string__SWIG_1', 'idc_value_t_set_string__SWIG_2', - 'idc_value_t_str_get', - 'idc_value_t_str_set', 'idc_value_t_swap', 'idc_value_t_u_str', 'idc_value_t_vtype_get', 'idc_value_t_vtype_set', - 'idd_opinfo_old_t_addr_get', - 'idd_opinfo_old_t_addr_set', - 'idd_opinfo_old_t_modified_get', - 'idd_opinfo_old_t_modified_set', - 'idd_opinfo_old_t_value_get', - 'idd_opinfo_old_t_value_set', + 'idc_values_t___getitem__', + 'idc_values_t___len__', + 'idc_values_t___setitem__', + 'idc_values_t_at', + 'idc_values_t_begin', + 'idc_values_t_begin__SWIG_0', + 'idc_values_t_begin__SWIG_1', + 'idc_values_t_capacity', + 'idc_values_t_clear', + 'idc_values_t_empty', + 'idc_values_t_end', + 'idc_values_t_end__SWIG_0', + 'idc_values_t_end__SWIG_1', + 'idc_values_t_erase', + 'idc_values_t_erase__SWIG_0', + 'idc_values_t_erase__SWIG_1', + 'idc_values_t_extract', + 'idc_values_t_grow', + 'idc_values_t_inject', + 'idc_values_t_insert', + 'idc_values_t_pop_back', + 'idc_values_t_push_back', + 'idc_values_t_push_back__SWIG_0', + 'idc_values_t_push_back__SWIG_1', + 'idc_values_t_qclear', + 'idc_values_t_reserve', + 'idc_values_t_resize', + 'idc_values_t_resize__SWIG_0', + 'idc_values_t_resize__SWIG_1', + 'idc_values_t_size', + 'idc_values_t_swap', + 'idc_values_t_truncate', + 'idcv_float', + 'idcv_int64', + 'idcv_long', + 'idcv_num', + 'idcv_object', + 'idcv_string', 'idp_desc_t_checked_get', 'idp_desc_t_checked_set', 'idp_desc_t_family_get', @@ -3784,43 +3701,54 @@ 'idp_name_t_lname_set', 'idp_name_t_sname_get', 'idp_name_t_sname_set', - 'ids_array___getitem__', - 'ids_array___len__', - 'ids_array___setitem__', - 'ids_array_data_get', 'import_type', 'info', 'info__varargs__', 'init_hexrays_plugin', - 'init_output_buffer', - 'init_process', + 'insn_add_cref', + 'insn_add_dref', + 'insn_add_off_drefs', + 'insn_create_stkvar', + 'insn_t___get_auxpref__', + 'insn_t___get_operand__', + 'insn_t___get_ops__', + 'insn_t___set_auxpref__', + 'insn_t__from_ptrval__', + 'insn_t_add_cref', + 'insn_t_add_dref', + 'insn_t_add_off_drefs', 'insn_t_assign', - 'insn_t_create', - 'insn_t_destroy', - 'insn_t_get_auxpref', + 'insn_t_create_op_data', + 'insn_t_create_op_data__SWIG_0', + 'insn_t_create_op_data__SWIG_1', + 'insn_t_create_stkvar', + 'insn_t_cs_get', + 'insn_t_cs_set', + 'insn_t_ea_get', + 'insn_t_ea_set', + 'insn_t_flags_get', + 'insn_t_flags_set', 'insn_t_get_canon_feature', 'insn_t_get_canon_mnem', - 'insn_t_get_cs', - 'insn_t_get_ea', - 'insn_t_get_flags', - 'insn_t_get_insnpref', - 'insn_t_get_ip', - 'insn_t_get_itype', - 'insn_t_get_op_link', - 'insn_t_get_segpref', - 'insn_t_get_size', + 'insn_t_get_next_byte', + 'insn_t_get_next_dword', + 'insn_t_get_next_qword', + 'insn_t_get_next_word', + 'insn_t_insnpref_get', + 'insn_t_insnpref_set', + 'insn_t_ip_get', + 'insn_t_ip_set', 'insn_t_is_canon_insn', - 'insn_t_set_auxpref', - 'insn_t_set_cs', - 'insn_t_set_ea', - 'insn_t_set_flags', - 'insn_t_set_insnpref', - 'insn_t_set_ip', - 'insn_t_set_itype', - 'insn_t_set_segpref', - 'insn_t_set_size', + 'insn_t_is_macro', + 'insn_t_itype_get', + 'insn_t_itype_set', + 'insn_t_ops_get', + 'insn_t_ops_set', + 'insn_t_segpref_get', + 'insn_t_segpref_set', + 'insn_t_size_get', + 'insn_t_size_set', 'install_command_interpreter', - 'install_extlang', 'install_hexrays_callback', 'install_microcode_filter', 'instant_dbgopts_t__pass_get', @@ -3847,9 +3775,6 @@ 'int64vec_t__del', 'int64vec_t_add_unique', 'int64vec_t_at', - 'int64vec_t_back', - 'int64vec_t_back__SWIG_0', - 'int64vec_t_back__SWIG_1', 'int64vec_t_begin', 'int64vec_t_begin__SWIG_0', 'int64vec_t_begin__SWIG_1', @@ -3866,9 +3791,6 @@ 'int64vec_t_find', 'int64vec_t_find__SWIG_0', 'int64vec_t_find__SWIG_1', - 'int64vec_t_front', - 'int64vec_t_front__SWIG_0', - 'int64vec_t_front__SWIG_1', 'int64vec_t_has', 'int64vec_t_inject', 'int64vec_t_insert', @@ -3888,10 +3810,21 @@ 'int_pointer_cast', 'int_pointer_frompointer', 'int_pointer_value', - 'intel_data', 'internal_get_sreg_base', 'internal_ioctl', 'internal_register_place_class', + 'interval_t___eq__', + 'interval_t___ne__', + 'interval_t_contains', + 'interval_t_empty', + 'interval_t_intersect', + 'interval_t_length', + 'interval_t_make_union', + 'interval_t_move_by', + 'interval_t_x0_get', + 'interval_t_x0_set', + 'interval_t_x1_get', + 'interval_t_x1_set', 'intvec_t___eq__', 'intvec_t___getitem__', 'intvec_t___len__', @@ -3900,9 +3833,6 @@ 'intvec_t__del', 'intvec_t_add_unique', 'intvec_t_at', - 'intvec_t_back', - 'intvec_t_back__SWIG_0', - 'intvec_t_back__SWIG_1', 'intvec_t_begin', 'intvec_t_begin__SWIG_0', 'intvec_t_begin__SWIG_1', @@ -3919,9 +3849,6 @@ 'intvec_t_find', 'intvec_t_find__SWIG_0', 'intvec_t_find__SWIG_1', - 'intvec_t_front', - 'intvec_t_front__SWIG_0', - 'intvec_t_front__SWIG_1', 'intvec_t_grow', 'intvec_t_has', 'intvec_t_inject', @@ -3940,78 +3867,20 @@ 'intvec_t_truncate', 'invalidate_dbgmem_config', 'invalidate_dbgmem_contents', - 'invalidate_visea_cache', - 'is3byte', - 'isASCII', - 'isAlign', - 'isByte', - 'isChar', - 'isChar0', - 'isChar1', - 'isCode', - 'isCustFmt', - 'isCustFmt0', - 'isCustFmt1', - 'isCustom', - 'isData', - 'isDefArg', - 'isDefArg0', - 'isDefArg1', - 'isDouble', - 'isDwrd', - 'isEnabled', - 'isEnum', - 'isEnum0', - 'isEnum1', - 'isFloat', - 'isFloat0', - 'isFloat1', - 'isFlow', - 'isFltnum', - 'isFop', - 'isFunc', - 'isHead', - 'isImmd', - 'isLoaded', - 'isNotTail', - 'isNum', - 'isNum0', - 'isNum1', - 'isOff', - 'isOff0', - 'isOff1', - 'isOwrd', - 'isPackReal', - 'isQwrd', - 'isSeg', - 'isSeg0', - 'isSeg1', - 'isStkvar', - 'isStkvar0', - 'isStkvar1', - 'isStroff', - 'isStroff0', - 'isStroff1', - 'isStruct', - 'isTail', - 'isTbyt', - 'isUnknown', - 'isVar', - 'isVoid', - 'isWord', - 'isYwrd', - 'isZwrd', 'is__bnot0', 'is__bnot1', 'is__invsign0', 'is__invsign1', 'is_action_enabled', 'is_additive', + 'is_align', 'is_align_flow', 'is_align_insn', 'is_allowed_on_small_struni', 'is_anonymous_member_name', 'is_assignment', + 'is_attached_custom_data_format', + 'is_auto_enabled', 'is_autosync', 'is_autosync__SWIG_0', 'is_autosync__SWIG_1', @@ -4023,26 +3892,51 @@ 'is_bnot', 'is_bool_type', 'is_break_consumer', + 'is_byte', 'is_call_insn', - 'is_castable2', - 'is_chooser_tform', + 'is_char', + 'is_char0', + 'is_char1', + 'is_chooser_widget', + 'is_code', 'is_code_far', 'is_colored_item', 'is_commutative', 'is_comp_unsure', 'is_control_tty', + 'is_custfmt', + 'is_custfmt0', + 'is_custfmt1', + 'is_custom', + 'is_data', 'is_data_far', + 'is_database_flag', 'is_debugger_busy', 'is_debugger_memory', 'is_debugger_on', + 'is_defarg', + 'is_defarg0', + 'is_defarg1', + 'is_double', 'is_dummy_member_name', + 'is_dword', + 'is_enum', + 'is_enum0', + 'is_enum1', 'is_enum_fromtil', 'is_enum_hidden', 'is_finally_visible_func', 'is_finally_visible_item', 'is_finally_visible_segm', 'is_fixed_spd', + 'is_fixup_custom', + 'is_float', + 'is_float0', + 'is_float1', + 'is_flow', + 'is_fltnum', 'is_forced_operand', + 'is_func', 'is_func_entry', 'is_func_locked', 'is_func_tail', @@ -4052,15 +3946,19 @@ 'is_gcc32', 'is_gcc64', 'is_ghost_enum', + 'is_head', 'is_hidden_border', 'is_hidden_item', 'is_idaq', - 'is_ident_char', + 'is_ident', + 'is_ident_cp', 'is_in_nlist', 'is_indirect_jump_insn', + 'is_inplace_def', 'is_insn_trace_enabled', 'is_invsign', 'is_libitem', + 'is_loaded', 'is_logical', 'is_loop', 'is_lvalue', @@ -4068,7 +3966,9 @@ 'is_lzero0', 'is_lzero1', 'is_main_thread', + 'is_manual', 'is_manual_insn', + 'is_mapped', 'is_member_id', 'is_miniidb', 'is_msg_inited', @@ -4077,49 +3977,66 @@ 'is_nonbool_type', 'is_noret', 'is_noret_block', + 'is_not_tail', 'is_notcode', + 'is_notproc', + 'is_numop', + 'is_numop0', + 'is_numop1', + 'is_off', + 'is_off0', + 'is_off1', 'is_one_bit_mask', 'is_ordinal_name', + 'is_oword', + 'is_pack_real', 'is_paf', 'is_pascal', 'is_place_class_ea_capable', 'is_prepost', + 'is_problem_present', 'is_ptr_or_array', 'is_public_name', 'is_purging_cc', - 'is_reg2_argloc', - 'is_reg_argloc', + 'is_qword', + 'is_refresh_requested', + 'is_reftype_target_optional', 'is_reg_custom', 'is_reg_float', 'is_reg_integer', 'is_relational', - 'is_resolved_type_struni', - 'is_restype_array', - 'is_restype_bitfld', - 'is_restype_complex', - 'is_restype_const', 'is_restype_enum', - 'is_restype_floating', - 'is_restype_func', - 'is_restype_ptr', 'is_restype_struct', 'is_restype_struni', - 'is_restype_union', 'is_restype_void', 'is_ret_block', 'is_ret_insn', 'is_retfp', 'is_same_data_type', + 'is_same_func', 'is_sdacl_byte', + 'is_seg', + 'is_seg0', + 'is_seg1', 'is_segm_locked', - 'is_segreg_locked', 'is_small_struni', 'is_spec_ea', 'is_spec_segm', 'is_special_member', - 'is_stack_argloc', 'is_step_trace_enabled', + 'is_stkvar', + 'is_stkvar0', + 'is_stkvar1', + 'is_strlit', + 'is_strlit_cp', + 'is_stroff', + 'is_stroff0', + 'is_stroff1', + 'is_struct', + 'is_suspop', 'is_tah_byte', + 'is_tail', + 'is_tbyte', 'is_terse_struc', 'is_tilcmt', 'is_trusted_idb', @@ -4145,13 +4062,10 @@ 'is_type_int64', 'is_type_integral', 'is_type_ldouble', - 'is_type_only_size', 'is_type_paf', 'is_type_partial', 'is_type_ptr', 'is_type_ptr_or_array', - 'is_type_resolvable', - 'is_type_scalar2', 'is_type_struct', 'is_type_struni', 'is_type_sue', @@ -4163,41 +4077,37 @@ 'is_type_uint32', 'is_type_uint64', 'is_type_union', - 'is_type_unk', 'is_type_unknown', 'is_type_void', - 'is_type_void_obsolete', - 'is_type_voiddef', 'is_type_volatile', 'is_typeid_last', 'is_uname', 'is_unary', - 'is_unicode', 'is_union', + 'is_unknown', 'is_user_cc', 'is_usersp', 'is_userti', - 'is_valid_full_type', + 'is_valid_cp', 'is_valid_trace_file', 'is_valid_typename', 'is_vararg_cc', 'is_varmember', 'is_varsize_item', 'is_varstr', - 'is_visible_char', + 'is_visible_cp', 'is_visible_func', 'is_visible_item', 'is_visible_segm', 'is_weak_name', + 'is_word', + 'is_yword', 'is_zstroff', - 'isident', - 'jumptable_info_t_size_get', - 'jumptable_info_t_size_set', - 'jumptable_info_t_table_get', - 'jumptable_info_t_table_set', + 'is_zword', 'jumpto', 'jumpto__SWIG_0', 'jumpto__SWIG_1', + 'last_idcv_attr', 'leading_zero_important', 'lexcompare_tinfo', 'linput_buffer_t_eof', @@ -4209,21 +4119,14 @@ 'llabel_t_ea_set', 'llabel_t_name_get', 'llabel_t_name_set', - 'lnot', 'load_and_run_plugin', 'load_binary_file', 'load_dbg_dbginfo', 'load_debugger', 'load_ids_module', - 'load_loader_module', 'load_plugin', 'load_til', - 'load_til2', - 'load_til__SWIG_0', - 'load_til__SWIG_1', 'load_til_header', - 'load_til_header__SWIG_0', - 'load_til_header__SWIG_1', 'load_trace_file', 'loader_input_t___idc_cvt_id___get', 'loader_input_t___idc_cvt_id___set', @@ -4246,23 +4149,10 @@ 'loader_input_t_set_linput', 'loader_input_t_size', 'loader_input_t_tell', - 'loader_t__UNUSED1_was_init_loader_options_get', - 'loader_t__UNUSED1_was_init_loader_options_set', 'loader_t_flags_get', 'loader_t_flags_set', 'loader_t_version_get', 'loader_t_version_set', - 'location_t_copy_current_location', - 'location_t_get', - 'location_t_get_entry', - 'location_t_gli_get', - 'location_t_gli_set', - 'location_t_jump', - 'location_t_jump_nopush', - 'location_t_linkTo', - 'location_t_mark', - 'location_t_pop', - 'location_t_push_and_jump', 'locchange_md_t_is_sync', 'locchange_md_t_reason', 'lochist_entry_t___eq__', @@ -4297,9 +4187,10 @@ 'lochist_t_set', 'lochist_t_set_current', 'lochist_t_size', + 'lock_func_range', + 'lock_segm', 'lookup_key_code', 'lower_type', - 'lower_type2', 'lowertype_helper_t_func_has_stkframe_hole', 'lowertype_helper_t_get_func_purged_bytes', 'lvar_locator_t___eq__', @@ -4368,9 +4259,6 @@ 'lvar_saved_infos_t__del', 'lvar_saved_infos_t_add_unique', 'lvar_saved_infos_t_at', - 'lvar_saved_infos_t_back', - 'lvar_saved_infos_t_back__SWIG_0', - 'lvar_saved_infos_t_back__SWIG_1', 'lvar_saved_infos_t_begin', 'lvar_saved_infos_t_begin__SWIG_0', 'lvar_saved_infos_t_begin__SWIG_1', @@ -4387,9 +4275,6 @@ 'lvar_saved_infos_t_find', 'lvar_saved_infos_t_find__SWIG_0', 'lvar_saved_infos_t_find__SWIG_1', - 'lvar_saved_infos_t_front', - 'lvar_saved_infos_t_front__SWIG_0', - 'lvar_saved_infos_t_front__SWIG_1', 'lvar_saved_infos_t_grow', 'lvar_saved_infos_t_has', 'lvar_saved_infos_t_inject', @@ -4485,20 +4370,24 @@ 'lvars_t_find_input_lvar', 'lvars_t_find_lvar', 'lvars_t_find_stkvar', - 'make_array_type', - 'make_ascii_string', 'make_name_auto', 'make_name_non_public', 'make_name_non_weak', 'make_name_public', 'make_name_user', 'make_name_weak', - 'make_num', - 'make_old_argloc', 'make_pointer', - 'make_ref', - 'make_visible_name', + 'map_code_ea', + 'map_code_ea__SWIG_0', + 'map_code_ea__SWIG_1', + 'map_data_ea', + 'map_data_ea__SWIG_0', + 'map_data_ea__SWIG_1', + 'map_ea', + 'map_ea__SWIG_0', + 'map_ea__SWIG_1', 'mark_cfunc_dirty', + 'mark_position', 'may_create_stkvars', 'may_trace_sp', 'mem2base', @@ -4524,9 +4413,6 @@ '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', @@ -4540,9 +4426,6 @@ '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', @@ -4571,9 +4454,70 @@ 'module_info_t_size_get', 'module_info_t_size_set', 'move_bpt_to_grp', + 'move_idcv', 'move_segm', 'move_segm_start', 'msg', + 'mutable_graph_t_belongs_get', + 'mutable_graph_t_belongs_set', + 'mutable_graph_t_calc_group_ea', + 'mutable_graph_t_change_group_visibility', + 'mutable_graph_t_clear', + 'mutable_graph_t_create_digraph_layout', + 'mutable_graph_t_create_group', + 'mutable_graph_t_del_custom_layout', + 'mutable_graph_t_delete_group', + 'mutable_graph_t_edges_get', + 'mutable_graph_t_edges_set', + 'mutable_graph_t_empty', + 'mutable_graph_t_exists', + 'mutable_graph_t_get_custom_layout', + 'mutable_graph_t_get_first_subgraph_node', + 'mutable_graph_t_get_graph_groups', + 'mutable_graph_t_get_next_subgraph_node', + 'mutable_graph_t_get_node_group', + 'mutable_graph_t_get_node_representative', + 'mutable_graph_t_gid_get', + 'mutable_graph_t_gid_set', + 'mutable_graph_t_is_collapsed_node', + 'mutable_graph_t_is_deleted_node', + 'mutable_graph_t_is_displayable_node', + 'mutable_graph_t_is_dot_node', + 'mutable_graph_t_is_group_node', + 'mutable_graph_t_is_simple_node', + 'mutable_graph_t_is_subgraph_node', + 'mutable_graph_t_is_uncollapsed_node', + 'mutable_graph_t_is_user_graph', + 'mutable_graph_t_is_visible_node', + 'mutable_graph_t_node_flags_get', + 'mutable_graph_t_node_flags_set', + 'mutable_graph_t_node_qty', + 'mutable_graph_t_nodes_get', + 'mutable_graph_t_nodes_set', + 'mutable_graph_t_npred', + 'mutable_graph_t_nrect', + 'mutable_graph_t_nrect__SWIG_0', + 'mutable_graph_t_nrect__SWIG_1', + 'mutable_graph_t_nsucc', + 'mutable_graph_t_org_preds_get', + 'mutable_graph_t_org_preds_set', + 'mutable_graph_t_org_succs_get', + 'mutable_graph_t_org_succs_set', + 'mutable_graph_t_pred', + 'mutable_graph_t_preds_get', + 'mutable_graph_t_preds_set', + 'mutable_graph_t_predset', + 'mutable_graph_t_reset', + 'mutable_graph_t_set_custom_layout', + 'mutable_graph_t_set_deleted_node', + 'mutable_graph_t_set_edge', + 'mutable_graph_t_set_graph_groups', + 'mutable_graph_t_set_node_group', + 'mutable_graph_t_size', + 'mutable_graph_t_succ', + 'mutable_graph_t_succs_get', + 'mutable_graph_t_succs_set', + 'mutable_graph_t_succset', 'nbits', 'negated_relation', 'netnode___eq__', @@ -4582,54 +4526,69 @@ 'netnode___ne__', 'netnode___ne____SWIG_0', 'netnode___ne____SWIG_1', - 'netnode_alt1st', - 'netnode_alt1st_idx8', 'netnode_altdel', 'netnode_altdel__SWIG_0', 'netnode_altdel__SWIG_1', 'netnode_altdel_all', + 'netnode_altdel_ea', 'netnode_altdel_idx8', + 'netnode_altfirst', + 'netnode_altfirst_idx8', 'netnode_altlast', 'netnode_altlast_idx8', - 'netnode_altnxt', - 'netnode_altnxt_idx8', + 'netnode_altnext', + 'netnode_altnext_idx8', 'netnode_altprev', 'netnode_altprev_idx8', 'netnode_altset', + 'netnode_altset_ea', 'netnode_altset_idx8', 'netnode_altshift', 'netnode_altval', + 'netnode_altval_ea', 'netnode_altval_idx8', 'netnode_blobsize', - 'netnode_char1st', - 'netnode_char1st_idx8', + 'netnode_blobsize_ea', 'netnode_chardel', + 'netnode_chardel_ea', 'netnode_chardel_idx8', + 'netnode_charfirst', + 'netnode_charfirst_idx8', 'netnode_charlast', 'netnode_charlast_idx8', - 'netnode_charnxt', - 'netnode_charnxt_idx8', + 'netnode_charnext', + 'netnode_charnext_idx8', 'netnode_charprev', 'netnode_charprev_idx8', 'netnode_charset', + 'netnode_charset_ea', 'netnode_charset_idx8', 'netnode_charshift', 'netnode_charval', + 'netnode_charval_ea', 'netnode_charval_idx8', 'netnode_copyto', 'netnode_create', 'netnode_create__SWIG_0', 'netnode_create__SWIG_1', 'netnode_delblob', + 'netnode_delblob_ea', 'netnode_delvalue', + 'netnode_eadel', + 'netnode_eadel_idx8', + 'netnode_eaget', + 'netnode_eaget_idx8', + 'netnode_easet', + 'netnode_easet_idx8', 'netnode_end', 'netnode_get_name', 'netnode_getblob', - 'netnode_hash1st', + 'netnode_getblob_ea', 'netnode_hashdel', 'netnode_hashdel_all', + 'netnode_hashfirst', 'netnode_hashlast', - 'netnode_hashnxt', + 'netnode_hashnext', 'netnode_hashprev', 'netnode_hashset', 'netnode_hashset_buf', @@ -4641,36 +4600,43 @@ 'netnode_index', 'netnode_kill', 'netnode_long_value', + 'netnode_lower_bound', + 'netnode_lower_bound_ea', + 'netnode_lower_bound_idx8', 'netnode_moveto', - 'netnode_name', 'netnode_next', 'netnode_prev', 'netnode_rename', 'netnode_set', 'netnode_set_long', 'netnode_setblob', + 'netnode_setblob_ea', 'netnode_start', - 'netnode_sup1st', - 'netnode_sup1st_idx8', 'netnode_supdel', 'netnode_supdel__SWIG_0', 'netnode_supdel__SWIG_1', 'netnode_supdel_all', + 'netnode_supdel_ea', 'netnode_supdel_idx8', 'netnode_supdel_range', 'netnode_supdel_range_idx8', + 'netnode_supfirst', + 'netnode_supfirst_idx8', 'netnode_suplast', 'netnode_suplast_idx8', - 'netnode_supnxt', - 'netnode_supnxt_idx8', + 'netnode_supnext', + 'netnode_supnext_idx8', 'netnode_supprev', 'netnode_supprev_idx8', 'netnode_supset', + 'netnode_supset_ea', 'netnode_supset_idx8', 'netnode_supshift', 'netnode_supstr', + 'netnode_supstr_ea', 'netnode_supstr_idx8', 'netnode_supval', + 'netnode_supval_ea', 'netnode_supval_idx8', 'netnode_valobj', 'netnode_valstr', @@ -4678,7 +4644,12 @@ 'new_DBG_Hooks', 'new_IDB_Hooks', 'new_IDP_Hooks', + 'new_TPointDouble', + 'new_TPointDouble__SWIG_0', + 'new_TPointDouble__SWIG_1', + 'new_TPointDouble__SWIG_2', 'new_UI_Hooks', + 'new_View_Hooks', 'new___qmutex_t', 'new___qsemaphore_t', 'new___qthread_t', @@ -4689,16 +4660,6 @@ 'new_action_update_ctx_t', 'new_addon_info_t', 'new_aloc_visitor_t', - 'new_area_t', - 'new_area_t__SWIG_0', - 'new_area_t__SWIG_1', - 'new_area_visitor2_t', - 'new_areacb_t', - 'new_areaset_t', - 'new_areaset_t__SWIG_0', - 'new_areaset_t__SWIG_1', - 'new_areaset_t__SWIG_2', - 'new_areavec_t', 'new_argloc_t', 'new_argloc_t__SWIG_0', 'new_argloc_t__SWIG_1', @@ -4711,7 +4672,6 @@ 'new_auto_display_t', 'new_bgcolors_t', 'new_bitfield_type_data_t', - 'new_block', 'new_boolvec_t', 'new_boolvec_t__SWIG_0', 'new_boolvec_t__SWIG_1', @@ -4738,17 +4698,16 @@ 'new_casm_t', 'new_casm_t__SWIG_0', 'new_casm_t__SWIG_1', + 'new_catch_t', + 'new_catchvec_t', + 'new_catchvec_t__SWIG_0', + 'new_catchvec_t__SWIG_1', 'new_cblock_t', 'new_ccase_t', 'new_ccases_t', 'new_cdo_t', 'new_ceinsn_t', 'new_cexpr_t', - 'new_cexpr_t__SWIG_0', - 'new_cexpr_t__SWIG_1', - 'new_cexpr_t__SWIG_2', - 'new_cexpr_t__SWIG_3', - 'new_cexpr_t__SWIG_4', 'new_cfor_t', 'new_cfunc_parentee_t', 'new_cfuncptr_t', @@ -4756,12 +4715,11 @@ 'new_cfuncptr_t__SWIG_1', 'new_cgoto_t', 'new_channel_redir_t', + 'new_chooser_item_attrs_t', 'new_cif_t', 'new_cif_t__SWIG_0', 'new_cif_t__SWIG_1', 'new_cinsn_t', - 'new_cinsn_t__SWIG_0', - 'new_cinsn_t__SWIG_1', 'new_cinsnptrvec_t', 'new_cinsnptrvec_t__SWIG_0', 'new_cinsnptrvec_t__SWIG_1', @@ -4771,7 +4729,6 @@ 'new_citem_locator_t', 'new_citem_locator_t__SWIG_0', 'new_citem_locator_t__SWIG_1', - 'new_citem_locator_t__SWIG_2', 'new_citem_t', 'new_citem_t__SWIG_0', 'new_citem_t__SWIG_1', @@ -4780,6 +4737,7 @@ 'new_cloop_t__SWIG_1', 'new_cloop_t__SWIG_2', 'new_cnumber_t', + 'new_codegen_t', 'new_compiler_info_t', 'new_const_aloc_visitor_t', 'new_creturn_t', @@ -4792,11 +4750,11 @@ 'new_ctree_items_t__SWIG_1', 'new_ctree_parentee_t', 'new_ctree_visitor_t', - 'new_curloc', - 'new_curloc__SWIG_0', - 'new_curloc__SWIG_1', + 'new_custom_data_type_ids_fids_array', 'new_custom_data_type_ids_t', 'new_cwhile_t', + 'new_data_format_t', + 'new_data_type_t', 'new_debapp_attrs_t', 'new_debug_event_t', 'new_disasm_line_t', @@ -4814,6 +4772,15 @@ 'new_ea_pointer', 'new_eamap_iterator_t', 'new_eamap_t', + 'new_edge_info_t', + 'new_edge_layout_point_t', + 'new_edge_layout_point_t__SWIG_0', + 'new_edge_layout_point_t__SWIG_1', + 'new_edge_layout_point_t__SWIG_2', + 'new_edge_segment_t', + 'new_edge_t', + 'new_edge_t__SWIG_0', + 'new_edge_t__SWIG_1', 'new_enum_const_t', 'new_enum_member_t', 'new_enum_member_visitor_t', @@ -4826,6 +4793,10 @@ 'new_excvec_t__SWIG_0', 'new_excvec_t__SWIG_1', 'new_fixup_data_t', + 'new_fixup_data_t__SWIG_0', + 'new_fixup_data_t__SWIG_1', + 'new_fixup_info_t', + 'new_fnum_array', 'new_fnumber_t', 'new_func_item_iterator_t', 'new_func_item_iterator_t__SWIG_0', @@ -4838,14 +4809,16 @@ 'new_func_tail_iterator_t__SWIG_0', 'new_func_tail_iterator_t__SWIG_1', 'new_func_type_data_t', - 'new_func_type_info_t', - 'new_funcarg_info_t', 'new_funcarg_t', 'new_funcargvec_t', 'new_funcargvec_t__SWIG_0', 'new_funcargvec_t__SWIG_1', - 'new_get_strmem_t', + 'new_graph_item_t', 'new_graph_location_info_t', + 'new_graph_node_visitor_t', + 'new_graph_path_visitor_t', + 'new_graph_visitor_t', + 'new_group_crinfo_t', 'new_hexrays_failure_t', 'new_hexrays_failure_t__SWIG_0', 'new_hexrays_failure_t__SWIG_1', @@ -4854,14 +4827,11 @@ 'new_hexwarns_t', 'new_hexwarns_t__SWIG_0', 'new_hexwarns_t__SWIG_1', - 'new_hidden_area_t', + 'new_hidden_range_t', 'new_highlighter_cbs_t', 'new_history_item_t', 'new_history_t', - 'new_ida_false_type', 'new_ida_lowertype_helper_t', - 'new_ida_true_type', - 'new_idainfo', 'new_idc_global_t', 'new_idc_global_t__SWIG_0', 'new_idc_global_t__SWIG_1', @@ -4870,36 +4840,36 @@ 'new_idc_value_t__SWIG_1', 'new_idc_value_t__SWIG_2', 'new_idc_value_t__SWIG_3', - 'new_idd_opinfo_old_t', + 'new_idc_values_t', + 'new_idc_values_t__SWIG_0', + 'new_idc_values_t__SWIG_1', 'new_idp_desc_t', 'new_idp_name_t', - 'new_ids_array', + 'new_insn_t', 'new_instant_dbgopts_t', 'new_int64vec_t', 'new_int64vec_t__SWIG_0', 'new_int64vec_t__SWIG_1', 'new_int_pointer', + 'new_interval_t', + 'new_interval_t__SWIG_0', + 'new_interval_t__SWIG_1', + 'new_interval_t__SWIG_2', 'new_intvec_t', 'new_intvec_t__SWIG_0', 'new_intvec_t__SWIG_1', - 'new_jumptable_info_t', 'new_linput_buffer_t', 'new_llabel_t', 'new_loader_input_t', 'new_loader_t', - 'new_location_t', - 'new_location_t__SWIG_0', - 'new_location_t__SWIG_1', 'new_locchange_md_t', 'new_lochist_entry_t', 'new_lochist_entry_t__SWIG_0', 'new_lochist_entry_t__SWIG_1', 'new_lochist_entry_t__SWIG_2', 'new_lochist_t', - 'new_lock_area', 'new_lock_func', 'new_lock_segment', - 'new_lock_segreg', 'new_lvar_locator_t', 'new_lvar_locator_t__SWIG_0', 'new_lvar_locator_t__SWIG_1', @@ -4924,14 +4894,24 @@ 'new_netnode__SWIG_2', 'new_node_info_t', 'new_node_iterator', + 'new_node_ordering_t', 'new_number_format_t', + 'new_op_t', 'new_operand_locator_t', - 'new_operand_locator_t__SWIG_0', - 'new_operand_locator_t__SWIG_1', + 'new_operands_array', 'new_operator_info_t', 'new_opinfo_t', 'new_plugin_info_t', + 'new_point_t', + 'new_point_t__SWIG_0', + 'new_point_t__SWIG_1', + 'new_pointseq_t', + 'new_predicate_t', + 'new_printop_t', 'new_process_info_t', + 'new_procinfo_vec_t', + 'new_procinfo_vec_t__SWIG_0', + 'new_procinfo_vec_t__SWIG_1', 'new_ptr_type_data_t', 'new_qbasic_block_t', 'new_qfile_t', @@ -4961,6 +4941,21 @@ 'new_qvector_snapshotvec_t', 'new_qvector_snapshotvec_t__SWIG_0', 'new_qvector_snapshotvec_t__SWIG_1', + 'new_range_t', + 'new_range_t__SWIG_0', + 'new_range_t__SWIG_1', + 'new_rangeset_t', + 'new_rangeset_t__SWIG_0', + 'new_rangeset_t__SWIG_1', + 'new_rangeset_t__SWIG_2', + 'new_rangevec_base_t', + 'new_rangevec_base_t__SWIG_0', + 'new_rangevec_base_t__SWIG_1', + 'new_rangevec_t', + 'new_rect_t', + 'new_rect_t__SWIG_0', + 'new_rect_t__SWIG_1', + 'new_rect_t__SWIG_2', 'new_refinfo_t', 'new_reg_info_t', 'new_regarg_t', @@ -4973,32 +4968,44 @@ 'new_regval_t__SWIG_0', 'new_regval_t__SWIG_1', 'new_regvar_t', + 'new_renderer_info_pos_t', 'new_renderer_info_t', 'new_renderer_pos_info_t', + 'new_row_info_t', 'new_rrel_t', 'new_scattered_aloc_t', - 'new_scattered_vloc_t', + 'new_scattered_segm_t', + 'new_screen_graph_selection_t', 'new_segm_move_info_t', 'new_segm_move_info_vec_t', 'new_segm_move_info_vec_t__SWIG_0', 'new_segm_move_info_vec_t__SWIG_1', 'new_segm_move_infos_t', 'new_segment_t', - 'new_segreg_area_t', - 'new_segreg_t', + 'new_seh_t', 'new_sel_array', 'new_sel_pointer', + 'new_selection_item_t', + 'new_selection_item_t__SWIG_0', + 'new_selection_item_t__SWIG_1', + 'new_selection_item_t__SWIG_2', + 'new_selection_item_t__SWIG_3', 'new_simd_info_t', 'new_simpleline_t', 'new_simpleline_t__SWIG_0', 'new_simpleline_t__SWIG_1', 'new_simpleline_t__SWIG_2', 'new_simpleline_t__SWIG_3', + 'new_sizevec_t', + 'new_sizevec_t__SWIG_0', + 'new_sizevec_t__SWIG_1', 'new_snapshot_t', + 'new_sreg_range_t', 'new_strarray_t', 'new_string_info_t', 'new_string_info_t__SWIG_0', 'new_string_info_t__SWIG_1', + 'new_strpath_ids_array', 'new_strpath_t', 'new_struct_field_visitor_t', 'new_strvec_t', @@ -5007,7 +5014,6 @@ 'new_strwinsetup_t', 'new_sval_pointer', 'new_tev_info_t', - 'new_text_options_t', 'new_text_sink_t', 'new_tid_array', 'new_til', @@ -5018,17 +5024,22 @@ 'new_tinfo_t__SWIG_1', 'new_tinfo_visitor_t', 'new_treeloc_t', + 'new_try_handler_t', + 'new_tryblk_t', + 'new_tryblk_t__SWIG_0', + 'new_tryblk_t__SWIG_1', + 'new_tryblks_t', + 'new_tryblks_t__SWIG_0', + 'new_tryblks_t__SWIG_1', 'new_twinpos_t', 'new_twinpos_t__SWIG_0', 'new_twinpos_t__SWIG_1', 'new_twinpos_t__SWIG_2', 'new_type_attr_t', + 'new_type_attrs_t', + 'new_type_attrs_t__SWIG_0', + 'new_type_attrs_t__SWIG_1', 'new_type_mods_t', - 'new_type_pair_t', - 'new_type_pair_t__SWIG_0', - 'new_type_pair_t__SWIG_1', - 'new_type_pair_t__SWIG_2', - 'new_type_pair_vec_t', 'new_typedef_type_data_t', 'new_typedef_type_data_t__SWIG_0', 'new_typedef_type_data_t__SWIG_1', @@ -5058,14 +5069,8 @@ 'new_uvalvec_t__SWIG_0', 'new_uvalvec_t__SWIG_1', 'new_valstr_t', - 'new_valstrs_deprecated2_t', - 'new_valstrs_deprecated_t', 'new_valstrs_t', 'new_var_ref_t', - 'new_varloc_t', - 'new_varloc_t__SWIG_0', - 'new_varloc_t__SWIG_1', - 'new_varpart_t', 'new_vc_printer_t', 'new_vd_failure_t', 'new_vd_failure_t__SWIG_0', @@ -5077,24 +5082,23 @@ 'new_vd_interr_t__SWIG_1', 'new_vd_printer_t', 'new_vdloc_t', + 'new_view_mouse_event_location_t', + 'new_view_mouse_event_t', 'new_xrefblk_t', 'new_xreflist_entry_t', 'new_xreflist_t', 'new_xreflist_t__SWIG_0', 'new_xreflist_t__SWIG_1', + 'next_addr', + 'next_chunk', 'next_head', + 'next_idcv_attr', 'next_inited', 'next_named_type', 'next_not_tail', + 'next_that', 'next_unknown', - 'nextaddr', - 'nextchunk', - 'nextthat', - 'noImmd', - 'noType', - 'noUsed', - 'noUsed__SWIG_0', - 'noUsed__SWIG_1', + 'node2ea', 'node_info_t_bg_color_get', 'node_info_t_bg_color_set', 'node_info_t_ea_get', @@ -5111,20 +5115,26 @@ 'node_iterator___eq__', 'node_iterator___ne__', 'node_iterator___ref__', + 'node_ordering_t_clear', + 'node_ordering_t_node', + 'node_ordering_t_resize', + 'node_ordering_t_set', + 'node_ordering_t_size', 'nomem', 'nomem__varargs__', 'notify_when', + 'num_flag', 'number_format_t_flags_get', 'number_format_t_flags_set', - 'number_format_t_getRadix', - 'number_format_t_isChar', - 'number_format_t_isDec', - 'number_format_t_isEnum', - 'number_format_t_isHex', - 'number_format_t_isNum', - 'number_format_t_isOct', - 'number_format_t_isStroff', + 'number_format_t_get_radix', + 'number_format_t_is_char', + 'number_format_t_is_dec', + 'number_format_t_is_enum', 'number_format_t_is_fixed', + 'number_format_t_is_hex', + 'number_format_t_is_numop', + 'number_format_t_is_oct', + 'number_format_t_is_stroff', 'number_format_t_needs_to_be_inverted', 'number_format_t_opnum_get', 'number_format_t_opnum_set', @@ -5136,9 +5146,8 @@ 'number_format_t_serial_set', 'number_format_t_type_name_get', 'number_format_t_type_name_set', - 'numflag', - 'octflag', - 'offflag', + 'oct_flag', + 'off_flag', 'op_adds_xrefs', 'op_bin', 'op_chr', @@ -5151,46 +5160,48 @@ 'op_oct', 'op_offset', 'op_offset_ex', + 'op_plain_offset', 'op_seg', 'op_stkvar', 'op_stroff', + 'op_t___get_addr__', + 'op_t___get_reg_phrase__', + 'op_t___get_specval__', + 'op_t___get_value__', + 'op_t___set_addr__', + 'op_t___set_reg_phrase__', + 'op_t___set_specval__', + 'op_t___set_value__', + 'op_t__from_ptrval__', 'op_t_assign', - 'op_t_create', - 'op_t_destroy', - 'op_t_get_addr', - 'op_t_get_dtyp', - 'op_t_get_flags', - 'op_t_get_n', - 'op_t_get_offb', - 'op_t_get_offo', - 'op_t_get_reg_phrase', - 'op_t_get_specflag1', - 'op_t_get_specflag2', - 'op_t_get_specflag3', - 'op_t_get_specflag4', - 'op_t_get_specval', - 'op_t_get_type', - 'op_t_get_value', - 'op_t_set_addr', - 'op_t_set_dtyp', - 'op_t_set_flags', - 'op_t_set_n', - 'op_t_set_offb', - 'op_t_set_offo', - 'op_t_set_reg_phrase', - 'op_t_set_specflag1', - 'op_t_set_specflag2', - 'op_t_set_specflag3', - 'op_t_set_specflag4', - 'op_t_set_specval', - 'op_t_set_type', - 'op_t_set_value', + 'op_t_clr_shown', + 'op_t_dtype_get', + 'op_t_dtype_set', + 'op_t_flags_get', + 'op_t_flags_set', + 'op_t_is_imm', + 'op_t_is_reg', + 'op_t_n_get', + 'op_t_n_set', + 'op_t_offb_get', + 'op_t_offb_set', + 'op_t_offo_get', + 'op_t_offo_set', + 'op_t_set_shown', + 'op_t_shown', + 'op_t_specflag1_get', + 'op_t_specflag1_set', + 'op_t_specflag2_get', + 'op_t_specflag2_set', + 'op_t_specflag3_get', + 'op_t_specflag3_set', + 'op_t_specflag4_get', + 'op_t_specflag4_set', + 'op_t_type_get', + 'op_t_type_set', 'op_uses_x', 'op_uses_y', 'op_uses_z', - 'openM', - 'openR', - 'openRT', 'open_bpts_window', 'open_calls_window', 'open_disasm_window', @@ -5215,7 +5226,6 @@ 'open_stack_window', 'open_strings_window', 'open_structs_window', - 'open_tform', 'open_threads_window', 'open_tils_window', 'open_trace_window', @@ -5232,6 +5242,10 @@ 'operand_locator_t_ea_set', 'operand_locator_t_opnum_get', 'operand_locator_t_opnum_set', + 'operands_array___getitem__', + 'operands_array___len__', + 'operands_array___setitem__', + 'operands_array_data_get', 'operator_info_t_fixtype_get', 'operator_info_t_fixtype_set', 'operator_info_t_flags_get', @@ -5255,53 +5269,125 @@ 'opinfo_t_tid_get', 'opinfo_t_tid_set', 'optimize_argloc', - 'optimize_varloc', - 'out_addr_tag', - 'out_colored_register_line', - 'out_keyword', - 'out_line', - 'out_long', - 'out_name_expr', - 'out_one_operand', - 'out_register', - 'out_symbol', - 'out_tagoff', - 'out_tagon', - 'owrdflag', + 'outctx_base_t__from_ptrval__', + 'outctx_base_t_close_comment', + 'outctx_base_t_clr_gen_label', + 'outctx_base_t_default_lnnum_get', + 'outctx_base_t_default_lnnum_set', + 'outctx_base_t_display_voids', + 'outctx_base_t_flush_buf', + 'outctx_base_t_flush_outbuf', + 'outctx_base_t_forbid_annotations', + 'outctx_base_t_force_code', + 'outctx_base_t_gen_block_cmt', + 'outctx_base_t_gen_border_line', + 'outctx_base_t_gen_cmt_line', + 'outctx_base_t_gen_cmt_line__varargs__', + 'outctx_base_t_gen_collapsed_line', + 'outctx_base_t_gen_collapsed_line__varargs__', + 'outctx_base_t_gen_empty_line', + 'outctx_base_t_gen_empty_line_without_annotations', + 'outctx_base_t_gen_printf', + 'outctx_base_t_gen_printf__varargs__', + 'outctx_base_t_gen_xref_lines', + 'outctx_base_t_get_stkvar', + 'outctx_base_t_init_lines_array', + 'outctx_base_t_insn_ea_get', + 'outctx_base_t_insn_ea_set', + 'outctx_base_t_multiline', + 'outctx_base_t_only_main_line', + 'outctx_base_t_out_addr_tag', + 'outctx_base_t_out_btoa', + 'outctx_base_t_out_char', + 'outctx_base_t_out_chars', + 'outctx_base_t_out_colored_register_line', + 'outctx_base_t_out_keyword', + 'outctx_base_t_out_line', + 'outctx_base_t_out_long', + 'outctx_base_t_out_name_expr', + 'outctx_base_t_out_printf', + 'outctx_base_t_out_printf__varargs__', + 'outctx_base_t_out_register', + 'outctx_base_t_out_spaces', + 'outctx_base_t_out_symbol', + 'outctx_base_t_out_tagoff', + 'outctx_base_t_out_tagon', + 'outctx_base_t_out_value', + 'outctx_base_t_outbuf_get', + 'outctx_base_t_outbuf_set', + 'outctx_base_t_print_label_now', + 'outctx_base_t_restore_ctxflags', + 'outctx_base_t_retrieve_cmt', + 'outctx_base_t_retrieve_name', + 'outctx_base_t_set_comment_addr', + 'outctx_base_t_set_gen_cmt', + 'outctx_base_t_set_gen_demangled_label', + 'outctx_base_t_set_gen_label', + 'outctx_base_t_set_gen_xrefs', + 'outctx_base_t_setup_outctx', + 'outctx_base_t_stack_view', + 'outctx_base_t_term_outctx', + 'outctx_t__from_ptrval__', + 'outctx_t_bin_ea_get', + 'outctx_t_bin_ea_set', + 'outctx_t_bin_state_get', + 'outctx_t_bin_state_set', + 'outctx_t_bin_width_get', + 'outctx_t_bin_width_set', + 'outctx_t_curlabel_get', + 'outctx_t_curlabel_set', + 'outctx_t_gen_func_footer', + 'outctx_t_gen_func_header', + 'outctx_t_gen_header', + 'outctx_t_gen_header_extra', + 'outctx_t_gen_xref_lines', + 'outctx_t_gl_bpsize_get', + 'outctx_t_gl_bpsize_set', + 'outctx_t_insn_get', + 'outctx_t_insn_set', + 'outctx_t_out_custom_mnem', + 'outctx_t_out_data', + 'outctx_t_out_immchar_cmts', + 'outctx_t_out_mnem', + 'outctx_t_out_mnemonic', + 'outctx_t_out_one_operand', + 'outctx_t_out_specea', + 'outctx_t_retrieve_cmt', + 'outctx_t_retrieve_name', + 'outctx_t_setup_outctx', + 'oword_flag', 'pack_idcobj_to_bv', 'pack_idcobj_to_idb', 'pack_object_to_bv', 'pack_object_to_idb', - 'packrealflag', + 'packreal_flag', 'parse_command_line3', 'parse_dbgopts', 'parse_decl', - 'parse_decl2', 'parse_decls', 'parse_reg_name', - 'parse_types2', 'parse_user_call', 'partial_type_num', 'patch_byte', - 'patch_long', - 'patch_many_bytes', + 'patch_bytes', + 'patch_dword', + 'patch_fixup_value', 'patch_qword', 'patch_word', 'peek_auto_queue', 'ph_get_cnbits', 'ph_get_dnbits', 'ph_get_flag', - 'ph_get_high_fixup_bits', 'ph_get_icode_return', 'ph_get_id', 'ph_get_instruc', 'ph_get_instruc_end', 'ph_get_instruc_start', 'ph_get_operand_info', - 'ph_get_regCodeSreg', - 'ph_get_regDataSreg', - 'ph_get_regFirstSreg', - 'ph_get_regLastSreg', + 'ph_get_reg_code_sreg', + 'ph_get_reg_data_sreg', + 'ph_get_reg_first_sreg', + 'ph_get_reg_last_sreg', 'ph_get_regnames', 'ph_get_segreg_size', 'ph_get_tbyte_size', @@ -5330,6 +5416,9 @@ 'place_t_rebase', 'place_t_toea', 'place_t_touval', + 'plan_and_wait', + 'plan_ea', + 'plan_range', 'plan_to_apply_idasgn', 'plgform_close', 'plgform_new', @@ -5356,30 +5445,80 @@ 'plugin_info_t_org_name_set', 'plugin_info_t_path_get', 'plugin_info_t_path_set', + 'point_t___eq__', + 'point_t___ne__', + 'point_t_add', + 'point_t_negate', + 'point_t_sub', + 'point_t_x_get', + 'point_t_x_set', + 'point_t_y_get', + 'point_t_y_set', + 'predicate_t_should_display', + 'prev_addr', + 'prev_chunk', 'prev_head', + 'prev_idcv_attr', 'prev_inited', 'prev_not_tail', + 'prev_that', 'prev_unknown', - 'prevaddr', - 'prevchunk', - 'prevthat', 'print_argloc', - 'print_ascii_string_type', 'print_decls', + 'print_idcv', + 'print_insn_mnem', + 'print_operand', + 'print_strlit_type', 'print_tinfo', 'print_type', - 'print_type2', - 'print_type3', - 'print_type_to_qstring', - 'print_varloc', 'print_vdloc', - 'printf_line', - 'printf_line__varargs__', + 'printop_t_flags_get', + 'printop_t_flags_set', + 'printop_t_get_ti', + 'printop_t_is_ti_valid_get', + 'printop_t_is_ti_valid_set', + 'printop_t_suspop_get', + 'printop_t_suspop_set', + 'printop_t_ti_get', + 'printop_t_ti_set', + 'process_archive', 'process_info_t_name_get', 'process_info_t_name_set', 'process_info_t_pid_get', 'process_info_t_pid_set', 'process_ui_action', + 'procinfo_vec_t___getitem__', + 'procinfo_vec_t___len__', + 'procinfo_vec_t___setitem__', + 'procinfo_vec_t_at', + 'procinfo_vec_t_begin', + 'procinfo_vec_t_begin__SWIG_0', + 'procinfo_vec_t_begin__SWIG_1', + 'procinfo_vec_t_capacity', + 'procinfo_vec_t_clear', + 'procinfo_vec_t_empty', + 'procinfo_vec_t_end', + 'procinfo_vec_t_end__SWIG_0', + 'procinfo_vec_t_end__SWIG_1', + 'procinfo_vec_t_erase', + 'procinfo_vec_t_erase__SWIG_0', + 'procinfo_vec_t_erase__SWIG_1', + 'procinfo_vec_t_extract', + 'procinfo_vec_t_grow', + 'procinfo_vec_t_inject', + 'procinfo_vec_t_insert', + 'procinfo_vec_t_pop_back', + 'procinfo_vec_t_push_back', + 'procinfo_vec_t_push_back__SWIG_0', + 'procinfo_vec_t_push_back__SWIG_1', + 'procinfo_vec_t_qclear', + 'procinfo_vec_t_reserve', + 'procinfo_vec_t_resize', + 'procinfo_vec_t_resize__SWIG_0', + 'procinfo_vec_t_resize__SWIG_1', + 'procinfo_vec_t_size', + 'procinfo_vec_t_swap', + 'procinfo_vec_t_truncate', 'ptr_type_data_t___eq__', 'ptr_type_data_t___ne__', 'ptr_type_data_t_based_ptr_size_get', @@ -5393,25 +5532,22 @@ 'ptr_type_data_t_taptr_bits_get', 'ptr_type_data_t_taptr_bits_set', 'put_byte', + 'put_bytes', 'put_dbg_byte', - 'put_long', - 'put_many_bytes', + 'put_dword', 'put_qword', 'put_word', - 'py_get_AskUsingForm', - 'py_get_OpenForm', + 'py_add_idc_func', + 'py_get_ask_form', 'py_get_call_idc_func', - 'py_get_global_cmd_link', + 'py_get_open_form', 'py_load_custom_icon_data', 'py_load_custom_icon_fn', - 'py_menu_item_callback', 'py_register_compiled_form', - 'py_set_idc_func_ex', 'py_ss_restore_callback', 'py_unregister_compiled_form', - 'pycim_get_tcustom_control', - 'pycim_get_tform', - 'pyg_add_command', + 'pycim_get_widget', + 'pycim_view_close', 'pyg_close', 'pyg_select_node', 'pyg_show', @@ -5428,9 +5564,7 @@ 'pyidag_bind', 'pyidag_unbind', 'pyscv_add_line', - 'pyscv_add_popup_menu', 'pyscv_clear_lines', - 'pyscv_clear_popup_menu', 'pyscv_close', 'pyscv_count', 'pyscv_del_line', @@ -5441,8 +5575,7 @@ 'pyscv_get_line', 'pyscv_get_pos', 'pyscv_get_selection', - 'pyscv_get_tcustom_control', - 'pyscv_get_tform', + 'pyscv_get_widget', 'pyscv_init', 'pyscv_insert_line', 'pyscv_is_focused', @@ -5451,9 +5584,11 @@ 'pyscv_refresh', 'pyscv_refresh_current', 'pyscv_show', + 'pyw_convert_defvals', 'pyw_register_idc_func', 'pyw_unregister_idc_func', 'qatoll', + 'qcleanline', 'qcontrol_tty', 'qdetach_tty', 'qexit', @@ -5506,10 +5641,7 @@ 'qflow_chart_t_succ', 'qflow_chart_t_title_get', 'qflow_chart_t_title_set', - 'qfsize', - 'qfsize64', 'qlgetz', - 'qlgetz64', 'qlist_cinsn_t___eq__', 'qlist_cinsn_t___ne__', 'qlist_cinsn_t_back', @@ -5546,13 +5678,9 @@ 'qlist_cinsn_t_rend__SWIG_1', 'qlist_cinsn_t_size', 'qlist_cinsn_t_swap', - 'qlseek64', - 'qlsize64', - 'qltell64', 'qrefcnt_obj_t_refcnt_get', 'qrefcnt_obj_t_refcnt_set', 'qrefcnt_obj_t_release', - 'qsplitpath', 'qstring_printer_t__print', 'qstring_printer_t__print__varargs__', 'qstring_printer_t_get_s', @@ -5584,9 +5712,6 @@ 'qvector_carg_t__del', 'qvector_carg_t_add_unique', 'qvector_carg_t_at', - 'qvector_carg_t_back', - 'qvector_carg_t_back__SWIG_0', - 'qvector_carg_t_back__SWIG_1', 'qvector_carg_t_begin', 'qvector_carg_t_begin__SWIG_0', 'qvector_carg_t_begin__SWIG_1', @@ -5603,9 +5728,6 @@ 'qvector_carg_t_find', 'qvector_carg_t_find__SWIG_0', 'qvector_carg_t_find__SWIG_1', - 'qvector_carg_t_front', - 'qvector_carg_t_front__SWIG_0', - 'qvector_carg_t_front__SWIG_1', 'qvector_carg_t_grow', 'qvector_carg_t_has', 'qvector_carg_t_inject', @@ -5630,9 +5752,6 @@ 'qvector_ccase_t__del', 'qvector_ccase_t_add_unique', 'qvector_ccase_t_at', - 'qvector_ccase_t_back', - 'qvector_ccase_t_back__SWIG_0', - 'qvector_ccase_t_back__SWIG_1', 'qvector_ccase_t_begin', 'qvector_ccase_t_begin__SWIG_0', 'qvector_ccase_t_begin__SWIG_1', @@ -5649,9 +5768,6 @@ 'qvector_ccase_t_find', 'qvector_ccase_t_find__SWIG_0', 'qvector_ccase_t_find__SWIG_1', - 'qvector_ccase_t_front', - 'qvector_ccase_t_front__SWIG_0', - 'qvector_ccase_t_front__SWIG_1', 'qvector_ccase_t_grow', 'qvector_ccase_t_has', 'qvector_ccase_t_inject', @@ -5676,9 +5792,6 @@ 'qvector_history_t__del', 'qvector_history_t_add_unique', 'qvector_history_t_at', - 'qvector_history_t_back', - 'qvector_history_t_back__SWIG_0', - 'qvector_history_t_back__SWIG_1', 'qvector_history_t_begin', 'qvector_history_t_begin__SWIG_0', 'qvector_history_t_begin__SWIG_1', @@ -5695,9 +5808,6 @@ 'qvector_history_t_find', 'qvector_history_t_find__SWIG_0', 'qvector_history_t_find__SWIG_1', - 'qvector_history_t_front', - 'qvector_history_t_front__SWIG_0', - 'qvector_history_t_front__SWIG_1', 'qvector_history_t_grow', 'qvector_history_t_has', 'qvector_history_t_inject', @@ -5722,9 +5832,6 @@ 'qvector_lvar_t__del', 'qvector_lvar_t_add_unique', 'qvector_lvar_t_at', - 'qvector_lvar_t_back', - 'qvector_lvar_t_back__SWIG_0', - 'qvector_lvar_t_back__SWIG_1', 'qvector_lvar_t_begin', 'qvector_lvar_t_begin__SWIG_0', 'qvector_lvar_t_begin__SWIG_1', @@ -5741,9 +5848,6 @@ 'qvector_lvar_t_find', 'qvector_lvar_t_find__SWIG_0', 'qvector_lvar_t_find__SWIG_1', - 'qvector_lvar_t_front', - 'qvector_lvar_t_front__SWIG_0', - 'qvector_lvar_t_front__SWIG_1', 'qvector_lvar_t_grow', 'qvector_lvar_t_has', 'qvector_lvar_t_inject', @@ -5769,9 +5873,6 @@ 'qvector_snapshotvec_t__del', 'qvector_snapshotvec_t_add_unique', 'qvector_snapshotvec_t_at', - 'qvector_snapshotvec_t_back', - 'qvector_snapshotvec_t_back__SWIG_0', - 'qvector_snapshotvec_t_back__SWIG_1', 'qvector_snapshotvec_t_begin', 'qvector_snapshotvec_t_begin__SWIG_0', 'qvector_snapshotvec_t_begin__SWIG_1', @@ -5788,9 +5889,6 @@ 'qvector_snapshotvec_t_find', 'qvector_snapshotvec_t_find__SWIG_0', 'qvector_snapshotvec_t_find__SWIG_1', - 'qvector_snapshotvec_t_front', - 'qvector_snapshotvec_t_front__SWIG_0', - 'qvector_snapshotvec_t_front__SWIG_1', 'qvector_snapshotvec_t_has', 'qvector_snapshotvec_t_inject', 'qvector_snapshotvec_t_insert', @@ -5806,19 +5904,142 @@ 'qvector_snapshotvec_t_size', 'qvector_snapshotvec_t_swap', 'qvector_snapshotvec_t_truncate', - 'qwait_timed', - 'qwrdflag', + 'qword_flag', + 'range_t___eq__', + 'range_t___gt__', + 'range_t___lt__', + 'range_t___ne__', + 'range_t__print', + 'range_t_clear', + 'range_t_compare', + 'range_t_contains', + 'range_t_contains__SWIG_0', + 'range_t_contains__SWIG_1', + 'range_t_empty', + 'range_t_end_ea_get', + 'range_t_end_ea_set', + 'range_t_extend', + 'range_t_intersect', + 'range_t_overlaps', + 'range_t_print', + 'range_t_size', + 'range_t_start_ea_get', + 'range_t_start_ea_set', + 'rangeset_t___eq__', + 'rangeset_t___ne__', + 'rangeset_t__print', + 'rangeset_t_add', + 'rangeset_t_add__SWIG_0', + 'rangeset_t_add__SWIG_1', + 'rangeset_t_add__SWIG_2', + 'rangeset_t_begin', + 'rangeset_t_begin__SWIG_0', + 'rangeset_t_begin__SWIG_1', + 'rangeset_t_cached_range', + 'rangeset_t_clear', + 'rangeset_t_contains', + 'rangeset_t_contains__SWIG_0', + 'rangeset_t_contains__SWIG_1', + 'rangeset_t_empty', + 'rangeset_t_end', + 'rangeset_t_end__SWIG_0', + 'rangeset_t_end__SWIG_1', + 'rangeset_t_find_range', + 'rangeset_t_getrange', + 'rangeset_t_has_common', + 'rangeset_t_has_common__SWIG_0', + 'rangeset_t_has_common__SWIG_1', + 'rangeset_t_includes', + 'rangeset_t_intersect', + 'rangeset_t_is_equal', + 'rangeset_t_is_subset_of', + 'rangeset_t_lastrange', + 'rangeset_t_next_addr', + 'rangeset_t_next_range', + 'rangeset_t_nranges', + 'rangeset_t_prev_addr', + 'rangeset_t_prev_range', + 'rangeset_t_sub', + 'rangeset_t_sub__SWIG_0', + 'rangeset_t_sub__SWIG_1', + 'rangeset_t_sub__SWIG_2', + 'rangeset_t_swap', + 'rangevec_base_t___eq__', + 'rangevec_base_t___getitem__', + 'rangevec_base_t___len__', + 'rangevec_base_t___ne__', + 'rangevec_base_t___setitem__', + 'rangevec_base_t__del', + 'rangevec_base_t_add_unique', + 'rangevec_base_t_at', + 'rangevec_base_t_begin', + 'rangevec_base_t_begin__SWIG_0', + 'rangevec_base_t_begin__SWIG_1', + 'rangevec_base_t_capacity', + 'rangevec_base_t_clear', + 'rangevec_base_t_empty', + 'rangevec_base_t_end', + 'rangevec_base_t_end__SWIG_0', + 'rangevec_base_t_end__SWIG_1', + 'rangevec_base_t_erase', + 'rangevec_base_t_erase__SWIG_0', + 'rangevec_base_t_erase__SWIG_1', + 'rangevec_base_t_extract', + 'rangevec_base_t_find', + 'rangevec_base_t_find__SWIG_0', + 'rangevec_base_t_find__SWIG_1', + 'rangevec_base_t_grow', + 'rangevec_base_t_has', + 'rangevec_base_t_inject', + 'rangevec_base_t_insert', + 'rangevec_base_t_pop_back', + 'rangevec_base_t_push_back', + 'rangevec_base_t_push_back__SWIG_0', + 'rangevec_base_t_push_back__SWIG_1', + 'rangevec_base_t_qclear', + 'rangevec_base_t_reserve', + 'rangevec_base_t_resize', + 'rangevec_base_t_resize__SWIG_0', + 'rangevec_base_t_resize__SWIG_1', + 'rangevec_base_t_size', + 'rangevec_base_t_swap', + 'rangevec_base_t_truncate', 'read_dbg_memory', + 'read_range_selection', 'read_regargs', 'read_selection', 'read_tinfo_bitfield_value', 'readbytes', - 'readsel2', 'reanalyze_callers', 'reanalyze_function', + 'reanalyze_noret_flag', 'rebase_program', 'rebuild_nlist', 'recalc_spd', + 'rect_t___eq__', + 'rect_t___ne__', + 'rect_t_area', + 'rect_t_bottom_get', + 'rect_t_bottom_set', + 'rect_t_bottomright', + 'rect_t_center', + 'rect_t_contains', + 'rect_t_empty', + 'rect_t_grow', + 'rect_t_height', + 'rect_t_intersect', + 'rect_t_is_intersection_empty', + 'rect_t_left_get', + 'rect_t_left_set', + 'rect_t_make_union', + 'rect_t_move_by', + 'rect_t_move_to', + 'rect_t_right_get', + 'rect_t_right_set', + 'rect_t_top_get', + 'rect_t_top_set', + 'rect_t_topleft', + 'rect_t_width', 'refinfo_t_base_get', 'refinfo_t_base_set', 'refinfo_t_flags_get', @@ -5829,6 +6050,7 @@ 'refinfo_t_is_rvaoff', 'refinfo_t_is_signed', 'refinfo_t_is_subtract', + 'refinfo_t_is_target_optional', 'refinfo_t_no_base_xref', 'refinfo_t_set_type', 'refinfo_t_target_get', @@ -5837,12 +6059,12 @@ 'refinfo_t_tdelta_set', 'refinfo_t_type', 'refresh_chooser', + 'refresh_choosers', 'refresh_debugger_memory', 'refresh_idaview', 'refresh_idaview_anyway', - 'refresh_lists', 'refresh_navband', - 'refresh_strlist', + 'refresh_viewer', 'reg_data_type', 'reg_delete', 'reg_delete_subkey', @@ -5889,9 +6111,6 @@ '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', @@ -5908,9 +6127,6 @@ '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', @@ -5978,17 +6194,25 @@ 'reload_file', 'reloc_value', 'relocate_relobj', + 'remember_problem', + 'remove_abi_opts', 'remove_command_interpreter', - 'remove_extlang', 'remove_func_tail', 'remove_hexrays_callback', 'remove_pointer', 'remove_tinfo_pointer', - 'remove_type_pointer', 'rename_bptgrp', + 'rename_encoding', 'rename_entry', - 'rename_named_type', 'rename_regvar', + 'renderer_info_pos_t___eq__', + 'renderer_info_pos_t___ne__', + 'renderer_info_pos_t_cx_get', + 'renderer_info_pos_t_cx_set', + 'renderer_info_pos_t_cy_get', + 'renderer_info_pos_t_cy_set', + 'renderer_info_pos_t_node_get', + 'renderer_info_pos_t_node_set', 'renderer_info_t___eq__', 'renderer_info_t___ne__', 'renderer_info_t_clear', @@ -6010,9 +6234,6 @@ 'renderer_pos_info_t_sx_set', 'reorder_dummy_names', 'repaint_custom_viewer', - 'replace_subtypes', - 'replace_subtypes2', - 'replace_tabs', 'replace_wait_box', 'replace_wait_box__varargs__', 'request_add_bpt', @@ -6049,8 +6270,7 @@ 'request_step_until_ret', 'request_suspend_process', 'request_suspend_thread', - 'resolve_complex_type2', - 'resolve_typedef2', + 'resolve_typedef', 'restore_database_snapshot', 'restore_user_cmts', 'restore_user_defined_calls', @@ -6066,19 +6286,24 @@ 'retrieve_input_file_sha256', 'retrieve_input_file_size', 'retrieve_member_info', + 'revert_byte', 'revert_ida_decisions', + 'row_info_t_bottom_get', + 'row_info_t_bottom_set', + 'row_info_t_height', + 'row_info_t_nodes_get', + 'row_info_t_nodes_set', + 'row_info_t_top_get', + 'row_info_t_top_set', 'rrel_t_off_get', 'rrel_t_off_set', 'rrel_t_reg_get', 'rrel_t_reg_set', 'run_plugin', 'run_requests', - 'run_statements', 'run_to', 'save_database', - 'save_database_ex', 'save_struc', - 'save_struc2', 'save_tinfo', 'save_trace_file', 'save_user_cmts', @@ -6088,10 +6313,21 @@ 'save_user_lvar_settings', 'save_user_numforms', 'save_user_unions', + 'scattered_segm_t_name_get', + 'scattered_segm_t_name_set', 'score_tinfo', - 'scr2idb', + 'screen_graph_selection_t_add', + 'screen_graph_selection_t_add_node', + 'screen_graph_selection_t_add_point', + 'screen_graph_selection_t_del_node', + 'screen_graph_selection_t_del_point', + 'screen_graph_selection_t_has', + 'screen_graph_selection_t_items_count', + 'screen_graph_selection_t_nodes_count', + 'screen_graph_selection_t_points_count', + 'screen_graph_selection_t_sub', 'search_down', - 'segflag', + 'seg_flag', 'segm_adjust_diff', 'segm_adjust_ea', 'segm_move_info_t___eq__', @@ -6110,9 +6346,6 @@ 'segm_move_info_vec_t__del', 'segm_move_info_vec_t_add_unique', 'segm_move_info_vec_t_at', - 'segm_move_info_vec_t_back', - 'segm_move_info_vec_t_back__SWIG_0', - 'segm_move_info_vec_t_back__SWIG_1', 'segm_move_info_vec_t_begin', 'segm_move_info_vec_t_begin__SWIG_0', 'segm_move_info_vec_t_begin__SWIG_1', @@ -6129,9 +6362,6 @@ 'segm_move_info_vec_t_find', 'segm_move_info_vec_t_find__SWIG_0', 'segm_move_info_vec_t_find__SWIG_1', - 'segm_move_info_vec_t_front', - 'segm_move_info_vec_t_front__SWIG_0', - 'segm_move_info_vec_t_front__SWIG_1', 'segm_move_info_vec_t_grow', 'segm_move_info_vec_t_has', 'segm_move_info_vec_t_inject', @@ -6164,8 +6394,8 @@ 'segment_t_comorg', 'segment_t_defsr_get', 'segment_t_defsr_set', - 'segment_t_endEA_get', - 'segment_t_endEA_set', + 'segment_t_end_ea_get', + 'segment_t_end_ea_set', 'segment_t_flags_get', 'segment_t_flags_set', 'segment_t_is_hidden_segtype', @@ -6188,24 +6418,21 @@ 'segment_t_set_loader_segm', 'segment_t_set_ob_ok', 'segment_t_set_visible_segm', - 'segment_t_startEA_get', - 'segment_t_startEA_set', + 'segment_t_start_ea_get', + 'segment_t_start_ea_set', 'segment_t_type_get', 'segment_t_type_set', 'segment_t_update', 'segment_t_use32', 'segment_t_use64', - 'segreg_area_t_tag_get', - 'segreg_area_t_tag_set', - 'segreg_area_t_val_get', - 'segreg_area_t_val_set', - 'segreg_t_reg', - 'segreg_t_setregs', - 'segreg_t_settags', - 'segreg_t_tag', - 'segreg_t_undefregs', 'segtype', + 'seh_t_clear', + 'seh_t_filter_get', + 'seh_t_filter_set', + 'seh_t_seh_code_get', + 'seh_t_seh_code_set', 'sel2ea', + 'sel2para', 'sel_array___getitem__', 'sel_array___setitem__', 'sel_array_cast', @@ -6214,13 +6441,19 @@ 'sel_pointer_cast', 'sel_pointer_frompointer', 'sel_pointer_value', - 'select_extlang', 'select_thread', + 'selection_item_t___eq__', + 'selection_item_t___lt__', + 'selection_item_t___ne__', + 'selection_item_t_compare', + 'selection_item_t_elp_get', + 'selection_item_t_elp_set', + 'selection_item_t_is_node_get', + 'selection_item_t_is_node_set', + 'selection_item_t_node_get', + 'selection_item_t_node_set', 'send_database', 'serialize_tinfo', - 'setBreak', - 'setFlags', - 'setStat', 'set__bnot0', 'set__bnot1', 'set__invsign0', @@ -6231,9 +6464,10 @@ 'set_aflags', 'set_align_flow', 'set_alignment', + 'set_archive_path', 'set_array_parameters', 'set_asm_inc_file', - 'set_auto_plugins', + 'set_auto_state', 'set_bblk_trace_options', 'set_bmask_cmt', 'set_bmask_name', @@ -6242,6 +6476,7 @@ 'set_bptloc_string', 'set_c_header_path', 'set_c_macros', + 'set_cancelled', 'set_cmt', 'set_code_viewer_handler', 'set_code_viewer_is_source', @@ -6252,14 +6487,12 @@ 'set_code_viewer_user_data', 'set_colored_item', 'set_compiler', - 'set_compiler2', 'set_compiler_id', - 'set_complex_n', - 'set_const_cmt', - 'set_const_name', + 'set_compiler_string', + 'set_cp_validity', 'set_custom_data_type_ids', - 'set_custom_fixup_ex', 'set_custom_viewer_qt_aware', + 'set_database_flag', 'set_dbg_default_options', 'set_dbg_options', 'set_dbg_options__SWIG_0', @@ -6269,7 +6502,7 @@ 'set_debugger_options', 'set_default_dataseg', 'set_default_encoding_idx', - 'set_default_segreg_value', + 'set_default_sreg_value', 'set_defsr', 'set_dock_pos', 'set_dummy_name', @@ -6288,25 +6521,31 @@ 'set_enum_width', 'set_fixed_spd', 'set_fixup', - 'set_fixup_ex', 'set_forced_operand', 'set_frame_size', 'set_func_cmt', + 'set_func_end', 'set_func_name_if_jumpfunc', + 'set_func_start', 'set_func_trace_options', + 'set_gotea', 'set_group_selector', 'set_has_lname', 'set_has_ti', 'set_has_ti0', 'set_has_ti1', 'set_header_path', + 'set_highlight', 'set_highlight_trace_options', + 'set_ida_state', + 'set_idcv_attr', + 'set_idcv_slice', 'set_ids_modnode', 'set_imagebase', + 'set_immd', 'set_insn_trace_options', 'set_int_dbg_options', 'set_item_color', - 'set_jumptable_info', 'set_libitem', 'set_lzero', 'set_lzero0', @@ -6314,26 +6553,20 @@ 'set_manual_insn', 'set_member_cmt', 'set_member_name', - 'set_member_ti', 'set_member_tinfo', - 'set_member_tinfo2', 'set_member_type', - 'set_menu_item_icon', 'set_name', - 'set_name__SWIG_0', - 'set_name__SWIG_1', - 'set_named_type64', 'set_nav_colorizer', 'set_node_info', - 'set_node_info2', 'set_noret', 'set_noret_insn', 'set_notcode', + 'set_notproc', 'set_numbered_type', - 'set_offset', - 'set_op_tinfo2', + 'set_op_tinfo', 'set_op_type', 'set_opinfo', + 'set_path', 'set_process_options', 'set_process_state', 'set_processor_type', @@ -6348,37 +6581,33 @@ 'set_resume_mode', 'set_retfp', 'set_root_filename', - 'set_scattered_varloc', 'set_script_timeout', 'set_segm_addressing', 'set_segm_base', 'set_segm_class', 'set_segm_end', 'set_segm_name', - 'set_segm_name__varargs__', 'set_segm_start', 'set_segment_cmt', 'set_segment_translations', 'set_selector', 'set_source_linnum', - 'set_spoils', 'set_sreg_at_next_code', 'set_step_trace_options', - 'set_strlist_options', + 'set_str_type', 'set_struc_align', 'set_struc_cmt', 'set_struc_hidden', 'set_struc_idx', 'set_struc_listed', 'set_struc_name', - 'set_switch_info_ex', + 'set_switch_info', 'set_switch_parent', 'set_tail_owner', 'set_target_assembler', 'set_terse_struc', 'set_tilcmt', 'set_tinfo', - 'set_tinfo2', 'set_tinfo_attr', 'set_tinfo_attrs', 'set_tinfo_property', @@ -6388,12 +6617,12 @@ 'set_trace_size', 'set_type', 'set_type_alias', - 'set_typeinfo', 'set_usemodsp', 'set_user_defined_prefix', 'set_usersp', 'set_userti', 'set_view_renderer_type', + 'set_viewer_graph', 'set_visible_func', 'set_visible_item', 'set_visible_segm', @@ -6401,12 +6630,12 @@ 'setup_selector', 'should_create_stkvars', 'should_trace_sp', - 'showAddr', - 'showAllComments', - 'showAuto', - 'showComments', - 'showRepeatables', + 'show_addr', + 'show_all_comments', + 'show_auto', + 'show_comments', 'show_name', + 'show_repeatables', 'show_wait_box', 'show_wait_box__varargs__', 'simd_info_t_match_pattern', @@ -6427,8 +6656,46 @@ 'simpleline_t_line_get', 'simpleline_t_line_set', 'sizeof_ldbl', - 'skip_spoiled_info', - 'skip_varloc', + 'sizevec_t___eq__', + 'sizevec_t___getitem__', + 'sizevec_t___len__', + 'sizevec_t___ne__', + 'sizevec_t___setitem__', + 'sizevec_t__del', + 'sizevec_t_add_unique', + 'sizevec_t_at', + 'sizevec_t_begin', + 'sizevec_t_begin__SWIG_0', + 'sizevec_t_begin__SWIG_1', + 'sizevec_t_capacity', + 'sizevec_t_clear', + 'sizevec_t_empty', + 'sizevec_t_end', + 'sizevec_t_end__SWIG_0', + 'sizevec_t_end__SWIG_1', + 'sizevec_t_erase', + 'sizevec_t_erase__SWIG_0', + 'sizevec_t_erase__SWIG_1', + 'sizevec_t_extract', + 'sizevec_t_find', + 'sizevec_t_find__SWIG_0', + 'sizevec_t_find__SWIG_1', + 'sizevec_t_grow', + 'sizevec_t_has', + 'sizevec_t_inject', + 'sizevec_t_insert', + 'sizevec_t_pop_back', + 'sizevec_t_push_back', + 'sizevec_t_push_back__SWIG_0', + 'sizevec_t_push_back__SWIG_1', + 'sizevec_t_qclear', + 'sizevec_t_reserve', + 'sizevec_t_resize', + 'sizevec_t_resize__SWIG_0', + 'sizevec_t_resize__SWIG_1', + 'sizevec_t_size', + 'sizevec_t_swap', + 'sizevec_t_truncate', 'snapshot_t___eq__', 'snapshot_t___ge__', 'snapshot_t___gt__', @@ -6446,21 +6713,21 @@ 'snapshot_t_flags_set', 'snapshot_t_id_get', 'snapshot_t_id_set', - 'splitSRarea1', - 'split_old_argloc', - 'split_srarea', + 'split_sreg_range', + 'sreg_range_t_tag_get', + 'sreg_range_t_tag_set', + 'sreg_range_t_val_get', + 'sreg_range_t_val_set', 'start_process', - 'std_gen_func_header', - 'std_gen_segm_footer', + 'std_out_segm_footer', 'step_into', 'step_over', 'step_until_ret', - 'stkvarflag', + 'stkvar_flag', 'store_exceptions', 'store_til', 'str2ea', 'str2reg', - 'str2regf', 'str2user', 'strarray', 'strarray_t_code_get', @@ -6474,9 +6741,13 @@ 'string_info_t_length_set', 'string_info_t_type_get', 'string_info_t_type_set', - 'strlwr', + 'strlit_flag', 'stroff_as_size', - 'stroffflag', + 'stroff_flag', + 'strpath_ids_array___getitem__', + 'strpath_ids_array___len__', + 'strpath_ids_array___setitem__', + 'strpath_ids_array_data_get', 'strpath_t___getIds', 'strpath_t_delta_get', 'strpath_t_delta_set', @@ -6484,6 +6755,7 @@ 'strpath_t_ids_set', 'strpath_t_len_get', 'strpath_t_len_set', + 'stru_flag', 'struc_t_age_get', 'struc_t_age_set', 'struc_t_from_til', @@ -6493,6 +6765,7 @@ 'struc_t_id_get', 'struc_t_id_set', 'struc_t_is_choosable', + 'struc_t_is_frame', 'struc_t_is_ghost', 'struc_t_is_hidden', 'struc_t_is_union', @@ -6512,15 +6785,10 @@ 'structplace_t_idx_set', 'structplace_t_offset_get', 'structplace_t_offset_set', - 'struflag', - 'strupr', 'strvec_t___getitem__', 'strvec_t___len__', 'strvec_t___setitem__', 'strvec_t_at', - 'strvec_t_back', - 'strvec_t_back__SWIG_0', - 'strvec_t_back__SWIG_1', 'strvec_t_begin', 'strvec_t_begin__SWIG_0', 'strvec_t_begin__SWIG_1', @@ -6534,9 +6802,6 @@ 'strvec_t_erase__SWIG_0', 'strvec_t_erase__SWIG_1', 'strvec_t_extract', - 'strvec_t_front', - 'strvec_t_front__SWIG_0', - 'strvec_t_front__SWIG_1', 'strvec_t_grow', 'strvec_t_inject', 'strvec_t_insert', @@ -6552,12 +6817,10 @@ 'strvec_t_size', 'strvec_t_swap', 'strvec_t_truncate', + 'strwinsetup_t__get_strtypes', + 'strwinsetup_t__set_strtypes', 'strwinsetup_t_display_only_existing_strings_get', 'strwinsetup_t_display_only_existing_strings_set', - 'strwinsetup_t_ea1_get', - 'strwinsetup_t_ea1_set', - 'strwinsetup_t_ea2_get', - 'strwinsetup_t_ea2_set', 'strwinsetup_t_ignore_heads_get', 'strwinsetup_t_ignore_heads_set', 'strwinsetup_t_is_initialized', @@ -6565,44 +6828,40 @@ 'strwinsetup_t_minlen_set', 'strwinsetup_t_only_7bit_get', 'strwinsetup_t_only_7bit_set', - 'strwinsetup_t_strtypes_get', - 'strwinsetup_t_strtypes_set', 'suspend_process', 'suspend_thread', 'sval_pointer_assign', 'sval_pointer_cast', 'sval_pointer_frompointer', 'sval_pointer_value', - 'switch_info_ex_t_assign', - 'switch_info_ex_t_create', - 'switch_info_ex_t_destroy', - 'switch_info_ex_t_get_custom', - 'switch_info_ex_t_get_defjump', - 'switch_info_ex_t_get_elbase', - 'switch_info_ex_t_get_flags', - 'switch_info_ex_t_get_flags2', - 'switch_info_ex_t_get_ind_lowcase', - 'switch_info_ex_t_get_jcases', - 'switch_info_ex_t_get_jumps', - 'switch_info_ex_t_get_ncases', - 'switch_info_ex_t_get_regdtyp', - 'switch_info_ex_t_get_regnum', - 'switch_info_ex_t_get_startea', - 'switch_info_ex_t_get_values_lowcase', - 'switch_info_ex_t_set_custom', - 'switch_info_ex_t_set_defjump', - 'switch_info_ex_t_set_elbase', - 'switch_info_ex_t_set_flags', - 'switch_info_ex_t_set_flags2', - 'switch_info_ex_t_set_ind_lowcase', - 'switch_info_ex_t_set_jcases', - 'switch_info_ex_t_set_jumps', - 'switch_info_ex_t_set_ncases', - 'switch_info_ex_t_set_regdtyp', - 'switch_info_ex_t_set_regnum', - 'switch_info_ex_t_set_startea', - 'switch_info_ex_t_set_values_lowcase', - 'switchto_tform', + 'swap_idcvs', + 'switch_info_t_assign', + 'switch_info_t_create', + 'switch_info_t_destroy', + 'switch_info_t_get_custom', + 'switch_info_t_get_defjump', + 'switch_info_t_get_elbase', + 'switch_info_t_get_flags', + 'switch_info_t_get_ind_lowcase', + 'switch_info_t_get_jcases', + 'switch_info_t_get_jumps', + 'switch_info_t_get_ncases', + 'switch_info_t_get_regdtype', + 'switch_info_t_get_regnum', + 'switch_info_t_get_startea', + 'switch_info_t_get_values_lowcase', + 'switch_info_t_set_custom', + 'switch_info_t_set_defjump', + 'switch_info_t_set_elbase', + 'switch_info_t_set_flags', + 'switch_info_t_set_ind_lowcase', + 'switch_info_t_set_jcases', + 'switch_info_t_set_jumps', + 'switch_info_t_set_ncases', + 'switch_info_t_set_regdtype', + 'switch_info_t_set_regnum', + 'switch_info_t_set_startea', + 'switch_info_t_set_values_lowcase', 'tag_addr', 'tag_advance', 'tag_remove', @@ -6611,21 +6870,14 @@ 'tag_strlen', 'take_database_snapshot', 'take_memory_snapshot', - 'tbytflag', + 'tbyte_flag', 'term_hexrays_plugin', - 'term_output_buffer', 'tev_info_t_ea_get', 'tev_info_t_ea_set', 'tev_info_t_tid_get', 'tev_info_t_tid_set', 'tev_info_t_type_get', 'tev_info_t_type_set', - 'text_options_t_copy_from_inf', - 'text_options_t_copy_to_inf', - 'text_options_t_graph_get', - 'text_options_t_graph_set', - 'text_options_t_text_get', - 'text_options_t_text_set', 'text_sink_t__print', 'textctrl_info_t_assign', 'textctrl_info_t_create', @@ -6642,7 +6894,6 @@ 'tid_array___setitem__', 'tid_array_cast', 'tid_array_frompointer', - 'til2idb', 'til_symbol_t_name_get', 'til_symbol_t_name_set', 'til_symbol_t_til_get', @@ -6772,6 +7023,7 @@ 'tinfo_t_is_decl_float', 'tinfo_t_is_decl_floating', 'tinfo_t_is_decl_func', + 'tinfo_t_is_decl_int', 'tinfo_t_is_decl_int128', 'tinfo_t_is_decl_int16', 'tinfo_t_is_decl_int32', @@ -6807,6 +7059,7 @@ 'tinfo_t_is_func', 'tinfo_t_is_funcptr', 'tinfo_t_is_high_func', + 'tinfo_t_is_int', 'tinfo_t_is_int128', 'tinfo_t_is_int16', 'tinfo_t_is_int32', @@ -6854,6 +7107,7 @@ 'tinfo_t_set_modifiers', 'tinfo_t_set_named_type', 'tinfo_t_set_numbered_type', + 'tinfo_t_set_symbol_type', 'tinfo_t_set_volatile', 'tinfo_t_swap', 'tinfo_t_write_bitfield_value', @@ -6862,7 +7116,7 @@ 'tinfo_visitor_t_state_get', 'tinfo_visitor_t_state_set', 'tinfo_visitor_t_visit_type', - 'toEA', + 'to_ea', 'toggle_bnot', 'toggle_lzero', 'toggle_sign', @@ -6872,19 +7126,107 @@ 'treeloc_t_ea_set', 'treeloc_t_itp_get', 'treeloc_t_itp_set', - 'tribyteflag', + 'try_handler_t_clear', + 'try_handler_t_disp_get', + 'try_handler_t_disp_set', + 'try_handler_t_fpreg_get', + 'try_handler_t_fpreg_set', 'try_to_add_libfunc', + 'tryblk_t_clear', + 'tryblk_t_cpp', + 'tryblk_t_empty', + 'tryblk_t_get_kind', + 'tryblk_t_is_cpp', + 'tryblk_t_is_seh', + 'tryblk_t_level_get', + 'tryblk_t_level_set', + 'tryblk_t_seh', + 'tryblk_t_set_cpp', + 'tryblk_t_set_seh', + 'tryblks_t___eq__', + 'tryblks_t___getitem__', + 'tryblks_t___len__', + 'tryblks_t___ne__', + 'tryblks_t___setitem__', + 'tryblks_t__del', + 'tryblks_t_add_unique', + 'tryblks_t_at', + 'tryblks_t_begin', + 'tryblks_t_begin__SWIG_0', + 'tryblks_t_begin__SWIG_1', + 'tryblks_t_capacity', + 'tryblks_t_clear', + 'tryblks_t_empty', + 'tryblks_t_end', + 'tryblks_t_end__SWIG_0', + 'tryblks_t_end__SWIG_1', + 'tryblks_t_erase', + 'tryblks_t_erase__SWIG_0', + 'tryblks_t_erase__SWIG_1', + 'tryblks_t_extract', + 'tryblks_t_find', + 'tryblks_t_find__SWIG_0', + 'tryblks_t_find__SWIG_1', + 'tryblks_t_grow', + 'tryblks_t_has', + 'tryblks_t_inject', + 'tryblks_t_insert', + 'tryblks_t_pop_back', + 'tryblks_t_push_back', + 'tryblks_t_push_back__SWIG_0', + 'tryblks_t_push_back__SWIG_1', + 'tryblks_t_qclear', + 'tryblks_t_reserve', + 'tryblks_t_resize', + 'tryblks_t_resize__SWIG_0', + 'tryblks_t_resize__SWIG_1', + 'tryblks_t_size', + 'tryblks_t_swap', + 'tryblks_t_truncate', 'twinpos_t___eq__', 'twinpos_t___ne__', 'twinpos_t_at_get', 'twinpos_t_at_set', 'twinpos_t_x_get', 'twinpos_t_x_set', + 'type_attr_t___ge__', + 'type_attr_t___lt__', 'type_attr_t_key_get', 'type_attr_t_key_set', 'type_attr_t_value_get', 'type_attr_t_value_set', - 'type_mapper_t_map_type', + 'type_attrs_t___getitem__', + 'type_attrs_t___len__', + 'type_attrs_t___setitem__', + 'type_attrs_t_at', + 'type_attrs_t_begin', + 'type_attrs_t_begin__SWIG_0', + 'type_attrs_t_begin__SWIG_1', + 'type_attrs_t_capacity', + 'type_attrs_t_clear', + 'type_attrs_t_empty', + 'type_attrs_t_end', + 'type_attrs_t_end__SWIG_0', + 'type_attrs_t_end__SWIG_1', + 'type_attrs_t_erase', + 'type_attrs_t_erase__SWIG_0', + 'type_attrs_t_erase__SWIG_1', + 'type_attrs_t_extract', + 'type_attrs_t_grow', + 'type_attrs_t_inject', + 'type_attrs_t_insert', + 'type_attrs_t_pop_back', + 'type_attrs_t_push_back', + 'type_attrs_t_push_back__SWIG_0', + 'type_attrs_t_push_back__SWIG_1', + 'type_attrs_t_qclear', + 'type_attrs_t_reserve', + 'type_attrs_t_resize', + 'type_attrs_t_resize__SWIG_0', + 'type_attrs_t_resize__SWIG_1', + 'type_attrs_t_size', + 'type_attrs_t_swap', + 'type_attrs_t_truncate', 'type_mods_t_clear', 'type_mods_t_cmt_get', 'type_mods_t_cmt_set', @@ -6901,11 +7243,6 @@ 'type_mods_t_set_new_type', 'type_mods_t_type_get', 'type_mods_t_type_set', - 'type_pair_t_type1_get', - 'type_pair_t_type1_set', - 'type_pair_t_type2_get', - 'type_pair_t_type2_set', - 'type_visitor_t_visit_type', 'typedef_type_data_t_is_ordref_get', 'typedef_type_data_t_is_ordref_set', 'typedef_type_data_t_resolve_get', @@ -6913,22 +7250,6 @@ 'typedef_type_data_t_swap', 'typedef_type_data_t_til_get', 'typedef_type_data_t_til_set', - 'ua_add_cref', - 'ua_add_dref', - 'ua_add_off_drefs', - 'ua_add_off_drefs2', - 'ua_ana0', - 'ua_code', - 'ua_dodata', - 'ua_dodata2', - 'ua_mnem', - 'ua_next_byte', - 'ua_next_long', - 'ua_next_qword', - 'ua_next_word', - 'ua_outop', - 'ua_outop2', - 'ua_stkvar2', 'uchar_array___getitem__', 'uchar_array___setitem__', 'uchar_array_cast', @@ -7017,9 +7338,6 @@ 'udtmembervec_t__del', 'udtmembervec_t_add_unique', 'udtmembervec_t_at', - 'udtmembervec_t_back', - 'udtmembervec_t_back__SWIG_0', - 'udtmembervec_t_back__SWIG_1', 'udtmembervec_t_begin', 'udtmembervec_t_begin__SWIG_0', 'udtmembervec_t_begin__SWIG_1', @@ -7036,9 +7354,6 @@ 'udtmembervec_t_find', 'udtmembervec_t_find__SWIG_0', 'udtmembervec_t_find__SWIG_1', - 'udtmembervec_t_front', - 'udtmembervec_t_front__SWIG_0', - 'udtmembervec_t_front__SWIG_1', 'udtmembervec_t_grow', 'udtmembervec_t_has', 'udtmembervec_t_inject', @@ -7057,7 +7372,6 @@ 'udtmembervec_t_truncate', 'ui_load_new_file', 'ui_run_debugger', - 'umsg', 'unhide_border', 'unhide_item', 'unmark_selection', @@ -7081,8 +7395,10 @@ 'update_extra_cmt', 'update_fpd', 'update_func', - 'update_hidden_area', + 'update_hidden_range', 'update_segm', + 'use_mapping', + 'user_cancelled', 'user_cmts_begin', 'user_cmts_clear', 'user_cmts_end', @@ -7102,6 +7418,8 @@ 'user_cmts_size', 'user_cmts_t_at', 'user_cmts_t_size', + 'user_graph_place_t_node_get', + 'user_graph_place_t_node_set', 'user_iflags_begin', 'user_iflags_clear', 'user_iflags_end', @@ -7192,9 +7510,6 @@ 'uvalvec_t__del', 'uvalvec_t_add_unique', 'uvalvec_t_at', - 'uvalvec_t_back', - 'uvalvec_t_back__SWIG_0', - 'uvalvec_t_back__SWIG_1', 'uvalvec_t_begin', 'uvalvec_t_begin__SWIG_0', 'uvalvec_t_begin__SWIG_1', @@ -7211,9 +7526,6 @@ 'uvalvec_t_find', 'uvalvec_t_find__SWIG_0', 'uvalvec_t_find__SWIG_1', - 'uvalvec_t_front', - 'uvalvec_t_front__SWIG_0', - 'uvalvec_t_front__SWIG_1', 'uvalvec_t_has', 'uvalvec_t_inject', 'uvalvec_t_insert', @@ -7231,8 +7543,6 @@ 'uvalvec_t_truncate', 'validate_idb_names', 'validate_name', - 'validate_name2', - 'validate_name3', 'valstr_t_info_get', 'valstr_t_info_set', 'valstr_t_length_get', @@ -7254,49 +7564,11 @@ 'var_ref_t_idx_set', 'var_ref_t_mba_get', 'var_ref_t_mba_set', - 'varloc_t__consume_scattered', - 'varloc_t__set_badloc', - 'varloc_t__set_reg1', - 'varloc_t__set_reg2', - 'varloc_t__set_stkoff', - 'varloc_t_advance', - 'varloc_t_calc_offset', - 'varloc_t_consume_scattered', - 'varloc_t_get_value', - 'varloc_t_is_badloc', - 'varloc_t_is_fragmented', - 'varloc_t_is_reg', - 'varloc_t_is_reg1', - 'varloc_t_is_reg2', - 'varloc_t_is_scattered', - 'varloc_t_is_stkoff', - 'varloc_t_reg1', - 'varloc_t_reg2', - 'varloc_t_regoff', - 'varloc_t_scattered', - 'varloc_t_scattered__SWIG_0', - 'varloc_t_scattered__SWIG_1', - 'varloc_t_set_badloc', - 'varloc_t_set_reg1', - 'varloc_t_set_reg2', - 'varloc_t_set_stkoff', - 'varloc_t_stkoff', - 'varloc_t_swap', - 'varloc_t_type', - 'varpart_t_bad_offset', - 'varpart_t_bad_size', - 'varpart_t_off_get', - 'varpart_t_off_set', - 'varpart_t_size_get', - 'varpart_t_size_set', - 'vaskqstr', 'vc_printer_t_func_get', 'vc_printer_t_func_set', 'vc_printer_t_lastchar_get', 'vc_printer_t_lastchar_set', 'vc_printer_t_oneliner', - 'vcall_helper', - 'vcreate_helper', 'vd_failure_t_desc', 'vd_failure_t_hf_get', 'vd_failure_t_hf_set', @@ -7318,15 +7590,11 @@ 'vdui_t_ct_get', 'vdui_t_ct_set', 'vdui_t_ctree_to_disasm', - 'vdui_t_cv_get', - 'vdui_t_cv_set', 'vdui_t_del_orphan_cmts', 'vdui_t_edit_cmt', 'vdui_t_edit_func_cmt', 'vdui_t_flags_get', 'vdui_t_flags_set', - 'vdui_t_form_get', - 'vdui_t_form_set', 'vdui_t_get_current_item', 'vdui_t_get_current_label', 'vdui_t_get_number', @@ -7365,6 +7633,8 @@ 'vdui_t_switch_to', 'vdui_t_tail_get', 'vdui_t_tail_set', + 'vdui_t_toplevel_get', + 'vdui_t_toplevel_set', 'vdui_t_ui_edit_lvar_cmt', 'vdui_t_ui_map_lvar', 'vdui_t_ui_rename_lvar', @@ -7376,19 +7646,46 @@ 'vdui_t_visible', 'verify_argloc', 'verify_tinfo', - 'verify_varloc', - 'vinterr', + 'view_mouse_event_location_t_ea_get', + 'view_mouse_event_location_t_ea_set', + 'view_mouse_event_location_t_item_get', + 'view_mouse_event_location_t_item_set', + 'view_mouse_event_t_button_get', + 'view_mouse_event_t_button_set', + 'view_mouse_event_t_location_get', + 'view_mouse_event_t_location_set', + 'view_mouse_event_t_renderer_pos_get', + 'view_mouse_event_t_renderer_pos_set', + 'view_mouse_event_t_rtype_get', + 'view_mouse_event_t_rtype_set', + 'view_mouse_event_t_state_get', + 'view_mouse_event_t_state_set', + 'view_mouse_event_t_x_get', + 'view_mouse_event_t_x_set', + 'view_mouse_event_t_y_get', + 'view_mouse_event_t_y_set', + 'viewer_attach_menu_item', + 'viewer_center_on', + 'viewer_create_groups', + 'viewer_del_node_info', + 'viewer_delete_groups', + 'viewer_fit_window', + 'viewer_get_curnode', + 'viewer_get_gli', + 'viewer_get_node_info', + 'viewer_get_selection', + 'viewer_set_gli', + 'viewer_set_groups_visibility', + 'viewer_set_node_info', + 'viewer_set_titlebar_height', 'visit_patched_bytes', 'visit_stroff_fields', 'visit_subtypes', - 'vloc_visitor_t_visit_location', - 'vumsg', 'wait_for_next_event', 'warning', 'warning__varargs__', - 'wasBreak', 'was_ida_decision', - 'wordflag', + 'word_flag', 'write_dbg_memory', 'write_tinfo_bitfield_value', 'writebytes', @@ -7427,9 +7724,6 @@ 'xreflist_t__del', 'xreflist_t_add_unique', 'xreflist_t_at', - 'xreflist_t_back', - 'xreflist_t_back__SWIG_0', - 'xreflist_t_back__SWIG_1', 'xreflist_t_begin', 'xreflist_t_begin__SWIG_0', 'xreflist_t_begin__SWIG_1', @@ -7446,9 +7740,6 @@ 'xreflist_t_find', 'xreflist_t_find__SWIG_0', 'xreflist_t_find__SWIG_1', - 'xreflist_t_front', - 'xreflist_t_front__SWIG_0', - 'xreflist_t_front__SWIG_1', 'xreflist_t_grow', 'xreflist_t_has', 'xreflist_t_inject', @@ -7465,5 +7756,5 @@ 'xreflist_t_size', 'xreflist_t_swap', 'xreflist_t_truncate', - 'ywrdflag', - 'zwrdflag']} \ No newline at end of file + 'yword_flag', + 'zword_flag']} diff --git a/build.py b/build.py index 4f18a8a..f513e3b 100644 --- a/build.py +++ b/build.py @@ -42,6 +42,7 @@ parser.add_argument("--debug", help="Build debug version of the plugin", default parser.add_argument("--python-home", help="Python home, where the 'include' directory can be found (linux only)", 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") +parser.add_argument("-I", "--idc", required=True, help="IDA's idc.idc file (necessary for generating 6.95 compat API layer)", type=str) args = parser.parse_args() _probe = os.path.join("..", "..", "include", "pro.h") @@ -69,12 +70,15 @@ def main(): env["SWIGINCLUDES"] = " ".join(map(lambda p: "-I%s" % p, args.swig_inc.split(os.pathsep))) if args.with_hexrays: env["HAS_HEXRAYS"] = "1" - if not args.debug: + if args.debug: + env["__VC__"] = "1" # to enable PDB flags + else: env["NDEBUG"] = "1" if args.python_home: env["LINUX_PYTHON_HOME"] = args.python_home if args.verbose: argv.append("-d") + env["IDC_BC695_IDC_SOURCE"] = args.idc for ea64 in [False, True]: if ea64: env["__EA64__"] = "1" diff --git a/docs/bc695.md b/docs/bc695.md new file mode 100644 index 0000000..d7ade40 --- /dev/null +++ b/docs/bc695.md @@ -0,0 +1,46 @@ + +IDAPython for IDA 7.00: backward-compatibility with 6.95 APIs +============================================================= + +Availability of the backward-compatibility code +----------------------------------------------- + +* Backward-compatibility is provided by python.cfg's + `AUTOIMPORT_COMPAT_IDA695` directive. This directive is + currently turned on by default, but in the future it will: + 1. be turned off by default + 1. eventually disappear, and all the corresponding code will be removed + +* Consequently IDAPython script/plugin writers should try and port + their code, with the help of the porting guide XXX FIXME URL? XXX. + +* Once you have done the porting, please check that your code works + with `AUTOIMPORT_COMPAT_IDA695` set to `NO`. + +* If anything proves too hard or confusing, please let us know about + it on , and we will help you, either by fixing + IDAPython if needed, or by improving the documentation. + + +Coverage of the backward-compatibility code +------------------------------------------- + +* We did what was reasonably feasible, to provide an IDAPython API + that's as backward-compatible as possible with the IDA 6.95 API + +* However, we considered it unreasonable for some parts of the API + to be ported. Most notably: + * the "processor module" API: existing processor modules will + have to be ported to the new API. Please see the SDK's + `module/script/proctemplate.py` (or any other `*.py` file in + that directory) for examples how to use the new API. + * processor module-related notifications: some of those have either + been renamed, or have possibly changed signature + +* Most (all?) of the renamed functions, properties, etc... should be + covered, in all modules: `idaapi`, `idc`, ... + If something doesn't work/isn't there anymore, it's likely an + omission from our side. + +* Please let us know about any missing bits & pieces, that you + believe should be there and that we might have forgotten! diff --git a/docs/bc695.sh b/docs/bc695.sh new file mode 100755 index 0000000..9cc5f9d --- /dev/null +++ b/docs/bc695.sh @@ -0,0 +1,11 @@ +#!/bin/sh +TARGET_DIR=../../../../www/www.hex-rays.com/public_html/hex-rays/products/ida/7.0/docs +TARGET_FILE=$TARGET_DIR/idapython_backward_compat_695.html +p4 edit $TARGET_FILE +echo \\ > $TARGET_FILE +echo \ >> $TARGET_FILE +echo \ >> $TARGET_FILE +echo \\ >> $TARGET_FILE +markdown bc695.md >> $TARGET_FILE +echo \\ >> $TARGET_FILE +p4 revert -a $TARGET_FILE diff --git a/docs/notes.txt b/docs/notes.txt new file mode 100644 index 0000000..ab89347 --- /dev/null +++ b/docs/notes.txt @@ -0,0 +1,53 @@ +Assorted notes +-------------- + +Wrapped functions and constants: + +All the symbols from the idaapi module are listed in symbollist.txt. +Documentation for the plugin API functions functions is in the IDA +SDK header files. All function and symbol names directly translate +to the C++ counterparts. If you try to use a function that is not +wrapped yet you will get an exception like this: + + Traceback (most recent call last): + File "", line 1, in ? + NameError: name 'foobar' is not defined + +If this happens you can check the function in symbollist.txt. If it +is not included and it should be please report it to the author. + + +Data types: + +All the C++ data types are mapped to corresponding Python data types. +For example ea_t maps to a Python integer. Complex data types (like +structures and classes) are mapped to Python classes that have the +same attributes as the original type. + + +Arguments and return values: + +Generally all function arguments should be the same type as specified +by the original headers. Pointers to complex types (structures, classes) +are checked and must match the original declarations. + +For example comment = get_func_comment("aa", 0) will raise an exception: + + Traceback (most recent call last): + File "", line 1, in ? + TypeError: Type error. Got aa, expected _p_func_t + +When calling functions that return a string in a buffer (usually with +maximum size) the buffer and size parameter is omitted. These functions +return either the result in a string or None if the call fails and returns +NULL. The output buffers are maximized at MAXSTR. + + Example: + + C++: get_func_name(0x1234, buf, sizeof(buf)); + Python: name = get_func_name(0x1234) + +Any function that should return a char * is going to return either a +Python string (up to MAXSTR) or None. + + diff --git a/examples/chooser.py b/examples/chooser.py deleted file mode 100644 index b459063..0000000 --- a/examples/chooser.py +++ /dev/null @@ -1,50 +0,0 @@ -#--------------------------------------------------------------------- -# Chooser test -# -# This script demonstrates the usage of the class-based chooser. -# -# Author: Gergely Erdelyi -#--------------------------------------------------------------------- -from idaapi import Choose - -# -# Modal chooser -# - -# Get a modal Choose instance -chooser = Choose([], "MyChooser", 1) -# List to choose from -chooser.list = [ "First", "Second", "Third" ] -# Set the width -chooser.width = 50 -# Run the chooser -ch = chooser.choose() -# Print the results -if ch > 0: - print "You chose %d which is %s" % (ch, chooser.list[ch-1]) -else: - print "Escape from chooser" - -# -# Normal chooser -# -class MyChoose(Choose): - """ - You have to subclass Chooser to override the enter() method - """ - def __init__(self, list=[], name="Choose"): - Choose.__init__(self, list, name) - # Set the width - self.width = 50 - self.deflt = 1 - - def enter(self, n): - print "Enter called. Do some stuff here." - print "The chosen item is %d = %s" % (n, self.list[n-1]) - print "Now press ESC to leave." - -# Get a Choose instance -chooser = MyChoose([ "First", "Second", "Third" ], "MyChoose") - -# Run the chooser -ch = chooser.choose() diff --git a/examples/colours.py b/examples/colours.py index 49f0ce2..b1aa2e7 100644 --- a/examples/colours.py +++ b/examples/colours.py @@ -7,13 +7,13 @@ #--------------------------------------------------------------------- # Set the colour of the current segment to BLUE -SetColor(here(), CIC_SEGM, 0xc02020) +set_color(here(), CIC_SEGM, 0xc02020) # Set the colour of the current function to GREEN -SetColor(here(), CIC_FUNC, 0x208020) +set_color(here(), CIC_FUNC, 0x208020) # Set the colour of the current item to RED -SetColor(here(), CIC_ITEM, 0x2020c0) +set_color(here(), CIC_ITEM, 0x2020c0) # Print the colours just set -print "%x" % GetColor(here(), CIC_SEGM) -print "%x" % GetColor(here(), CIC_FUNC) -print "%x" % GetColor(here(), CIC_ITEM) +print "%x" % get_color(here(), CIC_SEGM) +print "%x" % get_color(here(), CIC_FUNC) +print "%x" % get_color(here(), CIC_ITEM) diff --git a/examples/debughook.py b/examples/debughook.py index d47f98d..99ccf4d 100644 --- a/examples/debughook.py +++ b/examples/debughook.py @@ -73,7 +73,7 @@ class MyDbgHook(DBG_Hooks): def dbg_step_over(self): - eip = GetRegValue("EIP") + eip = get_reg_value("EIP") print("0x%x %s" % (eip, GetDisasm(eip))) self.steps += 1 @@ -97,7 +97,7 @@ debughook.hook() debughook.steps = 0 # Stop at the entry point -ep = GetLongPrm(INF_START_IP) +ep = get_inf_attr(INF_START_IP) request_run_to(ep) # Step one instruction diff --git a/examples/ex1.idc b/examples/ex1.idc index e3c0aa7..cc5d7dc 100644 --- a/examples/ex1.idc +++ b/examples/ex1.idc @@ -12,22 +12,22 @@ static main() auto ea, func, ref; // Get current ea - ea = ScreenEA(); + ea = get_screen_ea(); // Loop from start to end in the current segment - for (func=SegStart(ea); - func != BADADDR && func < SegEnd(ea); - func=NextFunction(func)) + for (func=get_segm_start(ea); + func != BADADDR && func < get_segm_end(ea); + func=get_next_func(func)) { // If the current address is function process it - if (GetFunctionFlags(func) != -1) + if (get_func_flags(func) != -1) { - Message("Function %s at 0x%x\n", GetFunctionName(func), func); + msg("Function %s at 0x%x\n", get_func_name(func), func); // Find all code references to func - for (ref=RfirstB(func); ref != BADADDR; ref=RnextB(func, ref)) + for (ref=get_first_cref_to(func); ref != BADADDR; ref=get_next_cref_to(func, ref)) { - Message(" called from %s(0x%x)\n", GetFunctionName(ref), ref); + msg(" called from %s(0x%x)\n", get_func_name(ref), ref); } } diff --git a/examples/ex1_idaapi.py b/examples/ex1_idaapi.py index 4729554..172c0e0 100644 --- a/examples/ex1_idaapi.py +++ b/examples/ex1_idaapi.py @@ -23,10 +23,10 @@ def main(): # No function there, try to get the next one func = get_next_func(func_ea) - seg_end = seg.endEA - while func is not None and func.startEA < seg_end: - funcea = func.startEA - print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea) + seg_end = seg.end_ea + while func is not None and func.start_ea < seg_end: + funcea = func.start_ea + print "Function %s at 0x%x" % (get_func_name(funcea), funcea) ref = get_first_cref_to(funcea) @@ -37,4 +37,4 @@ def main(): func = get_next_func(funcea) -main() \ No newline at end of file +main() diff --git a/examples/ex1_idautils.py b/examples/ex1_idautils.py index 5072f94..72c2e6c 100644 --- a/examples/ex1_idautils.py +++ b/examples/ex1_idautils.py @@ -9,18 +9,18 @@ from idautils import * def main(): # Get current ea - ea = ScreenEA() + ea = get_screen_ea() if ea == idaapi.BADADDR: print("Could not get get_screen_ea()") return # Loop from start to end in the current segment - for funcea in Functions(SegStart(ea), SegEnd(ea)): - print("Function %s at 0x%x" % (GetFunctionName(funcea), funcea)) + for funcea in Functions(get_segm_start(ea), get_segm_end(ea)): + print("Function %s at 0x%x" % (get_func_name(funcea), funcea)) # Find all code references to funcea for ref in CodeRefsTo(funcea, 1): - print(" called from %s(0x%x)" % (GetFunctionName(ref), ref)) + print(" called from %s(0x%x)" % (get_func_name(ref), ref)) if __name__=='__main__': diff --git a/examples/ex_actions.py b/examples/ex_actions.py index 265991a..2325bb4 100644 --- a/examples/ex_actions.py +++ b/examples/ex_actions.py @@ -12,7 +12,7 @@ class SayHi(idaapi.action_handler_t): # You can implement update(), to inform IDA when: # * your action is enabled # * update() should queried again - # E.g., returning 'idaapi.AST_ENABLE_FOR_FORM' will + # E.g., returning 'idaapi.AST_ENABLE_FOR_WIDGET' will # tell IDA that this action is available while the # user is in the current widget, and that update() # must be queried again once the user gives focus @@ -24,7 +24,7 @@ class SayHi(idaapi.action_handler_t): # querying update() anymore until the user has moved # to another view.. def update(self, ctx): - return idaapi.AST_ENABLE_FOR_FORM if ctx.form_type == idaapi.BWN_DISASM else idaapi.AST_DISABLE_FOR_FORM + return idaapi.AST_ENABLE_FOR_WIDGET if ctx.widget_type == idaapi.BWN_DISASM else idaapi.AST_DISABLE_FOR_WIDGET print "Creating a custom icon from raw data!" @@ -92,16 +92,16 @@ if idaapi.register_action(idaapi.action_desc_t( # when the popup for "IDA View-A" is being populated, right before # it is displayed. class Hooks(idaapi.UI_Hooks): - def finish_populating_tform_popup(self, form, popup): + def finish_populating_widget_popup(self, widget, popup): # We'll add our action to all "IDA View-*"s. # If we wanted to add it only to "IDA View-A", we could # also discriminate on the widget's title: # - # if idaapi.get_tform_title(form) == "IDA View-A": + # if idaapi.get_widget_title(widget) == "IDA View-A": # ... # - if idaapi.get_tform_type(form) == idaapi.BWN_DISASM: - idaapi.attach_action_to_popup(form, popup, act_name, None) + if idaapi.get_widget_type(widget) == idaapi.BWN_DISASM: + idaapi.attach_action_to_popup(widget, popup, act_name, None) hooks = Hooks() hooks.hook() diff --git a/examples/ex_askusingform.py b/examples/ex_askusingform.py index aef440d..5cb1d04 100644 --- a/examples/ex_askusingform.py +++ b/examples/ex_askusingform.py @@ -2,30 +2,22 @@ # This is an example illustrating how to use the Form class # (c) Hex-Rays # -from idaapi import Form +from ida_kernwin import Form, Choose, ask_str # -------------------------------------------------------------------------- -class TestEmbeddedChooserClass(Choose2): +class TestEmbeddedChooserClass(Choose): """ A simple chooser to be used as an embedded chooser """ - def __init__(self, title, nb = 5, flags=0): - Choose2.__init__(self, - title, - [ ["Address", 10], ["Name", 30] ], - embedded=True, width=30, height=20, flags=flags) - self.n = 0 - self.items = [ self.make_item() for x in xrange(0, nb+1) ] + def __init__(self, title, nb = 5, flags = 0): + Choose.__init__(self, + title, + [ ["Address", 10], ["Name", 30] ], + flags=flags, + embedded=True, width=30, height=6) + self.items = [ [str(x), "func_%04d" % x] + for x in xrange(nb + 1) ] self.icon = 5 - self.selcount = 0 - - def make_item(self): - r = [str(self.n), "func_%04d" % self.n] - self.n += 1 - return r - - def OnClose(self): - pass def OnGetLine(self, n): print("getline %d" % n) @@ -40,7 +32,7 @@ class TestEmbeddedChooserClass(Choose2): class MyForm(Form): def __init__(self): self.invert = False - self.EChooser = TestEmbeddedChooserClass("E1", flags=Choose2.CH_MULTI) + self.EChooser = TestEmbeddedChooserClass("E1", flags=Choose.CH_MULTI) Form.__init__(self, r"""STARTITEM {id:rNormal} BUTTON YES* Yeah BUTTON NO Nope @@ -48,44 +40,33 @@ BUTTON CANCEL Nevermind Form Test {FormChangeCb} -This is a string: +{cStr1}+ -This is an address: +{cAddr1}+ -This is some HTML: +{cHtml1}+ +This is a string: |+{cStr1}+ +This is an address:|+{cAddr1}+ +This is some HTML: |+{cHtml1}+ +This is a number: |+{cVal1}+ -Escape\{control} -This is a string: '{cStr2}' -This is a number: {cVal1} - -<#Hint1#Enter name:{iStr1}> +<#Hint1#Enter text :{iStr1}> <#Hint2#Select color:{iColor1}> Browse test <#Select a file to open#Browse to open:{iFileOpen}> <#Select a file to save#Browse to save:{iFileSave}> <#Select dir#Browse for dir:{iDir}> -Type -<#Select type#Write a type:{iType}> -Numbers +Misc <##Enter a selector value:{iSegment}> -<##Enter a raw hex:{iRawHex}> -<##Enter a character:{iChar}> -<##Enter an address:{iAddr}> -Button test -<##Button1:{iButton1}> <##Button2:{iButton2}> +<##Enter a raw hex :{iRawHex}> +<##Enter a character :{iChar}> +<##Enter an address :{iAddr}> +<##Write a type name :{iType}> +Button test: <##Button1:{iButton1}> <##Button2:{iButton2}> -Check boxes: - - -{cGroup1}> +<##Check boxes##Error output:{rError}> | <##Radio boxes##Green:{rGreen}> + | +{cGroup1}> | {cGroup2}> -Radio boxes: - - -{cGroup2}> 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), @@ -131,6 +112,13 @@ The end! elif fid == self.cEChooser.id: l = self.GetControlValue(self.cEChooser) print("Chooser: %s" % l) + elif fid in [self.rGreen.id, self.rRed.id, self.rBlue.id]: + color = { + self.rGreen.id : 0x00FF00, + self.rRed.id : 0x0000FF, + self.rBlue.id : 0xFF0000, + } + self.SetControlValue(self.iColor1, color[fid]) else: print(">>fid:%d" % fid) return 1 @@ -212,8 +200,8 @@ using address %$ # Use either StringArgument or NumericArgument to pass values to the function num = Form.NumericArgument('N', value=123) - ok = idaapi.AskUsingForm(s, - Form.StringArgument("PyAskUsingForm").arg, + ok = idaapi.ask_form(s, + Form.StringArgument("PyAskform").arg, Form.NumericArgument('$', 0x401000).arg, num.arg) if ok == 1: @@ -231,7 +219,7 @@ This is sample dialog box """ # Use either StringArgument or NumericArgument to pass values to the function ti = textctrl_info_t("Some initial value") - ok = idaapi.AskUsingForm(s, pointer(c_void_p.from_address(ti.clink_ptr))) + ok = idaapi.ask_form(s, pointer(c_void_p.from_address(ti.clink_ptr))) if ok == 1: print("You entered: %s" % ti.text) @@ -319,11 +307,11 @@ Dropdown list test def OnFormChange(self, fid): if fid == self.iButtonSetString.id: - s = idc.AskStr("none", "Enter value") + s = ask_str("none", 0, "Enter value") if s: self.SetControlValue(self.cbEditable, s) elif fid == self.iButtonSetIndex.id: - s = idc.AskStr("1", "Enter index value:") + s = ask_str("1", 0, "Enter index value:") if s: try: i = int(s) diff --git a/examples/ex_choose.py b/examples/ex_choose.py new file mode 100644 index 0000000..592ee88 --- /dev/null +++ b/examples/ex_choose.py @@ -0,0 +1,141 @@ +import ida_kernwin +from ida_kernwin import Choose + +class chooser_handler_t(ida_kernwin.action_handler_t): + def __init__(self, thing): + ida_kernwin.action_handler_t.__init__(self) + self.thing = thing + + def activate(self, ctx): + sel = [] + for idx in ctx.chooser_selection: + sel.append(str(idx)) + print "command %s selected @ %s" % (self.thing, ", ".join(sel)) + + def update(self, ctx): + return ida_kernwin.AST_ENABLE_FOR_WIDGET \ + if ida_kernwin.is_chooser_widget(ctx.widget_type) \ + else ida_kernwin.AST_DISABLE_FOR_WIDGET + + +class MyChoose(Choose): + + def __init__(self, title, nb = 5, flags = 0, + modal = False, + embedded = False, width = None, height = None): + Choose.__init__( + self, + title, + [ ["Address", 10], ["Name", 30] ], + flags = flags | (Choose.CH_CAN_INS + | Choose.CH_CAN_DEL + | Choose.CH_CAN_EDIT + | Choose.CH_CAN_REFRESH), + embedded = embedded, + width = width, + height = height) + self.n = 0 + self.items = [ self.make_item() for x in xrange(nb) ] + self.icon = 5 + self.selcount = 0 + self.modal = modal + self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"] + + print("created %s" % str(self)) + + def OnInit(self): + print "inited", str(self) + return True + + def OnGetSize(self): + n = len(self.items) + print("getsize -> %d" % n) + return n + + def OnGetLine(self, n): + print("getline %d" % n) + return self.items[n] + + def OnGetIcon(self, n): + r = self.items[n] + t = self.icon + r[1].count("*") + print "geticon", n, t + return t + + def OnGetLineAttr(self, n): + print("getlineattr %d" % n) + if n == 1: + return [0xFF0000, 0] + + def OnInsertLine(self, n): + # we ignore current selection + n = self.n # position at the just added item + self.items.append(self.make_item()) + print("insert line") + return (Choose.ALL_CHANGED, n) + + def OnDeleteLine(self, n): + print("del %d " % n) + del self.items[n] + return [Choose.ALL_CHANGED] + self.adjust_last_item(n) + + def OnEditLine(self, n): + self.items[n][1] = self.items[n][1] + "*" + print("editing %d" % n) + return (Choose.ALL_CHANGED, n) + + def OnRefresh(self, n): + print("refresh %d" % n) + return None # call standard refresh + + def OnSelectLine(self, n): + self.selcount += 1 + warning("[%02d] selectline '%d'" % (self.selcount, n)) + return (Choose.NOTHING_CHANGED, ) + + def OnClose(self): + print "closed", str(self) + + def OnPopup(self, form, popup_handle): + for c in ["A", "B"]: + actname = "choose:act%s" % c + desc = ida_kernwin.action_desc_t( + actname, + "command %s" % c, + chooser_handler_t(c)) + ida_kernwin.attach_dynamic_action_to_popup( + form, popup_handle, desc) + + def show(self): + return self.Show(self.modal) >= 0 + + def make_item(self): + r = [str(self.n), "func_%04d" % self.n] + self.n += 1 + return r + + +# ----------------------------------------------------------------------- +def test_choose(modal = False, nb = 10): + global c + c = MyChoose("Choose - sample 1", nb = nb, modal = modal) + c.show() + +# ----------------------------------------------------------------------- +def test_choose_embedded(): + global c + c = MyChoose("Choose - embedded", nb=12, embedded = True, width=123, height=222) + r = c.Embedded() + if r == 0: + try: + if test_embedded: + o, sel = _idaapi.choose_get_embedded(c) + print("o=%s, type(o)=%s" % (str(o), type(o))) + test_embedded(o) + finally: + c.Close() + +# ----------------------------------------------------------------------- +if __name__ == '__main__': + #test_choose_embedded() + test_choose(False) diff --git a/examples/ex_choose2.py b/examples/ex_choose2.py deleted file mode 100644 index d7915eb..0000000 --- a/examples/ex_choose2.py +++ /dev/null @@ -1,128 +0,0 @@ -import idaapi -from idaapi import Choose2 - -class chooser_handler_t(idaapi.action_handler_t): - def __init__(self, thing): - idaapi.action_handler_t.__init__(self) - self.thing = thing - - def activate(self, ctx): - sel = [] - for i in xrange(len(ctx.chooser_selection)): - sel.append(str(ctx.chooser_selection.at(i))) - print "command %s selected @ %s" % (self.thing, ", ".join(sel)) - - def update(self, ctx): - return idaapi.AST_ENABLE_FOR_FORM if idaapi.is_chooser_tform(ctx.form_type) else idaapi.AST_DISABLE_FOR_FORM - - -class MyChoose2(Choose2): - - def __init__(self, title, nb = 5, flags=0, width=None, height=None, embedded=False, modal=False): - Choose2.__init__( - self, - title, - [ ["Address", 10], ["Name", 30] ], - flags = flags, - width = width, - height = height, - embedded = embedded) - self.n = 0 - self.items = [ self.make_item() for x in xrange(0, nb+1) ] - self.icon = 5 - self.selcount = 0 - self.modal = modal - self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"] - - print("created %s" % str(self)) - - def OnClose(self): - print "closed", str(self) - - def OnEditLine(self, n): - self.items[n][1] = self.items[n][1] + "*" - print("editing %d" % n) - - def OnInsertLine(self): - self.items.append(self.make_item()) - print("insert line") - - def OnSelectLine(self, n): - self.selcount += 1 - Warning("[%02d] selectline '%s'" % (self.selcount, n)) - - def OnGetLine(self, n): - print("getline %d" % n) - return self.items[n] - - def OnGetSize(self): - n = len(self.items) - print("getsize -> %d" % n) - return n - - def OnDeleteLine(self, n): - print("del %d " % n) - del self.items[n] - return n - - def OnRefresh(self, n): - print("refresh %d" % n) - return n - - def OnGetIcon(self, n): - r = self.items[n] - t = self.icon + r[1].count("*") - print "geticon", n, t - return t - - def show(self): - return self.Show(self.modal) >= 0 - - def make_item(self): - r = [str(self.n), "func_%04d" % self.n] - self.n += 1 - return r - - def OnGetLineAttr(self, n): - print("getlineattr %d" % n) - if n == 1: - return [0xFF0000, 0] - - -# ----------------------------------------------------------------------- -def test_choose2(modal=False): - global c - c = MyChoose2("Choose2 - sample 1", nb=10, modal=modal) - r = c.show() - form = idaapi.get_current_tform() - for thing in ["A", "B"]: - idaapi.attach_action_to_popup(form, None, "choose2:act%s" % thing) - -# ----------------------------------------------------------------------- -def test_choose2_embedded(): - global c - c = MyChoose2("Choose2 - embedded", nb=12, embedded = True, width=123, height=222) - r = c.Embedded() - if r == 1: - try: - if test_embedded: - o, sel = _idaapi.choose2_get_embedded(c) - print("o=%s, type(o)=%s" % (str(o), type(o))) - test_embedded(o) - finally: - c.Close() - -# ----------------------------------------------------------------------- -if __name__ == '__main__': - - # Register actions - for thing in ["A", "B"]: - actname = "choose2:act%s" % thing - idaapi.register_action( - idaapi.action_desc_t( - actname, - "command %s" % thing, - chooser_handler_t(thing))) - - #test_choose2_embedded() - test_choose2(False) diff --git a/examples/ex_choose_multi.py b/examples/ex_choose_multi.py new file mode 100644 index 0000000..2ef2e5e --- /dev/null +++ b/examples/ex_choose_multi.py @@ -0,0 +1,40 @@ +from ida_kernwin import Choose + + +class MyChoose(Choose): + + def __init__(self, title, nb = 5): + Choose.__init__( + self, + title, + [ ["Bit", Choose.CHCOL_HEX | 10] ], + flags = Choose.CH_MULTI) + self.items = [ str(1 << x) for x in xrange(nb) ] + + def OnGetSize(self): + return len(self.items) + + def OnGetLine(self, n): + return [self.items[n]] + + def OnSelectLine(self, n): + self.deflt = n # save current selection + return (Choose.NOTHING_CHANGED, ) + + def show(self, num): + self.deflt = [x + for x in xrange(len(self.items)) + if (num & (1 << x)) != 0] + if self.Show(True) < 0: + return 0 + return sum([(1 << x) for x in self.deflt]) + + +# ----------------------------------------------------------------------- +def test_choose(num): + c = MyChoose("Choose - sample 2", nb = 5) + return c.show(num) + +# ----------------------------------------------------------------------- +if __name__ == '__main__': + print test_choose(11) diff --git a/examples/ex_custdata.py b/examples/ex_custdata.py index b78cbac..99aaa88 100644 --- a/examples/ex_custdata.py +++ b/examples/ex_custdata.py @@ -7,14 +7,16 @@ import struct import ctypes import platform -# - # ----------------------------------------------------------------------- class pascal_data_type(data_type_t): def __init__(self): - data_type_t.__init__(self, name="py_pascal_string", - value_size = 2, menu_name = "Pascal string", - asm_keyword = "pstr") + data_type_t.__init__( + self, + "py_pascal_string", + 2, + "Pascal string", + None, + "pstr") def calc_item_size(self, ea, maxsize): # Custom data types may be used in structure definitions. If this case @@ -34,7 +36,9 @@ class pascal_data_type(data_type_t): class pascal_data_format(data_format_t): FORMAT_NAME = "py_pascal_string_pstr" def __init__(self): - data_format_t.__init__(self, name=pascal_data_format.FORMAT_NAME) + data_format_t.__init__( + self, + pascal_data_format.FORMAT_NAME) def printf(self, value, current_ea, operand_num, dtid): # Take the length byte @@ -52,12 +56,19 @@ class pascal_data_format(data_format_t): # ----------------------------------------------------------------------- class simplevm_data_type(data_type_t): ASM_KEYWORD = "svm_emit" - def __init__(self): - data_type_t.__init__(self, - name="py_simple_vm", - value_size = 1, - menu_name = "SimpleVM", - asm_keyword = simplevm_data_type.ASM_KEYWORD) + def __init__( + self, + name="py_simple_vm", + value_size=1, + menu_name="SimpleVM", + asm_keyword=ASM_KEYWORD): + data_type_t.__init__( + self, + name, + value_size, + menu_name, + None, + asm_keyword) def calc_item_size(self, ea, maxsize): if _idaapi.is_member_id(ea): @@ -71,10 +82,15 @@ class simplevm_data_type(data_type_t): return n class simplevm_data_format(data_format_t): - def __init__(self): - data_format_t.__init__(self, - name="py_simple_vm_format", - menu_name = "SimpleVM") + def __init__( + self, + name="py_simple_vm_format", + menu_name="SimpleVM"): + data_format_t.__init__( + self, + name, + 0, + menu_name) # Some tables for the disassembler INST = {1: 'add', 2: 'mul', 3: 'sub', 4: 'xor', 5: 'mov'} @@ -114,10 +130,11 @@ class simplevm_data_format(data_format_t): # This format will display DWORD values as MAKE_DWORD(0xHI, 0xLO) class makedword_data_format(data_format_t): def __init__(self): - data_format_t.__init__(self, - name="py_makedword", - value_size = 4, - menu_name = "Make DWORD") + data_format_t.__init__( + self, + "py_makedword", + 4, + "Make DWORD") def printf(self, value, current_ea, operand_num, dtid): if len(value) != 4: return None @@ -138,10 +155,11 @@ class makedword_data_format(data_format_t): # DLL each time for a new string. It can be improved in many ways. class rsrc_string_format(data_format_t): def __init__(self): - data_format_t.__init__(self, - name="py_w32rsrcstring", - value_size = 1, - menu_name = "Resource string") + data_format_t.__init__( + self, + "py_w32rsrcstring", + 1, + "Resource string") self.cache_node = idaapi.netnode("$ py_w32rsrcstring", 0, 1) def get_rsrc_string(self, fn, id): @@ -186,19 +204,21 @@ new_formats = [ (pascal_data_type(), pascal_data_format()), (simplevm_data_type(), simplevm_data_format()), (makedword_data_format(),), - (simplevm_data_format(),) + (simplevm_data_format(),), ] -if platform.system() == 'Windows': - new_formats.append((rsrc_string_format(),)) - -# +try: + if platform.system() == 'Windows': + new_formats.append((rsrc_string_format(),)) +except: + pass # ----------------------------------------------------------------------- def nw_handler(code, old=0): # delete notifications if code == NW_OPENIDB: - idaapi.register_data_types_and_formats(new_formats) + if not idaapi.register_data_types_and_formats(new_formats): + print "Failed to register types!" elif code == NW_CLOSEIDB: idaapi.unregister_data_types_and_formats(new_formats) elif code == NW_TERMIDA: diff --git a/examples/ex_custview.py b/examples/ex_custview.py index 36a9997..2a11a40 100644 --- a/examples/ex_custview.py +++ b/examples/ex_custview.py @@ -98,7 +98,7 @@ class mycv_t(simplecustviewer_t): elif vkey == ord('G'): n = self.GetLineNo() if n is not None: - v = idc.AskLong(self.GetLineNo(), "Where to go?") + v = idaapi.ask_long(self.GetLineNo(), "Where to go?") if v: self.Jump(v, 0, 5) elif vkey == ord('R'): @@ -108,7 +108,7 @@ class mycv_t(simplecustviewer_t): print "refreshing current line..." self.RefreshCurrent() elif vkey == ord('A'): - s = idc.AskStr("NewLine%d" % self.Count(), "Append new line") + s = idaapi.ask_str("NewLine%d" % self.Count(), 0, "Append new line") self.AddLine(s) self.Refresh() elif vkey == ord('X'): @@ -117,7 +117,7 @@ class mycv_t(simplecustviewer_t): self.Refresh() elif vkey == ord('I'): n = self.GetLineNo() - s = idc.AskStr("InsertedLine%d" % n, "Insert new line") + s = idaapi.ask_str("InsertedLine%d" % n, 0, "Insert new line") self.InsertLine(n, s) self.Refresh() elif vkey == ord('E'): @@ -160,7 +160,7 @@ def show_win(): print "Failed to create!" return None x.Show() - tcc = x.GetTCustomControl() + tcc = x.GetWidget() # Register actions for thing in ["Hello", "World"]: diff --git a/examples/ex_dbg.py b/examples/ex_dbg.py index 1c04403..5716629 100644 --- a/examples/ex_dbg.py +++ b/examples/ex_dbg.py @@ -4,9 +4,9 @@ def test_getmeminfo(): L = tempo.getmeminfo() out = [] - # startEA endEA name sclass sbase bitness perm - for (startEA, endEA, name, sclass, sbase, bitness, perm) in L: - out.append("%x: %x name=<%s> sclass=<%s> sbase=%x bitness=%2x perm=%2x" % (startEA, endEA, name, sclass, sbase, bitness, perm)) + # start_ea end_ea name sclass sbase bitness perm + for (start_ea, end_ea, name, sclass, sbase, bitness, perm) in L: + out.append("%x: %x name=<%s> sclass=<%s> sbase=%x bitness=%2x perm=%2x" % (start_ea, end_ea, name, sclass, sbase, bitness, perm)) f = file(r"d:\temp\out.log", "w") f.write("\n".join(out)) @@ -16,7 +16,7 @@ def test_getmeminfo(): def test_getregs(): - # name flags class dtyp bit_strings bit_strings_default_mask + # name flags class dtype bit_strings bit_strings_default_mask L = tempo.getregs() out = [] for (name, flags, cls, dtype, bit_strings, bit_strings_default_mask) in L: diff --git a/examples/ex_debug_names.py b/examples/ex_debug_names.py index 68cb1b1..f59720d 100644 --- a/examples/ex_debug_names.py +++ b/examples/ex_debug_names.py @@ -8,7 +8,7 @@ def main(): print "Please suspend the debugger first!" return - dn = idaapi.get_debug_names(idaapi.cvar.inf.minEA, idaapi.cvar.inf.maxEA) + dn = idaapi.get_debug_names(idaapi.cvar.inf.min_ea, idaapi.cvar.inf.max_ea) for i in dn: print "%08x: %s" % (i, dn[i]) diff --git a/examples/ex_expr.py b/examples/ex_expr.py index a40e449..6ceed76 100644 --- a/examples/ex_expr.py +++ b/examples/ex_expr.py @@ -2,12 +2,18 @@ # This is an example illustrating how to extend IDC from Python # (c) Hex-Rays # -from idaapi import set_idc_func_ex +from idaapi import add_idc_func def py_power(n, e): return n ** e -ok = set_idc_func_ex("pow", py_power, (idaapi.VT_LONG, idaapi.VT_LONG), 0) +desc = ext_idcfunc_t +desc.name = "pow" +desc.func = py_power, +desc.args = (idaapi.VT_LONG, idaapi.VT_LONG), +desc.defvals = () +desc.flags = 0 +ok = add_idc_func(desc) if ok: print("Now the pow() will be present IDC!") else: diff --git a/examples/ex_func_chooser.py b/examples/ex_func_chooser.py index b489f5f..d3579d3 100644 --- a/examples/ex_func_chooser.py +++ b/examples/ex_func_chooser.py @@ -1,38 +1,45 @@ -import idaapi import idautils import idc +from ida_kernwin import Choose -class MyChoose2(Choose2): +class MyChoose(Choose): def __init__(self, title): - Choose2.__init__(self, title, [ ["Address", 10 | Choose2.CHCOL_HEX], ["Name", 30 | Choose2.CHCOL_PLAIN] ]) - self.n = 0 + Choose.__init__( + self, + title, + [ ["Address", 10 | Choose.CHCOL_HEX], + ["Name", 30 | Choose.CHCOL_PLAIN] ]) + self.items = [] self.icon = 41 - self.PopulateItems() - def PopulateItems(self): - self.items = [ [hex(x), GetFunctionName(x), x] for x in idautils.Functions() ] - - def OnClose(self): - print "closed ", self.title - - def OnSelectLine(self, n): - idc.Jump(self.items[n][2]) - - def OnGetLine(self, n): - return self.items[n] + def OnInit(self): + self.items = [ [hex(x), get_func_name(x), x] + for x in idautils.Functions() ] + return True def OnGetSize(self): return len(self.items) + def OnGetLine(self, n): + return self.items[n] + def OnDeleteLine(self, n): ea = self.items[n][2] - idc.DelFunction(ea) - return n + idc.del_func(ea) + return (Choose.ALL_CHANGED, n) + + def OnSelectLine(self, n): + idc.jumpto(self.items[n][2]) + return (Choose.NOTHING_CHANGED, ) def OnRefresh(self, n): - self.PopulateItems() - return n + self.OnInit() + # try to preserve the cursor + return [Choose.ALL_CHANGED] + self.adjust_last_item(n) -c = MyChoose2("My functions list") -c.Show() \ No newline at end of file + def OnClose(self): + print "closed ", self.title + +c = MyChoose("My functions list") +c.Show() diff --git a/examples/ex_gdl_qflow_chart.py b/examples/ex_gdl_qflow_chart.py index 8ee9c8e..38b0593 100644 --- a/examples/ex_gdl_qflow_chart.py +++ b/examples/ex_gdl_qflow_chart.py @@ -6,17 +6,17 @@ def raw_main(p=True): f = idaapi.get_func(here()) if not f: return - + q = idaapi.qflow_chart_t("The title", f, 0, 0, idaapi.FC_PREDS) for n in xrange(0, q.size()): b = q[n] if p: - print "%x - %x [%d]:" % (b.startEA, b.endEA, n) - + print "%x - %x [%d]:" % (b.start_ea, b.end_ea, n) + for ns in xrange(0, q.nsucc(n)): if p: print "SUCC: %d->%d" % (n, q.succ(n, ns)) - + for ns in xrange(0, q.npred(n)): if p: print "PRED: %d->%d" % (n, q.pred(n, ns)) @@ -27,14 +27,14 @@ def cls_main(p=True): f = idaapi.FlowChart(idaapi.get_func(here())) for block in f: if p: - print "%x - %x [%d]:" % (block.startEA, block.endEA, block.id) + print "%x - %x [%d]:" % (block.start_ea, block.end_ea, block.id) for succ_block in block.succs(): if p: - print " %x - %x [%d]:" % (succ_block.startEA, succ_block.endEA, succ_block.id) - + print " %x - %x [%d]:" % (succ_block.start_ea, succ_block.end_ea, succ_block.id) + for pred_block in block.preds(): if p: - print " %x - %x [%d]:" % (pred_block.startEA, pred_block.endEA, pred_block.id) + print " %x - %x [%d]:" % (pred_block.start_ea, pred_block.end_ea, pred_block.id) q = None f = None diff --git a/examples/ex_graph.py b/examples/ex_graph.py index dafeb6b..2fe9fc1 100644 --- a/examples/ex_graph.py +++ b/examples/ex_graph.py @@ -51,19 +51,16 @@ class MyGraph(GraphViewer): def OnGetText(self, node_id): return self[node_id] - def Show(self): - if not GraphViewer.Show(self): - return False + def OnPopup(self, form, popup_handle): # graph closer actname = "graph_closer:%s" % self.title - register_action(action_desc_t(actname, "Close: %s" % self.title, GraphCloser(self))) - attach_action_to_popup(self.GetTCustomControl(), None, actname) + desc = action_desc_t(actname, "Close: %s" % self.title, GraphCloser(self)) + attach_dynamic_action_to_popup(form, popup_handle, desc) # color changer actname = "color_changer:%s" % self.title - register_action(action_desc_t(actname, "Change colors: %s" % self.title, ColorChanger(self))) - attach_action_to_popup(self.GetTCustomControl(), None, actname) - return True + desc = action_desc_t(actname, "Change colors: %s" % self.title, ColorChanger(self)) + attach_dynamic_action_to_popup(form, popup_handle, desc) def show_graph(): @@ -73,14 +70,15 @@ def show_graph(): return # Iterate through all function instructions and take only call instructions result = {} - for x in [x for x in FuncItems(f.startEA) if idaapi.is_call_insn(x)]: + tmp = idaapi.insn_t() + for x in [x for x in FuncItems(f.start_ea) if (idaapi.decode_insn(tmp, x) and idaapi.is_call_insn(tmp))]: for xref in XrefsFrom(x, idaapi.XREF_FAR): if not xref.iscode: continue - t = GetFunctionName(xref.to) + t = get_func_name(xref.to) if not t: t = hex(xref.to) result[t] = True - g = MyGraph(GetFunctionName(f.startEA), result) + g = MyGraph(get_func_name(f.start_ea), result) if g.Show(): return g else: diff --git a/examples/ex_hexrays.py b/examples/ex_hexrays.py new file mode 100644 index 0000000..503d0af --- /dev/null +++ b/examples/ex_hexrays.py @@ -0,0 +1,40 @@ +# +# This example tries to load a decompiler plugin corresponding to the current +# architecture (and address size) right after auto-analysis is performed, +# and then tries to decompile the function at the first entrypoint. +# +# It is particularly suited for use with the '-S' flag. +# + +import ida_ida +import ida_auto +import ida_loader +import ida_hexrays +import ida_idp +import ida_entry + +ida_auto.auto_wait() +ALL_DECOMPILERS = { + ida_idp.PLFM_386 : ("hexrays", "hexx64"), + ida_idp.PLFM_ARM : ("hexarm", "hexarm64"), + ida_idp.PLFM_PPC : ("hexppc", "hexppc64"), +} +pair = ALL_DECOMPILERS.get(ida_idp.ph.id, None) +if pair: + decompiler = pair[1 if ida_ida.cvar.inf.is_64bit() else 0] + if ida_loader.load_plugin(decompiler) and ida_hexrays.init_hexrays_plugin(): + eqty = ida_entry.get_entry_qty() + if eqty: + ea = ida_entry.get_entry(ida_entry.get_entry_ordinal(0)) + print("Decompiling at: %X" % ea) + cf = ida_hexrays.decompile(ea) + if cf: + print(cf) + else: + print("Decompilation failed") + else: + print("No known entrypoint. Cannot decompile.") + else: + print("Couldn't load or initialize decompiler: \"%s\"" % decompiler) +else: + print("No known decompilers for architecture with ID: %d" % ida_idp.ph.id) diff --git a/examples/ex_procext.py b/examples/ex_procext.py new file mode 100644 index 0000000..d7a311b --- /dev/null +++ b/examples/ex_procext.py @@ -0,0 +1,43 @@ +# this script implements disassembly of BUG_INSTR used in Linux kernel BUG() macro +# normally it's architecturally undefined and is not disassembled by IDA's ARM module +# see Linux/arch/arm/include/asm/bug.h + +import idaapi + +ITYPE_BUGINSN = idaapi.CUSTOM_CMD_ITYPE + 10 +MNEM_WIDTH = 16 + +class MyHooks(idaapi.IDP_Hooks): + + def __init__(self): + idaapi.IDP_Hooks.__init__(self) + self.reported = [] + + def ev_ana_insn(self, insn): + t = get_sreg(insn.ea, "T") + if t==0 and get_wide_dword(insn.ea) == 0xE7F001F2: + insn.itype = ITYPE_BUGINSN + insn.size = 4 + elif t!=0 and get_wide_word(insn.ea) == 0xde02: + insn.itype = ITYPE_BUGINSN + insn.size = 2 + return insn.size + + def ev_emu_insn(self, insn): + if insn.ea == ITYPE_BUGINSN: + return 1 + return 0 + + def ev_out_mnem(self, outctx): + if outctx.insn.itype == ITYPE_BUGINSN: + outctx.out_custom_mnem("BUG_INSTR", MNEM_WIDTH) + return 1 + return 0 + +if idaapi.ph.id == idaapi.PLFM_ARM: + bahooks = MyHooks() + bahooks.hook() + print "BUG_INSTR processor extension installed" +else: + warning("This script only supports ARM files") + diff --git a/examples/ex_sync_graphs.py b/examples/ex_sync_graphs.py new file mode 100644 index 0000000..2f26150 --- /dev/null +++ b/examples/ex_sync_graphs.py @@ -0,0 +1,82 @@ + +from idaapi import * + +# +# Cleanup (in case the script is run more than once) +# +try: + wrap_a.Unbind() +except: + pass + + +wrap_a = None + +# +# The IDA View-A "monitor": changes will be reported into IDA View-B +# +class IDAViewA_monitor_t(IDAViewWrapper): + def __init__(self): + IDAViewWrapper.__init__(self, "IDA View-A") + + def OnViewLocationChanged(self, now, was): + self.update_widget_b() + + def update_widget_b(self): + + # Make sure we are in the same function + place_a, _, _ = get_custom_viewer_place(widget_a, False) + jumpto(widget_b, place_a, -1, -1) + + # and that we show the right place (slightly zoomed out) + widget_a_center_gli = graph_location_info_t() + if viewer_get_gli(widget_a_center_gli, widget_a, GLICTL_CENTER): + widget_b_center_gli = graph_location_info_t() + widget_b_center_gli.orgx = widget_a_center_gli.orgx + widget_b_center_gli.orgy = widget_a_center_gli.orgy + widget_b_center_gli.zoom = widget_a_center_gli.zoom * 0.5 + viewer_set_gli(widget_b, widget_b_center_gli, GLICTL_CENTER) + +# +# Make sure both views are opened... +# +for label in ["A", "B"]: + title = "IDA View-%s" % label + if not find_widget(title): + print("View %s not available. Opening." % title) + open_disasm_window(label) + +# +# ...and that they are both in graph mode +# +widget_a = find_widget("IDA View-A") +set_view_renderer_type(widget_a, TCCRT_GRAPH) + +widget_b = find_widget("IDA View-B") +set_view_renderer_type(widget_b, TCCRT_GRAPH) + +# +# Put view B to the right of view A +# +set_dock_pos("IDA View-B", "IDA View-A", DP_RIGHT) + +# +# Start monitoring IDA View-A +# +wrap_a = IDAViewA_monitor_t() +wrap_a.Bind() + +# +# This is to get a properly initialized set of views to begin with. +# At this point, all UI resize/move events resulting of 'set_dock_pos()' +# haven't yet been processed, and thus the views don't know their final +# geometries. We'll give them a bit of time to process those events, and +# then we'll request that "IDA View-A" shows the whole graph (and +# "IDA View-B" will obviously follow.) +# +def fit_widget_a(): + def do_fit_widget_a(): + viewer_fit_window(widget_a) + execute_sync(do_fit_widget_a, MFF_FAST) +import threading +threading.Timer(0.25, fit_widget_a).start() diff --git a/examples/ex_uihook.py b/examples/ex_uihook.py index 85f349a..f9dfd8e 100644 --- a/examples/ex_uihook.py +++ b/examples/ex_uihook.py @@ -22,7 +22,7 @@ class MyUiHook(idaapi.UI_Hooks): def postprocess(self): print("IDA finished processing command: %s" % self.cmdname) return 0 - + def saving(self): """ The kernel is saving the database. @@ -43,7 +43,7 @@ class MyUiHook(idaapi.UI_Hooks): """ IDA is terminated and the database is already closed. The UI may close its windows in this callback. - + This callback is best used with a plugin_t with flags PLUGIN_FIX """ print("IDA terminated") @@ -51,12 +51,12 @@ class MyUiHook(idaapi.UI_Hooks): def get_ea_hint(self, ea): """ The UI wants to display a simple hint for an address in the navigation band - + @param ea: The address @return: String with the hint or None """ print("get_ea_hint(%x)" % ea) - + #--------------------------------------------------------------------- # Remove an existing hook on second run diff --git a/examples/ex_uirequests.py b/examples/ex_uirequests.py index 292c6bb..cbd1566 100644 --- a/examples/ex_uirequests.py +++ b/examples/ex_uirequests.py @@ -67,7 +67,7 @@ class print_req_t(object): -if idc.AskYN(1,("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n" +if idc.ask_yn(1,("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n" "Press NO to execute ProcessUiActions() example\n")): idaapi.execute_ui_requests( (print_req_t("Hello"), print_req_t(" world\n")) ) diff --git a/examples/hotkey.py b/examples/hotkey.py index fdc8b5a..82dd078 100644 --- a/examples/hotkey.py +++ b/examples/hotkey.py @@ -13,12 +13,12 @@ def foo(): # IDA binds hotkeys to IDC functions so a trampoline IDC function # must be created -idaapi.CompileLine('static key_2() { RunPythonStatement("foo()"); }') +idaapi.compile_idc_text('static key_2() { RunPythonStatement("foo()"); }') # Add the hotkey -AddHotkey("2", 'key_2') +add_idc_hotkey("2", 'key_2') # Press 2 to activate foo() # The hotkey can be removed with -# DelHotkey('2') +# del_idc_hotkey('2') diff --git a/examples/idapythonrc.py b/examples/idapythonrc.py index 0d544ad..9c7b9b2 100644 --- a/examples/idapythonrc.py +++ b/examples/idapythonrc.py @@ -1,7 +1,7 @@ #--------------------------------------------------------------------- # Example user initialisation script: idapythonrc.py # -# Place this script to ~/.idapro/ or to +# Place this script to ~/.idapro/ or to # %APPDATA%\Hex-Rays\IDA Pro #--------------------------------------------------------------------- import idaapi diff --git a/examples/structure.py b/examples/structure.py index 1ebedd3..1fa9f92 100644 --- a/examples/structure.py +++ b/examples/structure.py @@ -8,42 +8,42 @@ #--------------------------------------------------------------------- from idaapi import stroffflag, offflag -sid = GetStrucIdByName("mystr1") +sid = get_struc_id("mystr1") if sid != -1: - DelStruc(sid) -sid = AddStrucEx(-1, "mystr1", 0) + del_struc(sid) +sid = add_struc(-1, "mystr1", 0) print "%x" % sid # Test simple data types -simple_types = [ FF_BYTE, FF_WORD, FF_DWRD, FF_QWRD, FF_TBYT, FF_OWRD, FF_FLOAT, FF_DOUBLE, FF_PACKREAL ] +simple_types = [ FF_BYTE, FF_WORD, FF_DWORD, FF_QWORD, FF_TBYTE, FF_OWORD, FF_FLOAT, FF_DOUBLE, FF_PACKREAL ] simple_sizes = [ 1, 2, 4, 8, 10, 16, 4, 8, 10 ] i = 0 for t,nsize in zip(simple_types, simple_sizes): - print "t%x:"% ((t|FF_DATA)&0xFFFFFFFF), AddStrucMember(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize) + print "t%x:"% ((t|FF_DATA)&0xFFFFFFFF), add_struc_member(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize) i+=1 - + # Test ASCII type -print "ASCII:", AddStrucMember(sid, "tascii", -1, FF_ASCI|FF_DATA, ASCSTR_C, 8) +print "ASCII:", add_struc_member(sid, "tascii", -1, FF_STRLIT|FF_DATA, STRTYPE_C, 8) # Test enum type - Add a defined enum name or load MACRO_WMI from a type library. -#eid = GetEnum("MACRO_WMI") -#print "Enum:", AddStrucMember(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWRD, eid, 4) +#eid = get_enum("MACRO_WMI") +#print "Enum:", add_struc_member(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWORD, eid, 4) # Test struc member type -msid = GetStrucIdByName("mystr2") +msid = get_struc_id("mystr2") if msid != -1: - DelStruc(msid) -msid = AddStrucEx(-1, "mystr2", 0) -print AddStrucMember(msid, "member1", -1, (FF_DWRD|FF_DATA )&0xFFFFFFFF, -1, 4) -print AddStrucMember(msid, "member2", -1, (FF_DWRD|FF_DATA )&0xFFFFFFFF, -1, 4) + del_struc(msid) +msid = add_struc(-1, "mystr2", 0) +print add_struc_member(msid, "member1", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4) +print add_struc_member(msid, "member2", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4) -msize = GetStrucSize(msid) -print "Struct:", AddStrucMember(sid, "tstruct", -1, FF_STRU|FF_DATA, msid, msize) -print "Stroff:", AddStrucMember(sid, "tstroff", -1, stroffflag()|FF_DWRD, msid, 4) +msize = get_struc_size(msid) +print "Struct:", add_struc_member(sid, "tstruct", -1, FF_STRUCT|FF_DATA, msid, msize) +print "Stroff:", add_struc_member(sid, "tstroff", -1, stroffflag()|FF_DWORD, msid, 4) # Test offset types -print "Offset:", AddStrucMember(sid, "toffset", -1, offflag()|FF_DATA|FF_DWRD, 0, 4) -print "Offset:", SetMemberType(sid, 0, offflag()|FF_DATA|FF_DWRD, 0, 4) +print "Offset:", add_struc_member(sid, "toffset", -1, offflag()|FF_DATA|FF_DWORD, 0, 4) +print "Offset:", set_member_type(sid, 0, offflag()|FF_DATA|FF_DWORD, 0, 4) print "Done" diff --git a/examples/vds3.py b/examples/vds3.py index 3057751..73fab14 100644 --- a/examples/vds3.py +++ b/examples/vds3.py @@ -3,19 +3,14 @@ Author: EiNSTeiN_ This is a rewrite in Python of the vds3 example that comes with hexrays sdk. - - -The main difference with the original C code is that when we create the inverted -condition object, the newly created cexpr_t instance is given to the hexrays and -must not be freed by swig. To achieve this, we have to change the 'thisown' flag -when appropriate. See http://www.swig.org/Doc1.3/Python.html#Python_nn35 - """ import idautils import idaapi import idc +import traceback + NETNODE_NAME = '$ hexrays-inverted-if' inverter_actname = "vds3:invert" @@ -26,16 +21,14 @@ class invert_action_handler_t(idaapi.action_handler_t): self.inverter = inverter def activate(self, ctx): - vdui = idaapi.get_tform_vdui(ctx.form) + vdui = idaapi.get_widget_vdui(ctx.widget) self.inverter.invert_if_event(vdui) return 1 def update(self, ctx): - vdui = idaapi.get_tform_vdui(ctx.form) - if vdui: - return idaapi.AST_ENABLE_FOR_FORM - else: - return idaapi.AST_DISABLE_FOR_FORM + return idaapi.AST_ENABLE_FOR_WIDGET if \ + ctx.widget_type == idaapi.BWN_PSEUDOCODE else \ + idaapi.AST_DISABLE_FOR_WIDGET class hexrays_callback_info(object): @@ -92,7 +85,6 @@ class hexrays_callback_info(object): idaapi.qswap(cif.ithen, cif.ielse) cond = idaapi.cexpr_t(cif.expr) notcond = idaapi.lnot(cond) - cond.thisown = 0 # the new wrapper 'notcond' now holds the reference to the cexpr_t cif.expr.swap(notcond) @@ -176,7 +168,7 @@ class hexrays_callback_info(object): def event_callback(self, event, *args): if event == idaapi.hxe_populating_popup: - form, phandle, vu = args + widget, phandle, vu = args res = idaapi.attach_action_to_popup(vu.ct, None, inverter_actname) elif event == idaapi.hxe_maturity: diff --git a/examples/vds4.py b/examples/vds4.py index 0cb666c..b19cff0 100644 --- a/examples/vds4.py +++ b/examples/vds4.py @@ -53,17 +53,17 @@ def run(): print "Number format at %a, operand %d: %s" % (ol.ea, ol.opnum, "negated " if (nf.props & NF_NEGATE) != 0 else "") - if nf.isEnum(): + if nf.is_enum(): print "enum %s (serial %d)" % (str(nf.type_name), nf.serial) - elif nf.isChar(): + elif nf.is_char(): print "char" - elif nf.isStroff(): + elif nf.is_stroff(): print "struct offset %s" % (str(nf.type_name), ) else: - print "number base=%d" % (idaapi.getRadix(nf.flags, ol.opnum), ) + print "number base=%d" % (idaapi.get_radix(nf.flags, ol.opnum), ) idaapi.user_numforms_free(numforms) diff --git a/examples/vds5.py b/examples/vds5.py new file mode 100644 index 0000000..51c24ec --- /dev/null +++ b/examples/vds5.py @@ -0,0 +1,308 @@ + +import ida_hexrays +import ida_kernwin +import ida_gdl +import ida_lines + +ACTION_NAME = "vds5.py:displaygraph" +ACTION_SHORTCUT = "Ctrl+Shift+G" + +CL_WHITE = ((255)+ (255<<8)+ (255<<16)) # 0 +CL_BLUE = ((0 )+ (0 <<8)+ (255<<16)) # 1 +CL_RED = ((255)+ (0 <<8)+ (0 <<16)) # 2 +CL_GREEN = ((0 )+ (255<<8)+ (0 <<16)) # 3 +CL_YELLOW = ((255)+ (255<<8)+ (0 <<16)) # 4 +CL_MAGENTA = ((255)+ (0 <<8)+ (255<<16)) # 5 +CL_CYAN = ((0 )+ (255<<8)+ (255<<16)) # 6 +CL_DARKGREY = ((85 )+ (85 <<8)+ (85 <<16)) # 7 +CL_DARKBLUE = ((0 )+ (0 <<8)+ (128<<16)) # 8 +CL_DARKRED = ((128)+ (0 <<8)+ (0 <<16)) # 9 +CL_DARKGREEN = ((0 )+ (128<<8)+ (0 <<16)) # 10 +CL_DARKYELLOW = ((128)+ (128<<8)+ (0 <<16)) # 11 +CL_DARKMAGENTA = ((128)+ (0 <<8)+ (128<<16)) # 12 +CL_DARKCYAN = ((0 )+ (128<<8)+ (128<<16)) # 13 +CL_GOLD = ((255)+ (215<<8)+ (0 <<16)) # 14 +CL_LIGHTGREY = ((170)+ (170<<8)+ (170<<16)) # 15 +CL_LIGHTBLUE = ((128)+ (128<<8)+ (255<<16)) # 16 +CL_LIGHTRED = ((255)+ (128<<8)+ (128<<16)) # 17 +CL_LIGHTGREEN = ((128)+ (255<<8)+ (128<<16)) # 18 +CL_LIGHTYELLOW = ((255)+ (255<<8)+ (128<<16)) # 19 +CL_LIGHTMAGENTA = ((255)+ (128<<8)+ (255<<16)) # 20 +CL_LIGHTCYAN = ((128)+ (255<<8)+ (255<<16)) # 21 +CL_LILAC = ((238)+ (130<<8)+ (238<<16)) # 22 +CL_TURQUOISE = ((64 )+ (224<<8)+ (208<<16)) # 23 +CL_AQUAMARINE = ((127)+ (255<<8)+ (212<<16)) # 24 +CL_KHAKI = ((240)+ (230<<8)+ (140<<16)) # 25 +CL_PURPLE = ((160)+ (32 <<8)+ (240<<16)) # 26 +CL_YELLOWGREEN = ((154)+ (205<<8)+ (50 <<16)) # 27 +CL_PINK = ((255)+ (192<<8)+ (203<<16)) # 28 +CL_ORANGE = ((255)+ (165<<8)+ (0 <<16)) # 29 +CL_ORCHID = ((218)+ (112<<8)+ (214<<16)) # 30 +CL_BLACK = ((0 )+ (0 <<8)+ (0 <<16)) # 31 + +COLORS_LUT = { + CL_WHITE : "white", + CL_BLUE : "blue", + CL_RED : "red", + CL_GREEN : "green", + CL_YELLOW : "yellow", + CL_MAGENTA : "magenta", + CL_CYAN : "cyan", + CL_DARKGREY : "darkgrey", + CL_DARKBLUE : "darkblue", + CL_DARKRED : "darkred", + CL_DARKGREEN : "darkgreen", + CL_DARKYELLOW : "darkyellow", + CL_DARKMAGENTA : "darkmagenta", + CL_DARKCYAN : "darkcyan", + CL_GOLD : "gold", + CL_LIGHTGREY : "lightgrey", + CL_LIGHTBLUE : "lightblue", + CL_LIGHTRED : "lightred", + CL_LIGHTGREEN : "lightgreen", + CL_LIGHTYELLOW : "lightyellow", + CL_LIGHTMAGENTA : "lightmagenta", + CL_LIGHTCYAN : "lightcyan", + CL_LILAC : "lilac", + CL_TURQUOISE : "turquoise", + CL_AQUAMARINE : "aquamarine", + CL_KHAKI : "khaki", + CL_PURPLE : "purple", + CL_YELLOWGREEN : "yellowgreen", + CL_PINK : "pink", + CL_ORANGE : "orange", + CL_ORCHID : "orchid", + CL_BLACK : "black", +} + +def get_color_name(c): + return COLORS_LUT[c] if c in COLORS_LUT.keys() else "?" + +class cfunc_graph_t: # alas we can't inherit gdl_graph_t + def __init__(self, highlight): + self.items = [] # list of citem_t + self.highlight = highlight + self.succs = [] # list of lists of next nodes + self.preds = [] # list of lists of previous nodes + + def nsucc(self, n): + return len(self.succs[n]) if self.size() else 0 + + def npred(self, n): + return len(self.preds[n]) if self.size() else 0 + + def succ(self, n, i): + return self.succs[n][i] + + def pred(self, n, i): + return self.preds[n][i] + + def size(self): + return len(self.preds) + + def add_node(self): + n = self.size() + + def resize(array, new_size): + if new_size > len(array): + while len(array) < new_size: + array.append([]) + else: + array = array[:new_size] + return array + + self.preds = resize(self.preds, n+1) + self.succs = resize(self.succs, n+1) + return n + + def add_edge(self, x, y): + self.preds[y].append(x) + self.succs[x].append(y) + + def get_expr_name(self, expr): + name = expr.print1(None) + name = ida_lines.tag_remove(name) + name = ida_pro.str2user(name) + return name + + def get_node_label(self, n): + item = self.items[n] + op = item.op + insn = item.cinsn + expr = item.cexpr + parts = [ida_hexrays.get_ctype_name(op)] + if op == ida_hexrays.cot_ptr: + parts.append(".%d" % expr.ptrsize) + elif op == ida_hexrays.cot_memptr: + parts.append(".%d (m=%d)" % (expr.ptrsize, expr.m)) + elif op == ida_hexrays.cot_memref: + parts.append(" (m=%d)" % (expr.m,)) + elif op in [ + ida_hexrays.cot_obj, + ida_hexrays.cot_var]: + name = self.get_expr_name(expr) + parts.append(".%d %s" % (expr.refwidth, name)) + elif op in [ + ida_hexrays.cot_num, + ida_hexrays.cot_helper, + ida_hexrays.cot_str]: + name = self.get_expr_name(expr) + parts.append(" %s" % (name,)) + elif op == ida_hexrays.cit_goto: + parts.append(" LABEL_%d" % insn.cgoto.label_num) + elif op == ida_hexrays.cit_asm: + parts.append("") + # parts.append(" %a.%d" % ()) + parts.append("\\n") + parts.append("ea: %08X" % item.ea) + if item.is_expr() and not expr.type.empty(): + parts.append("\\n") + tstr = expr.type._print() + parts.append(tstr if tstr else "?") + return "".join(parts) + + def get_node_color(self, n): + item = self.items[n] + if self.highlight is not None and item.obj_id == self.highlight.obj_id: + return CL_GREEN + return None + + def gen_gdl(self, fname): + with open(fname, "wb") as out: + out.write("graph: {\n") + + out.write("// *** nodes\n") + for n in xrange(len(self.items)): + item = self.items[n] + node_label = self.get_node_label(n) + node_props = [""] + if n == 0: + node_props.append("vertical_order: 0") + color = self.get_node_color(n) + if color is not None: + node_props.append("color: %s" % get_color_name(color)) + out.write("""node: { title: "%d" label: "%d: %s" %s}\n""" % ( + n, + n, + node_label, + " ".join(node_props))) + + out.write("// *** edges\n") + for n in xrange(len(self.items)): + item = self.items[n] + out.write("// edges %d -> ?\n" % n) + for i in xrange(self.nsucc(n)): + t = self.succ(n, i) + label = "" + if item.is_expr(): + target = self.items[t] + if item.x is not None and item.x == target: + label = "x" + elif item.y is not None and item.y == target: + label = "y" + elif item.z is not None and item.z == target: + label = "z" + if label: + label = """ label: "%s" """ % label + out.write("""edge: { sourcename: "%s" targetname: "%s"%s}\n""" % ( + str(n), str(t), label)) + + out.write("}\n") + + def dump(self): + print("%d items:" % len(self.items)) + for i in self.items: + print("\t%s (%08x)" % (i, i.ea)) + + print("succs:") + for s in self.succs: + print("\t%s" % s) + + print("preds:") + for p in self.preds: + print("\t%s" % p) + + +class graph_builder_t(ida_hexrays.ctree_parentee_t): + + def __init__(self, cg): + ida_hexrays.ctree_parentee_t.__init__(self) + self.cg = cg + self.reverse = {} # citem_t -> node# + + def add_node(self, i): + for k in self.reverse.keys(): + if i.obj_id == k.obj_id: + ida_kernwin.warning("bad ctree - duplicate nodes! (i.ea=%x)" % i.ea) + self.cg.dump() + return -1 + + n = self.cg.add_node() + if n <= len(self.cg.items): + self.cg.items.append(i) + self.cg.items[n] = i + self.reverse[i] = n + return n + + def process(self, i): + n = self.add_node(i) + if n < 0: + return n + if len(self.parents) > 1: + lp = self.parents.back().obj_id + for k, v in self.reverse.items(): + if k.obj_id == lp: + p = v + break + self.cg.add_edge(p, n) + return 0 + + def visit_insn(self, i): + return self.process(i) + + def visit_expr(self, e): + return self.process(e) + + +class display_graph_ah_t(ida_kernwin.action_handler_t): + def __init__(self): + ida_kernwin.action_handler_t.__init__(self) + + def activate(self, ctx): + vu = ida_hexrays.get_widget_vdui(ctx.widget) + vu.get_current_item(ida_hexrays.USE_KEYBOARD) + highlight = vu.item.e if vu.item.is_citem() else None + + cg = cfunc_graph_t(highlight) + gb = graph_builder_t(cg) + gb.apply_to(vu.cfunc.body, None) + + import tempfile + fname = tempfile.mktemp(suffix=".gdl") + cg.gen_gdl(fname) + ida_gdl.display_gdl(fname) + return 1 + + def update(self, ctx): + return ida_kernwin.AST_ENABLE_FOR_WIDGET if \ + ctx.widget_type == ida_kernwin.BWN_PSEUDOCODE else \ + ida_kernwin.AST_DISABLE_FOR_WIDGET + + +def cb(event, *args): + if event == ida_hexrays.hxe_populating_popup: + widget, phandle, vu = args + res = idaapi.attach_action_to_popup(vu.ct, None, ACTION_NAME) + return 0 + + +if ida_hexrays.init_hexrays_plugin(): + ida_kernwin.register_action( + ida_kernwin.action_desc_t( + ACTION_NAME, + "Hex-Rays show C graph (IDAPython)", + display_graph_ah_t(), + ACTION_SHORTCUT)) + idaapi.install_hexrays_callback(cb) +else: + print 'hexrays-graph: hexrays is not available.' diff --git a/examples/vds8.py b/examples/vds8.py new file mode 100644 index 0000000..0897ea2 --- /dev/null +++ b/examples/vds8.py @@ -0,0 +1,94 @@ + +# Hex-Rays Decompiler project +# Copyright (c) 2007-2017 by Hex-Rays, support@hex-rays.com +# ALL RIGHTS RESERVED. +# +# Sample plugin for Hex-Rays Decompiler usage of udc_filter_t +# class: decompile svc 0x900001 and svc 0x9000F8 as function calls to +# svc_exit() and svc_exit_group() respectively. +# NOTE: You will need to have an ARM + Linux IDB for this plugin to be usable +# +# It is also added into the right-click menu as "vds8.py:Toggle UDC" + +import ida_hexrays +import ida_kernwin +import ida_allins + +ACTION_NAME = "vds8.py:udcall" +ACTION_SHORTCUT = "Ctrl+Shift+U" + +# -------------------------------------------------------------------------- +class udc_exit_t(ida_hexrays.udc_filter_t): + def __init__(self, code, name): + ida_hexrays.udc_filter_t.__init__(self) + if not self.init("int __usercall %s@(int status@);" % name): + raise Exception("Couldn't initialize udc_exit_t instance") + self.code = code + self.installed = False + + def match(self, cdg): + return cdg.insn.itype == ida_allins.ARM_svc and cdg.insn.Op1.value == self.code + + def install(self): + ida_hexrays.install_microcode_filter(self, True); + self.installed = True + + def uninstall(self): + ida_hexrays.install_microcode_filter(self, False); + self.installed = False + + def toggle_install(self): + if self.installed: + self.uninstall() + else: + self.install() + + +# -------------------------------------------------------------------------- +class toggle_udc_ah_t(ida_kernwin.action_handler_t): + def __init__(self): + ida_kernwin.action_handler_t.__init__(self) + + def activate(self, ctx): + udc_exit.toggle_install(); + udc_exit_group.toggle_install(); + vu = ida_hexrays.get_widget_vdui(ctx.widget) + vu.refresh_view(True) + return 1 + + def update(self, ctx): + return ida_kernwin.AST_ENABLE_FOR_WIDGET if \ + ctx.widget_type == ida_kernwin.BWN_PSEUDOCODE else \ + ida_kernwin.AST_DISABLE_FOR_WIDGET + + +# -------------------------------------------------------------------------- +class my_hooks_t(ida_kernwin.UI_Hooks): + def __init__(self): + ida_kernwin.UI_Hooks.__init__(self) + + def populating_widget_popup(self, widget, popup): + if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_PSEUDOCODE: + ida_kernwin.attach_action_to_popup(widget, popup, ACTION_NAME) +my_hooks = my_hooks_t() +my_hooks.hook() + + +# -------------------------------------------------------------------------- +SVC_EXIT = 0x900001 +SVC_EXIT_GROUP = 0x9000f8 + +if ida_hexrays.init_hexrays_plugin(): + udc_exit = udc_exit_t(SVC_EXIT, "svc_exit") + udc_exit.toggle_install() + + udc_exit_group = udc_exit_t(SVC_EXIT_GROUP, "svc_exit_group") + udc_exit_group.toggle_install() + + ida_kernwin.register_action( + ida_kernwin.action_desc_t( + ACTION_NAME, + "vds8.py:Toggle UDC", + toggle_udc_ah_t(), + ACTION_SHORTCUT)) + diff --git a/examples/vds_create_hint.py b/examples/vds_create_hint.py new file mode 100644 index 0000000..860013d --- /dev/null +++ b/examples/vds_create_hint.py @@ -0,0 +1,32 @@ +"""'Hints' plugin for Hexrays Decompiler + +Hijack the 'hxe_create_hint' notification, to return our own. +If the object under the cursor is: + - a function call, prefix the original decompiler hint with "==> " + - a local variable declaration, replace the hint with our own in the form of "!{varname}" (where '{varname}' is replaced w/ the variable name) + - an 'if' statement, replace the hint with our own, saying "condition" +""" + +import ida_hexrays + +def create_hint_cb(event, *args): + if event == ida_hexrays.hxe_create_hint: + vu = args[0] + if vu.get_current_item(ida_hexrays.USE_MOUSE): + cit = vu.item.citype + if cit == ida_hexrays.VDI_LVAR: + return 1, "!%s" % vu.item.l.name, 1 + elif cit == ida_hexrays.VDI_EXPR: + ce = vu.item.e + if ce.op == ida_hexrays.cot_call: + return 2, "==> ", 1 + if ce.op == ida_hexrays.cit_if: + return 1, "condition", 1 + return 0 + return 0 + +if ida_hexrays.init_hexrays_plugin(): + ida_hexrays.install_hexrays_callback(create_hint_cb) +else: + print 'hexrays is not available.' + diff --git a/examples/vds_xrefs.py b/examples/vds_xrefs.py index b949b27..1fb55cb 100644 --- a/examples/vds_xrefs.py +++ b/examples/vds_xrefs.py @@ -60,15 +60,15 @@ class XrefsForm(idaapi.PluginForm): xtype.remove_ptr_or_array() typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') - sid = idc.GetStrucIdByName(typename) - member = idc.GetMemberName(sid, m) + sid = idc.get_struc_id(typename) + member = idc.get_member_name(sid, m) return '%s::%s' % (typename, member) - def OnCreate(self, form): + def OnCreate(self, widget): # Get parent widget - self.parent = self.FormToPyQtWidget(form) + self.parent = self.FormToPyQtWidget(widget) self.populate_form() @@ -144,7 +144,7 @@ class XrefsForm(idaapi.PluginForm): cfunc = idaapi.decompile(ea) self.functions.append(cfunc.entry_ea) - self.items.append((ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea))) + self.items.append((ea, idc.get_func_name(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea))) except Exception as e: print 'could not decompile: %s' % (str(e), ) @@ -210,7 +210,7 @@ class XrefsForm(idaapi.PluginForm): self.functions.append(cfunc.entry_ea) self.items.append(( parent.ea, - idc.GetFunctionName(cfunc.entry_ea), + idc.get_func_name(cfunc.entry_ea), self.get_decompiled_line(cfunc, parent.ea))) @@ -247,7 +247,7 @@ class XrefsForm(idaapi.PluginForm): return - def OnClose(self, form): + def OnClose(self, widget): pass @@ -257,7 +257,7 @@ class show_xrefs_ah_t(idaapi.action_handler_t): self.sel = None def activate(self, ctx): - vu = idaapi.get_tform_vdui(ctx.form) + vu = idaapi.get_widget_vdui(ctx.widget) if not vu or not self.sel: print "No vdui? Strange, since this action should be enabled only for pseudocode views." return 0 @@ -267,22 +267,21 @@ class show_xrefs_ah_t(idaapi.action_handler_t): return 1 def update(self, ctx): - vu = idaapi.get_tform_vdui(ctx.form) - if not vu: - return idaapi.AST_DISABLE_FOR_FORM - else: - vu.get_current_item(idaapi.USE_KEYBOARD) - item = vu.item - self.sel = None - if item.citype == idaapi.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'): - # if an expression is selected. verify that it's either a cot_obj, cot_memref or cot_memptr - self.sel = item.it.to_specific_type + if ctx.widget_type != idaapi.BWN_PSEUDOCODE: + return idaapi.AST_DISABLE_FOR_WIDGET + vu = idaapi.get_widget_vdui(ctx.widget) + vu.get_current_item(idaapi.USE_KEYBOARD) + item = vu.item + self.sel = None + if item.citype == idaapi.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'): + # if an expression is selected. verify that it's either a cot_obj, cot_memref or cot_memptr + self.sel = item.it.to_specific_type - elif item.citype == idaapi.VDI_FUNC: - # if the function itself is selected, show xrefs to it. - self.sel = item.f + elif item.citype == idaapi.VDI_FUNC: + # if the function itself is selected, show xrefs to it. + self.sel = item.f - return idaapi.AST_ENABLE if self.sel else idaapi.AST_DISABLE + return idaapi.AST_ENABLE if self.sel else idaapi.AST_DISABLE class hexrays_callback_info(object): @@ -293,8 +292,8 @@ class hexrays_callback_info(object): try: if event == idaapi.hxe_populating_popup: - form, phandle, vu = args - idaapi.attach_action_to_popup(form, phandle, "vdsxrefs:show", None) + widget, phandle, vu = args + idaapi.attach_action_to_popup(widget, phandle, "vdsxrefs:show", None) except: traceback.print_exc() diff --git a/idapython.vcxproj b/idapython.vcxproj index 17090a7..2792f5d 100644 --- a/idapython.vcxproj +++ b/idapython.vcxproj @@ -110,6 +110,7 @@ EditAndContinue Cdecl 4102;4804;4800;4018;4005;%(DisableSpecificWarnings) + true _DEBUG;%(PreprocessorDefinitions) @@ -165,6 +166,7 @@ EditAndContinue Cdecl 4804;4800;4018;4005;%(DisableSpecificWarnings) + true _DEBUG;%(PreprocessorDefinitions) @@ -220,7 +222,7 @@ ProgramDatabase Cdecl 4102;4005;4804;4018;4800;%(DisableSpecificWarnings) - + true NDEBUG;%(PreprocessorDefinitions) 0x0419 @@ -276,6 +278,7 @@ EditAndContinue Cdecl 4102;4804;4800;4018;%(DisableSpecificWarnings) + true _DEBUG;%(PreprocessorDefinitions) @@ -318,7 +321,6 @@ - @@ -333,7 +335,6 @@ - @@ -352,7 +353,6 @@ - @@ -363,9 +363,10 @@ + - + @@ -450,4 +451,4 @@ - \ No newline at end of file + diff --git a/idapython.vcxproj.filters b/idapython.vcxproj.filters index 9da6bb5..886433a 100644 --- a/idapython.vcxproj.filters +++ b/idapython.vcxproj.filters @@ -98,9 +98,6 @@ swig_i - - swig_i - swig_i @@ -152,9 +149,6 @@ autogen - - swig_i - swig_i @@ -212,9 +206,6 @@ pywraps - - pywraps - pywraps @@ -248,13 +239,16 @@ swig_i + + swig_i + swig_i swig_i - + swig_i @@ -317,4 +311,4 @@ {b581ad45-b3f6-4591-baf0-306dab4e0590} - \ No newline at end of file + diff --git a/makefile b/makefile index 49b23fe..44b12a0 100644 --- a/makefile +++ b/makefile @@ -19,6 +19,13 @@ PROC=python API_CONTENTS=api_contents.txt PYDOC_INJECTIONS=pydoc_injections.txt +BC695=1 +ifdef BC695 + BC695_CFLAGS=-DBC695 + BC695_SWIGFLAGS=-DBC695 + BC695_DEPLOYFLAGS=--bc695 +endif + IDA_INCLUDE=../../include DIST=$(F)dist @@ -26,6 +33,8 @@ DIST=$(F)dist ifdef __NT__ SYSNAME=win MSRUNTIME=/MD + MSCLOPTS=/nologo + MSLDOPTS=/nologo endif ifdef __LINUX__ @@ -67,6 +76,11 @@ else endif endif +ifdef __NT__ + IDA_CMD=TVHEADLESS=1 $(R)idaw$(X64SUFF)$(SUFF64) +else + IDA_CMD=TVHEADLESS=1 $(R)idal$(X64SUFF)$(SUFF64) +endif ST_SWIG=$(F)swig ifeq ($(OUT_OF_TREE_BUILD),) @@ -86,10 +100,14 @@ 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 +DEPLOY_IDC_BC695_PY=$(DEPLOY_PYDIR)/idc_bc695.py +DEPLOY_IDAAPI_PY=$(DEPLOY_PYDIR)/idaapi.py +DEPLOY_IDADEX_PY=$(DEPLOY_PYDIR)/idadex.py ifeq ($(OUT_OF_TREE_BUILD),) TEST_IDC=test_idc DBLZIP_SCRIPT:=$(abspath ../../ida/build/dblzip.py) PKGBIN_SCRIPT:=$(abspath ../../ida/build/pkgbin.py) + IDC_BC695_IDC_SOURCE?=$(DEPLOY_PYDIR)/../idc/idc.idc endif # @@ -129,11 +147,12 @@ 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_MODNAME) 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) +MNAMES_0=allins range auto bytes dbg diskio entry enum expr fixup +MNAMES_1=fpro frame funcs gdl graph $(HEXRAYS_MODNAME) ida idaapi idd idp +MNAMES_2=kernwin lines loader moves nalt name netnode offset pro problems +MNAMES_3=registry search segment segregs strlist struct typeinf tryblks ua xref +MNAMES_EXTRA=idc +MODULES_NAMES=$(MNAMES_0) $(MNAMES_1) $(MNAMES_2) $(MNAMES_3) $(MNAMES_EXTRA) MODULES=$(MODULES_NAMES:%=$(F)_ida_%$(MODULE_SFX)) DEPLOYED_MODULES=$(MODULES_NAMES:%=$(DEPLOY_LIBDIR)/_ida_%$(MODULE_SFX)) @@ -154,7 +173,12 @@ ifdef __NT__ BINARY_LINKOPTS=/def:$(IDAPYTHON_IMPLIB_DEF) /IMPLIB:$(IDAPYTHON_IMPLIB_PATH) RESFILES=$(IDAPYTHON_IMPLIB_DEF) else - MODULE_LINKIDA=-L$(R) $(LINKIDA) $(BINARY) + ifeq ($(OUT_OF_TREE_BUILD),) + LIBIDA_DIR:=$(R) + else + LIBIDA_DIR:=$(L) + endif + MODULE_LINKIDA=-L$(LIBIDA_DIR) $(LINKIDA) $(BINARY) endif all: objdir pyfiles config $(DEPLOYED_MODULES) $(PYTHON_MODULES) $(ST_API_CONTENTS) $(IDAPYTHON_IMPLIB) $(ST_PYDOC_INJECTIONS) #$(TEST_IDC) @@ -193,6 +217,8 @@ else # unix/mac PRECOMPILED_COPY=$(R)$(LIBPYTHON_NAME) $(R)$(LIBPYTHON_NAME) $(patsubst precompiled/%,$(DEPLOY_PYDIR)/%,$(PYLIBFILES)) endif endif + PYTHON_LDFLAGS_RPATH_MAIN=-Wl,-rpath='$$ORIGIN/..' + PYTHON_LDFLAGS_RPATH_MODULE=-Wl,-rpath='$$$$ORIGIN/../../..' else MACDEFINES=-DMACSDKVER=$(MACSDKVER) endif @@ -208,21 +234,29 @@ endif # 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) +SWIGFLAGS=$(_SWIGFLAGS) -Itools/typemaps-supplement $(SWIGINCLUDES) $(DEF_TYPE_TABLE) -D__IDP__ -D__PLUGIN__ $(BC695_SWIGFLAGS) + +ADDITIONAL_LIBS=$(PYTHON_LDFLAGS) $(PYTHON_LDFLAGS_RPATH_MAIN) +ifdef __LINUX__ + ADDITIONAL_LIBS_MODULE=$(PYTHON_LDFLAGS) $(PYTHON_LDFLAGS_RPATH_MODULE) +else + ADDITIONAL_LIBS_MODULE=$(ADDITIONAL_LIBS) +endif -ADDITIONAL_LIBS=$(PYTHON_LDFLAGS) PUBTREE_DIR=$(F)/public_tree .PHONY: pyfiles docs $(TEST_IDC) staging_dirs clean check_python package public_tree config: $(C)python.cfg -clean: +clean:: rm -rf obj/ -pyfiles: $(DEPLOY_PYDIR)/idautils.py \ - $(DEPLOY_PYDIR)/idc.py \ - $(DEPLOY_PYDIR)/init.py \ - $(DEPLOY_PYDIR)/idaapi.py +pyfiles: $(DEPLOY_IDAUTILS_PY) \ + $(DEPLOY_IDC_PY) \ + $(DEPLOY_IDC_BC695_PY) \ + $(DEPLOY_INIT_PY) \ + $(DEPLOY_IDAAPI_PY) \ + $(DEPLOY_IDADEX_PY) GENHOOKS=tools/genhooks/ _SPACE := $(null) # @@ -237,9 +271,15 @@ $(DEPLOY_IDC_PY): python/idc.py | $(DEPLOY_PYDIR) $(DEPLOY_IDAUTILS_PY): python/idautils.py | $(DEPLOY_PYDIR) $(CP) $? $@ -$(DEPLOY_PYDIR)/idaapi.py: python/idaapi.py tools/genidaapi.py | $(DEPLOY_PYDIR) +$(DEPLOY_IDC_BC695_PY): $(IDC_BC695_IDC_SOURCE) python/idc.py tools/gen_idc_bc695.py | $(DEPLOY_PYDIR) + $(PYTHON) tools/gen_idc_bc695.py --idc $(IDC_BC695_IDC_SOURCE) --output $@ + +$(DEPLOY_PYDIR)/idaapi.py: python/idaapi.py tools/genidaapi.py $(PYTHON_MODULES) | $(DEPLOY_PYDIR) $(PYTHON) tools/genidaapi.py -i $< -o $@ -m $(subst $(_SPACE),$(_COMMA),$(MODULES_NAMES)) +$(DEPLOY_PYDIR)/idadex.py: python/idadex.py | $(DEPLOY_PYDIR) + $(CP) $? $@ + $(DEPLOY_PYDIR)/lib/%: precompiled/lib/% mkdir -p $(@D) cp $< $@ @@ -299,7 +339,7 @@ $(ST_PYW)/py_idp.hpp: pywraps/py_idp.hpp \ $(GENHOOKS)recipe_idphooks.py \ $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ - -x $(ST_PARSED_HEADERS)/structprocessor__t.xml -e idp_notify \ + -x $(ST_PARSED_HEADERS)/structprocessor__t.xml -e event_t \ -r int -n 0 -m hookgenIDP -q "processor_t::" \ -R $(GENHOOKS)recipe_idphooks.py $(ST_PYW)/py_idp_idbhooks.hpp: pywraps/py_idp_idbhooks.hpp \ @@ -330,11 +370,24 @@ $(ST_PYW)/py_kernwin.hpp: pywraps/py_kernwin.hpp \ -r void -n 0 -m hookgenUI \ -R $(GENHOOKS)recipe_uihooks.py \ -d "ui_dbg_,ui_obsolete" -D "ui:" -s "ui_" +$(ST_PYW)/py_kernwin_viewhooks.hpp: pywraps/py_kernwin_viewhooks.hpp \ + $(I)kernwin.hpp \ + $(GENHOOKS)genhooks.py \ + $(GENHOOKS)recipe_viewhooks.py \ + $(GENERATED_HEADERS) | staging_dirs $(SDK_SOURCES) + @$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ + -x $(ST_PARSED_HEADERS)/kernwin_8hpp.xml -e view_notification_t \ + -r void -n 0 -m hookgenVIEW \ + -R $(GENHOOKS)recipe_viewhooks.py + 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__ \ + -DVER_MAJOR="1" -DVER_MINOR="7" -DVER_PATCH="0" -D__IDP__ -D__PLUGIN__ \ -DUSE_STANDARD_FILE_FUNCTIONS $(IDAPYTHON_CFLAGS) \ - $(SWITCH64) $(SWITCHX64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) $(DEF_TYPE_TABLE) + $(SWITCH64) $(SWITCHX64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) $(DEF_TYPE_TABLE) $(BC695_CFLAGS) +ifdef TESTABLE_BUILD + CFLAGS+=-DTESTABLE_BUILD +endif ST_SWIG_HEADER=$(ST_SWIG)/header.i $(ST_SWIG)/header.i: tools/deploy/header.i.in tools/genswigheader.py $(ST_SDK_TARGETS) | staging_dirs @@ -342,24 +395,39 @@ $(ST_SWIG)/header.i: tools/deploy/header.i.in tools/genswigheader.py $(ST_SDK_TA ifdef __NT__ +PATCH_DIRECTORS_SCRIPT:=tools/patch_directors_cc.py + $(IDAPYTHON_IMPLIB_DEF): $(IDAPYTHON_IMPLIB_DEF_IN) sed s/%LIBNAME%/$(notdir $(BINARY))/ < $? > $@ + ifdef __X64__ + sed -i s/%PLUGIN_DATA_EXP%// $@ + else + sed -i s/%PLUGIN_DATA_EXP%/'PLUGIN DATA'/ $@ + endif +endif + +ifdef __X64__ + PATCH_CODEGEN_X64_OPTS=--apply-valist-patches 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 +# (e.g., segregs.i imports range.i). Declare the list of such dependencies here # so they will be picked by the auto-generated rules. -SWIG_IFACE_bytes=area +SWIG_IFACE_bytes=range SWIG_IFACE_dbg=idd -SWIG_IFACE_frame=area -SWIG_IFACE_funcs=area -SWIG_IFACE_gdl=area +SWIG_IFACE_frame=range +SWIG_IFACE_funcs=range +SWIG_IFACE_gdl=range SWIG_IFACE_hexrays=typeinf -SWIG_IFACE_segment=area -SWIG_IFACE_srarea=area +SWIG_IFACE_segment=range +SWIG_IFACE_segregs=range SWIG_IFACE_typeinf=idp +SWIG_IFACE_tryblks=range + +MODULE_LIFECYCLE_hexrays=--lifecycle-aware +MODULE_LIFECYCLE_bytes=--lifecycle-aware define make-module-rules @@ -384,19 +452,24 @@ define make-module-rules # 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)) + $(PYTHON) tools/deploy.py \ + --pywraps $(ST_PYW) \ + --template $$(subst $(F),,$$@) \ + --output $$@ \ + --module $$(subst .i,,$$(notdir $$@)) \ + $(MODULE_LIFECYCLE_$1) \ + $(BC695_DEPLOYFLAGS) \ + --interface-dependencies=$(subst $(_SPACE),$(_COMMA),$(SWIG_IFACE_$1)) # obj/x86_linux_gcc/wrappers/X.cpp - $(ST_WRAP)/$1.cpp: $(ST_SWIG)/$1.i tools/patch_codegen.py + $(ST_WRAP)/$1.cpp: $(ST_SWIG)/$1.i tools/patch_codegen.py makefile $(PATCH_DIRECTORS_SCRIPT) tools/chkapi.py $(SWIG) -modern $(WITH_HEXRAYS) -python -threads -c++ -shadow \ $(MACDEFINES) -D__GNUC__ $(SWIGFLAGS) $(SWITCH64) $(SWITCHX64) -I$(ST_SWIG) \ -outdir $(ST_WRAP) -o $$@ -I$(ST_SDK) $$< @$(PYTHON) tools/patch_constants.py --file $(ST_WRAP)/$1.cpp - ifdef __X64__ - $(PYTHON) tools/patch_codegen.py --file $(ST_WRAP)/$1.cpp --patches tools/patch_codegen/$1.py - endif + $(PYTHON) tools/patch_codegen.py $(PATCH_CODEGEN_X64_OPTS) --file $(ST_WRAP)/$1.cpp --patches tools/patch_codegen/$1.py ifdef __NT__ - @$(PYTHON) tools/patch_directors_cc.py --file $(ST_WRAP)/$1.h + $(PYTHON) $(PATCH_DIRECTORS_SCRIPT) --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, @@ -409,7 +482,7 @@ define make-module-rules ifdef __CODE_CHECKER__ touch $$@ else - $(CXX) $(CFLAGS) $(MSRUNTIME) $(NORTTI) -DPLUGIN_SUBMODULE -DSWIG_DIRECTOR_NORTTI -c $(OBJSW)$$@ $(ST_WRAP)/$1.cpp + $(CXX) $(CFLAGS) $(MSRUNTIME) $(MSCLOPTS) $(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) @@ -419,10 +492,10 @@ define make-module-rules # 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) + ifdef __NT__ # we repeat /map switch with the explicit file name because @F does not work inside macro + $(LINKER) $(LINKOPTS) /map:$(F)_ida_$1$(MODULE_SFX).map $(MSLDOPTS) /OPT:ICF /OPT:REF /INCREMENTAL:NO /STUB:../../plugins/stub /OUT:$$@ $$< $(IDALIB) user32.lib $(ADDITIONAL_LIBS_MODULE) $(IDAPYTHON_IMPLIB_PATH) else - $(CCL) $(OUTDLL) $(OUTSW)$$@ $$< $(MODULE_LINKIDA) $(PLUGIN_SCRIPT) $(ADDITIONAL_LIBS) $(STDLIBS) + $(CCL) $(OUTDLL) $(OUTSW)$$@ $$< $(MODULE_LINKIDA) $(PLUGIN_SCRIPT) $(ADDITIONAL_LIBS_MODULE) $(STDLIBS) endif # ../../bin/x86_linux_gcc/python/lib/lib-dynload/ida_32/_ida_X.so @@ -434,10 +507,12 @@ $(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) ifeq ($(OUT_OF_TREE_BUILD),) + ifdef BC695 # turn off comparison when bw-compat is off, or api_contents will differ @(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)) + endif endif # Check that doc injection is stable @@ -471,15 +546,6 @@ 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 -# the idapython). -ifdef __NT__ - IDA_CMD=TVHEADLESS=1 $(R)idaw$(X64SUFF)$(SUFF64) -else - IDA_CMD=TVHEADLESS=1 $(R)idal$(X64SUFF)$(SUFF64) -endif - # the demo version of ida does not have the -B command line option ifeq ($(OUT_OF_TREE_BUILD),) ISDEMO=$(shell grep "define DEMO$$" $(IDA_INCLUDE)/commerc.hpp) @@ -488,6 +554,9 @@ ifeq ($(OUT_OF_TREE_BUILD),) endif endif +# Test that all functions that are present in ftable.cpp +# are present in idc.py (and therefore made available by +# the idapython). $(TEST_IDC): $(F)idctest.log $(F)idctest.log: $(RS)idc/idc.idc | $(BINARY) pyfiles $(PRECOMPILED_COPY) ifneq ($(wildcard ../../tests),) @@ -523,9 +592,9 @@ echo_modules: @echo $(MODULES_NAMES) # MAKEDEP dependency list ------------------ -$(F)python$(O) : $(I)area.hpp $(I)bitrange.hpp $(I)bytes.hpp \ +$(F)python$(O) : $(I)range.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)ida.hpp $(I)idp.hpp $(I)config.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 pywraps.cpp | $(ST_SDK_TARGETS) diff --git a/out_of_tree/parsed_notifications.zip b/out_of_tree/parsed_notifications.zip index 847d62bb7fd18c13426c17b53f47ef239977ae05..2cec574c2e2fd86c52717404e859dfce3d56a932 100644 GIT binary patch delta 554438 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

ES|3=H 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�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 delta 548210 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

kZVv@Xmj!J6kjtL-;kdOxN1p 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

q!{2Kok}YyFzS`&Ii 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≶I;tmQ9=NpKUDWL$MdfbuKJI#Hqc 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%0Avxy{~`liUpdW+{I}KL=E7{-}>svK&GB>(teh<5P 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%0DpN6TyXAM?SIE%ZFQouHn%;3SD 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

=vn85FrES}`ZQHi({L;4V%u3s~ZJU*LrMpg# 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

i=~~Ne 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 diff --git a/pydoc_injections.txt b/pydoc_injections.txt index 74e4b0a..e735b3c 100644 --- a/pydoc_injections.txt +++ b/pydoc_injections.txt @@ -1,19 +1,16 @@ ### Processing allins.i -### Processing area.i +### Processing range.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_many_bytes_ex -fix_fun: found info for get_ascii_contents2 -fix_fun: found info for get_ascii_contents +fix_fun: found info for next_that +fix_fun: found info for get_bytes +fix_fun: found info for get_bytes_and_mask +fix_fun: found info for get_strlit_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 @@ -42,13 +39,11 @@ 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 @@ -90,12 +85,11 @@ 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_reg_first_sreg +fix_fun: found info for ph_get_reg_last_sreg 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_reg_code_sreg +fix_fun: found info for ph_get_reg_data_sreg 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 @@ -106,42 +100,29 @@ 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 +fix_method: found info for ev_ana_insn +fix_method: found info for ev_emu_insn +fix_method: found info for ev_out_insn +fix_method: found info for ev_out_operand +fix_method: found info for ev_undefine +fix_method: found info for ev_rename +fix_method: found info for ev_is_sane_insn +fix_method: found info for ev_is_call_insn +fix_method: found info for ev_is_ret_insn +fix_method: found info for ev_may_be_func +fix_method: found info for ev_assemble ### 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 get_highlight fix_fun: found info for msg -fix_fun: found info for asktext +fix_fun: found info for ask_text +fix_fun: found info for ask_str 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 @@ -151,18 +132,18 @@ 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 preprocess_action +fix_method: found info for postprocess_action 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_method: found info for populating_widget_popup +fix_method: found info for finish_populating_widget_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 +fix_fun: found info for read_selection ### Processing lines.i fix_fun: found info for tag_remove fix_fun: found info for set_user_defined_prefix @@ -174,42 +155,36 @@ 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 get_switch_info +fix_fun: found info for set_switch_info +fix_fun: found info for del_switch_info fix_fun: found info for enum_import_names ### Processing name.i ### Processing netnode.i ### Processing offset.i ### Processing pro.i -### Processing queue.i +fix_fun: found info for str2user +### Processing problems.i ### Processing registry.i ### Processing search.i ### Processing segment.i -### Processing srarea.i +### Processing segregs.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 get_arg_addrs 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 tryblks.i ### 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 +### Processing idc.i diff --git a/python.cfg b/python.cfg index b2a1857..28af8c0 100644 --- a/python.cfg +++ b/python.cfg @@ -12,3 +12,7 @@ SCRIPT_TIMEOUT = 3 // Should the plugin automatically load a backward-compatibility-providing // 'idaapi' wrapper module? AUTOIMPORT_COMPAT_IDAAPI = YES + +// Should the plugin automatically load a 6.95 bw-compatibility layer? +AUTOIMPORT_COMPAT_IDA695 = YES + diff --git a/python.cpp b/python.cpp index a02a6a2..eb55d7b 100644 --- a/python.cpp +++ b/python.cpp @@ -58,9 +58,9 @@ static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data"; // enum script_run_when { - run_on_db_open = 0, // run script after opening database (default) - run_on_ui_ready = 1, // run script when UI is ready - run_on_init = 2, // run script immediately on plugin load (shortly after IDA starts) + RUN_ON_DB_OPEN = 0, // run script after opening database (default) + RUN_ON_UI_READY = 1, // run script when UI is ready + RUN_ON_INIT = 2, // run script immediately on plugin load (shortly after IDA starts) }; //------------------------------------------------------------------------- @@ -79,7 +79,7 @@ static char g_idapython_dir[QMAXPATH]; // extern "C" void init_idaapi(void); // Plugin run() callback -void idaapi run(int arg); +bool idaapi run(size_t); //------------------------------------------------------------------------- // This is a simple tracing code for debugging purposes. @@ -116,13 +116,14 @@ 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 bool g_autoimport_compat_ida695 = true; // 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) +// gen_disasm_text(dtext, ea, ea + 4, False) // --- // This script will call the processor module's out/outop functions in // order to generate the text. If the processor module behaves @@ -157,11 +158,13 @@ struct execution_t int timeout; uint32 steps_before_action; bool waitdialog_shown; + bool interruptible_state; execution_t() : timeout(2), steps_before_action(0), - waitdialog_shown(false) + waitdialog_shown(false), + interruptible_state(true) { reset_steps(); } @@ -172,6 +175,7 @@ struct execution_t void stop_tracking(); void sync_to_present_time(); void maybe_hide_waitdialog(); + void set_interruptible(bool intr) { interruptible_state = intr; } static int on_trace(PyObject *obj, _frame *frame, int what, PyObject *arg); }; static execution_t execution; @@ -192,7 +196,7 @@ void execution_t::reset_steps() // E.g., imagine the following loop: // --- // while True: - // gen_disasm_text(ea, ea + 4, dtext, False) + // gen_disasm_text(dtext, ea, ea + 4, 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' @@ -248,7 +252,7 @@ void execution_t::maybe_hide_waitdialog() 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 ) + if ( entries.empty() || timeout <= 0 || !interruptible_state ) return false; const exec_entry_t &last = entries.back(); bool can = (now - last.etime) > timeout; @@ -276,7 +280,7 @@ int execution_t::on_trace(PyObject *obj, _frame *frame, int what, PyObject *arg) int(execution.waitdialog_shown)); if ( execution.waitdialog_shown ) { - if ( wasBreak() ) + if ( user_cancelled() ) { LEXEC("on_trace()::INTERRUPTING\n"); PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted"); @@ -326,6 +330,12 @@ struct new_execution_t } }; +//------------------------------------------------------------------------- +void ida_export set_interruptible_state(bool interruptible) +{ + execution.set_interruptible(interruptible); +} + //------------------------------------------------------------------------- //lint -esym(714,disable_script_timeout) Symbol not referenced idaman void ida_export disable_script_timeout() @@ -353,20 +363,17 @@ idaman int ida_export set_script_timeout(int timeout) //------------------------------------------------------------------------ // Return a formatted error or just print it to the console static void handle_python_error( - char *errbuf, - size_t errbufsize, - bool clear_error = true) + qstring *errbuf, + bool clear_error = true) { - if ( errbufsize > 0 && errbuf != NULL ) - errbuf[0] = '\0'; + if ( errbuf != NULL ) + errbuf->clear(); // No exception? if ( !PyErr_Occurred() ) return; - qstring s; - if ( PyW_GetError(&s, clear_error) && errbuf != NULL ) - qstrncpy(errbuf, s.c_str(), errbufsize); + PyW_GetError(errbuf, clear_error); } //------------------------------------------------------------------------ @@ -380,8 +387,8 @@ static PyObject *GetMainGlobals() //------------------------------------------------------------------------ static void PythonEvalOrExec( - const char *str, - const char *filename = "") + const char *str, + const char *filename = "") { // Compile as an expression PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -418,7 +425,7 @@ static void PythonEvalOrExec( newref_t py_result_utf8(PyUnicode_AsUTF8String(py_result.o)); ok = py_result_utf8 != NULL; if ( ok ) - umsg("%s\n", PyString_AS_STRING(py_result_utf8.o)); + msg("%s\n", PyString_AS_STRING(py_result_utf8.o)); } else { @@ -437,10 +444,9 @@ static void PythonEvalOrExec( //------------------------------------------------------------------------ // Executes a simple string -static bool idaapi IDAPython_extlang_run_statements( - const char *str, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_eval_snippet( + const char *str, + qstring *errbuf) { PYW_GIL_GET; PyObject *globals = GetMainGlobals(); @@ -451,7 +457,7 @@ static bool idaapi IDAPython_extlang_run_statements( } else { - errbuf[0] = '\0'; + errbuf->clear(); PyErr_Clear(); { new_execution_t exec; @@ -462,23 +468,22 @@ static bool idaapi IDAPython_extlang_run_statements( globals)); ok = result != NULL && !PyErr_Occurred(); if ( !ok ) - handle_python_error(errbuf, errbufsize); + handle_python_error(errbuf); } } - if ( !ok && errbuf[0] == '\0' ) - qstrncpy(errbuf, "internal error", errbufsize); + if ( !ok && errbuf->empty() ) + *errbuf = "internal error"; return ok; } //------------------------------------------------------------------------ // Simple Python statement runner function for IDC -static const char idc_runpythonstatement_args[] = { VT_STR2, 0 }; static error_t idaapi idc_runpythonstatement( - idc_value_t *argv, - idc_value_t *res) + idc_value_t *argv, + idc_value_t *res) { - char errbuf[MAXSTR]; - bool ok = IDAPython_extlang_run_statements(argv[0].c_str(), errbuf, sizeof(errbuf)); + qstring errbuf; + bool ok = IDAPython_extlang_eval_snippet(argv[0].c_str(), &errbuf); if ( ok ) res->set_long(0); @@ -487,6 +492,16 @@ static error_t idaapi idc_runpythonstatement( return eOk; } +static const char idc_runpythonstatement_args[] = { VT_STR, 0 }; +static const ext_idcfunc_t idc_runpythonstatement_desc = +{ + S_IDC_RUNPYTHON_STATEMENT, + idc_runpythonstatement, + idc_runpythonstatement_args, + NULL, + 0, + 0 +}; //-------------------------------------------------------------------------- static const cfgopt_t opts[] = @@ -495,6 +510,7 @@ static const cfgopt_t opts[] = 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), + cfgopt_t("AUTOIMPORT_COMPAT_IDA695", &g_autoimport_compat_ida695, true), }; //------------------------------------------------------------------------- @@ -548,7 +564,7 @@ static int PyRunFile(const char *FileName) char curdir[QMAXPATH]; // check if the current directory is accessible. if not, qgetcwd won't return qgetcwd(curdir, sizeof(curdir)); - if ( getdspace(curdir) == 0 ) + if ( get_free_disk_space(curdir) == 0 ) { warning("No free disk space on %s, python will not be available", curdir); return 0; @@ -581,27 +597,23 @@ static int PyRunFile(const char *FileName) // Execute Python statement(s) from an editor window void IDAPython_RunStatement(void) { - char statement[16 * MAXSTR]; + qstring qbuf; netnode history; // Get the existing or create a new netnode in the database history.create(S_IDAPYTHON_DATA_NODE); + history.getblob(&qbuf, 0, 'A'); - // Fetch the previous statement - size_t statement_size = sizeof(statement); - - if ( history.getblob(statement, &statement_size, 0, 'A') == NULL ) - statement[0] = '\0'; - - if ( asktext(sizeof(statement), statement, statement, "ACCEPT TABS\nEnter Python expressions") != NULL ) + if ( ask_text(&qbuf, 0, qbuf.c_str(), "ACCEPT TABS\nEnter Python expressions") ) { { + PYW_GIL_GET; new_execution_t exec; - PyRun_SimpleString(statement); + PyRun_SimpleString(qbuf.c_str()); } // Store the statement to the database - history.setblob(statement, strlen(statement) + 1, 0, 'A'); + history.setblob(qbuf.c_str(), qbuf.size(), 0, 'A'); } } @@ -609,17 +621,16 @@ void IDAPython_RunStatement(void) // Convert return value from Python to IDC or report about an error. // This function also decrements the reference "result" (python variable) static bool return_python_result( - idc_value_t *idc_result, - const ref_t &py_result, - char *errbuf, - size_t errbufsize) + idc_value_t *idc_result, + const ref_t &py_result, + qstring *errbuf) { - if ( errbufsize > 0 ) - errbuf[0] = '\0'; + if ( errbuf != NULL ) + errbuf->clear(); if ( py_result == NULL ) { - handle_python_error(errbuf, errbufsize); + handle_python_error(errbuf); return false; } @@ -628,8 +639,8 @@ static bool return_python_result( { idc_result->clear(); cvt = pyvar_to_idcvar(py_result, idc_result); - if ( cvt < CIP_OK ) - qsnprintf(errbuf, errbufsize, "ERROR: bad return value"); + if ( cvt < CIP_OK && errbuf != NULL ) + *errbuf = "ERROR: bad return value"; } return cvt >= CIP_OK; @@ -643,8 +654,7 @@ static bool return_python_result( // module reloading. static bool IDAPython_ExecFile( const char *FileName, - char *errbuf, - size_t errbufsz, + qstring *errbuf, const char *idaapi_script = S_IDAAPI_EXECSCRIPT, idc_value_t *second_res = NULL, bool want_tuple = false) @@ -653,7 +663,7 @@ static bool IDAPython_ExecFile( ref_t py_execscript(get_idaapi_attr(idaapi_script)); if ( py_execscript == NULL ) { - qsnprintf(errbuf, errbufsz, "Could not find %s.%s ?!", S_IDA_IDAAPI_MODNAME, idaapi_script); + errbuf->sprnt("Could not find %s.%s ?!", S_IDA_IDAAPI_MODNAME, idaapi_script); return false; } @@ -672,14 +682,11 @@ static bool IDAPython_ExecFile( // Failure at this point means the script was interrupted bool interrupted = false; - qstring err; - if ( PyW_GetError(&err) || py_ret == NULL ) + if ( PyW_GetError(errbuf) || py_ret == NULL ) { PyErr_Clear(); - if ( err.empty() ) - qstrncpy(errbuf, "Script interrupted", errbufsz); - else - qstrncpy(errbuf, err.c_str(), errbufsz); + if ( errbuf->empty() ) + *errbuf = "Script interrupted"; interrupted = true; } @@ -710,7 +717,7 @@ static bool IDAPython_ExecFile( if ( want_tuple ) { borref_t ret2_o(PyTuple_GetItem(py_ret.o, 1)); - ok = return_python_result(second_res, ret2_o, errbuf, errbufsz); + ok = return_python_result(second_res, ret2_o, errbuf); } else { @@ -719,7 +726,7 @@ static bool IDAPython_ExecFile( } else if ( PyString_Check(ret_o) ) { - qstrncpy(errbuf, PyString_AsString(ret_o), errbufsz); + *errbuf = PyString_AsString(ret_o); } else { @@ -733,14 +740,14 @@ static bool IDAPython_ExecFile( // Execute the Python script from the plugin static bool RunScript(const char *script) { - char errbuf[MAXSTR]; + qstring errbuf; bool ok; { new_execution_t exec; - ok = IDAPython_ExecFile(script, errbuf, sizeof(errbuf)); + ok = IDAPython_ExecFile(script, &errbuf); } if ( !ok ) - warning("IDAPython: error executing '%s':\n%s", script, errbuf); + warning("IDAPython: error executing '%s':\n%s", script, errbuf.c_str()); return ok; } @@ -751,11 +758,11 @@ static bool RunScript(const char *script) // parse_py_modname("modname.attrname", mod_buf, attr_buf) // It splits the full name into two parts. static bool parse_py_modname( - const char *full_name, - char *modname, - char *attrname, - size_t sz, - const char *defmod = S_IDA_IDAAPI_MODNAME) + const char *full_name, + char *modname, + char *attrname, + size_t sz, + const char *defmod = S_IDA_IDAAPI_MODNAME) { const char *p = strchr(full_name, '.'); if ( p == NULL ) @@ -773,18 +780,17 @@ static bool parse_py_modname( //------------------------------------------------------------------------- // Run callback for Python external language evaluator -bool idaapi IDAPython_extlang_run( - const char *name, - int nargs, - const idc_value_t args[], - idc_value_t *result, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_call_func( + idc_value_t *result, + const char *name, + const idc_value_t args[], + size_t nargs, + qstring *errbuf) { PYW_GIL_GET; // Try to extract module name (if any) from the funcname - char modname[MAXSTR] = {0}; - char funcname[MAXSTR] = {0}; + char modname[MAXSTR]; + char funcname[MAXSTR]; bool imported_module = parse_py_modname(name, modname, funcname, MAXSTR); bool ok = true; @@ -793,7 +799,7 @@ bool idaapi IDAPython_extlang_run( do { // Convert arguments to python - ok = pyw_convert_idc_args(args, nargs, pargs, false, errbuf, errbufsize); + ok = pyw_convert_idc_args(args, nargs, pargs, 0, errbuf); if ( !ok ) break; @@ -813,7 +819,7 @@ bool idaapi IDAPython_extlang_run( PyObject *func = PyDict_GetItemString(globals, funcname); if ( func == NULL ) { - qsnprintf(errbuf, errbufsize, "undefined function %s", name); + errbuf->sprnt("undefined function %s", name); ok = false; break; } @@ -827,7 +833,7 @@ bool idaapi IDAPython_extlang_run( pargs_ptrs.begin(), nargs, NULL, 0, NULL, 0, NULL)); - ok = return_python_result(result, py_res, errbuf, errbufsize); + ok = return_python_result(result, py_res, errbuf); } while ( false ); if ( imported_module ) @@ -849,32 +855,31 @@ static void wrap_in_function(qstring *out, const qstring &body, const char *name //------------------------------------------------------------------------- // Compile callback for Python external language evaluator -bool idaapi IDAPython_extlang_compile( - const char *name, - ea_t /*current_ea*/, - const char *expr, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_compile_expr( + const char *name, + ea_t /*current_ea*/, + const char *expr, + qstring *errbuf) { PYW_GIL_GET; PyObject *globals = GetMainGlobals(); - bool is_func = false; + bool isfunc = false; PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "", Py_eval_input); if ( code == NULL ) { // try compiling as a list of statements // wrap them into a function - handle_python_error(errbuf, errbufsize); + handle_python_error(errbuf); qstring func; wrap_in_function(&func, expr, name); code = (PyCodeObject *)Py_CompileString(func.c_str(), "", Py_file_input); if ( code == NULL ) { - handle_python_error(errbuf, errbufsize); + handle_python_error(errbuf); return false; } - is_func = true; + isfunc = true; } // Set the desired function name @@ -887,7 +892,7 @@ bool idaapi IDAPython_extlang_compile( if ( func == NULL ) { ERR: - handle_python_error(errbuf, errbufsize); + handle_python_error(errbuf); Py_XDECREF(code); return false; } @@ -898,44 +903,41 @@ ERR: if ( err ) goto ERR; - if ( is_func ) + if ( isfunc ) { - const idc_value_t args; idc_value_t result; - return IDAPython_extlang_run(name, 0, &args, &result, errbuf, errbufsize); + return IDAPython_extlang_call_func(&result, name, NULL, 0, errbuf); } return true; } //------------------------------------------------------------------------- // Compile callback for Python external language evaluator -bool idaapi IDAPython_extlang_compile_file( - const char *filename, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_compile_file( + const char *path, + qstring *errbuf) { PYW_GIL_GET; new_execution_t exec; - return IDAPython_ExecFile(filename, errbuf, errbufsize); + return IDAPython_ExecFile(path, errbuf); } //------------------------------------------------------------------------- // Load processor module callback for Python external language evaluator -static bool idaapi IDAPython_extlang_loadprocmod( - const char *filename, +static bool idaapi IDAPython_extlang_load_procmod( idc_value_t *procobj, - char *errbuf, - size_t errbufsize) + const char *path, + qstring *errbuf) { PYW_GIL_GET; bool ok; { new_execution_t exec; - ok = IDAPython_ExecFile(filename, errbuf, errbufsize, S_IDAAPI_LOADPROCMOD, procobj, true); + ok = IDAPython_ExecFile(path, errbuf, S_IDAAPI_LOADPROCMOD, procobj, true); } if ( ok && procobj->is_zero() ) { - errbuf[0] = '\0'; + errbuf->clear(); ok = false; } return ok; @@ -943,25 +945,24 @@ static bool idaapi IDAPython_extlang_loadprocmod( //------------------------------------------------------------------------- // Unload processor module callback for Python external language evaluator -static bool idaapi IDAPython_extlang_unloadprocmod( - const char *filename, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_unload_procmod( + const char *path, + qstring *errbuf) { PYW_GIL_GET; new_execution_t exec; - return IDAPython_ExecFile(filename, errbuf, errbufsize, S_IDAAPI_UNLOADPROCMOD); + return IDAPython_ExecFile(path, errbuf, S_IDAAPI_UNLOADPROCMOD); } //------------------------------------------------------------------------- // Create an object instance -bool idaapi IDAPython_extlang_create_object( - const char *name, // in: object class name - int nargs, // in: number of input arguments - const idc_value_t args[], // in: input arguments - idc_value_t *result, // out: created object or exception - char *errbuf, // out: error message if evaluation fails - size_t errbufsize) // in: size of the error buffer +//lint -e605 Increase in pointer capability +static bool idaapi IDAPython_extlang_create_object( + idc_value_t *result, // out: created object or exception + const char *name, // in: object class name + const idc_value_t args[], // in: input arguments + size_t nargs, // in: number of input arguments + qstring *errbuf) // out: error message if evaluation fails { PYW_GIL_GET; bool ok = false; @@ -969,34 +970,45 @@ bool idaapi IDAPython_extlang_create_object( do { // Parse the object name (to get the module and class name) - char modname[MAXSTR] = {0}; - char clsname[MAXSTR] = {0}; + char modname[MAXSTR]; + char clsname[MAXSTR]; parse_py_modname(name, modname, clsname, MAXSTR); // Get a reference to the module ref_t py_mod(PyW_TryImportModule(modname)); if ( py_mod == NULL ) { - qsnprintf(errbuf, errbufsize, "Could not import module '%s'!", modname); + errbuf->sprnt("Could not import module '%s'!", modname); break; } - // Get the class reference - ref_t py_cls(PyW_TryGetAttrString(py_mod.o, clsname)); - if ( py_cls == NULL ) + // If the class provides an wraper instantiator, use that + ref_t py_res; + if ( nargs == 1 && args[0].vtype == VT_PVOID ) + py_res = try_create_swig_wrapper(py_mod, clsname, args[0].pvoid); + if ( py_res != NULL ) { - qsnprintf(errbuf, errbufsize, "Could not find class type '%s'!", clsname); - break; + PyObject_SetAttrString(py_res.o, S_PY_IDCCVT_ID_ATTR, PyInt_FromLong(PY_ICID_OPAQUE)); } + else + { + // Get the class reference + ref_t py_cls(PyW_TryGetAttrString(py_mod.o, clsname)); + if ( py_cls == NULL ) + { + errbuf->sprnt("Could not find class type '%s'!", clsname); + break; + } - // Error during conversion? - ok = pyw_convert_idc_args(args, nargs, pargs, true, errbuf, errbufsize); - if ( !ok ) - break; + // Error during conversion? + ok = pyw_convert_idc_args(args, nargs, pargs, PYWCVTF_AS_TUPLE, errbuf); + if ( !ok ) + break; - // Call the constructor - newref_t py_res(PyObject_CallObject(py_cls.o, pargs.empty() ? NULL : pargs[0].o)); - ok = return_python_result(result, py_res, errbuf, errbufsize); + // Call the constructor + py_res = newref_t(PyObject_CallObject(py_cls.o, pargs.empty() ? NULL : pargs[0].o)); + } + ok = return_python_result(result, py_res, errbuf); } while ( false ); return ok; @@ -1004,10 +1016,10 @@ bool idaapi IDAPython_extlang_create_object( //------------------------------------------------------------------------- // Returns the attribute value of a given object from the global scope -bool idaapi IDAPython_extlang_get_attr( - const idc_value_t *obj, // in: object (may be NULL) - const char *attr, // in: attribute name - idc_value_t *result) +static bool idaapi IDAPython_extlang_get_attr( + idc_value_t *result, // out: result + const idc_value_t *obj, // in: object (may be NULL) + const char *attr) // in: attribute name { PYW_GIL_GET; int cvt = CIP_FAILED; @@ -1025,7 +1037,7 @@ bool idaapi IDAPython_extlang_get_attr( if ( obj != NULL ) { // (1) Get attribute from main module - if ( obj->vtype == VT_STR2 ) + if ( obj->vtype == VT_STR ) { py_obj = PyW_TryGetAttrString(py_mod.o, obj->c_str()); } @@ -1116,10 +1128,10 @@ bool idaapi IDAPython_extlang_get_attr( //------------------------------------------------------------------------- // Returns the attribute value of a given object from the global scope //lint -e{818} -bool idaapi IDAPython_extlang_set_attr( - idc_value_t *obj, // in: object name (may be NULL) - const char *attr, // in: attribute name - idc_value_t *value) +static bool idaapi IDAPython_extlang_set_attr( + idc_value_t *obj, // in: object name (may be NULL) + const char *attr, // in: attribute name + const idc_value_t &value) { PYW_GIL_GET; bool ok = false; @@ -1133,7 +1145,7 @@ bool idaapi IDAPython_extlang_set_attr( if ( obj != NULL ) { // Get the attribute reference (from just a name) - if ( obj->vtype == VT_STR2 ) + if ( obj->vtype == VT_STR ) { py_obj = PyW_TryGetAttrString(py_mod.o, obj->c_str()); } @@ -1154,7 +1166,7 @@ bool idaapi IDAPython_extlang_set_attr( } // Convert the value ref_t py_var; - int cvt = idcvar_to_pyvar(*value, &py_var); + int cvt = idcvar_to_pyvar(value, &py_var); if ( cvt >= CIP_OK ) { ok = PyObject_SetAttrString(py_obj.o, attr, py_var.o) != -1; @@ -1168,12 +1180,11 @@ bool idaapi IDAPython_extlang_set_attr( //------------------------------------------------------------------------- // Calculator callback for Python external language evaluator //lint -e{818} -bool idaapi IDAPython_extlang_calcexpr( - ea_t /*current_ea*/, - const char *expr, - idc_value_t *rv, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_eval_expr( + idc_value_t *rv, + ea_t /*current_ea*/, + const char *expr, + qstring *errbuf) { PYW_GIL_GET; PyObject *globals = GetMainGlobals(); @@ -1185,34 +1196,33 @@ bool idaapi IDAPython_extlang_calcexpr( new_execution_t exec; result = newref_t(PyRun_String(expr, Py_eval_input, globals, globals)); } - ok = return_python_result(rv, result, errbuf, errbufsize); + ok = return_python_result(rv, result, errbuf); } return ok; } //------------------------------------------------------------------------- -bool idaapi IDAPython_extlang_call_method( - const idc_value_t *idc_obj, - const char *method_name, - int nargs, - const idc_value_t args[], - idc_value_t *result, - char *errbuf, - size_t errbufsize) +static bool idaapi IDAPython_extlang_call_method( + idc_value_t *result, + const idc_value_t *idc_obj, + const char *method_name, + const idc_value_t args[], + size_t nargs, + qstring *errbuf) { PYW_GIL_GET; // Check for unsupported usage of call_method. // Mainly a method call requires an object and a method. if ( (idc_obj == NULL && method_name == NULL) || (idc_obj != NULL && method_name == NULL) ) { - qstrncpy(errbuf, "call_method does not support this operation", errbufsize); + *errbuf = "call_method does not support this operation"; return false; } // Behave like run() else if ( idc_obj == NULL && method_name != NULL ) { new_execution_t exec; - return IDAPython_extlang_run(method_name, nargs, args, result, errbuf, errbufsize); + return IDAPython_extlang_call_func(result, method_name, args, nargs, errbuf); } // Holds conversion status of input object @@ -1226,26 +1236,42 @@ bool idaapi IDAPython_extlang_call_method( obj_cvt = idcvar_to_pyvar(*idc_obj, &py_obj); if ( obj_cvt < CIP_OK ) { - qstrncpy(errbuf, "Failed to convert input object to Python value", errbufsize); + *errbuf = "Failed to convert input object to Python value"; break; } ref_t py_method(PyW_TryGetAttrString(py_obj.o, method_name)); if ( py_method == NULL || !PyCallable_Check(py_method.o) ) { - qsnprintf(errbuf, errbufsize, "The input object does not have a callable method called '%s'", method_name); + errbuf->sprnt("The input object does not have a callable method called '%s'", method_name); break; } // Convert arguments to python objects - ok = pyw_convert_idc_args(args, nargs, pargs, true, errbuf, errbufsize); + uint32 flags = PYWCVTF_AS_TUPLE; + // if we are running a ida_idaapi.plugin_t.run, we want the 'int64' + // to be converted to an unsigned python long + if ( streq(method_name, "run") ) + { + ref_t py_ida_idaapi_mod(PyW_TryImportModule(S_IDA_IDAAPI_MODNAME)); + if ( py_ida_idaapi_mod != NULL ) + { + ref_t py_plugin_t_cls(PyW_TryGetAttrString(py_ida_idaapi_mod.o, "plugin_t")); + if ( py_plugin_t_cls != NULL ) + { + if ( PyObject_IsInstance(py_obj.o, py_plugin_t_cls.o) ) + flags |= PYWCVTF_INT64_AS_UNSIGNED_PYLONG; + } + } + } + ok = pyw_convert_idc_args(args, nargs, pargs, flags, errbuf); if ( !ok ) break; { 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); + ok = return_python_result(result, py_res, errbuf); } } while ( false ); @@ -1285,24 +1311,25 @@ struct python_highlighter_t : public ida_syntax_highlighter_t }; static python_highlighter_t python_highlighter; -const extlang_t extlang_python = +extlang_t extlang_python = { - sizeof(extlang_t), - 0, - "Python", - IDAPython_extlang_compile, - IDAPython_extlang_run, - IDAPython_extlang_calcexpr, - IDAPython_extlang_compile_file, - "py", - IDAPython_extlang_create_object, - IDAPython_extlang_get_attr, - IDAPython_extlang_set_attr, - IDAPython_extlang_call_method, - IDAPython_extlang_run_statements, - IDAPython_extlang_loadprocmod, - IDAPython_extlang_unloadprocmod, - &python_highlighter + sizeof(extlang_t), + 0, // flags + 0, // refcnt + "Python", // name + "py", // filext + &python_highlighter, + IDAPython_extlang_compile_expr, + IDAPython_extlang_compile_file, + IDAPython_extlang_call_func, + IDAPython_extlang_eval_expr, + IDAPython_extlang_eval_snippet, + IDAPython_extlang_create_object, + IDAPython_extlang_get_attr, + IDAPython_extlang_set_attr, + IDAPython_extlang_call_method, + IDAPython_extlang_load_procmod, + IDAPython_extlang_unload_procmod, }; //------------------------------------------------------------------------- @@ -1367,11 +1394,11 @@ bool idaapi IDAPython_cli_execute_line(const char *line) //------------------------------------------------------------------------- bool idaapi IDAPYthon_cli_complete_line( - qstring *completion, - const char *prefix, - int n, - const char *line, - int x) + qstring *completion, + const char *prefix, + int n, + const char *line, + int x) { PYW_GIL_GET; @@ -1428,7 +1455,7 @@ void parse_plugin_options() const char *p = strchr(options, ';'); if ( p == NULL ) { - g_run_when = run_on_db_open; + g_run_when = RUN_ON_DB_OPEN; p = options; } else @@ -1452,7 +1479,7 @@ void convert_idc_args() { idc_value_t attr; char attr_name[20] = { "0" }; - for ( int i=1; VarGetAttr(idc_args, attr_name, &attr) == eOk; i++ ) + for ( int i=1; get_idcv_attr(&attr, idc_args, attr_name) == eOk; i++ ) { PyList_Insert(py_args.o, i, PyString_FromString(attr.c_str())); qsnprintf(attr_name, sizeof(attr_name), "%d", i); @@ -1465,9 +1492,16 @@ void convert_idc_args() PyObject_SetAttrString(py_mod.o, S_IDC_ARGS_VARNAME, py_args.o); } +#define DISPATCH_TO_MODULES(Method) \ + do \ + { \ + for ( size_t i = modules_callbacks.size(); i > 0; --i ) \ + modules_callbacks[i-1].Method(); \ + } while ( false ) + //------------------------------------------------------------------------ //lint -esym(715,va) Symbol not referenced -static int idaapi on_ui_notification(void *, int code, va_list) +static ssize_t idaapi on_ui_notification(void *, int code, va_list) { switch ( code ) { @@ -1488,7 +1522,7 @@ static int idaapi on_ui_notification(void *, int code, va_list) PYW_GIL_GET; // See above g_ui_ready = true; PyRun_SimpleString("print_banner()"); - if ( g_run_when == run_on_ui_ready ) + if ( g_run_when == RUN_ON_UI_READY ) RunScript(g_run_script); } break; @@ -1497,7 +1531,7 @@ static int idaapi on_ui_notification(void *, int code, va_list) { PYW_GIL_GET; // See above convert_idc_args(); - if ( g_run_when == run_on_db_open ) + if ( g_run_when == RUN_ON_DB_OPEN ) RunScript(g_run_script); } break; @@ -1510,15 +1544,16 @@ static int idaapi on_ui_notification(void *, int code, va_list) //------------------------------------------------------------------------- //lint -esym(526,til_clear_python_tinfo_t_instances) not defined -static int idaapi on_idp_notification(void *, int code, va_list) +static ssize_t idaapi on_idb_notification(void *, int code, va_list) { switch ( code ) { - case processor_t::closebase: + case idb_event::closebase: // The til machinery is about to garbage-collect: We must go // 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(); + DISPATCH_TO_MODULES(closebase); break; } return 0; @@ -1528,7 +1563,7 @@ static int idaapi on_idp_notification(void *, int code, va_list) //------------------------------------------------------------------------ // extern int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag); extern PyThreadState *_PyThreadState_Current; -static int idaapi ui_debug_handler_cb(void *, int code, va_list) +static ssize_t idaapi ui_debug_handler_cb(void *, int code, va_list) { // This hook gets called from the kernel, but its very point is to // make sure that we don't hold the GIL. Thus: No PYW_GIL_GET here! @@ -1635,7 +1670,7 @@ bool IDAPython_Init(void) if ( !check_python_dir() ) return false; - char tmp[QMAXPATH]; + char path[QMAXPATH]; #ifdef __LINUX__ // Export symbols from libpython to resolve imported module deps // use the standard soname: libpython2.7.so.1.0 @@ -1673,9 +1708,14 @@ bool IDAPython_Init(void) read_config_file("python.cfg", opts, qnumber(opts)); if ( g_alert_auto_scripts ) { - if ( pywraps_check_autoscripts(tmp, sizeof(tmp)) - && askyn_c(0, "HIDECANCEL\nTITLE IDAPython\nThe script '%s' was found in the current directory and will be automatically executed by Python.\n\n" - "Do you want to continue loading IDAPython?", tmp) <= 0 ) + if ( pywraps_check_autoscripts(path, sizeof(path)) + && ask_yn(ASKBTN_NO, + "HIDECANCEL\n" + "TITLE IDAPython\n" + "The script '%s' was found in the current directory\n" + "and will be automatically executed by Python.\n" + "\n" + "Do you want to continue loading IDAPython?", path) <= 0 ) { return false; } @@ -1730,14 +1770,14 @@ bool IDAPython_Init(void) #endif // Set IDAPYTHON_VERSION in Python - qsnprintf( - tmp, - sizeof(tmp), + qstring init_code; + init_code.sprnt( "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\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", + "IDAPYTHON_DYNLOAD_RELPATH = \"ida_%" FMT_Z "\"\n" + "IDAPYTHON_COMPAT_AUTOIMPORT_MODULES = %s\n" + "IDAPYTHON_COMPAT_695_API = %s\n", VER_MAJOR, VER_MINOR, VER_PATCH, @@ -1745,25 +1785,34 @@ bool IDAPython_Init(void) VER_SERIAL, g_remove_cwd_sys_path ? "True" : "False", idadir(NULL), -#ifdef __EA64__ - 64, + sizeof(ea_t)*8, + g_autoimport_compat_idaapi ? "True" : "False", +#ifdef BC695 + g_autoimport_compat_ida695 ? "True" : "False" #else - 32, + "False" #endif - g_autoimport_compat_idaapi ? "True" : "False"); - PyRun_SimpleString(tmp); + ); + + if ( PyRun_SimpleString(init_code.c_str()) != 0 ) + { + warning("IDAPython: error executing bootstrap code"); + return false; + } // Install extlang. Needs to be done before running init.py // in case it's calling idaapi.enable_extlang_python(1) install_extlang(&extlang_python); // Execute init.py (for Python side initialization) - qmakepath(tmp, MAXSTR, g_idapython_dir, S_INIT_PY, NULL); - if ( !PyRunFile(tmp) ) + qmakepath(path, MAXSTR, g_idapython_dir, S_INIT_PY, NULL); + if ( !PyRunFile(path) ) { + qstring errbuf; + // Try to fetch a one line error string. We must do it before printing // the traceback information. Make sure that the exception is not cleared - handle_python_error(tmp, sizeof(tmp), false); + handle_python_error(&errbuf, false); // Print the exception traceback PyRun_SimpleString("import traceback;traceback.print_exc();"); @@ -1771,7 +1820,7 @@ bool IDAPython_Init(void) warning("IDAPython: error executing " S_INIT_PY ":\n" "%s\n" "\n" - "Refer to the message window to see the full error log.", tmp); + "Refer to the message window to see the full error log.", errbuf.c_str()); remove_extlang(&extlang_python); return false; } @@ -1792,21 +1841,17 @@ bool IDAPython_Init(void) parse_plugin_options(); // Register a RunPythonStatement() function for IDC - set_idc_func_ex( - S_IDC_RUNPYTHON_STATEMENT, - idc_runpythonstatement, - idc_runpythonstatement_args, - 0); + add_idc_func(idc_runpythonstatement_desc); // A script specified on the command line is run - if ( g_run_when == run_on_init ) + if ( g_run_when == RUN_ON_INIT ) RunScript(g_run_script); #ifdef _DEBUG - hook_to_notification_point(HT_UI, ui_debug_handler_cb, NULL); + hook_to_notification_point(HT_UI, ui_debug_handler_cb); #endif - hook_to_notification_point(HT_UI, on_ui_notification, NULL); - hook_to_notification_point(HT_IDP, on_idp_notification, NULL); + hook_to_notification_point(HT_UI, on_ui_notification); + hook_to_notification_point(HT_IDB, on_idb_notification); // Enable the CLI by default enable_python_cli(true); @@ -1836,10 +1881,13 @@ void IDAPython_Term(void) PyGILState_Ensure(); } - unhook_from_notification_point(HT_IDP, on_idp_notification, NULL); - unhook_from_notification_point(HT_UI, on_ui_notification, NULL); + // Let all modules perform possible de-initialization + DISPATCH_TO_MODULES(term); + + unhook_from_notification_point(HT_IDB, on_idb_notification); + unhook_from_notification_point(HT_UI, on_ui_notification); #ifdef _DEBUG - unhook_from_notification_point(HT_UI, ui_debug_handler_cb, NULL); + unhook_from_notification_point(HT_UI, ui_debug_handler_cb); #endif // Notify about IDA closing @@ -1858,11 +1906,16 @@ void IDAPython_Term(void) deinit_pywraps(); // Uninstall IDC function - set_idc_func_ex(S_IDC_RUNPYTHON_STATEMENT, NULL, NULL, 0); + del_idc_func(idc_runpythonstatement_desc.name); // Shut the interpreter down Py_Finalize(); g_instance_initialized = false; + +#ifdef TESTABLE_BUILD + // Check that all hooks were unhooked + QASSERT(30509, hook_data_vec.empty()); +#endif } //------------------------------------------------------------------------- @@ -1884,7 +1937,7 @@ void idaapi term(void) //------------------------------------------------------------------------- // Plugin hotkey entry point -void idaapi run(int arg) +bool idaapi run(size_t arg) { try { @@ -1900,7 +1953,7 @@ void idaapi run(int arg) enable_extlang_python(false); break; default: - warning("IDAPython: unknown plugin argument %d", arg); + warning("IDAPython: unknown plugin argument %d", int(arg)); break; } } @@ -1910,6 +1963,7 @@ void idaapi run(int arg) IDAPython_Term(); IDAPython_Init(); } + return true; } //------------------------------------------------------------------------- diff --git a/python/idadex.py b/python/idadex.py new file mode 100644 index 0000000..dc97c92 --- /dev/null +++ b/python/idadex.py @@ -0,0 +1,428 @@ +#--------------------------------------------------------------------- +# IDAPython - Python plugin for Interactive Disassembler +# +# (c) The IDAPython Team +# +# All rights reserved. +# +# For detailed copyright information see the file COPYING in +# the root of the distribution archive. +#--------------------------------------------------------------------- +# +# dex.py - module to access DEX-file related information +# +#--------------------------------------------------------------------- +# pylint: disable=C0103, C0111, C0301, C0326, W0511, R0903 +import ctypes +import idaapi +import ida_idaapi +import ida_bytes + +uint8 = ctypes.c_ubyte +char = ctypes.c_char +uint32 = ctypes.c_uint +uint64 = ctypes.c_uint64 +uint16 = ctypes.c_ushort +ushort = uint16 +# __EA64__ is set if IDA is running in 64-bit mode +__EA64__ = ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL +ea_t = uint64 if __EA64__ else uint32 + +# parse a ctypes struct from byte data in str_ at 'off' +def get_struct(str_, off, struct): + s = struct() + slen = ctypes.sizeof(s) + bytebuf = str_[off:off+slen] + fit = min(len(bytebuf), slen) + if fit < slen: + raise Exception("can't read struct: %d bytes available but %d required" % (fit, slen)) + ctypes.memmove(ctypes.addressof(s), bytebuf, fit) + return s + +#--------------------------------------------------------------------------- +# This structure is used both for imported methods and locally defined ones +# +class dex_method(ctypes.LittleEndianStructure): + # flags + IS_LOCAL = 1 + HAS_CODE = 2 + _fields_ = [ + ("flags", uint32), # Class type where this method is defined + ("defaddr", ea_t), # Address in file where the "definiton" (DexMethodId) is stored + ("cname", uint32), # Class type where this method is defined + ("id", uint32), # Id of method; key to look up name + ("proto_ret", uint32), # Name of return type + ("proto_shorty", uint32), # 'shorty' parameter descirptor name + ("nparams", ushort), # No of parameters to method. May be >32 + ("proto_params",uint32*32), # Name of types for the first 32 parameters + ("access_flags", uint32), # Access flags + ("startAddr", ea_t), # Function start and end address + ("endAddr", ea_t), # + ("reg_total", ushort), # Registers total, parameters and out + ("reg_params", ushort), # + ("reg_out", ushort), # + ("catchHData", ea_t), # offset to methods catch handler data + ] + def is_local(self): + return (self.flags & dex_method.IS_LOCAL) != 0 + + +""" +struct dex_field +{ + uint32 ctype, name, type; + ea_t maddr; // Address used for xrefs. +}; + +""" +class dex_field(ctypes.LittleEndianStructure): + # flags + _fields_ = [ + ("ctype", uint32), # + ("name", uint32), # + ("type", uint32), # + ("maddr", ea_t), # Address used for xrefs. + ] + +""" +struct longname_director_t +{ + char zero; + netnode node; +}; +""" +class longname_director_t(ctypes.LittleEndianStructure): + # flags + _pack_ = 1 + _fields_ = [ + ("zero", uint8), # + ("node", ea_t), # netnode index with the actual string blob + ] + + +class Dex(object): + + # meta-data + HASHVAL_MAGIC = "version" # Interface version + HASHVAL_OPTIMIZED = "optimized" # 1 for optimized dex files, 0 - for others + HASHVAL_DEXVERSION = "dex_version" # DEX File version + + # The dex string table; lookup from string id# to values + STRTAB_TAB = 1 # Lookup string id => address + STRTAB_RTAB = 2 # Lookup address => id + + # fields + FIELDTAB_DESCR = 1 # Field id => struct dex_field + FIELDTAB_NAMEDATA = 2 # Field id => char data, field name + + # The dex method table; lookup method meta-data based on index + METHTAB_BEGIN = 1 # Method id => start address + METHTAB_RBEGIN = 2 # Start address => method id + METHTAB_DESCR = 3 # Method id => struct dex_method + METHTAB_NAMEDATA = 4 # Method id => char data, method name + METHTAB_NAMEORGDATA = 5 # Method id => char data, method name from dex file + METHTAB_NTAB = 6 # Method id => String id of method name + + # debug info representation + DEBINFO_LINEINFO = 1 # Line start EA => dex_lineinfo_t + + # Try/Catches + TRYTAB_TRYLIST = 3 # key=methodIdx, value= tryItem data + TRYTAB_HANDLERLIST = 4 # key=ea (handler start), value=list of typeIdx, handled types + TRYTAB_HANDLERTRYLIST = 5 # key=ea (handler start), value=list of tryItemIdx + + # Types + TYPETAB_TAB = 1 # Type ID => String ID + TYPETAB_STRDATA = 2 # Type ID => String data (possible user redefined) + TYPETAB_STRORGDATA = 3 # Type ID => Original String data + TYPETAB_EA = 4 # Type ID => ea + + #--------------------------------------------------------------------------- + def __init__(self): + self.nn_meta = idaapi.netnode("$ dex_meta") + self.nn_strtab = idaapi.netnode("$ dex_strtab") + self.nn_fieldtab = idaapi.netnode("$ dex_fields") + self.nn_methtab = idaapi.netnode("$ dex_methtab") + self.nn_debinfo = idaapi.netnode("$ dex_debinfo") + self.nn_trytab = idaapi.netnode("$ dex_tries") + self.nn_typetab = idaapi.netnode("$ dex_types") + + #--------------------------------------------------------------------------- + ACCESS_FLAGS = { + "public" : 0x00000001, + "private" : 0x00000002, + "protected" : 0x00000004, + "static" : 0x00000008, + "final" : 0x00000010, + "synchronized" : 0x00000020, + "volatile" : 0x00000040, + "bridge" : 0x00000040, + "transient" : 0x00000080, + "varargs" : 0x00000080, + "native" : 0x00000100, + "interface" : 0x00000200, + "abstract" : 0x00000400, + "strictfp" : 0x00000800, + "synthetic" : 0x00001000, + "annotation" : 0x00002000, + "enum" : 0x00004000, + "constructor" : 0x00010000, + "dsynchronized" : 0x00020000, } + + #--------------------------------------------------------------------------- + @staticmethod + def access_string(flags): + res = "" + for access_bit in ("synchronized", "synthetic", "public", + "private", "protected", "interface", + "abstract", "strictfp", "final", + "native", "static"): + if flags & Dex.ACCESS_FLAGS[access_bit] != 0: + res += " " + access_bit + return res[1:] if res else "" + + #--------------------------------------------------------------------------- + def get_string(self, string_idx): + addr = self.nn_strtab.altval(string_idx, Dex.STRTAB_TAB) + if addr is 0: + return None + length = ida_bytes.get_max_strlit_length(addr, STRTYPE_C, ida_bytes.ALOPT_IGNHEADS|ida_bytes.ALOPT_IGNPRINT) + return ida_bytes.get_strlit_contents(addr, length, STRTYPE_C) + + def get_method_idx(self, ea): + return self.nn_methtab.altval(ea, Dex.METHTAB_RBEGIN) + + def get_method(self, method_idx): + val = self.nn_methtab.supval(method_idx, Dex.METHTAB_DESCR) + if len(val) != ctypes.sizeof(dex_method): + print "bad data in METHTAB_DESCR for index 0x%X" % method_idx + return None + method = get_struct(val,0, dex_method) + return method + + #--------------------------------------------------------------------------- + @staticmethod + def get_string_by_index(node, idx, tag): + if idx is None: + return None + val = node.supval(idx, tag) + # check for long line + if len(val) == ctypes.sizeof(longname_director_t): + longname_director = get_struct(val, 0, longname_director_t) + if longname_director.zero == 0: + nn = idaapi.netnode(longname_director.node) + return nn.getblob(0, tag)[:-1] + if len(val) > 0: + return val[:-1] + return "" + + #--------------------------------------------------------------------------- + # Converts a single-char primitive type into its human-readable equivalent + PRIMITVE_TYPES = { + 'B': "byte", + 'C': "char", + 'D': "double", + 'F': "float", + 'I': "int", + 'J': "long", + 'S': "short", + 'V': "void", + 'Z': "boolean", + 'L': "ref" } + @staticmethod + def _primitive_type_label(typechar): + if typechar in Dex.PRIMITVE_TYPES: + return Dex.PRIMITVE_TYPES[typechar] + return "UNKNOWN" + + @staticmethod + def is_wide_type(typechar): + return typechar[0] == 'J' or typechar[0] == 'D' + + #--------------------------------------------------------------------------- + # Converts a type descriptor to human-readable "dotted" form. For + # example, "Ljava/lang/String;" becomes "java.lang.String", and + # "[I" becomes "int[]". Also converts '$' to '.', which means this + # form can't be converted back to a descriptor. + @staticmethod + def decorate_java_typename(desc): + target_len = len(desc) + offset = 0 + # strip leading [s; will be added to end + while target_len > 1 and desc[offset] == '[': + offset += 1 + target_len -= 1 + array_depth = offset + if target_len == 1: + # primitive type + desc = Dex._primitive_type_label(desc[offset]) + offset = 0 + target_len = len(desc) + else: + # account for leading 'L' and trailing ';' + if target_len >= 2 and desc[offset] == 'L' and desc[offset + target_len - 1] == ';': + target_len -= 2 + offset += 1 + # copy class name over + res = "" + for _i in range(0, target_len): + ch = desc[offset + _i] + res += '.' if ch == '/' else ch + # add the appropriate number of brackets for arrays + res += "[]"*array_depth + return res + + #--------------------------------------------------------------------------- + def get_type_string(self, type_idx): + return Dex.get_string_by_index(self.nn_typetab, type_idx, Dex.TYPETAB_STRDATA) + + def get_method_name(self, method_idx): + return Dex.get_string_by_index(self.nn_methtab, method_idx, Dex.METHTAB_NAMEDATA) + + def get_field_name(self, field_idx): + return Dex.get_string_by_index(self.nn_fieldtab, field_idx, Dex.FIELDTAB_NAMEDATA) + + def get_parameter_name(self, idx): + return self.get_string(idx) + + #--------------------------------------------------------------------------- + @staticmethod + def get_short_type_name(longname): + if not longname: + return "unknown" + deco = Dex.decorate_java_typename(longname) + if not deco: + return "unknown" + start = deco.rfind('.') + if start == -1: + start = 0 + else: + start += 1 + return deco[start:].replace('<', '_').replace('>', '_') + + @staticmethod + def get_full_type_name(longname): + if not longname: + return "unknown" + return Dex.decorate_java_typename(longname) + + #--------------------------------------------------------------------------- + def get_short_method_name(self, method): + res = Dex.get_short_type_name(self.get_type_string(method.cname)) + res += '.' + res += self.get_method_name(method.id) + res += '@' + res += self.get_string(method.proto_shorty) + return res + + def get_full_method_name(self, method): + res = Dex.get_full_type_name(self.get_type_string(method.proto_ret)) + res += ' ' + res += self.get_full_type_name(self.get_type_string(method.cname)) + res += '.' + res += self.get_method_name(method.id) + + def get_call_method_name(self, method): + shorty = self.get_string(method.proto_shorty) + res = Dex._primitive_type_label(shorty[0]) + res += ' ' + res += Dex.get_short_type_name(self.get_type_string(method.cname)) + res += '.' + res += self.get_method_name(method.id) + res += '(' + last_idx = len(shorty) - 1 + for s in range(1, last_idx + 1): + res += Dex._primitive_type_label(shorty[s]) + if s != last_idx: + res += ", " + res += ')' + return res + + def get_field(self, method_idx): + val = self.nn_fieldtab.supval(method_idx, Dex.FIELDTAB_DESCR) + if len(val) != ctypes.sizeof(dex_field): + print "bad data in FIELDTAB_DESCR for index 0x%X" % method_idx + return None + field = get_struct(val,0, dex_field) + return field + + #--------------------------------------------------------------------------- + def get_full_field_name(self, field_idx, field, field_name): + res = Dex.get_full_type_name(self.get_type_string(field.type)) + res += ' ' + res += Dex.get_full_type_name(self.get_type_string(field_idx)) + res += '.' + res += field_name if field_name else self.get_field_name(field_idx) + return res + + #--------------------------------------------------------------------------- + def get_short_field_name(self, field_idx, field, field_name): + res = Dex.get_short_type_name(self.get_type_string(field.ctype)) + res += '_' + res += field_name if field_name else self.get_field_name(field_idx) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + dex = Dex() + # reproduce IDA function header + f = idaapi.get_func(here()) + if not f: + print "ERROR: must be in a function!" + exit(1) + + func_start_ea = f.start_ea + methno = dex.get_method_idx(func_start_ea) + func_method = dex.get_method(methno) + if func_method is None: + print "ERROR: Missing method info" + exit(1) + out = "" + # Return type + out += Dex.access_string(func_method.access_flags) + " " + method_proto = dex.get_type_string(func_method.proto_ret) + if method_proto: + out += Dex.get_full_type_name(method_proto) + else: + out += "%x" % func_method.proto_ret + out += ' ' + # Class name + method_classnm = dex.get_type_string(func_method.cname) + if method_classnm: + out += Dex.get_full_type_name(method_classnm) + else: + out += "%x" % func_method.cname + out += '.' + # Method name + method_name = dex.get_method_name(methno) + if method_name: + out += method_name + else: + out += "%x" % methno + # Method parameters + if func_method.nparams == 0: + print out + "()" + else: + print out + "(" + out = "" + maxp = min(func_method.nparams, 32) + start_reg = func_method.reg_total - func_method.reg_params + if func_method.access_flags & Dex.ACCESS_FLAGS["static"] == 0: + start_reg += 1 + for i in range(0, maxp): + ptype = dex.get_type_string(func_method.proto_params[i]) + + out = " %s " % dex.get_full_type_name(ptype) + regbuf = "v%u" % start_reg + start_reg += 1 + r = idaapi.find_regvar(f, f.start_ea, regbuf) + if r is None: + out += regbuf + if Dex.is_wide_type(ptype): + out += ':' + regbuf = "v%u" % start_reg + start_reg += 1 + else: + out += r.user + out += ')' if i + 1 == maxp else ',' + print out diff --git a/python/idautils.py b/python/idautils.py index 0e6e700..222569e 100644 --- a/python/idautils.py +++ b/python/idautils.py @@ -56,7 +56,7 @@ def CodeRefsTo(ea, flow): Example:: - for ref in CodeRefsTo(ScreenEA(), 1): + for ref in CodeRefsTo(get_screen_ea(), 1): print ref """ if flow == 1: @@ -77,7 +77,7 @@ def CodeRefsFrom(ea, flow): Example:: - for ref in CodeRefsFrom(ScreenEA(), 1): + for ref in CodeRefsFrom(get_screen_ea(), 1): print ref """ if flow == 1: @@ -96,7 +96,7 @@ def DataRefsTo(ea): Example:: - for ref in DataRefsTo(ScreenEA()): + for ref in DataRefsTo(get_screen_ea()): print ref """ return refs(ea, ida_xref.get_first_dref_to, ida_xref.get_next_dref_to) @@ -112,7 +112,7 @@ def DataRefsFrom(ea): Example:: - for ref in DataRefsFrom(ScreenEA()): + for ref in DataRefsFrom(get_screen_ea()): print ref """ return refs(ea, ida_xref.get_first_dref_from, ida_xref.get_next_dref_from) @@ -193,24 +193,24 @@ def XrefsTo(ea, flags=0): def Threads(): """Returns all thread IDs""" - for i in xrange(0, idc.GetThreadQty()): - yield idc.GetThreadId(i) + for i in xrange(0, idc.get_thread_qty()): + yield idc.getn_thread(i) def Heads(start=None, end=None): """ Get a list of heads (instructions or data) - @param start: start address (default: inf.minEA) - @param end: end address (default: inf.maxEA) + @param start: start address (default: inf.min_ea) + @param end: end address (default: inf.max_ea) @return: list of heads between start and end """ - if not start: start = ida_ida.cvar.inf.minEA - if not end: end = ida_ida.cvar.inf.maxEA + if not start: start = ida_ida.cvar.inf.min_ea + if not end: end = ida_ida.cvar.inf.max_ea ea = start - if not idc.isHead(idc.GetFlags(ea)): + if not idc.is_head(ida_bytes.get_flags(ea)): ea = ida_bytes.next_head(ea, end) while ea != ida_idaapi.BADADDR: yield ea @@ -221,8 +221,8 @@ def Functions(start=None, end=None): """ Get a list of functions - @param start: start address (default: inf.minEA) - @param end: end address (default: inf.maxEA) + @param start: start address (default: inf.min_ea) + @param end: end address (default: inf.max_ea) @return: list of heads between start and end @@ -231,19 +231,19 @@ 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 = ida_ida.cvar.inf.minEA - if not end: end = ida_ida.cvar.inf.maxEA + if not start: start = ida_ida.cvar.inf.min_ea + if not end: end = ida_ida.cvar.inf.max_ea # find first function head chunk in the range chunk = ida_funcs.get_fchunk(start) if not chunk: 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) + while chunk and chunk.start_ea < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: + chunk = ida_funcs.get_next_fchunk(chunk.start_ea) func = chunk - while func and func.startEA < end: - startea = func.startEA + while func and func.start_ea < end: + startea = func.start_ea yield startea func = ida_funcs.get_next_func(startea) @@ -261,7 +261,7 @@ def Chunks(start): status = func_iter.main() while status: chunk = func_iter.chunk() - yield (chunk.startEA, chunk.endEA) + yield (chunk.start_ea, chunk.end_ea) status = func_iter.next() @@ -297,7 +297,7 @@ def Segments(): for n in xrange(ida_segment.get_segm_qty()): seg = ida_segment.getnseg(n) if seg: - yield seg.startEA + yield seg.start_ea def Entries(): @@ -338,11 +338,11 @@ def Structs(): @return: List of tuples (idx, sid, name) """ - idx = idc.GetFirstStrucIdx() + idx = idc.get_first_struc_idx() while idx != ida_idaapi.BADADDR: - sid = idc.GetStrucId(idx) - yield (idx, sid, idc.GetStrucName(sid)) - idx = idc.GetNextStrucIdx(idx) + sid = idc.get_struc_by_idx(idx) + yield (idx, sid, idc.get_struc_name(sid)) + idx = idc.get_next_struc_idx(idx) def StructMembers(sid): @@ -358,14 +358,14 @@ def StructMembers(sid): @note: This will not return 'holes' in structures/stack frames; it only returns defined structure members. """ - m = idc.GetFirstMember(sid) + m = idc.get_first_member(sid) if m == -1: raise Exception("No structure with ID: 0x%x" % sid) while (m != ida_idaapi.BADADDR): - name = idc.GetMemberName(sid, m) + name = idc.get_member_name(sid, m) if name: - yield (m, name, idc.GetMemberSize(sid, m)) - m = idc.GetStrucNextOff(sid, m) + yield (m, name, idc.get_member_size(sid, m)) + m = idc.get_next_offset(sid, m) def DecodePrecedingInstruction(ea): @@ -376,12 +376,9 @@ def DecodePrecedingInstruction(ea): @return: (None or the decode instruction, farref) farref will contain 'true' if followed an xref, false otherwise """ - prev_addr, farref = ida_ua.decode_preceding_insn(ea) - if prev_addr == ida_idaapi.BADADDR: - return (None, False) - else: - return (ida_ua.cmd.copy(), farref) - + insn = ida_ua.insn_t() + prev_addr, farref = ida_ua.decode_preceding_insn(insn, ea) + return (insn, farref) if prev_addr != ida_idaapi.BADADDR else (None, False) def DecodePreviousInstruction(ea): @@ -391,11 +388,9 @@ def DecodePreviousInstruction(ea): @param ea: address to decode @return: None or a new insn_t instance """ - prev_addr = ida_ua.decode_prev_insn(ea) - if prev_addr == ida_idaapi.BADADDR: - return None - - return ida_ua.cmd.copy() + insn = ida_ua.insn_t() + prev_addr = ida_ua.decode_prev_insn(insn, ea) + return insn if prev_addr != ida_idaapi.BADADDR else None def DecodeInstruction(ea): @@ -405,11 +400,9 @@ def DecodeInstruction(ea): @param ea: address to decode @return: None or a new insn_t instance """ - inslen = ida_ua.decode_insn(ea) - if inslen == 0: - return None - - return ida_ua.cmd.copy() + insn = ida_ua.insn_t() + inslen = ida_ua.decode_insn(insn, ea) + return insn if inslen > 0 else None def GetDataList(ea, count, itemsize=1): @@ -421,7 +414,7 @@ def GetDataList(ea, count, itemsize=1): elif itemsize == 2: getdata = ida_bytes.get_word elif itemsize == 4: - getdata = ida_bytes.get_long + getdata = ida_bytes.get_dword elif itemsize == 8: getdata = ida_bytes.get_qword else: @@ -445,7 +438,7 @@ def PutDataList(ea, datalist, itemsize=1): if itemsize == 2: putdata = ida_bytes.patch_word if itemsize == 4: - putdata = ida_bytes.patch_long + putdata = ida_bytes.patch_dword assert putdata, "Invalid data size! Must be 1, 2 or 4" @@ -474,19 +467,21 @@ def GetInputFileMD5(): @return: MD5 string or None on error """ - return idc.GetInputMD5() + return idc.retrieve_input_file_md5() class Strings(object): """ - Allows iterating over the string list. The set of strings will not be modified. - , unless asked explicitly at setup()-time.. + Allows iterating over the string list. The set of strings will not be + modified, unless asked explicitly at setup()-time. This string list also + is used by the "String window" so it may be changed when this window is + updated. Example: s = Strings() for i in s: - print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.type, str(i)) + print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.strtype, str(i)) """ class StringItem(object): @@ -494,34 +489,19 @@ class Strings(object): Class representing each string item. """ def __init__(self, si): - self.ea = si.ea + self.ea = si.ea """String ea""" - self.type = si.type - """string type (ASCSTR_xxxxx)""" + self.strtype = si.type + """string type (STRTYPE_xxxxx)""" self.length = si.length """string length""" def is_1_byte_encoding(self): - 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 [ida_nalt.ASCSTR_UTF16, ida_nalt.ASCSTR_ULEN2, ida_nalt.ASCSTR_ULEN4] - - def is_4_bytes_encoding(self): - return (self.type & 7) == ida_nalt.ASCSTR_UTF32 + return ida_nalt.get_strtype_bpu(self.strtype) == 1 def _toseq(self, as_unicode): - if self.is_2_bytes_encoding(): - conv = ida_bytes.ACFOPT_UTF16 - pyenc = "utf-16" - elif self.is_4_bytes_encoding(): - conv = ida_bytes.ACFOPT_UTF8 - pyenc = "utf-8" - else: - conv = ida_bytes.ACFOPT_ASCII - pyenc = 'ascii' - strbytes = ida_bytes.get_ascii_contents2(self.ea, self.length, self.type, conv) - return unicode(strbytes, pyenc, 'replace') if as_unicode else strbytes + strbytes = ida_bytes.get_strlit_contents(self.ea, self.length, self.strtype) + return unicode(strbytes, "UTF-8", 'replace') if as_unicode else strbytes def __str__(self): return self._toseq(False) @@ -529,25 +509,9 @@ class Strings(object): def __unicode__(self): return self._toseq(True) - - STR_C = 0x0001 - """C-style ASCII string""" - STR_PASCAL = 0x0002 - """Pascal-style ASCII string (length byte)""" - STR_LEN2 = 0x0004 - """Pascal-style, length is 2 bytes""" - STR_UNICODE = 0x0008 - """Unicode string""" - STR_LEN4 = 0x0010 - """Pascal-style, length is 4 bytes""" - STR_ULEN2 = 0x0020 - """Pascal-style Unicode, length is 2 bytes""" - STR_ULEN4 = 0x0040 - """Pascal-style Unicode, length is 4 bytes""" - def clear_cache(self): """Clears the strings list cache""" - self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache + ida_strlist.clear_strlist() def __init__(self, default_setup = False): """ @@ -559,54 +523,38 @@ class Strings(object): if default_setup: self.setup() else: - self.refresh() + # restore saved options + ida_strlist.get_strlist_options() + self.refresh() - self._si = ida_strlist.string_info_t() + self._si = ida_strlist.string_info_t() - def refresh(self, ea1=None, ea2=None): + + def refresh(self): """Refreshes the strings list""" - if ea1 is None: - ea1 = ida_ida.cvar.inf.minEA - if ea2 is None: - ea2 = ida_ida.cvar.inf.maxEA - - ida_strlist.refresh_strlist(ea1, ea2) + ida_strlist.build_strlist() self.size = ida_strlist.get_strlist_qty() def setup(self, - strtypes = STR_C, + strtypes = [ida_nalt.STRTYPE_C], minlen = 5, only_7bit = True, ignore_instructions = False, - ea1 = None, - ea2 = None, display_only_existing_strings = False): - if ea1 is None: - ea1 = ida_ida.cvar.inf.minEA - - if ea2 is None: - ea2 = ida_ida.cvar.inf.maxEA - - t = ida_strlist.strwinsetup_t() + t = ida_strlist.get_strlist_options() 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 - ida_strlist.set_strlist_options(t) - - # Automatically refreshes self.refresh() def _get_item(self, index): - if not ida_strlist.get_strlist_item(index, self._si): + if not ida_strlist.get_strlist_item(self._si, index): return None - else: - return Strings.StringItem(self._si) + return Strings.StringItem(self._si) def __iter__(self): @@ -627,7 +575,7 @@ def GetIdbDir(): This function returns directory path of the current IDB database """ - return os.path.dirname(ida_loader.cvar.database_idb) + os.sep + return os.path.dirname(ida_loader.get_path(ida_loader.PATH_TYPE_IDB)) + os.sep # ----------------------------------------------------------------------- def GetRegisterList(): @@ -653,7 +601,7 @@ def _Assemble(ea, line): seg = ida_segment.getseg(ea) if not seg: return (False, "No segment at ea") - ip = ea - (ida_segment.ask_selector(seg.sel) << 4) + ip = ea - (ida_segment.sel2para(seg.sel) << 4) buf = ida_idp.AssembleLine(ea, seg.sel, ip, seg.bitness, line) if not buf: return (False, "Assembler failed: " + line) @@ -674,9 +622,9 @@ def Assemble(ea, line): @param ea: start address @return: (False, "Error message") or (True, asm_buf) or (True, [asm_buf1, asm_buf2, asm_buf3]) """ - old_batch = idc.Batch(1) + old_batch = idc.batch(1) ret = _Assemble(ea, line) - idc.Batch(old_batch) + idc.batch(old_batch) return ret def _copy_obj(src, dest, skip_list = None): @@ -711,21 +659,21 @@ class _reg_dtyp_t(object): This class describes a register's number and dtyp. The equal operator is overloaded so that two instances can be tested for equality """ - def __init__(self, reg, dtyp): - self.reg = reg - self.dtyp = dtyp + def __init__(self, reg, dtype): + self.reg = reg + self.dtype = dtype def __eq__(self, other): - return (self.reg == other.reg) and (self.dtyp == other.dtyp) + return (self.reg == other.reg) and (self.dtype == other.dtype) # ----------------------------------------------------------------------- class _procregs(object): """Utility class allowing the users to identify registers in a decoded instruction""" def __getattr__(self, attr): ri = ida_idp.reg_info_t() - if not ida_idp.parse_reg_name(attr, ri): + if not ida_idp.parse_reg_name(ri, attr): raise AttributeError() - r = _reg_dtyp_t(ri.reg, ord(ida_ua.get_dtyp_by_size(ri.size))) + r = _reg_dtyp_t(ri.reg, ida_ua.get_dtype_by_size(ri.size)) self.__dict__[attr] = r return r @@ -735,14 +683,14 @@ class _procregs(object): # ----------------------------------------------------------------------- class _cpu(object): - "Simple wrapper around GetRegValue/SetRegValue" + "Simple wrapper around get_reg_value/set_reg_value" def __getattr__(self, name): #print "cpu.get(%s)" % name - return idc.GetRegValue(name) + return idc.get_reg_value(name) def __setattr__(self, name, value): #print "cpu.set(%s)" % name - return idc.SetRegValue(value, name) + return idc.set_reg_value(value, name) # -------------------------------------------------------------------------- diff --git a/python/idc.py b/python/idc.py index ed9edc9..6d3183f 100644 --- a/python/idc.py +++ b/python/idc.py @@ -20,9 +20,7 @@ IDC compatibility module This file contains IDA built-in function declarations and internal bit definitions. Each byte of the program has 32-bit flags (low 8 bits keep -the byte value). These 32 bits are used in GetFlags/SetFlags functions. -You may freely examine these bits using GetFlags() but the use of the -SetFlags() function is strongly discouraged. +the byte value). These 32 bits are used in get_full_flags/get_flags functions. This file is subject to change without any notice. Future versions of IDA may use other definitions. @@ -40,6 +38,7 @@ import ida_frame import ida_funcs import ida_gdl import ida_ida +import ida_idc import ida_bytes import ida_idd import ida_idp @@ -54,7 +53,7 @@ import ida_offset import ida_pro import ida_search import ida_segment -import ida_srarea +import ida_segregs import ida_struct import ida_typeinf import ida_ua @@ -67,7 +66,9 @@ import re import struct import time import types +import sys +__X64__ = sys.maxsize > 0xFFFFFFFF __EA64__ = ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL WORDMASK = 0xFFFFFFFFFFFFFFFF if __EA64__ else 0xFFFFFFFF class DeprecatedIDCError(Exception): @@ -109,7 +110,7 @@ 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()) +# Flag bit definitions (for get_full_flags()) # MS_VAL = ida_bytes.MS_VAL # Mask for byte value FF_IVL = ida_bytes.FF_IVL # Byte has value ? @@ -117,9 +118,9 @@ 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. -def hasValue(F): return ((F & FF_IVL) != 0) # any defined value? +def has_value(F): return ((F & FF_IVL) != 0) # any defined value? -def byteValue(F): +def byte_value(F): """ Get byte value from flags Get value of byte provided that the byte is initialized. @@ -128,9 +129,9 @@ def byteValue(F): return (F & MS_VAL) -def isLoaded(ea): +def is_loaded(ea): """Is the byte initialized?""" - return hasValue(GetFlags(ea)) # any defined value? + return has_value(get_full_flags(ea)) # any defined value? MS_CLS = ida_bytes.MS_CLS # Mask for typing FF_CODE = ida_bytes.FF_CODE # Code ? @@ -138,11 +139,11 @@ 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? -def isTail(F): return ((F & MS_CLS) == FF_TAIL) # is tail byte? -def isUnknown(F): return ((F & MS_CLS) == FF_UNK) # is unexplored byte? -def isHead(F): return ((F & FF_DATA) != 0) # is start of code/data? +def is_code(F): return ((F & MS_CLS) == FF_CODE) # is code byte? +def is_data(F): return ((F & MS_CLS) == FF_DATA) # is data byte? +def is_tail(F): return ((F & MS_CLS) == FF_TAIL) # is tail byte? +def is_unknown(F): return ((F & MS_CLS) == FF_UNK) # is unexplored byte? +def is_head(F): return ((F & FF_DATA) != 0) # is start of code/data? # # Common bits @@ -154,11 +155,9 @@ 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) -def isVar(F): return ((F & FF_VAR ) != 0) +def is_flow(F): return ((F & FF_FLOW) != 0) def isExtra(F): return ((F & FF_LINE) != 0) def isRef(F): return ((F & FF_REF) != 0) def hasName(F): return ((F & FF_NAME) != 0) @@ -196,8 +195,8 @@ FF_1STK = ida_bytes.FF_1STK # Stack variable? # 'is the 1st (or 2nd) operand of instruction or data of the given type'? # Please note that data items use only the 1st operand type (is...0) -def isDefArg0(F): return ((F & MS_0TYPE) != FF_0VOID) -def isDefArg1(F): return ((F & MS_1TYPE) != FF_1VOID) +def is_defarg0(F): return ((F & MS_0TYPE) != FF_0VOID) +def is_defarg1(F): return ((F & MS_1TYPE) != FF_1VOID) def isDec0(F): return ((F & MS_0TYPE) == FF_0NUMD) def isDec1(F): return ((F & MS_1TYPE) == FF_1NUMD) def isHex0(F): return ((F & MS_0TYPE) == FF_0NUMH) @@ -206,20 +205,20 @@ def isOct0(F): return ((F & MS_0TYPE) == FF_0NUMO) def isOct1(F): return ((F & MS_1TYPE) == FF_1NUMO) def isBin0(F): return ((F & MS_0TYPE) == FF_0NUMB) def isBin1(F): return ((F & MS_1TYPE) == FF_1NUMB) -def isOff0(F): return ((F & MS_0TYPE) == FF_0OFF) -def isOff1(F): return ((F & MS_1TYPE) == FF_1OFF) -def isChar0(F): return ((F & MS_0TYPE) == FF_0CHAR) -def isChar1(F): return ((F & MS_1TYPE) == FF_1CHAR) -def isSeg0(F): return ((F & MS_0TYPE) == FF_0SEG) -def isSeg1(F): return ((F & MS_1TYPE) == FF_1SEG) -def isEnum0(F): return ((F & MS_0TYPE) == FF_0ENUM) -def isEnum1(F): return ((F & MS_1TYPE) == FF_1ENUM) -def isFop0(F): return ((F & MS_0TYPE) == FF_0FOP) -def isFop1(F): return ((F & MS_1TYPE) == FF_1FOP) -def isStroff0(F): return ((F & MS_0TYPE) == FF_0STRO) -def isStroff1(F): return ((F & MS_1TYPE) == FF_1STRO) -def isStkvar0(F): return ((F & MS_0TYPE) == FF_0STK) -def isStkvar1(F): return ((F & MS_1TYPE) == FF_1STK) +def is_off0(F): return ((F & MS_0TYPE) == FF_0OFF) +def is_off1(F): return ((F & MS_1TYPE) == FF_1OFF) +def is_char0(F): return ((F & MS_0TYPE) == FF_0CHAR) +def is_char1(F): return ((F & MS_1TYPE) == FF_1CHAR) +def is_seg0(F): return ((F & MS_0TYPE) == FF_0SEG) +def is_seg1(F): return ((F & MS_1TYPE) == FF_1SEG) +def is_enum0(F): return ((F & MS_0TYPE) == FF_0ENUM) +def is_enum1(F): return ((F & MS_1TYPE) == FF_1ENUM) +def is_manual0(F): return ((F & MS_0TYPE) == FF_0FOP) +def is_manual1(F): return ((F & MS_1TYPE) == FF_1FOP) +def is_stroff0(F): return ((F & MS_0TYPE) == FF_0STRO) +def is_stroff1(F): return ((F & MS_1TYPE) == FF_1STRO) +def is_stkvar0(F): return ((F & MS_0TYPE) == FF_0STK) +def is_stkvar1(F): return ((F & MS_1TYPE) == FF_1STK) # # Bits for DATA bytes @@ -228,29 +227,29 @@ DT_TYPE = ida_bytes.DT_TYPE & 0xFFFFFFFF # Mask for DATA typing 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_DWORD = ida_bytes.FF_DWORD & 0xFFFFFFFF # dword +FF_QWORD = ida_bytes.FF_QWORD & 0xFFFFFFFF # qword +FF_TBYTE = ida_bytes.FF_TBYTE & 0xFFFFFFFF # tbyte +FF_STRLIT = ida_bytes.FF_STRLIT & 0xFFFFFFFF # ASCII ? +FF_STRUCT = ida_bytes.FF_STRUCT & 0xFFFFFFFF # Struct ? +FF_OWORD = ida_bytes.FF_OWORD & 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) -def isDwrd(F): return (isData(F) and (F & DT_TYPE) == FF_DWRD) -def isQwrd(F): return (isData(F) and (F & DT_TYPE) == FF_QWRD) -def isOwrd(F): return (isData(F) and (F & DT_TYPE) == FF_OWRD) -def isTbyt(F): return (isData(F) and (F & DT_TYPE) == FF_TBYT) -def isFloat(F): return (isData(F) and (F & DT_TYPE) == FF_FLOAT) -def isDouble(F): return (isData(F) and (F & DT_TYPE) == FF_DOUBLE) -def isPackReal(F): return (isData(F) and (F & DT_TYPE) == FF_PACKREAL) -def isASCII(F): return (isData(F) and (F & DT_TYPE) == FF_ASCI) -def isStruct(F): return (isData(F) and (F & DT_TYPE) == FF_STRU) -def isAlign(F): return (isData(F) and (F & DT_TYPE) == FF_ALIGN) +def is_byte(F): return (is_data(F) and (F & DT_TYPE) == FF_BYTE) +def is_word(F): return (is_data(F) and (F & DT_TYPE) == FF_WORD) +def is_dword(F): return (is_data(F) and (F & DT_TYPE) == FF_DWORD) +def is_qword(F): return (is_data(F) and (F & DT_TYPE) == FF_QWORD) +def is_oword(F): return (is_data(F) and (F & DT_TYPE) == FF_OWORD) +def is_tbyte(F): return (is_data(F) and (F & DT_TYPE) == FF_TBYTE) +def is_float(F): return (is_data(F) and (F & DT_TYPE) == FF_FLOAT) +def is_double(F): return (is_data(F) and (F & DT_TYPE) == FF_DOUBLE) +def is_pack_real(F): return (is_data(F) and (F & DT_TYPE) == FF_PACKREAL) +def is_strlit(F): return (is_data(F) and (F & DT_TYPE) == FF_STRLIT) +def is_struct(F): return (is_data(F) and (F & DT_TYPE) == FF_STRUCT) +def is_align(F): return (is_data(F) and (F & DT_TYPE) == FF_ALIGN) # # Bits for CODE bytes @@ -287,14 +286,14 @@ NEF_FLAT = ida_loader.NEF_FLAT # Autocreated FLAT group (PE) # ---------------------------------------------------------------------------- # M I S C E L L A N E O U S # ---------------------------------------------------------------------------- -def IsString(var): raise NotImplementedError, "this function is not needed in Python" -def IsLong(var): raise NotImplementedError, "this function is not needed in Python" -def IsFloat(var): raise NotImplementedError, "this function is not needed in Python" -def IsFunc(var): raise NotImplementedError, "this function is not needed in Python" -def IsPvoid(var): raise NotImplementedError, "this function is not needed in Python" -def IsInt64(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_string(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_long(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_float(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_func(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_pvoid(var): raise NotImplementedError, "this function is not needed in Python" +def value_is_int64(var): raise NotImplementedError, "this function is not needed in Python" -def MK_FP(seg, off): +def to_ea(seg, off): """ Return value of expression: ((seg<<4) + off) """ @@ -374,13 +373,13 @@ def rotate_word(x, count): return rotate_left(x, count, 16, 0) def rotate_byte(x, count): return rotate_left(x, count, 8, 0) -# AddHotkey return codes +# add_idc_hotkey return codes IDCHK_OK = 0 # ok IDCHK_ARG = -1 # bad argument(s) IDCHK_KEY = -2 # bad hotkey name IDCHK_MAX = -3 # too many IDC hotkeys -def AddHotkey(hotkey, idcfunc): +def add_idc_hotkey(hotkey, idcfunc): """ Add hotkey for IDC function @@ -392,7 +391,7 @@ def AddHotkey(hotkey, idcfunc): return ida_kernwin.add_idc_hotkey(hotkey, idcfunc) -def DelHotkey(hotkey): +def del_idc_hotkey(hotkey): """ Delete IDC function hotkey @@ -401,7 +400,7 @@ def DelHotkey(hotkey): return ida_kernwin.del_idc_hotkey(hotkey) -def Jump(ea): +def jumpto(ea): """ Move cursor to the specifed linear address @@ -410,7 +409,7 @@ def Jump(ea): return ida_kernwin.jumpto(ea) -def Wait(): +def auto_wait(): """ Process all entries in the autoanalysis queue Wait for the end of autoanalysis @@ -418,35 +417,10 @@ def Wait(): @note: This function will suspend execution of the calling script till the autoanalysis queue is empty. """ - return ida_auto.autoWait() + return ida_auto.auto_wait() -def CompileEx(input, isfile): - """ - Compile an IDC script - - The input should not contain functions that are - currently executing - otherwise the behaviour of the replaced - functions is undefined. - - @param input: if isfile != 0, then this is the name of file to compile - otherwise it holds the text to compile - @param isfile: specify if 'input' holds a filename or the expression itself - - @return: 0 - ok, otherwise it returns an error message - """ - if isfile: - res = ida_expr.Compile(input) - else: - res = ida_expr.CompileLine(input) - - if res: - return res - else: - return 0 - - -def Eval(expr): +def eval_idc(expr): """ Evaluate an IDC expression @@ -459,32 +433,30 @@ def Eval(expr): """ rv = ida_expr.idc_value_t() - err = ida_expr.calc_idc_expr(BADADDR, expr, rv) + err = ida_expr.eval_idc_expr(rv, BADADDR, expr) if err: return "IDC_FAILURE: "+err else: - if rv.vtype == '\x01': # VT_STR - return rv.str - elif rv.vtype == '\x02': # long + if rv.vtype == '\x02': # long return rv.num - elif rv.vtype == '\x07': # VT_STR2 + elif rv.vtype == '\x07': # VT_STR return rv.c_str() else: - raise NotImplementedError, "Eval() supports only expressions returning strings or longs" + raise NotImplementedError, "eval_idc() supports only expressions returning strings or longs" def EVAL_FAILURE(code): """ - Check the result of Eval() for evaluation failures + Check the result of eval_idc() for evaluation failures - @param code: result of Eval() + @param code: result of eval_idc() @return: True if there was an evaluation error """ return type(code) == types.StringType and code.startswith("IDC_FAILURE: ") -def SaveBase(idbname, flags=0): +def save_database(idbname, flags=0): """ Save current database to the specified idb file @@ -493,25 +465,21 @@ def SaveBase(idbname, flags=0): @param flags: combination of ida_loader.DBFL_... bits or 0 """ if len(idbname) == 0: - idbname = GetIdbPath() - saveflags = ida_loader.cvar.database_flags + idbname = get_idb_path() 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 + res = ida_loader.save_database_ex(idbname, flags & mask) return res DBFL_BAK = ida_loader.DBFL_BAK # for compatiblity with older versions, eventually delete this -def ValidateNames(): +def validate_idb_names(): """ check consistency of IDB name records @return: number of inconsistent name records """ return ida_nalt.validate_idb_names() -def Exit(code): +def qexit(code): """ Stop execution of IDC program, close the database and exit to OS @@ -522,7 +490,7 @@ def Exit(code): ida_pro.qexit(code) -def Exec(command): +def call_system(command): """ Execute an OS command. @@ -539,9 +507,9 @@ def Exec(command): return os.system(command) -def Sleep(milliseconds): +def qsleep(milliseconds): """ - Sleep the specified number of milliseconds + qsleep the specified number of milliseconds This function suspends IDA for the specified amount of time @param milliseconds: time to sleep @@ -549,7 +517,7 @@ def Sleep(milliseconds): time.sleep(float(milliseconds)/1000) -def RunPlugin(name, arg): +def load_and_run_plugin(name, arg): """ Load and run a plugin @@ -561,7 +529,7 @@ def RunPlugin(name, arg): return ida_loader.load_and_run_plugin(name, arg) -def ApplySig(name): +def plan_to_apply_idasgn(name): """ Load (plan to apply) a FLIRT signature file @@ -577,15 +545,15 @@ def ApplySig(name): #---------------------------------------------------------------------------- -def DeleteAll(): +def delete_all_segments(): """ Delete all segments, instructions, comments, i.e. everything except values of bytes. """ - ea = ida_ida.cvar.inf.minEA + ea = ida_ida.cvar.inf.min_ea # Brute-force nuke all info from all the heads - while ea != BADADDR and ea <= ida_ida.cvar.inf.maxEA: + while ea != BADADDR and ea <= ida_ida.cvar.inf.max_ea: ida_name.del_local_name(ea) ida_name.del_global_name(ea) func = ida_funcs.get_func(ea) @@ -593,17 +561,17 @@ def DeleteAll(): 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) + ida_bytes.del_hidden_range(ea) seg = ida_segment.getseg(ea) if seg: 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) + ida_segment.del_segm(ea, ida_segment.SEGMOD_KEEP | ida_segment.SEGMOD_SILENT) - ea = ida_bytes.next_head(ea, ida_ida.cvar.inf.maxEA) + ea = ida_bytes.next_head(ea, ida_ida.cvar.inf.max_ea) -def MakeCode(ea): +def create_insn(ea): """ Create an instruction at the specified address @@ -616,19 +584,20 @@ def MakeCode(ea): return ida_ua.create_insn(ea) -def AnalyzeArea(sEA, eEA): +def plan_and_wait(sEA, eEA, final_pass=True): """ - Perform full analysis of the area + Perform full analysis of the range @param sEA: starting linear address @param eEA: ending linear address (excluded) + @param final_pass: make the final pass over the specified range @return: 1-ok, 0-Ctrl-Break was pressed. """ - return ida_auto.analyze_area(sEA, eEA) + return ida_auto.plan_and_wait(sEA, eEA, final_pass) -def MakeNameEx(ea, name, flags): +def set_name(ea, name, flags=ida_name.SN_CHECK): """ Rename an address @@ -640,14 +609,12 @@ def MakeNameEx(ea, name, flags): """ return ida_name.set_name(ea, name, flags) -SN_CHECK = ida_name.SN_CHECK # Fail if the name contains invalid - # characters +SN_CHECK = ida_name.SN_CHECK +SN_NOCHECK = ida_name.SN_NOCHECK # Don't 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 + # (those !is_ident_cp()) will be replaced + # by SUBSTCHAR (usually '_'). + # List of valid characters is defined in ida.cfg 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 @@ -665,31 +632,20 @@ SN_LOCAL = ida_name.SN_LOCAL # create local name. a function should exis # also they are not included into the list # of names they can't have dummy prefixes -def MakeComm(ea, comment): +def set_cmt(ea, comment, rptble): """ Set an indented regular comment of an item @param ea: linear address @param comment: comment string + @param rptble: is repeatable? @return: None """ - return ida_bytes.set_cmt(ea, comment, 0) + return ida_bytes.set_cmt(ea, comment, rptble) -def MakeRptCmt(ea, comment): - """ - Set an indented repeatable comment of an item - - @param ea: linear address - @param comment: comment string - - @return: None - """ - return ida_bytes.set_cmt(ea, comment, 1) - - -def MakeArray(ea, nitems): +def make_array(ea, nitems): """ Create an array. @@ -700,32 +656,32 @@ 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 = ida_bytes.getFlags(ea) + flags = ida_bytes.get_flags(ea) - if ida_bytes.isCode(flags) or ida_bytes.isTail(flags) or ida_bytes.isAlign(flags): + if ida_bytes.is_code(flags) or ida_bytes.is_tail(flags) or ida_bytes.is_align(flags): return False - if ida_bytes.isUnknown(flags): + if ida_bytes.is_unknown(flags): flags = ida_bytes.FF_BYTE - if ida_bytes.isStruct(flags): + if ida_bytes.is_struct(flags): ti = ida_nalt.opinfo_t() - assert ida_bytes.get_opinfo(ea, 0, flags, ti), "get_opinfo() failed" + assert ida_bytes.get_opinfo(ti, ea, 0, flags), "get_opinfo() failed" itemsize = ida_bytes.get_data_elsize(ea, flags, ti) tid = ti.tid else: itemsize = ida_bytes.get_item_size(ea) tid = BADADDR - return ida_bytes.do_data_ex(ea, flags, itemsize*nitems, tid) + return ida_bytes.create_data(ea, flags, itemsize*nitems, tid) -def MakeStr(ea, endea): +def create_strlit(ea, endea): """ Create a string. This function creates a string (the string type is determined by the - value of GetLongPrm(INF_STRTYPE)) + value of get_inf_attr(INF_STRTYPE)) @param ea: linear address @param endea: ending address of the string (excluded) @@ -734,26 +690,26 @@ def MakeStr(ea, endea): @return: 1-ok, 0-failure - @note: The type of an existing string is returned by GetStringType() + @note: The type of an existing string is returned by get_str_type() """ - return ida_bytes.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE)) + return ida_bytes.create_strlit(ea, 0 if endea == BADADDR else endea - ea, get_inf_attr(INF_STRTYPE)) -def MakeData(ea, flags, size, tid): +def create_data(ea, flags, size, tid): """ Create a data item at the specified address @param ea: linear address @param flags: FF_BYTE..FF_PACKREAL @param size: size of item in bytes - @param tid: for FF_STRU the structure id + @param tid: for FF_STRUCT the structure id @return: 1-ok, 0-failure """ - return ida_bytes.do_data_ex(ea, flags, size, tid) + return ida_bytes.create_data(ea, flags, size, tid) -def MakeByte(ea): +def create_byte(ea): """ Convert the current item to a byte @@ -761,10 +717,10 @@ def MakeByte(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doByte(ea, 1) + return ida_bytes.create_byte(ea, 1) -def MakeWord(ea): +def create_word(ea): """ Convert the current item to a word (2 bytes) @@ -772,10 +728,10 @@ def MakeWord(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doWord(ea, 2) + return ida_bytes.create_word(ea, 2) -def MakeDword(ea): +def create_dword(ea): """ Convert the current item to a double word (4 bytes) @@ -783,10 +739,10 @@ def MakeDword(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doDwrd(ea, 4) + return ida_bytes.create_dword(ea, 4) -def MakeQword(ea): +def create_qword(ea): """ Convert the current item to a quadro word (8 bytes) @@ -794,10 +750,10 @@ def MakeQword(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doQwrd(ea, 8) + return ida_bytes.create_qword(ea, 8) -def MakeOword(ea): +def create_oword(ea): """ Convert the current item to an octa word (16 bytes/128 bits) @@ -805,10 +761,10 @@ def MakeOword(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doOwrd(ea, 16) + return ida_bytes.create_oword(ea, 16) -def MakeYword(ea): +def create_yword(ea): """ Convert the current item to a ymm word (32 bytes/256 bits) @@ -816,10 +772,10 @@ def MakeYword(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doYwrd(ea, 32) + return ida_bytes.create_yword(ea, 32) -def MakeFloat(ea): +def create_float(ea): """ Convert the current item to a floating point (4 bytes) @@ -827,10 +783,10 @@ def MakeFloat(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doFloat(ea, 4) + return ida_bytes.create_float(ea, 4) -def MakeDouble(ea): +def create_double(ea): """ Convert the current item to a double floating point (8 bytes) @@ -838,10 +794,10 @@ def MakeDouble(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doDouble(ea, 8) + return ida_bytes.create_double(ea, 8) -def MakePackReal(ea): +def create_pack_real(ea): """ Convert the current item to a packed real (10 or 12 bytes) @@ -849,10 +805,10 @@ def MakePackReal(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doPackReal(ea, ida_idp.ph_get_tbyte_size()) + return ida_bytes.create_packed_real(ea, ida_idp.ph_get_tbyte_size()) -def MakeTbyte(ea): +def create_tbyte(ea): """ Convert the current item to a tbyte (10 or 12 bytes) @@ -860,10 +816,10 @@ def MakeTbyte(ea): @return: 1-ok, 0-failure """ - return ida_bytes.doTbyt(ea, ida_idp.ph_get_tbyte_size()) + return ida_bytes.create_tbyte(ea, ida_idp.ph_get_tbyte_size()) -def MakeStructEx(ea, size, strname): +def create_struct(ea, size, strname): """ Convert the current item to a structure instance @@ -879,10 +835,10 @@ def MakeStructEx(ea, size, strname): if size == -1: size = ida_struct.get_struc_size(strid) - return ida_bytes.doStruct(ea, size, strid) + return ida_bytes.create_struct(ea, size, strid) -def MakeCustomDataEx(ea, size, dtid, fid): +def create_custom_data(ea, size, dtid, fid): """ Convert the item at address to custom data. @@ -893,11 +849,11 @@ def MakeCustomDataEx(ea, size, dtid, fid): @return: 1-ok, 0-failure """ - return ida_bytes.doCustomData(ea, size, dtid, fid) + return ida_bytes.create_custdata(ea, size, dtid, fid) -def MakeAlign(ea, count, align): +def create_align(ea, count, align): """ Convert the current item to an alignment directive @@ -909,10 +865,10 @@ def MakeAlign(ea, count, align): @return: 1-ok, 0-failure """ - return ida_bytes.doAlign(ea, count, align) + return ida_bytes.create_align(ea, count, align) -def MakeLocal(start, end, location, name): +def define_local_var(start, end, location, name): """ Create a local variable @@ -971,41 +927,29 @@ def MakeLocal(start, end, location, name): return ida_frame.add_regvar(func, start, end, location, name, None) -def MakeUnkn(ea, flags): +def del_items(ea, flags=0, size=1): """ Convert the current item to an explored item @param ea: linear address - @param flags: combination of DOUNK_* constants + @param flags: combination of DELIT_* constants + @param size: size of the range to undefine @return: None """ - return ida_bytes.do_unknown(ea, flags) + return ida_bytes.del_items(ea, flags, size) -def MakeUnknown(ea, size, flags): - """ - Convert the current item to an explored item - - @param ea: linear address - @param size: size of the range to undefine (for MakeUnknown) - @param flags: combination of DOUNK_* constants - - @return: None - """ - return ida_bytes.do_unknown_range(ea, size, flags) - - -DOUNK_SIMPLE = ida_bytes.DOUNK_SIMPLE # simply undefine the specified item -DOUNK_EXPAND = ida_bytes.DOUNK_EXPAND # propogate undefined items, for example +DELIT_SIMPLE = ida_bytes.DELIT_SIMPLE # simply undefine the specified item +DELIT_EXPAND = ida_bytes.DELIT_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) +DELIT_DELNAMES = ida_bytes.DELIT_DELNAMES # delete any names at the specified address(es) -def SetArrayFormat(ea, flags, litems, align): +def set_array_params(ea, flags, litems, align): """ Set array representation format @@ -1019,7 +963,7 @@ def SetArrayFormat(ea, flags, litems, align): @return: 1-ok, 0-failure """ - return Eval("SetArrayFormat(0x%X, 0x%X, %d, %d)"%(ea, flags, litems, align)) + return eval_idc("set_array_params(0x%X, 0x%X, %d, %d)"%(ea, flags, litems, align)) AP_ALLOWDUPS = 0x00000001L # use 'dup' construct AP_SIGNED = 0x00000002L # treats numbers as signed @@ -1031,7 +975,7 @@ AP_IDXHEX = 0x00000010L # display indexes in hex AP_IDXOCT = 0x00000020L # display indexes in octal AP_IDXBIN = 0x00000030L # display indexes in binary -def OpBinary(ea, n): +def op_bin(ea, n): """ Convert an operand of the item (instruction or data) to a binary number @@ -1048,7 +992,7 @@ def OpBinary(ea, n): return ida_bytes.op_bin(ea, n) -def OpOctal(ea, n): +def op_oct(ea, n): """ Convert an operand of the item (instruction or data) to an octal number @@ -1061,7 +1005,7 @@ def OpOctal(ea, n): return ida_bytes.op_oct(ea, n) -def OpDecimal(ea, n): +def op_dec(ea, n): """ Convert an operand of the item (instruction or data) to a decimal number @@ -1074,7 +1018,7 @@ def OpDecimal(ea, n): return ida_bytes.op_dec(ea, n) -def OpHex(ea, n): +def op_hex(ea, n): """ Convert an operand of the item (instruction or data) to a hexadecimal number @@ -1087,7 +1031,7 @@ def OpHex(ea, n): return ida_bytes.op_hex(ea, n) -def OpChr(ea, n): +def op_chr(ea, n): """ @param ea: linear address @param n: number of operand @@ -1098,10 +1042,10 @@ def OpChr(ea, n): return ida_bytes.op_chr(ea, n) -def OpOff(ea, n, base): +def op_plain_offset(ea, n, base): """ Convert operand to an offset - (for the explanations of 'ea' and 'n' please see OpBinary()) + (for the explanations of 'ea' and 'n' please see op_bin()) Example: ======== @@ -1116,7 +1060,7 @@ def OpOff(ea, n, base): Then you need to specify a linear address of the segment base to create a proper offset: - OpOff(["seg000",0x2000],0,0x10000); + op_plain_offset(["seg000",0x2000],0,0x10000); and you will have: @@ -1137,16 +1081,19 @@ 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 ida_offset.set_offset(ea, n, base) + if base == BADADDR: + return ida_bytes.clr_op_type(ea, n) + else: + return ida_offset.op_plain_offset(ea, n, base) OPND_OUTER = ida_bytes.OPND_OUTER # outer offset base -def OpOffEx(ea, n, reftype, target, base, tdelta): +def op_offset(ea, n, reftype, target, base, tdelta): """ Convert operand to a complex offset expression - This is a more powerful version of OpOff() function. + This is a more powerful version of op_plain_offset() function. It allows to explicitly specify the reference type (off8,off16, etc) and the expression target with a possible target delta. The complex expressions are represented by IDA in the following form: @@ -1160,7 +1107,7 @@ def OpOffEx(ea, n, reftype, target, base, tdelta): The target must be present for LOW.. and HIGH.. reference types @param ea: linear address of the instruction/data - @param n: number of operand to convert (the same as in OpOff) + @param n: number of operand to convert (the same as in op_plain_offset) @param reftype: one of REF_... constants @param target: an explicitly specified expression target. if you don't want to specify it, use -1. Please note that LOW... and @@ -1181,8 +1128,6 @@ 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 @@ -1197,7 +1142,7 @@ REFINFO_SUBTRACT = 0x0100 # the reference value is subtracted from REFINFO_SIGNEDOP = 0x0200 # the operand value is sign-extended (only # supported for REF_OFF8/16/32/64) -def OpSeg(ea, n): +def op_seg(ea, n): """ Convert operand to a segment expression @@ -1210,7 +1155,7 @@ def OpSeg(ea, n): return ida_bytes.op_seg(ea, n) -def OpNumber(ea, n): +def op_num(ea, n): """ Convert operand to a number (with default number base, radix) @@ -1223,7 +1168,7 @@ def OpNumber(ea, n): return ida_bytes.op_num(ea, n) -def OpFloat(ea, n): +def op_flt(ea, n): """ Convert operand to a floating-point number @@ -1238,7 +1183,7 @@ def OpFloat(ea, n): return ida_bytes.op_flt(ea, n) -def OpAlt(ea, n, opstr): +def op_man(ea, n, opstr): """ Specify operand represenation manually. @@ -1255,7 +1200,7 @@ def OpAlt(ea, n, opstr): return ida_bytes.set_forced_operand(ea, n, opstr) -def OpSign(ea, n): +def toggle_sign(ea, n): """ Change sign of the operand @@ -1268,7 +1213,7 @@ def OpSign(ea, n): return ida_bytes.toggle_sign(ea, n) -def OpNot(ea, n): +def toggle_bnot(ea, n): """ Toggle the bitwise not operator for the operand @@ -1282,7 +1227,7 @@ def OpNot(ea, n): return True -def OpEnumEx(ea, n, enumid, serial): +def op_enum(ea, n, enumid, serial): """ Convert operand to a symbolic constant @@ -1303,7 +1248,7 @@ def OpEnumEx(ea, n, enumid, serial): return ida_bytes.op_enum(ea, n, enumid, serial) -def OpStroffEx(ea, n, strid, delta): +def op_stroff(ea, n, strid, delta): """ Convert operand to an offset in a structure @@ -1322,7 +1267,7 @@ def OpStroffEx(ea, n, strid, delta): return ida_bytes.op_stroff(ea, n, path.cast(), 1, delta) -def OpStkvar(ea, n): +def op_stkvar(ea, n): """ Convert operand to a stack variable @@ -1335,7 +1280,7 @@ def OpStkvar(ea, n): return ida_bytes.op_stkvar(ea, n) -def OpHigh(ea, n, target): +def op_offset_high16(ea, n, target): """ Convert operand to a high offset High offset is the upper 16bits of an offset. @@ -1366,13 +1311,34 @@ def MakeVar(ea): """ ida_bytes.doVar(ea, 1) +# Every anterior/posterior line has its number. +# Anterior lines have numbers from E_PREV +# Posterior lines have numbers from E_NEXT +E_PREV = ida_lines.E_PREV +E_NEXT = ida_lines.E_NEXT -def ExtLinA(ea, n, line): +def get_extra_cmt(ea, n): """ - Specify an additional line to display before the generated ones. + Get extra comment line @param ea: linear address - @param n: number of anterior additional line (0..MAX_ITEM_LINES) + @param n: number of line (0..MAX_ITEM_LINES) + MAX_ITEM_LINES is defined in IDA.CFG + + To get anterior line #n use (E_PREV + n) + To get posterior line #n use (E_NEXT + n) + + @return: extra comment line string + """ + return ida_lines.get_extra_cmt(ea, n) + + +def update_extra_cmt(ea, n, line): + """ + Set or update extra comment line + + @param ea: linear address + @param n: number of additional line (0..MAX_ITEM_LINES) @param line: the line to display @return: None @@ -1381,55 +1347,29 @@ def ExtLinA(ea, n, line): additional line. So, if you specify additional line #150 and there is no additional line #149, your line will not be displayed. MAX_ITEM_LINES is defined in IDA.CFG + + To set anterior line #n use (E_PREV + n) + To set posterior line #n use (E_NEXT + n) """ - ida_lines.update_extra_cmt(ea, ida_lines.E_PREV + n, line) - ida_bytes.doExtra(ea) + ida_lines.update_extra_cmt(ea, n, line) -def ExtLinB(ea, n, line): +def del_extra_cmt(ea, n): """ - Specify an additional line to display after the generated ones. + Delete an extra comment line @param ea: linear address - @param n: number of posterior additional line (0..MAX_ITEM_LINES) - @param line: the line to display + @param n: number of anterior additional line (0..MAX_ITEM_LINES) @return: None - @note: IDA displays additional lines from number 0 up to the first - unexisting additional line. So, if you specify additional line #150 - and there is no additional line #149, your line will not be displayed. - MAX_ITEM_LINES is defined in IDA.CFG + To delete anterior line #n use (E_PREV + n) + To delete posterior line #n use (E_NEXT + n) """ - ida_lines.update_extra_cmt(ea, ida_lines.E_NEXT + n, line) - ida_bytes.doExtra(ea) + ida_lines.del_extra_cmt(ea, n) -def DelExtLnA(ea, n): - """ - Delete an additional anterior line - - @param ea: linear address - @param n: number of anterior additional line (0..500) - - @return: None - """ - ida_lines.del_extra_cmt(ea, ida_lines.E_PREV + n) - - -def DelExtLnB(ea, n): - """ - Delete an additional posterior line - - @param ea: linear address - @param n: number of posterior additional line (0..500) - - @return: None - """ - ida_lines.del_extra_cmt(ea, ida_lines.E_NEXT + n) - - -def SetManualInsn(ea, insn): +def set_manual_insn(ea, insn): """ Specify instruction represenation manually. @@ -1442,18 +1382,18 @@ def SetManualInsn(ea, insn): return ida_bytes.set_manual_insn(ea, insn) -def GetManualInsn(ea): +def get_manual_insn(ea): """ Get manual representation of instruction @param ea: linear address - @note: This function returns value set by SetManualInsn earlier. + @note: This function returns value set by set_manual_insn earlier. """ return ida_bytes.get_manual_insn(ea) -def PatchDbgByte(ea,value): +def patch_dbg_byte(ea,value): """ Change a byte in the debugged process memory only @@ -1465,7 +1405,7 @@ def PatchDbgByte(ea,value): return ida_dbg.put_dbg_byte(ea, value) -def PatchByte(ea, value): +def patch_byte(ea, value): """ Change value of a program byte If debugger was active then the debugged process memory will be patched too @@ -1482,7 +1422,7 @@ def PatchByte(ea, value): return ida_bytes.patch_byte(ea, value) -def PatchWord(ea, value): +def patch_word(ea, value): """ Change value of a program word (2 bytes) @@ -1498,7 +1438,7 @@ def PatchWord(ea, value): return ida_bytes.patch_word(ea, value) -def PatchDword(ea, value): +def patch_dword(ea, value): """ Change value of a double word @@ -1511,10 +1451,10 @@ def PatchDword(ea, value): or the debugger is not running, and the IDB has value 'value' at address 'ea already. """ - return ida_bytes.patch_long(ea, value) + return ida_bytes.patch_dword(ea, value) -def PatchQword(ea, value): +def patch_qword(ea, value): """ Change value of a quad word @@ -1530,19 +1470,12 @@ def PatchQword(ea, value): return ida_bytes.patch_qword(ea, value) -def SetFlags(ea, flags): - """ - Set new value of flags - This function should not used be used directly if possible. - It changes properties of a program byte and if misused, may lead to - very-very strange results. +SR_inherit = 1 # value is inherited from the previous range +SR_user = 2 # value is specified by the user +SR_auto = 3 # value is determined by IDA +SR_autostart = 4 # as SR_auto for segment starting address - @param ea: adress - @param flags: new flags value - """ - return ida_bytes.setFlags(ea, flags) - -def SetRegEx(ea, reg, value, tag): +def split_sreg_range(ea, reg, value, tag=SR_user): """ Set value of a segment register. @@ -1554,22 +1487,15 @@ def SetRegEx(ea, reg, value, tag): @note: IDA keeps tracks of all the points where segment register change their values. This function allows you to specify the correct value of a segment register if IDA is not able to find the corrent value. - - See also SetReg() compatibility macro. """ reg = ida_idp.str2reg(reg); if reg >= 0: - return ida_srarea.splitSRarea1(ea, reg, value, tag) + return ida_segregs.split_sreg_range(ea, reg, value, tag) else: return False -SR_inherit = 1 # value is inherited from the previous area -SR_user = 2 # value is specified by the user -SR_auto = 3 # value is determined by IDA -SR_autostart = 4 # as SR_auto for segment starting address - -def AutoMark2(start, end, queuetype): +def auto_mark_range(start, end, queuetype): """ Plan to perform an action in the future. This function will put your request to a special autoanalysis queue. @@ -1580,18 +1506,18 @@ def AutoMark2(start, end, queuetype): return ida_auto.auto_mark_range(start, end, queuetype) -def AutoUnmark(start, end, queuetype): +def auto_unmark(start, end, queuetype): """ Remove range of addresses from a queue. """ - return ida_auto.autoUnmark(start, end, queuetype) + return ida_auto.auto_unmark(start, end, queuetype) def AutoMark(ea,qtype): """ Plan to analyze an address """ - return AutoMark2(ea,ea+1,qtype) + return auto_mark_range(ea,ea+1,qtype) AU_UNK = ida_auto.AU_UNK # make unknown AU_CODE = ida_auto.AU_CODE # convert to instruction @@ -1605,7 +1531,7 @@ AU_FINAL = ida_auto.AU_FINAL # coagulate unexplored items # P R O D U C E O U T P U T F I L E S #---------------------------------------------------------------------------- -def GenerateFile(filetype, path, ea1, ea2, flags): +def gen_file(filetype, path, ea1, ea2, flags): """ Generate an output file @@ -1647,14 +1573,14 @@ GENFLG_ASMTYPE = ida_loader.GENFLG_ASMTYPE # asm&lst: gen information about type 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): +def gen_flow_graph(outfile, title, ea1, ea2, flags): """ Generate a flow chart GDL file @param outfile: output file name. GDL extension will be used @param title: graph title - @param ea1: beginning of the area to flow chart - @param ea2: end of the area to flow chart. + @param ea1: beginning of the range to flow chart + @param ea2: end of the range to flow chart. @param flags: combination of CHART_... constants @note: If ea2 == BADADDR then ea1 is treated as an address within a function. @@ -1669,7 +1595,7 @@ CHART_WINGRAPH = 0x8000 # call wingraph32 to display the graph CHART_NOLIBFUNCS = 0x0400 # don't include library functions in the graph -def GenCallGdl(outfile, title, flags): +def gen_simple_call_chart(outfile, title, flags): """ Generate a function call graph GDL file @@ -1683,7 +1609,7 @@ def GenCallGdl(outfile, title, flags): #---------------------------------------------------------------------------- # C O M M O N I N F O R M A T I O N #---------------------------------------------------------------------------- -def GetIdaDirectory(): +def idadir(): """ Get IDA directory @@ -1692,7 +1618,7 @@ def GetIdaDirectory(): return ida_diskio.idadir("") -def GetInputFile(): +def get_root_filename(): """ Get input file name @@ -1701,7 +1627,7 @@ def GetInputFile(): return ida_nalt.get_root_filename() -def GetInputFilePath(): +def get_input_file_path(): """ Get input file path @@ -1710,7 +1636,7 @@ def GetInputFilePath(): return ida_nalt.get_input_file_path() -def SetInputFilePath(path): +def set_root_filename(path): """ Set input file name This function updates the file name that is stored in the database @@ -1723,16 +1649,16 @@ def SetInputFilePath(path): return ida_nalt.set_root_filename(path) -def GetIdbPath(): +def get_idb_path(): """ Get IDB full path This function returns full path of the current IDB database """ - return ida_idaapi.as_cstr(ida_loader.cvar.database_idb) + return ida_loader.get_path(ida_loader.PATH_TYPE_IDB) -def GetInputMD5(): +def retrieve_input_file_md5(): """ Return the MD5 hash of the input binary file @@ -1741,7 +1667,7 @@ def GetInputMD5(): return ida_nalt.retrieve_input_file_md5() -def GetFlags(ea): +def get_full_flags(ea): """ Get internal flags @@ -1750,10 +1676,10 @@ def GetFlags(ea): @return: 32-bit value of internal flags. See start of IDC.IDC file for explanations. """ - return ida_bytes.getFlags(ea) + return ida_bytes.get_full_flags(ea) -def IdbByte(ea): +def get_db_byte(ea): """ Get one byte (8-bit) of the program at 'ea' from the database even if the debugger is active @@ -1762,12 +1688,12 @@ def IdbByte(ea): @return: byte value. If the byte has no value then 0xFF is returned. @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)) + To check if a byte has a value, use is_loaded() """ return ida_bytes.get_db_byte(ea) -def GetManyBytes(ea, size, use_dbg = False): +def get_bytes(ea, size, use_dbg = False): """ Return the specified number of bytes of the program @@ -1783,10 +1709,10 @@ def GetManyBytes(ea, size, use_dbg = False): if use_dbg: return ida_idd.dbg_read_memory(ea, size) else: - return ida_bytes.get_many_bytes(ea, size) + return ida_bytes.get_bytes(ea, size) -def Byte(ea): +def get_wide_byte(ea): """ Get value of program byte @@ -1795,19 +1721,19 @@ def Byte(ea): @return: value of byte. If byte has no value then returns 0xFF If the current byte size is different from 8 bits, then the returned value might have more 1's. - To check if a byte has a value, use functions hasValue(GetFlags(ea)) + To check if a byte has a value, use is_loaded() """ - return ida_bytes.get_full_byte(ea) + return ida_bytes.get_wide_byte(ea) def __DbgValue(ea, len): if len not in ida_idaapi.__struct_unpack_table: return None 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] + return None if r is None else struct.unpack((">" if ida_ida.cvar.inf.is_be() else "<") + ida_idaapi.__struct_unpack_table[len][1], r)[0] -def DbgByte(ea): +def read_dbg_byte(ea): """ Get value of program byte using the debugger memory @@ -1817,7 +1743,7 @@ def DbgByte(ea): return __DbgValue(ea, 1) -def DbgWord(ea): +def read_dbg_word(ea): """ Get value of program word using the debugger memory @@ -1827,7 +1753,7 @@ def DbgWord(ea): return __DbgValue(ea, 2) -def DbgDword(ea): +def read_dbg_dword(ea): """ Get value of program double-word using the debugger memory @@ -1837,7 +1763,7 @@ def DbgDword(ea): return __DbgValue(ea, 4) -def DbgQword(ea): +def read_dbg_qword(ea): """ Get value of program quadro-word using the debugger memory @@ -1847,7 +1773,7 @@ def DbgQword(ea): return __DbgValue(ea, 8) -def DbgRead(ea, size): +def read_dbg_memory(ea, size): """ Read from debugger memory. @@ -1860,7 +1786,7 @@ def DbgRead(ea, size): return ida_idd.dbg_read_memory(ea, size) -def DbgWrite(ea, data): +def write_dbg_memory(ea, data): """ Write to debugger memory. @@ -1876,7 +1802,7 @@ def DbgWrite(ea, data): return ida_idd.dbg_write_memory(ea, data) -def GetOriginalByte(ea): +def get_original_byte(ea): """ Get original value of program byte @@ -1887,7 +1813,7 @@ def GetOriginalByte(ea): return ida_bytes.get_original_byte(ea) -def Word(ea): +def get_wide_word(ea): """ Get value of program word (2 bytes) @@ -1897,10 +1823,10 @@ def Word(ea): If the current byte size is different from 8 bits, then the returned value might have more 1's. """ - return ida_bytes.get_full_word(ea) + return ida_bytes.get_wide_word(ea) -def Dword(ea): +def get_wide_dword(ea): """ Get value of program double word (4 bytes) @@ -1908,10 +1834,10 @@ def Dword(ea): @return: the value of the double word. If failed returns -1 """ - return ida_bytes.get_full_long(ea) + return ida_bytes.get_wide_dword(ea) -def Qword(ea): +def get_qword(ea): """ Get value of program quadro word (8 bytes) @@ -1932,7 +1858,7 @@ def GetFloat(ea): @return: float """ - tmp = struct.pack("I", Dword(ea)) + tmp = struct.pack("I", get_wide_dword(ea)) return struct.unpack("f", tmp)[0] @@ -1946,11 +1872,11 @@ def GetDouble(ea): @return: double """ - tmp = struct.pack("Q", Qword(ea)) + tmp = struct.pack("Q", get_qword(ea)) return struct.unpack("d", tmp)[0] -def LocByName(name): +def get_name_ea_simple(name): """ Get linear address of a name @@ -1962,7 +1888,7 @@ def LocByName(name): return ida_name.get_name_ea(BADADDR, name) -def LocByNameEx(fromaddr, name): +def get_name_ea(fromaddr, name): """ Get linear address of a name @@ -1980,7 +1906,7 @@ def LocByNameEx(fromaddr, name): return ida_name.get_name_ea(fromaddr, name) -def SegByBase(base): +def get_segm_by_sel(base): """ Get segment by segment base @@ -1993,19 +1919,19 @@ def SegByBase(base): seg = ida_segment.get_segm_by_sel(sel) if seg: - return seg.startEA + return seg.start_ea else: return BADADDR -def ScreenEA(): +def get_screen_ea(): """ Get linear address of cursor """ return ida_kernwin.get_screen_ea() -def GetCurrentLine(): +def get_curline(): """ Get the disassembly line at the cursor @@ -2014,12 +1940,12 @@ def GetCurrentLine(): return ida_lines.tag_remove(ida_kernwin.get_curline()) -def SelStart(): +def read_selection_start(): """ - Get start address of the selected area - returns BADADDR - the user has not selected an area + Get start address of the selected range + returns BADADDR - the user has not selected an range """ - selection, startaddr, endaddr = ida_kernwin.read_selection() + selection, startaddr, endaddr = ida_kernwin.read_range_selection(None) if selection == 1: return startaddr @@ -2027,13 +1953,13 @@ def SelStart(): return BADADDR -def SelEnd(): +def read_selection_end(): """ - Get end address of the selected area + Get end address of the selected range - @return: BADADDR - the user has not selected an area + @return: BADADDR - the user has not selected an range """ - selection, startaddr, endaddr = ida_kernwin.read_selection() + selection, startaddr, endaddr = ida_kernwin.read_range_selection(None) if selection == 1: return endaddr @@ -2041,7 +1967,7 @@ def SelEnd(): return BADADDR -def GetReg(ea, reg): +def get_sreg(ea, reg): """ Get value of segment register at the specified address @@ -2052,15 +1978,15 @@ def GetReg(ea, reg): @note: The segment registers in 32bit program usually contain selectors, so to get paragraph pointed to by the segment register you need to - call AskSelector() function. + call sel2para() function. """ reg = ida_idp.str2reg(reg); if reg >= 0: - return ida_srarea.getSR(ea, reg) + return ida_segregs.get_sreg(ea, reg) else: return -1 -def NextAddr(ea): +def next_addr(ea): """ Get next address in the program @@ -2068,10 +1994,10 @@ def NextAddr(ea): @return: BADADDR - the specified address in the last used address """ - return ida_bytes.nextaddr(ea) + return ida_bytes.next_addr(ea) -def PrevAddr(ea): +def prev_addr(ea): """ Get previous address in the program @@ -2079,10 +2005,10 @@ def PrevAddr(ea): @return: BADADDR - the specified address in the first address """ - return ida_bytes.prevaddr(ea) + return ida_bytes.prev_addr(ea) -def NextHead(ea, maxea=BADADDR): +def next_head(ea, maxea=BADADDR): """ Get next defined item (instruction or data) in the program @@ -2095,7 +2021,7 @@ def NextHead(ea, maxea=BADADDR): return ida_bytes.next_head(ea, maxea) -def PrevHead(ea, minea=0): +def prev_head(ea, minea=0): """ Get previous defined item (instruction or data) in the program @@ -2108,7 +2034,7 @@ def PrevHead(ea, minea=0): return ida_bytes.prev_head(ea, minea) -def NextNotTail(ea): +def next_not_tail(ea): """ Get next not-tail address in the program This function searches for the next displayable address in the program. @@ -2121,7 +2047,7 @@ def NextNotTail(ea): return ida_bytes.next_not_tail(ea) -def PrevNotTail(ea): +def prev_not_tail(ea): """ Get previous not-tail address in the program This function searches for the previous displayable address in the program. @@ -2134,7 +2060,7 @@ def PrevNotTail(ea): return ida_bytes.prev_not_tail(ea) -def ItemHead(ea): +def get_item_head(ea): """ Get starting address of the item (instruction or data) @@ -2146,7 +2072,7 @@ def ItemHead(ea): return ida_bytes.get_item_head(ea) -def ItemEnd(ea): +def get_item_end(ea): """ Get address of the end of the item (instruction or data) @@ -2157,7 +2083,7 @@ def ItemEnd(ea): return ida_bytes.get_item_end(ea) -def ItemSize(ea): +def get_item_size(ea): """ Get size of instruction or data item in bytes @@ -2168,68 +2094,74 @@ def ItemSize(ea): return ida_bytes.get_item_end(ea) - ea -def NameEx(fromaddr, ea): +def func_contains(func_ea, ea): """ - Get visible name of program byte + Does the given function contain the given address? - This function returns name of byte as it is displayed on the screen. - If a name contains illegal characters, IDA replaces them by the - substitution character during displaying. See IDA.CFG for the - definition of the substitution character. + @param func_ea: any address belonging to the function + @param ea: linear address + + @return: success + """ + func = ida_funcs.get_func(func_ea) + + if func: + return ida_funcs.func_contains(func, ea) + return False + + +GN_VISIBLE = ida_name.GN_VISIBLE # replace forbidden characters by SUBSTCHAR +GN_COLORED = ida_name.GN_COLORED # return colored name +GN_DEMANGLED = ida_name.GN_DEMANGLED # return demangled name +GN_STRICT = ida_name.GN_STRICT # fail if can not demangle +GN_SHORT = ida_name.GN_SHORT # use short form of demangled name +GN_LONG = ida_name.GN_LONG # use long form of demangled name +GN_LOCAL = ida_name.GN_LOCAL # try to get local name first; if failed, get global +GN_ISRET = ida_name.GN_ISRET # for dummy names: use retloc +GN_NOT_ISRET = ida_name.GN_NOT_ISRET # for dummy names: do not use retloc + + +def calc_gtn_flags(fromaddr, ea): + """ + Calculate flags for get_name() function @param fromaddr: the referring address. May be BADADDR. - Allows to retrieve local label addresses in functions. - If a local name is not found, then a global name is - returned. @param ea: linear address + @return: success + """ + return ida_name.calc_gtn_flags(fromaddr, ea) + + +def get_name(ea, gtn_flags=0): + """ + Get name at the specified address + + @param ea: linear address + @param gtn_flags: how exactly the name should be retrieved. + combination of GN_ bits + @return: "" - byte has no name """ - name = ida_name.get_name(fromaddr, ea) - - if not name: - return "" - else: - return name + return ida_name.get_ea_name(ea, gtn_flags) -def GetTrueNameEx(fromaddr, ea): +def demangle_name(name, disable_mask): """ - Get true name of program byte - - This function returns name of byte as is without any replacements. - - @param fromaddr: the referring address. May be BADADDR. - Allows to retrieve local label addresses in functions. - If a local name is not found, then a global name is returned. - @param ea: linear address - - @return: "" - byte has no name - """ - name = ida_name.get_true_name(fromaddr, ea) - - if not name: - return "" - else: - return name - - -def Demangle(name, disable_mask): - """ - Demangle a name + demangle_name a name @param name: name to demangle @param disable_mask: a mask that tells how to demangle the name it is a good idea to get this mask using - GetLongPrm(INF_SHORT_DN) or GetLongPrm(INF_LONG_DN) + get_inf_attr(INF_SHORT_DN) or get_inf_attr(INF_LONG_DN) @return: a demangled name If the input name cannot be demangled, returns None """ - return ida_name.demangle_name(name, disable_mask) + return ida_name.demangle_name(name, disable_mask, ida_name.DQT_FULL) -def GetDisasmEx(ea, flags): +def generate_disasm_line(ea, flags): """ Get disassembly line @@ -2248,7 +2180,7 @@ def GetDisasmEx(ea, flags): else: return "" -# flags for GetDisasmEx +# flags for generate_disasm_line # generate a disassembly line as if # there is an instruction at 'ea' GENDSM_FORCE_CODE = ida_lines.GENDSM_FORCE_CODE @@ -2268,9 +2200,9 @@ def GetDisasm(ea): @note: this function may not return exactly the same mnemonics as you see on the screen. """ - return GetDisasmEx(ea, 0) + return generate_disasm_line(ea, 0) -def GetMnem(ea): +def print_insn_mnem(ea): """ Get instruction mnemonics @@ -2289,11 +2221,11 @@ def GetMnem(ea): return res -def GetOpnd(ea, n): +def print_operand(ea, n): """ - Get operand of an instruction + Get operand of an instruction or data - @param ea: linear address of instruction + @param ea: linear address of the item @param n: number of operand: 0 - the first operand 1 - the second operand @@ -2301,10 +2233,7 @@ def GetOpnd(ea, n): @return: the current text representation of operand or "" """ - if not isCode(ida_bytes.get_flags_novalue(ea)): - return "" - - res = ida_ua.ua_outop2(ea, n) + res = ida_ua.print_operand(ea, n) if not res: return "" @@ -2312,7 +2241,7 @@ def GetOpnd(ea, n): return ida_lines.tag_remove(res) -def GetOpType(ea, n): +def get_operand_type(ea, n): """ Get type of instruction operand @@ -2323,8 +2252,9 @@ def GetOpType(ea, n): @return: any of o_* constants or -1 on error """ - inslen = ida_ua.decode_insn(ea) - return -1 if inslen == 0 else ida_ua.cmd.Operands[n].type + insn = ida_ua.insn_t() + inslen = ida_ua.decode_insn(insn, ea) + return -1 if inslen == 0 else insn.ops[n].type o_void = ida_ua.o_void # No Operand ---------- @@ -2355,9 +2285,9 @@ o_xmmreg = ida_ua.o_idpspec5 # xmm register 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 +o_fpreglist = ida_ua.o_idpspec4 # Floating point register list +o_text = ida_ua.o_idpspec5 # Arbitrary text stored in the operand +o_cond = (ida_ua.o_idpspec5+1) # ARM condition as an operand # ppc o_spr = ida_ua.o_idpspec0 # Special purpose register @@ -2367,7 +2297,7 @@ 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): +def get_operand_value(ea, n): """ Get number used in the operand @@ -2384,10 +2314,11 @@ def GetOperandValue(ea, n): operand is a register phrase => phrase number otherwise => -1 """ - inslen = ida_ua.decode_insn(ea) + insn = ida_ua.insn_t() + inslen = ida_ua.decode_insn(insn, ea) if inslen == 0: return -1 - op = ida_ua.cmd.Operands[n] + op = insn.ops[n] if not op: return -1 @@ -2404,31 +2335,6 @@ def GetOperandValue(ea, n): return value -def LineA(ea, num): - """ - Get anterior line - - @param ea: linear address - @param num: number of anterior line (0..MAX_ITEM_LINES) - MAX_ITEM_LINES is defined in IDA.CFG - - @return: anterior line string - """ - return ida_lines.get_extra_cmt(ea, ida_lines.E_PREV + num) - - -def LineB(ea, num): - """ - Get posterior line - - @param ea: linear address - @param num: number of posterior line (0..MAX_ITEM_LINES) - - @return: posterior line string - """ - return ida_lines.get_extra_cmt(ea, ida_lines.E_NEXT + num) - - def GetCommentEx(ea, repeatable): """ Get regular indented comment @@ -2442,7 +2348,7 @@ def GetCommentEx(ea, repeatable): return ida_bytes.get_cmt(ea, repeatable) -def CommentEx(ea, repeatable): +def get_cmt(ea, repeatable): """ Get regular indented comment @@ -2455,7 +2361,7 @@ def CommentEx(ea, repeatable): return GetCommentEx(ea, repeatable) -def AltOp(ea, n): +def get_forced_operand(ea, n): """ Get manually entered operand string @@ -2468,42 +2374,41 @@ def AltOp(ea, n): """ return ida_bytes.get_forced_operand(ea, n) -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 +STRTYPE_C = ida_nalt.STRTYPE_TERMCHR # C-style ASCII string +STRTYPE_PASCAL = ida_nalt.STRTYPE_PASCAL # Pascal-style ASCII string (length byte) +STRTYPE_LEN2 = ida_nalt.STRTYPE_LEN2 # Pascal-style, length is 2 bytes +STRTYPE_C_16 = ida_nalt.STRTYPE_C_16 # Unicode string +STRTYPE_LEN4 = ida_nalt.STRTYPE_LEN4 # Pascal-style, length is 4 bytes +STRTYPE_LEN2_16 = ida_nalt.STRTYPE_LEN2_16 # Pascal-style Unicode, length is 2 bytes +STRTYPE_LEN4_16 = ida_nalt.STRTYPE_LEN4_16 # Pascal-style Unicode, length is 4 bytes -def GetString(ea, length = -1, strtype = ASCSTR_C): +def get_strlit_contents(ea, length = -1, strtype = STRTYPE_C): """ Get string contents @param ea: linear address @param length: string length. -1 means to calculate the max string length - @param strtype: the string type (one of ASCSTR_... constants) + @param strtype: the string type (one of STRTYPE_... constants) @return: string contents or empty string """ if length == -1: - length = ida_bytes.get_max_ascii_length(ea, strtype, ida_bytes.ALOPT_IGNHEADS) + length = ida_bytes.get_max_strlit_length(ea, strtype, ida_bytes.ALOPT_IGNHEADS) - return ida_bytes.get_ascii_contents2(ea, length, strtype) + return ida_bytes.get_strlit_contents(ea, length, strtype) -def GetStringType(ea): +def get_str_type(ea): """ Get string type @param ea: linear address - @return: One of ASCSTR_... constants + @return: One of STRTYPE_... constants """ - flags = ida_bytes.getFlags(ea) - if ida_bytes.isASCII(flags): + flags = ida_bytes.get_flags(ea) + if ida_bytes.is_strlit(flags): oi = ida_nalt.opinfo_t() - if ida_bytes.get_opinfo(ea, 0, flags, oi): + if ida_bytes.get_opinfo(oi, ea, 0, flags): return oi.strtype # The following functions search for the specified byte @@ -2511,24 +2416,24 @@ def GetStringType(ea): # flag is combination of the following bits # returns BADADDR - not found -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) +def find_suspop (ea, flag): return ida_search.find_suspop(ea, flag) +def find_code (ea, flag): return ida_search.find_code(ea, flag) +def find_data (ea, flag): return ida_search.find_data(ea, flag) +def find_unknown (ea, flag): return ida_search.find_unknown(ea, flag) +def find_defined (ea, flag): return ida_search.find_defined(ea, flag) +def find_imm (ea, flag, value): return ida_search.find_imm(ea, flag, value) 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() + # useful only for find_text() and find_binary() 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): +def find_text(ea, flag, y, x, searchstr): """ @param ea: start address @param flag: combination of SEARCH_* flags @@ -2541,7 +2446,7 @@ def FindText(ea, flag, y, x, searchstr): return ida_search.find_text(ea, y, x, searchstr, flag) -def FindBinary(ea, flag, searchstr, radix=16): +def find_binary(ea, flag, searchstr, radix=16): """ @param ea: start address @param flag: combination of SEARCH_* flags @@ -2552,14 +2457,14 @@ def FindBinary(ea, flag, searchstr, radix=16): @note: Example: "41 42" - find 2 bytes 41h,42h (radix is 16) """ - endea = flag & 1 and ida_ida.cvar.inf.maxEA or ida_ida.cvar.inf.minEA + endea = flag & 1 and ida_ida.cvar.inf.max_ea or ida_ida.cvar.inf.min_ea return ida_search.find_binary(ea, endea, searchstr, radix, flag) #---------------------------------------------------------------------------- # G L O B A L S E T T I N G S M A N I P U L A T I O N #---------------------------------------------------------------------------- -def ChangeConfig(directive): +def process_config_line(directive): """ Parse one or more ida.cfg config directives @param directive: directives to process, for example: PACK_DATABASE=2 @@ -2567,13 +2472,13 @@ 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")' % ida_kernwin.str2user(directive)) + return eval_idc('process_config_line("%s")' % ida_kernwin.str2user(directive)) # The following functions allow you to set/get common parameters. # Please note that not all parameters can be set directly. -def GetLongPrm(offset): +def get_inf_attr(offset): """ """ val = _IDC_GetAttr(ida_ida.cvar.inf, _INFMAP, offset) @@ -2582,418 +2487,413 @@ def GetLongPrm(offset): val = ida_idaapi.as_cstr(val) return val -def GetShortPrm(offset): - return GetLongPrm(offset) - - -def GetCharPrm (offset): - return GetLongPrm(offset) - - -def _invoke_idc_setprm(vtype, offset, value): +def set_inf_attr(offset, value): if offset == INF_PROCNAME: 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)) + return eval_idc("set_inf_attr(%d, %d)" % (offset, value)) -def SetLongPrm (offset, value): - return _invoke_idc_setprm("Long", offset, value) +INF_VERSION = 4 # short; Version of database +INF_PROCNAME = 6 # char[8]; Name of current processor +INF_GENFLAGS = 22 # ushort; General flags: +INFFL_AUTO = 0x01 # Autoanalysis is enabled? +INFFL_ALLASM = 0x02 # May use constructs not supported by + # the target assembler +INFFL_LOADIDC = 0x04 # loading an idc file that contains database info +INFFL_NOUSER = 0x08 # do not store user info in the database +INFFL_READONLY = 0x10 # (internal) temporary interdiction to modify the database +INFFL_CHKOPS = 0x20 # check manual operands? +INFFL_NMOPS = 0x40 # allow non-matched operands? +INFFL_GRAPH_VIEW= 0x80 # currently using graph options (\dto{graph}) +INF_LFLAGS = 24 # uint32; IDP-dependent flags +LFLG_PC_FPP = 0x00000001 # decode floating point processor + # instructions? +LFLG_PC_FLAT = 0x00000002 # Flat model? +LFLG_64BIT = 0x00000004 # 64-bit program? +LFLG_IS_DLL = 0x00000008 # is dynamic library? +LFLG_FLAT_OFF32= 0x00000010 # treat REF_OFF32 as 32-bit offset for 16bit segments (otherwise try SEG16:OFF16) +LFLG_MSF = 0x00000020 # byte order: is MSB first? +LFLG_WIDE_HBF = 0x00000040 # bit order of wide bytes: high byte first? +LFLG_DBG_NOPATH= 0x00000080 # do not store input full path +LFLG_SNAPSHOT = 0x00000100 # is memory snapshot? +LFLG_PACK = 0x00000200 # pack the database? +LFLG_COMPRESS = 0x00000400 # compress the database? +LFLG_KERNMODE = 0x00000800 # is kernel mode binary? +INF_CHANGE_COUNTER= 28 # uint32; database change counter; keeps track of byte and segment modifications -def SetShortPrm(offset, value): - return _invoke_idc_setprm("Short", offset, value) +INF_FILETYPE = 32 # short; type of input file (see ida.hpp) +FT_EXE_OLD = 0 # MS DOS EXE File (obsolete) +FT_COM_OLD = 1 # MS DOS COM File (obsolete) +FT_BIN = 2 # Binary File +FT_DRV = 3 # MS DOS Driver +FT_WIN = 4 # New Executable (NE) +FT_HEX = 5 # Intel Hex Object File +FT_MEX = 6 # MOS Technology Hex Object File +FT_LX = 7 # Linear Executable (LX) +FT_LE = 8 # Linear Executable (LE) +FT_NLM = 9 # Netware Loadable Module (NLM) +FT_COFF = 10 # Common Object File Format (COFF) +FT_PE = 11 # Portable Executable (PE) +FT_OMF = 12 # Object Module Format +FT_SREC = 13 # R-records +FT_ZIP = 14 # ZIP file (this file is never loaded to IDA database) +FT_OMFLIB = 15 # Library of OMF Modules +FT_AR = 16 # ar library +FT_LOADER = 17 # file is loaded using LOADER DLL +FT_ELF = 18 # Executable and Linkable Format (ELF) +FT_W32RUN = 19 # Watcom DOS32 Extender (W32RUN) +FT_AOUT = 20 # Linux a.out (AOUT) +FT_PRC = 21 # PalmPilot program file +FT_EXE = 22 # MS DOS EXE File +FT_COM = 23 # MS DOS COM File +FT_AIXAR = 24 # AIX ar library +FT_MACHO = 25 # Mac OS X Mach-O file +INF_OSTYPE = 34 # short; FLIRT: OS type the program is for +OSTYPE_MSDOS= 0x0001 +OSTYPE_WIN = 0x0002 +OSTYPE_OS2 = 0x0004 +OSTYPE_NETW = 0x0008 +INF_APPTYPE = 36 # short; FLIRT: Application type +APPT_CONSOLE= 0x0001 # console +APPT_GRAPHIC= 0x0002 # graphics +APPT_PROGRAM= 0x0004 # EXE +APPT_LIBRARY= 0x0008 # DLL +APPT_DRIVER = 0x0010 # DRIVER +APPT_1THREAD= 0x0020 # Singlethread +APPT_MTHREAD= 0x0040 # Multithread +APPT_16BIT = 0x0080 # 16 bit application +APPT_32BIT = 0x0100 # 32 bit application +INF_ASMTYPE = 38 # char; target assembler number (0..n) +INF_SPECSEGS = 39 +INF_AF = 40 # uint32; Analysis flags: +AF_CODE = 0x00000001 # Trace execution flow +AF_MARKCODE = 0x00000002 # Mark typical code sequences as code +AF_JUMPTBL = 0x00000004 # Locate and create jump tables +AF_PURDAT = 0x00000008 # Control flow to data segment is ignored +AF_USED = 0x00000010 # Analyze and create all xrefs +AF_UNK = 0x00000020 # Delete instructions with no xrefs -def SetCharPrm (offset, value): - return _invoke_idc_setprm("Char", offset, value) +AF_PROCPTR = 0x00000040 # Create function if data xref data->code32 exists +AF_PROC = 0x00000080 # Create functions if call is present +AF_FTAIL = 0x00000100 # Create function tails +AF_LVAR = 0x00000200 # Create stack variables +AF_STKARG = 0x00000400 # Propagate stack argument information +AF_REGARG = 0x00000800 # Propagate register argument information +AF_TRACE = 0x00001000 # Trace stack pointer +AF_VERSP = 0x00002000 # Perform full SP-analysis. (\ph{verify_sp}) +AF_ANORET = 0x00004000 # Perform 'no-return' analysis +AF_MEMFUNC = 0x00008000 # Try to guess member function types +AF_TRFUNC = 0x00010000 # Truncate functions upon code deletion +AF_STRLIT = 0x00020000 # Create string literal if data xref exists +AF_CHKUNI = 0x00040000 # Check for unicode strings +AF_FIXUP = 0x00080000 # Create offsets and segments using fixup info +AF_DREFOFF = 0x00100000 # Create offset if data xref to seg32 exists +AF_IMMOFF = 0x00200000 # Convert 32bit instruction operand to offset +AF_DATOFF = 0x00400000 # Automatically convert data to offsets -INF_VERSION = 3 # short; Version of database -INF_PROCNAME = 5 # char[8]; Name of current processor -INF_LFLAGS = 13 # char; IDP-dependent flags -LFLG_PC_FPP = 0x01 # decode floating point processor - # instructions? -LFLG_PC_FLAT = 0x02 # Flat model? -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 -INF_DEMNAMES = 14 # char; display demangled names as: -DEMNAM_CMNT = 0 # comments -DEMNAM_NAME = 1 # regular names -DEMNAM_NONE = 2 # don't display -INF_FILETYPE = 15 # short; type of input file (see ida.hpp) -FT_EXE_OLD = 0 # MS DOS EXE File (obsolete) -FT_COM_OLD = 1 # MS DOS COM File (obsolete) -FT_BIN = 2 # Binary File -FT_DRV = 3 # MS DOS Driver -FT_WIN = 4 # New Executable (NE) -FT_HEX = 5 # Intel Hex Object File -FT_MEX = 6 # MOS Technology Hex Object File -FT_LX = 7 # Linear Executable (LX) -FT_LE = 8 # Linear Executable (LE) -FT_NLM = 9 # Netware Loadable Module (NLM) -FT_COFF = 10 # Common Object File Format (COFF) -FT_PE = 11 # Portable Executable (PE) -FT_OMF = 12 # Object Module Format -FT_SREC = 13 # R-records -FT_ZIP = 14 # ZIP file (this file is never loaded to IDA database) -FT_OMFLIB = 15 # Library of OMF Modules -FT_AR = 16 # ar library -FT_LOADER = 17 # file is loaded using LOADER DLL -FT_ELF = 18 # Executable and Linkable Format (ELF) -FT_W32RUN = 19 # Watcom DOS32 Extender (W32RUN) -FT_AOUT = 20 # Linux a.out (AOUT) -FT_PRC = 21 # PalmPilot program file -FT_EXE = 22 # MS DOS EXE File -FT_COM = 23 # MS DOS COM File -FT_AIXAR = 24 # AIX ar library -INF_FCORESIZ = 17 -INF_CORESTART = 21 -INF_OSTYPE = 25 # short; FLIRT: OS type the program is for -OSTYPE_MSDOS = 0x0001 -OSTYPE_WIN = 0x0002 -OSTYPE_OS2 = 0x0004 -OSTYPE_NETW = 0x0008 -INF_APPTYPE = 27 # short; FLIRT: Application type -APPT_CONSOLE = 0x0001 # console -APPT_GRAPHIC = 0x0002 # graphics -APPT_PROGRAM = 0x0004 # EXE -APPT_LIBRARY = 0x0008 # DLL -APPT_DRIVER = 0x0010 # DRIVER -APPT_1THREAD = 0x0020 # Singlethread -APPT_MTHREAD = 0x0040 # Multithread -APPT_16BIT = 0x0080 # 16 bit application -APPT_32BIT = 0x0100 # 32 bit application -INF_START_SP = 29 # long; SP register value at the start of - # program execution -INF_START_AF = 33 # short; Analysis flags: -AF_FIXUP = 0x0001 # Create offsets and segments using fixup info -AF_MARKCODE = 0x0002 # Mark typical code sequences as code -AF_UNK = 0x0004 # Delete instructions with no xrefs -AF_CODE = 0x0008 # Trace execution flow -AF_PROC = 0x0010 # Create functions if call is present -AF_USED = 0x0020 # Analyze and create all xrefs -AF_FLIRT = 0x0040 # Use flirt signatures -AF_PROCPTR = 0x0080 # Create function if data xref data->code32 exists -AF_JFUNC = 0x0100 # Rename jump functions as j_... -AF_NULLSUB = 0x0200 # Rename empty functions as nullsub_... -AF_LVAR = 0x0400 # Create stack variables -AF_TRACE = 0x0800 # Trace stack pointer -AF_ASCII = 0x1000 # Create ascii string if data xref exists -AF_IMMOFF = 0x2000 # Convert 32bit instruction operand to offset -AF_DREFOFF = 0x4000 # Create offset if data xref to seg32 exists -AF_FINAL = 0x8000 # Final pass of analysis -INF_START_IP = 35 # long; IP register value at the start of - # program execution -INF_BEGIN_EA = 39 # long; Linear address of program entry point -INF_MIN_EA = 43 # long; The lowest address used - # in the program -INF_MAX_EA = 47 # long; The highest address used - # in the program - = 1 -INF_OMIN_EA = 51 -INF_OMAX_EA = 55 -INF_LOW_OFF = 59 # long; low limit of voids -INF_HIGH_OFF = 63 # long; high limit of voids -INF_MAXREF = 67 # long; max xref depth -INF_ASCII_BREAK = 71 # char; ASCII line break symbol -INF_WIDE_HIGH_BYTE_FIRST = 72 -INF_INDENT = 73 # char; Indention for instructions -INF_COMMENT = 74 # char; Indention for comments -INF_XREFNUM = 75 # char; Number of references to generate - # = 0 - xrefs wont be generated at all -INF_ENTAB = 76 # char; Use '\t' chars in the output file? -INF_SPECSEGS = 77 -INF_VOIDS = 78 # char; Display void marks? -INF_SHOWAUTO = 80 # char; Display autoanalysis indicator? -INF_AUTO = 81 # char; Autoanalysis is enabled? -INF_BORDER = 82 # char; Generate borders? -INF_NULL = 83 # char; Generate empty lines? -INF_GENFLAGS = 84 # char; General flags: -INFFL_LZERO = 0x01 # generate leading zeroes in numbers -INFFL_LOADIDC = 0x04 # Loading an idc file t -INF_SHOWPREF = 85 # char; Show line prefixes? -INF_PREFSEG = 86 # char; line prefixes with segment name? -INF_ASMTYPE = 87 # char; target assembler number (0..n) -INF_BASEADDR = 88 # long; base paragraph of the program -INF_XREFS = 92 # char; xrefs representation: -SW_SEGXRF = 0x01 # show segments in xrefs? -SW_XRFMRK = 0x02 # show xref type marks? -SW_XRFFNC = 0x04 # show function offsets? -SW_XRFVAL = 0x08 # show xref values? (otherwise-"...") -INF_BINPREF = 93 # short; # of instruction bytes to show - # in line prefix -INF_CMTFLAG = 95 # char; comments: -SW_RPTCMT = 0x01 # show repeatable comments? -SW_ALLCMT = 0x02 # comment all lines? -SW_NOCMT = 0x04 # no comments at all -SW_LINNUM = 0x08 # show source line numbers -SW_MICRO = 0x10 # show microcode (if implemented) -INF_NAMETYPE = 96 # char; dummy names represenation type -NM_REL_OFF = 0 -NM_PTR_OFF = 1 -NM_NAM_OFF = 2 -NM_REL_EA = 3 -NM_PTR_EA = 4 -NM_NAM_EA = 5 -NM_EA = 6 -NM_EA4 = 7 -NM_EA8 = 8 -NM_SHORT = 9 -NM_SERIAL = 10 -INF_SHOWBADS = 97 # char; show bad instructions? - # an instruction is bad if it appears - # in the ash.badworks array +AF_FLIRT = 0x00800000 # Use flirt signatures +AF_SIGCMT = 0x01000000 # Append a signature name comment for recognized anonymous library functions +AF_SIGMLT = 0x02000000 # Allow recognition of several copies of the same function +AF_HFLIRT = 0x04000000 # Automatically hide library functions -INF_PREFFLAG = 98 # char; line prefix type: -PREF_SEGADR = 0x01 # show segment addresses? -PREF_FNCOFF = 0x02 # show function offsets? -PREF_STACK = 0x04 # show stack pointer? +AF_JFUNC = 0x08000000 # Rename jump functions as j_... +AF_NULLSUB = 0x10000000 # Rename empty functions as nullsub_... -INF_PACKBASE = 99 # char; pack database? +AF_DODATA = 0x20000000 # Coagulate data segs at the final pass +AF_DOCODE = 0x40000000 # Coagulate code segs at the final pass +AF_FINAL = 0x80000000 # Final pass of analysis -INF_ASCIIFLAGS = 100 # uchar; ascii flags -ASCF_GEN = 0x01 # generate ASCII names? -ASCF_AUTO = 0x02 # ASCII names have 'autogenerated' bit? -ASCF_SERIAL = 0x04 # generate serial names? -ASCF_COMMENT = 0x10 # generate auto comment for ascii references? -ASCF_SAVECASE = 0x20 # preserve case of ascii strings for identifiers +INF_AF2 = 44 # uint32; Analysis flags 2 -INF_LISTNAMES = 101 # uchar; What names should be included in the list? -LN_NORMAL = 0x01 # normal names -LN_PUBLIC = 0x02 # public names -LN_AUTO = 0x04 # autogenerated names -LN_WEAK = 0x08 # weak names +AF2_DOEH = 0x00000001 # Handle EH information -INF_ASCIIPREF = 102 # char[16];ASCII names prefix -INF_ASCIISERNUM = 118 # ulong; serial number -INF_ASCIIZEROES = 122 # char; leading zeroes -INF_TRIBYTE_ORDER = 125 # char; order of bytes in 3-byte items -TRIBYTE_123 = 0 # regular most significant byte first (big endian) - default -TRIBYTE_132 = 1 -TRIBYTE_213 = 2 -TRIBYTE_231 = 3 -TRIBYTE_312 = 4 -TRIBYTE_321 = 5 # regular least significant byte first (little endian) -INF_MF = 126 # uchar; Byte order: 1==MSB first -INF_ORG = 127 # char; Generate 'org' directives? -INF_ASSUME = 128 # char; Generate 'assume' directives? -INF_CHECKARG = 129 # char; Check manual operands? -INF_START_SS = 130 # long; value of SS at the start -INF_START_CS = 134 # long; value of CS at the start -INF_MAIN = 138 # long; address of main() -INF_SHORT_DN = 142 # long; short form of demangled names -INF_LONG_DN = 146 # long; long form of demangled names - # see demangle.h for definitions -INF_DATATYPES = 150 # long; data types allowed in data carousel -INF_STRTYPE = 154 # long; current ascii string type - # is considered as several bytes: - # low byte: -ASCSTR_TERMCHR = 0 # Character-terminated ASCII string -ASCSTR_C = 0 # C-string, zero terminated -ASCSTR_PASCAL = 1 # Pascal-style ASCII string (length byte) -ASCSTR_LEN2 = 2 # Pascal-style, length is 2 bytes -ASCSTR_UNICODE = 3 # Unicode string -ASCSTR_LEN4 = 4 # Delphi string, length is 4 bytes -ASCSTR_ULEN2 = 5 # Pascal-style Unicode, length is 2 bytes -ASCSTR_ULEN4 = 6 # Pascal-style Unicode, length is 4 bytes +INF_BASEADDR = 48 # uval_t; base paragraph of the program +INF_START_SS = 52 # int32; value of SS at the start +INF_START_CS = 56 # int32; value of CS at the start +INF_START_IP = 60 # ea_t; IP register value at the start of + # program execution +INF_START_EA = 64 # ea_t; Linear address of program entry point +INF_START_SP = 68 # ea_t; SP register value at the start of + # program execution +INF_MAIN = 72 # ea_t; address of main() +INF_MIN_EA = 76 # ea_t; The lowest address used + # in the program +INF_MAX_EA = 80 # ea_t; The highest address used + # in the program - 1 +INF_OMIN_EA = 84 +INF_OMAX_EA = 88 +INF_LOW_OFF = 92 # ea_t; low limit of voids +INF_HIGH_OFF = 96 # ea_t; high limit of voids +INF_MAXREF = 100 # uval_t; max xref depth +INF_START_PRIVRANGE = 104 # uval_t; Range of addresses reserved for internal use. +INF_END_PRIVRANGE = 108 # uval_t; Initially (MAXADDR, MAXADDR+0x100000) -# = 2nd byte - termination chracters for ASCSTR_TERMCHR: -#STRTERM1(strtype) ((strtype>>8)&0xFF) -# = 3d byte: -#STRTERM2(strtype) ((strtype>>16)&0xFF) - # The termination characters are kept in - # the = 2nd and 3d bytes of string type - # if the second termination character is - # '\0', then it is ignored. -INF_AF2 = 158 # ushort; Analysis flags 2 -AF2_JUMPTBL = 0x0001 # Locate and create jump tables -AF2_DODATA = 0x0002 # Coagulate data segs in final pass -AF2_HFLIRT = 0x0004 # Automatically hide library functions -AF2_STKARG = 0x0008 # Propagate stack argument information -AF2_REGARG = 0x0010 # Propagate register argument information -AF2_CHKUNI = 0x0020 # Check for unicode strings -AF2_SIGCMT = 0x0040 # Append a signature name comment for recognized anonymous library functions -AF2_SIGMLT = 0x0080 # Allow recognition of several copies of the same function -AF2_FTAIL = 0x0100 # Create function tails -AF2_DATOFF = 0x0200 # Automatically convert data to offsets -AF2_ANORET = 0x0400 # Perform 'no-return' analysis -AF2_VERSP = 0x0800 # Perform full stack pointer analysis -AF2_DOCODE = 0x1000 # Coagulate code segs at the final pass -AF2_TRFUNC = 0x2000 # Truncate functions upon code deletion -AF2_PURDAT = 0x4000 # Control flow to data segment is ignored -INF_NAMELEN = 160 # ushort; max name length (without zero byte) -INF_MARGIN = 162 # ushort; max length of data lines -INF_LENXREF = 164 # ushort; max length of line with xrefs -INF_LPREFIX = 166 # char[16];prefix of local names - # if a new name has this prefix, - # it will be automatically converted to a local name -INF_LPREFIXLEN = 182 # uchar; length of the lprefix -INF_COMPILER = 183 # uchar; compiler -COMP_MASK = 0x0F # mask to apply to get the pure compiler id -COMP_UNK = 0x00 # Unknown -COMP_MS = 0x01 # Visual C++ -COMP_BC = 0x02 # Borland C++ -COMP_WATCOM = 0x03 # Watcom C++ -COMP_GNU = 0x06 # GNU C++ -COMP_VISAGE = 0x07 # Visual Age C++ -COMP_BP = 0x08 # Delphi +INF_NETDELTA = 112 # sval_t; Delta value to be added to all adresses for mapping to netnodes. + # Initially 0. +# CROSS REFERENCES +INF_XREFNUM = 116 # char; Number of references to generate + # 0 - xrefs won't be generated at all +INF_TYPE_XREFS = 117 # char; Number of references to generate + # in the struct & enum windows + # 0 - xrefs won't be generated at all +INF_REFCMTS = 118 # uchar; number of comment lines to + # generate for refs to ASCII + # string or demangled name + # 0 - such comments won't be + # generated at all +INF_XREFS = 119 # char; xrefs representation: +SW_SEGXRF = 0x01 # show segments in xrefs? +SW_XRFMRK = 0x02 # show xref type marks? +SW_XRFFNC = 0x04 # show function offsets? +SW_XRFVAL = 0x08 # show xref values? (otherwise-"...") -INF_MODEL = 184 # uchar; memory model & calling convention -INF_SIZEOF_INT = 185 # uchar; sizeof(int) -INF_SIZEOF_BOOL = 186 # uchar; sizeof(bool) -INF_SIZEOF_ENUM = 187 # uchar; sizeof(enum) -INF_SIZEOF_ALGN = 188 # uchar; default alignment -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_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 +# NAMES +INF_MAX_AUTONAME_LEN = 120 # ushort; max name length (without zero byte) +INF_NAMETYPE = 122 # char; dummy names represenation type +NM_REL_OFF = 0 +NM_PTR_OFF = 1 +NM_NAM_OFF = 2 +NM_REL_EA = 3 +NM_PTR_EA = 4 +NM_NAM_EA = 5 +NM_EA = 6 +NM_EA4 = 7 +NM_EA8 = 8 +NM_SHORT = 9 +NM_SERIAL = 10 +INF_SHORT_DN = 124 # int32; short form of demangled names +INF_LONG_DN = 128 # int32; long form of demangled names + # see demangle.h for definitions +INF_DEMNAMES = 132 # char; display demangled names as: +DEMNAM_CMNT = 0 # comments +DEMNAM_NAME = 1 # regular names +DEMNAM_NONE = 2 # don't display +DEMNAM_GCC3 = 4 # assume gcc3 names (valid for gnu compiler) +DEMNAM_FIRST= 8 # override type info +INF_LISTNAMES = 133 # uchar; What names should be included in the list? +LN_NORMAL = 0x01 # normal names +LN_PUBLIC = 0x02 # public names +LN_AUTO = 0x04 # autogenerated names +LN_WEAK = 0x08 # weak names + +# DISASSEMBLY LISTING DETAILS +INF_INDENT = 134 # char; Indention for instructions +INF_COMMENT = 135 # char; Indention for comments +INF_MARGIN = 136 # ushort; max length of data lines +INF_LENXREF = 138 # ushort; max length of line with xrefs +INF_OUTFLAGS = 140 # uint32; output flags +OFLG_SHOW_VOID = 0x0002 # Display void marks? +OFLG_SHOW_AUTO = 0x0004 # Display autoanalysis indicator? +OFLG_GEN_NULL = 0x0010 # Generate empty lines? +OFLG_SHOW_PREF = 0x0020 # Show line prefixes? +OFLG_PREF_SEG = 0x0040 # line prefixes with segment name? +OFLG_LZERO = 0x0080 # generate leading zeroes in numbers +OFLG_GEN_ORG = 0x0100 # Generate 'org' directives? +OFLG_GEN_ASSUME= 0x0200 # Generate 'assume' directives? +OFLG_GEN_TRYBLKS = 0x0400 # Generate try/catch directives? +INF_CMTFLAG = 144 # char; comments: +SW_RPTCMT = 0x01 # show repeatable comments? +SW_ALLCMT = 0x02 # comment all lines? +SW_NOCMT = 0x04 # no comments at all +SW_LINNUM = 0x08 # show source line numbers +INF_BORDER = 145 # char; Generate borders? +INF_BINPREF = 146 # short; # of instruction bytes to show + # in line prefix +INF_PREFFLAG = 148 # char; line prefix type: +PREF_SEGADR = 0x01 # show segment addresses? +PREF_FNCOFF = 0x02 # show function offsets? +PREF_STACK = 0x04 # show stack pointer? + +# STRING LITERALS +INF_STRLIT_FLAGS= 149 # uchar; string literal flags +STRF_GEN = 0x01 # generate names? +STRF_AUTO = 0x02 # names have 'autogenerated' bit? +STRF_SERIAL = 0x04 # generate serial names? +STRF_COMMENT = 0x10 # generate auto comment for string references? +STRF_SAVECASE = 0x20 # preserve case of strings for identifiers +INF_STRLIT_BREAK= 150 # char; string literal line break symbol +INF_STRLIT_ZEROES= 151 # char; leading zeroes +INF_STRTYPE = 152 # int32; current ascii string type + # is considered as several bytes: + # low byte: +BPU_1B = 1 +BPU_2B = 2 +BPU_4B = 4 + +STRWIDTH_1B = 0 +STRWIDTH_2B = 1 +STRWIDTH_4B = 2 +STRWIDTH_MASK = 0x03 + +STRLYT_TERMCHR = 0 +STRLYT_PASCAL1 = 1 +STRLYT_PASCAL2 = 2 +STRLYT_PASCAL4 = 3 +STRLYT_MASK = 0xFC +STRLYT_SHIFT = 2 + +STRTYPE_TERMCHR = STRWIDTH_1B|STRLYT_TERMCHR<= 0: - return ida_srarea.SetDefaultRegisterValue(seg, reg, value) + return ida_segregs.set_default_sreg_value(seg, reg, value) else: return False -def SetSegmentType(segea, segtype): +def set_segm_type(segea, segtype): """ Set segment type @@ -3666,7 +3496,7 @@ SEG_COMM = ida_segment.SEG_COMM # * segment with communal definitions SEG_IMEM = ida_segment.SEG_IMEM # internal processor memory & sfr (8051) -def GetSegmentAttr(segea, attr): +def get_segm_attr(segea, attr): """ Get segment attribute @@ -3681,7 +3511,7 @@ def GetSegmentAttr(segea, attr): return _IDC_GetAttr(seg, _SEGATTRMAP, attr) -def SetSegmentAttr(segea, attr, value): +def set_segm_attr(segea, attr, value): """ Set segment attribute @@ -3690,7 +3520,7 @@ def SetSegmentAttr(segea, attr, value): @note: Please note that not all segment attributes are modifiable. Also some of them should be modified using special functions - like SetSegAddressing, etc. + like set_segm_addressing, etc. """ seg = ida_segment.getseg(segea) assert seg, "could not find segment at 0x%x" % segea @@ -3710,17 +3540,17 @@ SEGATTR_PERM = 22 # permissions SEGATTR_BITNESS = 23 # bitness (0: 16, 1: 32, 2: 64 bit segment) # Note: modifying the attribute directly does # not lead to the reanalysis of the segment. - # Using SetSegAddressing() is more correct. + # Using set_segm_addressing() is more correct. SEGATTR_FLAGS = 24 # segment flags -SEGATTR_SEL = 26 # segment selector -SEGATTR_ES = 30 # default ES value -SEGATTR_CS = 34 # default CS value -SEGATTR_SS = 38 # default SS value -SEGATTR_DS = 42 # default DS value -SEGATTR_FS = 46 # default FS value -SEGATTR_GS = 50 # default GS value -SEGATTR_TYPE = 94 # segment type -SEGATTR_COLOR = 95 # segment color +SEGATTR_SEL = 28 # segment selector +SEGATTR_ES = 32 # default ES value +SEGATTR_CS = 36 # default CS value +SEGATTR_SS = 40 # default SS value +SEGATTR_DS = 44 # default DS value +SEGATTR_FS = 48 # default FS value +SEGATTR_GS = 52 # default GS value +SEGATTR_TYPE = 96 # segment type +SEGATTR_COLOR = 100 # segment color # Redefining these for 64-bit if __EA64__: @@ -3732,19 +3562,19 @@ if __EA64__: SEGATTR_PERM = 42 SEGATTR_BITNESS = 43 SEGATTR_FLAGS = 44 - SEGATTR_SEL = 46 - SEGATTR_ES = 54 - SEGATTR_CS = 62 - SEGATTR_SS = 70 - SEGATTR_DS = 78 - SEGATTR_FS = 86 - SEGATTR_GS = 94 - SEGATTR_TYPE = 182 - SEGATTR_COLOR = 183 + SEGATTR_SEL = 48 + SEGATTR_ES = 56 + SEGATTR_CS = 64 + SEGATTR_SS = 72 + SEGATTR_DS = 80 + SEGATTR_FS = 88 + SEGATTR_GS = 96 + SEGATTR_TYPE = 184 + SEGATTR_COLOR = 188 _SEGATTRMAP = { - SEGATTR_START : (True, 'startEA'), - SEGATTR_END : (True, 'endEA'), + SEGATTR_START : (True, 'start_ea'), + SEGATTR_END : (True, 'end_ea'), SEGATTR_ORGBASE : (False, 'orgbase'), SEGATTR_ALIGN : (False, 'align'), SEGATTR_COMB : (False, 'comb'), @@ -3771,7 +3601,7 @@ SFL_LOADER = 0x10 # is the segment created by the loader? SFL_HIDETYPE = 0x20 # hide segment type (do not print it in the listing) -def MoveSegm(ea, to, flags): +def move_segm(ea, to, flags): """ Move a segment to a new address This function moves all information to the new address @@ -3818,17 +3648,17 @@ def rebase_program(delta, flags): return ida_segment.rebase_program(delta, flags) -def SetStorageType(startEA, endEA, stt): +def set_storage_type(start_ea, end_ea, stt): """ Set storage type - @param startEA: starting address - @param endEA: ending address + @param start_ea: starting address + @param end_ea: ending address @param stt: new storage type, one of STT_VA and STT_MM @returns: 0 - ok, otherwise internal error code """ - return ida_bytes.change_storage_type(startEA, endEA, stt) + return ida_bytes.change_storage_type(start_ea, end_ea, stt) STT_VA = 0 # regular storage: virtual arrays, an explicit flag for each byte @@ -3841,8 +3671,8 @@ STT_MM = 1 # memory map: sparse storage. useful for huge objects # Flow types (combine with XREF_USER!): fl_CF = 16 # Call Far fl_CN = 17 # Call Near -fl_JF = 18 # Jump Far -fl_JN = 19 # Jump Near +fl_JF = 18 # jumpto Far +fl_JN = 19 # jumpto Near fl_F = 21 # Ordinary flow XREF_USER = 32 # All user-specified xref types @@ -3850,13 +3680,13 @@ XREF_USER = 32 # All user-specified xref types # Mark exec flow 'from' 'to' -def AddCodeXref(From, To, flowtype): +def add_cref(From, To, flowtype): """ """ return ida_xref.add_cref(From, To, flowtype) -def DelCodeXref(From, To, undef): +def del_cref(From, To, undef): """ Unmark exec flow 'from' 'to' @@ -3869,28 +3699,28 @@ def DelCodeXref(From, To, undef): # The following functions include the ordinary flows: # (the ordinary flow references are returned first) -def Rfirst(From): +def get_first_cref_from(From): """ Get first code xref from 'From' """ return ida_xref.get_first_cref_from(From) -def Rnext(From, current): +def get_next_cref_from(From, current): """ Get next code xref from """ return ida_xref.get_next_cref_from(From, current) -def RfirstB(To): +def get_first_cref_to(To): """ Get first code xref to 'To' """ return ida_xref.get_first_cref_to(To) -def RnextB(To, current): +def get_next_cref_to(To, current): """ Get next code xref to 'To' """ @@ -3898,28 +3728,28 @@ def RnextB(To, current): # The following functions don't take into account the ordinary flows: -def Rfirst0(From): +def get_first_fcref_from(From): """ Get first xref from 'From' """ return ida_xref.get_first_fcref_from(From) -def Rnext0(From, current): +def get_next_fcref_from(From, current): """ Get next xref from """ return ida_xref.get_next_fcref_from(From, current) -def RfirstB0(To): +def get_first_fcref_to(To): """ Get first xref to 'To' """ return ida_xref.get_first_fcref_to(To) -def RnextB0(To, current): +def get_next_fcref_to(To, current): """ Get next xref to 'To' """ @@ -3948,35 +3778,35 @@ def del_dref(From, To): return ida_xref.del_dref(From, To) -def Dfirst(From): +def get_first_dref_from(From): """ Get first data xref from 'From' """ return ida_xref.get_first_dref_from(From) -def Dnext(From, current): +def get_next_dref_from(From, current): """ Get next data xref from 'From' """ return ida_xref.get_next_dref_from(From, current) -def DfirstB(To): +def get_first_dref_to(To): """ Get first data xref to 'To' """ return ida_xref.get_first_dref_to(To) -def DnextB(To, current): +def get_next_dref_to(To, current): """ Get next data xref to 'To' """ return ida_xref.get_next_dref_to(To, current) -def XrefType(): +def get_xref_type(): """ Return type of the last xref obtained by [RD]first/next[B0] functions. @@ -4086,7 +3916,7 @@ def writestr(handle, s): # F U N C T I O N S # ---------------------------------------------------------------------------- -def MakeFunction(start, end = ida_idaapi.BADADDR): +def add_func(start, end = ida_idaapi.BADADDR): """ Create a function @@ -4105,7 +3935,7 @@ def MakeFunction(start, end = ida_idaapi.BADADDR): return ida_funcs.add_func(start, end) -def DelFunction(ea): +def del_func(ea): """ Delete a function @@ -4116,7 +3946,7 @@ def DelFunction(ea): return ida_funcs.del_func(ea) -def SetFunctionEnd(ea, end): +def set_func_end(ea, end): """ Change function end address @@ -4125,10 +3955,10 @@ def SetFunctionEnd(ea, end): @return: !=0 - ok """ - return ida_funcs.func_setend(ea, end) + return ida_funcs.set_func_end(ea, end) -def NextFunction(ea): +def get_next_func(ea): """ Find next function @@ -4142,10 +3972,10 @@ def NextFunction(ea): if not func: return BADADDR else: - return func.startEA + return func.start_ea -def PrevFunction(ea): +def get_prev_func(ea): """ Find previous function @@ -4159,10 +3989,10 @@ def PrevFunction(ea): if not func: return BADADDR else: - return func.startEA + return func.start_ea -def GetFunctionAttr(ea, attr): +def get_func_attr(ea, attr): """ Get a function attribute @@ -4176,7 +4006,7 @@ def GetFunctionAttr(ea, attr): return _IDC_GetAttr(func, _FUNCATTRMAP, attr) if func else BADADDR -def SetFunctionAttr(ea, attr, value): +def set_func_attr(ea, attr, value): """ Set a function attribute @@ -4194,36 +4024,60 @@ def SetFunctionAttr(ea, attr, value): return 0 -FUNCATTR_START = 0 # function start address -FUNCATTR_END = 4 # function end address +FUNCATTR_START = 0 # readonly: function start address +FUNCATTR_END = 4 # readonly: function end address FUNCATTR_FLAGS = 8 # function flags -FUNCATTR_FRAME = 10 # function frame id -FUNCATTR_FRSIZE = 14 # size of local variables -FUNCATTR_FRREGS = 18 # size of saved registers area -FUNCATTR_ARGSIZE = 20 # number of bytes purged from the stack -FUNCATTR_FPD = 24 # frame pointer delta -FUNCATTR_COLOR = 28 # function color code -FUNCATTR_OWNER = 10 # chunk owner (valid only for tail chunks) -FUNCATTR_REFQTY = 14 # number of chunk parents (valid only for tail chunks) +FUNCATTR_FRAME = 12 # readonly: function frame id +FUNCATTR_FRSIZE = 16 # readonly: size of local variables +FUNCATTR_FRREGS = 20 # readonly: size of saved registers area +FUNCATTR_ARGSIZE = 24 # readonly: number of bytes purged from the stack +FUNCATTR_FPD = 28 # frame pointer delta +FUNCATTR_COLOR = 32 # function color code +FUNCATTR_OWNER = 12 # readonly: chunk owner (valid only for tail chunks) +FUNCATTR_REFQTY = 16 # readonly: number of chunk parents (valid only for tail chunks) + +if __X64__: + FUNCATTR_START = 0 + FUNCATTR_END = 4 + FUNCATTR_FLAGS = 8 + FUNCATTR_FRAME = 16 + FUNCATTR_FRSIZE = 20 + FUNCATTR_FRREGS = 24 + FUNCATTR_ARGSIZE = 28 + FUNCATTR_FPD = 32 + FUNCATTR_COLOR = 36 + FUNCATTR_OWNER = 16 + FUNCATTR_REFQTY = 20 # Redefining the constants for 64-bit if __EA64__: - FUNCATTR_START = 0 - FUNCATTR_END = 8 + FUNCATTR_START = 0 + FUNCATTR_END = 8 FUNCATTR_FLAGS = 16 - FUNCATTR_FRAME = 18 - FUNCATTR_FRSIZE = 26 - FUNCATTR_FRREGS = 34 - FUNCATTR_ARGSIZE = 36 - FUNCATTR_FPD = 44 - FUNCATTR_COLOR = 52 - FUNCATTR_OWNER = 18 - FUNCATTR_REFQTY = 26 - + FUNCATTR_FRAME = 20 + FUNCATTR_FRSIZE = 28 + FUNCATTR_FRREGS = 36 + FUNCATTR_ARGSIZE = 40 + FUNCATTR_FPD = 48 + FUNCATTR_COLOR = 56 + FUNCATTR_OWNER = 20 + FUNCATTR_REFQTY = 28 + if __X64__: + FUNCATTR_START = 0 + FUNCATTR_END = 8 + FUNCATTR_FLAGS = 16 + FUNCATTR_FRAME = 24 + FUNCATTR_FRSIZE = 32 + FUNCATTR_FRREGS = 40 + FUNCATTR_ARGSIZE = 48 + FUNCATTR_FPD = 56 + FUNCATTR_COLOR = 64 + FUNCATTR_OWNER = 24 + FUNCATTR_REFQTY = 32 _FUNCATTRMAP = { - FUNCATTR_START : (True, 'startEA'), - FUNCATTR_END : (True, 'endEA'), + FUNCATTR_START : (True, 'start_ea'), + FUNCATTR_END : (True, 'end_ea'), FUNCATTR_FLAGS : (False, 'flags'), FUNCATTR_FRAME : (True, 'frame'), FUNCATTR_FRSIZE : (True, 'frsize'), @@ -4236,7 +4090,7 @@ _FUNCATTRMAP = { } -def GetFunctionFlags(ea): +def get_func_flags(ea): """ Retrieve function flags @@ -4281,12 +4135,12 @@ FUNC_TAIL = ida_funcs.FUNC_TAIL # This is a function tail. # (except FUNC_HIDDEN) -def SetFunctionFlags(ea, flags): +def set_func_flags(ea, flags): """ Change function flags @param ea: any address belonging to the function - @param flags: see GetFunctionFlags() for explanations + @param flags: see get_func_flags() for explanations @return: !=0 - ok """ @@ -4300,7 +4154,7 @@ def SetFunctionFlags(ea, flags): return 1 -def GetFunctionName(ea): +def get_func_name(ea): """ Retrieve function name @@ -4317,7 +4171,7 @@ def GetFunctionName(ea): return name -def GetFunctionCmt(ea, repeatable): +def get_func_cmt(ea, repeatable): """ Retrieve function comment @@ -4340,7 +4194,7 @@ def GetFunctionCmt(ea, repeatable): return comment -def SetFunctionCmt(ea, cmt, repeatable): +def set_func_cmt(ea, cmt, repeatable): """ Set function comment @@ -4357,7 +4211,7 @@ def SetFunctionCmt(ea, cmt, repeatable): return ida_funcs.set_func_cmt(func, cmt, repeatable) -def ChooseFunction(title): +def choose_func(title): """ Ask the user to select a function @@ -4369,10 +4223,10 @@ def ChooseFunction(title): otherwise returns the selected function start address """ f = ida_kernwin.choose_func(title, ida_idaapi.BADADDR) - return BADADDR if f is None else f.startEA + return BADADDR if f is None else f.start_ea -def GetFuncOffset(ea): +def get_func_off_str(ea): """ Convert address to 'funcname+offset' string @@ -4382,10 +4236,12 @@ def GetFuncOffset(ea): formed as 'name+offset' where 'name' is a function name 'offset' is offset within the function else return null string """ - return ida_funcs.a2funcoff(ea) + + flags = ida_name.GNCN_NOCOLOR | ida_name.GNCN_REQFUNC + return ida_name.get_nice_colored_name(ea, flags) -def FindFuncEnd(ea): +def find_func_end(ea): """ Determine a new function boundaries @@ -4395,17 +4251,17 @@ def FindFuncEnd(ea): If a function end cannot be determined, the return BADADDR otherwise return the end address of the new function """ - func = ida_funcs.func_t() + func = ida_funcs.func_t(ea) - res = ida_funcs.find_func_bounds(ea, func, ida_funcs.FIND_FUNC_DEFINE) + res = ida_funcs.find_func_bounds(func, ida_funcs.FIND_FUNC_DEFINE) if res == ida_funcs.FIND_FUNC_UNDEF: return BADADDR else: - return func.endEA + return func.end_ea -def GetFrame(ea): +def get_frame_id(ea): """ Get ID of function frame structure @@ -4423,7 +4279,7 @@ def GetFrame(ea): return None -def GetFrameLvarSize(ea): +def get_frame_lvar_size(ea): """ Get size of local variables in function frame @@ -4433,10 +4289,10 @@ def GetFrameLvarSize(ea): If the function doesn't have a frame, return 0 If the function does't exist, return None """ - return GetFunctionAttr(ea, FUNCATTR_FRSIZE) + return get_func_attr(ea, FUNCATTR_FRSIZE) -def GetFrameRegsSize(ea): +def get_frame_regs_size(ea): """ Get size of saved registers in function frame @@ -4447,10 +4303,10 @@ def GetFrameRegsSize(ea): This value is used as offset for BP (if FUNC_FRAME is set) If the function does't exist, return None """ - return GetFunctionAttr(ea, FUNCATTR_FRREGS) + return get_func_attr(ea, FUNCATTR_FRREGS) -def GetFrameArgsSize(ea): +def get_frame_args_size(ea): """ Get size of arguments in function frame which are purged upon return @@ -4460,10 +4316,10 @@ def GetFrameArgsSize(ea): If the function doesn't have a frame, return 0 If the function does't exist, return -1 """ - return GetFunctionAttr(ea, FUNCATTR_ARGSIZE) + return get_func_attr(ea, FUNCATTR_ARGSIZE) -def GetFrameSize(ea): +def get_frame_size(ea): """ Get full size of function frame @@ -4484,7 +4340,7 @@ def GetFrameSize(ea): return ida_frame.get_frame_size(func) -def MakeFrame(ea, lvsize, frregs, argsize): +def set_frame_size(ea, lvsize, frregs, argsize): """ Make function frame @@ -4510,7 +4366,7 @@ def MakeFrame(ea, lvsize, frregs, argsize): return func.frame -def GetSpd(ea): +def get_spd(ea): """ Get current delta for the stack pointer @@ -4528,7 +4384,7 @@ def GetSpd(ea): return ida_frame.get_spd(func, ea) -def GetSpDiff(ea): +def get_sp_delta(ea): """ Get modification of SP made by the instruction @@ -4547,39 +4403,26 @@ def GetSpDiff(ea): return ida_frame.get_sp_delta(func, ea) -def SetSpDiff(ea, delta): - """ - Setup modification of SP made by the instruction - - @param ea: end address of the instruction - i.e.the last address of the instruction+1 - @param delta: the difference made by the current instruction. - - @return: 1-ok, 0-failed - """ - return ida_frame.add_user_stkpnt(ea, delta) - - # ---------------------------------------------------------------------------- # S T A C K # ---------------------------------------------------------------------------- -def AddAutoStkPnt2(func_ea, ea, delta): +def add_auto_stkpnt(func_ea, ea, delta): """ Add automatical SP register change point @param func_ea: function start @param ea: linear address where SP changes usually this is the end of the instruction which - modifies the stack pointer (cmd.ea+cmd.size) + modifies the stack pointer (insn.ea+insn.size) @param delta: difference between old and new values of SP @return: 1-ok, 0-failed """ pfn = ida_funcs.get_func(func_ea) if not pfn: return 0 - return ida_frame.add_auto_stkpnt2(pfn, ea, delta) + return ida_frame.add_auto_stkpnt(pfn, ea, delta) -def AddUserStkPnt(ea, delta): +def add_user_stkpnt(ea, delta): """ Add user-defined SP register change point. @@ -4590,7 +4433,7 @@ def AddUserStkPnt(ea, delta): """ return ida_frame.add_user_stkpnt(ea, delta); -def DelStkPnt(func_ea, ea): +def del_stkpnt(func_ea, ea): """ Delete SP register change point @@ -4603,7 +4446,7 @@ def DelStkPnt(func_ea, ea): return 0 return ida_frame.del_stkpnt(pfn, ea) -def GetMinSpd(func_ea): +def get_min_spd_ea(func_ea): """ Return the address with the minimal spd (stack pointer delta) If there are no SP change points, then return BADADDR. @@ -4616,7 +4459,7 @@ def GetMinSpd(func_ea): return BADADDR return ida_frame.get_min_spd_ea(pfn) -def RecalcSpd(cur_ea): +def recalc_spd(cur_ea): """ Recalculate SP delta for an instruction that stops execution. @@ -4633,7 +4476,7 @@ def RecalcSpd(cur_ea): # E N T R Y P O I N T S # ---------------------------------------------------------------------------- -def GetEntryPointQty(): +def get_entry_qty(): """ Retrieve number of entry points @@ -4642,7 +4485,7 @@ def GetEntryPointQty(): return ida_entry.get_entry_qty() -def AddEntryPoint(ordinal, ea, name, makecode): +def add_entry(ordinal, ea, name, makecode): """ Add entry point @@ -4661,11 +4504,11 @@ def AddEntryPoint(ordinal, ea, name, makecode): return ida_entry.add_entry(ordinal, ea, name, makecode) -def GetEntryOrdinal(index): +def get_entry_ordinal(index): """ Retrieve entry point ordinal number - @param index: 0..GetEntryPointQty()-1 + @param index: 0..get_entry_qty()-1 @return: 0 if entry point doesn't exist otherwise entry point ordinal @@ -4673,7 +4516,7 @@ def GetEntryOrdinal(index): return ida_entry.get_entry_ordinal(index) -def GetEntryPoint(ordinal): +def get_entry(ordinal): """ Retrieve entry point address @@ -4688,7 +4531,7 @@ def GetEntryPoint(ordinal): return ida_entry.get_entry(ordinal) -def GetEntryName(ordinal): +def get_entry_name(ordinal): """ Retrieve entry point name @@ -4699,7 +4542,7 @@ def GetEntryName(ordinal): return ida_entry.get_entry_name(ordinal) -def RenameEntryPoint(ordinal, name): +def rename_entry(ordinal, name): """ Rename entry point @@ -4714,7 +4557,7 @@ def RenameEntryPoint(ordinal, name): # ---------------------------------------------------------------------------- # F I X U P S # ---------------------------------------------------------------------------- -def GetNextFixupEA(ea): +def get_next_fixup_ea(ea): """ Find next address with fixup information @@ -4726,7 +4569,7 @@ def GetNextFixupEA(ea): return ida_fixup.get_next_fixup_ea(ea) -def GetPrevFixupEA(ea): +def get_prev_fixup_ea(ea): """ Find previous address with fixup information @@ -4738,26 +4581,24 @@ def GetPrevFixupEA(ea): return ida_fixup.get_prev_fixup_ea(ea) -def GetFixupTgtType(ea): +def get_fixup_target_type(ea): """ Get fixup target type @param ea: address to get information about - @return: -1 - no fixup at the specified address - otherwise returns fixup target type: + @return: 0 - no fixup at the specified address + otherwise returns fixup type """ fd = ida_fixup.fixup_data_t() - if not ida_fixup.get_fixup(ea, fd): - return -1 + if not fd.get(ea): + return 0 - return fd.type + return fd.get_type() -FIXUP_MASK = 0xF -FIXUP_OFF8 = 0 # 8-bit offset. -FIXUP_BYTE = FIXUP_OFF8 # 8-bit offset. +FIXUP_OFF8 = 13 # 8-bit offset. FIXUP_OFF16 = 1 # 16-bit offset. FIXUP_SEG16 = 2 # 16-bit base--logical segment base (selector). FIXUP_PTR32 = 3 # 32-bit long pointer (16-bit base:16-bit @@ -4768,96 +4609,108 @@ FIXUP_HI8 = 6 # high 8 bits of 16bit offset FIXUP_HI16 = 7 # high 16 bits of 32bit offset FIXUP_LOW8 = 8 # low 8 bits of 16bit offset FIXUP_LOW16 = 9 # low 16 bits of 32bit offset -FIXUP_REL = 0x10 # fixup is relative to the linear address - # specified in the 3d parameter to set_fixup() -FIXUP_SELFREL = 0x0 # self-relative? - # - disallows the kernel to convert operands - # in the first pass - # - this fixup is used during output - # This type of fixups is not used anymore. - # Anyway you can use it for commenting purposes - # in the loader modules -FIXUP_EXTDEF = 0x20 # target is a location (otherwise - segment) -FIXUP_UNUSED = 0x40 # fixup is ignored by IDA - # - disallows the kernel to convert operands - # - this fixup is not used during output -FIXUP_CREATED = 0x80 # fixup was not present in the input file +FIXUP_OFF64 = 12 # 64-bit offset +FIXUP_CUSTOM = 0x8000 # fixups with this bit are processed by + # processor module/plugin + +def get_fixup_target_flags(ea): + """ + Get fixup target flags + + @param ea: address to get information about + + @return: 0 - no fixup at the specified address + otherwise returns fixup target flags + """ + fd = ida_fixup.fixup_data_t() + + if not fd.get(ea): + return 0 + + return fd.get_flags() -def GetFixupTgtSel(ea): +FIXUPF_REL = 0x1 # fixup is relative to the linear address +FIXUPF_EXTDEF = 0x2 # target is a location (otherwise - segment) +FIXUPF_UNUSED = 0x4 # fixup is ignored by IDA +FIXUPF_CREATED = 0x8 # fixup was not present in the input file + + +def get_fixup_target_sel(ea): """ Get fixup target selector @param ea: address to get information about - @return: -1 - no fixup at the specified address - otherwise returns fixup target selector + @return: BADSEL - no fixup at the specified address + otherwise returns fixup target selector """ fd = ida_fixup.fixup_data_t() - if not ida_fixup.get_fixup(ea, fd): - return -1 + if not fd.get(ea): + return BADSEL return fd.sel -def GetFixupTgtOff(ea): +def get_fixup_target_off(ea): """ Get fixup target offset @param ea: address to get information about - @return: -1 - no fixup at the specified address - otherwise returns fixup target offset + @return: BADADDR - no fixup at the specified address + otherwise returns fixup target offset """ fd = ida_fixup.fixup_data_t() - if not ida_fixup.get_fixup(ea, fd): - return -1 + if not fd.get(ea): + return BADADDR return fd.off -def GetFixupTgtDispl(ea): +def get_fixup_target_dis(ea): """ Get fixup target displacement @param ea: address to get information about - @return: -1 - no fixup at the specified address - otherwise returns fixup target displacement + @return: 0 - no fixup at the specified address + otherwise returns fixup target displacement """ fd = ida_fixup.fixup_data_t() - if not ida_fixup.get_fixup(ea, fd): - return -1 + if not fd.get(ea): + return 0 return fd.displacement -def SetFixup(ea, fixuptype, targetsel, targetoff, displ): +def set_fixup(ea, fixuptype, fixupflags, targetsel, targetoff, displ): """ Set fixup information @param ea: address to set fixup information about - @param fixuptype: fixup type. see GetFixupTgtType() - for possible fixup types. - @param targetsel: target selector - @param targetoff: target offset - @param displ: displacement + @param fixuptype: fixup type. see get_fixup_target_type() + for possible fixup types. + @param fixupflags: fixup flags. see get_fixup_target_flags() + for possible fixup types. + @param targetsel: target selector + @param targetoff: target offset + @param displ: displacement @return: none """ - fd = ida_fixup.fixup_data_t() - fd.type = fixuptype - fd.sel = targetsel - fd.off = targetoff + fd = ida_fixup.fixup_data_t(fixuptype, fixupflags) + fd.sel = targetsel + fd.off = targetoff fd.displacement = displ - ida_fixup.set_fixup(ea, fd) + fd.set(ea) -def DelFixup(ea): +def del_fixup(ea): """ Delete fixup information @@ -4872,7 +4725,7 @@ def DelFixup(ea): # M A R K E D P O S I T I O N S #---------------------------------------------------------------------------- -def MarkPosition(ea, lnnum, x, y, slot, comment): +def put_bookmark(ea, lnnum, x, y, slot, comment): """ Mark position @@ -4887,15 +4740,10 @@ def MarkPosition(ea, lnnum, x, y, slot, comment): @return: None """ - curloc = ida_moves.curloc() - curloc.ea = ea - curloc.lnnum = lnnum - curloc.x = x - curloc.y = y - curloc.mark(slot, comment, comment) + ida_idc.mark_position(ea, lnnum, x, y, slot, comment) -def GetMarkedPos(slot): +def get_bookmark(slot): """ Get marked position @@ -4905,13 +4753,10 @@ def GetMarkedPos(slot): @return: BADADDR - the slot doesn't contain a marked address otherwise returns the marked address """ - curloc = ida_moves.curloc() - intp = ida_pro.int_pointer() - intp.assign(slot) - return curloc.markedpos(intp) + return ida_idc.get_marked_pos(slot) -def GetMarkComment(slot): +def get_bookmark_desc(slot): """ Get marked position comment @@ -4920,15 +4765,14 @@ def GetMarkComment(slot): @return: None if the slot doesn't contain a marked address otherwise returns the marked address comment """ - curloc = ida_moves.curloc() - return curloc.markdesc(slot) + return ida_idc.get_mark_comment(slot) # ---------------------------------------------------------------------------- # S T R U C T U R E S # ---------------------------------------------------------------------------- -def GetStrucQty(): +def get_struc_qty(): """ Get number of defined structure types @@ -4937,7 +4781,7 @@ def GetStrucQty(): return ida_struct.get_struc_qty() -def GetFirstStrucIdx(): +def get_first_struc_idx(): """ Get index of first structure type @@ -4958,19 +4802,19 @@ def GetFirstStrucIdx(): return ida_struct.get_first_struc_idx() -def GetLastStrucIdx(): +def get_last_struc_idx(): """ Get index of last structure type @return: BADADDR if no structure type is defined index of last structure type. - See GetFirstStrucIdx() for the explanation of + See get_first_struc_idx() for the explanation of structure indices and IDs. """ return ida_struct.get_last_struc_idx() -def GetNextStrucIdx(index): +def get_next_struc_idx(index): """ Get index of next structure type @@ -4978,13 +4822,13 @@ def GetNextStrucIdx(index): @return: BADADDR if no (more) structure type is defined index of the next structure type. - See GetFirstStrucIdx() for the explanation of + See get_first_struc_idx() for the explanation of structure indices and IDs. """ return ida_struct.get_next_struc_idx(index) -def GetPrevStrucIdx(index): +def get_prev_struc_idx(index): """ Get index of previous structure type @@ -4992,13 +4836,13 @@ def GetPrevStrucIdx(index): @return: BADADDR if no (more) structure type is defined index of the presiouvs structure type. - See GetFirstStrucIdx() for the explanation of + See get_first_struc_idx() for the explanation of structure indices and IDs. """ return ida_struct.get_prev_struc_idx(index) -def GetStrucIdx(sid): +def get_struc_idx(sid): """ Get structure index by structure ID @@ -5006,13 +4850,13 @@ def GetStrucIdx(sid): @return: BADADDR if bad structure ID is passed otherwise returns structure index. - See GetFirstStrucIdx() for the explanation of + See get_first_struc_idx() for the explanation of structure indices and IDs. """ return ida_struct.get_struc_idx(sid) -def GetStrucId(index): +def get_struc_by_idx(index): """ Get structure ID by structure index @@ -5020,12 +4864,12 @@ def GetStrucId(index): @return: BADADDR if bad structure index is passed otherwise returns structure ID. - @note: See GetFirstStrucIdx() for the explanation of structure indices and IDs. + @note: See get_first_struc_idx() for the explanation of structure indices and IDs. """ return ida_struct.get_struc_by_idx(index) -def GetStrucIdByName(name): +def get_struc_id(name): """ Get structure ID by structure name @@ -5037,7 +4881,7 @@ def GetStrucIdByName(name): return ida_struct.get_struc_id(name) -def GetStrucName(sid): +def get_struc_name(sid): """ Get structure type name @@ -5049,7 +4893,7 @@ def GetStrucName(sid): return ida_struct.get_struc_name(sid) -def GetStrucComment(sid, repeatable): +def get_struc_cmt(sid, repeatable): """ Get structure type comment @@ -5063,7 +4907,7 @@ def GetStrucComment(sid, repeatable): return ida_struct.get_struc_cmt(sid, repeatable) -def GetStrucSize(sid): +def get_struc_size(sid): """ Get size of a structure @@ -5075,7 +4919,7 @@ def GetStrucSize(sid): return ida_struct.get_struc_size(sid) -def GetMemberQty(sid): +def get_member_qty(sid): """ Get number of members of a structure @@ -5092,7 +4936,7 @@ def GetMemberQty(sid): return -1 if not s else s.memqty -def GetMemberId(sid, member_offset): +def get_member_id(sid, member_offset): """ @param sid: structure type ID @param member_offset:. The offset can be @@ -5116,7 +4960,7 @@ def GetMemberId(sid, member_offset): return m.id -def GetStrucPrevOff(sid, offset): +def get_prev_offset(sid, offset): """ Get previous offset in a structure @@ -5145,7 +4989,7 @@ def GetStrucPrevOff(sid, offset): return ida_struct.get_struc_prev_offset(s, offset) -def GetStrucNextOff(sid, offset): +def get_next_offset(sid, offset): """ Get next offset in a structure @@ -5171,7 +5015,7 @@ def GetStrucNextOff(sid, offset): return -1 if not s else ida_struct.get_struc_next_offset(s, offset) -def GetFirstMember(sid): +def get_first_member(sid): """ Get offset of the first member of a structure @@ -5196,7 +5040,7 @@ def GetFirstMember(sid): return ida_struct.get_struc_first_offset(s) -def GetLastMember(sid): +def get_last_member(sid): """ Get offset of the last member of a structure @@ -5221,7 +5065,7 @@ def GetLastMember(sid): return ida_struct.get_struc_last_offset(s) -def GetMemberOffset(sid, member_name): +def get_member_offset(sid, member_name): """ Get offset of a member of a structure by the member name @@ -5247,7 +5091,7 @@ def GetMemberOffset(sid, member_name): return m.get_soff() -def GetMemberName(sid, member_offset): +def get_member_name(sid, member_offset): """ Get name of a member of a structure @@ -5273,7 +5117,7 @@ def GetMemberName(sid, member_offset): return ida_struct.get_member_name(m.id) -def GetMemberComment(sid, member_offset, repeatable): +def get_member_cmt(sid, member_offset, repeatable): """ Get comment of a member @@ -5301,7 +5145,7 @@ def GetMemberComment(sid, member_offset, repeatable): return ida_struct.get_member_cmt(m.id, repeatable) -def GetMemberSize(sid, member_offset): +def get_member_size(sid, member_offset): """ Get size of a member @@ -5328,7 +5172,7 @@ def GetMemberSize(sid, member_offset): return ida_struct.get_member_size(m) -def GetMemberFlag(sid, member_offset): +def get_member_flag(sid, member_offset): """ Get type of a member @@ -5354,7 +5198,7 @@ def GetMemberFlag(sid, member_offset): return -1 if not m else m.flag -def GetMemberStrId(sid, member_offset): +def get_member_strid(sid, member_offset): """ Get structure id of a member @@ -5384,7 +5228,7 @@ def GetMemberStrId(sid, member_offset): return -1 -def IsUnion(sid): +def is_union(sid): """ Is a structure a union? @@ -5402,7 +5246,7 @@ def IsUnion(sid): return s.is_union() -def AddStrucEx(index, name, is_union): +def add_struc(index, name, is_union): """ Define a new structure type @@ -5412,7 +5256,7 @@ def AddStrucEx(index, name, is_union): structures will be incremented, freeing the specifed index. If index is == -1, then the biggest index number will be used. - See GetFirstStrucIdx() for the explanation of + See get_first_struc_idx() for the explanation of structure indices and IDs. @param name: name of the new structure type. @param is_union: 0: structure @@ -5429,7 +5273,7 @@ def AddStrucEx(index, name, is_union): return ida_struct.add_struc(index, name, is_union) -def DelStruc(sid): +def del_struc(sid): """ Delete a structure type @@ -5448,7 +5292,7 @@ def DelStruc(sid): return ida_struct.del_struc(s) -def SetStrucIdx(sid, index): +def set_struc_idx(sid, index): """ Change structure index @@ -5457,7 +5301,7 @@ def SetStrucIdx(sid, index): @return: != 0 - ok - @note: See GetFirstStrucIdx() for the explanation of + @note: See get_first_struc_idx() for the explanation of structure indices and IDs. """ s = ida_struct.get_struc(sid) @@ -5467,7 +5311,7 @@ def SetStrucIdx(sid, index): return ida_struct.set_struc_idx(s, index) -def SetStrucName(sid, name): +def set_struc_name(sid, name): """ Change structure name @@ -5479,7 +5323,7 @@ def SetStrucName(sid, name): return ida_struct.set_struc_name(sid, name) -def SetStrucComment(sid, comment, repeatable): +def set_struc_cmt(sid, comment, repeatable): """ Change structure comment @@ -5492,7 +5336,7 @@ def SetStrucComment(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): +def add_struc_member(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, reftype=REF_OFF32): """ Add structure member @@ -5503,11 +5347,11 @@ def AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, @param flag: type of the new member. Should be one of FF_BYTE..FF_PACKREAL (see above) combined with FF_DATA @param typeid: if isStruc(flag) then typeid specifies the structure id for the member - if isOff0(flag) then typeid specifies the offset base. - if isASCII(flag) then typeid specifies the string type (ASCSTR_...). - if isStroff(flag) then typeid specifies the structure id - if isEnum(flag) then typeid specifies the enum id - if isCustom(flags) then typeid specifies the dtid and fid: dtid|(fid<<16) + if is_off0(flag) then typeid specifies the offset base. + if is_strlit(flag) then typeid specifies the string type (STRTYPE_...). + if is_stroff(flag) then typeid specifies the structure id + if is_enum(flag) then typeid specifies the enum id + if is_custom(flags) then typeid specifies the dtid and fid: dtid|(fid<<16) Otherwise typeid should be -1. @param nbytes: number of bytes in the new member @@ -5516,17 +5360,17 @@ def AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, @param tdelta: offset target delta. usually 0 @param reftype: see REF_... definitions - @note: The remaining arguments are allowed only if isOff0(flag) and you want + @note: The remaining arguments are allowed only if is_off0(flag) and you want to specify a complex offset expression @return: 0 - ok, otherwise error code (one of STRUC_ERROR_*) """ - if isOff0(flag): - return Eval('AddStrucMember(%d, "%s", %d, %d, %d, %d, %d, %d, %d);' % (sid, ida_kernwin.str2user(name), offset, flag, typeid, nbytes, + if is_off0(flag): + return eval_idc('add_struc_member(%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, ida_kernwin.str2user(name), offset, flag, typeid, nbytes)) + return eval_idc('add_struc_member(%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) @@ -5538,7 +5382,7 @@ STRUC_ERROR_MEMBER_UNIVAR = -6 # unions can't have variable sized members STRUC_ERROR_MEMBER_VARLAST = -7 # variable sized member should be the last member in the structure -def DelStrucMember(sid, member_offset): +def del_struc_member(sid, member_offset): """ Delete structure member @@ -5558,7 +5402,7 @@ def DelStrucMember(sid, member_offset): return ida_struct.del_struc_member(s, member_offset) -def SetMemberName(sid, member_offset, name): +def set_member_name(sid, member_offset, name): """ Change structure member name @@ -5575,7 +5419,7 @@ def SetMemberName(sid, 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): +def set_member_type(sid, member_offset, flag, typeid, nitems, target=-1, tdelta=0, reftype=REF_OFF32): """ Change structure member type @@ -5584,11 +5428,11 @@ def SetMemberType(sid, member_offset, flag, typeid, nitems, target=-1, tdelta=0, @param flag: new type of the member. Should be one of FF_BYTE..FF_PACKREAL (see above) combined with FF_DATA @param typeid: if isStruc(flag) then typeid specifies the structure id for the member - if isOff0(flag) then typeid specifies the offset base. - if isASCII(flag) then typeid specifies the string type (ASCSTR_...). - if isStroff(flag) then typeid specifies the structure id - if isEnum(flag) then typeid specifies the enum id - if isCustom(flags) then typeid specifies the dtid and fid: dtid|(fid<<16) + if is_off0(flag) then typeid specifies the offset base. + if is_strlit(flag) then typeid specifies the string type (STRTYPE_...). + if is_stroff(flag) then typeid specifies the structure id + if is_enum(flag) then typeid specifies the enum id + if is_custom(flags) then typeid specifies the dtid and fid: dtid|(fid<<16) Otherwise typeid should be -1. @param nitems: number of items in the member @@ -5597,19 +5441,19 @@ def SetMemberType(sid, member_offset, flag, typeid, nitems, target=-1, tdelta=0, @param tdelta: offset target delta. usually 0 @param reftype: see REF_... definitions - @note: The remaining arguments are allowed only if isOff0(flag) and you want + @note: The remaining arguments are allowed only if is_off0(flag) and you want to specify a complex offset expression @return: !=0 - ok. """ - if isOff0(flag): - return Eval('SetMemberType(%d, %d, %d, %d, %d, %d, %d, %d);' % (sid, member_offset, flag, typeid, nitems, + if is_off0(flag): + return eval_idc('set_member_type(%d, %d, %d, %d, %d, %d, %d, %d);' % (sid, member_offset, flag, typeid, nitems, target, tdelta, reftype)) else: - return Eval('SetMemberType(%d, %d, %d, %d, %d);' % (sid, member_offset, flag, typeid, nitems)) + return eval_idc('set_member_type(%d, %d, %d, %d, %d);' % (sid, member_offset, flag, typeid, nitems)) -def SetMemberComment(sid, member_offset, comment, repeatable): +def set_member_cmt(sid, member_offset, comment, repeatable): """ Change structure member comment @@ -5632,7 +5476,7 @@ def SetMemberComment(sid, member_offset, comment, repeatable): return ida_struct.set_member_cmt(m, comment, repeatable) -def ExpandStruc(sid, offset, delta, recalc): +def expand_struc(sid, offset, delta, recalc): """ Expand or shrink a structure type @param id: structure type ID @@ -5649,7 +5493,7 @@ def ExpandStruc(sid, offset, delta, recalc): return ida_struct.expand_struc(s, offset, delta, recalc) -def GetFchunkAttr(ea, attr): +def get_fchunk_attr(ea, attr): """ Get a function chunk attribute @@ -5662,7 +5506,7 @@ def GetFchunkAttr(ea, attr): return _IDC_GetAttr(func, _FUNCATTRMAP, attr) if func else BADADDR -def SetFchunkAttr(ea, attr, value): +def set_fchunk_attr(ea, attr, value): """ Set a function chunk attribute @@ -5680,19 +5524,19 @@ def SetFchunkAttr(ea, attr, value): return 0 -def GetFchunkReferer(ea, idx): +def get_fchunk_referer(ea, idx): """ Get a function chunk referer @param ea: any address in the chunk - @param idx: referer index (0..GetFchunkAttr(FUNCATTR_REFQTY)) + @param idx: referer index (0..get_fchunk_attr(FUNCATTR_REFQTY)) @return: referer address or BADADDR """ return ida_funcs.get_fchunk_referer(ea, idx) -def NextFchunk(ea): +def get_next_fchunk(ea): """ Get next function chunk @@ -5705,12 +5549,12 @@ def NextFchunk(ea): func = ida_funcs.get_next_fchunk(ea) if func: - return func.startEA + return func.start_ea else: return BADADDR -def PrevFchunk(ea): +def get_prev_fchunk(ea): """ Get previous function chunk @@ -5723,12 +5567,12 @@ def PrevFchunk(ea): func = ida_funcs.get_prev_fchunk(ea) if func: - return func.startEA + return func.start_ea else: return BADADDR -def AppendFchunk(funcea, ea1, ea2): +def append_func_tail(funcea, ea1, ea2): """ Append a function chunk to the function @@ -5748,7 +5592,7 @@ def AppendFchunk(funcea, ea1, ea2): return ida_funcs.append_func_tail(func, ea1, ea2) -def RemoveFchunk(funcea, tailea): +def remove_fchunk(funcea, tailea): """ Remove a function chunk from the function @@ -5765,7 +5609,7 @@ def RemoveFchunk(funcea, tailea): return ida_funcs.remove_func_tail(func, tailea) -def SetFchunkOwner(tailea, funcea): +def set_tail_owner(tailea, funcea): """ Change the function chunk owner @@ -5784,7 +5628,7 @@ def SetFchunkOwner(tailea, funcea): return ida_funcs.set_tail_owner(tail, funcea) -def FirstFuncFchunk(funcea): +def first_func_chunk(funcea): """ Get the first function chunk of the specified function @@ -5797,12 +5641,12 @@ def FirstFuncFchunk(funcea): func = ida_funcs.get_func(funcea) fci = ida_funcs.func_tail_iterator_t(func, funcea) if fci.main(): - return fci.chunk().startEA + return fci.chunk().start_ea else: return BADADDR -def NextFuncFchunk(funcea, tailea): +def next_func_chunk(funcea, tailea): """ Get the next function chunk of the specified function @@ -5821,8 +5665,8 @@ def NextFuncFchunk(funcea, tailea): # Iterate and try to find the current chunk found = False while True: - if fci.chunk().startEA <= tailea and \ - fci.chunk().endEA > tailea: + if fci.chunk().start_ea <= tailea and \ + fci.chunk().end_ea > tailea: found = True break if not fci.next(): @@ -5830,7 +5674,7 @@ def NextFuncFchunk(funcea, tailea): # Return the next chunk, if there is one if found and fci.next(): - return fci.chunk().startEA + return fci.chunk().start_ea else: return BADADDR @@ -5838,7 +5682,7 @@ def NextFuncFchunk(funcea, tailea): # ---------------------------------------------------------------------------- # E N U M S # ---------------------------------------------------------------------------- -def GetEnumQty(): +def get_enum_qty(): """ Get number of enum types @@ -5847,29 +5691,29 @@ def GetEnumQty(): return ida_enum.get_enum_qty() -def GetnEnum(idx): +def getn_enum(idx): """ Get ID of the specified enum by its serial number - @param idx: number of enum (0..GetEnumQty()-1) + @param idx: number of enum (0..get_enum_qty()-1) @return: ID of enum or -1 if error """ return ida_enum.getn_enum(idx) -def GetEnumIdx(enum_id): +def get_enum_idx(enum_id): """ Get serial number of enum by its ID @param enum_id: ID of enum - @return: (0..GetEnumQty()-1) or -1 if error + @return: (0..get_enum_qty()-1) or -1 if error """ return ida_enum.get_enum_idx(enum_id) -def GetEnum(name): +def get_enum(name): """ Get enum ID by the name of enum @@ -5881,7 +5725,7 @@ def GetEnum(name): return ida_enum.get_enum(name) -def GetEnumName(enum_id): +def get_enum_name(enum_id): """ Get name of enum @@ -5892,7 +5736,7 @@ def GetEnumName(enum_id): return ida_enum.get_enum_name(enum_id) -def GetEnumCmt(enum_id, repeatable): +def get_enum_cmt(enum_id, repeatable): """ Get comment of enum @@ -5905,7 +5749,7 @@ def GetEnumCmt(enum_id, repeatable): return ida_enum.get_enum_cmt(enum_id, repeatable) -def GetEnumSize(enum_id): +def get_enum_size(enum_id): """ Get size of enum @@ -5917,21 +5761,19 @@ def GetEnumSize(enum_id): return ida_enum.get_enum_size(enum_id) -def GetEnumWidth(enum_id): +def get_enum_width(enum_id): """ Get width of enum elements @param enum_id: ID of enum - @return: log2(size of enum elements in bytes)+1 - possible returned values are 1..7 - 1-1byte,2-2bytes,3-4bytes,4-8bytes,etc - Returns 0 if enum_id is bad or the width is unknown. + @return: size of enum elements in bytes + (0 if enum_id is bad or the width is unknown). """ return ida_enum.get_enum_width(enum_id) -def GetEnumFlag(enum_id): +def get_enum_flag(enum_id): """ Get flag of enum @@ -5946,7 +5788,7 @@ def GetEnumFlag(enum_id): return ida_enum.get_enum_flag(enum_id) -def GetConstByName(name): +def get_enum_member_by_name(name): """ Get member of enum - a symbolic constant ID @@ -5957,7 +5799,7 @@ def GetConstByName(name): return ida_enum.get_enum_member_by_name(name) -def GetConstValue(const_id): +def get_enum_member_value(const_id): """ Get value of symbolic constant @@ -5968,7 +5810,7 @@ def GetConstValue(const_id): return ida_enum.get_enum_member_value(const_id) -def GetConstBmask(const_id): +def get_enum_member_bmask(const_id): """ Get bit mask of symbolic constant @@ -5980,7 +5822,7 @@ def GetConstBmask(const_id): return ida_enum.get_enum_member_bmask(const_id) -def GetConstEnum(const_id): +def get_enum_member_enum(const_id): """ Get id of enum by id of constant @@ -5992,16 +5834,16 @@ def GetConstEnum(const_id): return ida_enum.get_enum_member_enum(const_id) -def GetConstEx(enum_id, value, serial, bmask): +def get_enum_member(enum_id, value, serial, bmask): """ Get id of constant @param enum_id: id of enum @param value: value of constant @param serial: serial number of the constant in the - enumeration. See OpEnumEx() for details. + enumeration. See op_enum() for details. @param bmask: bitmask of the constant - ordinary enums accept only -1 as a bitmask + ordinary enums accept only ida_enum.DEFMASK as a bitmask @return: id of constant or -1 if error """ @@ -6010,7 +5852,7 @@ def GetConstEx(enum_id, value, serial, bmask): return ida_enum.get_enum_member(enum_id, value, serial, bmask) -def GetFirstBmask(enum_id): +def get_first_bmask(enum_id): """ Get first bitmask in the enum (bitfield) @@ -6024,7 +5866,7 @@ def GetFirstBmask(enum_id): return ida_enum.get_first_bmask(enum_id) -def GetLastBmask(enum_id): +def get_last_bmask(enum_id): """ Get last bitmask in the enum (bitfield) @@ -6036,7 +5878,7 @@ def GetLastBmask(enum_id): return ida_enum.get_last_bmask(enum_id) -def GetNextBmask(enum_id, value): +def get_next_bmask(enum_id, value): """ Get next bitmask in the enum (bitfield) @@ -6051,7 +5893,7 @@ def GetNextBmask(enum_id, value): return ida_enum.get_next_bmask(enum_id, value) -def GetPrevBmask(enum_id, value): +def get_prev_bmask(enum_id, value): """ Get prev bitmask in the enum (bitfield) @@ -6065,7 +5907,7 @@ def GetPrevBmask(enum_id, value): return ida_enum.get_prev_bmask(enum_id, value) -def GetBmaskName(enum_id, bmask): +def get_bmask_name(enum_id, bmask): """ Get bitmask name (only for bitfields) @@ -6079,7 +5921,7 @@ def GetBmaskName(enum_id, bmask): return ida_enum.get_bmask_name(enum_id, bmask) -def GetBmaskCmt(enum_id, bmask, repeatable): +def get_bmask_cmt(enum_id, bmask, repeatable): """ Get bitmask comment (only for bitfields) @@ -6094,7 +5936,7 @@ def GetBmaskCmt(enum_id, bmask, repeatable): return ida_enum.get_bmask_cmt(enum_id, bmask, repeatable) -def SetBmaskName(enum_id, bmask, name): +def set_bmask_name(enum_id, bmask, name): """ Set bitmask name (only for bitfields) @@ -6109,7 +5951,7 @@ def SetBmaskName(enum_id, bmask, name): return ida_enum.set_bmask_name(enum_id, bmask, name) -def SetBmaskCmt(enum_id, bmask, cmt, repeatable): +def set_bmask_cmt(enum_id, bmask, cmt, repeatable): """ Set bitmask comment (only for bitfields) @@ -6125,14 +5967,14 @@ def SetBmaskCmt(enum_id, bmask, cmt, repeatable): return ida_enum.set_bmask_cmt(enum_id, bmask, cmt, repeatable) -def GetFirstConst(enum_id, bmask): +def get_first_enum_member(enum_id, bmask): """ Get first constant in the enum @param enum_id: id of enum - @param bmask: bitmask of the constant (ordinary enums accept only -1 as a bitmask) + @param bmask: bitmask of the constant (ordinary enums accept only ida_enum.DEFMASK as a bitmask) - @return: value of constant or -1 no constants are defined + @return: value of constant or idaapi.BADNODE no constants are defined All constants are sorted by their values as unsigned longs. """ if bmask < 0: @@ -6140,14 +5982,14 @@ def GetFirstConst(enum_id, bmask): return ida_enum.get_first_enum_member(enum_id, bmask) -def GetLastConst(enum_id, bmask): +def get_last_enum_member(enum_id, bmask): """ Get last constant in the enum @param enum_id: id of enum - @param bmask: bitmask of the constant (ordinary enums accept only -1 as a bitmask) + @param bmask: bitmask of the constant (ordinary enums accept only ida_enum.DEFMASK as a bitmask) - @return: value of constant or -1 no constants are defined + @return: value of constant or idaapi.BADNODE no constants are defined All constants are sorted by their values as unsigned longs. """ @@ -6156,16 +5998,16 @@ def GetLastConst(enum_id, bmask): return ida_enum.get_last_enum_member(enum_id, bmask) -def GetNextConst(enum_id, value, bmask): +def get_next_enum_member(enum_id, value, bmask): """ Get next constant in the enum @param enum_id: id of enum - @param bmask: bitmask of the constant ordinary enums accept only -1 as a bitmask + @param bmask: bitmask of the constant ordinary enums accept only ida_enum.DEFMASK as a bitmask @param value: value of the current constant @return: value of a constant with value higher than the specified - value. -1 no such constants exist. + value. idaapi.BADNODE no such constants exist. All constants are sorted by their values as unsigned longs. """ if bmask < 0: @@ -6173,17 +6015,17 @@ def GetNextConst(enum_id, value, bmask): return ida_enum.get_next_enum_member(enum_id, value, bmask) -def GetPrevConst(enum_id, value, bmask): +def get_prev_enum_member(enum_id, value, bmask): """ Get prev constant in the enum @param enum_id: id of enum @param bmask : bitmask of the constant - ordinary enums accept only -1 as a bitmask + ordinary enums accept only ida_enum.DEFMASK as a bitmask @param value: value of the current constant @return: value of a constant with value lower than the specified - value. -1 no such constants exist. + value. idaapi.BADNODE no such constants exist. All constants are sorted by their values as unsigned longs. """ if bmask < 0: @@ -6191,7 +6033,7 @@ def GetPrevConst(enum_id, value, bmask): return ida_enum.get_prev_enum_member(enum_id, value, bmask) -def GetConstName(const_id): +def get_enum_member_name(const_id): """ Get name of a constant @@ -6207,7 +6049,7 @@ def GetConstName(const_id): return name -def GetConstCmt(const_id, repeatable): +def get_enum_member_cmt(const_id, repeatable): """ Get comment of a constant @@ -6224,7 +6066,7 @@ def GetConstCmt(const_id, repeatable): return cmt -def AddEnum(idx, name, flag): +def add_enum(idx, name, flag): """ Add a new enum type @@ -6235,7 +6077,7 @@ def AddEnum(idx, name, flag): serial numbers incremented (in other words, the new enum is put in the middle of the list of enums). - If idx >= GetEnumQty() or idx == -1 + If idx >= get_enum_qty() or idx == idaapi.BADNODE then the new enum is created at the end of the list of enums. @@ -6250,7 +6092,7 @@ def AddEnum(idx, name, flag): return ida_enum.add_enum(idx, name, flag) -def DelEnum(enum_id): +def del_enum(enum_id): """ Delete enum type @@ -6261,7 +6103,7 @@ def DelEnum(enum_id): ida_enum.del_enum(enum_id) -def SetEnumIdx(enum_id, idx): +def set_enum_idx(enum_id, idx): """ Give another serial number to a enum @@ -6273,7 +6115,7 @@ def SetEnumIdx(enum_id, idx): serial numbers incremented (in other words, the new enum is put in the middle of the list of enums). - If idx >= GetEnumQty() then the enum is + If idx >= get_enum_qty() then the enum is moved to the end of the list of enums. @return: comment string @@ -6281,7 +6123,7 @@ def SetEnumIdx(enum_id, idx): return ida_enum.set_enum_idx(enum_id, idx) -def SetEnumName(enum_id, name): +def set_enum_name(enum_id, name): """ Rename enum @@ -6293,7 +6135,7 @@ def SetEnumName(enum_id, name): return ida_enum.set_enum_name(enum_id, name) -def SetEnumCmt(enum_id, cmt, repeatable): +def set_enum_cmt(enum_id, cmt, repeatable): """ Set comment of enum @@ -6308,7 +6150,7 @@ def SetEnumCmt(enum_id, cmt, repeatable): return ida_enum.set_enum_cmt(enum_id, cmt, repeatable) -def SetEnumFlag(enum_id, flag): +def set_enum_flag(enum_id, flag): """ Set flag of enum @@ -6321,7 +6163,7 @@ def SetEnumFlag(enum_id, flag): return ida_enum.set_enum_flag(enum_id, flag) -def SetEnumBf(enum_id, flag): +def set_enum_bf(enum_id, flag): """ Set bitfield property of enum @@ -6335,21 +6177,19 @@ def SetEnumBf(enum_id, flag): return ida_enum.set_enum_bf(enum_id, flag) -def SetEnumWidth(enum_id, width): +def set_enum_width(enum_id, width): """ Set width of enum elements @param enum_id: id of enum - @param width: element width in bytes - allowed values: 0-unknown - or 1..7: (log2 of the element size)+1 + @param width: element width in bytes (0-unknown) @return: 1-ok, 0-failed """ return ida_enum.set_enum_width(enum_id, width) -def IsBitfield(enum_id): +def is_bf(enum_id): """ Is enum a bitfield? @@ -6360,7 +6200,7 @@ def IsBitfield(enum_id): return ida_enum.is_bf(enum_id) -def AddConstEx(enum_id, name, value, bmask): +def add_enum_member(enum_id, name, value, bmask): """ Add a member of enum - a symbolic constant @@ -6368,7 +6208,7 @@ def AddConstEx(enum_id, name, value, bmask): @param name: name of symbolic constant. Must be unique in the program. @param value: value of symbolic constant. @param bmask: bitmask of the constant - ordinary enums accept only -1 as a bitmask + ordinary enums accept only ida_enum.DEFMASK as a bitmask all bits set in value should be set in bmask too @return: 0-ok, otherwise error code (one of ENUM_MEMBER_ERROR_*) @@ -6385,16 +6225,16 @@ 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): +def del_enum_member(enum_id, value, serial, bmask): """ Delete a member of enum - a symbolic constant @param enum_id: id of enum @param value: value of symbolic constant. @param serial: serial number of the constant in the - enumeration. See OpEnumEx() for for details. + enumeration. See op_enum() for for details. @param bmask: bitmask of the constant ordinary enums accept - only -1 as a bitmask + only ida_enum.DEFMASK as a bitmask @return: 1-ok, 0-failed """ @@ -6403,7 +6243,7 @@ def DelConstEx(enum_id, value, serial, bmask): return ida_enum.del_enum_member(enum_id, value, serial, bmask) -def SetConstName(const_id, name): +def set_enum_member_name(const_id, name): """ Rename a member of enum - a symbolic constant @@ -6415,7 +6255,7 @@ def SetConstName(const_id, name): return ida_enum.set_enum_member_name(const_id, name) -def SetConstCmt(const_id, cmt, repeatable): +def set_enum_member_cmt(const_id, cmt, repeatable): """ Set a comment of a symbolic constant @@ -6477,12 +6317,12 @@ class __dummy_netnode(object): def supval(self, *args): return 0 def altdel(self, *args): return 0 def supdel(self, *args): return 0 - def alt1st(self, *args): return -1 - def sup1st(self, *args): return -1 + def altfirst(self, *args): return -1 + def supfirst(self, *args): return -1 def altlast(self, *args): return -1 def suplast(self, *args): return -1 - def altnxt(self, *args): return -1 - def supnxt(self, *args): return -1 + def altnext(self, *args): return -1 + def supnext(self, *args): return -1 def altprev(self, *args): return -1 def supprev(self, *args): return -1 def hashset(self, *args): return 0 @@ -6493,8 +6333,8 @@ class __dummy_netnode(object): def hashset_buf(self, *args): return 0 def hashval_long(self, *args): return 0 def hashdel(self, *args): return 0 - def hash1st(self, *args): return 0 - def hashnxt(self, *args): return 0 + def hashfirst(self, *args): return 0 + def hashnext(self, *args): return 0 def hashprev(self, *args): return 0 def hashlast(self, *args): return 0 __dummy_netnode.instance = __dummy_netnode() @@ -6514,7 +6354,7 @@ def __GetArrayById(array_id): """ try: node = ida_netnode.netnode(array_id) - nodename = node.name() + nodename = node.get_name() if nodename is None or not nodename.startswith(_IDC_ARRAY_PREFIX): return __dummy_netnode.instance else: @@ -6523,7 +6363,7 @@ def __GetArrayById(array_id): return __dummy_netnode.instance -def CreateArray(name): +def create_array(name): """ Create array. @@ -6539,7 +6379,7 @@ def CreateArray(name): return node.index() -def GetArrayId(name): +def get_array_id(name): """ Get array array_id, by name. @@ -6551,7 +6391,7 @@ def GetArrayId(name): return __l2m1(ida_netnode.netnode(_IDC_ARRAY_PREFIX + name, 0, False).index()) -def RenameArray(array_id, newname): +def rename_array(array_id, newname): """ Rename array, by its ID. @@ -6563,7 +6403,7 @@ def RenameArray(array_id, newname): return __GetArrayById(array_id).rename(_IDC_ARRAY_PREFIX + newname) == 1 -def DeleteArray(array_id): +def delete_array(array_id): """ Delete array, by its ID. @@ -6572,7 +6412,7 @@ def DeleteArray(array_id): __GetArrayById(array_id).kill() -def SetArrayLong(array_id, idx, value): +def set_array_long(array_id, idx, value): """ Sets the long value of an array element. @@ -6585,7 +6425,7 @@ def SetArrayLong(array_id, idx, value): return __GetArrayById(array_id).altset(idx, value) -def SetArrayString(array_id, idx, value): +def set_array_string(array_id, idx, value): """ Sets the string value of an array element. @@ -6598,7 +6438,7 @@ def SetArrayString(array_id, idx, value): return __GetArrayById(array_id).supset(idx, value) -def GetArrayElement(tag, array_id, idx): +def get_array_element(tag, array_id, idx): """ Get value of array element. @@ -6620,7 +6460,7 @@ def GetArrayElement(tag, array_id, idx): return 0 -def DelArrayElement(tag, array_id, idx): +def del_array_element(tag, array_id, idx): """ Delete an array element. @@ -6639,7 +6479,7 @@ def DelArrayElement(tag, array_id, idx): return 0 -def GetFirstIndex(tag, array_id): +def get_first_index(tag, array_id): """ Get index of the first existing array element. @@ -6651,14 +6491,14 @@ def GetFirstIndex(tag, array_id): """ node = __GetArrayById(array_id) if tag == AR_LONG: - return __l2m1(node.alt1st(tag)) + return __l2m1(node.altfirst(tag)) elif tag == AR_STR: - return __l2m1(node.sup1st(tag)) + return __l2m1(node.supfirst(tag)) else: return -1 -def GetLastIndex(tag, array_id): +def get_last_index(tag, array_id): """ Get index of last existing array element. @@ -6677,7 +6517,7 @@ def GetLastIndex(tag, array_id): return -1 -def GetNextIndex(tag, array_id, idx): +def get_next_index(tag, array_id, idx): """ Get index of the next existing array element. @@ -6691,9 +6531,9 @@ def GetNextIndex(tag, array_id, idx): node = __GetArrayById(array_id) try: if tag == AR_LONG: - return __l2m1(node.altnxt(idx, tag)) + return __l2m1(node.altnext(idx, tag)) elif tag == AR_STR: - return __l2m1(node.supnxt(idx, tag)) + return __l2m1(node.supnext(idx, tag)) else: return -1 except OverflowError: @@ -6701,7 +6541,7 @@ def GetNextIndex(tag, array_id, idx): return -1 -def GetPrevIndex(tag, array_id, idx): +def get_prev_index(tag, array_id, idx): """ Get index of the previous existing array element. @@ -6727,7 +6567,7 @@ def GetPrevIndex(tag, array_id, idx): # -------------------- hashes ----------------------- -def SetHashLong(hash_id, key, value): +def set_hash_long(hash_id, key, value): """ Sets the long value of a hash element. @@ -6740,7 +6580,7 @@ def SetHashLong(hash_id, key, value): return __GetArrayById(hash_id).hashset_idx(key, value) -def GetHashLong(hash_id, key): +def get_hash_long(hash_id, key): """ Gets the long value of a hash element. @@ -6753,7 +6593,7 @@ def GetHashLong(hash_id, key): return __GetArrayById(hash_id).hashval_long(key); -def SetHashString(hash_id, key, value): +def set_hash_string(hash_id, key, value): """ Sets the string value of a hash element. @@ -6766,7 +6606,7 @@ def SetHashString(hash_id, key, value): return __GetArrayById(hash_id).hashset_buf(key, value) -def GetHashString(hash_id, key): +def get_hash_string(hash_id, key): """ Gets the string value of a hash element. @@ -6779,7 +6619,7 @@ def GetHashString(hash_id, key): return __GetArrayById(hash_id).hashstr_buf(key); -def DelHashElement(hash_id, key): +def del_hash_string(hash_id, key): """ Delete a hash element. @@ -6791,7 +6631,7 @@ def DelHashElement(hash_id, key): return __GetArrayById(hash_id).hashdel(key) -def GetFirstHashKey(hash_id): +def get_first_hash_key(hash_id): """ Get the first key in the hash. @@ -6799,11 +6639,11 @@ def GetFirstHashKey(hash_id): @return: the key, 0 otherwise. """ - r = __GetArrayById(hash_id).hash1st() + r = __GetArrayById(hash_id).hashfirst() return 0 if r is None else r -def GetLastHashKey(hash_id): +def get_last_hash_key(hash_id): """ Get the last key in the hash. @@ -6815,7 +6655,7 @@ def GetLastHashKey(hash_id): return 0 if r is None else r -def GetNextHashKey(hash_id, key): +def get_next_hash_key(hash_id, key): """ Get the next key in the hash. @@ -6824,11 +6664,11 @@ def GetNextHashKey(hash_id, key): @return: the next key, 0 otherwise """ - r = __GetArrayById(hash_id).hashnxt(key) + r = __GetArrayById(hash_id).hashnext(key) return 0 if r is None else r -def GetPrevHashKey(hash_id, key): +def get_prev_hash_key(hash_id, key): """ Get the previous key in the hash. @@ -6846,7 +6686,7 @@ def GetPrevHashKey(hash_id, key): #---------------------------------------------------------------------------- # S O U R C E F I L E / L I N E N U M B E R S #---------------------------------------------------------------------------- -def AddSourceFile(ea1, ea2, filename): +def add_sourcefile(ea1, ea2, filename): """ Mark a range of address as belonging to a source file An address range may belong only to one source file. @@ -6865,7 +6705,7 @@ def AddSourceFile(ea1, ea2, filename): return ida_lines.add_sourcefile(ea1, ea2, filename) -def GetSourceFile(ea): +def get_sourcefile(ea): """ Get name of source file occupying the given address @@ -6877,7 +6717,7 @@ def GetSourceFile(ea): return ida_lines.get_sourcefile(ea) -def DelSourceFile(ea): +def del_sourcefile(ea): """ Delete information about the source file @@ -6889,7 +6729,7 @@ def DelSourceFile(ea): return ida_lines.del_sourcefile(ea) -def SetLineNumber(ea, lnnum): +def set_source_linnum(ea, lnnum): """ Set source line number @@ -6901,7 +6741,7 @@ def SetLineNumber(ea, lnnum): ida_nalt.set_source_linnum(ea, lnnum) -def GetLineNumber(ea): +def get_source_linnum(ea): """ Get source line number @@ -6912,7 +6752,7 @@ def GetLineNumber(ea): return ida_nalt.get_source_linnum(ea) -def DelLineNumber(ea): +def del_source_linnum(ea): """ Delete information about source line number @@ -6927,21 +6767,21 @@ def DelLineNumber(ea): # T Y P E L I B R A R I E S #---------------------------------------------------------------------------- -def LoadTil(name): +def add_default_til(name): """ Load a type library @param name: name of type library. @return: 1-ok, 0-failed. """ - til = ida_typeinf.add_til2(name, ida_typeinf.ADDTIL_DEFAULT) + til = ida_typeinf.add_til(name, ida_typeinf.ADDTIL_DEFAULT) if til: return 1 else: return 0 -def Til2Idb(idx, type_name): +def import_type(idx, type_name): """ Copy information from type library to database Copy structure, union, or enum definition from the type library @@ -6953,10 +6793,10 @@ def Til2Idb(idx, type_name): @return: BADNODE-failed, otherwise the type id (structure id or enum id) """ - return ida_typeinf.import_type(ida_typeinf.cvar.idati, idx, type_name) + return ida_typeinf.import_type(None, idx, type_name) -def GetType(ea): +def get_type(ea): """ Get type of function/variable @@ -6969,12 +6809,12 @@ def GetType(ea): def SizeOf(typestr): """ Returns the size of the type. It is equivalent to IDC's sizeof(). - Use name, tp, fld = idc.ParseType() ; SizeOf(tp) to retrieve the size + Use name, tp, fld = idc.parse_decl() ; SizeOf(tp) to retrieve the size @return: -1 if typestring is not valid otherwise the size of the type """ - return ida_typeinf.calc_type_size(ida_typeinf.cvar.idati, typestr) + return ida_typeinf.calc_type_size(None, typestr) -def GetTinfo(ea): +def get_tinfo(ea): """ Get type information of function/variable as 'typeinfo' object @@ -6983,7 +6823,7 @@ def GetTinfo(ea): """ return ida_typeinf.idc_get_type_raw(ea) -def GetLocalTinfo(ordinal): +def get_local_tinfo(ordinal): """ Get local type information as 'typeinfo' object @@ -6992,7 +6832,7 @@ def GetLocalTinfo(ordinal): """ return ida_typeinf.idc_get_local_type_raw(ordinal) -def GuessType(ea): +def guess_type(ea): """ Guess type of function/variable @@ -7008,17 +6848,16 @@ TINFO_DELAYFUNC = 0x0002 # if type is a function and no function exists at ea, # schedule its creation and argument renaming to # auto-analysis otherwise try to create it immediately -def ApplyType(ea, py_type, flags = TINFO_DEFINITE): +def apply_type(ea, py_type, flags = TINFO_DEFINITE): """ Apply the specified type to the address - @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 + @param ea: the address of the object + @param py_type: typeinfo tuple (type, fields) as get_tinfo() returns + or tuple (name, type, fields) as parse_decl() returns or None if specified as None, then the item associated with 'ea' will be deleted. - @param ea: the address of the object @param flags: combination of TINFO_... constants or 0 @return: Boolean """ @@ -7032,7 +6871,7 @@ def ApplyType(ea, py_type, flags = TINFO_DEFINITE): pt = py_type[1:] # skip name component else: pt = py_type - return ida_typeinf.apply_type(ida_typeinf.cvar.idati, pt[0], pt[1], ea, flags) + return ida_typeinf.apply_type(None, pt[0], pt[1], ea, flags) def SetType(ea, newtype): """ @@ -7047,15 +6886,15 @@ def SetType(ea, newtype): @return: 1-ok, 0-failed. """ if newtype is not '': - pt = ParseType(newtype, 1) # silent + pt = parse_decl(newtype, 1) # silent if pt is None: # parsing failed return None else: pt = None - return ApplyType(ea, pt, TINFO_DEFINITE) + return apply_type(ea, pt, TINFO_DEFINITE) -def ParseType(inputtype, flags): +def parse_decl(inputtype, flags): """ Parse type declaration @@ -7066,9 +6905,9 @@ def ParseType(inputtype, flags): """ if len(inputtype) != 0 and inputtype[-1] != ';': inputtype = inputtype + ';' - return ida_typeinf.idc_parse_decl(ida_typeinf.cvar.idati, inputtype, flags) + return ida_typeinf.idc_parse_decl(None, inputtype, flags) -def ParseTypes(inputtype, flags = 0): +def parse_decls(inputtype, flags = 0): """ Parse type declarations @@ -7093,7 +6932,7 @@ PT_HIGH = 0x0080 # assume high level prototypes PT_LOWER = 0x0100 # lower the function prototypes -def PrintLocalTypes(ordinals, flags): +def print_decls(ordinals, flags): """ Print types in a format suitable for use in a header file @@ -7114,7 +6953,7 @@ def PrintLocalTypes(ordinals, flags): sink = def_sink() py_ordinals = map(lambda l : int(l), ordinals.split(",")) - ida_typeinf.print_decls(sink, ida_typeinf.cvar.idati, py_ordinals, flags) + ida_typeinf.print_decls(sink, None, py_ordinals, flags) return sink.text @@ -7125,16 +6964,16 @@ PDF_DEF_BASE = 0x4 # include base types: __int8, __int16, etc.. PDF_HEADER_CMT = 0x8 # prepend output with a descriptive comment -def GetMaxLocalType(): +def get_ordinal_qty(): """ Get number of local types + 1 @return: value >= 1. 1 means that there are no local types. """ - return ida_typeinf.get_ordinal_qty(ida_typeinf.cvar.idati) + return ida_typeinf.get_ordinal_qty(None) -def SetLocalType(ordinal, input, flags): +def set_local_type(ordinal, input, flags): """ Parse one type declaration and store it in the specified slot @@ -7155,9 +6994,9 @@ def GetLocalType(ordinal, flags): @param flags: any of PRTYPE_* constants @return: local type as a C declaration or "" """ - (type, fields) = GetLocalTinfo(ordinal) + (type, fields) = get_local_tinfo(ordinal) if type: - name = GetLocalTypeName(ordinal) + name = get_numbered_type_name(ordinal) return ida_typeinf.idc_print_type(type, fields, name, flags) return "" @@ -7167,7 +7006,7 @@ PRTYPE_TYPE = 0x0002 # print type declaration (not variable declaration) PRTYPE_PRAGMA = 0x0004 # print pragmas for alignment -def GetLocalTypeName(ordinal): +def get_numbered_type_name(ordinal): """ Retrieve a local type name @@ -7181,56 +7020,56 @@ def GetLocalTypeName(ordinal): # ---------------------------------------------------------------------------- # H I D D E N A R E A S # ---------------------------------------------------------------------------- -def HideArea(start, end, description, header, footer, color): +def add_hidden_range(start, end, description, header, footer, color): """ - Hide an area + Hide a range - Hidden areas - address ranges which can be replaced by their descriptions + Hidden ranges - address ranges which can be replaced by their descriptions - @param start: area start - @param end: area end - @param description: description to display if the area is collapsed - @param header: header lines to display if the area is expanded - @param footer: footer lines to display if the area is expanded + @param start: range start + @param end: range end + @param description: description to display if the range is collapsed + @param header: header lines to display if the range is expanded + @param footer: footer lines to display if the range is expanded @param color: RGB color code (-1 means default color) @returns: !=0 - ok """ - return ida_bytes.add_hidden_area(start, end, description, header, footer, color) + return ida_bytes.add_hidden_range(start, end, description, header, footer, color) -def SetHiddenArea(ea, visible): +def update_hidden_range(ea, visible): """ - Set hidden area state + Set hidden range state - @param ea: any address belonging to the hidden area - @param visible: new state of the area + @param ea: any address belonging to the hidden range + @param visible: new state of the range @return: != 0 - ok """ - ha = ida_bytes.get_hidden_area(ea) + ha = ida_bytes.get_hidden_range(ea) if not ha: return 0 else: ha.visible = visible - return ida_bytes.update_hidden_area(ha) + return ida_bytes.update_hidden_range(ha) -def DelHiddenArea(ea): +def del_hidden_range(ea): """ - Delete a hidden area + Delete a hidden range - @param ea: any address belonging to the hidden area + @param ea: any address belonging to the hidden range @returns: != 0 - ok """ - return ida_bytes.del_hidden_area(ea) + return ida_bytes.del_hidden_range(ea) #-------------------------------------------------------------------------- # D E B U G G E R I N T E R F A C E #-------------------------------------------------------------------------- -def LoadDebugger(dbgname, use_remote): +def load_debugger(dbgname, use_remote): """ Load the debugger @@ -7243,7 +7082,7 @@ def LoadDebugger(dbgname, use_remote): return ida_dbg.load_debugger(dbgname, use_remote) -def StartDebugger(path, args, sdir): +def start_process(path, args, sdir): """ Launch the debugger @@ -7254,12 +7093,12 @@ def StartDebugger(path, args, sdir): @return: -1-failed, 0-cancelled by the user, 1-ok @note: For all args: if empty, the default value from the database will be used - See the important note to the StepInto() function + See the important note to the step_into() function """ return ida_dbg.start_process(path, args, sdir) -def StopDebugger(): +def exit_process(): """ Stop the debugger Kills the currently debugger process and returns to the disassembly mode @@ -7269,57 +7108,30 @@ def StopDebugger(): return ida_dbg.exit_process() -def PauseProcess(): +def suspend_process(): """ Suspend the running process Tries to suspend the process. If successful, the PROCESS_SUSPEND - debug event will arrive (see GetDebuggerEvent) + debug event will arrive (see wait_for_next_event) @return: success - @note: To resume a suspended process use the GetDebuggerEvent function. - See the important note to the StepInto() function + @note: To resume a suspended process use the wait_for_next_event function. + See the important note to the step_into() function """ return ida_dbg.suspend_process() -def GetProcessQty(): +def get_processes(): """ - Take a snapshot of running processes and return their number. + Take a snapshot of running processes and return their description. + + @return: -1:network error, 0-failed, 1-ok """ - return ida_dbg.get_process_qty() + return ida_dbg.get_processes() -def GetProcessPid(idx): - """ - Get the process ID of a running process - - @param idx: number of process, is in range 0..GetProcessQty()-1 - - @return: 0 if failure - """ - 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 - - -def GetProcessName(idx): - """ - Get the name of a running process - - @param idx: number of process, is in range 0..GetProcessQty()-1 - - @return: None if failure - """ - 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): +def attach_process(pid, event_id): """ Attach the debugger to a running process @@ -7333,12 +7145,12 @@ def AttachProcess(pid, event_id): needed, not supported by the debugger plugin, ...) - 0: the user cancelled the attaching to the process - 1: the debugger properly attached to the process - @note: See the important note to the StepInto() function + @note: See the important note to the step_into() function """ return ida_dbg.attach_process(pid, event_id) -def DetachProcess(): +def detach_process(): """ Detach the debugger from the debugged process. @@ -7347,7 +7159,7 @@ def DetachProcess(): return ida_dbg.detach_process() -def GetThreadQty(): +def get_thread_qty(): """ Get number of threads. @@ -7356,18 +7168,18 @@ def GetThreadQty(): return ida_dbg.get_thread_qty() -def GetThreadId(idx): +def getn_thread(idx): """ Get the ID of a thread - @param idx: number of thread, is in range 0..GetThreadQty()-1 + @param idx: number of thread, is in range 0..get_thread_qty()-1 @return: -1 if failure """ return ida_dbg.getn_thread(idx) -def GetCurrentThreadId(): +def get_current_thread(): """ Get current thread ID @@ -7376,7 +7188,7 @@ def GetCurrentThreadId(): return ida_dbg.get_current_thread() -def SelectThread(tid): +def select_thread(tid): """ Select the given thread as the current debugged thread. @@ -7389,7 +7201,7 @@ def SelectThread(tid): return ida_dbg.select_thread(tid) -def SuspendThread(tid): +def suspend_thread(tid): """ Suspend thread @@ -7403,7 +7215,7 @@ def SuspendThread(tid): return ida_dbg.suspend_thread(tid) -def ResumeThread(tid): +def resume_thread(tid): """ Resume thread @@ -7425,7 +7237,7 @@ def _get_modules(): result = ida_dbg.get_next_module(module) -def GetFirstModule(): +def get_first_module(): """ Enumerate process modules @@ -7437,7 +7249,7 @@ def GetFirstModule(): return None -def GetNextModule(base): +def get_next_module(base): """ Enumerate process modules @@ -7455,7 +7267,7 @@ def GetNextModule(base): return None -def GetModuleName(base): +def get_module_name(base): """ Get process module name @@ -7470,7 +7282,7 @@ def GetModuleName(base): return 0 -def GetModuleSize(base): +def get_module_size(base): """ Get process module size @@ -7485,14 +7297,14 @@ def GetModuleSize(base): return -1 -def StepInto(): +def step_into(): """ Execute one instruction in the current thread. Other threads are kept suspended. @return: success - @note: You must call GetDebuggerEvent() after this call + @note: You must call wait_for_next_event() after this call in order to find out what happened. Normally you will get the STEP event but other events are possible (for example, an exception might occur or the process might exit). @@ -7502,42 +7314,42 @@ def StepInto(): return ida_dbg.step_into() -def StepOver(): +def step_over(): """ Execute one instruction in the current thread, but without entering into functions Others threads keep suspended. - See the important note to the StepInto() function + See the important note to the step_into() function @return: success """ return ida_dbg.step_over() -def RunTo(ea): +def run_to(ea): """ Execute the process until the given address is reached. If no process is active, a new process is started. - See the important note to the StepInto() function + See the important note to the step_into() function @return: success """ return ida_dbg.run_to(ea) -def StepUntilRet(): +def step_until_ret(): """ Execute instructions in the current thread until a function return instruction is reached. Other threads are kept suspended. - See the important note to the StepInto() function + See the important note to the step_into() function @return: success """ return ida_dbg.step_until_ret() -def GetDebuggerEvent(wfne, timeout): +def wait_for_next_event(wfne, timeout): """ Wait for the next event This function (optionally) resumes the process @@ -7551,15 +7363,15 @@ def GetDebuggerEvent(wfne, timeout): return ida_dbg.wait_for_next_event(wfne, timeout) -def ResumeProcess(): - return GetDebuggerEvent(WFNE_CONT|WFNE_NOWAIT, 0) +def resume_process(): + return wait_for_next_event(WFNE_CONT|WFNE_NOWAIT, 0) -def SendDbgCommand(cmd): +def send_dbg_command(cmd): """Sends a command to the debugger module and returns the output string. An exception will be raised if the debugger is not running or the current debugger does not export - the 'SendDbgCommand' IDC command. + the 'send_dbg_command' IDC command. """ - s = Eval('SendDbgCommand("%s");' % ida_kernwin.str2user(cmd)) + s = eval_idc('send_dbg_command("%s");' % ida_kernwin.str2user(cmd)) if s.startswith("IDC_FAILURE"): raise Exception, "Debugger command is available only when the debugger is active!" return s @@ -7568,7 +7380,7 @@ def SendDbgCommand(cmd): WFNE_ANY = 0x0001 # return the first event (even if it doesn't suspend the process) # if the process is still running, the database # does not reflect the memory state. you might want - # to call RefreshDebuggerMemory() in this case + # to call refresh_debugger_memory() in this case WFNE_SUSP = 0x0002 # wait until the process gets suspended WFNE_SILENT = 0x0004 # 1: be slient, 0:display modal boxes if necessary WFNE_CONT = 0x0008 # continue from the suspended state @@ -7596,9 +7408,9 @@ PROCESS_DETACH = 0x00002000 # Detached from process PROCESS_SUSPEND = 0x00004000 # Process has been suspended -def RefreshDebuggerMemory(): +def refresh_debugger_memory(): """ - Refresh debugger memory + refresh_idaview_anyway debugger memory Upon this call IDA will forget all cached information about the debugged process. This includes the segmentation information and memory contents (register cache is managed @@ -7611,7 +7423,7 @@ def RefreshDebuggerMemory(): return ida_dbg.refresh_debugger_memory() -def TakeMemorySnapshot(only_loader_segs): +def take_memory_snapshot(only_loader_segs): """ Take memory snapshot of the debugged process @@ -7621,7 +7433,7 @@ def TakeMemorySnapshot(only_loader_segs): return ida_segment.take_memory_snapshot(only_loader_segs) -def GetProcessState(): +def get_process_state(): """ Get debugged process state @@ -7644,7 +7456,7 @@ DSTATE_RUN_WAIT_END = 3 # process is running, but the user asked to kill/det # For all events: -def GetEventId(): +def get_event_id(): """ Get ID of debug event @@ -7655,7 +7467,7 @@ def GetEventId(): return ev.eid -def GetEventPid(): +def get_event_pid(): """ Get process ID for debug event @@ -7666,7 +7478,7 @@ def GetEventPid(): return ev.pid -def GetEventTid(): +def get_event_tid(): """ Get type ID for debug event @@ -7677,7 +7489,7 @@ def GetEventTid(): return ev.tid -def GetEventEa(): +def get_event_ea(): """ Get ea for debug event @@ -7688,7 +7500,7 @@ def GetEventEa(): return ev.ea -def IsEventHandled(): +def is_event_handled(): """ Is the debug event handled? @@ -7701,7 +7513,7 @@ def IsEventHandled(): # For PROCESS_START, PROCESS_ATTACH, LIBRARY_LOAD events: -def GetEventModuleName(): +def get_event_module_name(): """ Get module name for debug event @@ -7712,7 +7524,7 @@ def GetEventModuleName(): return ida_idd.get_event_module_name(ev) -def GetEventModuleBase(): +def get_event_module_base(): """ Get module base for debug event @@ -7723,7 +7535,7 @@ def GetEventModuleBase(): return ida_idd.get_event_module_base(ev) -def GetEventModuleSize(): +def get_event_module_size(): """ Get module size for debug event @@ -7734,7 +7546,7 @@ def GetEventModuleSize(): return ida_idd.get_event_module_size(ev) -def GetEventExitCode(): +def get_event_exit_code(): """ Get exit code for debug event @@ -7745,7 +7557,7 @@ def GetEventExitCode(): return ev.exit_code -def GetEventInfo(): +def get_event_info(): """ Get debug event info @@ -7757,7 +7569,7 @@ def GetEventInfo(): return ida_idd.get_event_info(ev) -def GetEventBptHardwareEa(): +def get_event_bpt_hea(): """ Get hardware address for BREAKPOINT event @@ -7768,7 +7580,7 @@ def GetEventBptHardwareEa(): return ida_idd.get_event_bpt_hea(ev) -def GetEventExceptionCode(): +def get_event_exc_code(): """ Get exception code for EXCEPTION event @@ -7779,7 +7591,7 @@ def GetEventExceptionCode(): return ida_idd.get_event_exc_code(ev) -def GetEventExceptionEa(): +def get_event_exc_ea(): """ Get address for EXCEPTION event @@ -7790,7 +7602,7 @@ def GetEventExceptionEa(): return ida_idd.get_event_exc_ea(ev) -def CanExceptionContinue(): +def can_exc_continue(): """ Can it continue after EXCEPTION event? @@ -7801,7 +7613,7 @@ def CanExceptionContinue(): return ida_idd.can_exc_continue(ev) -def GetEventExceptionInfo(): +def get_event_exc_info(): """ Get info for EXCEPTION event @@ -7812,7 +7624,7 @@ def GetEventExceptionInfo(): return ida_idd.get_event_exc_info(ev) -def SetDebuggerOptions(opt): +def set_debugger_options(opt): """ Get/set debugger options @@ -7844,21 +7656,21 @@ EXCDLG_ALWAYS = 0x00006000 # always display DOPT_LOAD_DINFO = 0x00008000 # automatically load debug files (pdb) -def GetDebuggerEventCondition(): +def get_debugger_event_cond(): """ Return the debugger event condition """ return ida_dbg.get_debugger_event_cond() -def SetDebuggerEventCondition(cond): +def set_debugger_event_cond(cond): """ Set the debugger event condition """ return ida_dbg.set_debugger_event_cond(cond) -def SetRemoteDebugger(hostname, password, portnum): +def set_remote_debugger(hostname, password, portnum): """ Set remote debugging options @@ -7871,7 +7683,7 @@ def SetRemoteDebugger(hostname, password, portnum): return ida_dbg.set_remote_debugger(hostname, password, portnum) -def DefineException(code, name, desc, flags): +def define_exception(code, name, desc, flags): """ Add exception handling information @@ -7888,7 +7700,7 @@ EXC_BREAK = 0x0001 # break on the exception EXC_HANDLE = 0x0002 # should be handled by the debugger? -def GetRegValue(name): +def get_reg_value(name): """ Get register value @@ -7907,7 +7719,7 @@ def GetRegValue(name): return rv.ival -def SetRegValue(value, name): +def set_reg_value(value, name): """ Set register value @@ -7922,7 +7734,7 @@ def SetRegValue(value, name): if type(value) == types.StringType: value = int(value, 16) elif type(value) != types.IntType and type(value) != types.LongType: - print "SetRegValue: value must be integer!" + print "set_reg_value: value must be integer!" return BADADDR if value < 0: @@ -7933,7 +7745,7 @@ def SetRegValue(value, name): return ida_dbg.set_reg_val(name, rv) -def GetBptQty(): +def get_bpt_qty(): """ Get number of breakpoints. @@ -7942,13 +7754,13 @@ def GetBptQty(): return ida_dbg.get_bpt_qty() -def GetBptEA(n): +def get_bpt_ea(n): """ Get breakpoint address - @param n: number of breakpoint, is in range 0..GetBptQty()-1 + @param n: number of breakpoint, is in range 0..get_bpt_qty()-1 - @return: addresss of the breakpoint or BADADDR + @return: address of the breakpoint or BADADDR """ bpt = ida_dbg.bpt_t() @@ -7958,7 +7770,7 @@ def GetBptEA(n): return BADADDR -def GetBptAttr(ea, bptattr): +def get_bpt_attr(ea, bptattr): """ Get the characteristics of a breakpoint @@ -8028,13 +7840,13 @@ BPLT_SYM = 2 # Symbolic name. The name will be resolved on DLL load/unload # - locinfo: offset from the symbol base address -def SetBptAttr(address, bptattr, value): +def set_bpt_attr(address, bptattr, value): """ modifiable characteristics of a breakpoint @param address: any address in the breakpoint range @param bptattr: the attribute code, one of BPTATTR_* constants - BPTATTR_CND is not allowed, see SetBptCnd() + BPTATTR_CND is not allowed, see set_bpt_cond() @param value: the attibute value @return: success @@ -8057,7 +7869,8 @@ def SetBptAttr(address, bptattr, value): return ida_dbg.update_bpt(bpt) -def SetBptCndEx(ea, cnd, is_lowcnd): + +def set_bpt_cond(ea, cnd, is_lowcnd=0): """ Set breakpoint condition @@ -8081,19 +7894,7 @@ def SetBptCndEx(ea, cnd, is_lowcnd): return ida_dbg.update_bpt(bpt) -def SetBptCnd(ea, cnd): - """ - Set breakpoint condition - - @param ea: any address in the breakpoint range - @param cnd: breakpoint condition - - @return: success - """ - return SetBptCndEx(ea, cnd, 0) - - -def AddBptEx(ea, size, bpttype): +def add_bpt(ea, size=0, bpttype=BPT_DEFAULT): """ Add a new breakpoint @@ -8108,11 +7909,7 @@ def AddBptEx(ea, size, bpttype): return ida_dbg.add_bpt(ea, size, bpttype) -def AddBpt(ea): - return AddBptEx(ea, 0, BPT_DEFAULT) - - -def DelBpt(ea): +def del_bpt(ea): """ Delete breakpoint @@ -8123,7 +7920,7 @@ def DelBpt(ea): return ida_dbg.del_bpt(ea) -def EnableBpt(ea, enable): +def enable_bpt(ea, enable): """ Enable/disable breakpoint @@ -8136,7 +7933,7 @@ def EnableBpt(ea, enable): return ida_dbg.enable_bpt(ea, enable) -def CheckBpt(ea): +def check_bpt(ea): """ Check a breakpoint @@ -8152,7 +7949,7 @@ BPTCK_YES = 1 # breakpoint is enabled BPTCK_ACT = 2 # breakpoint is active (written to the process) -def EnableTracing(trace_level, enable): +def enable_tracing(trace_level, enable): """ Enable step tracing @@ -8180,7 +7977,7 @@ TRACE_INSN = 0x1 # instruction level trace TRACE_FUNC = 0x2 # function level trace (calls & rets) -def GetStepTraceOptions(): +def get_step_trace_options(): """ Get step current tracing options @@ -8189,7 +7986,7 @@ def GetStepTraceOptions(): return ida_dbg.get_step_trace_options() -def SetStepTraceOptions(options): +def set_step_trace_options(options): """ Set step current tracing options. @param options: combination of ST_... constants @@ -8202,14 +7999,14 @@ ST_OVER_LIB_FUNC = 0x02 # step tracing will be disabled when IP is in a library ST_ALREADY_LOGGED = 0x04 # step tracing will be disabled when IP is already logged ST_SKIP_LOOPS = 0x08 # step tracing will try to skip loops already recorded -def LoadTraceFile(filename): +def load_trace_file(filename): """ Load a previously recorded binary trace file @param filename: trace file """ return ida_dbg.load_trace_file(filename) -def SaveTraceFile(filename, description): +def save_trace_file(filename, description): """ Save current trace to a binary trace file @param filename: trace file @@ -8217,34 +8014,34 @@ def SaveTraceFile(filename, description): """ return ida_dbg.save_trace_file(filename, description) -def CheckTraceFile(filename): +def is_valid_trace_file(filename): """ Check the given binary trace file @param filename: trace file """ return ida_dbg.is_valid_trace_file(filename) -def DiffTraceFile(filename): +def diff_trace_file(filename): """ Diff current trace buffer against given trace @param filename: trace file """ return ida_dbg.diff_trace_file(filename) -def ClearTraceFile(filename): +def clear_trace(filename): """ Clear the current trace buffer """ return ida_dbg.clear_trace() -def GetTraceDesc(filename): +def get_trace_file_desc(filename): """ Get the trace description of the given binary trace file @param filename: trace file """ return ida_dbg.get_trace_file_desc(filename) -def SetTraceDesc(filename, description): +def set_trace_file_desc(filename, description): """ Update the trace description of the given binary trace file @param filename: trace file @@ -8252,13 +8049,13 @@ def SetTraceDesc(filename, description): """ return ida_dbg.set_trace_file_desc(filename, description) -def GetMaxTev(): +def get_tev_qty(): """ Return the total number of recorded events """ return ida_dbg.get_tev_qty() -def GetTevEa(tev): +def get_tev_ea(tev): """ Return the address of the specified event @param tev: event number @@ -8273,21 +8070,21 @@ TEV_BPT = 4 # write, read/write, execution trace TEV_MEM = 5 # memory layout changed TEV_EVENT = 6 # debug event -def GetTevType(tev): +def get_tev_type(tev): """ Return the type of the specified event (TEV_... constants) @param tev: event number """ return ida_dbg.get_tev_type(tev) -def GetTevTid(tev): +def get_tev_tid(tev): """ Return the thread id of the specified event @param tev: event number """ return ida_dbg.get_tev_tid(tev) -def GetTevRegVal(tev, reg): +def get_tev_reg(tev, reg): """ Return the register value for the specified event @param tev: event number @@ -8295,7 +8092,7 @@ def GetTevRegVal(tev, reg): """ return ida_dbg.get_tev_reg_val(tev, reg) -def GetTevRegMemQty(tev): +def get_tev_mem_qty(tev): """ Return the number of blobs of memory recorded, for the specified event @@ -8305,7 +8102,7 @@ def GetTevRegMemQty(tev): """ return ida_dbg.get_tev_reg_mem_qty(tev) -def GetTevRegMem(tev, idx): +def get_tev_mem(tev, idx): """ Return the blob of memory pointed to by 'index', for the specified event @@ -8316,7 +8113,7 @@ def GetTevRegMem(tev, idx): """ return ida_dbg.get_tev_reg_mem(tev, idx) -def GetTevRegMemEa(tev, idx): +def get_tev_mem_ea(tev, idx): """ Return the address of the blob of memory pointed to by 'index' for the specified event @@ -8327,21 +8124,21 @@ def GetTevRegMemEa(tev, idx): """ return ida_dbg.get_tev_reg_mem_ea(tev, idx) -def GetTevCallee(tev): +def get_call_tev_callee(tev): """ Return the address of the callee for the specified event @param tev: event number """ return ida_dbg.get_call_tev_callee(tev) -def GetTevReturn(tev): +def get_ret_tev_return(tev): """ Return the return address for the specified event @param tev: event number """ return ida_dbg.get_ret_tev_return(tev) -def GetBptTevEa(tev): +def get_bpt_tev_ea(tev): """ Return the address of the specified TEV_BPT event @param tev: event number @@ -8353,7 +8150,7 @@ def GetBptTevEa(tev): # C O L O R S #-------------------------------------------------------------------------- -def GetColor(ea, what): +def get_color(ea, what): """ Get item color @@ -8390,7 +8187,7 @@ CIC_SEGM = 3 # segment DEFCOLOR = 0xFFFFFFFF # Default color -def SetColor(ea, what, color): +def set_color(ea, what, color): """ Set item color @@ -8426,7 +8223,7 @@ def SetColor(ea, what, color): #---------------------------------------------------------------------------- # A R M S P E C I F I C #---------------------------------------------------------------------------- -def ArmForceBLJump(ea): +def force_bl_jump(ea): """ Some ARM compilers in Thumb mode use BL (branch-and-link) instead of B (branch) for long jumps, since BL has more range. @@ -8440,10 +8237,10 @@ def ArmForceBLJump(ea): @return: 1-ok, 0-failed """ - return Eval("ArmForceBLJump(0x%x)"%ea) + return eval_idc("force_bl_jump(0x%x)"%ea) -def ArmForceBLCall(ea): +def force_bl_call(ea): """ Force BL instruction to be a call @@ -8451,126 +8248,99 @@ def ArmForceBLCall(ea): @return: 1-ok, 0-failed """ - return Eval("ArmForceBLCall(0x%x)"%ea) + return eval_idc("force_bl_call(0x%x)"%ea) #-------------------------------------------------------------------------- -# Compatibility macros: -def Compile(file): return CompileEx(file, 1) -def OpOffset(ea,base): return OpOff(ea,-1,base) -def OpNum(ea): return OpNumber(ea,-1) -def OpChar(ea): return OpChr(ea,-1) -def OpSegment(ea): return OpSeg(ea,-1) -def OpDec(ea): return OpDecimal(ea,-1) -def OpAlt1(ea, opstr): return OpAlt(ea, 0, opstr) -def OpAlt2(ea, opstr): return OpAlt(ea, 1, opstr) -def StringStp(x): return SetCharPrm(INF_ASCII_BREAK,x) -def LowVoids(x): return SetLongPrm(INF_LOW_OFF,x) -def HighVoids(x): return SetLongPrm(INF_HIGH_OFF,x) -def TailDepth(x): return SetLongPrm(INF_MAXREF,x) -def Analysis(x): return SetCharPrm(INF_AUTO,x) -def Tabs(x): return SetCharPrm(INF_ENTAB,x) -#def Comments(x): SetCharPrm(INF_CMTFLAG,((x) ? (SW_ALLCMT|GetCharPrm(INF_CMTFLAG)) : (~SW_ALLCMT&GetCharPrm(INF_CMTFLAG)))) -def Voids(x): return SetCharPrm(INF_VOIDS,x) -def XrefShow(x): return SetCharPrm(INF_XREFNUM,x) -def Indent(x): return SetCharPrm(INF_INDENT,x) -def CmtIndent(x): return SetCharPrm(INF_COMMENT,x) -def AutoShow(x): return SetCharPrm(INF_SHOWAUTO,x) -def MinEA(): return GetLongPrm(INF_MIN_EA) -def MaxEA(): return GetLongPrm(INF_MAX_EA) -def BeginEA(): return GetLongPrm(INF_BEGIN_EA) -def set_start_cs(x): return SetLongPrm(INF_START_CS,x) -def set_start_ip(x): return SetLongPrm(INF_START_IP,x) +def set_flag(off, bit, value): + v = get_inf_attr(off) + if value: + v = v | bit + else: + v = v & ~bit + set_inf_attr(off, v) -def WriteMap(filepath): - return GenerateFile(OFILE_MAP, filepath, 0, BADADDR, GENFLG_MAPSEG|GENFLG_MAPNAME) +#-------------------------------------------------------------------------- +# Compatibility macros (auto-generated part. Comes first so +# that any re-definition below will override auto-generated part) +if sys.modules["__main__"].IDAPYTHON_COMPAT_695_API: -def WriteTxt(filepath, ea1, ea2): - return GenerateFile(OFILE_ASM, filepath, ea1, ea2, 0) + # see header.i.in + bc695redef = ida_idaapi.bc695redef -def WriteExe(filepath): - return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0) + # although many things have changed in the 'inf' structure, + # let's still try and do the best we can here even though + # some INF_* accessor enumerators don't exist anymore + GetCharPrm=get_inf_attr + GetLongPrm=get_inf_attr + GetShortPrm=get_inf_attr + SetCharPrm=set_inf_attr + SetLongPrm=set_inf_attr + SetShortPrm=set_inf_attr + + #-------------------------------------------------------------------------- + # Compatibility macros (non-auto-generated part) + def CompileEx(inp, isfile): return compile_idc_file(inp) if isfile else compile_idc_text(inp) + + def WriteMap(filepath): + return gen_file(OFILE_MAP, filepath, 0, BADADDR, GENFLG_MAPSEG|GENFLG_MAPNAME) + + def WriteTxt(filepath, ea1, ea2): + return gen_file(OFILE_ASM, filepath, ea1, ea2, 0) + + def WriteExe(filepath): + return gen_file(OFILE_EXE, filepath, 0, BADADDR, 0) + + UTP_STRUCT = ida_typeinf.UTP_STRUCT + UTP_ENUM = ida_typeinf.UTP_ENUM -UTP_STRUCT = ida_typeinf.UTP_STRUCT -UTP_ENUM = ida_typeinf.UTP_ENUM + def begin_type_updating(utp): + """ + Begin type updating. Use this function if you + plan to call AddEnumConst or similar type modification functions + many times or from inside a loop + + @param utp: one of UTP_xxxx consts + @return: None + """ + return ida_typeinf.begin_type_updating(utp) -def BeginTypeUpdating(utp): - """ - Begin type updating. Use this function if you - plan to call AddEnumConst or similar type modification functions - many times or from inside a loop + def end_type_updating(utp): + """ + End type updating. Refreshes the type system + at the end of type modification operations - @param utp: one of UTP_xxxx consts - @return: None - """ - return ida_typeinf.begin_type_updating(utp) + @param utp: one of ida_typeinf.UTP_xxxx consts + @return: None + """ + return ida_typeinf.end_type_updating(utp) + from idc_bc695 import * -def EndTypeUpdating(utp): - """ - End type updating. Refreshes the type system - at the end of type modification operations + SendDbgCommand=send_dbg_command - @param utp: one of ida_typeinf.UTP_xxxx consts - @return: None - """ - return ida_typeinf.end_type_updating(utp) - - -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) -def OpEnum(ea, n, enumid): return OpEnumEx(ea,n,enumid, 0) -def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask) -def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask) -def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA) - -def MakeStruct(ea, name): return MakeStructEx(ea, -1, name) -def MakeCustomData(ea, size, dtid, fid): return MakeCustomDataEx(ea, size, dtid, fid) -def Name(ea): return NameEx(BADADDR, ea) -def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea) -def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK) - -#def GetFrame(ea): return GetFunctionAttr(ea, FUNCATTR_FRAME) -#def GetFrameLvarSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRSIZE) -#def GetFrameRegsSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRREGS) -#def GetFrameArgsSize(ea): return GetFunctionAttr(ea, FUNCATTR_ARGSIZE) -#def GetFunctionFlags(ea): return GetFunctionAttr(ea, FUNCATTR_FLAGS) -#def SetFunctionFlags(ea, flags): return SetFunctionAttr(ea, FUNCATTR_FLAGS, flags) - -#def SegStart(ea): return GetSegmentAttr(ea, SEGATTR_START) -#def SegEnd(ea): return GetSegmentAttr(ea, SEGATTR_END) -#def SetSegmentType(ea, type): return SetSegmentAttr(ea, SEGATTR_TYPE, type) - -def SegCreate(a1, a2, base, use32, align, comb): return AddSeg(a1, a2, base, use32, align, comb) -def SegDelete(ea, flags): return DelSeg(ea, flags) -def SegBounds(ea, startea, endea, flags): return SetSegBounds(ea, startea, endea, flags) -def SegRename(ea, name): return RenameSeg(ea, name) -def SegClass(ea, segclass): return SetSegClass(ea, segclass) -def SegAddrng(ea, bitness): return SetSegAddressing(ea, bitness) -def SegDefReg(ea, reg, value): return SetSegDefReg(ea, reg, value) - - -def Comment(ea): return GetCommentEx(ea, 0) -"""Returns the regular comment or None""" - -def RptCmt(ea): return GetCommentEx(ea, 1) -"""Returns the repeatable comment or None""" - -def SetReg(ea, reg, value): return SetRegEx(ea, reg, value, SR_user) + def MakeFunction(start, end=ida_idaapi.BADADDR): + return ida_funcs.add_func(start, end) + ApplyType = apply_type + GetManyBytes = get_bytes + GetString = get_strlit_contents + ClearTraceFile = clear_trace + FindBinary = find_binary + NextHead = next_head + ParseTypes = parse_decls + PrevHead = prev_head + ProcessUiAction = process_ui_action + SaveBase = save_database + Eval = eval_idc + def MakeStr(ea, endea): + return create_strlit(ea, endea) # Convenience functions: -def here(): return ScreenEA() -def isEnabled(ea): return (PrevAddr(ea+1)==ea) - -# Obsolete segdel macros: -SEGDEL_PERM = 0x0001 # permanently, i.e. disable addresses -SEGDEL_KEEP = 0x0002 # keep information (code & data, etc) -SEGDEL_SILENT = 0x0004 # be silent +def here(): return get_screen_ea() +def is_mapped(ea): return (prev_addr(ea+1)==ea) ARGV = [] """The command line arguments passed to IDA via the -S switch.""" diff --git a/python/init.py b/python/init.py index 3649343..8f818e9 100644 --- a/python/init.py +++ b/python/init.py @@ -17,7 +17,26 @@ import time import warnings # 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)) +lib_dynload = os.path.join( + sys.executable, + IDAPYTHON_DYNLOAD_BASE, + "python", "lib", "python2.7", "lib-dynload") + +is_x64 = sys.maxint >= 0x100000000L +if is_x64: + # x64 python requires our lib_dynload to be added; sys.path seems + # to be composed differently than x86 builds. + # In addition, we always want our own lib-dynload to come first: + # the PyQt (& sip) modules that might have to be loaded, should + # be the ones shipped with IDA and not those possibly available + # on the system. + sys.path.insert(0, os.path.join(lib_dynload, IDAPYTHON_DYNLOAD_RELPATH)) + sys.path.insert(0, lib_dynload) +else: + # for non-x64 platforms, make sure everything works as it used to, + # by appending our own lib-dynload to sys.argv.. + sys.path.append(os.path.join(lib_dynload, IDAPYTHON_DYNLOAD_RELPATH)) + try: import ida_idaapi import ida_kernwin @@ -40,7 +59,7 @@ class IDAPythonStdOut: """ def write(self, text): # NB: in case 'text' is Unicode, msg() will decode it - # and call umsg() to print it + # and call msg() to print it ida_kernwin.msg(text) def flush(self): @@ -88,7 +107,7 @@ sys.stdout = sys.stderr = IDAPythonStdOut() import pydoc class IDAPythonHelpPrompter: def readline(self): - return ida_kernwin.askstr(0, '', 'Help topic?') + return ida_kernwin.ask_str('', 0, 'Help topic?') help = pydoc.Helper(input = IDAPythonHelpPrompter(), output = sys.stdout) # Assign a default sys.argv @@ -110,7 +129,9 @@ if not IDAPYTHON_REMOVE_CWD_SYS_PATH: if IDAPYTHON_COMPAT_AUTOIMPORT_MODULES: # Import all the required modules - from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall, Form + from idaapi import get_user_idadir, cvar, Appcall, Form + if IDAPYTHON_COMPAT_695_API: + from idaapi import Choose2 from idc import * from idautils import * import idaapi diff --git a/pywraps.cpp b/pywraps.cpp index 4abd294..b05e7c3 100644 --- a/pywraps.cpp +++ b/pywraps.cpp @@ -6,6 +6,9 @@ #include "pywraps.hpp" +#undef hook_to_notification_point +#undef unhook_from_notification_point + //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 @@ -15,8 +18,8 @@ // 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"; +#define S_PY_IDC_OPAQUE_T "py_idc_cvt_helper_t" // Constants used by get_idaapi_class_reference() #define PY_CLSID_CVT_INT64 0 @@ -133,12 +136,23 @@ ref_t ida_export PyW_IntVecToPyList(const intvec_t &intvec) } //--------------------------------------------------------------------------- -static int idaapi pylist_to_intvec_cb( +ref_t ida_export PyW_SizeVecToPyList(const sizevec_t &vec) +{ + size_t n = vec.size(); + PYW_GIL_CHECK_LOCKED_SCOPE(); + newref_t py_list(PyList_New(n)); + for ( size_t i = 0; i < n; ++i ) + PyList_SetItem(py_list.o, i, PyInt_FromSize_t(vec[i])); + return ref_t(py_list); +} + +//--------------------------------------------------------------------------- +static int idaapi pylist_to_sizevec_cb( const ref_t &py_item, Py_ssize_t /*index*/, void *ud) { - intvec_t &intvec = *(intvec_t *) ud; + sizevec_t &vec = *static_cast(ud); uint64 num; { PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -146,15 +160,15 @@ static int idaapi pylist_to_intvec_cb( num = 0; } - intvec.push_back(int(num)); + vec.push_back(size_t(num)); return CIP_OK; } //--------------------------------------------------------------------------- -bool ida_export PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec) +bool ida_export PyW_PyListToSizeVec(PyObject *py_list, sizevec_t &vec) { - intvec.clear(); - return pyvar_walk_list(py_list, pylist_to_intvec_cb, &intvec) != CIP_FAILED; + vec.clear(); + return pyvar_walk_list(py_list, pylist_to_sizevec_cb, &vec) != CIP_FAILED; } //------------------------------------------------------------------------- @@ -231,24 +245,24 @@ bool ida_export PyWStringOrNone_Check(PyObject *tp) } //------------------------------------------------------------------------- -PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &areas) +PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &ranges) { PYW_GIL_CHECK_LOCKED_SCOPE(); - PyObject *py_list = PyList_New(areas.size()); - meminfo_vec_t::const_iterator it, it_end(areas.end()); + PyObject *py_list = PyList_New(ranges.size()); + meminfo_vec_t::const_iterator it, it_end(ranges.end()); Py_ssize_t i = 0; - for ( it=areas.begin(); it != it_end; ++it, ++i ) + for ( it=ranges.begin(); it != it_end; ++it, ++i ) { const memory_info_t &mi = *it; - // startEA endEA name sclass sbase bitness perm + // start_ea end_ea 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), + Py_BuildValue("(" PY_BV_EA PY_BV_EA "ss" PY_BV_EA "II)", + bvea_t(mi.start_ea), + bvea_t(mi.end_ea), mi.name.c_str(), mi.sclass.c_str(), - pyul_t(mi.sbase), + bvea_t(mi.sbase), (unsigned int)(mi.bitness), (unsigned int)mi.perm)); } @@ -332,18 +346,18 @@ 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 ) + if ( idcv_object(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); + set_idcv_attr(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); + set_idcv_attr(idc_var, S_PY_IDCCVT_VALUE_ATTR, idc_val); return true; } @@ -351,10 +365,9 @@ static bool wrap_PyObject_ptr(const ref_t &py_var, idc_value_t *idc_var) //------------------------------------------------------------------------ // 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*/) + 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 @@ -363,16 +376,28 @@ static error_t idaapi py_idc_opaque_dtor( // Get the value from the object idc_value_t idc_val; - VarGetAttr(&argv[0], S_PY_IDCCVT_VALUE_ATTR, &idc_val); + get_idcv_attr(&idc_val, &argv[0], S_PY_IDCCVT_VALUE_ATTR); // Extract the Python object reference PyObject *py_obj = (PyObject *)idc_val.pvoid; // Decrease its reference (and eventually destroy it) - Py_DECREF(py_obj); - + { + uninterruptible_op_t op; + Py_DECREF(py_obj); + } return eOk; } +static const char py_idc_cvt_helper_dtor_args[] = { VT_OBJ, 0 }; +static const ext_idcfunc_t opaque_dtor_desc = +{ + S_PY_IDC_OPAQUE_T ".dtor_name", + py_idc_opaque_dtor, + py_idc_cvt_helper_dtor_args, + NULL, + 0, + 0 +}; //------------------------------------------------------------------------- // Converts a Python variable into an IDC variable @@ -420,7 +445,7 @@ int ida_export pyvar_to_idcvar( else if ( PyList_CheckExact(py_var.o) || PyW_IsSequenceType(py_var.o) ) { // Create the object - VarObject(idc_var); + idcv_object(idc_var); // Determine list size and type bool is_seq = !PyList_CheckExact(py_var.o); @@ -449,7 +474,7 @@ int ida_export pyvar_to_idcvar( if ( !ok ) break; // Store the attribute - VarSetAttr(idc_var, attr_name.c_str(), &v); + set_idcv_attr(idc_var, attr_name.c_str(), v); } if ( !ok ) break; @@ -460,7 +485,7 @@ int ida_export pyvar_to_idcvar( else if ( PyDict_Check(py_var.o) ) { // Create an empty IDC object - VarObject(idc_var); + idcv_object(idc_var); // Get the dict.items() list newref_t py_items(PyDict_Items(py_var.o)); @@ -487,7 +512,7 @@ int ida_export pyvar_to_idcvar( if ( ok ) { // Store the attribute - VarSetAttr(idc_var, key_name.c_str(), &v); + set_idcv_attr(idc_var, key_name.c_str(), v); } if ( !ok ) break; @@ -547,7 +572,7 @@ int ida_export pyvar_to_idcvar( { (*gvar_sn)++; // Create a reference to this global variable - VarRef(idc_var, gvar); + create_idcv_ref(idc_var, gvar); } return ok ? CIP_OK : CIP_FAILED; } @@ -570,7 +595,7 @@ int ida_export pyvar_to_idcvar( if ( py_dir == NULL || !PyList_Check(py_dir.o) || size == 0 ) return CIP_FAILED; // Create the IDC object - VarObject(idc_var); + idcv_object(idc_var); for ( Py_ssize_t i=0; i < size; i++ ) { borref_t item(PyList_GetItem(py_dir.o, i)); @@ -599,7 +624,7 @@ int ida_export pyvar_to_idcvar( } // Store the attribute - VarSetAttr(idc_var, field_name, &v); + set_idcv_attr(idc_var, field_name, v); } } } @@ -623,8 +648,9 @@ inline PyObject *cvt_to_pylong(int64 v) // 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) + const idc_value_t &idc_var, + ref_t *py_var, + uint32 flags) { PYW_GIL_CHECK_LOCKED_SCOPE(); switch ( idc_var.vtype ) @@ -643,33 +669,37 @@ int ida_export idcvar_to_pyvar( case VT_INT64: { - // Recycle? - if ( *py_var != NULL ) + bool as_pylong = (flags & PYWCVTF_INT64_AS_UNSIGNED_PYLONG) != 0; + if ( as_pylong ) { - // 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)); + QASSERT(30513, *py_var == NULL); // recycling not supported in this case + *py_var = newref_t(PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) 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; + else + { + // 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(); @@ -688,7 +718,7 @@ int ida_export idcvar_to_pyvar( if ( *py_var == NULL ) { double x; - if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 ) + if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 1 ) INTERR(30160); *py_var = newref_t(PyFloat_FromDouble(x)); @@ -716,7 +746,7 @@ int ida_export idcvar_to_pyvar( // 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); + idc_value_t *dref_v = deref_idcv(const_cast(&idc_var), VREF_LOOP); if ( dref_v == NULL ) return CIP_FAILED; @@ -749,8 +779,8 @@ int ida_export idcvar_to_pyvar( { // 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 ) + if ( get_idcv_attr(&idc_val, &idc_var, S_PY_IDCCVT_ID_ATTR) == eOk + && get_idcv_attr(&idc_val, &idc_var, S_PY_IDCCVT_VALUE_ATTR) == eOk ) { // Extract the object *py_var = borref_t((PyObject *) idc_val.pvoid); @@ -781,13 +811,13 @@ int ida_export idcvar_to_pyvar( } // Walk the IDC attributes and store into python - for ( const char *attr_name = VarFirstAttr(&idc_var); + for ( const char *attr_name = first_idcv_attr(&idc_var); attr_name != NULL; - attr_name = VarNextAttr(&idc_var, attr_name) ) + attr_name = next_idcv_attr(&idc_var, attr_name) ) { // Get the attribute idc_value_t v; - VarGetAttr(&idc_var, attr_name, &v, true); + get_idcv_attr(&v, &idc_var, attr_name, true); // Convert attribute to a python value (recursively) ref_t py_attr; @@ -817,9 +847,8 @@ 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) + uint32 flags, + qstring *errbuf) { PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -827,13 +856,14 @@ bool ida_export pyw_convert_idc_args( pargs.qclear(); - if ( as_tupple ) + bool as_tuple = (flags & PYWCVTF_AS_TUPLE) != 0; + if ( as_tuple ) { 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); + if ( errbuf != NULL ) + *errbuf = "Failed to create a new tuple to store arguments!"; return false; } } @@ -841,15 +871,15 @@ bool ida_export pyw_convert_idc_args( for ( int i=0; i < nargs; i++ ) { ref_t py_obj; - int cvt = idcvar_to_pyvar(args[i], &py_obj); + int cvt = idcvar_to_pyvar(args[i], &py_obj, flags); if ( cvt < CIP_OK ) { - if ( errbuf != 0 && errbufsize > 0 ) - qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype); + if ( errbuf != NULL ) + errbuf->sprnt("arg#%d has wrong type %d", i, args[i].vtype); return false; } - if ( as_tupple ) + if ( as_tuple ) { // PyTuple_SetItem() steals the reference. py_obj.incref(); @@ -864,7 +894,7 @@ bool ida_export pyw_convert_idc_args( // 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 ) + if ( as_tuple ) pargs.push_back(py_tuple); return true; @@ -921,12 +951,12 @@ static bool pywraps_check_autoscripts(char *buf, size_t bufsize) error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char *msg) { // Create exception object - VarObject(res, find_idc_class("exception")); + idcv_object(res, find_idc_class("exception")); // Set the message field idc_value_t v; v.set_string(msg); - VarSetAttr(res, "message", &v); + set_idcv_attr(res, "message", v); // Throw exception return set_qerrno(eExecThrow); @@ -934,10 +964,9 @@ error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char *msg) //------------------------------------------------------------------------ // 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) + idc_value_t *argv, + idc_value_t *res) { PYW_GIL_GET; PyObject *pyfunc = (PyObject *) argv[0].pvoid; @@ -950,6 +979,11 @@ static error_t idaapi idc_py_invoke0( err_code = PyW_CreateIdcException(res, err.c_str()); return err_code; } +static const char idc_py_invoke0_args[] = { VT_PVOID, 0 }; +static const ext_idcfunc_t idc_py_invoke0_desc = +{ + S_PYINVOKE0, idc_py_invoke0, idc_py_invoke0_args, NULL, 0, 0 +}; //------------------------------------------------------------------------ // This function must be called on initialization @@ -969,7 +1003,7 @@ static bool init_pywraps() } // 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) ) + if ( !add_idc_func(idc_py_invoke0_desc) ) return false; // IDC opaque class not registered? @@ -980,16 +1014,12 @@ static bool init_pywraps() 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) ) + if ( !add_idc_func(opaque_dtor_desc) ) return false; // Link the dtor function to the class - set_idc_dtor(idc_cvt_opaque, dtor_name); + set_idc_dtor(idc_cvt_opaque, opaque_dtor_desc.name); } pywraps_initialized = true; @@ -1011,7 +1041,7 @@ static void deinit_pywraps() } // Unregister the IDC PyInvoke0 method (helper function for add_idc_hotkey()) - set_idc_func_ex(S_PYINVOKE0, NULL, idc_py_invoke0_args, 0); + del_idc_func(idc_py_invoke0_desc.name); } //------------------------------------------------------------------------ @@ -1071,9 +1101,9 @@ static ref_t get_idaapi_attr(const char *attrname) //------------------------------------------------------------------------ // Returns a qstring from an object attribute bool ida_export PyW_GetStringAttr( - PyObject *py_obj, - const char *attr_name, - qstring *str) + PyObject *py_obj, + const char *attr_name, + qstring *str) { PYW_GIL_CHECK_LOCKED_SCOPE(); ref_t py_attr(PyW_TryGetAttrString(py_obj, attr_name)); @@ -1112,44 +1142,26 @@ ref_t ida_export PyW_TryImportModule(const char *name) //------------------------------------------------------------------------- // Converts a Python number into an IDC value (32 or 64bits) -// The function will first try to convert the number into a 32bit value +// The function will 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; - } + if ( !(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)) ) + return false; - // 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; + PY_LONG_LONG pyll = PyLong_AsLongLong(py_var); + if ( PyErr_Occurred() ) + return false; + + bool as_i64 = pyll >= 0 + ? pyll > (PY_LONG_LONG) SVAL_MAX + : pyll < (PY_LONG_LONG) SVAL_MIN; + if ( as_i64 ) + idc_var->set_int64(int64(pyll)); + else + idc_var->set_long(sval_t(pyll)); + return true; } //------------------------------------------------------------------------- @@ -1386,13 +1398,13 @@ void *ida_export pyobj_get_clink(PyObject *pyobj) } //------------------------------------------------------------------------ -int idaapi pywraps_notify_when_t::idp_callback(void *ud, int event_id, va_list va) +ssize_t 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: + case processor_t::ev_newfile: + case processor_t::ev_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 @@ -1400,12 +1412,23 @@ int idaapi pywraps_notify_when_t::idp_callback(void *ud, int event_id, va_list v // 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; + int old = event_id == processor_t::ev_oldfile ? 1 : 0; char *dbname = va_arg(va, char *); _this->notify(NW_OPENIDB_SLOT, old); } break; - case processor_t::closebase: + } + // event not processed, let other plugins or the processor module handle it + return 0; +} + +//------------------------------------------------------------------------ +ssize_t idaapi pywraps_notify_when_t::idb_callback(void *ud, int event_id, va_list va) +{ + pywraps_notify_when_t *_this = (pywraps_notify_when_t *)ud; + switch ( event_id ) + { + case idb_event::closebase: { PYW_GIL_GET; _this->notify(NW_CLOSEIDB_SLOT); @@ -1466,6 +1489,7 @@ void pywraps_notify_when_t::unregister_callback(int slot, PyObject *py_callable) bool pywraps_notify_when_t::init() { return hook_to_notification_point(HT_IDP, idp_callback, this); + return hook_to_notification_point(HT_IDB, idb_callback, this); } //------------------------------------------------------------------------ @@ -1479,7 +1503,8 @@ bool pywraps_notify_when_t::deinit() unregister_callback(slot, it->o); } // ...and remove the notification - return unhook_from_notification_point(HT_IDP, idp_callback, this); + bool ok = unhook_from_notification_point(HT_IDP, idp_callback, this); + return unhook_from_notification_point(HT_IDB, idb_callback, this) && ok; } //------------------------------------------------------------------------ @@ -1565,7 +1590,6 @@ bool pywraps_notify_when_t::notify_va(int slot, va_list va) ok = false; } } - in_notify = false; // Process any delayed notify_when() calls that @@ -1651,61 +1675,51 @@ static bool pywraps_nw_term() //------------------------------------------------------------------------- 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)); + QASSERT(30454, py_view != NULL && !_this->find_by_py_view(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) +void ida_export lookup_info_t_commit(lookup_info_t *_this, lookup_entry_t &e, TWidget *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; + QASSERT(30456, view != NULL && e.py_view != NULL + && !_this->find_by_view(NULL, view) + && _this->find_by_py_view(NULL, e.py_view)); 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); +#define FIND_BY__BODY(self, crit, res) \ + 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_##res != NULL ) \ + *out_##res = e.res; \ + return true; \ + } \ + } \ + return false; \ bool ida_export lookup_info_t_find_by_py_view( const lookup_info_t *_this, - TForm **out_form, - TCustomControl **out_view, + TWidget **out_view, const py_customidamemo_t *py_view) - FIND_BY__BODY(_this, py_view, view, form); +{ + FIND_BY__BODY(_this, py_view, view); +} -bool lookup_info_t::find_by_view( - TForm **out_form, +bool ida_export lookup_info_t_find_by_view( + const lookup_info_t *_this, py_customidamemo_t **out_py_view, - const TCustomControl *view) const - FIND_BY__BODY(this, view, form, py_view); + const TWidget *view) +{ + FIND_BY__BODY(_this, view, py_view); +} #undef FIND_BY__BODY //------------------------------------------------------------------------- @@ -1759,77 +1773,6 @@ void py_customidamemo_t::convert_node_info( #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, @@ -2028,11 +1971,11 @@ PyObject *ida_export py_customidamemo_t_set_groups_visibility( } //------------------------------------------------------------------------- -bool ida_export py_customidamemo_t_bind(py_customidamemo_t *_this, PyObject *self, TCustomControl *view) +bool ida_export py_customidamemo_t_bind(py_customidamemo_t *_this, PyObject *self, TWidget *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); + PYGLOG("%p: py_customidamemo_t::bind(self=%p, view=%p)\n", _this, _this->self.o, _this->view); PYW_GIL_CHECK_LOCKED_SCOPE(); newref_t py_cobj(PyCObject_FromVoidPtr(_this, NULL)); @@ -2057,50 +2000,11 @@ void ida_export py_customidamemo_t_unbind(py_customidamemo_t *_this, bool clear_ _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); } @@ -2131,275 +2035,6 @@ bool ida_export py_customidamemo_t_collect_pyobject_callbacks( 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 - //------------------------------------------------------------------------- // //------------------------------------------------------------------------- @@ -2476,6 +2111,7 @@ DEF_REG_UNREG_REFCOUNTED(array_type_data_t); DEF_REG_UNREG_REFCOUNTED(func_type_data_t); DEF_REG_UNREG_REFCOUNTED(udt_type_data_t); + //------------------------------------------------------------------------- // //--------------------------------------------------------------------------- @@ -2511,4 +2147,89 @@ static void clear_python_timer_instances(void) } } +//------------------------------------------------------------------------- +ref_t ida_export try_create_swig_wrapper(ref_t mod, const char *clsname, void *cobj) +{ + qstring wname; + wname.sprnt("%s__from_ptrval__", clsname); + ref_t res; + ref_t py_cls_wrapper_inst(PyW_TryGetAttrString(mod.o, wname.c_str())); + if ( py_cls_wrapper_inst != NULL ) + { + uninterruptible_op_t op; + res = newref_t(PyObject_CallFunction(py_cls_wrapper_inst.o, "(K)", uint64(cobj))); + } + return res; +} + +//------------------------------------------------------------------------- +typedef qvector modules_callbacks_t; +static modules_callbacks_t modules_callbacks; +void register_module_lifecycle_callbacks( + const module_callbacks_t &cbs) +{ + modules_callbacks.push_back(cbs); +} + +//------------------------------------------------------------------------- +// hooks +//------------------------------------------------------------------------- +#ifdef TESTABLE_BUILD +struct hook_data_t +{ + hook_type_t type; + hook_cb_t *cb; + void *ud; +}; +DECLARE_TYPE_AS_MOVABLE(hook_data_t); +typedef qvector hook_data_vec_t; +static hook_data_vec_t hook_data_vec; +#endif // TESTABLE_BUILD + +//------------------------------------------------------------------------- +bool ida_export idapython_hook_to_notification_point( + hook_type_t hook_type, + hook_cb_t *cb, + void *user_data) +{ + bool ok = hook_to_notification_point(hook_type, cb, user_data); +#ifdef TESTABLE_BUILD + if ( ok ) + { + hook_data_t &hd = hook_data_vec.push_back(); + hd.type = hook_type; + hd.cb = cb; + hd.ud = user_data; + } +#endif // TESTABLE_BUILD + return ok; +} + +//------------------------------------------------------------------------- +bool ida_export idapython_unhook_from_notification_point( + hook_type_t hook_type, + hook_cb_t *cb, + void *user_data) +{ + bool ok = unhook_from_notification_point(hook_type, cb, user_data); +#ifdef TESTABLE_BUILD + if ( ok ) + { + bool found = false; + for ( size_t i = 0, n = hook_data_vec.size(); i < n; ++i ) + { + const hook_data_t &hd = hook_data_vec[i]; + if ( hd.type == hook_type && hd.cb == cb && hd.ud == user_data ) + { + hook_data_vec.erase(hook_data_vec.begin() + i); + found = true; + break; + } + } + QASSERT(30510, found); + } +#endif // TESTABLE_BUILD + return ok; +} + #undef DEF_REG_UNREG_REFCOUNTED diff --git a/pywraps.hpp b/pywraps.hpp index afe7760..0d0ee40 100644 --- a/pywraps.hpp +++ b/pywraps.hpp @@ -4,22 +4,27 @@ #include //------------------------------------------------------------------------ -// Types -#ifndef PYUL_DEFINED - #define PYUL_DEFINED - #ifdef __EA64__ - typedef unsigned PY_LONG_LONG pyul_t; - typedef PY_LONG_LONG pyl_t; - #else - typedef unsigned long pyul_t; - typedef long pyl_t; - #endif -#endif +// The following are to be used whenever Py_BuildValue-style +// format specifiers are needed. +#define PY_BV_EA "K" // Convert a C unsigned long long to a Python long integer object. +#define PY_BV_SZ "n" // Convert a C Py_ssize_t to a Python integer or long integer. +#define PY_BV_UVAL PY_BV_EA +#define PY_BV_ASIZE PY_BV_EA +#define PY_BV_SEL PY_BV_EA +#define PY_BV_SVAL "L" // Convert a C long long to a Python long integer object +typedef unsigned PY_LONG_LONG bvea_t; +typedef Py_ssize_t bvsz_t; +typedef bvea_t bvuval_t; +typedef bvea_t bvasize_t; +typedef bvea_t bvsel_t; +typedef PY_LONG_LONG bvsval_t; + +//------------------------------------------------------------------------- // a few forward decls class insn_t; class op_t; -struct switch_info_ex_t; +struct switch_info_t; // "A pointer can be explicitly converted to any integral type large // enough to hold it. The mapping function is implementation-defined." @@ -49,19 +54,12 @@ struct switch_info_ex_t; #define exported #endif -#ifdef __EA64__ - #define PY_FMT64 "K" - #define PY_SFMT64 "L" -#else - #define PY_FMT64 "k" - #define PY_SFMT64 "l" -#endif - //------------------------------------------------------------------------ #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_IDA_MOVES_MODNAME "ida_moves" #define S_IDC_MODNAME "idc" #define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript" #define S_IDAAPI_COMPLETION "IDAPython_Completion" @@ -73,7 +71,7 @@ struct switch_info_ex_t; //------------------------------------------------------------------------ // 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_SWIEX_CLSNAME[] = "switch_info_t"; static const char S_PY_OP_T_CLSNAME[] = "op_t"; static const char S_PROPS[] = "props"; static const char S_NAME[] = "name"; @@ -108,11 +106,9 @@ 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"; @@ -123,19 +119,12 @@ 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_ON_INIT[] = "OnInit"; 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__"; @@ -198,7 +187,7 @@ 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) \ +#define GIL_CHKCONDFAIL (((debug & IDA_DEBUG_PLUGIN) != 0) \ && PyGILState_GetThisThreadState() != _PyThreadState_Current) #define PYW_GIL_CHECK_LOCKED_SCOPE() \ @@ -233,7 +222,7 @@ idaman void * ida_export pyobj_get_clink(PyObject *pyobj); // All the exported functions from PyWraps are forward declared here 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); } +inline switch_info_t *switch_info_t_get_clink(PyObject *self) { return (switch_info_t *)pyobj_get_clink(self); } //------------------------------------------------------------------------- // The base for a reference. Will automatically increase the reference @@ -379,9 +368,9 @@ exported bool ida_export PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_v // Returns a qstring from a Python attribute string exported bool ida_export PyW_GetStringAttr( - PyObject *py_obj, - const char *attr_name, - qstring *str); + 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 exported bool ida_export PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL); @@ -412,14 +401,25 @@ exported error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char // // Conversion functions // +#define PYWCVTF_AS_TUPLE 0x1 +#define PYWCVTF_INT64_AS_UNSIGNED_PYLONG 0x2 // don't wrap int64 into 'PyIdc_cvt_int64__' objects, but make them 'long' instead + +// Converts from IDC to Python exported bool ida_export pyw_convert_idc_args( const idc_value_t args[], int nargs, ref_vec_t &pargs, - bool as_tupple, - char *errbuf = NULL, - size_t errbufsize = 0); + uint32 flags, + qstring *errbuf = NULL); +// Converts from IDC to Python +// We support converting VT_REF IDC variable types +exported int ida_export idcvar_to_pyvar( + const idc_value_t &idc_var, + ref_t *py_var, + uint32 flags=0); + +//------------------------------------------------------------------------- // 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 exported int ida_export pyvar_to_idcvar( @@ -427,23 +427,18 @@ exported int ida_export pyvar_to_idcvar( idc_value_t *idc_var, int *gvar_sn = NULL); -// Converts from IDC to Python -// We support converting VT_REF IDC variable types -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 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, + 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 -exported ref_t ida_export PyW_IntVecToPyList(const intvec_t &intvec); +// Converts a sizevec_t to a Python list object +exported ref_t ida_export PyW_SizeVecToPyList(const sizevec_t &vec); -// Converts an Python list to an intvec -exported bool ida_export PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec); +// Converts an Python list to an sizevec +exported bool ida_export PyW_PyListToSizeVec(PyObject *py_list, sizevec_t &vec); // Converts an Python list to an eavec exported bool ida_export PyW_PyListToEaVec(PyObject *py_list, eavec_t &eavec); @@ -456,7 +451,7 @@ exported bool ida_export PyWStringOrNone_Check(PyObject *tp); //------------------------------------------------------------------------- #include -exported PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &areas); +exported PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &ranges); //------------------------------------------------------------------------- exported void ida_export PyW_register_compiled_form(PyObject *py_form); @@ -479,7 +474,8 @@ class pywraps_notify_when_t 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); + static ssize_t idaapi idp_callback(void *ud, int event_id, va_list va); + static ssize_t idaapi idb_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); @@ -498,7 +494,7 @@ exported bool ida_export add_notify_when(int when, PyObject *py_callable); // void free_compiled_form_instances(void); -//#define PYGDBG_ENABLED +// #define PYGDBG_ENABLED #ifdef PYGDBG_ENABLED #define PYGLOG(...) msg(__VA_ARGS__) #else @@ -528,6 +524,8 @@ private: pycall_res_t(); // No. }; +#include + //------------------------------------------------------------------------- // CustomIDAMemo wrappers //-------------------------------------------------------------------------i @@ -535,10 +533,9 @@ class lookup_info_t; class py_customidamemo_t; struct lookup_entry_t { - lookup_entry_t() : form(NULL), view(NULL), py_view(NULL) {} + lookup_entry_t() : view(NULL), py_view(NULL) {} - TForm *form; - TCustomControl *view; + TWidget *view; py_customidamemo_t *py_view; }; DECLARE_TYPE_AS_MOVABLE(lookup_entry_t); @@ -549,17 +546,17 @@ typedef qvector lookup_entries_t; #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_commit (lookup_info_t *_this, lookup_entry_t &e, TWidget *view) +#define PY_LINFO_PARAMS_commit (lookup_entry_t &e, TWidget *view) +#define PY_LINFO_TRANSM_commit (this, e, 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_view (const lookup_info_t *_this, py_customidamemo_t **out_py_view, const TWidget *view) +#define PY_LINFO_PARAMS_find_by_view (py_customidamemo_t **out_py_view, const TWidget *view) const +#define PY_LINFO_TRANSM_find_by_view (this, out_py_view, view) -#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_find_by_py_view (const lookup_info_t *_this, TWidget **out_view, const py_customidamemo_t *py_view) +#define PY_LINFO_PARAMS_find_by_py_view (TWidget **out_view, const py_customidamemo_t *py_view) const +#define PY_LINFO_TRANSM_find_by_py_view (this, 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) @@ -571,7 +568,7 @@ typedef qvector lookup_entries_t; #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_view, PY_LINFO_HLPPRM_find_by_view);\ 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); @@ -589,13 +586,11 @@ public: 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_view, PY_LINFO_PARAMS_find_by_view, PY_LINFO_TRANSM_find_by_view); 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; }; @@ -666,20 +661,14 @@ struct pycim_callbacks_ids_t : public qvector #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_HLPPRM_bind (py_customidamemo_t *_this, PyObject *self, TWidget *view) +#define PY_CIM_PARAMS_bind (PyObject *in_self, TWidget *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 @@ -696,10 +685,8 @@ struct pycim_callbacks_ids_t : public qvector \ 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); @@ -714,45 +701,21 @@ class py_customidamemo_t uint32 *out_flags, ref_t py_nodeinfo); + // can use up to 16 bits; not more! (GRCODE_HAVE_* uses the rest) 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, + GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x0001, }; 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, + TWidget *cv, int shift, view_mouse_event_t *e, void *ud); @@ -761,29 +724,23 @@ class py_customidamemo_t protected: ref_t self; - TCustomControl *view; + TWidget *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); + friend TWidget *pycim_get_widget(PyObject *self); public: py_customidamemo_t() - : self(newref_t(NULL)), + : cb_flags(0), + 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() { @@ -850,4 +807,55 @@ struct py_timer_ctx_t 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); +//------------------------------------------------------------------------- +exported ref_t ida_export try_create_swig_wrapper(ref_t mod, const char *clsname, void *cobj); + +//------------------------------------------------------------------------- +// Useful for small operations that must not be interrupted: e.g., when +// wrapping an insn_t into a SWiG proxy object, or when destroying +// such an instance from the kernel. Use 'uninterruptible_op_t' if you can. +exported void ida_export set_interruptible_state(bool interruptible); +struct uninterruptible_op_t +{ + uninterruptible_op_t() { set_interruptible_state(false); } + ~uninterruptible_op_t() { set_interruptible_state(true); } +}; + +// //------------------------------------------------------------------------- +// class py_custom_data_type_t; +// class py_custom_data_format_t; +// typedef void py_custom_data_type_t_unregisterer_t(py_custom_data_type_t *inst); +// typedef void py_custom_data_format_t_unregisterer_t(py_custom_data_format_t *inst); +// exported void ida_export register_py_custom_data_type_and_format_unregisterer( +// py_custom_data_type_t_unregisterer_t cdt_unregisterer, +// py_custom_data_format_t_unregisterer_t cdf_unregisterer); +// exported void ida_export register_py_custom_data_type_instance(py_custom_data_type_t *inst); +// exported void ida_export register_py_custom_data_format_instance(py_custom_data_format_t *inst); +// exported void ida_export unregister_py_custom_data_type_instance(py_custom_data_type_t *inst); +// exported void ida_export unregister_py_custom_data_format_instance(py_custom_data_format_t *inst); +// exported py_custom_data_type_t *py_custom_data_type_cast(data_type_t *inst); +// exported py_custom_data_format_t *py_custom_data_format_cast(data_format_t *inst); + +exported bool ida_export idapython_hook_to_notification_point( + hook_type_t hook_type, + hook_cb_t *cb, + void *user_data); +exported bool ida_export idapython_unhook_from_notification_point( + hook_type_t hook_type, + hook_cb_t *cb, + void *user_data); +#define hook_to_notification_point USE_IDAPYTHON_HOOK_TO_NOTIFICATION_POINT +#define unhook_from_notification_point USE_IDAPYTHON_UNHOOK_FROM_NOTIFICATION_POINT + +//------------------------------------------------------------------------- +struct module_callbacks_t +{ + module_callbacks_t() { memset(this, 0, sizeof(*this)); } + void (*closebase) (void); + void (*term) (void); +}; +DECLARE_TYPE_AS_MOVABLE(module_callbacks_t); +exported void register_module_lifecycle_callbacks( + const module_callbacks_t &cbs); + #endif // __PYWRAPS_HPP__ diff --git a/pywraps/driver.cpp b/pywraps/driver.cpp deleted file mode 100644 index 05412f3..0000000 --- a/pywraps/driver.cpp +++ /dev/null @@ -1,172 +0,0 @@ -//-------------------------------------------------------------------------- -// 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 deleted file mode 100644 index cf9446b..0000000 --- a/pywraps/driver_bytes.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#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 deleted file mode 100644 index f3775dc..0000000 --- a/pywraps/driver_chooser.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#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 deleted file mode 100644 index 208c81d..0000000 --- a/pywraps/driver_cli.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#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 deleted file mode 100644 index fec3d8c..0000000 --- a/pywraps/driver_custview.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#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 deleted file mode 100644 index f2ff86e..0000000 --- a/pywraps/driver_dbg.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#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 deleted file mode 100644 index 8f99dda..0000000 --- a/pywraps/driver_diskio.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#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 deleted file mode 100644 index c636adb..0000000 --- a/pywraps/driver_expr.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#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 deleted file mode 100644 index 6216c78..0000000 --- a/pywraps/driver_graph.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#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 deleted file mode 100644 index 1c28e45..0000000 --- a/pywraps/driver_kernwin.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#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 deleted file mode 100644 index 395d18b..0000000 --- a/pywraps/driver_nalt.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#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 deleted file mode 100644 index 662fe77..0000000 --- a/pywraps/driver_notifywhen.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#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/py_area.hpp b/pywraps/py_area.hpp deleted file mode 100644 index 85c5a4b..0000000 --- a/pywraps/py_area.hpp +++ /dev/null @@ -1,11 +0,0 @@ - -// -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_auto.py b/pywraps/py_auto.py new file mode 100644 index 0000000..5996d14 --- /dev/null +++ b/pywraps/py_auto.py @@ -0,0 +1,14 @@ + +# +analyze_area = plan_and_wait +autoCancel = auto_cancel +autoIsOk = auto_is_ok +autoMark = auto_mark +autoUnmark = auto_unmark +autoWait = auto_wait + +noUsed = plan_ea +setStat = set_ida_state +showAddr = show_addr +showAuto = show_auto +# diff --git a/pywraps/py_bytes.hpp b/pywraps/py_bytes.hpp index 13d7d98..bffa52b 100644 --- a/pywraps/py_bytes.hpp +++ b/pywraps/py_bytes.hpp @@ -19,29 +19,92 @@ static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next) if ( !PyCallable_Check(py_callable) ) return BADADDR; else - return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable); + return (next ? next_that : prev_that)(ea, bound, py_testf_cb, py_callable); } //--------------------------------------------------------------------------- static int idaapi py_visit_patched_bytes_cb( - ea_t ea, - int32 fpos, - uint32 o, - uint32 v, - void *ud) + ea_t ea, + qoff64_t fpos, + uint32 o, + uint32 v, + void *ud) { PYW_GIL_CHECK_LOCKED_SCOPE(); newref_t py_result( PyObject_CallFunction( (PyObject *)ud, - PY_FMT64 "iII", - pyul_t(ea), + PY_BV_EA "LII", + bvea_t(ea), fpos, o, v)); PyW_ShowCbErr("visit_patched_bytes"); return (py_result != NULL && PyInt_Check(py_result.o)) ? PyInt_AsLong(py_result.o) : 0; } + +//------------------------------------------------------------------------- +static void ida_bytes_term(void) {} + +//------------------------------------------------------------------------- +static void clear_custom_data_types_and_formats(); +static void ida_bytes_closebase(void) +{ + clear_custom_data_types_and_formats(); +} + +//------------------------------------------------------------------------- +static bool py_do_get_bytes( + PyObject **out_py_bytes, + PyObject **out_py_mask, + ea_t ea, + unsigned int size, + int gmb_flags) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + bool has_mask = out_py_mask != NULL; + do + { + if ( size <= 0 ) + break; + + // Allocate memory via Python + newref_t py_bytes(PyString_FromStringAndSize(NULL, Py_ssize_t(size))); + if ( py_bytes == NULL ) + break; + + bytevec_t mask; + if ( has_mask ) + mask.resize((size + 7) / 8, 0); + + // Read bytes + int code = get_bytes(PyString_AsString(py_bytes.o), + size, + ea, + gmb_flags, + has_mask ? mask.begin() : NULL); + if ( code < 0 ) + break; + + // note: specify size, as '0' bytes would otherwise cut the mask short + if ( has_mask ) + { + newref_t py_mask(PyString_FromStringAndSize( + (const char *) mask.begin(), + mask.size())); + if ( py_mask == NULL ) + break; + py_mask.incref(); + *out_py_mask = py_mask.o; + } + + py_bytes.incref(); + *out_py_bytes = py_bytes.o; + return true; + } while ( false ); + return false; +} + // //------------------------------------------------------------------------ @@ -78,7 +141,7 @@ static int py_visit_patched_bytes(ea_t ea1, ea_t ea2, PyObject *py_callable) //------------------------------------------------------------------------ /* # -def nextthat(ea, maxea, callable): +def next_that(ea, maxea, callable): """ Find next address with a flag satisfying the function 'testf'. Start searching from address 'ea'+1 and inspect bytes up to 'maxea'. @@ -91,13 +154,13 @@ def nextthat(ea, maxea, callable): pass # */ -static ea_t py_nextthat(ea_t ea, ea_t maxea, PyObject *callable) +static ea_t py_next_that(ea_t ea, ea_t maxea, PyObject *callable) { return py_npthat(ea, maxea, callable, true); } //--------------------------------------------------------------------------- -static ea_t py_prevthat(ea_t ea, ea_t minea, PyObject *callable) +static ea_t py_prev_that(ea_t ea, ea_t minea, PyObject *callable) { return py_npthat(ea, minea, callable, false); } @@ -105,106 +168,57 @@ static ea_t py_prevthat(ea_t ea, ea_t minea, PyObject *callable) //------------------------------------------------------------------------ /* # -def get_many_bytes(ea, size): +def get_bytes(ea, size): """ - Get the specified number of bytes of the program into the buffer. + Get the specified number of bytes of the program. @param ea: program address @param size: number of bytes to return - @return: None or the string buffer + @return: the bytes (as a str), or None in case of failure """ pass # */ -static PyObject *py_get_many_bytes(ea_t ea, unsigned int size) +static PyObject *py_get_bytes(ea_t ea, unsigned int size, int gmb_flags=GMB_READALL) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - do - { - if ( size <= 0 ) - break; - - // Allocate memory via Python - newref_t py_buf(PyString_FromStringAndSize(NULL, Py_ssize_t(size))); - if ( py_buf == NULL ) - break; - - // Read bytes - if ( !get_many_bytes(ea, PyString_AsString(py_buf.o), size) ) - Py_RETURN_NONE; - - py_buf.incref(); - return py_buf.o; - } while ( false ); - Py_RETURN_NONE; + PyObject *py_bytes = NULL; + if ( py_do_get_bytes(&py_bytes, NULL, ea, size, gmb_flags) ) + return py_bytes; + else + Py_RETURN_NONE; } //--------------------------------------------------------------------------- /* # -def get_many_bytes_ex(ea, size, mask): +def get_bytes_and_mask(ea, size, mask): """ - Get the specified number of bytes of the program into the buffer. + Get the specified number of bytes of the program, and a bitmask + specifying what bytes are defined and what bytes are not. @param ea: program address @param size: number of bytes to return - @return: None or (string buffer, string mask) + @return: a tuple (bytes, mask), or None in case of failure. + Both 'bytes' and 'mask' are 'str' instances. """ pass # */ -static PyObject *py_get_many_bytes_ex(ea_t ea, unsigned int size) +static PyObject *py_get_bytes_and_mask(ea_t ea, unsigned int size, int gmb_flags=GMB_READALL) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - do - { - if ( size <= 0 ) - break; - - // Allocate memory via Python - newref_t py_buf(PyString_FromStringAndSize(NULL, Py_ssize_t(size))); - if ( py_buf == NULL ) - break; - - bytevec_t mask; - mask.resize((size + 7) / 8, 0); - - // Read bytes - int code = get_many_bytes_ex( - ea, - PyString_AsString(py_buf.o), - size, - (void *) mask.begin()); - if ( code < 0 ) - Py_RETURN_NONE; - - // note: specify size, as '0' bytes would otherwise cut the mask short - newref_t py_mask( - PyString_FromStringAndSize( - (const char *) mask.begin(), - mask.size())); - if ( py_mask == NULL ) - break; - - py_buf.incref(); - py_mask.incref(); - return Py_BuildValue("(OO)", py_buf.o, py_mask.o); - } while ( false ); - Py_RETURN_NONE; + PyObject *py_bytes = NULL; + PyObject *py_mask = NULL; + if ( py_do_get_bytes(&py_bytes, &py_mask, ea, size, gmb_flags) ) + return Py_BuildValue("(OO)", py_bytes, py_mask); + else + Py_RETURN_NONE; } //--------------------------------------------------------------------------- /* # -# Conversion options for get_ascii_contents2(): -ACFOPT_ASCII = 0x00000000 # convert Unicode strings to ASCII -ACFOPT_UTF16 = 0x00000001 # return UTF-16 (aka wide-char) array for Unicode strings - # ignored for non-Unicode strings -ACFOPT_UTF8 = 0x00000002 # convert Unicode strings to UTF-8 - # ignored for non-Unicode strings -ACFOPT_CONVMASK = 0x0000000F -ACFOPT_ESCAPE = 0x00000010 # for ACFOPT_ASCII, convert non-printable - # characters to C escapes (\n, \xNN, \uNNNN) +# Conversion options for get_strlit_contents(): +STRCONV_ESCAPE = 0x00000001 # convert non-printable characters to C escapes (\n, \xNN, \uNNNN) -def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII): +def get_strlit_contents(ea, len, type, flags = 0): """ Get bytes contents at location, possibly converted. It works even if the string has not been created in the database yet. @@ -219,60 +233,52 @@ def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII): @param len: length of the string in bytes (including terminating 0) @param type: type of the string. Represents both the character encoding, and the 'type' of string at the given location. - @param flags: combination of ACFOPT_..., to perform output conversion. + @param flags: combination of STRCONV_..., to perform output conversion. @return: a bytes-filled str object. """ pass # */ -static PyObject *py_get_ascii_contents2( - ea_t ea, - size_t len, - int32 type, - int flags = ACFOPT_ASCII) +static PyObject *py_get_strlit_contents( + ea_t ea, + size_t len, + int32 type, + int flags = 0) { - char *buf = (char *)qalloc(len+1); - if ( buf == NULL ) - return NULL; + qstring buf; - size_t used_size; - if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size, flags) ) - { - qfree(buf); + if ( get_strlit_contents(&buf, ea, len, type, NULL, flags) < 0 ) Py_RETURN_NONE; - } - if ( type == ASCSTR_C && used_size > 0 && buf[used_size-1] == '\0' ) - used_size--; + if ( type == STRTYPE_C && buf.length() > 0 && buf.last() == '\0' ) + buf.remove_last(); PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t py_buf(PyString_FromStringAndSize((const char *)buf, used_size)); - qfree(buf); + newref_t py_buf(PyString_FromStringAndSize(buf.begin(), buf.length())); py_buf.incref(); return py_buf.o; } -//--------------------------------------------------------------------------- -/* -# -def get_ascii_contents(ea, len, type): - """ - Get contents of ascii string - This function returns the displayed part of the string - It works even if the string has not been created in the database yet. - @param ea: linear address of the string - @param len: length of the string in bytes (including terminating 0) - @param type: type of the string - @return: string contents (not including terminating 0) or None - """ - pass -# -*/ -static PyObject *py_get_ascii_contents( - ea_t ea, - size_t len, - int32 type) +//------------------------------------------------------------------------- +static ea_t py_bin_search( + ea_t start_ea, + ea_t end_ea, + const uchar *image, + size_t len, + const uchar *mask, + int step, + int flags) { - return py_get_ascii_contents2(ea, len, type); + return bin_search(start_ea, end_ea, image, mask, len, step, flags); } + +//------------------------------------------------------------------------- +static PyObject *py_print_strlit_type(int32 strtype, int flags=0) +{ + qstring s, t; + if ( !print_strlit_type(&s, strtype, &t, flags) ) + Py_RETURN_NONE; + return Py_BuildValue("(ss)", s.c_str(), t.c_str()); +} + // #endif diff --git a/pywraps/py_bytes.py b/pywraps/py_bytes.py index 50516db..4c82e61 100644 --- a/pywraps/py_bytes.py +++ b/pywraps/py_bytes.py @@ -1,8 +1,234 @@ # -def doExtra(ea): - setFlags(ea, get_flags_novalue(ea) | FF_LINE) - -def noExtra(ea): - setFlags(ea, get_flags_novalue(ea) & ~(FF_LINE)) # + + +# +ACFOPT_ASCII=0 +ACFOPT_CONVMASK=0 +ACFOPT_ESCAPE=STRCONV_ESCAPE +ACFOPT_UTF16=0 +ACFOPT_UTF8=0 +DOUNK_DELNAMES=DELIT_DELNAMES +DOUNK_EXPAND=DELIT_EXPAND +DOUNK_NOTRUNC=DELIT_NOTRUNC +DOUNK_SIMPLE=DELIT_SIMPLE +FF_ASCI=FF_STRLIT +FF_DWRD=FF_DWORD +FF_OWRD=FF_OWORD +FF_QWRD=FF_QWORD +FF_STRU=FF_STRUCT +FF_TBYT=FF_TBYTE +FF_VAR=0 +FF_YWRD=FF_YWORD +FF_ZWRD=FF_ZWORD +GFE_NOVALUE=0 +add_hidden_area=add_hidden_range +asciflag=strlit_flag +delValue=del_value +del_hidden_area=del_hidden_range +do16bit=create_16bit_data +do32bit=create_32bit_data +doAlign=create_align +doByte=create_byte +doCustomData=create_custdata +doDouble=create_double +doDwrd=create_dword +doExtra=ida_idaapi._BC695.false_p +doFloat=create_float +doImmd=set_immd +doOwrd=create_oword +doPackReal=create_packed_real +doQwrd=create_qword +doStruct=create_struct +doTbyt=create_tbyte +doWord=create_word +doYwrd=create_yword +doZwrd=create_zword +do_data_ex=create_data +do_unknown=del_items +@bc695redef +def do_unknown_range(ea, size, flags): + return del_items(ea, flags, size) # swap 2 last args +dwrdflag=dword_flag +f_hasRef=f_has_xref +f_isASCII=f_is_strlit +f_isAlign=f_is_align +f_isByte=f_is_byte +f_isCode=f_is_code +f_isCustom=f_is_custom +f_isData=f_is_data +f_isDouble=f_is_double +f_isDwrd=f_is_dword +f_isFloat=f_is_float +f_isHead=f_is_head +f_isNotTail=f_is_not_tail +f_isOwrd=f_is_oword +f_isPackReal=f_is_pack_real +f_isQwrd=f_is_qword +f_isStruct=f_is_struct +f_isTail=f_is_tail +f_isTbyt=f_is_tbyte +f_isWord=f_is_word +f_isYwrd=f_is_yword +getDefaultRadix=get_default_radix +getFlags=get_full_flags +get_long=get_dword +get_full_byte=get_wide_byte +get_full_word=get_wide_word +get_full_long=get_wide_dword +get_original_long=get_original_dword +put_long=put_dword +patch_long=patch_dword +add_long=add_dword +getRadix=get_radix +get_ascii_contents=get_strlit_contents +get_ascii_contents2=get_strlit_contents +get_flags_novalue=get_flags +get_hidden_area=get_hidden_range +get_hidden_area_num=get_hidden_range_num +get_hidden_area_qty=get_hidden_range_qty +@bc695redef +def get_many_bytes(ea, size): + return get_bytes(ea, size) +@bc695redef +def get_many_bytes_ex(ea, size): + return get_bytes_and_mask(ea, size) +get_max_ascii_length=get_max_strlit_length +get_next_hidden_area=get_next_hidden_range +get_prev_hidden_area=get_prev_hidden_range +get_zero_areas=get_zero_ranges +getn_hidden_area=getn_hidden_range +hasExtra=has_extra_cmts +hasRef=has_xref +hasValue=has_value +hidden_area_t=hidden_range_t +isASCII=is_strlit +isAlign=is_align +isByte=is_byte +isChar=is_char +isChar0=is_char0 +isChar1=is_char1 +isCode=is_code +isCustFmt=is_custfmt +isCustFmt0=is_custfmt0 +isCustFmt1=is_custfmt1 +isCustom=is_custom +isData=is_data +isDefArg=is_defarg +isDefArg0=is_defarg0 +isDefArg1=is_defarg1 +isDouble=is_double +isDwrd=is_dword +isEnabled=is_mapped +isEnum=is_enum +isEnum0=is_enum0 +isEnum1=is_enum1 +isFloat=is_float +isFloat0=is_float0 +isFloat1=is_float1 +isFlow=is_flow +isFltnum=is_fltnum +isFop=is_forced_operand +isFunc=is_func +isHead=is_head +isImmd=has_immd +isLoaded=is_loaded +isNotTail=is_not_tail +isNum=is_numop +isNum0=is_numop0 +isNum1=is_numop1 +isOff=is_off +isOff0=is_off0 +isOff1=is_off1 +isOwrd=is_oword +isPackReal=is_pack_real +isQwrd=is_qword +isSeg=is_seg +isSeg0=is_seg0 +isSeg1=is_seg1 +isStkvar=is_stkvar +isStkvar0=is_stkvar0 +isStkvar1=is_stkvar1 +isStroff=is_stroff +isStroff0=is_stroff0 +isStroff1=is_stroff1 +isStruct=is_struct +isTail=is_tail +isTbyt=is_tbyte +isUnknown=is_unknown +isVoid=is_suspop +isWord=is_word +isYwrd=is_yword +isZwrd=is_zword +make_ascii_string=create_strlit +noExtra=ida_idaapi._BC695.false_p +noType=clr_op_type +owrdflag=oword_flag +patch_many_bytes=patch_bytes +print_ascii_string_type=print_strlit_type +put_many_bytes=put_bytes +qwrdflag=qword_flag +tbytflag=tbyte_flag +update_hidden_area=update_hidden_range +ywrdflag=yword_flag +zwrdflag=zword_flag +def get_opinfo(*args): + import ida_nalt + if isinstance(args[3], ida_nalt.opinfo_t): # 6.95: ea, n, flags, buf + ea, n, flags, buf = args + else: # 7.00: buf, ea, n, flags + buf, ea, n, flags = args + return _ida_bytes.get_opinfo(buf, ea, n, flags) +@bc695redef +def doASCI(ea, length): + import ida_netnode + return create_data(ea, FF_STRLIT, length, ida_netnode.BADNODE) +FF_3BYTE=FF_BYTE +chunksize=chunk_size +chunkstart=chunk_start +do3byte=ida_idaapi._BC695.false_p +f_is3byte=ida_idaapi._BC695.false_p +freechunk=free_chunk +get_3byte=ida_idaapi._BC695.false_p +is3byte=ida_idaapi._BC695.false_p +nextaddr=next_addr +nextchunk=next_chunk +nextthat=next_that +prevaddr=prev_addr +prevchunk=prev_chunk +prevthat=prev_that +tribyteflag=byte_flag +alignflag=align_flag +binflag=bin_flag +byteflag=byte_flag +charflag=char_flag +codeflag=code_flag +custflag=cust_flag +custfmtflag=custfmt_flag +decflag=dec_flag +doubleflag=double_flag +enumflag=enum_flag +floatflag=float_flag +fltflag=flt_flag +hexflag=hex_flag +numflag=num_flag +octflag=oct_flag +offflag=off_flag +packrealflag=packreal_flag +segflag=seg_flag +stkvarflag=stkvar_flag +stroffflag=stroff_flag +struflag=stru_flag +wordflag=word_flag +invalidate_visea_cache=ida_idaapi._BC695.false_p +@bc695redef +def op_stroff(*args): + insn, n, path, path_len, delta = args + import ida_ua + if not isinstance(insn, ida_ua.insn_t): + tmp = ida_ua.insn_t() + ida_ua.decode_insn(tmp, insn) + insn = tmp + return _ida_bytes.op_stroff(insn, n, path, path_len, delta) +# diff --git a/pywraps/py_bytes_custdata.hpp b/pywraps/py_bytes_custdata.hpp index 369bd9e..4f0b703 100644 --- a/pywraps/py_bytes_custdata.hpp +++ b/pywraps/py_bytes_custdata.hpp @@ -2,29 +2,33 @@ #define __PY_IDA_BYTES_CUSTDATA__ // -class py_custom_data_type_t + +//------------------------------------------------------------------------- +class py_custom_data_type_t; +static qvector py_custom_data_types; + +//------------------------------------------------------------------------- +class py_custom_data_type_t : public data_type_t { - data_type_t dt; qstring dt_name, dt_menu_name, dt_hotkey, dt_asm_keyword; int dtid; // The data format id - PyObject *py_self; // Associated Python object + PyObject *py_self; // may create data? NULL means always may static bool idaapi s_may_create_at( - void *ud, // user-defined data - ea_t ea, // address of the future item - size_t nbytes) // size of the future item + void *ud, // user-defined data + ea_t ea, // address of the future item + size_t nbytes) // size of the future item { py_custom_data_type_t *_this = (py_custom_data_type_t *)ud; - PYW_GIL_GET; newref_t py_result( PyObject_CallMethod( _this->py_self, (char *)S_MAY_CREATE_AT, - PY_FMT64 PY_FMT64, - pyul_t(ea), - pyul_t(nbytes))); + PY_BV_EA PY_BV_SZ, + bvea_t(ea), + bvsz_t(nbytes))); PyW_ShowCbErr(S_MAY_CREATE_AT); return py_result != NULL && PyObject_IsTrue(py_result.o); @@ -32,11 +36,11 @@ class py_custom_data_type_t // !=NULL means variable size datatype static asize_t idaapi s_calc_item_size( - // This function is used to determine - // size of the (possible) item at 'ea' - void *ud, // user-defined data - ea_t ea, // address of the item - asize_t maxsize) // maximal size of the item + // This function is used to determine + // size of the (possible) item at 'ea' + void *ud, // user-defined data + ea_t ea, // address of the item + asize_t maxsize) // maximal size of the item { PYW_GIL_GET; // Returns: 0-no such item can be created/displayed @@ -46,9 +50,9 @@ class py_custom_data_type_t PyObject_CallMethod( _this->py_self, (char *)S_CALC_ITEM_SIZE, - PY_FMT64 PY_FMT64, - pyul_t(ea), - pyul_t(maxsize))); + PY_BV_EA PY_BV_ASIZE, + bvea_t(ea), + bvasize_t(maxsize))); if ( PyW_ShowCbErr(S_CALC_ITEM_SIZE) || py_result == NULL ) return 0; @@ -59,132 +63,127 @@ class py_custom_data_type_t } public: - const char *get_name() const - { - return dt_name.c_str(); - } - - py_custom_data_type_t() + py_custom_data_type_t( + PyObject *py_dt, + const char *name, + asize_t value_size, + const char *menu_name, + const char *hotkey, + const char *asm_keyword, + int props) { + memset(this, 0, sizeof(data_type_t)); + cbsize = sizeof(data_type_t); + dt_name = name; + dt_menu_name = menu_name; + dt_hotkey = hotkey; + dt_asm_keyword = asm_keyword; + this->name = dt_name.begin(); + this->menu_name = dt_menu_name.begin(); + this->hotkey = dt_hotkey.begin(); + this->asm_keyword = dt_asm_keyword.begin(); + this->value_size = value_size; + this->props = props; dtid = -1; - py_self = NULL; + py_custom_data_types.add_unique(this); + py_self = py_dt; } - int register_dt(PyObject *py_obj) + ~py_custom_data_type_t() + { + do_unregister(); + py_custom_data_types.del(this); + } + + int get_dtid() const { return dtid; } + + int do_register() { PYW_GIL_CHECK_LOCKED_SCOPE(); // Already registered? if ( dtid >= 0 ) - return dtid; + return -1; - memset(&dt, 0, sizeof(dt)); - dt.cbsize = sizeof(dt); - dt.ud = this; + ud = this; - do - { - ref_t py_attr; + ref_t py_attr; - // name - if ( !PyW_GetStringAttr(py_obj, S_NAME, &dt_name) ) - break; + // may_create_at + py_attr = PyW_TryGetAttrString(py_self, S_MAY_CREATE_AT); + if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) + may_create_at = s_may_create_at; - dt.name = dt_name.c_str(); + // calc_item_size + py_attr = PyW_TryGetAttrString(py_self, S_CALC_ITEM_SIZE); + if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) + calc_item_size = s_calc_item_size; - // menu_name (optional) - if ( PyW_GetStringAttr(py_obj, S_MENU_NAME, &dt_menu_name) ) - dt.menu_name = dt_menu_name.c_str(); - - // asm_keyword (optional) - if ( PyW_GetStringAttr(py_obj, S_ASM_KEYWORD, &dt_asm_keyword) ) - dt.asm_keyword = dt_asm_keyword.c_str(); - - // hotkey (optional) - if ( PyW_GetStringAttr(py_obj, S_HOTKEY, &dt_hotkey) ) - dt.hotkey = dt_hotkey.c_str(); - - // value_size - py_attr = PyW_TryGetAttrString(py_obj, S_VALUE_SIZE); - if ( py_attr != NULL && PyInt_Check(py_attr.o) ) - dt.value_size = PyInt_AsLong(py_attr.o); - py_attr = ref_t(); - - // props - py_attr = PyW_TryGetAttrString(py_obj, S_PROPS); - if ( py_attr != NULL && PyInt_Check(py_attr.o) ) - dt.props = PyInt_AsLong(py_attr.o); - py_attr = ref_t(); - - // may_create_at - py_attr = PyW_TryGetAttrString(py_obj, S_MAY_CREATE_AT); - if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) - dt.may_create_at = s_may_create_at; - py_attr = ref_t(); - - // calc_item_size - py_attr = PyW_TryGetAttrString(py_obj, S_CALC_ITEM_SIZE); - if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) - dt.calc_item_size = s_calc_item_size; - py_attr = ref_t(); - - // Now try to register - dtid = register_custom_data_type(&dt); - if ( dtid < 0 ) - break; - - // Hold reference to the PyObject - Py_INCREF(py_obj); - py_self = py_obj; - - py_attr = newref_t(PyInt_FromLong(dtid)); - PyObject_SetAttrString(py_obj, S_ID, py_attr.o); - } while ( false ); + // Now try to register + dtid = register_custom_data_type(this); + if ( dtid >= 0 ) + Py_INCREF(py_self); return dtid; } - bool unregister_dt() + bool do_unregister() { PYW_GIL_CHECK_LOCKED_SCOPE(); - - if ( dtid < 0 ) - return true; - - if ( !unregister_custom_data_type(dtid) ) - return false; - - // Release reference of Python object - Py_XDECREF(py_self); - py_self = NULL; - dtid = -1; - return true; - } - - ~py_custom_data_type_t() - { - unregister_dt(); + bool ok = unregister_custom_data_type(dtid); + if ( ok ) + { + // when this is called at IDAPython-shutdown-time, this will cause the + // dtor to be called, which in turn will call this 'do_unregister' a + // second time, but this is no problem since the dtid has already been + // unregistered and thus we won't end up in this Py_XDECREF block. + Py_XDECREF(py_self); + dtid = -1; + } + return ok; } }; -typedef std::map py_custom_data_type_map_t; -static py_custom_data_type_map_t py_dt_map; -//------------------------------------------------------------------------ -class py_custom_data_format_t +//------------------------------------------------------------------------- +py_custom_data_type_t *py_custom_data_type_cast(data_type_t *inst) +{ + // The following code seems to not work with gcc. Compiler bug? Not sure, but no time ATM + // py_custom_data_type_t *py_inst = (py_custom_data_type_t *) inst; + // py_custom_data_types.has(py_inst) ? py_inst : NULL; + if ( py_custom_data_types.has((py_custom_data_type_t *) inst) ) + return (py_custom_data_type_t *) inst; + else + return 0; +} + +//------------------------------------------------------------------------- +static int py_custom_data_type_t_get_id(data_type_t *_dt) +{ + py_custom_data_type_t *dt = py_custom_data_type_cast(_dt); + return dt != NULL ? dt->get_dtid() : -1; +} + +//------------------------------------------------------------------------- +// data_format_t +//------------------------------------------------------------------------- +class py_custom_data_format_t; +static qvector py_custom_data_formats; + +//------------------------------------------------------------------------- +class py_custom_data_format_t : public data_format_t { private: - data_format_t df; int dfid; PyObject *py_self; qstring df_name, df_menu_name, df_hotkey; - static bool idaapi s_print( // convert to colored string - void *ud, // user-defined data - qstring *out, // output buffer. may be NULL - const void *value, // value to print. may not be NULL - asize_t size, // size of value in bytes - ea_t current_ea, // current address (BADADDR if unknown) - int operand_num, // current operand number - int dtid) // custom data type id + static bool idaapi s_print( // convert to colored string + void *ud, // user-defined data + qstring *out, // output buffer. may be NULL + const void *value, // value to print. may not be NULL + asize_t size, // size of value in bytes + ea_t current_ea, // current address (BADADDR if unknown) + int operand_num, // current operand number + int dtid) // custom data type id { PYW_GIL_GET; @@ -199,9 +198,9 @@ private: newref_t py_result(PyObject_CallMethod( _this->py_self, (char *)S_PRINTF, - "O" PY_FMT64 "ii", + "O" PY_BV_EA "ii", py_value.o, - pyul_t(current_ea), + bvea_t(current_ea), operand_num, dtid)); @@ -224,13 +223,13 @@ private: return ok; } - static bool idaapi s_scan( // convert from uncolored string - void *ud, // user-defined data - bytevec_t *value, // output buffer. may be NULL - const char *input, // input string. may not be NULL - ea_t current_ea, // current address (BADADDR if unknown) - int operand_num, // current operand number (-1 if unknown) - qstring *errstr) // buffer for error message + static bool idaapi s_scan( // convert from uncolored string + void *ud, // user-defined data + bytevec_t *value, // output buffer. may be NULL + const char *input, // input string. may not be NULL + ea_t current_ea, // current address (BADADDR if unknown) + int operand_num, // current operand number (-1 if unknown) + qstring *errstr) // buffer for error message { PYW_GIL_GET; @@ -239,9 +238,9 @@ private: PyObject_CallMethod( _this->py_self, (char *)S_SCAN, - "s" PY_FMT64, + "s" PY_BV_EA "i", input, - pyul_t(current_ea), + bvea_t(current_ea), operand_num)); // Error while calling the function? @@ -292,10 +291,10 @@ private: return ok; } - static void idaapi s_analyze( // analyze custom data format occurrence - void *ud, // user-defined data - ea_t current_ea, // current address (BADADDR if unknown) - int operand_num) // current operand number + static void idaapi s_analyze( // analyze custom data format occurrence + void *ud, // user-defined data + ea_t current_ea, // current address (BADADDR if unknown) + int operand_num) // current operand number // this callback can be used to create // xrefs from the current item. // this callback may be missing. @@ -307,190 +306,117 @@ private: PyObject_CallMethod( _this->py_self, (char *)S_ANALYZE, - PY_FMT64 "i", - pyul_t(current_ea), + PY_BV_EA "i", + bvea_t(current_ea), operand_num)); PyW_ShowCbErr(S_ANALYZE); } public: - py_custom_data_format_t() + py_custom_data_format_t( + PyObject *py_df, + const char *name, + asize_t value_size, + const char *menu_name, + int props, + const char *hotkey, + int32 text_width) { + memset(this, 0, sizeof(data_format_t)); + cbsize = sizeof(data_format_t); + df_name = name; + df_menu_name = menu_name; + df_hotkey = hotkey; + this->name = df_name.begin(); + this->menu_name = df_menu_name.begin(); + this->hotkey = df_hotkey.begin(); + this->value_size = value_size; + this->props = props; + this->text_width = text_width; dfid = -1; - py_self = NULL; - } - - const char *get_name() const - { - return df_name.c_str(); - } - - int register_df(int dtid, PyObject *py_obj) - { - // Already registered? - if ( dfid >= 0 ) - return dfid; - - memset(&df, 0, sizeof(df)); - df.cbsize = sizeof(df); - df.ud = this; - - PYW_GIL_CHECK_LOCKED_SCOPE(); - do - { - ref_t py_attr; - - // name - if ( !PyW_GetStringAttr(py_obj, S_NAME, &df_name) ) - break; - df.name = df_name.c_str(); - - // menu_name (optional) - if ( PyW_GetStringAttr(py_obj, S_MENU_NAME, &df_menu_name) ) - df.menu_name = df_menu_name.c_str(); - - // props - py_attr = PyW_TryGetAttrString(py_obj, S_PROPS); - if ( py_attr != NULL && PyInt_Check(py_attr.o) ) - df.props = PyInt_AsLong(py_attr.o); - - // hotkey - if ( PyW_GetStringAttr(py_obj, S_HOTKEY, &df_hotkey) ) - df.hotkey = df_hotkey.c_str(); - - // value_size - py_attr = PyW_TryGetAttrString(py_obj, S_VALUE_SIZE); - if ( py_attr != NULL && PyInt_Check(py_attr.o) ) - df.value_size = PyInt_AsLong(py_attr.o); - - // text_width - py_attr = PyW_TryGetAttrString(py_obj, S_TEXT_WIDTH); - if ( py_attr != NULL && PyInt_Check(py_attr.o) ) - df.text_width = PyInt_AsLong(py_attr.o); - - // print cb - py_attr = PyW_TryGetAttrString(py_obj, S_PRINTF); - if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) - df.print = s_print; - - // scan cb - py_attr = PyW_TryGetAttrString(py_obj, S_SCAN); - if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) - df.scan = s_scan; - - // analyze cb - py_attr = PyW_TryGetAttrString(py_obj, S_ANALYZE); - if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) - df.analyze = s_analyze; - - // Now try to register - dfid = register_custom_data_format(dtid, &df); - if ( dfid < 0 ) - break; - - // Hold reference to the PyObject - Py_INCREF(py_obj); - py_self = py_obj; - - // Update the format ID - py_attr = newref_t(PyInt_FromLong(dfid)); - PyObject_SetAttrString(py_obj, S_ID, py_attr.o); - } while ( false ); - return dfid; - } - - bool unregister_df(int dtid) - { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Never registered? - if ( dfid < 0 ) - return true; - - if ( !unregister_custom_data_format(dtid, dfid) ) - return false; - - // Release reference of Python object - Py_XDECREF(py_self); - py_self = NULL; - dfid = -1; - return true; + py_custom_data_formats.add_unique(this); + py_self = py_df; } ~py_custom_data_format_t() { + do_unregister(); + py_custom_data_formats.del(this); } -}; -//------------------------------------------------------------------------ -// Helper class to bind pairs to py_custom_data_format_t -class py_custom_data_format_list_t -{ - struct py_custom_data_format_entry_t + int get_dfid() const { return dfid; } + + int do_register() { - int dtid; - int dfid; - py_custom_data_format_t *df; - }; - typedef qvector ENTRY; - ENTRY entries; -public: - typedef ENTRY::iterator POS; - void add(int dtid, int dfid, py_custom_data_format_t *df) - { - py_custom_data_format_entry_t &e = entries.push_back(); - e.dtid = dtid; - e.dfid = dfid; - e.df = df; + // Already registered? + if ( dfid >= 0 ) + return -1; + + ud = this; + + PYW_GIL_CHECK_LOCKED_SCOPE(); + ref_t py_attr; + + // print cb + py_attr = PyW_TryGetAttrString(py_self, S_PRINTF); + if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) + print = s_print; + + // scan cb + py_attr = PyW_TryGetAttrString(py_self, S_SCAN); + if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) + scan = s_scan; + + // analyze cb + py_attr = PyW_TryGetAttrString(py_self, S_ANALYZE); + if ( py_attr != NULL && PyCallable_Check(py_attr.o) ) + analyze = s_analyze; + + // Now try to register + dfid = register_custom_data_format(this); + if ( dfid >= 0 ) + Py_INCREF(py_self); + return dfid; } - py_custom_data_format_t *find(int dtid, int dfid, POS *loc = NULL) + + bool do_unregister() { - for ( POS it=entries.begin(), it_end = entries.end(); it != it_end; ++it ) + PYW_GIL_CHECK_LOCKED_SCOPE(); + bool ok = unregister_custom_data_format(dfid); + if ( ok ) { - if ( it->dfid == dfid && it->dtid == dtid ) - { - if ( loc != NULL ) - *loc = it; - return it->df; - } + // see comment in py_custom_data_type_t::do_unregister() + Py_XDECREF(py_self); + dfid = -1; } - return NULL; - } - void erase(POS &pos) - { - entries.erase(pos); + return ok; } }; -static py_custom_data_format_list_t py_df_list; -//------------------------------------------------------------------------ -static PyObject *py_data_type_to_py_dict(const data_type_t *dt) +//------------------------------------------------------------------------- +py_custom_data_format_t *py_custom_data_format_cast(data_format_t *inst) { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - return Py_BuildValue("{s:" PY_FMT64 ",s:i,s:i,s:s,s:s,s:s,s:s}", - S_VALUE_SIZE, pyul_t(dt->value_size), - S_PROPS, dt->props, - S_CBSIZE, dt->cbsize, - S_NAME, dt->name == NULL ? "" : dt->name, - S_MENU_NAME, dt->menu_name == NULL ? "" : dt->menu_name, - S_HOTKEY, dt->hotkey == NULL ? "" : dt->hotkey, - S_ASM_KEYWORD, dt->asm_keyword == NULL ? "" : dt->asm_keyword); + if ( py_custom_data_formats.has((py_custom_data_format_t *) inst) ) + return (py_custom_data_format_t *) inst; + else + return 0; } -//------------------------------------------------------------------------ -static PyObject *py_data_format_to_py_dict(const data_format_t *df) +//------------------------------------------------------------------------- +static int py_custom_data_format_t_get_id(data_format_t *_df) { - PYW_GIL_CHECK_LOCKED_SCOPE(); + py_custom_data_format_t *df = py_custom_data_format_cast(_df); + return df != NULL ? df->get_dfid() : -1; +} - return Py_BuildValue("{s:i,s:i,s:i,s:" PY_FMT64 ",s:s,s:s,s:s}", - S_PROPS, df->props, - S_CBSIZE, df->cbsize, - S_TEXT_WIDTH, df->text_width, - S_VALUE_SIZE, pyul_t(df->value_size), - S_NAME, df->name == NULL ? "" : df->name, - S_MENU_NAME, df->menu_name == NULL ? "" : df->menu_name, - S_HOTKEY, df->hotkey == NULL ? "" : df->hotkey); +//------------------------------------------------------------------------- +static void clear_custom_data_types_and_formats() +{ + PYW_GIL_GET; + for ( size_t n = py_custom_data_types.size(); n > 0; --n ) + py_custom_data_types[n-1]->do_unregister(); + for ( size_t n = py_custom_data_formats.size(); n > 0; --n ) + py_custom_data_formats[n-1]->do_unregister(); } // @@ -511,19 +437,18 @@ def register_custom_data_type(dt): pass # */ -// Given a py.data_format_t object, this function will register a datatype +// Given a py_data_type_t object, this function will register a datatype static int py_register_custom_data_type(PyObject *py_dt) { - py_custom_data_type_t *inst = new py_custom_data_type_t(); - int r = inst->register_dt(py_dt); - if ( r < 0 ) - { - delete inst; - return r; - } - // Insert the instance to the map - py_dt_map[r] = inst; - return r; + ref_t py_attr = PyW_TryGetAttrString(py_dt, "this"); + if ( py_attr == NULL ) + return -1; + + py_custom_data_type_t *inst = NULL; + int cvt = SWIG_ConvertPtr(py_attr.o, (void **) &inst, SWIGTYPE_p_data_type_t, 0); + if ( !SWIG_IsOK(cvt) || py_custom_data_type_cast(inst) == NULL ) + return -1; + return inst->do_register(); } //------------------------------------------------------------------------ @@ -540,38 +465,25 @@ def unregister_custom_data_type(dtid): */ static bool py_unregister_custom_data_type(int dtid) { - py_custom_data_type_map_t::iterator it = py_dt_map.find(dtid); - - // Maybe the user is trying to unregister a C api dt? - if ( it == py_dt_map.end() ) - return unregister_custom_data_type(dtid); - - py_custom_data_type_t *inst = it->second; - bool ok = inst->unregister_dt(); - - // Perhaps it was automatically unregistered because the idb was close? - if ( !ok ) - { - // Is this type still registered with IDA? - // If not found then mark the context for deletion - ok = find_custom_data_type(inst->get_name()) < 0; - } + const data_type_t *_dt = get_custom_data_type(dtid); + if ( _dt == NULL ) + return false; + py_custom_data_type_t *dt = py_custom_data_type_cast((data_type_t *) _dt); + bool ok = dt != NULL; if ( ok ) - { - py_dt_map.erase(it); - delete inst; - } + ok = dt->do_unregister(); + else + ok = unregister_custom_data_type(dtid); // C API dt return ok; } //------------------------------------------------------------------------ /* # -def register_custom_data_format(dtid, df): +def register_custom_data_format(df): """ Registers a custom data format with a given data type. - @param dtid: data type id @param df: an instance of data_format_t @return: < 0 if failed to register @@ -580,102 +492,47 @@ def register_custom_data_format(dtid, df): pass # */ -static int py_register_custom_data_format(int dtid, PyObject *py_df) +static int py_register_custom_data_format(PyObject *py_df) { - py_custom_data_format_t *inst = new py_custom_data_format_t(); - int r = inst->register_df(dtid, py_df); - if ( r < 0 ) - { - delete inst; - return r; - } - // Insert the instance - py_df_list.add(dtid, r, inst); - return r; + ref_t py_attr = PyW_TryGetAttrString(py_df, "this"); + if ( py_attr == NULL ) + return -1; + + py_custom_data_format_t *inst = NULL; + int cvt = SWIG_ConvertPtr(py_attr.o, (void **) &inst, SWIGTYPE_p_data_format_t, 0); + if ( !SWIG_IsOK(cvt) || py_custom_data_format_cast(inst) == NULL ) + return -1; + + return inst->do_register(); } //------------------------------------------------------------------------ /* # -def unregister_custom_data_format(dtid, dfid): +def unregister_custom_data_format(dfid): """ Unregisters a custom data format - @param dtid: data type id @param dfid: data format id @return: Boolean """ pass # */ -static bool py_unregister_custom_data_format(int dtid, int dfid) +static bool py_unregister_custom_data_format(int dfid) { - py_custom_data_format_list_t::POS pos; - py_custom_data_format_t *inst = py_df_list.find(dtid, dfid, &pos); - // Maybe the user is trying to unregister a C api data format? - if ( inst == NULL ) - return unregister_custom_data_format(dtid, dfid); - - bool ok = inst->unregister_df(dtid); - - // Perhaps it was automatically unregistered because the type was unregistered? - if ( !ok ) - { - // Is this format still registered with IDA? - // If not, mark the context for deletion - ok = find_custom_data_format(inst->get_name()) < 0; - } + const data_format_t *_df = get_custom_data_format(dfid); + if ( _df == NULL ) + return false; + py_custom_data_format_t *df = py_custom_data_format_cast((data_format_t *) _df); + bool ok = df != NULL; if ( ok ) - { - py_df_list.erase(pos); - delete inst; - } + ok = df->do_unregister(); + else + ok = unregister_custom_data_format(dfid); // C API df return ok; } -//------------------------------------------------------------------------ -/* -# -def get_custom_data_format(dtid, dfid): - """ - Returns a dictionary populated with the data format values or None on failure. - @param dtid: data type id - @param dfid: data format id - """ - pass -# -*/ -// Get definition of a registered custom data format and returns a dictionary -static PyObject *py_get_custom_data_format(int dtid, int fid) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - const data_format_t *df = get_custom_data_format(dtid, fid); - if ( df == NULL ) - Py_RETURN_NONE; - return py_data_format_to_py_dict(df); -} - -//------------------------------------------------------------------------ -/* -# -def get_custom_data_type(dtid): - """ - Returns a dictionary populated with the data type values or None on failure. - @param dtid: data type id - """ - pass -# -*/ -// Get definition of a registered custom data format and returns a dictionary -static PyObject *py_get_custom_data_type(int dtid) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - const data_type_t *dt = get_custom_data_type(dtid); - if ( dt == NULL ) - Py_RETURN_NONE; - return py_data_type_to_py_dict(dt); -} - // #endif // __PY_IDA_BYTES_CUSTDATA__ diff --git a/pywraps/py_bytes_custdata.py b/pywraps/py_bytes_custdata.py index 6595424..d142205 100644 --- a/pywraps/py_bytes_custdata.py +++ b/pywraps/py_bytes_custdata.py @@ -1,143 +1,6 @@ # ----------------------------------------------------------------------- # DTP_NODUP = 0x0001 -class data_type_t(object): - """ - Custom data type definition. All data types should inherit from this class. - """ - - def __init__(self, name, value_size = 0, menu_name = None, hotkey = None, asm_keyword = None, props = 0): - """Please refer to bytes.hpp / data_type_t in the SDK""" - self.name = name - self.props = props - self.menu_name = menu_name - self.hotkey = hotkey - self.asm_keyword = asm_keyword - self.value_size = value_size - - self.id = -1 # Will be initialized after registration - """Contains the data type id after the data type is registered""" - - def register(self): - """Registers the data type and returns the type id or < 0 on failure""" - return _ida_bytes.register_custom_data_type(self) - - def unregister(self): - """Unregisters the data type and returns True on success""" - # Not registered? - if self.id < 0: - return True - - # Try to unregister - r = _ida_bytes.unregister_custom_data_type(self.id) - - # Clear the ID - if r: - self.id = -1 - return r -# -# def may_create_at(self, ea, nbytes): -# """ -# (optional) If this callback is not defined then this means always may create data type at the given ea. -# @param ea: address of the future item -# @param nbytes: size of the future item -# @return: Boolean -# """ -# -# return False -# -# def calc_item_size(self, ea, maxsize): -# """ -# (optional) If this callback is defined it means variable size datatype -# This function is used to determine size of the (possible) item at 'ea' -# @param ea: address of the item -# @param maxsize: maximal size of the item -# @return: integer -# Returns: 0-no such item can be created/displayed -# this callback is required only for varsize datatypes -# """ -# return 0 -# -# ----------------------------------------------------------------------- -# Uncomment the corresponding callbacks in the inherited class -class data_format_t(object): - """Information about a data format""" - def __init__(self, name, value_size = 0, menu_name = None, props = 0, hotkey = None, text_width = 0): - """Custom data format definition. - @param name: Format name, must be unique - @param menu_name: Visible format name to use in menus - @param props: properties (currently 0) - @param hotkey: Hotkey for the corresponding menu item - @param value_size: size of the value in bytes. 0 means any size is ok - @text_width: Usual width of the text representation - """ - self.name = name - self.menu_name = menu_name - self.props = props - self.hotkey = hotkey - self.value_size = value_size - self.text_width = text_width - - self.id = -1 # Will be initialized after registration - """contains the format id after the format gets registered""" - - def register(self, dtid): - """Registers the data format with the given data type id and returns the type id or < 0 on failure""" - return _ida_bytes.register_custom_data_format(dtid, self) - - def unregister(self, dtid): - """Unregisters the data format with the given data type id""" - - # Not registered? - if self.id < 0: - return True - - # Unregister - r = _ida_bytes.unregister_custom_data_format(dtid, self.id) - - # Clear the ID - if r: - self.id = -1 - return r -# -# def printf(self, value, current_ea, operand_num, dtid): -# """ -# Convert a value buffer to colored string. -# -# @param value: The value to be printed -# @param current_ea: The ea of the value -# @param operand_num: The affected operand -# @param dtid: custom data type id (0-standard built-in data type) -# @return: a colored string representing the passed 'value' or None on failure -# """ -# return None -# -# def scan(self, input, current_ea, operand_num): -# """ -# Convert from uncolored string 'input' to byte value -# -# @param input: input string -# @param current_ea: current address (BADADDR if unknown) -# @param operand_num: current operand number (-1 if unknown) -# -# @return: tuple (Boolean, string) -# - (False, ErrorMessage) if conversion fails -# - (True, Value buffer) if conversion succeeds -# """ -# return (False, "Not implemented") -# -# def analyze(self, current_ea, operand_num): -# """ -# (optional) Analyze custom data format occurrence. -# It can be used to create xrefs from the current item. -# -# @param current_ea: current address (BADADDR if unknown) -# @param operand_num: current operand number -# @return: None -# """ -# -# pass -# # ----------------------------------------------------------------------- def __walk_types_and_formats(formats, type_action, format_action, installing): broken = False @@ -182,17 +45,27 @@ def register_data_types_and_formats(formats): ] The first two tuples describe data types and their associated formats. The last two tuples describe two data formats to be used with built-in data types. + The data format may be attached to several data types. The id of the + data format is stored in the first data_format_t object. For example: + assert many_formats[1][1] != -1 + assert many_formats[2][0] != -1 + assert many_formats[3][0] == -1 """ def __reg_format(df, dtid): - df.register(dtid) + dfid = register_custom_data_format(df); + if dfid == -1: + dfid = find_custom_data_format(df.name); + if dfid == -1: + return False + attach_custom_data_format(dtid, dfid) if dtid == 0: - print "Registered format '%s' with built-in types, ID=%d" % (df.name, df.id) + print "Registered format '%s' with built-in types, ID=%d" % (df.name, dfid) else: - print " Registered format '%s', ID=%d (dtid=%d)" % (df.name, df.id, dtid) - return df.id != -1 + print " Registered format '%s', ID=%d (dtid=%d)" % (df.name, dfid, dtid) + return True def __reg_type(dt): - dt.register() + register_custom_data_type(dt) print "Registered type '%s', ID=%d" % (dt.name, dt.id) return dt.id != -1 ok = __walk_types_and_formats(formats, __reg_type, __reg_format, True) @@ -205,15 +78,93 @@ def unregister_data_types_and_formats(formats): """ def __unreg_format(df, dtid): print "%snregistering format '%s'" % ("U" if dtid == 0 else " u", df.name) - df.unregister(dtid) + unregister_custom_data_format(df.id) return True def __unreg_type(dt): print "Unregistering type '%s', ID=%d" % (dt.name, dt.id) - dt.unregister() + unregister_custom_data_type(dt.id) return True ok = __walk_types_and_formats(formats, __unreg_type, __unreg_format, False) return 1 if ok else -1 +#-------------------------------------------------------------------------- +# +# +# +#class data_type_t(object): +# """ +# The following optional callback methods can be implemented +# in a data_type_t subclass +# """ +# +# def may_create_at(ea, nbytes): +# """May create data? +# No such callback means: always succeed (i.e., no restriction where +# such a data type can be created.) +# @param ea: candidate address for the data item +# @param nbytes: candidate size for the data item +# @return: True/False +# """ +# return True +# +# def calc_item_size(ea, maxsize): +# """This callback is used to determine size of the (possible) +# item at `ea`. +# No such callback means that datatype is of fixed size `value_size`. +# (thus, this callback is required only for varsize datatypes.) +# @param ea: address of the item +# @param maxsize: maximum size of the item +# @return: 0 - no such item can be created/displayed +# """ +# return 0 +# +# +#class data_format_t(object): +# """ +# The following callback methods can be implemented +# in a data_format_t subclass +# """ +# +# def printf(value, current_ea, operand_num, dtid): +# """Convert `value` to colored string using custom format. +# @param value: value to print (of type 'str', sequence of bytes) +# @param current_ea: current address (BADADDR if unknown) +# @param operand_num: current operand number +# @param dtid: custom data type id +# @return: string representing data +# """ +# return None +# +# def scan(input, current_ea, operand_num): +# """Convert uncolored string (user input) to the value. +# This callback is called from the debugger when an user enters a +# new value for a register with a custom data representation (e.g., +# an MMX register.) +# @param input: input string +# @param current_ea: current address (BADADDR if unknown) +# @param operand_num: current operand number (-1 if unknown) +# @return: tuple(bool, string) +# (True, output value) or +# (False, error message) +# """ +# return (False, "Not implemented") +# +# def analyze(current_ea, operand_num): +# """Analyze custom data format occurrence. +# This callback is called in 2 cases: +# - after emulating an instruction (after a call of +# 'ev_emu_insn') if its operand is marked as "custom data +# representation" +# - when emulating data (this is done using a call of +# 'ev_out_data' with analyze_only == true). This is the right +# place to create cross references from the current item. +# @param current_ea: current address (BADADDR if unknown) +# @param operand_num: current operand number +# """ +# pass +# +# +# # # ----------------------------------------------------------------------- diff --git a/pywraps/py_dbg.hpp b/pywraps/py_dbg.hpp index 7aaa64b..bd58f13 100644 --- a/pywraps/py_dbg.hpp +++ b/pywraps/py_dbg.hpp @@ -12,16 +12,16 @@ def get_manual_regions(): """ Returns the manual memory regions - @return: list(startEA, endEA, name, sclass, sbase, bitness, perm) + @return: list(start_ea, end_ea, name, sclass, sbase, bitness, perm) """ pass # */ static PyObject *py_get_manual_regions() { - meminfo_vec_t areas; - get_manual_regions(&areas); - return meminfo_vec_t_to_py(areas); + meminfo_vec_t ranges; + get_manual_regions(&ranges); + return meminfo_vec_t_to_py(ranges); } //------------------------------------------------------------------------- @@ -61,20 +61,20 @@ static PyObject *refresh_debugger_memory() dbg->stopped_at_debug_event(true); // Invalidate the cache - isEnabled(0); + is_mapped(0); PYW_GIL_CHECK_LOCKED_SCOPE(); Py_RETURN_NONE; } -int idaapi DBG_Callback(void *ud, int notification_code, va_list va); +ssize_t idaapi DBG_Callback(void *ud, int notification_code, va_list va); class DBG_Hooks { public: virtual ~DBG_Hooks() { unhook(); } - bool hook() { return hook_to_notification_point(HT_DBG, DBG_Callback, this); } - bool unhook() { return unhook_from_notification_point(HT_DBG, DBG_Callback, this); } + bool hook() { return idapython_hook_to_notification_point(HT_DBG, DBG_Callback, this); } + bool unhook() { return idapython_unhook_from_notification_point(HT_DBG, DBG_Callback, this); } static int store_int(int rc, const debug_event_t *, int *warn) { @@ -91,7 +91,7 @@ public: // hookgenDBG:methods }; -int idaapi DBG_Callback(void *ud, int notification_code, va_list va) +ssize_t idaapi DBG_Callback(void *ud, int notification_code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; @@ -168,7 +168,7 @@ static ea_t py_internal_get_sreg_base(thid_t tid, int sreg_value) { PYW_GIL_CHECK_LOCKED_SCOPE(); ea_t answer; - return internal_get_sreg_base(tid, sreg_value, &answer) < 1 + return internal_get_sreg_base(&answer, tid, sreg_value) < 1 ? BADADDR : answer; } diff --git a/pywraps/py_dbg.py b/pywraps/py_dbg.py index 4cacdaf..87b22ef 100644 --- a/pywraps/py_dbg.py +++ b/pywraps/py_dbg.py @@ -1,8 +1,48 @@ - # +import ida_idd + +def get_tev_reg_val(tev, reg): + rv = ida_idd.regval_t() + if get_insn_tev_reg_val(tev, reg, rv): + if rv.rvtype == ida_idd.RVT_INT: + return rv.ival + +def get_tev_reg_mem_qty(tev): + ti = tev_info_t() + if get_tev_info(tev, ti): + mis = memreg_infos_t() + if get_insn_tev_reg_mem(tev, mis): + return mis.size() + 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 + +def get_tev_reg_mem_ea(tev, idx): + ti = tev_info_t() + if get_tev_info(tev, ti): + mis = memreg_infos_t() + if get_insn_tev_reg_mem(tev, mis): + if idx >= 0 and idx < mis.size(): + return mis[idx].ea # + +# +import ida_idd +@bc695redef +def get_process_info(n, pi): + pis = ida_idd.procinfo_vec_t() + cnt = get_processes(pis) + if n >= cnt: + return ida_idd.NO_PROCESS + pi.name = pis[n].name + pi.pid = pis[n].pid + return pi.pid + +@bc695redef +def get_process_qty(): + pis = ida_idd.procinfo_vec_t() + return get_processes(pis) +# diff --git a/pywraps/py_diskio.hpp b/pywraps/py_diskio.hpp index 8c7b937..4db535f 100644 --- a/pywraps/py_diskio.hpp +++ b/pywraps/py_diskio.hpp @@ -17,6 +17,16 @@ int idaapi py_enumerate_files_cb(const char *file, void *ud) NULL)); return (py_ret == NULL || !PyNumber_Check(py_ret.o)) ? 1 /* stop enum on failure */ : PyInt_AsLong(py_ret.o); } + +//------------------------------------------------------------------------- +struct bytearray_linput_data_t +{ + linput_t *li; + qstring *bytes; +}; +DECLARE_TYPE_AS_MOVABLE(bytearray_linput_data_t); +typedef qvector bytearray_linput_data_vec_t; +static bytearray_linput_data_vec_t bytearray_linput_data_vec; // // @@ -59,6 +69,42 @@ PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback } while ( false ); Py_RETURN_NONE; } + +//------------------------------------------------------------------------- +linput_t *py_create_bytearray_linput(const qstring &s) +{ + qstring *bytes = new qstring(s); + linput_t *li = create_bytearray_linput((const uchar *) bytes->c_str(), bytes->length()); + if ( li != NULL ) + { + bytearray_linput_data_t &ld = bytearray_linput_data_vec.push_back(); + ld.bytes = bytes; + ld.li = li; + } + else + { + delete bytes; + } + return li; +} + +//------------------------------------------------------------------------- +void py_close_linput(linput_t *li) +{ + bytearray_linput_data_vec_t::iterator it = bytearray_linput_data_vec.begin(); + bytearray_linput_data_vec_t::iterator end = bytearray_linput_data_vec.end(); + for ( ; it != end; ++it ) + { + if ( it->li == li ) + { + delete it->bytes; + bytearray_linput_data_vec.erase(it); + break; + } + } + close_linput(li); +} + // #endif diff --git a/pywraps/py_diskio.py b/pywraps/py_diskio.py index 9434cb7..44c7034 100644 --- a/pywraps/py_diskio.py +++ b/pywraps/py_diskio.py @@ -1,5 +1,4 @@ -# -def enumerate_system_files(subdir, fname, callback): - """Similar to enumerate_files() however it searches inside IDA directory or its subdirectories""" - return enumerate_files(idadir(subdir), fname, callback) -# +# +create_generic_linput64=create_generic_linput +generic_linput64_t=generic_linput_t +# diff --git a/pywraps/py_enum.py b/pywraps/py_enum.py new file mode 100644 index 0000000..11661b3 --- /dev/null +++ b/pywraps/py_enum.py @@ -0,0 +1,37 @@ +# +CONST_ERROR_ENUM=ENUM_MEMBER_ERROR_NAME +CONST_ERROR_ILLV=ENUM_MEMBER_ERROR_VALUE +CONST_ERROR_MASK=ENUM_MEMBER_ERROR_ENUM +CONST_ERROR_NAME=ENUM_MEMBER_ERROR_MASK +CONST_ERROR_VALUE=ENUM_MEMBER_ERROR_ILLV +add_const=add_enum_member +del_const=del_enum_member +get_const=get_enum_member +get_const_bmask=get_enum_member_bmask +get_const_by_name=get_enum_member_by_name +get_const_cmt=get_enum_member_cmt +get_const_enum=get_enum_member_enum +get_const_name=get_enum_member_name +get_const_serial=get_enum_member_serial +get_const_value=get_enum_member_value +get_first_const=get_first_enum_member +get_first_serial_const=get_first_serial_enum_member +get_last_const=get_last_enum_member +get_last_serial_const=get_last_serial_enum_member +get_next_const=get_next_enum_member +get_next_serial_const=get_next_serial_enum_member +get_prev_const=get_prev_enum_member +get_prev_serial_const=get_prev_serial_enum_member +set_const_cmt=set_enum_member_cmt +set_const_name=set_enum_member_name +def get_next_serial_enum_member(*args): + serial, cid = args[0], args[1] + if serial > 0xFF: + serial, cid = cid, serial + return _ida_enum.get_next_serial_enum_member(serial, cid) +def get_prev_serial_enum_member(*args): + serial, cid = args[0], args[1] + if serial > 0xFF: + serial, cid = cid, serial + return _ida_enum.get_prev_serial_enum_member(serial, cid) +# diff --git a/pywraps/py_expr.hpp b/pywraps/py_expr.hpp index e6bdcaa..c313ab6 100644 --- a/pywraps/py_expr.hpp +++ b/pywraps/py_expr.hpp @@ -4,50 +4,51 @@ // struct py_idcfunc_ctx_t { - PyObject *py_func; + ref_t py_func; qstring name; int nargs; - py_idcfunc_ctx_t(PyObject *py_func, const char *name, int nargs): py_func(py_func), name(name), nargs(nargs) + py_idcfunc_ctx_t(PyObject *_py_func, const char *name, int nargs) + : py_func(borref_t(_py_func)), + name(name), + nargs(nargs) { PYW_GIL_CHECK_LOCKED_SCOPE(); - Py_INCREF(py_func); } ~py_idcfunc_ctx_t() { PYW_GIL_CHECK_LOCKED_SCOPE(); - Py_DECREF(py_func); } }; //--------------------------------------------------------------------------- static error_t py_call_idc_func( - void *_ctx, - idc_value_t *argv, - idc_value_t *r) + void *_ctx, + idc_value_t *argv, + idc_value_t *r) { + PYW_GIL_GET; + // Convert IDC arguments to Python list py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)_ctx; - int cvt; - char errbuf[MAXSTR]; - PYW_GIL_CHECK_LOCKED_SCOPE(); ref_vec_t pargs; - if ( !pyw_convert_idc_args(argv, ctx->nargs, pargs, true, errbuf, sizeof(errbuf)) ) + qstring errbuf; + if ( !pyw_convert_idc_args(argv, ctx->nargs, pargs, PYWCVTF_AS_TUPLE, &errbuf) ) { // Error during conversion? Create an IDC exception - return PyW_CreateIdcException(r, errbuf); + return PyW_CreateIdcException(r, errbuf.c_str()); } // Call the Python function - newref_t py_result(PyObject_CallObject( - ctx->py_func, - pargs.empty() ? NULL : pargs[0].o)); + newref_t py_result = PyObject_CallObject( + ctx->py_func.o, + pargs.empty() ? NULL : pargs[0].o); + int cvt; error_t err; - qstring qerrbuf; - if ( PyW_GetError(&qerrbuf) ) + if ( PyW_GetError(&errbuf) ) { - err = PyW_CreateIdcException(r, qerrbuf.c_str()); + err = PyW_CreateIdcException(r, errbuf.c_str()); } else { @@ -78,9 +79,9 @@ static size_t py_get_call_idc_func() // - capture the python callable // - return a C context as a numeric value static size_t pyw_register_idc_func( - const char *name, - const char *args, - PyObject *py_fp) + const char *name, + const char *args, + PyObject *py_fp) { return (size_t)new py_idcfunc_ctx_t(py_fp, name, strlen(args)); } @@ -92,7 +93,7 @@ static bool pyw_unregister_idc_func(size_t ctxptr) { // Unregister the function py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)ctxptr; - bool ok = set_idc_func_ex(ctx->name.c_str(), NULL, NULL, 0); + bool ok = del_idc_func(ctx->name.c_str()); // Delete the context delete ctx; @@ -100,53 +101,69 @@ static bool pyw_unregister_idc_func(size_t ctxptr) return ok; } -//--------------------------------------------------------------------------- -static bool py_set_idc_func_ex( - const char *name, - size_t fp_ptr, - const char *args, - int flags) +//------------------------------------------------------------------------- +typedef qvector idc_values_t; + +//------------------------------------------------------------------------- +static bool pyw_convert_defvals(idc_values_t *out, PyObject *py_seq) { - return set_idc_func_ex(name, (idc_func_t *)fp_ptr, args, flags); + if ( !PySequence_Check(py_seq) ) + return false; + for ( Py_ssize_t i = 0, n = PySequence_Size(py_seq); i < n; ++i ) + { + newref_t py_var(PySequence_GetItem(py_seq, i)); + idc_value_t &idc_var = out->push_back(); + if ( pyvar_to_idcvar(py_var, &idc_var, NULL) != CIP_OK ) + return false; + } + return true; } //--------------------------------------------------------------------------- -// Compile* functions return false when error so the return +static bool py_add_idc_func( + const char *name, + size_t fp_ptr, + const char *args, + const idc_values_t &defvals, + int flags) +{ + ext_idcfunc_t desc = { name, (idc_func_t *)fp_ptr, args, defvals.begin(), defvals.size(), flags }; + return add_idc_func(desc); +} + +//--------------------------------------------------------------------------- +// compile_idc_* functions return false when error so the return // value must be negated for the error string to be returned -bool CompileEx_wrap( - const char *file, - bool del_macros, - char *errbuf, size_t errbufsize) +bool py_compile_idc_file( + const char *file, + qstring *errbuf) { - return !CompileEx(file, del_macros, errbuf, errbufsize); + return !compile_idc_file(file, errbuf); } -bool Compile_wrap(const char *file, char *errbuf, size_t errbufsize) +bool py_compile_idc_text( + const char *line, + qstring *errbuf) { - return !Compile(file, errbuf, errbufsize); + return !compile_idc_text(line, errbuf); } -bool calcexpr_wrap( - ea_t where, - const char *line, - idc_value_t *rv, - char *errbuf, size_t errbufsize) +bool py_eval_expr( + idc_value_t *rv, + ea_t where, + const char *line, + qstring *errbuf) { - return !calcexpr(where, line, rv, errbuf, errbufsize); + return !eval_expr(rv, where, line, errbuf); } -bool calc_idc_expr_wrap( - ea_t where, - const char *line, - idc_value_t *rv, - char *errbuf, size_t errbufsize) +bool py_eval_idc_expr( + idc_value_t *rv, + ea_t where, + const char *line, + qstring *errbuf) { - return !calc_idc_expr(where, line, rv, errbuf, errbufsize); -} - -bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize) -{ - return !CompileLineEx(line, errbuf, errbufsize); + return !eval_idc_expr(rv, where, line, errbuf); } // diff --git a/pywraps/py_expr.py b/pywraps/py_expr.py index c5838bb..f59f78e 100644 --- a/pywraps/py_expr.py +++ b/pywraps/py_expr.py @@ -5,20 +5,19 @@ try: import ctypes # Callback for IDC func callback (On Windows, we use stdcall) # typedef error_t idaapi idc_func_t(idc_value_t *argv,idc_value_t *r); - _IDCFUNC_CB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) + try: + _IDCFUNC_CB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) + except: + _IDCFUNC_CB_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) # 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)(_ida_expr.py_get_call_idc_func()) + call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p)(_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(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) - except: - _IDCFUNC_CB_T = None - + _IDCFUNC_CB_T = None # -------------------------------------------------------------------------- EXTFUN_BASE = 0x0001 @@ -37,7 +36,7 @@ class _IdcFunction(object): self.ctxptr = ctxptr # Take a reference to the ctypes callback # (note: this will create a circular reference) - self.cb = _IDCFUNC_CB_T(self) + self.cb = _IDCFUNC_CB_T(self) fp_ptr = property(lambda self: ctypes.cast(self.cb, ctypes.c_void_p).value) @@ -50,48 +49,65 @@ class _IdcFunction(object): # retrieved by using the internal pyw_register_idc_func() __IDC_FUNC_CTXS = {} -# -------------------------------------------------------------------------- -def set_idc_func_ex(name, fp=None, args=(), flags=0): +def del_idc_func(name): """ - Extends the IDC language by exposing a new IDC function that is backed up by a Python function - This function also unregisters the IDC function if 'fp' was passed as None + Unregisters the specified IDC function - @param name: IDC function name to expose - @param fp: Python callable that will receive the arguments and return a tuple. - If this argument is None then the IDC function is unregistered - @param args: Arguments. A tuple of idaapi.VT_XXX constants - @param flags: IDC function flags. A combination of EXTFUN_XXX constants + @param name: IDC function name to unregister - @return: Boolean. + @return: Boolean """ global __IDC_FUNC_CTXS # Get the context f = __IDC_FUNC_CTXS.get(name, None) - # Unregistering? - if fp is None: - # Not registered? - if f is None: - return False + if f is None: + return False # Not registered - # Break circular reference - del f.cb + # Break circular reference + del f.cb - # Delete the name from the dictionary - del __IDC_FUNC_CTXS[name] + # Delete the name from the dictionary + del __IDC_FUNC_CTXS[name] - # Delete the context and unregister the function - return _ida_expr.pyw_unregister_idc_func(f.ctxptr) + # Delete the context and unregister the function + return _ida_expr.pyw_unregister_idc_func(f.ctxptr) + +# -------------------------------------------------------------------------- +def add_idc_func(name, fp, args, defvals=None, flags=0): + """ + Extends the IDC language by exposing a new IDC function that is backed up by a Python function + + @param name: IDC function name to expose + @param fp: Python callable that will receive the arguments and return a tuple. + @param args: Arguments. A tuple of idaapi.VT_XXX constants + @param flags: IDC function flags. A combination of EXTFUN_XXX constants + + @return: Boolean + """ + global __IDC_FUNC_CTXS + + # Get the context + f = __IDC_FUNC_CTXS.get(name, None) # Registering a function that is already registered? if f is not None: # Unregister it first - set_idc_func_ex(name, None) + del_idc_func(name) # Convert the tupple argument info to a string args = "".join([chr(x) for x in args]) + # make sure we don't have an obvious discrepancy between + # the number of args, and the provided default values + if len(defvals) > len(args): + return False + + vdefvals = idc_values_t() + if not _ida_expr.pyw_convert_defvals(vdefvals, defvals): + return False + # Create a context ctxptr = _ida_expr.pyw_register_idc_func(name, args, fp) if ctxptr == 0: @@ -104,10 +120,55 @@ def set_idc_func_ex(name, fp=None, args=(), flags=0): __IDC_FUNC_CTXS[name] = f # Register IDC function with a callback - return _ida_expr.py_set_idc_func_ex( + return _ida_expr.py_add_idc_func( name, f.fp_ptr, args, + vdefvals, flags) # + +# +Compile=compile_idc_file +CompileEx=compile_idc_file +CompileLine=compile_idc_text +VT_STR2=VT_STR +VarCopy=copy_idcv +VarDelAttr=del_idcv_attr +VarDeref=deref_idcv +VarFirstAttr=first_idcv_attr +@bc695redef +def VarGetAttr(obj, attr, res, may_use_getattr=False): + return get_idcv_attr(res, obj, attr, may_use_getattr) +VarGetClassName=get_idcv_class_name +VarGetSlice=get_idcv_slice +VarInt64=idcv_int64 +VarLastAttr=last_idcv_attr +VarMove=move_idcv +VarNextAttr=next_idcv_attr +VarObject=idcv_object +VarPrevAttr=prev_idcv_attr +VarPrint=print_idcv +VarRef=create_idcv_ref +VarSetAttr=set_idcv_attr +VarSetSlice=set_idcv_slice +VarString2=idcv_string +VarSwap=swap_idcvs +@bc695redef +def calc_idc_expr(where, expr, res): + return eval_idc_expr(res, where, expr) +@bc695redef +def calcexpr(where, expr, res): + return eval_expr(res, where, expr) +@bc695redef +def dosysfile(complain_if_no_file, fname): + return exec_system_script(fname, complain_if_no_file) +@bc695redef +def execute(line): + return eval_idc_snippet(None, line) +py_set_idc_func_ex=py_add_idc_func +@bc695redef +def set_idc_func_ex(name, fp=None, args=(), flags=0): + return add_idc_func(name, fp, args, (), flags) +# diff --git a/pywraps/py_fixup.py b/pywraps/py_fixup.py new file mode 100644 index 0000000..b862b0c --- /dev/null +++ b/pywraps/py_fixup.py @@ -0,0 +1,6 @@ + +# +FIXUP_CREATED=FIXUPF_CREATED +FIXUP_EXTDEF=FIXUPF_EXTDEF +FIXUP_REL=FIXUPF_REL +# diff --git a/pywraps/py_fpro.hpp b/pywraps/py_fpro.hpp index 7eed9f1..1f26367 100644 --- a/pywraps/py_fpro.hpp +++ b/pywraps/py_fpro.hpp @@ -207,7 +207,7 @@ public: } //-------------------------------------------------------------------------- - int seek(int32 offset, int whence = SEEK_SET) + int seek(int64 offset, int whence = SEEK_SET) { int rc; Py_BEGIN_ALLOW_THREADS; @@ -217,9 +217,9 @@ public: } //-------------------------------------------------------------------------- - int32 tell() + int64 tell() { - int32 rc; + int64 rc; Py_BEGIN_ALLOW_THREADS; rc = qftell(fp); Py_END_ALLOW_THREADS; @@ -348,10 +348,10 @@ public: } //-------------------------------------------------------------------------- - int32 size() + int64 size() { PYW_GIL_CHECK_LOCKED_SCOPE(); - int32 r; + qoff64_t r; Py_BEGIN_ALLOW_THREADS; int pos = qfseek(fp, 0, SEEK_END); r = qftell(fp); diff --git a/pywraps/py_frame.hpp b/pywraps/py_frame.hpp index ba3ad67..acc3bab 100644 --- a/pywraps/py_frame.hpp +++ b/pywraps/py_frame.hpp @@ -1,27 +1,4 @@ // -//------------------------------------------------------------------------- -/* -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; -} //------------------------------------------------------------------------- /* @@ -39,21 +16,16 @@ def get_stkvar(op, v): pass # */ -PyObject *py_get_stkvar(PyObject *py_op, PyObject *py_v) +PyObject *py_get_stkvar(const insn_t &insn, const op_t &op, sval_t 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); + member_t *member = get_stkvar(&actval, insn, op, v); if ( member == NULL ) Py_RETURN_NONE; - return Py_BuildValue("(O" PY_SFMT64 ")", + return Py_BuildValue("(O" PY_BV_SVAL ")", SWIG_NewPointerObj(SWIG_as_voidptr(member), SWIGTYPE_p_member_t, 0), - pyl_t(actval)); + bvsval_t(actval)); } // diff --git a/pywraps/py_frame.py b/pywraps/py_frame.py new file mode 100644 index 0000000..5081506 --- /dev/null +++ b/pywraps/py_frame.py @@ -0,0 +1,21 @@ + +# +add_auto_stkpnt2=add_auto_stkpnt +# in fact, we cannot simulate add_stkvar[23] here, because we simply +# don't have the insn_t object -- and no way of retrieving it, either, +# since cmd is gone +def get_stkvar(*args): + if len(args) == 2: + import ida_ua + insn, op, v = ida_ua.cmd, args[0], args[1] + else: + insn, op, v = args + return _ida_frame.get_stkvar(insn, op, v) +def get_frame_part(*args): + import ida_funcs + if isinstance(args[0], ida_funcs.func_t): # 6.95: pfn, part, range + rnge, pfn, part = args[2], args[0], args[1] + else: # 7.00: range, pfn, part + rnge, pfn, part = args + return _ida_frame.get_frame_part(rnge, pfn, part) +# diff --git a/pywraps/py_funcs.hpp b/pywraps/py_funcs.hpp index 4075db0..7601645 100644 --- a/pywraps/py_funcs.hpp +++ b/pywraps/py_funcs.hpp @@ -42,13 +42,13 @@ def get_idasgn_desc(n): */ static PyObject *py_get_idasgn_desc(int n) { - char signame[MAXSTR]; - char optlibs[MAXSTR]; + qstring signame; + qstring optlibs; - if ( get_idasgn_desc(n, signame, sizeof(signame), optlibs, sizeof(optlibs)) < 0 ) + if ( get_idasgn_desc(&signame, &optlibs, n) < 0 ) Py_RETURN_NONE; else - return Py_BuildValue("(ss)", signame, optlibs); + return Py_BuildValue("(ss)", signame.c_str(), optlibs.c_str()); } //----------------------------------------------------------------------- @@ -67,42 +67,14 @@ def get_idasgn_desc_with_matches(n): */ static PyObject *py_get_idasgn_desc_with_matches(int n) { - char signame[MAXSTR]; - char optlibs[MAXSTR]; + qstring signame; + qstring optlibs; - int32 matches = get_idasgn_desc(n, signame, sizeof(signame), optlibs, sizeof(optlibs)); + int32 matches = get_idasgn_desc(&signame, &optlibs, n); if ( matches < 0 ) Py_RETURN_NONE; else - return Py_BuildValue("(ssi)", signame, optlibs, matches); -} - -//----------------------------------------------------------------------- -/* -# -def get_func_cmt(fn, repeatable): - """ - Retrieve function comment - @param fn: function instance - @param repeatable: retrieve repeatable or non-repeatable comments - @return: None on failure or the comment - """ - pass -# -*/ -static PyObject *py_get_func_cmt(func_t *fn, bool repeatable) -{ - char *s = get_func_cmt(fn, repeatable); - if ( s == NULL ) - { - Py_RETURN_NONE; - } - else - { - PyObject *py_s = PyString_FromString(s); - qfree(s); - return py_s; - } + return Py_BuildValue("(ssi)", signame.c_str(), optlibs.c_str(), matches); } // diff --git a/pywraps/py_funcs.py b/pywraps/py_funcs.py new file mode 100644 index 0000000..8dbc3d7 --- /dev/null +++ b/pywraps/py_funcs.py @@ -0,0 +1,25 @@ +# +# + +# +FUNC_STATIC=FUNC_STATICDEF +add_regarg2=add_regarg +clear_func_struct=lambda *args: True +@bc695redef +def del_func_cmt(pfn, rpt): + set_func_cmt(pfn, "", rpt) +func_parent_iterator_set2=func_parent_iterator_set +func_setend=set_func_end +func_setstart=set_func_start +func_tail_iterator_set2=func_tail_iterator_set +@bc695redef +def get_func_limits(pfn, limits): + import ida_range + rs = ida_range.rangeset_t() + if get_func_ranges(rs, pfn) == ida_idaapi.BADADDR: + return False + limits.start_ea = rs.begin().start_ea + limits.end_ea = rs.begin().end_ea + return True +get_func_name2=get_func_name +# diff --git a/pywraps/py_gdl.py b/pywraps/py_gdl.py index f503ef9..090c768 100644 --- a/pywraps/py_gdl.py +++ b/pywraps/py_gdl.py @@ -10,11 +10,11 @@ class BasicBlock(object): self.id = id """Basic block ID""" - self.startEA = bb.startEA - """startEA of basic block""" + self.start_ea = bb.start_ea + """start_ea of basic block""" - self.endEA = bb.endEA - """endEA of basic block""" + self.end_ea = bb.end_ea + """end_ea of basic block""" self.type = self._fc._q.calc_block_type(self.id) """Block type (check fc_block_type_t enum)""" @@ -37,6 +37,13 @@ class BasicBlock(object): for i in xrange(0, q.nsucc(self.id)): yield self._fc[q.succ(self.id, i)] + try: + if _BC695: + startEA = property(lambda self: self.start_ea, lambda self, ea: setattr(self, "start_ea", ea)) + endEA = property(lambda self: self.end_ea, lambda self, ea: setattr(self, "end_ea", ea)) + except: + pass # BC695 not defined at compile-time + # ----------------------------------------------------------------------- class FlowChart(object): """ diff --git a/pywraps/py_graph.hpp b/pywraps/py_graph.hpp index 43d3b9b..b2583af 100644 --- a/pywraps/py_graph.hpp +++ b/pywraps/py_graph.hpp @@ -18,10 +18,9 @@ private: GRCODE_HAVE_GOTFOCUS = 0x00080000, GRCODE_HAVE_LOSTFOCUS = 0x00100000, GRCODE_HAVE_CHANGED_CURRENT = 0x00200000, - GRCODE_HAVE_COMMAND = 0x00400000, - GRCODE_HAVE_CREATING_GROUP = 0x00800000, - GRCODE_HAVE_DELETING_GROUP = 0x01000000, - GRCODE_HAVE_GROUP_VISIBILITY = 0x02000000, + GRCODE_HAVE_CREATING_GROUP = 0x00400000, + GRCODE_HAVE_DELETING_GROUP = 0x00800000, + GRCODE_HAVE_GROUP_VISIBILITY = 0x01000000, }; struct nodetext_cache_t { @@ -48,84 +47,29 @@ private: } }; - class cmdid_map_t: public std::map - { - private: - Py_ssize_t uid; - public: - - cmdid_map_t() - { - // We start by one and keep zero for error id - uid = 1; - } - - void add(py_graph_t *pyg) - { - (*this)[uid] = pyg; - ++uid; - } - - const Py_ssize_t id() const - { - return uid; - } - - void clear(py_graph_t *pyg) - { - iterator e = end(); - for ( iterator it=begin(); it != end(); ) - { - if ( it->second == pyg ) - { - iterator temp = it++; - erase(temp); - } - else - ++it; - } - } - - py_graph_t *get(Py_ssize_t id) - { - iterator it = find(id); - return it == end() ? NULL : it->second; - } - }; - - static cmdid_map_t cmdid_pyg; - bool refresh_needed; nodetext_cache_map_t node_cache; // instance callback - int gr_callback(int code, va_list va); + ssize_t gr_callback(int code, va_list va); // static callback - static int idaapi s_callback(void *obj, int code, va_list va) - { - 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); - } - - static bool idaapi s_menucb(void *ud) - { - PYW_GIL_GET; - Py_ssize_t id = (Py_ssize_t)ud; - py_graph_t *_this = cmdid_pyg.get(id); - if ( _this != NULL ) - _this->on_command(id); - - return true; - } - - void on_command(Py_ssize_t id) - { - // Check return value to OnRefresh() call - PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id)); - PyW_ShowCbErr(S_ON_COMMAND); + static ssize_t idaapi s_callback(void *obj, int code, va_list va) +{ + // don't perform sanity check for 'grcode_destroyed', since if we called + // Close() on this object, it'll have been marked for later deletion in the + // UI, and thus when we end up here, the view has already been destroyed. + bool found = pycim_lookup_info.find_by_py_view(NULL, (py_graph_t *) obj); + QASSERT(30453, found || code == grcode_destroyed); + if ( found ) + { + PYW_GIL_GET; + return ((py_graph_t *)obj)->gr_callback(code, va); + } + else + { + return 0; + } } // Refresh user-defined graph node number and edges @@ -287,9 +231,9 @@ private: void show() { - TForm *form; - if ( pycim_lookup_info.find_by_py_view(&form, NULL, this) ) - open_tform(form, FORM_TAB|FORM_MENU|FORM_QWIDGET); + TWidget *view; + if ( pycim_lookup_info.find_by_py_view(&view, this) ) + display_widget(view, WOPN_TAB|WOPN_MENU); } void jump_to_node(int nid) @@ -325,10 +269,8 @@ private: if ( !collect_pyobject_callbacks(self) ) return -1; - // Create form - HWND hwnd = NULL; - TForm *form = create_tform(title, &hwnd); - if ( hwnd != NULL ) // Created new tform + TWidget *widget = find_widget(title); + if ( widget == NULL ) // create new widget { lookup_entry_t &e = pycim_lookup_info.new_entry(this); // get a unique graph id @@ -338,14 +280,14 @@ private: id.create(grnode); // pre-bind 'self', so that 'on_user_refresh()' can complete this->self = borref_t(self); - graph_viewer_t *pview = create_graph_viewer(form, id, s_callback, this, 0); + graph_viewer_t *pview = create_graph_viewer(title, id, s_callback, this, 0); this->self = ref_t(); - open_tform(form, FORM_TAB | FORM_MENU | FORM_QWIDGET); + display_widget(pview, WOPN_TAB | WOPN_MENU); + newref_t ret(PyObject_CallMethod(self, "hook", NULL)); if ( pview != NULL ) viewer_fit_window(pview); bind(self, pview); - install_custom_viewer_handlers(); - pycim_lookup_info.commit(e, form, view); + pycim_lookup_info.commit(e, view); } else { @@ -356,18 +298,6 @@ private: return 0; } - Py_ssize_t add_command(const char *title, const char *hotkey) - { - if ( !has_callback(GRCODE_HAVE_COMMAND) || view == NULL ) - return 0; - Py_ssize_t cmd_id = cmdid_pyg.id(); - bool ok = viewer_add_menu_item(view, title, s_menucb, (void *)cmd_id, hotkey, 0); - if ( !ok ) - return 0; - cmdid_pyg.add(this); - return cmd_id; - } - public: py_graph_t() { @@ -375,40 +305,27 @@ public: refresh_needed = true; } - virtual ~py_graph_t() - { - // Remove all associated commands from the list - cmdid_pyg.clear(this); - } - static void SelectNode(PyObject *self, int nid) { if ( nid < 0 ) return; py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !pycim_lookup_info.find_by_py_view(NULL, NULL, _this) ) + if ( _this == NULL || !pycim_lookup_info.find_by_py_view(NULL, _this) ) return; _this->jump_to_node(nid); } - static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey) + static py_graph_t *Close(PyObject *self) { + TWidget *view; py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !pycim_lookup_info.find_by_py_view(NULL, NULL, _this) ) - return 0; - - return _this->add_command(title, hotkey); - } - - static void Close(PyObject *self) - { - TForm *form; - py_graph_t *_this = view_extract_this(self); - if ( _this == NULL || !pycim_lookup_info.find_by_py_view(&form, NULL, _this) ) - return; - close_tform(form, FORM_CLOSE_LATER); + if ( _this == NULL || !pycim_lookup_info.find_by_py_view(&view, _this) ) + return NULL; + newref_t ret(PyObject_CallMethod(self, "unhook", NULL)); + close_widget(view, WCLS_CLOSE_LATER); + return _this; } static py_graph_t *Show(PyObject *self) @@ -426,10 +343,9 @@ public: // Form already created? try to get associated py_graph instance // so that we reuse it - graph_viewer_t *found_view; - TForm *form = find_tform(title.c_str()); - if ( form != NULL ) - pycim_lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_graph, form); + TWidget *existing = find_widget(title.c_str()); + if ( existing != NULL ) + pycim_lookup_info.find_by_view((py_customidamemo_t**) &py_graph, existing); if ( py_graph == NULL ) { @@ -466,7 +382,6 @@ void py_graph_t::collect_class_callbacks_ids(pycim_callbacks_ids_t *out) out->add(S_ON_HINT, GRCODE_HAVE_USER_HINT); out->add(S_ON_CLICK, GRCODE_HAVE_CLICKED); out->add(S_ON_DBL_CLICK, GRCODE_HAVE_DBL_CLICKED); - out->add(S_ON_COMMAND, GRCODE_HAVE_COMMAND); out->add(S_ON_SELECT, GRCODE_HAVE_CHANGED_CURRENT); out->add(S_ON_ACTIVATE, GRCODE_HAVE_GOTFOCUS); out->add(S_ON_DEACTIVATE, GRCODE_HAVE_LOSTFOCUS); @@ -613,7 +528,7 @@ int py_graph_t::on_user_hint(mutable_graph_t *, int mousenode, int /*mouseedge_s //------------------------------------------------------------------------- -int py_graph_t::gr_callback(int code, va_list va) +ssize_t py_graph_t::gr_callback(int code, va_list va) { int ret; switch ( code ) @@ -763,8 +678,6 @@ int py_graph_t::gr_callback(int code, va_list va) } //------------------------------------------------------------------------- -py_graph_t::cmdid_map_t py_graph_t::cmdid_pyg; - bool pyg_show(PyObject *self) { return py_graph_t::Show(self) != NULL; @@ -772,13 +685,9 @@ bool pyg_show(PyObject *self) void pyg_close(PyObject *self) { - py_graph_t::Close(self); -} - -PyObject *pyg_add_command(PyObject *self, const char *title, const char *hotkey) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return Py_BuildValue("n", py_graph_t::AddCommand(self, title, hotkey)); + py_graph_t *pyg = py_graph_t::Close(self); + if ( pyg != NULL ) + delete pyg; } void pyg_select_node(PyObject *self, int nid) @@ -791,7 +700,6 @@ void pyg_select_node(PyObject *self, int nid) // void pyg_close(PyObject *self); -PyObject *pyg_add_command(PyObject *self, const char *title, const char *hotkey); void pyg_select_node(PyObject *self, int nid); bool pyg_show(PyObject *self); // diff --git a/pywraps/py_graph.py b/pywraps/py_graph.py index d05d58b..add5856 100644 --- a/pywraps/py_graph.py +++ b/pywraps/py_graph.py @@ -1,6 +1,25 @@ # import ida_idaapi -class GraphViewer(ida_idaapi.CustomIDAMemo): +import ida_kernwin +try: + if _BC695: + from ida_kernwin import BC695_control_cmd +except: + pass # BC695 not defined at compile-time + +class GraphViewer(ida_kernwin.CustomIDAMemo): + class UI_Hooks_Trampoline(ida_kernwin.UI_Hooks): + def __init__(self, v): + ida_kernwin.UI_Hooks.__init__(self) + self.hook() + import weakref + self.v = weakref.ref(v) + + def populating_widget_popup(self, form, popup_handle): + my_form = self.v().GetWidget() + if form == my_form: + self.v().OnPopup(my_form, popup_handle) + """This class wraps the user graphing facility provided by the graph.hpp file""" def __init__(self, title, close_open = False): """ @@ -14,6 +33,8 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): self._nodes = [] self._edges = [] self._close_open = close_open + ida_kernwin.CustomIDAMemo.__init__(self) + self.ui_hooks_trampoline = self.UI_Hooks_Trampoline(self) def AddNode(self, obj): """Creates a node associated with the given object and returns the node id""" @@ -30,6 +51,8 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): self._nodes = [] self._edges = [] + def OnPopup(self, form, popup_handle): + pass def __iter__(self): return (self._nodes[index] for index in xrange(0, len(self._nodes))) @@ -61,23 +84,15 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): """ if self._close_open: import ida_kernwin - frm = ida_kernwin.find_tform(self._title) + frm = ida_kernwin.find_widget(self._title) if frm: - ida_kernwin.close_tform(frm, 0) + ida_kernwin.close_widget(frm, 0) return _ida_graph.pyg_show(self) def Select(self, node_id): """Selects a node on the graph""" _ida_graph.pyg_select_node(self, node_id) - def AddCommand(self, title, hotkey): - """ - Deprecated: Use - - register_action() - - attach_action_to_popup() - """ - return _ida_graph.pyg_add_command(self, title, hotkey) - def OnRefresh(self): """ Event called when the graph is refreshed or first created. @@ -90,6 +105,25 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): self.Clear() return True + + def AddCommand(self, title, hotkey): + return BC695_control_cmd.add_to_control( + self, + title, + ida_kernwin.CHOOSER_POPUP_MENU, # KLUDGE + -1, # menu index + -1, # icon + None, # emb + hotkey, + is_chooser=False) + + def OnPopup(self, widget, popup_handle): + BC695_control_cmd.populate_popup(self, widget, popup_handle) + + def OnCommand(self, cmd_id): + return 0 + + # # def OnGetText(self, node_id): # """ @@ -153,11 +187,13 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): # """ # print "dblclicked on", self[node_id] # return True -# -# def OnCommand(self, cmd_id): -# """ -# Deprecated -# """ -# pass # # + +# +clr_node_info2=clr_node_info +del_node_info2=del_node_info +get_node_info2=get_node_info +set_node_info2=set_node_info +GraphViewer.GetTForm = GraphViewer.GetWidget +# diff --git a/pywraps/py_hexrays.hpp b/pywraps/py_hexrays.hpp index 719c018..1e3d577 100644 --- a/pywraps/py_hexrays.hpp +++ b/pywraps/py_hexrays.hpp @@ -1,9 +1,38 @@ //------------------------------------------------------------------------- // #ifdef WITH_HEXRAYS -hexdsp_t *hexdsp = NULL; +static void *idaapi init_time_dummy_hexdsp(int code, ...) +{ + switch ( code ) + { + case hx_cexpr_t_cleanup: + case hx_cinsn_t_cleanup: + { +#ifdef _DEBUG + va_list va; + va_start(va, code); + citem_t *item = va_arg(va, citem_t*); + // catch leaks + if ( code == hx_cexpr_t_cleanup ) + QASSERT(30497, ((cexpr_t *)item)->op == cot_empty && ((cexpr_t *)item)->n == NULL); + else + QASSERT(30498, ((cinsn_t *)item)->op == cit_empty && ((cinsn_t *)item)->cblock == NULL); + va_end(va); +#endif + } + break; + default: + warning("Hex-Rays Decompiler got called from Python without being loaded"); + break; + } + return NULL; +} + +hexdsp_t *hexdsp = init_time_dummy_hexdsp; #endif // WITH_HEXRAYS +#define MODULE_NAME "Hex-Rays Decompiler" // Copied from vd/hexrays.cpp + //------------------------------------------------------------------------- qstring_printer_t *new_qstring_printer_t(const cfunc_t *f, bool tags) { @@ -18,7 +47,7 @@ void delete_qstring_printer_t(qstring_printer_t *qs) } //--------------------------------------------------------------------- -static int hexrays_python_call(ref_t fct, ref_t args) +static ref_t hexrays_python_call(ref_t fct, ref_t args) { PYW_GIL_GET; @@ -26,9 +55,17 @@ static int hexrays_python_call(ref_t fct, ref_t args) if ( PyErr_Occurred() ) { PyErr_Print(); - return 0; + return borref_t(Py_None); } + return resultobj; +} +//--------------------------------------------------------------------- +static int hexrays_python_intcall(ref_t fct, ref_t args) +{ + PYW_GIL_GET; + + ref_t resultobj = hexrays_python_call(fct, args); int result; if ( SWIG_IsOK(SWIG_AsVal_int(resultobj.o, &result)) ) return result; @@ -44,7 +81,7 @@ static bool idaapi __python_custom_viewer_popup_item_callback(void *ud) int ret; borref_t fct((PyObject *)ud); newref_t nil(NULL); - ret = hexrays_python_call(fct, nil); + ret = hexrays_python_intcall(fct, nil); return ret ? true : false; } @@ -66,7 +103,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_interr: @@ -75,7 +112,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ { int arg0 = va_argi(va, int); newref_t args(Py_BuildValue("(ii)", event, arg0)); - ret = hexrays_python_call(fct, args); + ret = hexrays_python_intcall(fct, args); } break; @@ -90,7 +127,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; @@ -102,7 +139,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; @@ -114,7 +151,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_switch_pseudocode: @@ -126,7 +163,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_refresh_pseudocode: @@ -137,7 +174,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_close_pseudocode: @@ -147,7 +184,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_keyboard: @@ -162,7 +199,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_right_click: @@ -172,7 +209,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_double_click: @@ -185,7 +222,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_curpos: @@ -196,7 +233,7 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_create_hint: @@ -213,7 +250,28 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = 0; + ref_t resultobj = hexrays_python_call(fct, args); + if ( PyTuple_Check(resultobj.o) && PyTuple_Size(resultobj.o) == 3 ) + { + borref_t i0 = PyTuple_GetItem(resultobj.o, 0); + borref_t i1 = PyTuple_GetItem(resultobj.o, 1); + borref_t i2 = PyTuple_GetItem(resultobj.o, 2); + if ( PyInt_Check(i0.o) && PyString_Check(i1.o) && PyInt_Check(i2.o) ) + { + qstring *result_hint = va_arg(va, qstring *); + char *buf; + Py_ssize_t bufsize; + if ( PyString_AsStringAndSize(i1.o, &buf, &bufsize) > -1 ) + { + ret = PyInt_AsLong(i0.o); + qstring tmp(buf, bufsize); + result_hint->swap(tmp); + int *implines = va_arg(va, int *); + *implines = PyInt_AsLong(i2.o); + } + } + } } break; case hxe_text_ready: @@ -226,23 +284,23 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ 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); + ret = hexrays_python_intcall(fct, args); } break; case hxe_populating_popup: ///< Populating popup menu. We can add menu items now. - ///< TForm *form + ///< TWidget *widget ///< TPopupMenu *popup_handle ///< vdui_t *vu { - TForm *form = va_arg(va, TForm *); + TWidget *widget = va_arg(va, TWidget *); 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_widget(SWIG_NewPointerObj(SWIG_as_voidptr(widget), SWIGTYPE_p_TWidget, 0)); + newref_t py_popup(SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_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); + newref_t py_args(Py_BuildValue("(iOOO)", event, py_widget.o, py_popup.o, py_vdui.o)); + ret = hexrays_python_intcall(fct, py_args); } break; default: @@ -255,40 +313,88 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_ } //------------------------------------------------------------------------- -// 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. -} - +// Clearable objects //------------------------------------------------------------------------- -void hexrays_register_python_cfuncptr_t_instance(cfuncptr_t *fp) +// A set of 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. +enum hx_clearable_type_t { - QASSERT(30457, !python_cfuncptrs.has(fp)); - python_cfuncptrs.push_back(fp); -} + hxclr_unknown = 0, + hxclr_cfuncptr, + hxclr_cinsn, + hxclr_cexpr, + hxclr_cblock, +}; +struct hx_clearable_t +{ + void *ptr; + hx_clearable_type_t type; +}; +DECLARE_TYPE_AS_MOVABLE(hx_clearable_t); -//------------------------------------------------------------------------- -void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp) +typedef qvector hx_clearables_t; +static hx_clearables_t python_clearables; +void hexrays_clear_python_clearable_references(void) { - qvector::iterator found = python_cfuncptrs.find(fp); - if ( found != python_cfuncptrs.end() ) + for ( size_t i = 0, n = python_clearables.size(); i < n; ++i ) { - fp->reset(); - python_cfuncptrs.erase(found); + const hx_clearable_t &hxc = python_clearables[i]; + /*msg("### cleaning up %p\n", hxc.ptr);*/ + switch ( hxc.type ) + { + case hxclr_cfuncptr: + ((cfuncptr_t*)hxc.ptr)->reset(); + break; + case hxclr_cinsn: + ((cinsn_t *)hxc.ptr)->cleanup(); + break; + case hxclr_cexpr: + ((cexpr_t *)hxc.ptr)->cleanup(); + break; + case hxclr_cblock: + ((cblock_t *)hxc.ptr)->clear(); + break; + default: INTERR(30499); + } } } +//------------------------------------------------------------------------- +void hexrays_register_python_clearable_instance( + void *ptr, + hx_clearable_type_t type) +{ + for ( size_t i = 0, n = python_clearables.size(); i < n; ++i ) + if ( python_clearables[i].ptr == ptr ) + return; + hx_clearable_t &hxc = python_clearables.push_back(); + hxc.ptr = ptr; + hxc.type = type; + /*msg("### registered %p\n", hxc.ptr);*/ +} + +//------------------------------------------------------------------------- +// Note: drop ownership, but don't cleanup! The cleanup will be done by +// the SWiG destructor wrapper if this object's still owned by the Python +// runtime, or it will be done by the C tree itself later. +void hexrays_deregister_python_clearable_instance(void *ptr) +{ + for ( size_t i = 0, n = python_clearables.size(); i < n; ++i ) + { + const hx_clearable_t &hxc = python_clearables[i]; + if ( hxc.ptr == ptr ) + { + python_clearables.erase(python_clearables.begin() + i); + /*msg("### de-registered %p\n", hxc.ptr);*/ + break; + } + } +} + +//------------------------------------------------------------------------- +// //------------------------------------------------------------------------- cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf) { @@ -311,7 +417,7 @@ static bool is_hexrays_plugin(const plugin_info_t *pinfo) if ( pinfo != NULL && pinfo->entry != NULL ) { const plugin_t *p = pinfo->entry; - if ( streq(p->wanted_name, "Hex-Rays Decompiler") ) + if ( streq(p->wanted_name, MODULE_NAME) ) is_hx = true; } return is_hx; @@ -326,59 +432,82 @@ static void try_init() } //------------------------------------------------------------------------- -static int idaapi on_ui_notification(void *, int code, va_list va) +static void *idaapi exit_time_dummy_hexdsp(int code, ...) +{ +/* This callback exists to avoid crashes if the user calls any hexrays functions + after unloading the decompiler. + switch ( code ) + { + case hx_cexpr_t_cleanup: break; + case hx_cinsn_t_cleanup: break; + default: break; + }*/ + return NULL; +} + +//------------------------------------------------------------------------- +inline bool hexdsp_inited() +{ + return hexdsp != NULL + && hexdsp != init_time_dummy_hexdsp + && hexdsp != exit_time_dummy_hexdsp; +} + +//------------------------------------------------------------------------- +static ssize_t idaapi ida_hexrays_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(); + if ( !hexdsp_inited() ) + { + const plugin_info_t *pi = va_arg(va, plugin_info_t *); + if ( is_hexrays_plugin(pi) ) + try_init(); + } break; case ui_plugin_unloading: + if ( hexdsp != NULL && hexdsp != init_time_dummy_hexdsp ) { - if ( hexdsp != NULL ) + // Hex-Rays will close. Make sure all the refcounted cfunc_t objects + // are cleared right away. + const plugin_info_t *pi = va_arg(va, plugin_info_t *); + if ( is_hexrays_plugin(pi) ) { - // 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; - } + QASSERT(30500, hexdsp != exit_time_dummy_hexdsp); + hexrays_clear_python_clearable_references(); + hexdsp = exit_time_dummy_hexdsp; } } break; + case ui_term: + hexdsp = init_time_dummy_hexdsp; + break; } return 0; } + +//------------------------------------------------------------------------- +static void ida_hexrays_term(void) +{ + idapython_unhook_from_notification_point( + HT_UI, ida_hexrays_ui_notification, NULL); +} + +//------------------------------------------------------------------------- +static void ida_hexrays_closebase(void) {} // // //--------------------------------------------------------------------- -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; + return hexdsp_inited() || init_hexrays_plugin(flags); } -//--------------------------------------------------------------------- -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) { @@ -420,20 +549,29 @@ bool py_decompile_many(const char *outfile, PyObject *funcaddrs, int 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 +// calls get_widget_vdui() to figure out whether the action should be enabled +// for the current widget. 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) +vdui_t *py_get_widget_vdui(TWidget *f) { - return hexdsp != NULL ? get_tform_vdui(f) : NULL; + return hexdsp_inited() ? get_widget_vdui(f) : NULL; +} + +inline boundaries_iterator_t py_boundaries_find(const boundaries_t *map, const cinsn_t *key) +{ + return boundaries_find(map, key); +} + +inline boundaries_iterator_t py_boundaries_insert(boundaries_t *map, const cinsn_t *key, const rangeset_t &val) +{ + return boundaries_insert(map, key, val); } // // -try_init(); -hook_to_notification_point(HT_UI, on_ui_notification, NULL); +idapython_hook_to_notification_point(HT_UI, ida_hexrays_ui_notification, NULL); // diff --git a/pywraps/py_hexrays.py b/pywraps/py_hexrays.py index 3f32205..895cb17 100644 --- a/pywraps/py_hexrays.py +++ b/pywraps/py_hexrays.py @@ -258,6 +258,10 @@ lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var) # dictify all dict-like types +def _map___iter__(self): + """ Iterate over dictionary keys. """ + return self.iterkeys() + def _map___getitem__(self, key): """ Returns the value associated with the provided key. """ if not isinstance(key, self.keytype): @@ -389,6 +393,7 @@ def _map_as_dict(maptype, name, keytype, valuetype): 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.__iter__ = _map___iter__ maptype.__getitem__ = _map___getitem__ maptype.__setitem__ = _map___setitem__ maptype.__delitem__ = _map___delitem__ @@ -414,6 +419,66 @@ _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) +import ida_range +_map_as_dict(boundaries_t, 'boundaries', cinsn_t, ida_range.rangeset_t) + +# +# Object ownership +# +def _call_with_transferrable_ownership(fun, *args): + e = args[0] + was_owned = e.thisown + res = fun(e, *args[1:]) + # ATM, 'res' doesn't own the resulting cexpr_t. + # In case 'fun' + # - created a new object: we want to own that one in case 'e' was owned + # - didn't create a new object: we will remove & re-gain ownership on + # the same underlying cexpr_t. No biggie. + if res and was_owned: + e._maybe_disown_and_deregister() + res._own_and_register() + return res + +def lnot(e): + return _call_with_transferrable_ownership(_ll_lnot, e) + +def make_ref(e): + return _call_with_transferrable_ownership(_ll_make_ref, e) + +def dereference(e, ptrsize, is_float=False): + return _call_with_transferrable_ownership(_ll_dereference, e, ptrsize, is_float) + +def call_helper(rettype, args, *rest): + res = _ll_call_helper(rettype, args, *rest) + if res: + res._own_and_register() + if type(args) == carglist_t: + args.thisown = False + return res + +def new_block(): + res = _ll_new_block() + if res: + res._own_and_register() + return res + +def make_num(*args): + res = _ll_make_num(*args) + if res: + res._own_and_register() + return res + +def create_helper(*args): + res = _ll_create_helper(*args) + if res: + res._own_and_register() + return res # + +# +get_tform_vdui=get_widget_vdui +hx_get_tform_vdui=hx_get_widget_vdui +HEXRAYS_API_MAGIC1=(HEXRAYS_API_MAGIC>>32) +HEXRAYS_API_MAGIC2=(HEXRAYS_API_MAGIC&0xFFFFFFFFL) +# diff --git a/pywraps/py_ida.py b/pywraps/py_ida.py new file mode 100644 index 0000000..e7efbaf --- /dev/null +++ b/pywraps/py_ida.py @@ -0,0 +1,47 @@ + +# +AF2_ANORET=AF_ANORET +AF2_CHKUNI=AF_CHKUNI +AF2_DATOFF=AF_DATOFF +AF2_DOCODE=AF_DOCODE +AF2_DODATA=AF_DODATA +AF2_FTAIL=AF_FTAIL +AF2_HFLIRT=AF_HFLIRT +AF2_JUMPTBL=AF_JUMPTBL +AF2_MEMFUNC=AF_MEMFUNC +AF2_PURDAT=AF_PURDAT +AF2_REGARG=AF_REGARG +AF2_SIGCMT=AF_SIGCMT +AF2_SIGMLT=AF_SIGMLT +AF2_STKARG=AF_STKARG +AF2_TRFUNC=AF_TRFUNC +AF2_VERSP=AF_VERSP +AF_ASCII=AF_STRLIT +ASCF_AUTO=STRF_AUTO +ASCF_COMMENT=STRF_COMMENT +ASCF_GEN=STRF_GEN +ASCF_SAVECASE=STRF_SAVECASE +ASCF_SERIAL=STRF_SERIAL +ASCF_UNICODE=STRF_UNICODE +INFFL_LZERO=OFLG_LZERO +ansi2idb=ida_idaapi._BC695.identity +idb2scr=ida_idaapi._BC695.identity +scr2idb=ida_idaapi._BC695.identity +showAllComments=show_all_comments +showComments=show_comments +showRepeatables=show_repeatables +toEA=to_ea + +def __wrap_hooks_callback(klass, new_name, old_name, do_call): + bkp_name = "__real_%s" % new_name + def __wrapper(self, *args): + rc = getattr(self, bkp_name)(*args) + cb = getattr(self, old_name, None) + if cb: + rc = do_call(cb, *args) + return rc + + setattr(klass, bkp_name, getattr(klass, new_name)) + setattr(klass, new_name, __wrapper) + +# diff --git a/pywraps/py_idaapi.hpp b/pywraps/py_idaapi.hpp index 6ac3971..253d860 100644 --- a/pywraps/py_idaapi.hpp +++ b/pywraps/py_idaapi.hpp @@ -95,23 +95,20 @@ PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject } //------------------------------------------------------------------------- -TForm *pycim_get_tform(PyObject *self) +TWidget *pycim_get_widget(PyObject *self) { CHK_THIS_OR_NULL(); - TForm *form = NULL; - if ( !pycim_lookup_info.find_by_py_view(&form, NULL, _this) ) + TWidget *widget = NULL; + if ( !pycim_lookup_info.find_by_py_view(&widget, _this) ) return NULL; - return form; + return widget; } //------------------------------------------------------------------------- -TCustomControl *pycim_get_tcustom_control(PyObject *self) +void pycim_view_close(PyObject *self) { - CHK_THIS_OR_NULL(); - TCustomControl *tcc = NULL; - if ( !pycim_lookup_info.find_by_py_view(NULL, &tcc, _this) ) - return NULL; - return tcc; + CHK_THIS(); + delete _this; } #undef CHK_THIS_OR_NONE @@ -141,7 +138,7 @@ static PyObject *py_parse_command_line(const char *cmdline) PYW_GIL_CHECK_LOCKED_SCOPE(); qstrvec_t args; - if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 ) + if ( parse_command_line(&args, NULL, cmdline, LP_PATH_WITH_ARGS) == 0 ) Py_RETURN_NONE; return qstrvec2pylist(args); } @@ -253,8 +250,8 @@ 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); +TWidget *pycim_get_widget(PyObject *self); +void pycim_view_close(PyObject *self); // #endif diff --git a/pywraps/py_idaapi.py b/pywraps/py_idaapi.py index b3f1e04..c84a454 100644 --- a/pywraps/py_idaapi.py +++ b/pywraps/py_idaapi.py @@ -178,6 +178,14 @@ class object_t(object): """Allow access to object attributes by index (like dictionaries)""" return getattr(self, idx) +# ----------------------------------------------------------------------- +def _qvector_front(self): + return self.at(0) + +# ----------------------------------------------------------------------- +def _qvector_back(self): + return self.at((self.size() - 1) if self.size() else 0) + # ----------------------------------------------------------------------- def _bounded_getitem_iterator(self): """Helper function, to be set as __iter__ method for qvector-, or array-based classes.""" @@ -276,7 +284,7 @@ def as_unicode(s): """Convenience function to convert a string into appropriate unicode format""" # use UTF16 big/little endian, depending on the environment? import _ida_ida - return unicode(s).encode("UTF-16" + ("BE" if _ida_ida.cvar.inf.mf else "LE")) + return unicode(s).encode("UTF-16" + ("BE" if _ida_ida.cvar.inf.is_be() else "LE")) # ----------------------------------------------------------------------- def as_uint32(v): @@ -340,6 +348,19 @@ def struct_unpack(buffer, signed = False, offs = 0): # Unpack return struct.unpack_from(__struct_unpack_table[n][signed], buffer, offs)[0] +# ------------------------------------------------------------ +try: + "".decode("UTF-8").encode("mbcs") + has_mbcs = True +except: + has_mbcs = False + +def _utf8_native(utf8): + if has_mbcs: + uni = utf8.decode("UTF-8") + return uni.encode("mbcs") + else: + return utf8 # ------------------------------------------------------------ def IDAPython_ExecSystem(cmd): @@ -347,6 +368,7 @@ def IDAPython_ExecSystem(cmd): Executes a command with popen(). """ try: + cmd = _utf8_native(cmd) f = os.popen(cmd, "r") s = ''.join(f.readlines()) f.close() @@ -374,6 +396,7 @@ def IDAPython_ExecScript(script, g, print_error=True): This function is used by the low-level plugin code. """ + script = _utf8_native(script) scriptpath = os.path.dirname(script) if len(scriptpath) and scriptpath not in sys.path: sys.path.append(scriptpath) @@ -404,6 +427,7 @@ def IDAPython_LoadProcMod(script, g, print_error=True): """ Load processor module. """ + script = _utf8_native(script) pname = g['__name__'] if g and g.has_key("__name__") else '__main__' parent = sys.modules[pname] @@ -444,6 +468,7 @@ def IDAPython_UnLoadProcMod(script, g, print_error=True): """ Unload processor module. """ + script = _utf8_native(script) pname = g['__name__'] if g and g.has_key("__name__") else '__main__' parent = sys.modules[pname] @@ -551,127 +576,38 @@ 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) +# Since version 5.5, PyQt5 doesn't simply print the PyQt exceptions by default +# anymore: https://github.com/baoboa/pyqt5/commit/1e1d8a3ba677ef3e47b916b8a5b9c281d0f8e4b5#diff-848704a82f6a6e3a13112145ce32ac69L63 +# The default behavior now is that qFatal() is called, causing the application +# to abort(). +# We do not want that to happen in IDA, and simply having a sys.excepthook +# that is different from sys.__excepthook__ is enough for PyQt5 to return +# to the previous behavior +def __install_excepthook(): + real_hook = sys.excepthook + sys.excepthook = lambda *args: real_hook(*args) +__install_excepthook() - 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) +# ----------------------------------- helpers for bw-compat w/ 6.95 API +class __BC695: + def __init__(self): + self.FIXME = "FIXME @arnaud" - def SetNodeInfo(self, node_index, node_info, flags): - """ - Set the properties for the given node. + def false_p(self, *args): + return False - 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) + def identity(self, arg): + return arg - @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) + def dummy(self, *args): + pass +_BC695 = __BC695() # + +# +pycim_get_tcustom_control=pycim_get_widget +pycim_get_tform=pycim_get_widget +# diff --git a/pywraps/py_idaapi_loader_input.hpp b/pywraps/py_idaapi_loader_input.hpp index de0e5b0..e1615e1 100644 --- a/pywraps/py_idaapi_loader_input.hpp +++ b/pywraps/py_idaapi_loader_input.hpp @@ -35,7 +35,7 @@ class loader_input_t(pyidc_opaque_object_t): """Create a linput for process memory (By internally calling idaapi.create_memory_linput()) This linput will use dbg->read_memory() to read data @param start: starting address of the input - @param size: size of the memory area to represent as linput + @param size: size of the memory range to represent as linput if unknown, may be passed as 0 """ pass @@ -251,9 +251,9 @@ public: } //-------------------------------------------------------------------------- - int32 seek(int32 pos, int whence = SEEK_SET) + int64 seek(int64 pos, int whence = SEEK_SET) { - int32 r; + int64 r; PYW_GIL_GET; Py_BEGIN_ALLOW_THREADS; r = qlseek(li, pos, whence); @@ -262,9 +262,9 @@ public: } //-------------------------------------------------------------------------- - int32 tell() + int64 tell() { - int32 r; + int64 r; PYW_GIL_GET; Py_BEGIN_ALLOW_THREADS; r = qltell(li); @@ -273,7 +273,7 @@ public: } //-------------------------------------------------------------------------- - PyObject *getz(size_t sz, int32 fpos = -1) + PyObject *getz(size_t sz, int64 fpos = -1) { PYW_GIL_CHECK_LOCKED_SCOPE(); do @@ -305,10 +305,7 @@ public: ok = qlgets(buf, len, li) != NULL; Py_END_ALLOW_THREADS; if ( !ok ) - { - free(buf); - break; - } + buf[0] = '\0'; PyObject *ret = PyString_FromString(buf); free(buf); return ret; @@ -330,10 +327,7 @@ public: r = qlread(li, buf, size); Py_END_ALLOW_THREADS; if ( r == -1 ) - { - free(buf); - break; - } + r = 0; PyObject *ret = PyString_FromStringAndSize(buf, r); free(buf); return ret; @@ -361,10 +355,7 @@ public: r = lreadbytes(li, buf, size, big_endian); Py_END_ALLOW_THREADS; if ( r == -1 ) - { - free(buf); - break; - } + r = 0; PyObject *ret = PyString_FromStringAndSize(buf, r); free(buf); return ret; @@ -373,7 +364,7 @@ public: } //-------------------------------------------------------------------------- - int file2base(int32 pos, ea_t ea1, ea_t ea2, int patchable) + int file2base(int64 pos, ea_t ea1, ea_t ea2, int patchable) { int rc; Py_BEGIN_ALLOW_THREADS; @@ -383,9 +374,9 @@ public: } //-------------------------------------------------------------------------- - int32 size() + int64 size() { - int32 rc; + int64 rc; Py_BEGIN_ALLOW_THREADS; rc = qlsize(li); Py_END_ALLOW_THREADS; diff --git a/pywraps/py_idc.hpp b/pywraps/py_idc.hpp new file mode 100644 index 0000000..a7b5dab --- /dev/null +++ b/pywraps/py_idc.hpp @@ -0,0 +1,46 @@ + +// +//------------------------------------------------------------------------- +inline void mark_position( + ea_t ea, + int lnnum, + short x, + short y, + int32 slot, + const char *comment) +{ + idaplace_t ip(ea, lnnum); + renderer_info_t ri; + ri.rtype = TCCRT_FLAT; + ri.pos.cx = x; + ri.pos.cy = y; + lochist_entry_t loc(&ip, ri); + bookmarks_t::mark(loc, slot, NULL, comment, NULL); +} + +//------------------------------------------------------------------------- +inline ea_t get_marked_pos(int32 slot) +{ + idaplace_t ip(inf.min_ea, 0); + renderer_info_t ri; + lochist_entry_t loc(&ip, ri); + uint32 uslot = uint32(slot); + return bookmarks_t::get(&loc, NULL, &uslot, NULL) + ? loc.place()->toea() + : BADADDR; +} + +//------------------------------------------------------------------------- +inline PyObject *get_mark_comment(int32 slot) +{ + qstring desc; + idaplace_t ip(inf.min_ea, 0); + renderer_info_t ri; + lochist_entry_t loc(&ip, ri); + if ( bookmarks_t::get_desc(&desc, loc, slot, NULL) ) + return PyString_FromString(desc.c_str()); + else + Py_RETURN_NONE; +} +// + diff --git a/pywraps/py_idd.hpp b/pywraps/py_idd.hpp index 0443002..f426871 100644 --- a/pywraps/py_idd.hpp +++ b/pywraps/py_idd.hpp @@ -11,11 +11,11 @@ static bool dbg_can_query() //------------------------------------------------------------------------- PyObject *py_appcall( - ea_t func_ea, - thid_t tid, - PyObject *py_type, - PyObject *py_fields, - PyObject *arg_list) + ea_t func_ea, + thid_t tid, + PyObject *py_type, + PyObject *py_fields, + PyObject *arg_list) { PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -24,6 +24,10 @@ PyObject *py_appcall( const char *type = py_type == Py_None ? NULL : PyString_AS_STRING(py_type); const char *fields = py_fields == Py_None ? NULL : PyString_AS_STRING(py_fields); + tinfo_t tif; + tinfo_t *ptif = NULL; + if ( tif.deserialize(NULL, (const type_t **)&type, (const p_list **)&fields) ) + ptif = &tif; // Convert Python arguments into IDC values qvector idc_args; @@ -70,21 +74,19 @@ PyObject *py_appcall( qstring s; for ( Py_ssize_t i=0; i < nargs; i++ ) { - VarPrint(&s, &idc_args[i]); + print_idcv(&s, idc_args[i]); msg("%d]\n%s\n-----------\n", int(i), s.c_str()); s.qclear(); } } // Do Appcall - ret = appcall( - func_ea, - tid, - (type_t *)type, - (p_list *)fields, - idc_args.size(), - idc_args.begin(), - &idc_result); + ret = dbg_appcall(&idc_result, + func_ea, + tid, + ptif, + idc_args.begin(), + idc_args.size()); Py_END_ALLOW_THREADS; @@ -102,9 +104,7 @@ PyObject *py_appcall( // An error in the Appcall? (or an exception but AppCallOptions/DEBEV is not set) else { - char err_str[MAXSTR]; - qstrerror(ret, err_str, sizeof(err_str)); - PyErr_SetString(PyExc_Exception, err_str); + PyErr_SetString(PyExc_Exception, qstrerror(ret)); return NULL; } } @@ -116,7 +116,7 @@ PyObject *py_appcall( qstring s; for ( Py_ssize_t i=0; i < nargs; i++ ) { - VarPrint(&s, &idc_args[i]); + print_idcv(&s, idc_args[i]); msg("%d]\n%s\n-----------\n", int(i), s.c_str()); s.qclear(); } @@ -147,7 +147,7 @@ PyObject *py_appcall( msg("return var:\n" "-----------\n"); qstring s; - VarPrint(&s, &idc_result); + print_idcv(&s, idc_result); msg("%s\n-----------\n", s.c_str()); } py_result.incref(); @@ -166,7 +166,7 @@ def dbg_get_registers(): Basically, it returns an array of structure similar to to idd.hpp / register_info_t @return: None if no debugger is loaded - tuple(name, flags, class, dtyp, bit_strings, default_bit_strings_mask) + tuple(name, flags, class, dtype, bit_strings, default_bit_strings_mask) The bit_strings can be a tuple of strings or None (if the register does not have bit_strings) """ pass @@ -190,7 +190,7 @@ static PyObject *dbg_get_registers() // (Make sure it does not use custom formats because bit_string would be the format name) if ( ri.bit_strings != NULL && (ri.flags & REGISTER_CUSTFMT) == 0 ) { - int nbits = (int)b2a_width((int)get_dtyp_size(ri.dtyp), 0) * 4; + int nbits = (int)b2a_width((int)get_dtype_size(ri.dtype), 0) * 4; py_bits = PyList_New(nbits); for ( int i=0; i < nbits; i++ ) { @@ -204,13 +204,13 @@ static PyObject *dbg_get_registers() py_bits = Py_None; } - // name, flags, class, dtyp, bit_strings, default_bit_strings_mask + // name, flags, class, dtype, bit_strings, default_bit_strings_mask PyList_SetItem(py_list, i, Py_BuildValue("(sIIINI)", ri.name, ri.flags, (unsigned int)ri.register_class, - (unsigned int)ri.dtyp, + (unsigned int)ri.dtype, py_bits, (unsigned int)ri.default_bit_strings_mask)); } @@ -241,10 +241,10 @@ static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_va ea_t answer; thid_t tid = PyInt_AsLong(py_tid); int sreg_value = PyInt_AsLong(py_sreg_value); - if ( internal_get_sreg_base(tid, sreg_value, &answer) != 1 ) + if ( internal_get_sreg_base(&answer, tid, sreg_value) != 1 ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, pyul_t(answer)); + return Py_BuildValue(PY_BV_EA, bvea_t(answer)); } //------------------------------------------------------------------------- @@ -343,7 +343,7 @@ def dbg_get_memory_info(): This function returns the memory configuration of a debugged process. @return: None if no debugger is active - tuple(startEA, endEA, name, sclass, sbase, bitness, perm) + tuple(start_ea, end_ea, name, sclass, sbase, bitness, perm) """ pass # @@ -356,14 +356,14 @@ static PyObject *dbg_get_memory_info() Py_RETURN_NONE; // Invalidate memory - meminfo_vec_t areas; + meminfo_vec_t ranges; Py_BEGIN_ALLOW_THREADS; invalidate_dbgmem_config(); invalidate_dbgmem_contents(BADADDR, BADADDR); - get_dbg_memory_info(&areas); + get_dbg_memory_info(&ranges); Py_END_ALLOW_THREADS; - return meminfo_vec_t_to_py(areas); + return meminfo_vec_t_to_py(ranges); } //------------------------------------------------------------------------- @@ -384,11 +384,11 @@ def dbg_can_query(): */ static bool dbg_can_query(); PyObject *py_appcall( - ea_t func_ea, - thid_t tid, - PyObject *py_type, - PyObject *py_fields, - PyObject *arg_list); + ea_t func_ea, + thid_t tid, + PyObject *py_type, + PyObject *py_fields, + PyObject *arg_list); char get_event_module_name(const debug_event_t *ev, char *buf, size_t bufsize) { diff --git a/pywraps/py_idd.py b/pywraps/py_idd.py index f672a5f..45ca764 100644 --- a/pywraps/py_idd.py +++ b/pywraps/py_idd.py @@ -155,7 +155,7 @@ class Appcall_callable__(object): def __get_size(self): if self.__type == None: return -1 - r = _ida_typeinf.calc_type_size(_ida_typeinf.cvar.idati, self.__type) + r = _ida_typeinf.calc_type_size(None, self.__type) if not r: return -1 return r @@ -188,9 +188,9 @@ class Appcall_callable__(object): src = self.ea if type(src) == types.StringType: - return _ida_typeinf.unpack_object_from_bv(_ida_typeinf.cvar.idati, self.type, self.fields, src, flags) + return _ida_typeinf.unpack_object_from_bv(None, self.type, self.fields, src, flags) else: - return _ida_typeinf.unpack_object_from_idb(_ida_typeinf.cvar.idati, self.type, self.fields, src, flags) + return _ida_typeinf.unpack_object_from_idb(None, self.type, self.fields, src, flags) def store(self, obj, dest_ea=None, base_ea=0, flags=0): """ @@ -207,14 +207,14 @@ class Appcall_callable__(object): # no ea passed? thus pack to a string if dest_ea is None: return _ida_typeinf.pack_object_to_bv(obj, - _ida_typeinf.cvar.idati, + None, self.type, self.fields, base_ea, flags) else: return _ida_typeinf.pack_object_to_idb(obj, - _ida_typeinf.cvar.idati, + None, self.type, self.fields, dest_ea, @@ -277,7 +277,7 @@ class Appcall__(object): else: ea = name_or_ea # could not resolve name or invalid address? - if ea == _ida_idaapi.BADADDR or not _ida_bytes.isEnabled(ea): + if ea == _ida_idaapi.BADADDR or not _ida_bytes.is_mapped(ea): raise ValueError, "Undefined function " + name_or_ea return ea @@ -299,7 +299,7 @@ class Appcall__(object): if flags is None: flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP - result = _ida_typeinf.idc_parse_decl(_ida_typeinf.cvar.idati, prototype, flags) + result = _ida_typeinf.idc_parse_decl(None, prototype, flags) if result is None: raise ValueError, "Could not parse type: " + prototype @@ -389,7 +389,7 @@ class Appcall__(object): @return: Appcall object or raises ValueError exception """ # parse the type - result = _ida_typeinf.idc_parse_decl(_ida_typeinf.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP + result = _ida_typeinf.idc_parse_decl(None, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP if result is None: raise ValueError, "Could not parse type: " + typestr # Return the callable method with type info @@ -414,3 +414,7 @@ class Appcall__(object): Appcall = Appcall__() # + +# +PROCESS_NO_THREAD=NO_THREAD +# diff --git a/pywraps/py_idp.hpp b/pywraps/py_idp.hpp index a71a88d..3e6a1ae 100644 --- a/pywraps/py_idp.hpp +++ b/pywraps/py_idp.hpp @@ -25,22 +25,16 @@ def AssembleLine(ea, cs, ip, use32, line): # */ static PyObject *AssembleLine( - ea_t ea, - ea_t cs, - ea_t ip, - bool use32, - const char *line) + ea_t ea, + ea_t cs, + ea_t ip, + bool use32, + const char *line) { - int inslen; char buf[MAXSTR]; - bool ok = false; - if ( ph.notify != NULL - && (inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf)) > 0 ) - { - ok = true; - } + int inslen = ph.assemble((uchar *)buf, ea, cs, ip, use32, line); PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( ok ) + if ( inslen > 0 ) return PyString_FromStringAndSize(buf, inslen); else Py_RETURN_NONE; @@ -63,25 +57,21 @@ def assemble(ea, cs, ip, use32, line): # */ bool assemble( - ea_t ea, - ea_t cs, - ea_t ip, - bool use32, - const char *line) + ea_t ea, + ea_t cs, + ea_t ip, + bool use32, + const char *line) { - int inslen; char buf[MAXSTR]; PYW_GIL_CHECK_LOCKED_SCOPE(); bool rc = false; Py_BEGIN_ALLOW_THREADS; - if ( ph.notify != NULL ) + int inslen = ph.assemble((uchar *)buf, ea, cs, ip, use32, line); + if ( inslen > 0 ) { - inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf); - if ( inslen > 0 ) - { - patch_many_bytes(ea, buf, inslen); - rc = true; - } + patch_bytes(ea, buf, inslen); + rc = true; } Py_END_ALLOW_THREADS; return rc; @@ -165,31 +155,31 @@ static size_t ph_get_dnbits() //------------------------------------------------------------------------- /* # -def ph_get_regFirstSreg(): +def ph_get_reg_first_sreg(): """ - Returns the 'ph.regFirstSreg' + Returns the 'ph.reg_first_sreg' """ pass # */ -static size_t ph_get_regFirstSreg() +static size_t ph_get_reg_first_sreg() { - return ph.regFirstSreg; + return ph.reg_first_sreg; } //------------------------------------------------------------------------- /* # -def ph_get_regLastSreg(): +def ph_get_reg_last_sreg(): """ - Returns the 'ph.regLastSreg' + Returns the 'ph.reg_last_sreg' """ pass # */ -static size_t ph_get_regLastSreg() +static size_t ph_get_reg_last_sreg() { - return ph.regLastSreg; + return ph.reg_last_sreg; } //------------------------------------------------------------------------- @@ -210,46 +200,31 @@ static size_t ph_get_segreg_size() //------------------------------------------------------------------------- /* # -def ph_get_regCodeSreg(): +def ph_get_reg_code_sreg(): """ - Returns the 'ph.regCodeSreg' + Returns the 'ph.reg_code_sreg' """ pass # */ -static size_t ph_get_regCodeSreg() +static size_t ph_get_reg_code_sreg() { - return ph.regCodeSreg; + return ph.reg_code_sreg; } //------------------------------------------------------------------------- /* # -def ph_get_regDataSreg(): +def ph_get_reg_data_sreg(): """ - Returns the 'ph.regDataSreg' + Returns the 'ph.reg_data_sreg' """ pass # */ -static size_t ph_get_regDataSreg() +static size_t ph_get_reg_data_sreg() { - return ph.regDataSreg; -} - -//------------------------------------------------------------------------- -/* -# -def ph_get_high_fixup_bits(): - """ - Returns the 'ph.high_fixup_bits' - """ - pass -# -*/ -static size_t ph_get_high_fixup_bits() -{ - return ph.high_fixup_bits; + return ph.reg_data_sreg; } //------------------------------------------------------------------------- @@ -351,16 +326,16 @@ 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 < ph.regsNum; i++ ) - PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i])); + PyObject *py_result = PyList_New(ph.regs_num); + for ( Py_ssize_t i=0; i < ph.regs_num; i++ ) + PyList_SetItem(py_result, i, PyString_FromString(ph.reg_names[i])); return py_result; } //--------------------------------------------------------------------------- static const regval_t *idaapi _py_getreg( - const char *name, - const regval_t *regvals); + const char *name, + const regval_t *regvals); /* # @@ -378,8 +353,8 @@ def ph_get_operand_info(): # */ static PyObject *ph_get_operand_info( - ea_t ea, - int n) + ea_t ea, + int n) { PYW_GIL_CHECK_LOCKED_SCOPE(); bool ok = false; @@ -399,13 +374,13 @@ static PyObject *ph_get_operand_info( break; // Call the processor module - if ( ph.notify(ph.get_operand_info, + if ( ph.notify(ph.ev_get_idd_opinfo, + &opinf, ea, n, tid, _py_getreg, - regvalues.begin(), - &opinf) > 0 ) + regvalues.begin()) == 0 ) { break; } @@ -414,9 +389,9 @@ static PyObject *ph_get_operand_info( Py_END_ALLOW_THREADS; if ( ok ) - return Py_BuildValue("(i" PY_FMT64 "Kii)", + return Py_BuildValue("(i" PY_BV_EA "Kii)", opinf.modified, - opinf.ea, + bvea_t(opinf.ea), opinf.value.ival, opinf.debregidx, opinf.value_size); @@ -445,65 +420,65 @@ class IDP_Hooks(object): pass - def custom_ana(self): + def ev_ana_insn(self, insn): """ - Analyzes and decodes an instruction at idaapi.cmd.ea - - cmd.itype must be set >= idaapi.CUSTOM_CMD_ITYPE - - cmd.size must be set to the instruction length + Analyzes and decodes an instruction at insn.ea + - insn.itype must be set >= idaapi.CUSTOM_CMD_ITYPE + - insn.size must be set to the instruction length @return: Boolean - False if the instruction is not recognized - - True if the instruction was decoded. idaapi.cmd should be filled in that case. + - True if the instruction was decoded. 'insn' should be filled in that case. """ pass - def custom_out(self): + def ev_out_insn(self, ctx): """ - Outputs the instruction defined in idaapi.cmd + Outputs the instruction defined in 'ctx.insn' @return: Boolean (whether this instruction can be outputted or not) """ pass - def custom_emu(self): + def ev_emu_insn(self, insn): """ Emulate instruction, create cross-references, plan to analyze subsequent instructions, modify flags etc. Upon entrance to this function - all information about the instruction is in 'cmd' structure. + all information about the instruction is in 'insn' structure. @return: Boolean (whether this instruction has been emulated or not) """ pass - def custom_outop(self, op): + def ev_out_operand(self, ctx, op): """ Notification to generate operand text. If False was returned, then the standard operand output function will be called. - The output buffer is inited with init_output_buffer() - and this notification may use out_...() functions to form the operand text + this notification may use out_...() functions to form the operand text @return: Boolean (whether the operand has been outputted or not) """ pass - def custom_mnem(self): + def ev_gen_mnem(self, ctx): """ - Prints the mnemonic of the instruction defined in idaapi.cmd + Notification to generate instruction mnemonics. @return: - - None: No mnemonic. IDA will use the default mnemonic value if present - - String: The desired mnemonic string + - None: No custom mnemonics. IDA will generate a mnemonic name + - 1: Generated the instruction mnemonics """ pass - def is_sane_insn(self, no_crefs): + def ev_is_sane_insn(self, insn, no_crefs): """ is the instruction sane for the current file type? + @param insn: the instruction @param no_crefs: - 1: the instruction has no code refs to it. ida just tries to convert unexplored bytes @@ -512,14 +487,15 @@ class IDP_Hooks(object): - 0: the instruction is created because of some coderef, user request or another weighty reason. - @return: 1-ok, <=0-no, the instruction isn't likely to appear in the program + @return: >=0-ok, <0-no, the instruction isn't likely to appear in the program """ pass - def may_be_func(self, no_crefs): + def ev_may_be_func(self, insn, state): """ Can a function start here? + @param insn: the instruction @param state: autoanalysis phase 0: creating functions 1: creating chunks @@ -529,21 +505,7 @@ class IDP_Hooks(object): pass - def closebase(self): - """ - The database will be closed now - """ - pass - - - def savebase(self): - """ - The database is being saved. Processor module should - """ - pass - - - def rename(self, ea, new_name): + def ev_rename(self, ea, new_name): """ The kernel is going to rename a byte. @@ -551,121 +513,46 @@ class IDP_Hooks(object): @param new_name: The new name @return: - - If returns value <=0, then the kernel should + - If returns value <0, then the kernel should not rename it. See also the 'renamed' event """ pass - def renamed(self, ea, new_name, local_name): - """ - The kernel has renamed a byte - - @param ea: Address - @param new_name: The new name - @param local_name: Is local name - - @return: Ignored - """ - pass - - - def undefine(self, ea): + def ev_undefine(self, ea): """ An item in the database (insn or data) is being deleted @param ea: Address @return: - - returns: >0-ok, <=0-the kernel should stop - - if the return value is positive: - bit0 - ignored - bit1 - do not delete srareas at the item end + - 1 - do not delete srranges at the item end + - 0 - srranges can be deleted """ pass - def make_code(self, ea, size): - """ - An instruction is being created - @param ea: Address - @param size: Instruction size - @return: 1-ok, <=0-the kernel should stop - """ - pass - - - def make_code(self, ea, size): - """ - An instruction is being created - @param ea: Address - @param size: Instruction size - @return: 1-ok, <=0-the kernel should stop - """ - pass - - - def make_data(self, ea, flags, tid, len): - """ - A data item is being created - @param ea: Address - @param tid: type id - @param flags: item flags - @param len: data item size - @return: 1-ok, <=0-the kernel should stop - """ - pass - - - def load_idasgn(self, short_sig_name): - """ - FLIRT signature have been loaded for normal processing - (not for recognition of startup sequences) - @param short_sig_name: signature name - @return: Ignored - """ - pass - - - def add_func(self, func): - """ - The kernel has added a function - @param func: the func_t instance - @return: Ignored - """ - pass - - - def del_func(self, func): - """ - The kernel is about to delete a function - @param func: the func_t instance - @return: 1-ok,<=0-do not delete - """ - pass - - - def is_call_insn(self, ea, func_name): + def ev_is_call_insn(self, insn): """ Is the instruction a "call"? - @param ea: instruction address - @return: 1-unknown, 0-no, 2-yes + @param insn: instruction + @return: 0-unknown, 1-yes, -1-no """ pass - def is_ret_insn(self, ea, func_name): + def ev_is_ret_insn(self, insn, strict): """ Is the instruction a "return"? - @param ea: instruction address + @param insn: instruction @param strict: - True: report only ret instructions False: include instructions like "leave" which begins the function epilog - @return: 1-unknown, 0-no, 2-yes + @return: 0-unknown, 1-yes, -1-no """ pass - def assemble(self, ea, cs, ip, use32, line): + def ev_assemble(self, ea, cs, ip, use32, line): """ Assembles an instruction @@ -689,37 +576,28 @@ class IDP_Hooks(object): // Necessary forward declarations; idp.hpp itself doesn't need them. struct mblock_t; struct proc_def; -struct set_elf_reloc_t; struct libfunc_t; -int idaapi IDP_Callback(void *ud, int notification_code, va_list va); +ssize_t idaapi IDP_Callback(void *ud, int notification_code, va_list va); class IDP_Hooks { - friend int idaapi IDP_Callback(void *ud, int notification_code, va_list va); - static int bool_to_cmdsize(bool in) { return in ? (1 + cmd.size) : 0; } - static int bool_to_2or0(bool in) { return in ? 2 : 0; } + friend ssize_t idaapi IDP_Callback(void *ud, int notification_code, va_list va); + static int bool_to_insn_t_size(bool in, const insn_t *insn) { return in ? insn->size : 0; } + static int bool_to_1or0(bool in) { return in ? 1 : 0; } static int cm_t_to_int(cm_t cm) { return int(cm); } - static bool _handle_string_output(PyObject *o, char *buf, size_t bufsize) - { - bool is_str = o != NULL && PyString_Check(o); - if ( is_str && buf != NULL ) - qstrncpy(buf, PyString_AS_STRING(o), bufsize); - Py_XDECREF(o); - return is_str; - } static bool _handle_qstring_output(PyObject *o, qstring *buf) { bool is_str = o != NULL && PyString_Check(o); if ( is_str && buf != NULL ) - buf->append(PyString_AS_STRING(o)); + *buf = PyString_AS_STRING(o); Py_XDECREF(o); return is_str; } - static int handle_custom_mnem_output(PyObject *o, char *buf, size_t bufsize) + static int handle_custom_mnem_output(PyObject *o, qstring *out, const insn_t *) { - return _handle_string_output(o, buf, bufsize) ? 2 : 0; + return _handle_qstring_output(o, out) && !out->empty() ? 1 : 0; } - static int handle_assemble_output(PyObject *o, ea_t /*ea*/, ea_t /*cs*/, ea_t /*ip*/, bool /*use32*/, const char */*line*/, uchar *bin) + static int handle_assemble_output(PyObject *o, uchar *bin, ea_t /*ea*/, ea_t /*cs*/, ea_t /*ip*/, bool /*use32*/, const char */*line*/) { int rc = 0; if ( o != NULL && PyString_Check(o) ) @@ -737,16 +615,13 @@ class IDP_Hooks Py_XDECREF(o); return rc; } - static int handle_get_reg_name_output(PyObject *o, int /*reg*/, size_t /*width*/, char *buf, size_t bufsize, int /*reghi*/) + static int handle_get_reg_name_output(PyObject *o, qstring *buf, int /*reg*/, size_t /*width*/, int /*reghi*/) { - int rc = 0; - if ( _handle_string_output(o, buf, bufsize) ) - rc = qstrlen(buf) + 2; - return rc; + return _handle_qstring_output(o, buf) ? buf->length() : 0; } - static int handle_decorate_name3_output(PyObject *o, qstring *outbuf, const char * /*name*/, bool /*mangle*/, int /*cc*/) + static int handle_decorate_name3_output(PyObject *o, qstring *outbuf, const char * /*name*/, bool /*mangle*/, int /*cc*/, const tinfo_t * /*type*/) { - return _handle_qstring_output(o, outbuf) ? 2 : 0; + return _handle_qstring_output(o, outbuf) ? 1 : 0; } static int handle_delay_slot_insn_output(PyObject *o, ea_t *pea, bool *pbexec, bool *pfexec) { @@ -766,11 +641,58 @@ class IDP_Hooks *pbexec = py_bexec.o == Py_True; if ( pfexec != NULL ) *pfexec = py_fexec.o == Py_True; - return 2; + return 1; } } return -1; } + static int handle_use_regarg_type_output(PyObject *o, int *idx, ea_t, const funcargvec_t *) + { + int rc = 0; + if ( PySequence_Check(o) && PySequence_Size(o) == 2 ) + { + newref_t py_rc(PySequence_GetItem(o, 0)); + newref_t py_idx(PySequence_GetItem(o, 1)); + if ( PyInt_Check(py_rc.o) && PyInt_Check(py_idx.o) ) + { + rc = PyInt_AsLong(py_rc.o); + *idx = PyInt_AsLong(py_idx.o); + } + } + return rc; + } + static int handle_demangle_name_output( + PyObject *o, + int32 *out_res, + qstring *out, + const char *name, + uint32 disable_mask, + demreq_type_t demreq) + { + int rc = 0; + if ( PySequence_Check(o) && PySequence_Size(o) == 3 ) + { + newref_t py_rc(PySequence_GetItem(o, 0)); + newref_t py_out(PySequence_GetItem(o, 1)); + newref_t py_out_res(PySequence_GetItem(o, 2)); + char *s; + Py_ssize_t len = 0; + if ( PyInt_Check(py_rc.o) + && PyInt_Check(py_out_res.o) + && PyString_Check(py_out.o) + && PyString_AsStringAndSize(py_out.o, &s, &len) != -1 ) + { + rc = PyInt_AsLong(py_rc.o); + *out_res = PyInt_AsLong(py_out_res.o); + if ( out != NULL ) + { + out->qclear(); + out->append(s, len); + } + } + } + return rc; + } public: virtual ~IDP_Hooks() @@ -780,12 +702,12 @@ public: bool hook() { - return hook_to_notification_point(HT_IDP, IDP_Callback, this); + return idapython_hook_to_notification_point(HT_IDP, IDP_Callback, this); } bool unhook() { - return unhook_from_notification_point(HT_IDP, IDP_Callback, this); + return idapython_unhook_from_notification_point(HT_IDP, IDP_Callback, this); } // hookgenIDP:methods }; @@ -794,7 +716,7 @@ public: //------------------------------------------------------------------------- // //------------------------------------------------------------------------- -int idaapi IDP_Callback(void *ud, int notification_code, va_list va) +ssize_t idaapi IDP_Callback(void *ud, int notification_code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; @@ -819,8 +741,8 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va) //------------------------------------------------------------------------- static const regval_t *idaapi _py_getreg( - const char *name, - const regval_t *regvals) + const char *name, + const regval_t *regvals) { for ( int i=dbg->registers_size - 1; i >= 0; i-- ) { diff --git a/pywraps/py_idp.py b/pywraps/py_idp.py index 0c3ea17..a473ccd 100644 --- a/pywraps/py_idp.py +++ b/pywraps/py_idp.py @@ -7,7 +7,7 @@ # ---------------------------------------------------------------------- # processor_t related constants -CUSTOM_CMD_ITYPE = 0x8000 +CUSTOM_INSN_ITYPE = 0x8000 REG_SPOIL = 0x80000000 REAL_ERROR_FORMAT = -1 # not supported format for current .idp @@ -109,7 +109,6 @@ 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 @@ -122,13 +121,11 @@ PR_BINMEM = 0x010000 # the processor module provides correct PR_SEGTRANS = 0x020000 # the processor module supports # the segment translation feature # (it means it calculates the code - # addresses using the codeSeg() function) + # addresses using the map_code_ea() 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 @@ -187,8 +184,7 @@ 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 + pass def get_idpdesc(self): """ @@ -202,9 +198,9 @@ class processor_t(ida_idaapi.pyidc_opaque_object_t): """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 + def get_auxpref(self, insn): + """This function returns insn.auxpref value""" + return insn.auxpref # ---------------------------------------------------------------------- @@ -213,15 +209,14 @@ class __ph(object): 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()) + reg_code_sreg = property(lambda self: ph_get_reg_code_sreg()) + reg_data_sreg = property(lambda self: ph_get_reg_data_sreg()) + reg_first_sreg = property(lambda self: ph_get_reg_first_sreg()) + reg_last_sreg = property(lambda self: ph_get_reg_last_sreg()) 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()) @@ -230,3 +225,65 @@ class __ph(object): ph = __ph() # + +# +AS_NOTAB=0 +CUSTOM_CMD_ITYPE=CUSTOM_INSN_ITYPE +InstrIsSet=has_insn_feature +NEXTEAS_ANSWER_SIZE=0 +PR_FULL_HIFXP=0 +SETPROC_ALL=SETPROC_LOADER_NON_FATAL +SETPROC_COMPAT=SETPROC_IDB +SETPROC_FATAL=SETPROC_LOADER +area_cmt_changed=range_cmt_changed +changed_stkpnts=stkpnts_changed +changed_struc=struc_align_changed +changing_area_cmt=changing_range_cmt +changing_struc=changing_struc_align +func_tail_removed=func_tail_deleted +get_reg_info2=get_reg_info +ph_get_regCodeSreg=ph_get_reg_code_sreg +ph_get_regDataSreg=ph_get_reg_data_sreg +ph_get_regFirstSreg=ph_get_reg_first_sreg +ph_get_regLastSreg=ph_get_reg_last_sreg +removing_func_tail=deleting_func_tail +segm_attrs_changed=segm_attrs_updated +str2regf=str2reg +def __wrap_insn_func(name): + def __wrapper(*args): + arg0 = args[0] + import ida_ua + if not isinstance(arg0, ida_ua.insn_t): + tmp = ida_ua.insn_t() + if not ida_ua.decode_insn(tmp, arg0): + return False + arg0 = tmp + return getattr(_ida_idp, name)(arg0, *args[1:]) + globals()[name] = __wrapper +__wrap_insn_func("is_call_insn") +__wrap_insn_func("is_ret_insn") +__wrap_insn_func("is_indirect_jump_insn") +__wrap_insn_func("is_basic_block_end") +def parse_reg_name(*args): + if isinstance(args[1], reg_info_t): # 6.95: regname, reg_info_t + regname, ri = args + else: # 7.00: reg_info_t, regname + ri, regname = args + return _ida_idp.parse_reg_name(ri, regname) + +def __call_IDP_Hooks_auto_queue_empty(cb, qtype): + old_rc = cb(qtype) + if old_rc == 0: # 6.95's queue not empty anymore + rc = -1 # 7.0's queue not empty anymore + else: + rc = old_rc + return rc + +import ida_ida +ida_ida.__wrap_hooks_callback( + IDP_Hooks, + "ev_auto_queue_empty", + "auto_queue_empty", + __call_IDP_Hooks_auto_queue_empty) + +# diff --git a/pywraps/py_idp_idbhooks.hpp b/pywraps/py_idp_idbhooks.hpp index 5f40831..8ef143b 100644 --- a/pywraps/py_idp_idbhooks.hpp +++ b/pywraps/py_idp_idbhooks.hpp @@ -4,7 +4,7 @@ //--------------------------------------------------------------------------- // IDB hooks //--------------------------------------------------------------------------- -int idaapi IDB_Callback(void *ud, int notification_code, va_list va); +ssize_t idaapi IDB_Callback(void *ud, int notification_code, va_list va); class IDB_Hooks { public: @@ -12,11 +12,11 @@ public: bool hook() { - return hook_to_notification_point(HT_IDB, IDB_Callback, this); + return idapython_hook_to_notification_point(HT_IDB, IDB_Callback, this); } bool unhook() { - return unhook_from_notification_point(HT_IDB, IDB_Callback, this); + return idapython_unhook_from_notification_point(HT_IDB, IDB_Callback, this); } // hookgenIDB:methods @@ -26,7 +26,7 @@ public: // //--------------------------------------------------------------------------- -int idaapi IDB_Callback(void *ud, int notification_code, va_list va) +ssize_t 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; diff --git a/pywraps/py_kernwin.hpp b/pywraps/py_kernwin.hpp index ba66780..dc662a3 100644 --- a/pywraps/py_kernwin.hpp +++ b/pywraps/py_kernwin.hpp @@ -6,15 +6,7 @@ // //------------------------------------------------------------------------ -//--------------------------------------------------------------------------- -// 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 { @@ -147,25 +139,25 @@ static PyObject *py_choose_idasgn() //------------------------------------------------------------------------ /* # -def get_highlighted_identifier(flags = 0): +def get_highlight(): """ - Returns the currently highlighted identifier + Returns the currently highlighted identifier and flags - @param flags: reserved (pass 0) - @return: None or the highlighted identifier + @return: a tuple (text, flags), or None if nothing + is highlighted or in case of error. """ pass # */ -static PyObject *py_get_highlighted_identifier(int flags = 0) +static PyObject *py_get_highlight(TWidget *v) { - char buf[MAXSTR]; - bool ok = get_highlighted_identifier(buf, sizeof(buf), flags); + qstring buf; + uint32 flags; + bool ok = get_highlight(&buf, v, &flags); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !ok ) Py_RETURN_NONE; - else - return PyString_FromString(buf); + return Py_BuildValue("(sk)", buf.c_str(), flags); } //------------------------------------------------------------------------ @@ -200,7 +192,7 @@ def free_custom_icon(icon_id): //------------------------------------------------------------------------- /* # -def readsel2(view, p0, p1): +def read_selection(view, p0, p1): """ Read the user selection, and store its information in p0 (from) and p1 (to). @@ -210,7 +202,7 @@ def readsel2(view, p0, p1): >>> p0 = idaapi.twinpos_t() p1 = idaapi.twinpos_t() view = idaapi.get_current_viewer() - idaapi.readsel2(view, p0, p1) + idaapi.read_selection(view, p0, p1) At that point, p0 and p1 hold information for the selection. @@ -236,41 +228,6 @@ def readsel2(view, p0, p1): # */ -//------------------------------------------------------------------------ -/* -# -def umsg(text): - """ - Prints text into IDA's Output window - - @param text: text to print - Can be Unicode, or string in UTF-8 encoding - @return: number of bytes printed - """ - pass -# -*/ -static PyObject *py_umsg(PyObject *o) -{ - PyObject *utf8 = NULL; - if ( PyUnicode_Check(o) ) - { - utf8 = PyUnicode_AsUTF8String(o); - o = utf8; - } - else if ( !PyString_Check(o) ) - { - PyErr_SetString(PyExc_TypeError, "A unicode or UTF-8 string expected"); - return NULL; - } - int rc; - Py_BEGIN_ALLOW_THREADS; - rc = umsg("%s", PyString_AsString(o)); - Py_END_ALLOW_THREADS; - Py_XDECREF(utf8); - return PyInt_FromLong(rc); -} - //------------------------------------------------------------------------ /* # @@ -287,17 +244,25 @@ def msg(text): */ static PyObject *py_msg(PyObject *o) { + const char *utf8 = NULL; + ref_t py_utf8; if ( PyUnicode_Check(o) ) - return py_umsg(o); - - if ( !PyString_Check(o) ) + { + py_utf8 = newref_t(PyUnicode_AsUTF8String(o)); + utf8 = PyString_AsString(py_utf8.o); + } + else if ( PyString_Check(o) ) + { + utf8 = PyString_AsString(o); + } + else { PyErr_SetString(PyExc_TypeError, "A string expected"); return NULL; } int rc; Py_BEGIN_ALLOW_THREADS; - rc = msg("%s", PyString_AsString(o)); + rc = msg("%s", utf8); Py_END_ALLOW_THREADS; return PyInt_FromLong(rc); } @@ -305,11 +270,11 @@ static PyObject *py_msg(PyObject *o) //------------------------------------------------------------------------ /* # -def asktext(max_text, defval, prompt): +def ask_text(defval, prompt): """ Asks for a long text - @param max_text: Maximum text length + @param max_size: Maximum text length, 0 for unlimited @param defval: The default value @param prompt: The prompt value @return: None or the entered string @@ -317,27 +282,54 @@ def asktext(max_text, defval, prompt): pass # */ -PyObject *py_asktext(int max_text, const char *defval, const char *prompt) +PyObject *py_ask_text(size_t max_size, const char *defval, const char *prompt) { PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( max_text <= 0 ) - Py_RETURN_NONE; - char *buf = new char[max_text]; - if ( buf == NULL ) - Py_RETURN_NONE; + qstring qbuf; PyObject *py_ret; - if ( asktext(size_t(max_text), buf, defval, "%s", prompt) != NULL ) + if ( ask_text(&qbuf, max_size, defval, "%s", prompt) ) { - py_ret = PyString_FromString(buf); + py_ret = PyString_FromStringAndSize(qbuf.begin(), qbuf.length()); + } + else + { + py_ret = Py_None; + Py_INCREF(py_ret); + } + return py_ret; +} + +//------------------------------------------------------------------------ +/* +# +def ask_str(defval, hist, prompt): + """ + Asks for a long text + + @param hist: history id + @param defval: The default value + @param prompt: The prompt value + @return: None or the entered string + """ + pass +# +*/ +PyObject *py_ask_str(qstring *defval, int hist, const char *prompt) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + PyObject *py_ret; + if ( ask_str(defval, hist, "%s", prompt) ) + { + py_ret = PyString_FromStringAndSize(defval->begin(), defval->length()); } else { py_ret = Py_None; Py_INCREF(py_ret); } - delete [] buf; return py_ret; } @@ -356,30 +348,10 @@ def str2ea(addr): ea_t py_str2ea(const char *str, ea_t screenEA = BADADDR) { ea_t ea; - bool ok = str2ea(str, &ea, screenEA); + bool ok = str2ea(&ea, str, screenEA); return ok ? ea : BADADDR; } -//------------------------------------------------------------------------ -/* -# -def str2user(str): - """ - Insert C-style escape characters to string - - @return: new string with escape characters inserted - """ - pass -# -*/ -PyObject *py_str2user(const char *str) -{ - qstring qstr(str); - qstring retstr; - qstr2user(&retstr, qstr); - return PyString_FromString(retstr.c_str()); -} - //------------------------------------------------------------------------ /* # @@ -398,32 +370,6 @@ static bool py_process_ui_action(const char *name, int flags = 0) return process_ui_action(name, flags, NULL); } -//------------------------------------------------------------------------ -/* -# -def del_menu_item(menu_ctx): - """Deprecated. Use detach_menu_item()/unregister_action() instead.""" - pass -# -*/ -static bool py_del_menu_item(PyObject *py_ctx) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( !PyCObject_Check(py_ctx) ) - return false; - - py_add_del_menu_item_ctx *ctx = (py_add_del_menu_item_ctx *)PyCObject_AsVoidPtr(py_ctx); - - bool ok = del_menu_item(ctx->menupath.c_str()); - if ( ok ) - { - Py_DECREF(ctx->cb_data); - delete ctx; - } - - return ok; -} - //------------------------------------------------------------------------ /* # @@ -508,8 +454,8 @@ PyObject *py_add_hotkey(const char *hotkey, PyObject *pyfunc) idc_gvarname.c_str()); // Compile the IDC condition - char errbuf[MAXSTR]; - if ( !CompileLineEx(idc_func.c_str(), errbuf, sizeof(errbuf)) ) + qstring errbuf; + if ( !compile_idc_text(idc_func.c_str(), &errbuf) ) break; // Create new context @@ -573,9 +519,9 @@ static void idaapi py_ss_restore_callback(const char *err_msg, void *userdata) PyErr_Print(); } static PyObject *py_restore_database_snapshot( - const snapshot_t *ss, - PyObject *pyfunc_or_none, - PyObject *pytuple_or_none) + const snapshot_t *ss, + PyObject *pyfunc_or_none, + PyObject *pytuple_or_none) { PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -607,76 +553,6 @@ static PyObject *py_restore_database_snapshot( return PyBool_FromLong(b); } -//------------------------------------------------------------------------ -/* -# -def add_menu_item(menupath, name, hotkey, flags, callback, args): - """Deprecated. Use register_action()/attach_menu_item() instead.""" - pass -# -*/ -bool idaapi py_menu_item_callback(void *userdata); -static PyObject *py_add_menu_item( - const char *menupath, - const char *name, - const char *hotkey, - int flags, - PyObject *pyfunc, - PyObject *args) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - bool no_args; - - // No slash in the menu path? - const char *p = strrchr(menupath, '/'); - if ( p == NULL ) - Py_RETURN_NONE; - - if ( args == Py_None ) - { - no_args = true; - args = PyTuple_New(0); - if ( args == NULL ) - return NULL; - } - else if ( !PyTuple_Check(args) ) - { - PyErr_SetString(PyExc_TypeError, "args must be a tuple or None"); - return NULL; - } - else - { - no_args = false; - } - - // Form a tuple holding the function to be called and its arguments - PyObject *cb_data = Py_BuildValue("(OO)", pyfunc, args); - - // If we created an empty tuple, then we must free it - if ( no_args ) - Py_DECREF(args); - - // Add the menu item - bool b = add_menu_item(menupath, name, hotkey, flags, py_menu_item_callback, (void *)cb_data); - - if ( !b ) - { - Py_XDECREF(cb_data); - Py_RETURN_NONE; - } - // Create a context (for the delete_menu_item()) - py_add_del_menu_item_ctx *ctx = new py_add_del_menu_item_ctx(); - - // Form the complete menu path - ctx->menupath.append(menupath, p - menupath + 1); - ctx->menupath.append(name); - // Save callback data - ctx->cb_data = cb_data; - - // Return context to user - return PyCObject_FromVoidPtr(ctx, NULL); -} - //------------------------------------------------------------------------ /* # @@ -711,7 +587,7 @@ def execute_sync(callable, reqf): If the current thread not the main thread, then the call is queued and executed afterwards. - @param callable: A python callable object + @param callable: A python callable object, must return an integer value @param reqf: one of MFF_ flags @return: -1 or the return value of the callable """ @@ -895,7 +771,7 @@ def is_idaq(): //--------------------------------------------------------------------------- // UI hooks //--------------------------------------------------------------------------- -int idaapi UI_Callback(void *ud, int notification_code, va_list va); +ssize_t idaapi UI_Callback(void *ud, int notification_code, va_list va); /* # class UI_Hooks(object): @@ -914,19 +790,19 @@ class UI_Hooks(object): """ pass - def preprocess(self, name): + def preprocess_action(self, name): """ - IDA ui is about to handle a user command + IDA ui is about to handle a user action - @param name: ui command name + @param name: ui action name (these names can be looked up in ida[tg]ui.cfg) - @return: 0-ok, nonzero - a plugin has handled the command + @return: 0-ok, nonzero - a plugin has handled the action """ pass - def postprocess(self): + def postprocess_action(self): """ - An ida ui command has been handled + An ida ui action has been handled @return: Ignored """ @@ -974,23 +850,23 @@ class UI_Hooks(object): """ pass - def populating_tform_popup(self, form, popup): + def populating_widget_popup(self, widget, popup): """ - The UI is populating the TForm's popup menu. + The UI is populating the TWidget's popup menu. Now is a good time to call idaapi.attach_action_to_popup() - @param form: The form + @param widget: The widget @param popup: The popup menu. @return: Ignored """ pass - def finish_populating_tform_popup(self, form, popup): + def finish_populating_widget_popup(self, widget, popup): """ - The UI is about to be done populating the TForm's popup menu. + The UI is about to be done populating the TWidget's popup menu. Now is a good time to call idaapi.attach_action_to_popup() - @param form: The form + @param widget: The widget @param popup: The popup menu. @return: Ignored """ @@ -1019,29 +895,29 @@ public: bool hook() { - return hook_to_notification_point(HT_UI, UI_Callback, this); + return idapython_hook_to_notification_point(HT_UI, UI_Callback, this); } bool unhook() { - return unhook_from_notification_point(HT_UI, UI_Callback, this); + return idapython_unhook_from_notification_point(HT_UI, UI_Callback, this); } - static int handle_get_ea_hint_output(PyObject *o, ea_t, char *buf, size_t bufsize) + static int handle_get_ea_hint_output(PyObject *o, qstring *buf, ea_t) { int rc = 0; char *_buf; Py_ssize_t _len; if ( o != NULL && PyString_Check(o) && PyString_AsStringAndSize(o, &_buf, &_len) != -1 ) { - qstrncpy(buf, _buf, qmin(_len, bufsize)); + buf->append(_buf, _len); rc = 1; } Py_XDECREF(o); return rc; } - static int handle_hint_output(PyObject *o, int *important_lines, qstring *hint) + static int handle_hint_output(PyObject *o, qstring *hint, int *important_lines) { int rc = 0; if ( o != NULL && PyTuple_Check(o) && PyTuple_Size(o) == 2 ) @@ -1070,14 +946,14 @@ public: return rc; } - static int handle_hint_output(PyObject *o, ea_t, int, int *important_lines, qstring *hint) + static int handle_hint_output(PyObject *o, qstring *hint, ea_t, int, int *important_lines) { - return handle_hint_output(o, important_lines, hint); + return handle_hint_output(o, hint, important_lines); } - static int handle_hint_output(PyObject *o, TCustomControl *, place_t *, int *important_lines, qstring *hint) + static int handle_hint_output(PyObject *o, qstring *hint, TWidget *, place_t *, int *important_lines) { - return handle_hint_output(o, important_lines, hint); + return handle_hint_output(o, hint, important_lines); } // hookgenUI:methods @@ -1086,12 +962,10 @@ public: //------------------------------------------------------------------------- bool py_register_action(action_desc_t *desc) { + desc->flags |= ADF_OWN_HANDLER; bool ok = register_action(*desc); if ( ok ) { - // Success. We are managing this handler from now on, - // and must prevent it from being destroyed. - py_action_handlers[desc->name] = desc->handler; // Let's set this to NULL, so when the wrapping Python action_desc_t // instance is deleted, it doesn't try to delete the handler (See // kernwin.i's action_desc_t::~action_desc_t()). @@ -1100,20 +974,6 @@ bool py_register_action(action_desc_t *desc) return ok; } -//------------------------------------------------------------------------- -bool py_unregister_action(const char *name) -{ - bool ok = unregister_action(name); - if ( ok ) - { - py_action_handler_t *handler = - (py_action_handler_t *) py_action_handlers[name]; - delete handler; - py_action_handlers.erase(name); - } - return ok; -} - //------------------------------------------------------------------------- PyObject *py_get_registered_actions() { @@ -1124,15 +984,42 @@ PyObject *py_get_registered_actions() } //------------------------------------------------------------------------- +/* +# +def py_attach_dynamic_action_to_popup( + widget, + popup_handle, + desc, + popuppath = None, + flags = 0) + """ + Create & insert an action into the widget's popup menu + (::ui_attach_dynamic_action_to_popup). + Note: The action description in the 'desc' parameter is modified by + this call so you should prepare a new description for each call. + For example: + desc = idaapi.action_desc_t(None, 'Dynamic popup action', Handler()) + idaapi.attach_dynamic_action_to_popup(form, popup, desc) + + @param widget: target widget + @param popup_handle: target popup + @param desc: action description of type action_desc_t + @param popuppath: can be None + @param flags: a combination of SETMENU_ constants + @return: success + """ + pass +# +*/ bool py_attach_dynamic_action_to_popup( - TForm *form, + TWidget *widget, TPopupMenu *popup_handle, action_desc_t *desc, const char *popuppath = NULL, int flags = 0) { bool ok = attach_dynamic_action_to_popup( - form, popup_handle, *desc, popuppath, flags); + widget, popup_handle, *desc, popuppath, flags); if ( ok ) // Set the handler to null, so the desc won't destroy // it, as it noticed ownership was taken by IDA. @@ -1166,51 +1053,19 @@ DECLARE_TYPE_AS_MOVABLE(disasm_line_t); typedef qvector disasm_text_t; //------------------------------------------------------------------------- -void py_gen_disasm_text(ea_t ea1, ea_t ea2, disasm_text_t &text, bool truncate_lines) +void py_gen_disasm_text(disasm_text_t &text, ea_t ea1, ea_t ea2, bool truncate_lines) { text_t _text; - gen_disasm_text(ea1, ea2, _text, truncate_lines); + gen_disasm_text(_text, ea1, ea2, truncate_lines); for ( size_t i = 0, n = _text.size(); i < n; ++i ) { - const twinline_t &tl = _text[i]; + twinline_t &tl = _text[i]; disasm_line_t &dl = text.push_back(); dl.at = tl.at; // Transfer ownership - dl.line.inject(tl.line); // Transfer ownership + dl.line.swap(tl.line); // Transfer ownership } } -//------------------------------------------------------------------------- -// Although 'TCustomControl*' and 'TForm*' instances can both be used -// for attach_action_to_popup() at a binary-level, IDAPython SWIG bindings -// require that a 'TForm *' wrapper be passed to wrap_attach_action_to_popup(). -// Thus, we provide another attach_action_to_popup() version, that -// accepts a 'TCustomControl' as first argument. -// -// Since user-created GraphViewer are created like so: -// +-------- PluginForm ----------+ -// |+----- TCustomControl -------+| -// || || -// || || -// || || -// || || -// || || -// |+----------------------------+| -// +------------------------------+ -// The user cannot use GetTForm(), and use that to attach -// an action to, because that'll attach the action to the PluginForm -// instance. -// Instead, the user must use GetTCustomControl(), and call -// this function below with it. -bool attach_action_to_popup( - TCustomControl *tcc, - TPopupMenu *popup_handle, - const char *name, - const char *popuppath = NULL, - int flags = 0) -{ - return attach_action_to_popup((TForm*) tcc, popup_handle, name, popuppath, flags); -} - //------------------------------------------------------------------------- /* # @@ -1311,7 +1166,7 @@ uint32 py_call_nav_colorizer( //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- -int idaapi UI_Callback(void *ud, int notification_code, va_list va) +ssize_t idaapi UI_Callback(void *ud, int notification_code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; diff --git a/pywraps/py_kernwin.py b/pywraps/py_kernwin.py index 7fa5876..d426796 100644 --- a/pywraps/py_kernwin.py +++ b/pywraps/py_kernwin.py @@ -35,8 +35,8 @@ def load_custom_icon(file_name=None, data=None, format=None): return 0 # ---------------------------------------------------------------------- -def asklong(defval, format): - res, val = _ida_kernwin._asklong(defval, format) +def ask_long(defval, format): + res, val = _ida_kernwin._ask_long(defval, format) if res == 1: return val @@ -44,8 +44,8 @@ def asklong(defval, format): return None # ---------------------------------------------------------------------- -def askaddr(defval, format): - res, ea = _ida_kernwin._askaddr(defval, format) +def ask_addr(defval, format): + res, ea = _ida_kernwin._ask_addr(defval, format) if res == 1: return ea @@ -53,23 +53,431 @@ def askaddr(defval, format): return None # ---------------------------------------------------------------------- -def askseg(defval, format): - res, sel = _ida_kernwin._askseg(defval, format) +def ask_seg(defval, format): + res, sel = _ida_kernwin._ask_seg(defval, format) if res == 1: return sel else: return None +# ---------------------------------------------------------------------- +def ask_ident(defval, format): + return ask_str(defval, HIST_IDENT, format) + # ---------------------------------------------------------------------- class action_handler_t(object): def __init__(self): pass def activate(self, ctx): - return 0 + return 0 def update(self, ctx): pass +# ---------------------------------------------------------------------- +# bw-compat/deprecated. You shouldn't rely on this in new code +from ida_pro import str2user + # + +# +AST_DISABLE_FOR_FORM=AST_DISABLE_FOR_WIDGET +AST_ENABLE_FOR_FORM=AST_ENABLE_FOR_WIDGET +CB_CLOSE_IDB=CB_INVISIBLE +chtype_generic2=chtype_generic +chtype_segreg=chtype_srcp +close_tform=close_widget +find_tform=find_widget +get_current_tform=get_current_widget +get_highlighted_identifier=get_highlight +get_tform_title=get_widget_title +get_tform_type=get_widget_type +is_chooser_tform=is_chooser_widget +open_tform=display_widget +pyscv_get_tcustom_control=pyscv_get_widget +pyscv_get_tform=pyscv_get_widget +__read_selection70 = read_selection +def read_selection(*args): + if len(args) == 0: + # bw-compat + t0, t1, view = twinpos_t(), twinpos_t(), get_current_viewer() + sel = __read_selection70(view, t0, t1) + import ida_idaapi + a0, a1 = ida_idaapi.BADADDR, ida_idaapi.BADADDR + if sel: + a0, a1 = t0.place(view).toea(), t1.place(view).toea() + return sel, a0, a1 + else: + return __read_selection70(*args) + +readsel2=read_selection +switchto_tform=activate_widget +umsg=msg + +import ida_ida +def __wrap_uihooks_callback(name, do_call): + return ida_ida.__wrap_hooks_callback(UI_Hooks, name, name.replace("widget", "tform"), do_call) + + +__wrap_uihooks_callback("widget_visible", lambda cb, *args: cb(args[0], args[0])) +__wrap_uihooks_callback("widget_invisible", lambda cb, *args: cb(args[0], args[0])) +__wrap_uihooks_callback("populating_widget_popup", lambda cb, *args: cb(*args)) +__wrap_uihooks_callback("finish_populating_widget_popup", lambda cb, *args: cb(*args)) +__wrap_uihooks_callback("current_widget_changed", lambda cb, *args: cb(*args)) + +AskUsingForm=ask_form +HIST_ADDR=0 +HIST_NUM=0 +KERNEL_VERSION_MAGIC1=0 +KERNEL_VERSION_MAGIC2=0 +OpenForm=open_form +_askaddr=_ida_kernwin._ask_addr +_asklong=_ida_kernwin._ask_long +_askseg=_ida_kernwin._ask_seg +askaddr=ask_addr +askbuttons_c=ask_buttons +askfile_c=ask_file +@bc695redef +def askfile2_c(forsave, defdir, filters, fmt): + if filters: + fmt = "FILTER %s\n%s" % (filters, fmt) + return ask_file(forsave, defdir, fmt) +askident=ask_ident +asklong=ask_long +@bc695redef +def askqstr(defval, fmt): + return ask_str(defval, 0, fmt) +askseg=ask_seg +@bc695redef +def askstr(hist, defval, fmt): + return ask_str(defval, hist, fmt) +asktext=ask_text +askyn_c=ask_yn +choose2_activate=choose_activate +choose2_close=choose_close +choose2_create=choose_create +choose2_find=choose_find +choose2_get_embedded=choose_get_embedded +choose2_get_embedded_selection=choose_get_embedded_selection +choose2_refresh=choose_refresh +clearBreak=clr_cancelled +py_get_AskUsingForm=py_get_ask_form +py_get_OpenForm=py_get_open_form +setBreak=set_cancelled +wasBreak=user_cancelled +refresh_lists=refresh_choosers + +#-------------------------------------------------------------------------- +class BC695_control_cmd: + def __init__(self, cmd_id, caption, flags, menu_index, icon, emb, shortcut, is_chooser): + self.cmd_id = cmd_id + self.caption = caption + self.flags = flags + self.menu_index = menu_index + self.icon = icon + self.emb = emb + self.shortcut = shortcut + self.is_chooser = is_chooser + + @staticmethod + def add_to_control(control, caption, flags, menu_index, icon, emb, shortcut, is_chooser): + if getattr(control, "commands", None) is None: + setattr(control, "commands", []) + found = filter(lambda x: x.caption == caption, control.commands) + if len(found) == 1: + cmd_id = found[0].cmd_id + else: + cmd_id = len(control.commands) + cmd = BC695_control_cmd(cmd_id, caption, flags, menu_index, icon, emb, shortcut, is_chooser) + control.commands.append(cmd) + return cmd_id + + @staticmethod + def populate_popup(control, widget, popup): + cmds = getattr(control, "commands", []) + for cmd in cmds: + if (cmd.flags & CHOOSER_POPUP_MENU) != 0: + desc = action_desc_t(None, cmd.caption, BC695_control_cmd_ah_t(control, cmd), cmd.shortcut, None, cmd.icon) + attach_dynamic_action_to_popup(widget, popup, desc) + +class BC695_control_cmd_ah_t(action_handler_t): + def __init__(self, control, cmd): + action_handler_t.__init__(self) + self.control = control + self.cmd = cmd + + def activate(self, ctx): + if self.cmd.is_chooser: + idx = ctx.chooser_selection[0] + self.control.OnCommand(idx, self.cmd.cmd_id) + else: + self.control.OnCommand(self.cmd.cmd_id) + + def update(self, ctx): + return AST_ENABLE_ALWAYS + + +class Choose2(object): + """v.6.95 compatible chooser wrapper class.""" + + CH_MODAL = 0x01 + CH_MULTI = 0x04 + CH_MULTI_EDIT = 0x08 + """ + The OnEditLine() callback will be called for all + selected items using the START_SEL/END_SEL + protocol. + This bit implies #CH_MULTI. + """ + CH_NOBTNS = 0x10 + CH_ATTRS = 0x20 + CH_NOIDB = 0x40 + CH_BUILTIN_SHIFT = 19 + CH_BUILTIN_MASK = 0x1F << CH_BUILTIN_SHIFT + + # column flags (are specified in the widths array) + CHCOL_PLAIN = 0x00000000 + CHCOL_PATH = 0x00010000 + CHCOL_HEX = 0x00020000 + CHCOL_DEC = 0x00030000 + CHCOL_FORMAT = 0x00070000 + + # special values of the chooser index + NO_SELECTION = -1 + """there is no selected item""" + START_SEL = -2 + """before calling the first selected item""" + END_SEL = -3 + """after calling the last selected item""" + + + # the v.7.0 chooser object implementing the v.6.95 chooser + class ChooseWrapper(Choose): + + def __init__(self, v695_chooser): + self.link = v695_chooser + # check what non-base callbacks we have + forbidden_cb = 0 + for cb in [("OnInsertLine", Choose.CHOOSE_HAVE_INS ), + ("OnDeleteLine", Choose.CHOOSE_HAVE_DEL ), + ("OnEditLine", Choose.CHOOSE_HAVE_EDIT ), + ("OnSelectLine", Choose.CHOOSE_HAVE_ENTER ), + ("OnRefresh", Choose.CHOOSE_HAVE_REFRESH), + ("OnSelectionChange", Choose.CHOOSE_HAVE_SELECT)]: + if not hasattr(self.link, cb[0]) or \ + not callable(getattr(self.link, cb[0])): + forbidden_cb |= cb[1] + Choose.__init__( + self, self.link.title, self.link.cols, + forbidden_cb = forbidden_cb) + + # redirect base callbacks to the v.6.95 chooser + def __getattr__(self, attr): + if attr in ["OnGetSize", + "OnGetLine", + "OnGetIcon", + "OnGetLineAttr", + "OnClose"]: + return getattr(self.link, attr) + return getattr(self.link, attr) + + def Show(self, modal = False): + # set `flags` and `deflt` + self.flags = self.link.flags + if self.link.deflt == -1: + self.deflt = 0 + else: + self.deflt = self.link.deflt - 1 + self.flags |= Choose.CH_FORCE_DEFAULT + if (self.flags & Choose.CH_MULTI) != 0: + self.deflt = [self.deflt] + # copy simple attributes from v.6.95 + for attr in ["title", "cols", "popup_names", "icon", + "x1", "y1", "x2", "y2", + "embedded", "width", "height"]: + if hasattr(self.link, attr): + setattr(self, attr, getattr(self.link, attr)) + else: + delattr(self, attr) + return Choose.Show(self, modal) + + def OnInsertLine(self, n): + # assert: hasattr(self.link, "OnInsertLine") + self.link.OnInsertLine() + # we preserve the selection + return (Choose.ALL_CHANGED, n) + if (self.link.flags & Choose2.CH_MULTI) == 0: + return (Choose.ALL_CHANGED, n) + else: + return [Choose.ALL_CHANGED] + n + + def OnDeleteLine(self, n): + # assert: hasattr(self.link, "OnDeleteLine") + res = None + if (self.link.flags & Choose2.CH_MULTI) == 0: + res = self.link.OnDeleteLine(n) + else: + # assert: n is iterable and n + # call the callback multiple times + self.link.OnDeleteLine(Choose2.START_SEL) + res = None + for idx in n: + new_idx = self.link.OnDeleteLine(idx) + if res == None: + res = new_idx + self.link.OnDeleteLine(Choose2.END_SEL) + return [Choose.ALL_CHANGED] + self.adjust_last_item(res) + + def OnEditLine(self, n): + # assert: hasattr(self.link, "OnEditLine") + if (self.link.flags & Choose2.CH_MULTI) == 0: + self.link.OnEditLine(n) + return (Choose.ALL_CHANGED, n) # preserve the selection + # assert: n is iterable and n + if (self.link.flags & Choose2.CH_MULTI_EDIT) == 0: + self.link.OnEditLine(n[0]) + return [Choose.ALL_CHANGED] + n # preserve the selection + # call the callback multiple times + self.link.OnEditLine(Choose2.START_SEL) + for idx in n: + self.link.OnEditLine(idx) + self.link.OnEditLine(Choose2.END_SEL) + return [Choose.ALL_CHANGED] + n # preserve the selection + + def OnSelectLine(self, n): + # assert: hasattr(self.link, "OnSelectLine") + if (self.link.flags & Choose2.CH_MULTI) == 0: + self.link.OnSelectLine(n) + return (Choose.ALL_CHANGED, n) + # assert: n is iterable and n + idx = n.pop(0) + self.link.OnSelectLine(idx) + # preserve all but the first item + return [Choose.ALL_CHANGED] + n + + def OnRefresh(self, n): + # assert: hasattr(self.link, "OnRefresh") + if (self.link.flags & Choose2.CH_MULTI) != 0: + # ignore all but the first item + n = n[0] if n else Choose.NO_SELECTION + res = self.link.OnRefresh(n) + return (Choose.ALL_CHANGED, res) + + def OnSelectionChange(self, n): + # assert: hasattr(self.link, "OnSelectionChange") + if (self.link.flags & Choose2.CH_MULTI) == 0: + n = [n] if n != Choose.NO_SELECTION else [] + self.link.OnSelectionChange(n) + + def OnPopup(self, widget, popup_handle): + BC695_control_cmd.populate_popup( + self.link, + widget, + popup_handle) + + + 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): + """ + Constructs a chooser window. + @param title: The chooser title + @param cols: a list of colums; each list item is a list of two items + example: [ ["Address", 10 | Choose2.CHCOL_HEX], + ["Name", 30 | Choose2.CHCOL_PLAIN] ] + @param flags: One of CH_XXXX constants + @param deflt: Default starting item (1-based). + 0 means that no item is selected, + -1 means that the first item selected for a new window and + that the selection is not updated for an existing window + @param popup_names: list of new captions to replace this list + ["Insert", "Delete", "Edit", "Refresh"] + @param icon: Icon index (the icon should exist in ida resources or + an index to a custom loaded icon) + @param x1, y1, x2, y2: The default location (for txt-version) + @param embedded: Create as embedded chooser + @param width: Embedded chooser width + @param height: Embedded chooser height + """ + # remember attributes + self.title = title + self.flags = flags + self.cols = cols + self.deflt = deflt + self.popup_names = popup_names + self.icon = icon + self.x1 = x1 + self.y1 = y1 + self.x2 = x2 + self.y2 = y2 + self.embedded = embedded + self.width = width + self.height = height + # construct the v.7.0 chooser object + self.chobj = Choose2.ChooseWrapper(self) + + + # redirect methods to the v.7.0 chooser + def __getattr__(self, attr): + if attr not in ["GetEmbSelection", + "Activate", + "Refresh", + "Close", + "GetWidget"]: + raise AttributeError(attr) + return getattr(self.chobj, attr) + + def Embedded(self): + """ + Creates an embedded chooser (as opposed to Show()) + @return: Returns 1 on success + """ + return 1 if self.chobj.Embedded() == 0 else 0 + + + def Show(self, modal=False): + """ + Activates or creates a chooser window + @param modal: Display as modal dialog + @return: For modal choosers it will return the selected item index (0-based) + or -1 in the case of error, + For non-modal choosers it will return 0 + or -1 if the chooser was already open and is active now + """ + ret = self.chobj.Show(modal) + return -1 if ret < 0 else ret + + + def AddCommand(self, + caption, + flags = _ida_kernwin.CHOOSER_POPUP_MENU, + menu_index = -1, + icon = -1, + emb=None, + shortcut=None): + # 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 BC695_control_cmd.add_to_control( + self, caption, flags, menu_index, icon, emb, None, + is_chooser=True) + + # callbacks + # def OnGetSize(self): + # def OnGetLine(self, n): + # def OnGetIcon(self, n): + # def OnGetLineAttr(self, n): + # def OnInsertLine(self): + # def OnDeleteLine(self, n): + # def OnEditLine(self, n): + # def OnSelectLine(self, n): + # def OnRefresh(self, n): + # def OnSelectionChange(self, sel_list): + # def OnClose(self): + # def OnCommand(self, n, cmd_id): +# + diff --git a/pywraps/py_kernwin_askusingform.hpp b/pywraps/py_kernwin_askform.hpp similarity index 81% rename from pywraps/py_kernwin_askusingform.hpp rename to pywraps/py_kernwin_askform.hpp index 76262e1..6bbacbd 100644 --- a/pywraps/py_kernwin_askusingform.hpp +++ b/pywraps/py_kernwin_askform.hpp @@ -1,11 +1,11 @@ -#ifndef __PY_KERNWIN_ASKUSINGFORM__ -#define __PY_KERNWIN_ASKUSINGFORM__ +#ifndef __PY_KERNWIN_ASKFORM__ +#define __PY_KERNWIN_ASKFORM__ -// -// +// +// //--------------------------------------------------------------------------- -// +// #define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa; //--------------------------------------------------------------------------- @@ -49,8 +49,8 @@ static bool textctrl_info_t_set_flags(PyObject *self, unsigned int flags) //------------------------------------------------------------------------- static unsigned int textctrl_info_t_get_flags( - PyObject *self, - unsigned int flags) + PyObject *self, + unsigned int flags) { textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(self); return ti == NULL ? 0 : ti->flags; @@ -58,8 +58,8 @@ static unsigned int textctrl_info_t_get_flags( //------------------------------------------------------------------------- static bool textctrl_info_t_set_tabsize( - PyObject *self, - unsigned int tabsize) + PyObject *self, + unsigned int tabsize) { textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(self); if ( ti == NULL ) @@ -70,8 +70,8 @@ static bool textctrl_info_t_set_tabsize( //------------------------------------------------------------------------- static unsigned int textctrl_info_t_get_tabsize( - PyObject *self, - unsigned int tabsize) + PyObject *self, + unsigned int tabsize) { textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(self); return ti == NULL ? 0 : ti->tabsize; @@ -93,12 +93,12 @@ static bool formchgcbfa_show_field(size_t p_fa, int fid, bool show) //--------------------------------------------------------------------------- static bool formchgcbfa_move_field( - size_t p_fa, - int fid, - int x, - int y, - int w, - int h) + size_t p_fa, + int fid, + int x, + int y, + int w, + int h) { DECLARE_FORM_ACTIONS; return fa->move_field(fid, x, y, w, h); @@ -134,10 +134,10 @@ static void formchgcbfa_close(size_t p_fa, int close_normally) //--------------------------------------------------------------------------- static PyObject *formchgcbfa_get_field_value( - size_t p_fa, - int fid, - int ft, - size_t sz) + size_t p_fa, + int fid, + int ft, + size_t sz) { DECLARE_FORM_ACTIONS; PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -190,7 +190,7 @@ static PyObject *formchgcbfa_get_field_value( case 1: { char val[MAXSTR]; - if ( fa->get_ascii_value(fid, val, sizeof(val)) ) + if ( fa->get_string_value(fid, val, sizeof(val)) ) return PyString_FromString(val); break; } @@ -199,20 +199,16 @@ static PyObject *formchgcbfa_get_field_value( { qstring val; val.resize(sz + 1); - if ( fa->get_ascii_value(fid, val.begin(), val.size()) ) + if ( fa->get_string_value(fid, val.begin(), val.size()) ) return PyString_FromString(val.begin()); break; } case 5: { - intvec_t intvec; - // Returned as 1-base - if ( fa->get_chooser_value(fid, &intvec) ) + sizevec_t selection; + if ( fa->get_chooser_value(fid, &selection) ) { - // Make 0-based - for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it ) - (*it)--; - ref_t l(PyW_IntVecToPyList(intvec)); + ref_t l(PyW_SizeVecToPyList(selection)); l.incref(); return l.o; } @@ -233,7 +229,7 @@ static PyObject *formchgcbfa_get_field_value( case 'S': // sel_t { if ( fa->get_segment_value(fid, &u.sel) ) - return Py_BuildValue(PY_FMT64, u.sel); + return Py_BuildValue(PY_BV_SEL, bvsel_t(u.sel)); break; } // sval_t @@ -244,7 +240,7 @@ static PyObject *formchgcbfa_get_field_value( case 'H': { if ( fa->get_signed_value(fid, &u.sval) ) - return Py_BuildValue(PY_SFMT64, u.sval); + return Py_BuildValue(PY_BV_SVAL, bvsval_t(u.sval)); break; } case 'L': // uint64 @@ -258,13 +254,13 @@ static PyObject *formchgcbfa_get_field_value( case 'M': // uval_t { if ( fa->get_unsigned_value(fid, &u.uval) ) - return Py_BuildValue(PY_FMT64, u.uval); + return Py_BuildValue(PY_BV_UVAL, bvuval_t(u.uval)); break; } case '$': // ea_t { if ( fa->get_ea_value(fid, &u.uval) ) - return Py_BuildValue(PY_FMT64, u.uval); + return Py_BuildValue(PY_BV_UVAL, bvuval_t(u.uval)); break; } } @@ -276,10 +272,10 @@ static PyObject *formchgcbfa_get_field_value( //--------------------------------------------------------------------------- static bool formchgcbfa_set_field_value( - size_t p_fa, - int fid, - int ft, - PyObject *py_val) + size_t p_fa, + int fid, + int ft, + PyObject *py_val) { DECLARE_FORM_ACTIONS; PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -324,20 +320,14 @@ static bool formchgcbfa_set_field_value( // strings case 3: case 1: - return fa->set_ascii_value(fid, PyString_AsString(py_val)); + return fa->set_string_value(fid, PyString_AsString(py_val)); // intvec_t case 5: { - intvec_t intvec; - // Passed as 0-based - if ( !PyW_PyListToIntVec(py_val, intvec) ) + sizevec_t selection; + if ( !PyW_PyListToSizeVec(py_val, selection) ) break; - - // Make 1-based - for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it ) - (*it)++; - - return fa->set_chooser_value(fid, &intvec); + return fa->set_chooser_value(fid, &selection); } // Numeric case 6: @@ -352,20 +342,20 @@ static bool formchgcbfa_set_field_value( #undef DECLARE_FORM_ACTIONS -static size_t py_get_AskUsingForm() +static size_t py_get_ask_form() { // Return a pointer to the function. Note that, although - // the C implementation of AskUsingForm_cv will do some + // the C implementation of vask_form will do some // Qt/txt widgets generation, the Python's ctypes - // implementation through which the call well go will first + // implementation through which the call will go will first // unblock other threads. No need to do it ourselves. - return (size_t)AskUsingForm_c; + return (size_t)ask_form; } -static size_t py_get_OpenForm() +static size_t py_get_open_form() { // See comments above. - return (size_t)OpenForm_c; + return (size_t)open_form; } static void py_register_compiled_form(PyObject *py_form) @@ -377,8 +367,8 @@ static void py_unregister_compiled_form(PyObject *py_form) { PyW_unregister_compiled_form(py_form); } -// +// -#endif // __PY_KERNWIN_ASKUSINGFORM__ +#endif // __PY_KERNWIN_ASKFORM__ diff --git a/pywraps/py_kernwin_askusingform.py b/pywraps/py_kernwin_askform.py old mode 100755 new mode 100644 similarity index 92% rename from pywraps/py_kernwin_askusingform.py rename to pywraps/py_kernwin_askform.py index 7f935da..3f1eb89 --- a/pywraps/py_kernwin_askusingform.py +++ b/pywraps/py_kernwin_askform.py @@ -1,5 +1,5 @@ # -------------------------------------------------------------------------- -# +# import ida_idaapi, _ida_idaapi import ida_pro @@ -11,23 +11,23 @@ import ida_pro #HELP / ENDHELP try: import types - from ctypes import * + import ctypes # On Windows, we use stdcall # Callback for buttons - # typedef void (idaapi *formcb_t)(TView *fields[], int code); + # typedef int (idaapi *buttoncb_t)(int button_code, form_actions_t &fa); - _FORMCB_T = WINFUNCTYPE(None, c_void_p, c_int) + _BUTTONCB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_void_p) # Callback for form change # typedef int (idaapi *formchgcb_t)(int field_id, form_actions_t &fa); - _FORMCHGCB_T = WINFUNCTYPE(c_int, c_int, c_void_p) + _FORMCHGCB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_void_p) except: try: - _FORMCB_T = CFUNCTYPE(None, c_void_p, c_int) - _FORMCHGCB_T = CFUNCTYPE(c_int, c_int, c_void_p) + _BUTTONCB_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_void_p) + _FORMCHGCB_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_void_p) except: - _FORMCHGCB_T = _FORMCB_T = None + _BUTTONCB_T = _FORMCHGCB_T = None # ----------------------------------------------------------------------- @@ -147,7 +147,7 @@ class Form(object): FT_FORMCHG = '%/' """Form change callback - formchgcb_t""" FT_ECHOOSER = 'E' - """Embedded chooser - idaapi.Choose2""" + """Embedded chooser - idaapi.Choose""" FT_MULTI_LINE_TEXT = 't' """Multi text control - textctrl_info_t""" FT_DROPDOWN_LIST = 'b' @@ -166,19 +166,19 @@ class Form(object): Factory method returning a ctype class corresponding to the field type string """ if tp in (Form.FT_SEG, Form.FT_HEX, Form.FT_RAWHEX, Form.FT_ADDR): - return c_ulonglong if i64 else c_ulong + return ctypes.c_ulonglong if i64 else ctypes.c_ulong elif tp in (Form.FT_SHEX, Form.FT_DEC, Form.FT_OCT, Form.FT_BIN, Form.FT_CHAR): - return c_longlong if i64 else c_long + return ctypes.c_longlong if i64 else ctypes.c_long elif tp == Form.FT_UINT64: - return c_ulonglong + return ctypes.c_ulonglong elif tp == Form.FT_INT64: - return c_longlong + return ctypes.c_longlong elif tp == Form.FT_COLOR: - return c_ulong + return ctypes.c_ulong elif tp == Form._FT_USHORT: - return c_ushort + return ctypes.c_ushort elif tp in (Form.FT_FORMCHG, Form.FT_ECHOOSER): - return c_void_p + return ctypes.c_void_p else: return None @@ -197,7 +197,7 @@ class Form(object): if cls is None: raise TypeError("Invalid numeric field type: %s" % tp) # Get a pointer type to the ctype type - self.arg = pointer(cls(value)) + self.arg = ctypes.pointer(cls(value)) def __set_value(self, v): self.arg.contents.value = v @@ -213,9 +213,9 @@ class Form(object): raise SyntaxError("The string size must be passed") if value is None: - self.arg = create_string_buffer(size) + self.arg = ctypes.create_string_buffer(size) else: - self.arg = create_string_buffer(value, size) + self.arg = ctypes.create_string_buffer(value, size) self.size = size def __set_value(self, v): @@ -240,6 +240,7 @@ class Form(object): self.form = None """Reference to the parent form. It is filled by Form.Add()""" + self.form_hasattr = False def get_tag(self): """ @@ -251,7 +252,7 @@ class Form(object): def get_arg(self): """ Control returns the parameter to be pushed on the stack - (Of AskUsingForm()) + (Of ask_form()) """ return self.arg @@ -301,7 +302,7 @@ class Form(object): tp = Form.FT_ASCII Form.LabelControl.__init__(self, tp) self.size = sz - self.arg = create_string_buffer(value, sz) + self.arg = ctypes.create_string_buffer(value, sz) class NumericLabel(LabelControl, NumericArgument): @@ -597,7 +598,16 @@ class Form(object): code, swidth, hlp) - self.arg = _FORMCB_T(lambda view, code, h=handler: h(code)) + self.handler = handler + self.arg = _BUTTONCB_T(self.helper_cb) + + def helper_cb(self, button_code, p_fa): + # Remember the pointer to the forms_action in the parent form + self.form.p_fa = p_fa + + # Call user's handler + r = self.handler(button_code) + return 0 if r is None else r def is_input_field(self): return False @@ -667,23 +677,23 @@ class Form(object): """ # !! Make sure a chooser instance is passed !! - if chooser is None or not isinstance(chooser, Choose2): + if chooser is None or not isinstance(chooser, Choose): raise ValueError("Invalid chooser passed.") - # Create an embedded chooser structure from the Choose2 instance - if chooser.Embedded() != 1: + # Create an embedded chooser structure from the Choose instance + if chooser.Embedded() != 0: raise ValueError("Failed to create embedded chooser instance.") # Construct input control Form.InputControl.__init__(self, Form.FT_ECHOOSER, "", swidth) # Get a pointer to the chooser_info_t and the selection vector - # (These two parameters are the needed arguments for the AskUsingForm()) - emb, sel = _ida_kernwin.choose2_get_embedded(chooser) + # (These two parameters are the needed arguments for the ask_form()) + emb, sel = _ida_kernwin.choose_get_embedded(chooser) # Get a pointer to a c_void_p constructed from an address - p_embedded = pointer(c_void_p.from_address(emb)) - p_sel = pointer(c_void_p.from_address(sel)) + p_embedded = ctypes.pointer(ctypes.c_void_p.from_address(emb)) + p_sel = ctypes.pointer(ctypes.c_void_p.from_address(sel)) # - Create the embedded chooser info on control creation # - Do not free the embeded chooser because after we get the args @@ -702,25 +712,6 @@ class Form(object): """Returns the embedded chooser instance""" - def AddCommand(self, - caption, - flags = _ida_kernwin.CHOOSER_POPUP_MENU, - menu_index = -1, - icon = -1): - """ - Adds a new embedded chooser command - Save the returned value and later use it in the OnCommand handler - - @return: Returns a negative value on failure or the command index - """ - if not self.form.title: - raise ValueError("Form title is not set!") - - # Encode all information for the AddCommand() in the 'caption' parameter - caption = "%s:%d:%s" % (self.form.title, self.id, caption) - return self.chooser.AddCommand(caption, flags=flags, menu_index=menu_index, icon=icon, emb=2002) - - def free(self): """ Frees the embedded chooser data @@ -764,8 +755,8 @@ class Form(object): if readonly: # Create a C integer and remember it - self.__selval = c_int(selval) - val_addr = addressof(self.__selval) + self.__selval = ctypes.c_int(selval) + val_addr = ctypes.addressof(self.__selval) else: # Create an strvec with one qstring self.__selval = ida_pro._qstrvec_t([selval]) @@ -778,8 +769,8 @@ class Form(object): # or # #2: a qstring to hold the dropdown text control value self.arg = ( - pointer(c_void_p.from_address(self.clink_ptr)), - pointer(c_void_p.from_address(val_addr)) + ctypes.pointer(ctypes.c_void_p.from_address(self.clink_ptr)), + ctypes.pointer(ctypes.c_void_p.from_address(val_addr)) ) @@ -832,7 +823,7 @@ class Form(object): textctrl_info_t.__init__(self, text=text, flags=flags, tabsize=tabsize) # Get the argument as a pointer from the embedded ti - self.arg = pointer(c_void_p.from_address(self.clink_ptr)) + self.arg = ctypes.pointer(ctypes.c_void_p.from_address(self.clink_ptr)) def free(self): @@ -845,7 +836,7 @@ class Form(object): def __init__(self, form, controls): """ Contruct a Form class. - This class wraps around AskUsingForm() or OpenForm() and provides an easier / alternative syntax for describing forms. + This class wraps around ask_form() or open_form() and provides an easier / alternative syntax for describing forms. The form control names are wrapped inside the opening and closing curly braces and the control themselves are defined and instantiated via various form controls (subclasses of Form). @@ -867,7 +858,7 @@ class Form(object): self.openform_flags = 0 """ - If non-modal, these flags will be passed to OpenForm. + If non-modal, these flags will be passed to open_form. This is an OR'ed combination of the PluginForm.FORM_* values. """ @@ -879,8 +870,11 @@ class Form(object): """ # Free all the controls - for ctrl in self.__controls.values(): - ctrl.free() + for name, ctrl in self.__controls.items(): + if ctrl.parent_hasattr: + delattr(self, name) + ctrl.parent_hasattr = False + ctrl.free() # Reset the controls # (Note that we are not removing the form control attributes, no need) @@ -919,6 +913,7 @@ class Form(object): # Create attribute with control name if mkattr: setattr(self, name, ctrl) + ctrl.parent_hasattr = True # Remember the control self.__controls[name] = ctrl @@ -994,7 +989,7 @@ class Form(object): """ Low level function. Compiles (parses the form syntax and adds the control) the form string and - returns the argument list to be passed the argument list to AskUsingForm(). + returns the argument list to be passed the argument list to ask_form(). The form controls are wrapped inside curly braces: {ControlName}. @@ -1003,7 +998,7 @@ class Form(object): (note that, technically, the index is not the same as the ID; that's because STARTITEM uses raw, 0-based indexes rather than control IDs to determine the focused widget.) - @param form: Compiles the form and returns the arguments needed to be passed to AskUsingForm() + @param form: Compiles the form and returns the arguments needed to be passed to ask_form() """ # First argument is the form string args = [None] @@ -1184,7 +1179,7 @@ class Form(object): if not self.modal: raise SyntaxError("Form is not modal. Open() should be instead") - return AskUsingForm(*self.__args) + return ask_form(*self.__args) def Open(self): @@ -1195,7 +1190,7 @@ class Form(object): if self.modal: raise SyntaxError("Form is modal. Execute() should be instead") - OpenForm(*self.__args) + open_form(*self.__args) def EnableField(self, ctrl, enable): @@ -1334,38 +1329,38 @@ class Form(object): raise NotImplementedError, "Not yet implemented" # -------------------------------------------------------------------------- -# Instantiate AskUsingForm function pointer +# Instantiate ask_form function pointer try: import ctypes # Setup the numeric argument size 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()) + ask_form__ = ctypes.CFUNCTYPE(ctypes.c_long)(_ida_kernwin.py_get_ask_form()) + open_form__ = ctypes.CFUNCTYPE(ctypes.c_long)(_ida_kernwin.py_get_open_form()) except: - def AskUsingForm__(*args): - warning("AskUsingForm() needs ctypes library in order to work") + def ask_form__(*args): + warning("ask_form() needs ctypes library in order to work") return 0 - def OpenForm__(*args): - warning("OpenForm() needs ctypes library in order to work") + def open_form__(*args): + warning("open_form() needs ctypes library in order to work") -def AskUsingForm(*args): +def ask_form(*args): """ - Calls AskUsingForm() + Calls ask_form() @param: Compiled Arguments obtain through the Form.Compile() function @return: 1 = ok, 0 = cancel """ old = _ida_idaapi.set_script_timeout(0) - r = AskUsingForm__(*args) + r = ask_form__(*args) _ida_idaapi.set_script_timeout(old) return r -def OpenForm(*args): +def open_form(*args): """ - Calls OpenForm() + Calls open_form() @param: Compiled Arguments obtain through the Form.Compile() function """ old = _ida_idaapi.set_script_timeout(0) - r = OpenForm__(*args) + r = open_form__(*args) _ida_idaapi.set_script_timeout(old) -# +# diff --git a/pywraps/py_kernwin_choose.hpp b/pywraps/py_kernwin_choose.hpp index bbce7a0..d4416ec 100644 --- a/pywraps/py_kernwin_choose.hpp +++ b/pywraps/py_kernwin_choose.hpp @@ -1,78 +1,858 @@ #ifndef __PY_KERNWIN_CHOOSE__ #define __PY_KERNWIN_CHOOSE__ -//--------------------------------------------------------------------------- -// -//--------------------------------------------------------------------------- -uint32 idaapi choose_sizer(void *self) +// + +//------------------------------------------------------------------------ +// Helper functions +class py_choose_t; +typedef std::map py2c_choose_map_t; +static py2c_choose_map_t choosers; + +py_choose_t *choose_find_instance(PyObject *self) { - PYW_GIL_GET; - newref_t pyres(PyObject_CallMethod((PyObject *)self, "sizer", "")); - return PyInt_AsLong(pyres.o); + py2c_choose_map_t::iterator it = choosers.find(self); + return it == choosers.end() ? NULL : it->second; } -//--------------------------------------------------------------------------- -char *idaapi choose_getl(void *self, uint32 n, char *buf) +void choose_add_instance(PyObject *self, py_choose_t *pych) { - PYW_GIL_GET; - newref_t pyres( - PyObject_CallMethod( - (PyObject *)self, - "getl", - "l", - n)); - - const char *res; - if ( pyres == NULL || (res = PyString_AsString(pyres.o)) == NULL ) - qstrncpy(buf, "", MAXSTR); - else - qstrncpy(buf, res, MAXSTR); - return buf; + choosers[self] = pych; } -//--------------------------------------------------------------------------- -void idaapi choose_enter(void *self, uint32 n) +void choose_del_instance(PyObject *self) { - PYW_GIL_GET; - newref_t res(PyObject_CallMethod((PyObject *)self, "enter", "l", n)); + py2c_choose_map_t::iterator it = choosers.find(self); + if ( it != choosers.end() ) + choosers.erase(it); } -//--------------------------------------------------------------------------- -uint32 choose_choose( - PyObject *self, - int flags, - int x0,int y0, - int x1,int y1, - int width, - int deflt, - int icon) +// set `prm` to the integer value of the `name` attribute +template +static void py_get_int(PyObject *self, T *prm, const char *name) +{ + ref_t attr(PyW_TryGetAttrString(self, name)); + if ( attr != NULL && attr.o != Py_None ) + *prm = T(PyInt_AsLong(attr.o)); +} + +//------------------------------------------------------------------------ +// Python's chooser class +class py_choose_t +{ +public: + // Python object link + PyObject *self; + + // the chooser object will be created in the create() method + chooser_base_t *chobj; + + enum + { + CHOOSE_HAVE_INIT = 0x0001, + CHOOSE_HAVE_GETICON = 0x0002, + CHOOSE_HAVE_GETATTR = 0x0004, + CHOOSE_HAVE_INS = 0x0008, + CHOOSE_HAVE_DEL = 0x0010, + CHOOSE_HAVE_EDIT = 0x0020, + CHOOSE_HAVE_ENTER = 0x0040, + CHOOSE_HAVE_REFRESH = 0x0080, + CHOOSE_HAVE_SELECT = 0x0100, + CHOOSE_HAVE_ONCLOSE = 0x0200, + CHOOSE_IS_EMBEDDED = 0x0400, + }; + + // Callback flags (to tell which callback exists and which not) + // One of CHOOSE_xxxx + uint32 cb_flags; + + sizevec_t embedded_sel; + + // Chooser title + qstring title; + + // Column widths + intvec_t widths; + + // Chooser headers + qstrvec_t header_strings; + qvector header; + +public: + py_choose_t(PyObject *self_) : self(self_), chobj(NULL), cb_flags(0) + { + PYW_GIL_GET; + choose_add_instance(self, this); + + // Increase object reference + Py_INCREF(self); + } + + // if the chooser object was created it will delete linked Python's + // chooser. + // if it was not created (e.g. because of the lack of a mandatory + // callback) it will be deleted in choose_close(). + ~py_choose_t() + { + PYW_GIL_GET; + // Remove from list + choose_del_instance(self); + + Py_XDECREF(self); + } + + // common callbacks + bool idaapi init() + { + if ( (cb_flags & CHOOSE_HAVE_INIT) == 0 ) + return chobj->chooser_base_t::init(); + PYW_GIL_GET; + pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_INIT, NULL)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chobj->chooser_base_t::init(); + return bool(PyInt_AsLong(pyres.result.o)); + } + + size_t idaapi get_count() const + { + PYW_GIL_GET; + pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_GET_SIZE, NULL)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return 0; + + return size_t(PyInt_AsLong(pyres.result.o)); + } + + void idaapi get_row( + qstrvec_t *cols, + int *icon_, + chooser_item_attrs_t *attrs, + size_t n) const + { + PYW_GIL_GET; + + // Call Python + PYW_GIL_CHECK_LOCKED_SCOPE(); + pycall_res_t list( + PyObject_CallMethod( + self, (char *)S_ON_GET_LINE, + "i", int(n))); + if ( list.result != NULL ) + { + // Go over the List returned by Python and convert to C strings + for ( int i = chobj->columns - 1; i >= 0; --i ) + { + borref_t item(PyList_GetItem(list.result.o, Py_ssize_t(i))); + if ( item == NULL ) + continue; + + const char *str = PyString_AsString(item.o); + if ( str != NULL ) + (*cols)[i] = str; + } + } + + *icon_ = chobj->icon; + if ( (cb_flags & CHOOSE_HAVE_GETICON) != 0 ) + { + pycall_res_t pyres( + PyObject_CallMethod( + self, (char *)S_ON_GET_ICON, + "i", int(n))); + if ( pyres.result != NULL ) + *icon_ = PyInt_AsLong(pyres.result.o); + } + + if ( (cb_flags & CHOOSE_HAVE_GETATTR) != 0 ) + { + pycall_res_t pyres( + PyObject_CallMethod( + self, (char *)S_ON_GET_LINE_ATTR, + "i", int(n))); + if ( pyres.result != NULL && PyList_Check(pyres.result.o) ) + { + PyObject *item; + if ( (item = PyList_GetItem(pyres.result.o, 0)) != NULL ) + attrs->color = PyInt_AsLong(item); + if ( (item = PyList_GetItem(pyres.result.o, 1)) != NULL ) + attrs->flags = PyInt_AsLong(item); + } + } + } + + void idaapi closed() + { + if ( (cb_flags & CHOOSE_HAVE_ONCLOSE) == 0 ) + { + chobj->chooser_base_t::closed(); + return; + } + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL)); + // delete UI hook + PyObject_DelAttrString(self, "ui_hooks_trampoline"); + } + +public: + static py_choose_t *find_chooser(const char *title) + { + return static_cast(::get_chooser_obj(title)); + } + + void close() + { + // will trigger closed() + close_chooser(chobj->title); + } + + bool activate() + { + TWidget *widget = get_widget(); + if ( widget == NULL ) + return false; + + activate_widget(widget, true); + return true; + } + + TWidget *get_widget() + { + return find_widget(chobj->title); + } + + // Create a chooser. + // If it doesn't detect the "embedded" attribute, then the chooser window + // is created and displayed. + // See ::choose() for the returned values. + // \retval NO_ATTR some mandatory attribute is missing + int create(); + + inline PyObject *get_self() + { + return self; + } + + void do_refresh() + { + refresh_chooser(chobj->title); + } + + chooser_base_t *get_chobj() const + { + return chobj; + } + + const sizevec_t *get_sel_vec() const + { + return &embedded_sel; + } + + bool is_valid() const + { + return chobj != NULL; + } + + bool is_embedded() const + { + return (cb_flags & CHOOSE_IS_EMBEDDED) != 0; + } +}; + +//------------------------------------------------------------------------ +// link from the chooser object to the Python's chooser +struct py_chooser_link_t +{ + py_choose_t *link; // link to Python's chooser + py_chooser_link_t(py_choose_t *pych) : link(pych) {} + ~py_chooser_link_t() { delete link; } +}; + +//------------------------------------------------------------------------ +// we do not use virtual subclasses so we use #define for common code +#define DEFINE_COMMON_CALLBACKS \ + virtual void *get_chooser_obj() ida_override { return link; } \ + virtual bool idaapi init() ida_override { return link->init(); } \ + virtual size_t idaapi get_count() const ida_override \ + { \ + return link->get_count(); \ + } \ + virtual void idaapi get_row( \ + qstrvec_t *cols, \ + int *icon_, \ + chooser_item_attrs_t *attrs, \ + size_t n) const ida_override \ + { \ + link->get_row(cols, icon_, attrs, n); \ + } \ + virtual void idaapi closed() ida_override { link->closed(); } + +//------------------------------------------------------------------------ +// chooser class without multi-selection +class py_chooser_single_t + : public py_chooser_link_t, + public chooser_t +{ +public: + py_chooser_single_t( + py_choose_t *pych, + uint32 flags_ = 0, + int columns_ = 0, + const int *widths_ = NULL, + const char *const *header_ = NULL, + const char *title_ = NULL) + : py_chooser_link_t(pych), + chooser_t(flags_, columns_, widths_, header_, title_) {} + + DEFINE_COMMON_CALLBACKS + + virtual cbret_t idaapi ins(ssize_t n) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_INS) == 0 ) + return chooser_t::ins(n); + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_INSERT_LINE, + "i", int(n))); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_t::ins(n); + return py_as_cbret(pyres.result.o); + } + + virtual cbret_t idaapi del(size_t n) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_DEL) == 0 ) + return chooser_t::del(n); + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_DELETE_LINE, + "i", int(n))); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_t::del(n); + return py_as_cbret(pyres.result.o); + } + + virtual cbret_t idaapi edit(size_t n) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_EDIT) == 0 ) + return chooser_t::edit(n); + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_EDIT_LINE, + "i", int(n))); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_t::edit(n); + return py_as_cbret(pyres.result.o); + } + + virtual cbret_t idaapi enter(size_t n) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_ENTER) == 0 ) + return chooser_t::enter(n); + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_SELECT_LINE, + "i", int(n))); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_t::enter(n); + return py_as_cbret(pyres.result.o); + } + + virtual cbret_t idaapi refresh(ssize_t n) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_REFRESH) == 0 ) + return chooser_t::refresh(n); + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_REFRESH, + "i", int(n))); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_t::refresh(n); + return py_as_cbret(pyres.result.o); + } + + virtual void idaapi select(ssize_t n) const ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_SELECT) == 0 ) + { + chooser_t::select(n); + return; + } + PYW_GIL_GET; + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_SELECTION_CHANGE, + "i", int(n))); + } + +protected: + // [ changed, idx ] + static cbret_t py_as_cbret(PyObject *py_ret) + { + cbret_t ret; + if ( PySequence_Check(py_ret) ) + { + { + newref_t item(PySequence_GetItem(py_ret, 0)); + if ( item.o != NULL && PyInt_Check(item.o) ) + ret.changed = cbres_t(PyInt_AsLong(item.o)); + } + if ( ret.changed != NOTHING_CHANGED ) + { + newref_t item(PySequence_GetItem(py_ret, 1)); + if ( item.o != NULL && PyInt_Check(item.o) ) + ret.idx = ssize_t(PyInt_AsSsize_t(item.o)); + } + } + return ret; + } +}; + +//------------------------------------------------------------------------ +// chooser class with multi-selection +class py_chooser_multi_t + : public py_chooser_link_t, + public chooser_multi_t +{ +public: + py_chooser_multi_t( + py_choose_t *pych, + uint32 flags_ = 0, + int columns_ = 0, + const int *widths_ = NULL, + const char *const *header_ = NULL, + const char *title_ = NULL) + : py_chooser_link_t(pych), + chooser_multi_t(flags_, columns_, widths_, header_, title_) {} + + DEFINE_COMMON_CALLBACKS + + virtual cbres_t idaapi ins(sizevec_t *sel) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_INS) == 0 ) + return chooser_multi_t::ins(sel); + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(*sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_INSERT_LINE, + "O", py_list.o)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_multi_t::ins(sel); + return py_as_cbres_sel(sel, pyres.result.o); + } + + virtual cbres_t idaapi del(sizevec_t *sel) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_DEL) == 0 ) + return chooser_multi_t::del(sel); + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(*sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_DELETE_LINE, + "O", py_list.o)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_multi_t::del(sel); + return py_as_cbres_sel(sel, pyres.result.o); + } + + virtual cbres_t idaapi edit(sizevec_t *sel) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_EDIT) == 0 ) + return chooser_multi_t::edit(sel); + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(*sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_EDIT_LINE, + "O", py_list.o)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_multi_t::edit(sel); + return py_as_cbres_sel(sel, pyres.result.o); + } + + virtual cbres_t idaapi enter(sizevec_t *sel) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_ENTER) == 0 ) + return chooser_multi_t::enter(sel); + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(*sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_SELECT_LINE, + "O", py_list.o)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_multi_t::enter(sel); + return py_as_cbres_sel(sel, pyres.result.o); + } + + virtual cbres_t idaapi refresh(sizevec_t *sel) ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_REFRESH) == 0 ) + return chooser_multi_t::refresh(sel); + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(*sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_REFRESH, + "O", py_list.o)); + if ( pyres.result == NULL || pyres.result.o == Py_None ) + return chooser_multi_t::refresh(sel); + return py_as_cbres_sel(sel, pyres.result.o); + } + + virtual void idaapi select(const sizevec_t &sel) const ida_override + { + if ( (link->cb_flags & py_choose_t::CHOOSE_HAVE_SELECT) == 0 ) + { + chooser_multi_t::select(sel); + return; + } + PYW_GIL_GET; + ref_t py_list(PyW_SizeVecToPyList(sel)); + pycall_res_t pyres( + PyObject_CallMethod( + link->self, (char *)S_ON_SELECTION_CHANGE, + "O", py_list.o)); + } + +protected: + // [ changed, idx, ... ] + static cbres_t py_as_cbres_sel(sizevec_t *sel, PyObject *py_ret) + { + // this is an easy but not an optimal way of converting + if ( !PySequence_Check(py_ret) + || !PyW_PyListToSizeVec(py_ret, *sel) + || sel->empty() ) + { + sel->clear(); + return NOTHING_CHANGED; + } + cbres_t res = cbres_t(sel->front()); + sel->erase(sel->begin()); + return res; + } +}; + +//------------------------------------------------------------------------ +int py_choose_t::create() { PYW_GIL_CHECK_LOCKED_SCOPE(); - newref_t pytitle(PyObject_GetAttrString(self, "title")); - const char *title = pytitle != NULL ? PyString_AsString(pytitle.o) : "Choose"; - int r = choose( - flags, - x0, y0, - x1, y1, - (void*) self, - width, - choose_sizer, - choose_getl, - title, - icon, - deflt, - NULL, /* del */ - NULL, /* inst */ - NULL, /* update */ - NULL, /* edit */ - choose_enter, - NULL, /* destroy */ - NULL, /* popup_names */ - NULL);/* get_icon */ + // Get flags + uint32 flags; + ref_t flags_attr(PyW_TryGetAttrString(self, S_FLAGS)); + if ( flags_attr == NULL ) + return chooser_base_t::NO_ATTR; + if ( PyInt_Check(flags_attr.o) ) + flags = uint32(PyInt_AsLong(flags_attr.o)); + // instruct TChooser destructor to delete this chooser when window + // closes + flags &= ~CH_KEEP; - return r; + // Get the title + if ( !PyW_GetStringAttr(self, S_TITLE, &title) ) + return chooser_base_t::NO_ATTR; + + // Get columns + ref_t cols_attr(PyW_TryGetAttrString(self, "cols")); + if ( cols_attr == NULL ) + return chooser_base_t::NO_ATTR; + + // Get col count + int columns = int(PyList_Size(cols_attr.o)); + if ( columns < 1 ) + return chooser_base_t::NO_ATTR; + + // Get columns caption and widthes + header_strings.resize(columns); + header.resize(columns); + widths.resize(columns); + for ( int i = 0; i < columns; ++i ) + { + // get list item: [name, width] + borref_t list(PyList_GetItem(cols_attr.o, i)); + borref_t v(PyList_GetItem(list.o, 0)); + + // Extract string + const char *str = v == NULL ? "" : PyString_AsString(v.o); + header_strings[i] = str; + header[i] = header_strings[i].c_str(); + + // Extract width + int width; + borref_t v2(PyList_GetItem(list.o, 1)); + // No width? Guess width from column title + if ( v2 == NULL ) + width = strlen(str); + else + width = PyInt_AsLong(v2.o); + widths[i] = width; + } + + // Check what callbacks we have + static const struct + { + const char *name; + unsigned int have; // 0 = mandatory callback + int chooser_t_flags; + } callbacks[] = + { + { S_ON_INIT, CHOOSE_HAVE_INIT, 0 }, + { S_ON_GET_SIZE, 0 }, + { S_ON_GET_LINE, 0 }, + { S_ON_GET_ICON, CHOOSE_HAVE_GETICON, 0 }, + { S_ON_GET_LINE_ATTR, CHOOSE_HAVE_GETATTR, 0 }, + { S_ON_INSERT_LINE, CHOOSE_HAVE_INS, CH_CAN_INS }, + { S_ON_DELETE_LINE, CHOOSE_HAVE_DEL, CH_CAN_DEL }, + { S_ON_EDIT_LINE, CHOOSE_HAVE_EDIT, CH_CAN_EDIT }, + { S_ON_SELECT_LINE, CHOOSE_HAVE_ENTER, 0 }, + { S_ON_REFRESH, CHOOSE_HAVE_REFRESH, CH_CAN_REFRESH }, + { S_ON_SELECTION_CHANGE, CHOOSE_HAVE_SELECT, 0 }, + { S_ON_CLOSE, CHOOSE_HAVE_ONCLOSE, 0 }, + }; + // we can forbid some callbacks explicitly + uint32 forbidden_cb = 0; + ref_t forbidden_cb_attr(PyW_TryGetAttrString(self, "forbidden_cb")); + if ( forbidden_cb_attr != NULL && PyInt_Check(forbidden_cb_attr.o) ) + forbidden_cb = uint32(PyInt_AsLong(forbidden_cb_attr.o)); + cb_flags = 0; + for ( int i = 0; i < qnumber(callbacks); ++i ) + { + ref_t cb_attr(PyW_TryGetAttrString(self, callbacks[i].name)); + bool have_cb = cb_attr != NULL && PyCallable_Check(cb_attr.o); + if ( have_cb && (forbidden_cb & callbacks[i].have) == 0 ) + { + cb_flags |= callbacks[i].have; + flags |= callbacks[i].chooser_t_flags; + } + else + { + // Mandatory field? + if ( callbacks[i].have == 0 ) + return chooser_base_t::NO_ATTR; + } + } + + // create chooser object + if ( (flags & CH_MULTI) == 0 ) + { + chobj = new py_chooser_single_t( + this, + flags, + columns, widths.begin(), header.begin(), + title.c_str()); + } + else + { + chobj = new py_chooser_multi_t( + this, + flags, + columns, widths.begin(), header.begin(), + title.c_str()); + } + + // Get *x1,y1,x2,y2 + py_get_int(self, &chobj->x0, "x1"); + py_get_int(self, &chobj->y0, "y1"); + py_get_int(self, &chobj->x1, "x2"); + py_get_int(self, &chobj->y1, "y2"); + + // Get *icon + py_get_int(self, &chobj->icon, "icon"); + + // Get *popup names + // An array of 4 strings: ("Insert", "Delete", "Edit", "Refresh") + ref_t pn_attr(PyW_TryGetAttrString(self, S_POPUP_NAMES)); + if ( pn_attr != NULL && PyList_Check(pn_attr.o) ) + { + int npopups = int(PyList_Size(pn_attr.o)); + if ( npopups > chooser_base_t::NSTDPOPUPS ) + npopups = chooser_base_t::NSTDPOPUPS; + for ( int i = 0; i < npopups; ++i ) + { + const char *str = PyString_AsString(PyList_GetItem(pn_attr.o, i)); + chobj->popup_names[i] = str; + } + } + + // Check if *embedded + ref_t emb_attr(PyW_TryGetAttrString(self, S_EMBEDDED)); + if ( emb_attr != NULL && PyObject_IsTrue(emb_attr.o) == 1 ) + { + cb_flags |= CHOOSE_IS_EMBEDDED; + py_get_int(self, &chobj->width, "width"); + py_get_int(self, &chobj->height, "height"); + return 0; // success + } + + // run + ssize_t res; + if ( !chobj->is_multi() ) + { + // Get *deflt + ssize_t deflt = 0; + py_get_int(self, &deflt, "deflt"); + res = ((chooser_t *)chobj)->choose(deflt); + } + else + { + // Get *deflt + sizevec_t deflt; + ref_t deflt_attr(PyW_TryGetAttrString(self, "deflt")); + if ( deflt_attr != NULL + && PyList_Check(deflt_attr.o) + && !PyW_PyListToSizeVec(deflt_attr.o, deflt) ) + { + deflt.clear(); + } + res = ((chooser_multi_t *)chobj)->choose(deflt); + } + // assert: `this` is deleted in the case of the modal chooser + + return res; } + +//------------------------------------------------------------------------ +int choose_create(PyObject *self) +{ + py_choose_t *pych; + + pych = choose_find_instance(self); + if ( pych != NULL && pych->is_valid() ) + { + if ( !pych->is_embedded() ) + pych->activate(); + return chooser_base_t::ALREADY_EXISTS; + } + + if ( pych == NULL ) + pych = new py_choose_t(self); + // assert: returned value != chooser_base_t::ALREADY_EXISTS + return pych->create(); +} + +//------------------------------------------------------------------------ +void choose_close(PyObject *self) +{ + py_choose_t *pych = choose_find_instance(self); + if ( pych == NULL ) + return; + + if ( !pych->is_valid() ) + { + // the chooser object is not created + // so we delete Python's chooser ourself + delete pych; + return; + } + + // embedded chooser is deleted by form + if ( pych->is_embedded() ) + return; + + // modal chooser is closed and deleted in py_choose_t::create() + // assert: !pych->is_modal() + + // close the non-modal chooser, + // in turn this will lead to the deletion of the object + pych->close(); +} + +//------------------------------------------------------------------------ +void choose_refresh(PyObject *self) +{ + py_choose_t *pych = choose_find_instance(self); + if ( pych != NULL && pych->is_valid() ) + pych->do_refresh(); +} + +//------------------------------------------------------------------------ +void choose_activate(PyObject *self) +{ + py_choose_t *pych = choose_find_instance(self); + if ( pych != NULL && pych->is_valid() ) + pych->activate(); +} + +//------------------------------------------------------------------------ +PyObject *choose_get_embedded_selection(PyObject *self) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + py_choose_t *pych = choose_find_instance(self); + if ( pych == NULL || !pych->is_valid() || !pych->is_embedded() ) + Py_RETURN_NONE; + + ref_t ret(PyW_SizeVecToPyList(*pych->get_sel_vec())); + ret.incref(); + return ret.o; +} + +//------------------------------------------------------------------------ +// Return the C instances as 64bit numbers +PyObject *choose_get_embedded(PyObject *self) +{ + PYW_GIL_CHECK_LOCKED_SCOPE(); + + py_choose_t *pych = choose_find_instance(self); + if ( pych == NULL || !pych->is_valid() || !pych->is_embedded() ) + Py_RETURN_NONE; + + return Py_BuildValue( + "(KK)", + PTR2U64(pych->get_chobj()), + PTR2U64(pych->get_sel_vec())); +} + +//------------------------------------------------------------------------ +PyObject *choose_find(const char *title) +{ + py_choose_t *pych = py_choose_t::find_chooser(title); + if ( pych == NULL || !pych->is_valid() ) + Py_RETURN_NONE; + PyObject *self = pych->get_self(); + Py_INCREF(self); + return self; +} +// + +//--------------------------------------------------------------------------- +// +PyObject *choose_find(const char *title); +void choose_refresh(PyObject *self); +void choose_close(PyObject *self); +int choose_create(PyObject *self); +void choose_activate(PyObject *self); +PyObject *choose_get_embedded(PyObject *self); +PyObject *choose_get_embedded_selection(PyObject *self); + +PyObject *py_get_chooser_data(const char *chooser_caption, int 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; +} + +//------------------------------------------------------------------------- +TWidget *choose_get_widget(PyObject *self) +{ + py_choose_t *pych = choose_find_instance(self); + if ( pych == NULL || !pych->is_valid() ) + return NULL; + return pych->get_widget(); +} + // #endif // __PY_KERNWIN_CHOOSE__ diff --git a/pywraps/py_kernwin_choose.py b/pywraps/py_kernwin_choose.py index 5923fcd..2c0d969 100644 --- a/pywraps/py_kernwin_choose.py +++ b/pywraps/py_kernwin_choose.py @@ -1,70 +1,242 @@ - +#-------------------------------------------------------------------------- # -import _ida_idaapi - class Choose(object): - """ - Choose - class for choose() with callbacks - """ - def __init__(self, list, title, flags=0, deflt=1, icon=37): - self.list = list - self.title = title - - self.flags = flags - self.x0 = -1 - self.x1 = -1 - self.y0 = -1 - self.y1 = -1 - - self.width = -1 - self.deflt = deflt - self.icon = icon - - # HACK: Add a circular reference for non-modal choosers. This prevents the GC - # from collecting the class object the callbacks need. Unfortunately this means - # that the class will never be collected, unless refhack is set to None explicitly. - if (flags & Choose2.CH_MODAL) == 0: - self.refhack = self - - - def sizer(self): """ - Callback: sizer - returns the length of the list + Chooser wrapper class. + + Some constants are defined in this class. + Please refer to kernwin.hpp for more information. """ - return len(self.list) + CH_MODAL = 0x01 + """Modal chooser""" - def getl(self, n): + CH_MULTI = 0x04 """ - Callback: getl - get one item from the list + Allow multi selection. + Refer the description of the OnInsertLine(), OnDeleteLine(), + OnEditLine(), OnSelectLine(), OnRefresh(), OnSelectionChange() to + see a difference between single and multi selection callbacks. """ - if n == 0: - return self.title - if n <= self.sizer(): - return str(self.list[n-1]) - else: - return "" + CH_NOBTNS = 0x10 - def enter(self, n): - print "enter(%d) called" % n + CH_ATTRS = 0x20 + CH_NOIDB = 0x40 + """use the chooser even without an open database, same as x0=-2""" - def choose(self): + CH_FORCE_DEFAULT = 0x80 """ - choose - Display the choose dialogue + If a non-modal chooser was already open, change selection to the given + default one """ - old = _ida_idaapi.set_script_timeout(0) - n = _ida_kernwin.choose_choose( - self, - self.flags, - self.x0, - self.y0, - self.x1, - self.y1, - self.width, - self.deflt, - self.icon) - _ida_idaapi.set_script_timeout(old) - return n + + CH_QFLT = 0x1000 + """open with quick filter enabled and focused""" + + CH_QFTYP_SHIFT = 13 + CH_QFTYP_DEFAULT = 0 << CH_QFTYP_SHIFT + CH_QFTYP_NORMAL = 1 << CH_QFTYP_SHIFT + CH_QFTYP_WHOLE_WORDS = 2 << CH_QFTYP_SHIFT + CH_QFTYP_REGEX = 3 << CH_QFTYP_SHIFT + CH_QFTYP_FUZZY = 4 << CH_QFTYP_SHIFT + CH_QFTYP_MASK = 0x7 << CH_QFTYP_SHIFT + + CH_CAN_INS = 0x000100 + """allow to insert new items""" + CH_CAN_DEL = 0x000200 + """allow to delete existing item(s)""" + CH_CAN_EDIT = 0x000400 + """allow to edit existing item(s)""" + CH_CAN_REFRESH = 0x000800 + """allow to refresh chooser""" + + CH_BUILTIN_SHIFT = 19 + CH_BUILTIN_MASK = 0x1F << CH_BUILTIN_SHIFT + + # column flags (are specified in the widths array) + CHCOL_PLAIN = 0x00000000 + CHCOL_PATH = 0x00010000 + CHCOL_HEX = 0x00020000 + CHCOL_DEC = 0x00030000 + CHCOL_FORMAT = 0x00070000 + + # special values of the chooser index + NO_SELECTION = -1 + """there is no selected item""" + EMPTY_CHOOSER = -4 + """the chooser is initialized""" + ALREADY_EXISTS = -5 + """the non-modal chooser with the same data is already open""" + NO_ATTR = -6 + """some mandatory attribute is missing""" + + # return value of ins(), del(), edit(), enter(), refresh() callbacks + NOTHING_CHANGED = 0 + ALL_CHANGED = 1 + SELECTION_CHANGED = 2 + + # to construct `forbidden_cb` + CHOOSE_HAVE_INIT = 0x0001 + CHOOSE_HAVE_GETICON = 0x0002 + CHOOSE_HAVE_GETATTR = 0x0004 + CHOOSE_HAVE_INS = 0x0008 + CHOOSE_HAVE_DEL = 0x0010 + CHOOSE_HAVE_EDIT = 0x0020 + CHOOSE_HAVE_ENTER = 0x0040 + CHOOSE_HAVE_REFRESH = 0x0080 + CHOOSE_HAVE_SELECT = 0x0100 + CHOOSE_HAVE_ONCLOSE = 0x0200 + + class UI_Hooks_Trampoline(UI_Hooks): + def __init__(self, v): + UI_Hooks.__init__(self) + self.hook() + import weakref + self.v = weakref.ref(v) + + def populating_widget_popup(self, form, popup_handle): + chooser = self.v() + if form == chooser.GetWidget() and \ + hasattr(chooser, "OnPopup") and \ + callable(getattr(chooser, "OnPopup")): + chooser.OnPopup(form, popup_handle) + + def __init__(self, title, cols, flags = 0, popup_names = None, + icon=-1, x1=-1, y1=-1, x2=-1, y2=-1, + deflt = None, + embedded = False, width = None, height = None, + forbidden_cb = 0): + """ + Constructs a chooser window. + @param title: The chooser title + @param cols: a list of colums; each list item is a list of two items + example: [ ["Address", 10 | Choose.CHCOL_HEX], + ["Name", 30 | Choose.CHCOL_PLAIN] ] + @param flags: One of CH_XXXX constants + @param deflt: The index of the default item (0-based) for single + selection choosers or the list of indexes for multi selection + chooser + @param popup_names: List of new captions to replace this list + ["Insert", "Delete", "Edit", "Refresh"] + @param icon: Icon index (the icon should exist in ida resources or + an index to a custom loaded icon) + @param x1, y1, x2, y2: The default location (for txt-version) + @param embedded: Create as embedded chooser + @param width: Embedded chooser width + @param height: Embedded chooser height + @param forbidden_cb: Explicitly forbidden callbacks + """ + self.title = title + self.flags = flags + self.cols = cols + if deflt == None: + deflt = 0 if (flags & Choose.CH_MULTI) == 0 else [0] + self.deflt = deflt + self.popup_names = popup_names + self.icon = icon + self.x1 = x1 + self.y1 = y1 + self.x2 = x2 + self.y2 = y2 + self.embedded = embedded + self.width = width + self.height = height + self.forbidden_cb = forbidden_cb + self.ui_hooks_trampoline = None # set on Show + + + def Embedded(self): + """ + Creates an embedded chooser (as opposed to Show()) + @return: Returns 0 on success or NO_ATTR + """ + if not self.embedded: + return Choose.NO_ATTR + return _ida_kernwin.choose_create(self) + + + def GetEmbSelection(self): + """ + Returns the selection associated with an embedded chooser + + @return: + - None if chooser is not embedded + - A list with selection indexes (0-based) + """ + return _ida_kernwin.choose_get_embedded_selection(self) + + + def Show(self, modal=False): + """ + Activates or creates a chooser window + @param modal: Display as modal dialog + @return: For all choosers it will return NO_ATTR if some mandatory + attribute is missing. The mandatory attributes are: flags, + title, cols, OnGetSize(), OnGetLine(); + For modal choosers it will return the selected item index (0-based), + or NO_SELECTION if no selection, + or EMPTY_CHOOSER if the OnRefresh() callback returns EMPTY_CHOOSER; + For non-modal choosers it will return 0 + or ALREADY_EXISTS if the chooser was already open and is active now; + """ + if self.embedded: + return Choose.NO_ATTR + # it will be deleted and unhooked in py_choose_t::closed() + self.ui_hooks_trampoline = self.UI_Hooks_Trampoline(self) + if modal: + self.flags |= Choose.CH_MODAL + + # Disable the timeout + old = _ida_idaapi.set_script_timeout(0) + n = _ida_kernwin.choose_create(self) + _ida_idaapi.set_script_timeout(old) + + # Delete the modal chooser instance + self.Close() + + return n + else: + self.flags &= ~Choose.CH_MODAL + return _ida_kernwin.choose_create(self) + + + def Activate(self): + """Activates a visible chooser""" + return _ida_kernwin.choose_activate(self) + + + def Refresh(self): + """Causes the refresh callback to trigger""" + return _ida_kernwin.choose_refresh(self) + + + def Close(self): + """Closes the chooser""" + _ida_kernwin.choose_close(self) + + def GetWidget(self): + """ + Return the TWidget underlying this view. + + @return: The TWidget underlying this view, or None. + """ + return _ida_kernwin.choose_get_widget(self) + + def adjust_last_item(self, n): + """ + Helper for OnDeleteLine() and OnRefresh() callbacks. + They can be finished by the following line: + return [Choose.ALL_CHANGED] + self.adjust_last_item(n) + @param: line number of the remaining select item + @return: list of selected lines numbers (one element or empty) + """ + cnt = self.OnGetSize(); + if cnt == 0: + return [] + # take in account deleting of the last item(s) + if n >= cnt: + n = cnt - 1 + return [n] # diff --git a/pywraps/py_kernwin_choose2.hpp b/pywraps/py_kernwin_choose2.hpp deleted file mode 100644 index 03a5054..0000000 --- a/pywraps/py_kernwin_choose2.hpp +++ /dev/null @@ -1,912 +0,0 @@ -#ifndef __PY_KERNWIN_CHOOSE2__ -#define __PY_KERNWIN_CHOOSE2__ - -// - -//------------------------------------------------------------------------ -// Some defines -#define POPUP_NAMES_COUNT 4 -#define MAX_CHOOSER_MENU_COMMANDS 20 -#define thisobj ((py_choose2_t *) obj) -#define thisdecl py_choose2_t *_this = thisobj -#define MENU_COMMAND_CB(id) \ - static uint32 idaapi s_menu_command_##id(void *obj, uint32 n) \ - { \ - return thisobj->on_command(id, int(n)); \ - } - -//------------------------------------------------------------------------ -// Helper functions -class py_choose2_t; -typedef std::map pychoose2_to_choose2_map_t; -static pychoose2_to_choose2_map_t choosers; - -py_choose2_t *choose2_find_instance(PyObject *self) -{ - pychoose2_to_choose2_map_t::iterator it = choosers.find(self); - return it == choosers.end() ? NULL : it->second; -} - -void choose2_add_instance(PyObject *self, py_choose2_t *c2) -{ - choosers[self] = c2; -} - -void choose2_del_instance(PyObject *self) -{ - pychoose2_to_choose2_map_t::iterator it = choosers.find(self); - if ( it != choosers.end() ) - choosers.erase(it); -} - -//------------------------------------------------------------------------ -class py_choose2_t -{ -private: - enum - { - CHOOSE2_HAVE_DEL = 0x0001, - CHOOSE2_HAVE_INS = 0x0002, - CHOOSE2_HAVE_UPDATE = 0x0004, - CHOOSE2_HAVE_EDIT = 0x0008, - CHOOSE2_HAVE_ENTER = 0x0010, - CHOOSE2_HAVE_GETICON = 0x0020, - CHOOSE2_HAVE_GETATTR = 0x0040, - CHOOSE2_HAVE_COMMAND = 0x0080, - CHOOSE2_HAVE_ONCLOSE = 0x0100, - CHOOSE2_HAVE_SELECT = 0x0200, - CHOOSE2_HAVE_REFRESHED = 0x0400, - }; - // Chooser flags - int flags; - - // Callback flags (to tell which callback exists and which not) - // One of CHOOSE2_HAVE_xxxx - unsigned int cb_flags; - chooser_info_t *embedded; - intvec_t embedded_sel; - - // Menu callback index (in the menu_cbs array) - int menu_cb_idx; - - // Chooser title - qstring title; - - // Column widths - intvec_t widths; - - // Python object link - PyObject *self; - // Chooser columns - qstrvec_t cols; - const char **popup_names; - bool ui_cb_hooked; - - // The number of declarations should follow the MAX_CHOOSER_MENU_COMMANDS value - MENU_COMMAND_CB(0) MENU_COMMAND_CB(1) - MENU_COMMAND_CB(2) MENU_COMMAND_CB(3) - MENU_COMMAND_CB(4) MENU_COMMAND_CB(5) - MENU_COMMAND_CB(6) MENU_COMMAND_CB(7) - MENU_COMMAND_CB(8) MENU_COMMAND_CB(9) - MENU_COMMAND_CB(10) MENU_COMMAND_CB(11) - MENU_COMMAND_CB(12) MENU_COMMAND_CB(13) - MENU_COMMAND_CB(14) MENU_COMMAND_CB(15) - MENU_COMMAND_CB(16) MENU_COMMAND_CB(17) - MENU_COMMAND_CB(18) MENU_COMMAND_CB(19) - static chooser_cb_t *menu_cbs[MAX_CHOOSER_MENU_COMMANDS]; - - //------------------------------------------------------------------------ - // Static methods to dispatch to member functions - //------------------------------------------------------------------------ - static int idaapi ui_cb(void *obj, int notification_code, va_list va) - { - // UI callback to handle chooser items with attributes - if ( notification_code != ui_get_chooser_item_attrs ) - return 0; - - // Pass events that belong to our chooser only - void *chooser_obj = va_arg(va, void *); - 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); - return 1; - } - - static void idaapi s_select(void *obj, const intvec_t &sel) - { - thisobj->on_select(sel); - } - - static void idaapi s_refreshed(void *obj) - { - thisobj->on_refreshed(); - } - - static uint32 idaapi s_sizer(void *obj) - { - return (uint32)thisobj->on_get_size(); - } - - static void idaapi s_getl(void *obj, uint32 n, char *const *arrptr) - { - thisobj->on_get_line(int(n), arrptr); - } - - static uint32 idaapi s_del(void *obj, uint32 n) - { - return uint32(thisobj->on_delete_line(int(n))); - } - - static void idaapi s_ins(void *obj) - { - thisobj->on_insert_line(); - } - - static uint32 idaapi s_update(void *obj, uint32 n) - { - return uint32(thisobj->on_refresh(int(n))); - } - - static void idaapi s_edit(void *obj, uint32 n) - { - thisobj->on_edit_line(int(n)); - } - - static void idaapi s_enter(void * obj, uint32 n) - { - thisobj->on_enter(int(n)); - } - - static int idaapi s_get_icon(void *obj, uint32 n) - { - return thisobj->on_get_icon(int(n)); - } - - static void idaapi s_destroy(void *obj) - { - thisobj->on_close(); - } - - //------------------------------------------------------------------------ - // Member functions corresponding to each chooser2() callback - //------------------------------------------------------------------------ - void clear_popup_names() - { - if ( popup_names == NULL ) - return; - - for ( int i=0; i < POPUP_NAMES_COUNT; i++ ) - qfree((void *)popup_names[i]); - - delete [] popup_names; - popup_names = NULL; - } - - void install_hooks(bool install) - { - if ( install ) - { - if ( (flags & CH_ATTRS) != 0 ) - { - if ( !hook_to_notification_point(HT_UI, ui_cb, this) ) - flags &= ~CH_ATTRS; - else - ui_cb_hooked = true; - } - } - else - { - if ( (flags & CH_ATTRS) != 0 ) - { - unhook_from_notification_point(HT_UI, ui_cb, this); - ui_cb_hooked = false; - } - } - } - - void on_get_line(int lineno, char *const *line_arr) - { - // Called from s_getl, which itself can be called from the kernel. Ensure GIL - PYW_GIL_GET; - - // Get headers? - if ( lineno == 0 ) - { - // Copy the pre-parsed columns - for ( size_t i=0; i < cols.size(); i++ ) - qstrncpy(line_arr[i], cols[i].c_str(), MAXSTR); - return; - } - - // Clear buffer - int ncols = int(cols.size()); - for ( int i=ncols-1; i >= 0; i-- ) - line_arr[i][0] = '\0'; - - // Call Python - PYW_GIL_CHECK_LOCKED_SCOPE(); - pycall_res_t list(PyObject_CallMethod(self, (char *)S_ON_GET_LINE, "i", lineno - 1)); - if ( list.result == NULL ) - return; - - // Go over the List returned by Python and convert to C strings - for ( int i=ncols-1; i >= 0; i-- ) - { - borref_t item(PyList_GetItem(list.result.o, Py_ssize_t(i))); - if ( item == NULL ) - continue; - - const char *str = PyString_AsString(item.o); - if ( str != NULL ) - qstrncpy(line_arr[i], str, MAXSTR); - } - } - - size_t on_get_size() - { - PYW_GIL_GET; - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_GET_SIZE, NULL)); - if ( pyres.result == NULL ) - return 0; - - return PyInt_AsLong(pyres.result.o); - } - - void on_refreshed() - { - PYW_GIL_GET; - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_REFRESHED, NULL)); - } - - void on_select(const intvec_t &intvec) - { - PYW_GIL_GET; - ref_t py_list(PyW_IntVecToPyList(intvec)); - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_SELECTION_CHANGE, "O", py_list.o)); - } - - void on_close() - { - PYW_GIL_GET; - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL)); - - // Delete this instance if non-modal and not embedded - if ( !is_modal() && get_embedded() == NULL ) - delete this; - } - - int on_delete_line(int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_DELETE_LINE, - "i", - IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1)); - return pyres.result == NULL ? 1 : PyInt_AsLong(pyres.result.o); - } - - int on_refresh(int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_REFRESH, - "i", - lineno - 1)); - return pyres.result == NULL ? lineno : PyInt_AsLong(pyres.result.o) + 1; - } - - void on_insert_line() - { - PYW_GIL_GET; - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_INSERT_LINE, NULL)); - } - - void on_enter(int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_SELECT_LINE, - "i", - lineno - 1)); - } - - void on_edit_line(int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_EDIT_LINE, - "i", - lineno - 1)); - } - - int on_command(int cmd_id, int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_COMMAND, - "ii", - lineno - 1, - cmd_id)); - return pyres.result == NULL ? lineno : PyInt_AsLong(pyres.result.o); - } - - int on_get_icon(int lineno) - { - PYW_GIL_GET; - pycall_res_t pyres( - PyObject_CallMethod( - self, - (char *)S_ON_GET_ICON, - "i", - lineno - 1)); - return pyres.result == NULL ? -1 : PyInt_AsLong(pyres.result.o); - } - - void on_get_line_attr(int lineno, chooser_item_attrs_t *attr) - { - PYW_GIL_GET; - pycall_res_t pyres(PyObject_CallMethod(self, (char *)S_ON_GET_LINE_ATTR, "i", lineno - 1)); - if ( pyres.result != NULL ) - { - if ( PyList_Check(pyres.result.o) ) - { - PyObject *item; - if ( (item = PyList_GetItem(pyres.result.o, 0)) != NULL ) - attr->color = PyInt_AsLong(item); - if ( (item = PyList_GetItem(pyres.result.o, 1)) != NULL ) - attr->flags = PyInt_AsLong(item); - } - } - } - - bool split_chooser_caption(qstring *out_title, qstring *out_caption, const char *caption) const - { - if ( get_embedded() != NULL ) - { - // For embedded chooser, the "caption" will be overloaded to encode - // the AskUsingForm's title, caption and embedded chooser id - // Title:EmbeddedChooserID:Caption - - char title_buf[MAXSTR]; - const char *ptitle; - - static const char delimiter[] = ":"; - char temp[MAXSTR]; - qstrncpy(temp, caption, sizeof(temp)); - - char *ctx; - char *p = qstrtok(temp, delimiter, &ctx); - if ( p == NULL ) - return false; - - // Copy the title - char title_str[MAXSTR]; - qstrncpy(title_str, p, sizeof(title_str)); - - // Copy the echooser ID - p = qstrtok(NULL, delimiter, &ctx); - if ( p == NULL ) - return false; - - char id_str[10]; - qstrncpy(id_str, p, sizeof(id_str)); - - // Form the new title of the form: "AskUsingFormTitle:EchooserId" - qsnprintf(title_buf, sizeof(title_buf), "%s:%s", title_str, id_str); - - // Adjust the title - *out_title = title_buf; - - // Adjust the caption - p = qstrtok(NULL, delimiter, &ctx); - *out_caption = caption + (p - temp); - } - else - { - *out_title = title; - *out_caption = caption; - } - return true; - } - - // This must be called at the end of create(), when many dependencies - // have been computed (title, widths, popup_names, [cb_]flags, ...) - void fill_chooser_info( - chooser_info_t *out, - int deflt, - int desired_width, - int desired_height, - int icon) - { - out->obj = this; - out->title = title.c_str(); - out->columns = widths.size(); - out->deflt = deflt; - out->flags = flags; - out->width = desired_width; - out->height = desired_height; - out->icon = icon; - out->popup_names = popup_names; - out->widths = widths.begin(); - out->destroyer = s_destroy; - out->getl = s_getl; - out->sizer = s_sizer; - out->del = (cb_flags & CHOOSE2_HAVE_DEL) != 0 ? s_del : NULL; - out->edit = (cb_flags & CHOOSE2_HAVE_EDIT) != 0 ? s_edit : NULL; - out->enter = (cb_flags & CHOOSE2_HAVE_ENTER) != 0 ? s_enter : NULL; - out->get_icon = (cb_flags & CHOOSE2_HAVE_GETICON) != 0 ? s_get_icon : NULL; - out->ins = (cb_flags & CHOOSE2_HAVE_INS) != 0 ? s_ins : NULL; - out->update = (cb_flags & CHOOSE2_HAVE_UPDATE) != 0 ? s_update : NULL; - out->get_attrs = NULL; - out->initializer = NULL; - // Fill callbacks that are only present in idaq - if ( is_idaq() ) - { - out->select = (cb_flags & CHOOSE2_HAVE_SELECT) != 0 ? s_select : NULL; - out->refresh = (cb_flags & CHOOSE2_HAVE_REFRESHED) != 0 ? s_refreshed : NULL; - } - else - { - out->select = NULL; - out->refresh = NULL; - } - } - -public: - //------------------------------------------------------------------------ - // Public methods - //------------------------------------------------------------------------ - py_choose2_t(): flags(0), cb_flags(0), - embedded(NULL), menu_cb_idx(0), - self(NULL), popup_names(NULL), ui_cb_hooked(false) - { - } - - ~py_choose2_t() - { - // Remove from list - choose2_del_instance(self); - - // Uninstall hooks - install_hooks(false); - - delete embedded; - Py_XDECREF(self); - clear_popup_names(); - } - - static py_choose2_t *find_chooser(const char *title) - { - return (py_choose2_t *) get_chooser_obj(title); - } - - void close() - { - // Will trigger on_close() - close_chooser(title.c_str()); - } - - bool activate() - { - TForm *frm = find_tform(title.c_str()); - if ( frm == NULL ) - return false; - - switchto_tform(frm, true); - return true; - } - - int add_command( - const char *_caption, - int flags=0, - int menu_index=-1, - int icon=-1) - { - if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS ) - return -1; - - qstring title, caption; - if ( !split_chooser_caption(&title, &caption, _caption) - || !add_chooser_command( - title.c_str(), - caption.c_str(), - menu_cbs[menu_cb_idx], - menu_index, - icon, - flags) ) - return -1; - - return menu_cb_idx++; - } - - // Create a chooser. - // If it detects the "embedded" attribute, then it will create a chooser_info_t structure - // Otherwise the chooser window is created and displayed - int create(PyObject *self) - { - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Get flags - ref_t flags_attr(PyW_TryGetAttrString(self, S_FLAGS)); - if ( flags_attr == NULL ) - return -1; - flags = PyInt_Check(flags_attr.o) != 0 ? PyInt_AsLong(flags_attr.o) : 0; - - // Get the title - if ( !PyW_GetStringAttr(self, S_TITLE, &title) ) - return -1; - - // Get columns - ref_t cols_attr(PyW_TryGetAttrString(self, "cols")); - if ( cols_attr == NULL ) - return -1; - - // Get col count - int ncols = int(PyList_Size(cols_attr.o)); - - // Get cols caption and widthes - cols.qclear(); - for ( int i=0; i < ncols; i++ ) - { - // get list item: [name, width] - borref_t list(PyList_GetItem(cols_attr.o, i)); - borref_t v(PyList_GetItem(list.o, 0)); - - // Extract string - const char *str = v == NULL ? "" : PyString_AsString(v.o); - cols.push_back(str); - - // Extract width - int width; - borref_t v2(PyList_GetItem(list.o, 1)); - // No width? Guess width from column title - if ( v2 == NULL ) - width = strlen(str); - else - width = PyInt_AsLong(v2.o); - widths.push_back(width); - } - - // Get *deflt - int deflt = -1; - ref_t deflt_attr(PyW_TryGetAttrString(self, "deflt")); - if ( deflt_attr != NULL ) - deflt = PyInt_AsLong(deflt_attr.o); - - // Get *icon - int icon = -1; - ref_t icon_attr(PyW_TryGetAttrString(self, "icon")); - if ( icon_attr != NULL ) - icon = PyInt_AsLong(icon_attr.o); - - // Get *x1,y1,x2,y2 - int pts[4]; - static const char *pt_attrs[qnumber(pts)] = { "x1", "y1", "x2", "y2" }; - for ( size_t i=0; i < qnumber(pts); i++ ) - { - ref_t pt_attr(PyW_TryGetAttrString(self, pt_attrs[i])); - if ( pt_attr == NULL ) - pts[i] = -1; - else - pts[i] = PyInt_AsLong(pt_attr.o); - } - - // Check what callbacks we have - static const struct - { - const char *name; - unsigned int have; // 0 = mandatory callback - } callbacks[] = - { - { S_ON_GET_SIZE, 0 }, - { S_ON_GET_LINE, 0 }, - { S_ON_CLOSE, 0 }, - { S_ON_EDIT_LINE, CHOOSE2_HAVE_EDIT }, - { S_ON_INSERT_LINE, CHOOSE2_HAVE_INS }, - { S_ON_DELETE_LINE, CHOOSE2_HAVE_DEL }, - { S_ON_REFRESH, CHOOSE2_HAVE_UPDATE }, // update() - { S_ON_SELECT_LINE, CHOOSE2_HAVE_ENTER }, // enter() - { S_ON_COMMAND, CHOOSE2_HAVE_COMMAND }, - { S_ON_GET_LINE_ATTR, CHOOSE2_HAVE_GETATTR }, - { S_ON_GET_ICON, CHOOSE2_HAVE_GETICON }, - { S_ON_SELECTION_CHANGE, CHOOSE2_HAVE_SELECT }, - { S_ON_REFRESHED, CHOOSE2_HAVE_REFRESHED }, - }; - cb_flags = 0; - for ( int i=0; i < qnumber(callbacks); i++ ) - { - ref_t cb_attr(PyW_TryGetAttrString(self, callbacks[i].name)); - bool have_cb = cb_attr != NULL && PyCallable_Check(cb_attr.o) != 0; - if ( have_cb ) - { - cb_flags |= callbacks[i].have; - } - else - { - // Mandatory field? - if ( callbacks[i].have == 0 ) - return -1; - } - } - - // Get *popup names - // An array of 4 strings: ("Insert", "Delete", "Edit", "Refresh" - ref_t pn_attr(PyW_TryGetAttrString(self, S_POPUP_NAMES)); - if ( (pn_attr != NULL) - && PyList_Check(pn_attr.o) - && PyList_Size(pn_attr.o) == POPUP_NAMES_COUNT ) - { - popup_names = new const char *[POPUP_NAMES_COUNT]; - for ( int i=0; i < POPUP_NAMES_COUNT; i++ ) - { - const char *str = PyString_AsString(PyList_GetItem(pn_attr.o, i)); - popup_names[i] = qstrdup(str); - } - } - - // Adjust flags (if needed) - if ( (cb_flags & CHOOSE2_HAVE_GETATTR) != 0 ) - flags |= CH_ATTRS; - - // Increase object reference - Py_INCREF(self); - this->self = self; - - // Hook to notification point (to handle chooser item attributes) - install_hooks(true); - - // Check if *embedded - ref_t emb_attr(PyW_TryGetAttrString(self, S_EMBEDDED)); - int rc; - if ( emb_attr != NULL && PyObject_IsTrue(emb_attr.o) == 1 ) - { - // Create an embedded chooser structure - embedded = new chooser_info_t(); - fill_chooser_info(embedded, deflt, pts[0], pts[1], icon); - rc = 1; // success - } - else - { - chooser_info_t ci; - fill_chooser_info(&ci, deflt, -1, -1, icon); - rc = choose3(&ci); - clear_popup_names(); - if ( is_modal() ) - --rc; // modal chooser return the index of the selected item - } - return rc; - } - - inline PyObject *get_self() - { - return self; - } - - void refresh() - { - refresh_chooser(title.c_str()); - } - - bool is_modal() - { - return (flags & CH_MODAL) != 0; - } - - intvec_t *get_sel_vec() - { - return &embedded_sel; - } - - chooser_info_t *get_embedded() const - { - return embedded; - } -}; - -//------------------------------------------------------------------------ -// Initialize the callback pointers -#define DECL_MENU_COMMAND_CB(id) s_menu_command_##id -chooser_cb_t *py_choose2_t::menu_cbs[MAX_CHOOSER_MENU_COMMANDS] = -{ - DECL_MENU_COMMAND_CB(0), DECL_MENU_COMMAND_CB(1), - DECL_MENU_COMMAND_CB(2), DECL_MENU_COMMAND_CB(3), - DECL_MENU_COMMAND_CB(4), DECL_MENU_COMMAND_CB(5), - DECL_MENU_COMMAND_CB(6), DECL_MENU_COMMAND_CB(7), - DECL_MENU_COMMAND_CB(8), DECL_MENU_COMMAND_CB(9), - DECL_MENU_COMMAND_CB(10), DECL_MENU_COMMAND_CB(11), - DECL_MENU_COMMAND_CB(12), DECL_MENU_COMMAND_CB(13), - DECL_MENU_COMMAND_CB(14), DECL_MENU_COMMAND_CB(15), - DECL_MENU_COMMAND_CB(16), DECL_MENU_COMMAND_CB(17), - DECL_MENU_COMMAND_CB(18), DECL_MENU_COMMAND_CB(19) -}; -#undef DECL_MENU_COMMAND_CB - -#undef POPUP_NAMES_COUNT -#undef MAX_CHOOSER_MENU_COMMANDS -#undef thisobj -#undef thisdecl -#undef MENU_COMMAND_CB - -//------------------------------------------------------------------------ -int choose2_create(PyObject *self, bool embedded) -{ - py_choose2_t *c2; - - c2 = choose2_find_instance(self); - if ( c2 != NULL ) - { - if ( !embedded ) - c2->activate(); - return 1; - } - - c2 = new py_choose2_t(); - - choose2_add_instance(self, c2); - - int r = c2->create(self); - // Non embedded chooser? Return immediately - if ( !embedded ) - return r; - - // Embedded chooser was not created? - if ( c2->get_embedded() == NULL || r != 1 ) - { - delete c2; - r = 0; - } - return r; -} - -//------------------------------------------------------------------------ -void choose2_close(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 == NULL ) - return; - - // Modal or embedded chooser? - if ( c2->get_embedded() != NULL || c2->is_modal() ) - { - // Then simply delete the instance - delete c2; - } - else - { - // Close the chooser. - // In turn this will lead to the deletion of the object - c2->close(); - } -} - -//------------------------------------------------------------------------ -void choose2_refresh(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - c2->refresh(); -} - -//------------------------------------------------------------------------ -void choose2_activate(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - c2->activate(); -} - -//------------------------------------------------------------------------ -PyObject *choose2_get_embedded_selection(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - py_choose2_t *c2 = choose2_find_instance(self); - chooser_info_t *embedded; - - if ( c2 == NULL || (embedded = c2->get_embedded()) == NULL ) - Py_RETURN_NONE; - - // Returned as 1-based - intvec_t &intvec = *c2->get_sel_vec(); - - // Make 0-based - for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it ) - (*it)--; - - ref_t ret(PyW_IntVecToPyList(intvec)); - ret.incref(); - return ret.o; -} - -//------------------------------------------------------------------------ -// Return the C instances as 64bit numbers -PyObject *choose2_get_embedded(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 == NULL ) - Py_RETURN_NONE; - - chooser_info_t *embedded = c2->get_embedded(); - if ( embedded == NULL ) - Py_RETURN_NONE; - - return Py_BuildValue("(KK)", PTR2U64(embedded), PTR2U64(c2->get_sel_vec())); -} - -//------------------------------------------------------------------------ -int choose2_add_command( - PyObject *self, - const char *caption, - int flags=0, - int menu_index=-1, - int icon=-1) -{ - py_choose2_t *c2 = choose2_find_instance(self); - return c2 == NULL ? -2 : c2->add_command(caption, flags, menu_index, icon); -} - -//------------------------------------------------------------------------ -PyObject *choose2_find(const char *title) -{ - py_choose2_t *c2 = py_choose2_t::find_chooser(title); - return c2 == NULL ? NULL : c2->get_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); -void choose2_close(PyObject *self); -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 -//--------------------------------------------------------------------------- - -static void NT_CDECL choose2_test_embedded(chooser_info_t *embedded) -{ - msg("cb=%d -> looks %valid\n", - embedded->cb, - embedded->cb == sizeof(chooser_info_t) ? "" : "in"); -} -static size_t choose2_get_test_embedded() -{ - return (size_t)choose2_test_embedded; -} -#endif // __PY_KERNWIN_CHOOSE2__ diff --git a/pywraps/py_kernwin_choose2.py b/pywraps/py_kernwin_choose2.py deleted file mode 100644 index 4320bdc..0000000 --- a/pywraps/py_kernwin_choose2.py +++ /dev/null @@ -1,237 +0,0 @@ -# ----------------------------------------------------------------------- -# -class Choose2(object): - """ - Choose2 wrapper class. - - Some constants are defined in this class. Please refer to kernwin.hpp for more information. - """ - - CH_MODAL = 0x01 - """Modal chooser""" - - CH_MULTI = 0x02 - """Allow multi selection""" - - CH_MULTI_EDIT = 0x04 - CH_NOBTNS = 0x08 - CH_ATTRS = 0x10 - CH_NOIDB = 0x20 - """use the chooser even without an open database, same as x0=-2""" - CH_UTF8 = 0x40 - """string encoding is utf-8""" - - CH_BUILTIN_MASK = 0xF80000 - - # column flags (are specified in the widths array) - CHCOL_PLAIN = 0x00000000 - CHCOL_PATH = 0x00010000 - CHCOL_HEX = 0x00020000 - CHCOL_DEC = 0x00030000 - CHCOL_FORMAT = 0x00070000 - - - 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): - """ - Constructs a chooser window. - @param title: The chooser title - @param cols: a list of colums; each list item is a list of two items - example: [ ["Address", 10 | Choose2.CHCOL_HEX], ["Name", 30 | Choose2.CHCOL_PLAIN] ] - @param flags: One of CH_XXXX constants - @param deflt: Default starting item - @param popup_names: list of new captions to replace this list ["Insert", "Delete", "Edit", "Refresh"] - @param icon: Icon index (the icon should exist in ida resources or an index to a custom loaded icon) - @param x1, y1, x2, y2: The default location - @param embedded: Create as embedded chooser - @param width: Embedded chooser width - @param height: Embedded chooser height - """ - self.title = title - self.flags = flags - self.cols = cols - self.deflt = deflt - self.popup_names = popup_names - self.icon = icon - self.x1 = x1 - self.y1 = y1 - self.x2 = x2 - self.y2 = y2 - self.embedded = embedded - if embedded: - self.x1 = width - self.y1 = height - - - def Embedded(self): - """ - Creates an embedded chooser (as opposed to Show()) - @return: Returns 1 on success - """ - return _ida_kernwin.choose2_create(self, True) - - - def GetEmbSelection(self): - """ - Returns the selection associated with an embedded chooser - - @return: - - None if chooser is not embedded - - A list with selection indices (0-based) - """ - return _ida_kernwin.choose2_get_embedded_selection(self) - - - def Show(self, modal=False): - """ - Activates or creates a chooser window - @param modal: Display as modal dialog - @return: For modal choosers it will return the selected item index (0-based) or -1 if no selection - """ - if modal: - self.flags |= Choose2.CH_MODAL - - # Disable the timeout - 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() - - return n - else: - self.flags &= ~Choose2.CH_MODAL - return _ida_kernwin.choose2_create(self, False) - - - def Activate(self): - """Activates a visible chooser""" - return _ida_kernwin.choose2_activate(self) - - - def Refresh(self): - """Causes the refresh callback to trigger""" - return _ida_kernwin.choose2_refresh(self) - - - def Close(self): - """Closes the chooser""" - return _ida_kernwin.choose2_close(self) - - - def AddCommand(self, - caption, - flags = _ida_kernwin.CHOOSER_POPUP_MENU, - menu_index = -1, - icon = -1, - emb=None): - """ - Deprecated: Use - - register_action() - - attach_action_to_menu() - - attach_action_to_popup() - """ - # 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 _ida_kernwin.choose2_add_command(self, caption, flags, menu_index, icon) - - # - # Implement these methods in the subclass: - # -# -# def OnClose(self): -# """ -# Called when the window is being closed. -# This callback is mandatory. -# @return: nothing -# """ -# pass -# -# def OnGetLine(self, n): -# """Called when the chooser window requires lines. -# This callback is mandatory. -# @param n: Line number (0-based) -# @return: The user should return a list with ncols elements. -# example: a list [col1, col2, col3, ...] describing the n-th line -# """ -# return ["col1 val", "col2 val"] -# -# def OnGetSize(self): -# """Returns the element count. -# This callback is mandatory. -# @return: Number of elements -# """ -# return len(self.the_list) -# -# def OnEditLine(self, n): -# """ -# Called when an item is being edited. -# @param n: Line number (0-based) -# @return: Nothing -# """ -# pass -# -# def OnInsertLine(self): -# """ -# Called when 'Insert' is selected either via the hotkey or popup menu. -# @return: Nothing -# """ -# pass -# -# def OnSelectLine(self, n): -# """ -# Called when a line is selected and then Ok or double click was pressed -# @param n: Line number (0-based) -# """ -# pass -# -# def OnSelectionChange(self, sel_list): -# """ -# Called when the selection changes -# @param sel_list: A list of selected item indices -# """ -# pass -# -# def OnDeleteLine(self, n): -# """ -# Called when a line is about to be deleted -# @param n: Line number (0-based) -# """ -# return self.n -# -# def OnRefresh(self, n): -# """ -# Triggered when the 'Refresh' is called from the popup menu item. -# -# @param n: The currently selected line (0-based) at the time of the refresh call -# @return: Return the new selected line -# """ -# return self.n -# -# def OnRefreshed(self): -# """ -# Triggered when a refresh happens (for example due to column sorting) -# """ -# -# def OnCommand(self, n, cmd_id): -# """Return int ; check add_chooser_command()""" -# return 0 -# -# def OnGetIcon(self, n): -# """ -# Return icon number for a given item (or -1 if no icon is avail) -# @param n: Line number (0-based) -# """ -# return -1 -# -# def OnGetLineAttr(self, n): -# """ -# Return list [bgcolor, flags=CHITEM_XXXX] or None; check chooser_item_attrs_t -# @param n: Line number (0-based) -# """ -# return [0x0, CHITEM_BOLD] -# -# diff --git a/pywraps/py_kernwin_custview.hpp b/pywraps/py_kernwin_custview.hpp index 8476978..5170a23 100644 --- a/pywraps/py_kernwin_custview.hpp +++ b/pywraps/py_kernwin_custview.hpp @@ -141,8 +141,7 @@ class customviewer_t { protected: qstring _title; - TForm *_form; - TCustomControl *_cv; + TWidget *_cv; custviewer_data_t *_data; int _features; custom_viewer_handlers_t handlers; @@ -166,27 +165,14 @@ private: cvw_popupctx_t(size_t mid, customviewer_t *v): menu_id(mid), cv(v) {} }; typedef std::map cvw_popupmap_t; - static cvw_popupmap_t _global_popup_map; static size_t _global_popup_id; qstring _curline; - intvec_t _installed_popups; - - static bool idaapi s_popup_menu_cb(void *ud) - { - size_t mid = (size_t)ud; - cvw_popupmap_t::iterator it = _global_popup_map.find(mid); - if ( it == _global_popup_map.end() ) - return false; - - PYW_GIL_GET; - return it->second.cv->on_popup_menu(it->second.menu_id); - } static bool idaapi s_cv_keydown( - TCustomControl * /*cv*/, - int vk_key, - int shift, - void *ud) + TWidget * /*cv*/, + int vk_key, + int shift, + void *ud) { PYW_GIL_GET; customviewer_t *_this = (customviewer_t *)ud; @@ -194,7 +180,7 @@ private: } // The popup menu is being constructed - static void idaapi s_cv_popup(TCustomControl * /*cv*/, void *ud) + static void idaapi s_cv_popup(TWidget * /*cv*/, void *ud) { PYW_GIL_GET; customviewer_t *_this = (customviewer_t *)ud; @@ -202,7 +188,7 @@ private: } // The user clicked - static bool idaapi s_cv_click(TCustomControl * /*cv*/, int shift, void *ud) + static bool idaapi s_cv_click(TWidget * /*cv*/, int shift, void *ud) { PYW_GIL_GET; customviewer_t *_this = (customviewer_t *)ud; @@ -210,7 +196,7 @@ private: } // The user double clicked - static bool idaapi s_cv_dblclick(TCustomControl * /*cv*/, int shift, void *ud) + static bool idaapi s_cv_dblclick(TWidget * /*cv*/, int shift, void *ud) { PYW_GIL_GET; customviewer_t *_this = (customviewer_t *)ud; @@ -218,7 +204,7 @@ private: } // Cursor position has been changed - static void idaapi s_cv_curpos(TCustomControl * /*cv*/, void *ud) + static void idaapi s_cv_curpos(TWidget * /*cv*/, void *ud) { PYW_GIL_GET; customviewer_t *_this = (customviewer_t *)ud; @@ -226,7 +212,7 @@ private: } //-------------------------------------------------------------------------- - static int idaapi s_ui_cb(void *ud, int code, va_list va) + static ssize_t idaapi s_ui_cb(void *ud, int code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; @@ -235,25 +221,25 @@ private: { 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 *); + qstring &hint = *va_arg(va, qstring *); + TWidget *viewer = va_arg(va, TWidget *); + place_t *place = va_arg(va, place_t *); + int *important_lines = va_arg(va, int *); if ( (_this->_features & HAVE_HINT) == 0 || place == NULL || _this->_cv != viewer ) return 0; else return _this->on_hint(place, important_lines, hint) ? 1 : 0; } - case ui_tform_invisible: + case ui_widget_invisible: { - TForm *form = va_arg(va, TForm *); - if ( _this->_form != form ) + TWidget *widget = va_arg(va, TWidget *); + if ( _this->_cv != widget ) break; } // fallthrough... case ui_term: - unhook_from_notification_point(HT_UI, s_ui_cb, _this); + idapython_unhook_from_notification_point(HT_UI, s_ui_cb, _this); _this->on_close(); _this->on_post_close(); break; @@ -265,13 +251,11 @@ private: void on_post_close() { init_vars(); - clear_popup_menu(); } public: - inline TForm *get_tform() { return _form; } - inline TCustomControl *get_tcustom_control() { return _cv; } + inline TWidget *get_widget() { return _cv; } // // All the overridable callbacks @@ -307,7 +291,6 @@ public: _features = 0; _curline.clear(); _cv = NULL; - _form = NULL; } customviewer_t() @@ -322,8 +305,8 @@ public: //-------------------------------------------------------------------------- void close() { - if ( _form != NULL ) - close_tform(_form, FORM_SAVE | FORM_CLOSE_LATER); + if ( _cv != NULL ) + close_widget(_cv, WCLS_SAVE | WCLS_CLOSE_LATER); } //-------------------------------------------------------------------------- @@ -404,12 +387,8 @@ public: if ( r == NULL || !notags ) return r; - size_t sz = strlen(r); - if ( sz == 0 ) - return r; - - _curline.resize(sz + 5, '\0'); - tag_remove(r, &_curline[0], sz + 1); + _curline = r; + tag_remove(&_curline); return _curline.c_str(); } @@ -425,63 +404,19 @@ public: return ::jumpto(_cv, place, x, y); } - //-------------------------------------------------------------------------- - void clear_popup_menu() - { - if ( _cv != NULL ) - set_custom_viewer_popup_menu(_cv, NULL); - - intvec_t::iterator it, it_end; - for ( it=_installed_popups.begin(), it_end=_installed_popups.end(); - it != it_end; - ++it ) - { - _global_popup_map.erase(*it); - } - _installed_popups.clear(); - } - - //-------------------------------------------------------------------------- - size_t add_popup_menu( - const char *title, - const char *hotkey) - { - size_t menu_id = _global_popup_id + 1; - - // Overlap / already exists? - if ( _cv == NULL // No custviewer? - || menu_id == 0 // Overlap? - || _global_popup_map.find(menu_id) != _global_popup_map.end() ) // Already exists? - { - return 0; - } - add_custom_viewer_popup_item(_cv, title, hotkey, s_popup_menu_cb, (void *)menu_id); - - // Save global association - _global_popup_map[menu_id] = cvw_popupctx_t(menu_id, this); - _global_popup_id = menu_id; - - // Remember what menu IDs are set with this form - _installed_popups.push_back(menu_id); - return menu_id; - } - - //-------------------------------------------------------------------------- bool create(const char *title, int features, custviewer_data_t *data) { // Already created? (in the instance) - if ( _form != NULL ) + if ( _cv != NULL ) return true; // Already created? (in IDA windows list) - HWND hwnd(NULL); - TForm *form = create_tform(title, &hwnd); - if ( hwnd == NULL ) + TWidget *found = find_widget(title); + if ( found != NULL ) return false; _title = title; _data = data; - _form = form; _features = features; // @@ -505,7 +440,6 @@ public: // Create the viewer _cv = create_custom_viewer( title, - (TWinControl *)_form, _data->get_min(), _data->get_max(), _data->get_min(), @@ -514,8 +448,8 @@ public: &handlers, this); - // Hook to UI notifications (for TForm close event) - hook_to_notification_point(HT_UI, s_ui_cb, this); + // Hook to UI notifications (for TWidget close event) + idapython_hook_to_notification_point(HT_UI, s_ui_cb, this); return true; } @@ -524,15 +458,14 @@ public: bool show() { // Closed already? - if ( _form == NULL ) + if ( _cv == NULL ) return false; - open_tform(_form, FORM_TAB|FORM_MENU|FORM_RESTORE|FORM_QWIDGET); + display_widget(_cv, WOPN_TAB|WOPN_MENU|WOPN_RESTORE); return true; } }; -customviewer_t::cvw_popupmap_t customviewer_t::_global_popup_map; size_t customviewer_t::_global_popup_id = 0; //--------------------------------------------------------------------------- class py_simplecustview_t: public customviewer_t @@ -675,8 +608,8 @@ private: PyObject_CallMethod( py_self, (char *)S_ON_HINT, - PY_FMT64, - pyul_t(ln))); + PY_BV_SZ, + bvsz_t(ln))); PyW_ShowCbErr(S_ON_HINT); bool ok = py_result != NULL && PyTuple_Check(py_result.o) && PyTuple_Size(py_result.o) == 2; @@ -698,8 +631,8 @@ private: PyObject_CallMethod( py_self, (char *)S_ON_POPUP_MENU, - PY_FMT64, - pyul_t(menu_id))); + PY_BV_SZ, + bvsz_t(menu_id))); PyW_ShowCbErr(S_ON_POPUP_MENU); return py_result != NULL && PyObject_IsTrue(py_result.o); } @@ -776,7 +709,7 @@ public: PYW_GIL_CHECK_LOCKED_SCOPE(); if ( pl == NULL ) Py_RETURN_NONE; - return Py_BuildValue("(" PY_FMT64 "ii)", pyul_t(data.to_lineno(pl)), x, y); + return Py_BuildValue("(" PY_BV_SZ "ii)", bvsz_t(data.to_lineno(pl)), x, y); } //-------------------------------------------------------------------------- @@ -815,7 +748,7 @@ public: bool init(PyObject *py_link, const char *title) { // Already created? - if ( _form != NULL ) + if ( _cv != NULL ) return true; // Probe callbacks @@ -859,8 +792,7 @@ public: //-------------------------------------------------------------------------- bool show() { - // Form was closed, but object already linked? - if ( _form == NULL && py_last_link != NULL ) + if ( _cv == NULL && py_last_link != NULL ) { // Re-create the view (with same previous parameters) if ( !init(py_last_link, _title.c_str()) ) @@ -876,7 +808,7 @@ public: return false; twinpos_t p1, p2; - if ( !::readsel2(_cv, &p1, &p2) ) + if ( !::read_selection(_cv, &p1, &p2) ) return false; if ( y1 != NULL ) @@ -896,7 +828,9 @@ public: PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !get_selection(&x1, &y1, &x2, &y2) ) Py_RETURN_NONE; - return Py_BuildValue("(" PY_FMT64 PY_FMT64 PY_FMT64 PY_FMT64 ")", pyul_t(x1), pyul_t(y1), pyul_t(x2), pyul_t(y2)); + return Py_BuildValue( + "(" PY_BV_SZ PY_BV_SZ PY_BV_SZ PY_BV_SZ ")", + bvsz_t(x1), bvsz_t(y1), bvsz_t(x2), bvsz_t(y2)); } static py_simplecustview_t *get_this(PyObject *py_this) @@ -984,19 +918,6 @@ bool pyscv_is_focused(PyObject *py_this) return _this->is_focused(); } -void pyscv_clear_popup_menu(PyObject *py_this) -{ - DECL_THIS; - if ( _this != NULL ) - _this->clear_popup_menu(); -} - -size_t pyscv_add_popup_menu(PyObject *py_this, const char *title, const char *hotkey) -{ - DECL_THIS; - return _this == NULL ? 0 : _this->add_popup_menu(title, hotkey); -} - size_t pyscv_count(PyObject *py_this) { DECL_THIS; @@ -1123,17 +1044,10 @@ bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl) } //------------------------------------------------------------------------- -TForm *pyscv_get_tform(PyObject *py_this) +TWidget *pyscv_get_widget(PyObject *py_this) { DECL_THIS; - return _this == NULL ? NULL : _this->get_tform(); -} - -//------------------------------------------------------------------------- -TCustomControl *pyscv_get_tcustom_control(PyObject *py_this) -{ - DECL_THIS; - return _this == NULL ? NULL : _this->get_tcustom_control(); + return _this == NULL ? NULL : _this->get_widget(); } diff --git a/pywraps/py_kernwin_custview.py b/pywraps/py_kernwin_custview.py index 35c18ea..e738a0b 100644 --- a/pywraps/py_kernwin_custview.py +++ b/pywraps/py_kernwin_custview.py @@ -57,7 +57,7 @@ class simplecustviewer_t(object): def GetSelection(self): """ - Returns the selected area or None + Returns the selected range or None @return: - tuple(x1, y1, x2, y2) - None if no selection @@ -142,42 +142,17 @@ class simplecustviewer_t(object): def Jump(self, lineno, x=0, y=0): return _ida_kernwin.pyscv_jumpto(self.__this, lineno, x, y) - def AddPopupMenu(self, title, hotkey=""): - """ - 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 id of the registered popup menu item - """ - return _ida_kernwin.pyscv_add_popup_menu(self.__this, title, hotkey) - - def ClearPopupMenu(self): - """ - Clears all previously installed popup menu items. - Use this function if you're generating menu items on the fly (in the OnPopup() callback), - and before adding new items - """ - _ida_kernwin.pyscv_clear_popup_menu(self.__this) - def IsFocused(self): """Returns True if the current view is the focused view""" return _ida_kernwin.pyscv_is_focused(self.__this) - def GetTForm(self): + def GetWidget(self): """ - Return the TForm hosting this view. + Return the TWidget underlying this view. - @return: The TForm that hosts this view, or None. + @return: The TWidget underlying this view, or None. """ - return _ida_kernwin.pyscv_get_tform(self.__this) - - def GetTCustomControl(self): - """ - Return the TCustomControl underlying this view. - - @return: The TCustomControl underlying this view, or None. - """ - return _ida_kernwin.pyscv_get_tcustom_control(self.__this) + return _ida_kernwin.pyscv_get_widget(self.__this) diff --git a/pywraps/py_kernwin_idaview.hpp b/pywraps/py_kernwin_idaview.hpp index b2f5d8b..034ef46 100644 --- a/pywraps/py_kernwin_idaview.hpp +++ b/pywraps/py_kernwin_idaview.hpp @@ -24,40 +24,28 @@ bool py_idaview_t::Bind(PyObject *self) 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 ) + // Get the IDAView associated to this TWidget + TWidget *widget = find_widget(title.c_str()); + if ( widget == NULL ) return false; - // Get unique py_idaview_t associated to that tform + // Get unique py_idaview_t associated to that TWidget 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 + if ( !pycim_lookup_info.find_by_view((py_customidamemo_t**) &py_view, widget) ) { py_view = new py_idaview_t(); lookup_entry_t &e = pycim_lookup_info.new_entry(py_view); - pycim_lookup_info.commit(e, tform, v); + pycim_lookup_info.commit(e, widget); } // Finally, bind: // py_idaview_t <=> IDAViewWrapper - // py_idaview_t => TCustomControl - bool ok = py_view->bind(self, v); + // py_idaview_t => TWidget + bool ok = py_view->bind(self, widget); if ( ok ) { ok = py_view->collect_pyobject_callbacks(self); - if ( ok ) - py_view->install_custom_viewer_handlers(); - else + if ( !ok ) delete py_view; } return ok; diff --git a/pywraps/py_kernwin_idaview.py b/pywraps/py_kernwin_idaview.py index b009f57..244ef8f 100644 --- a/pywraps/py_kernwin_idaview.py +++ b/pywraps/py_kernwin_idaview.py @@ -3,23 +3,30 @@ #------------------------------------------------------------------------- # 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'. +class IDAViewWrapper(CustomIDAMemo): + """ + Deprecated. Use View_Hooks instead. - @param title: The title of the existing IDA view. E.g., 'IDA View-A' - """ + Because the lifecycle of an IDAView is not trivial to track (e.g., a user + might close, then re-open the same disassembly view), this wrapper doesn't + bring anything superior to the View_Hooks: quite the contrary, as the + latter is much more generic (and better maps IDA's internal model.) + """ + def __init__(self, title): + CustomIDAMemo.__init__(self) self._title = title def Bind(self): - return _ida_kernwin.pyidag_bind(self) + rc = _ida_kernwin.pyidag_bind(self) + if rc: + self.hook() + return rc def Unbind(self): - return _ida_kernwin.pyidag_unbind(self) + rc = _ida_kernwin.pyidag_unbind(self) + if rc: + self.unhook() + return rc # diff --git a/pywraps/py_kernwin_plgform.hpp b/pywraps/py_kernwin_plgform.hpp index 30bf74b..58621a3 100644 --- a/pywraps/py_kernwin_plgform.hpp +++ b/pywraps/py_kernwin_plgform.hpp @@ -7,18 +7,18 @@ class plgform_t { private: ref_t py_obj; - TForm *form; + TWidget *widget; - static int idaapi s_callback(void *ud, int notification_code, va_list va) + static ssize_t idaapi s_callback(void *ud, int notification_code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; plgform_t *_this = (plgform_t *)ud; - if ( notification_code == ui_tform_visible ) + if ( notification_code == ui_widget_visible ) { - TForm *form = va_arg(va, TForm *); - if ( form == _this->form ) + TWidget *widget = va_arg(va, TWidget *); + if ( widget == _this->widget ) { // Qt: QWidget* // G: HWND @@ -28,21 +28,21 @@ private: PyObject_CallMethod( _this->py_obj.o, (char *)S_ON_CREATE, "O", - PyCObject_FromVoidPtr(form, NULL))); + PyCObject_FromVoidPtr(widget, NULL))); PyW_ShowCbErr(S_ON_CREATE); } } - else if ( notification_code == ui_tform_invisible ) + else if ( notification_code == ui_widget_invisible ) { - TForm *form = va_arg(va, TForm *); - if ( form == _this->form ) + TWidget *widget = va_arg(va, TWidget *); + if ( widget == _this->widget ) { { newref_t py_result( PyObject_CallMethod( _this->py_obj.o, (char *)S_ON_CLOSE, "O", - PyCObject_FromVoidPtr(form, NULL))); + PyCObject_FromVoidPtr(widget, NULL))); PyW_ShowCbErr(S_ON_CLOSE); } _this->unhook(); @@ -53,8 +53,8 @@ private: void unhook() { - unhook_from_notification_point(HT_UI, s_callback, this); - form = NULL; + idapython_unhook_from_notification_point(HT_UI, s_callback, this); + widget = NULL; // Call DECREF at last, since it may trigger __del__ PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -62,24 +62,24 @@ private: } public: - plgform_t(): form(NULL) + plgform_t(): widget(NULL) { } bool show( - PyObject *obj, - const char *caption, - int options) + PyObject *obj, + const char *caption, + int options) { // Already displayed? - TForm *f = find_tform(caption); + TWidget *f = find_widget(caption); if ( f != NULL ) { // Our form? - if ( f == form ) + if ( f == widget ) { // Switch to it - switchto_tform(form, true); + activate_widget(widget, true); return true; } // Fail to create @@ -87,30 +87,27 @@ public: } // Create a form - form = create_tform(caption, NULL); - if ( form == NULL ) + widget = create_empty_widget(caption); + if ( widget == NULL ) return false; - if ( !hook_to_notification_point(HT_UI, s_callback, this) ) + if ( !idapython_hook_to_notification_point(HT_UI, s_callback, this) ) { - form = NULL; + widget = NULL; return false; } py_obj = borref_t(obj); - if ( is_idaq() ) - options |= FORM_QWIDGET; - - this->form = form; - open_tform(form, options); + this->widget = widget; + display_widget(widget, options); return true; } void close(int options = 0) { - if ( form != NULL ) - close_tform(form, options); + if ( widget != NULL ) + close_widget(widget, options); } static PyObject *create() @@ -135,18 +132,18 @@ static PyObject *plgform_new() } static bool plgform_show( - PyObject *py_link, - PyObject *py_obj, - const char *caption, - int options = FORM_TAB|FORM_MENU|FORM_RESTORE) + PyObject *py_link, + PyObject *py_obj, + const char *caption, + int options = WOPN_TAB|WOPN_MENU|WOPN_RESTORE) { DECL_PLGFORM; return plgform->show(py_obj, caption, options); } static void plgform_close( - PyObject *py_link, - int options) + PyObject *py_link, + int options) { DECL_PLGFORM; plgform->close(options); diff --git a/pywraps/py_kernwin_plgform.py b/pywraps/py_kernwin_plgform.py index a3d070b..8237655 100644 --- a/pywraps/py_kernwin_plgform.py +++ b/pywraps/py_kernwin_plgform.py @@ -7,19 +7,19 @@ class PluginForm(object): This form can be used to host additional controls. Please check the PyQt example. """ - FORM_MDI = 0x01 + WOPN_MDI = 0x01 """start by default as MDI (obsolete)""" - FORM_TAB = 0x02 + WOPN_TAB = 0x02 """attached by default to a tab""" - FORM_RESTORE = 0x04 + WOPN_RESTORE = 0x04 """restore state from desktop config""" - FORM_ONTOP = 0x08 + WOPN_ONTOP = 0x08 """form should be "ontop""" - FORM_MENU = 0x10 + WOPN_MENU = 0x10 """form must be listed in the windows menu (automatically set for all plugins)""" - FORM_CENTERED = 0x20 + WOPN_CENTERED = 0x20 """form will be centered on the screen""" - FORM_PERSIST = 0x40 + WOPN_PERSIST = 0x40 """form will persist until explicitly closed with Close()""" @@ -32,19 +32,19 @@ class PluginForm(object): def Show(self, caption, options = 0): """ - Creates the form if not was not created or brings to front if it was already created + Creates the form if not was not created or brings to front if it was already created @param caption: The form caption - @param options: One of PluginForm.FORM_ constants + @param options: One of PluginForm.WOPN_ constants """ - options |= PluginForm.FORM_TAB|PluginForm.FORM_MENU|PluginForm.FORM_RESTORE + options |= PluginForm.WOPN_TAB|PluginForm.WOPN_MENU|PluginForm.WOPN_RESTORE return _ida_kernwin.plgform_show(self.__clink__, self, caption, options) @staticmethod def FormToPyQtWidget(form, ctx = sys.modules['__main__']): """ - Use this method to convert a TForm* to a QWidget to be used by PyQt + Use this method to convert a TWidget* to a QWidget to be used by PyQt @param ctx: Context. Reference to a module that already imported SIP and QtGui modules """ @@ -64,7 +64,7 @@ class PluginForm(object): @staticmethod def FormToPySideWidget(form, ctx = sys.modules['__main__']): """ - Use this method to convert a TForm* to a QWidget to be used by PySide + Use this method to convert a TWidget* to a QWidget to be used by PySide @param ctx: Context. Reference to a module that already imported QtGui module """ @@ -107,24 +107,38 @@ class PluginForm(object): """ Closes the form. - @param options: Close options (FORM_SAVE, FORM_NO_CONTEXT, ...) + @param options: Close options (WCLS_SAVE, WCLS_NO_CONTEXT, ...) @return: None """ return _ida_kernwin.plgform_close(self.__clink__, options) - FORM_SAVE = 0x1 + WCLS_SAVE = 0x1 """Save state in desktop config""" - FORM_NO_CONTEXT = 0x2 + WCLS_NO_CONTEXT = 0x2 """Don't change the current context (useful for toolbars)""" - FORM_DONT_SAVE_SIZE = 0x4 + WCLS_DONT_SAVE_SIZE = 0x4 """Don't save size of the window""" - FORM_CLOSE_LATER = 0x8 + WCLS_CLOSE_LATER = 0x8 """This flag should be used when Close() is called from an event handler""" # plg = PluginForm() plg.Show("This is it") + +# +PluginForm.FORM_MDI = PluginForm.WOPN_MDI +PluginForm.FORM_TAB = PluginForm.WOPN_TAB +PluginForm.FORM_RESTORE = PluginForm.WOPN_RESTORE +PluginForm.FORM_ONTOP = PluginForm.WOPN_ONTOP +PluginForm.FORM_MENU = PluginForm.WOPN_MENU +PluginForm.FORM_CENTERED = PluginForm.WOPN_CENTERED +PluginForm.FORM_PERSIST = PluginForm.WOPN_PERSIST +PluginForm.FORM_SAVE = PluginForm.WCLS_SAVE +PluginForm.FORM_NO_CONTEXT = PluginForm.WCLS_NO_CONTEXT +PluginForm.FORM_DONT_SAVE_SIZE = PluginForm.WCLS_DONT_SAVE_SIZE +PluginForm.FORM_CLOSE_LATER = PluginForm.WCLS_CLOSE_LATER +# diff --git a/pywraps/py_kernwin_viewhooks.hpp b/pywraps/py_kernwin_viewhooks.hpp new file mode 100644 index 0000000..a2df757 --- /dev/null +++ b/pywraps/py_kernwin_viewhooks.hpp @@ -0,0 +1,51 @@ + +// + +//--------------------------------------------------------------------------- +// View hooks +//--------------------------------------------------------------------------- +ssize_t idaapi View_Callback(void *ud, int notification_code, va_list va); +class View_Hooks +{ +public: + virtual ~View_Hooks() { unhook(); } + + bool hook() + { + return idapython_hook_to_notification_point(HT_VIEW, View_Callback, this); + } + bool unhook() + { + return idapython_unhook_from_notification_point(HT_VIEW, View_Callback, this); + } + + // hookgenVIEW:methods +}; +// + + +// +//--------------------------------------------------------------------------- +ssize_t idaapi View_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 View_Hooks *proxy = (class View_Hooks *)ud; + int ret = 0; + try + { + switch ( notification_code ) + { + // hookgenVIEW:notifications + } + } + catch (Swig::DirectorException &e) + { + msg("Exception in View Hook function: %s\n", e.getMessage()); + PYW_GIL_CHECK_LOCKED_SCOPE(); + if ( PyErr_Occurred() ) + PyErr_Print(); + } + return 0; +} +// diff --git a/pywraps/py_kernwin_viewhooks.py b/pywraps/py_kernwin_viewhooks.py new file mode 100644 index 0000000..6378a4b --- /dev/null +++ b/pywraps/py_kernwin_viewhooks.py @@ -0,0 +1,214 @@ +# +# ----------------------------------------------------------------------- +# CustomIDAMemo +# ----------------------------------------------------------------------- +class CustomIDAMemo(View_Hooks): + def __init__(self): + View_Hooks.__init__(self) + + def _graph_item_tuple(self, ve): + item = None + if ve.rtype in [TCCRT_GRAPH, TCCRT_PROXIMITY]: + item = ve.location.item + if item is not None: + if item.is_node: + return (item.node,) + else: + return (item.elp.e.src, item.elp.e.dst) + else: + return () + + @staticmethod + def _dummy_cb(*args): + pass + + def _get_cb(self, view, cb_name): + cb = CustomIDAMemo._dummy_cb + if view == self.GetWidget(): + cb = getattr(self, cb_name, cb) + return cb + + def _get_cb_arity(self, cb): + from inspect import getargspec + return len(getargspec(cb).args) + + def view_activated(self, view): + return self._get_cb(view, "OnViewActivated")() + + def view_deactivated(self, view): + return self._get_cb(view, "OnViewDeactivated")() + + def view_keydown(self, view, key, state): + return self._get_cb(view, "OnViewKeydown")(key, state) + + def view_click(self, view, ve): + cb = self._get_cb(view, "OnViewClick") + if cb != CustomIDAMemo._dummy_cb: + arity = self._get_cb_arity(cb) + args = [ve.x, ve.y, ve.state] + if arity >= 5: + args.append(ve.button) + if arity >= 6: + args.append(ve.renderer_pos) + return cb(*tuple(args)) + + def view_dblclick(self, view, ve): + cb = self._get_cb(view, "OnViewDblclick") + if cb != CustomIDAMemo._dummy_cb: + arity = self._get_cb_arity(cb) + args = [ve.x, ve.y, ve.state] + if arity >= 5: + args.append(ve.renderer_pos) + return cb(*tuple(args)) + + def view_curpos(self, view, *args): + return self._get_cb(view, "OnViewCurpos")() + + def view_close(self, view, *args): + rc = self._get_cb(view, "OnClose")() + if view == self.GetWidget(): + ida_idaapi.pycim_view_close(self) + return rc + + def view_switched(self, view, rt): + return self._get_cb(view, "OnViewSwitched")(rt) + + def view_mouse_over(self, view, ve): + cb = self._get_cb(view, "OnViewMouseOver") + if cb != CustomIDAMemo._dummy_cb: + arity = self._get_cb_arity(cb) + gitpl = self._graph_item_tuple(ve) + args = [ve.x, ve.y, ve.state, len(gitpl), gitpl] + if arity >= 7: + args.append(ve.renderer_pos) + return cb(*tuple(args)) + + def view_loc_changed(self, view, now, was): + return self._get_cb(view, "OnViewLocationChanged")(now, was) + + def view_mouse_moved(self, view, ve): + cb = self._get_cb(view, "OnViewMouseMoved") + if cb != CustomIDAMemo._dummy_cb: + gitpl = self._graph_item_tuple(ve) + return cb(ve.x, ve.y, ve.state, len(gitpl), gitpl, ve.renderer_pos) + + # End of hooks->wrapper trampolines + + + def Refresh(self): + """ + Refreshes the view. 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 GetWidget(self): + """ + Return the TWidget underlying this view. + + @return: The TWidget underlying this view, or None. + """ + return ida_idaapi.pycim_get_widget(self) + +# ---------------------------------------------------------------------- +# bw-compat/deprecated. You shouldn't rely on this in new code +import ida_idaapi +ida_idaapi.CustomIDAMemo = CustomIDAMemo + +# diff --git a/pywraps/py_lines.hpp b/pywraps/py_lines.hpp index 21ae2a1..f7a930f 100644 --- a/pywraps/py_lines.hpp +++ b/pywraps/py_lines.hpp @@ -5,19 +5,18 @@ //------------------------------------------------------------------------ static PyObject *py_get_user_defined_prefix = NULL; static void idaapi s_py_get_user_defined_prefix( - ea_t ea, - int lnnum, - int indent, - const char *line, - char *buf, - size_t bufsize) + qstring *buf, + ea_t ea, + int lnnum, + int indent, + const char *line) { PYW_GIL_GET; newref_t py_ret( PyObject_CallFunction( py_get_user_defined_prefix, - PY_FMT64 "iis" PY_FMT64, - ea, lnnum, indent, line, bufsize)); + PY_BV_EA "iis" PY_BV_SZ, + bvea_t(ea), lnnum, indent, line)); // Error? Display it // No error? Copy the buffer @@ -27,9 +26,8 @@ static void idaapi s_py_get_user_defined_prefix( char *py_str; if ( PyString_AsStringAndSize(py_ret.o, &py_str, &py_len) != -1 ) { - memcpy(buf, py_str, qmin(bufsize, py_len)); - if ( py_len < bufsize ) - buf[py_len] = '\0'; + buf->qclear(); + buf->append(py_str, py_len); } } } @@ -56,7 +54,6 @@ def set_user_defined_prefix(width, callback): indent and is used for instruction itself. see explanations for printf_line() line - the line to be generated. the line usually contains color tags this argument can be examined to decide whether to generated the prefix - bufsize- the maximum allowed size of the output buffer It returns a buffer of size < bufsize In order to remove the callback before unloading the plugin, specify the width = 0 or the callback = None @@ -103,9 +100,7 @@ def tag_remove(colstr): """ Remove color escape sequences from a string @param colstr: the colored string with embedded tags - @return: - None on failure - or a new string w/o the tags + @return: a new string w/o the tags """ pass # @@ -113,41 +108,18 @@ def tag_remove(colstr): PyObject *py_tag_remove(const char *instr) { PYW_GIL_CHECK_LOCKED_SCOPE(); - size_t sz = strlen(instr); - // Can't call tag_remove() with a size of 0; debug builds will INTERR 1270 - if ( sz > 0 ) - { - 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 - { - return PyString_FromString(""); - } + qstring qbuf; + tag_remove(&qbuf, instr); + return PyString_FromString(qbuf.c_str()); } //------------------------------------------------------------------------- PyObject *py_tag_addr(ea_t ea) { - char buf[100]; - tag_addr(buf, buf + sizeof(buf), ea); + qstring tag; + tag_addr(&tag, ea); PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyString_FromString(buf); + return PyString_FromString(tag.begin()); } //------------------------------------------------------------------------- @@ -187,35 +159,32 @@ def generate_disassembly(ea, max_lines, as_stack, notags): # */ PyObject *py_generate_disassembly( - ea_t ea, - int max_lines, - bool as_stack, - bool notags) + ea_t ea, + int max_lines, + bool as_stack, + bool notags) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( max_lines <= 0 ) Py_RETURN_NONE; qstring qbuf; - char **lines = new char *[max_lines]; + qstrvec_t lines; int lnnum; - int nlines = generate_disassembly(ea, lines, max_lines, &lnnum, as_stack); + int nlines = generate_disassembly(&lines, &lnnum, ea, max_lines, as_stack); newref_t py_tuple(PyTuple_New(nlines)); for ( int i=0; i < nlines; i++ ) { - const char *s = lines[i]; - size_t line_len = strlen(s); + const qstring &l = lines[i]; + const char *s = l.c_str(); if ( notags ) { - qbuf.resize(line_len+5); - tag_remove(s, &qbuf[0], line_len); - s = (const char *)&qbuf[0]; + tag_remove(&qbuf, l); + s = qbuf.c_str(); } PyTuple_SetItem(py_tuple.o, i, PyString_FromString(s)); - qfree(lines[i]); } - delete [] lines; return Py_BuildValue("(iO)", lnnum, py_tuple.o); } // diff --git a/pywraps/py_lines.py b/pywraps/py_lines.py index 158c07c..499c914 100644 --- a/pywraps/py_lines.py +++ b/pywraps/py_lines.py @@ -33,3 +33,9 @@ def COLSTR(str, tag): return SCOLOR_ON + tag + str + SCOLOR_OFF + tag # + +# +COLOR_UTF8=COLOR_ADDR+10 # old value of COLOR_UTF8; shouldn't trigger anything +add_long_cmt=add_extra_cmt +describe=add_extra_line +# diff --git a/pywraps/py_loader.hpp b/pywraps/py_loader.hpp index 99493b9..cc970ea 100644 --- a/pywraps/py_loader.hpp +++ b/pywraps/py_loader.hpp @@ -21,7 +21,7 @@ def mem2base(mem, ea, fpos): pass # */ -static int py_mem2base(PyObject *py_mem, ea_t ea, long fpos = -1) +static int py_mem2base(PyObject *py_mem, ea_t ea, qoff64_t fpos = -1) { Py_ssize_t len; char *buf; diff --git a/pywraps/py_loader.py b/pywraps/py_loader.py new file mode 100644 index 0000000..00298b1 --- /dev/null +++ b/pywraps/py_loader.py @@ -0,0 +1,10 @@ + +# +NEF_TIGHT=0 +@bc695redef +def save_database(outfile, flags=0): + if isinstance(flags, bool): + flags = DBFL_KILL if flags else 0 + return _ida_loader.save_database(outfile, flags) +save_database_ex=save_database +# diff --git a/pywraps/py_moves.hpp b/pywraps/py_moves.hpp new file mode 100644 index 0000000..098974c --- /dev/null +++ b/pywraps/py_moves.hpp @@ -0,0 +1,5 @@ +#ifndef __PYMOVES__ +#define __PYMOVES__ +// +// +#endif diff --git a/pywraps/py_nalt.hpp b/pywraps/py_nalt.hpp index 28744be..49b4b49 100644 --- a/pywraps/py_nalt.hpp +++ b/pywraps/py_nalt.hpp @@ -18,7 +18,7 @@ static int idaapi py_import_enum_cb( { // If no name, try to get the name associated with the 'ea'. It may be coming from IDS qstring name_buf; - if ( name == NULL && get_true_name(&name_buf, ea) > 0 ) + if ( name == NULL && get_name(&name_buf, ea) > 0 ) name = name_buf.begin(); PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -28,8 +28,8 @@ static int idaapi py_import_enum_cb( else py_name = newref_t(PyString_FromString(name)); - newref_t py_ord(Py_BuildValue(PY_FMT64, pyul_t(ord))); - newref_t py_ea(Py_BuildValue(PY_FMT64, pyul_t(ea))); + newref_t py_ord(Py_BuildValue(PY_BV_UVAL, bvuval_t(ord))); + newref_t py_ea(Py_BuildValue(PY_BV_EA, bvea_t(ea))); newref_t py_result( PyObject_CallFunctionObjArgs( (PyObject *)param, @@ -57,31 +57,31 @@ def get_import_module_name(path, fname, callback): static PyObject *py_get_import_module_name(int mod_index) { PYW_GIL_CHECK_LOCKED_SCOPE(); - char buf[MAXSTR]; - if ( !get_import_module_name(mod_index, buf, sizeof(buf)) ) + qstring qbuf; + if ( !get_import_module_name(&qbuf, mod_index) ) Py_RETURN_NONE; - return PyString_FromString(buf); + return PyString_FromStringAndSize(qbuf.begin(), qbuf.length()); } //------------------------------------------------------------------------- /* # -def get_switch_info_ex(ea): +def get_switch_info(ea): """ - Returns the a switch_info_ex_t structure containing the information about the switch. + Returns the a switch_info_t structure containing the information about the switch. Please refer to the SDK sample 'uiswitch' - @return: None or switch_info_ex_t instance + @return: None or switch_info_t instance """ pass # */ -PyObject *py_get_switch_info_ex(ea_t ea) +PyObject *py_get_switch_info(ea_t ea) { - switch_info_ex_t *ex = new switch_info_ex_t(); + switch_info_t *ex = new switch_info_t(); ref_t py_obj; PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( ::get_switch_info_ex(ea, ex, sizeof(switch_info_ex_t)) <= 0 + if ( ::get_switch_info(ex, ea) <= 0 || (py_obj = create_linked_class_instance(S_IDA_NALT_MODNAME, S_PY_SWIEX_CLSNAME, ex)) == NULL ) { delete ex; @@ -94,7 +94,7 @@ PyObject *py_get_switch_info_ex(ea_t ea) //------------------------------------------------------------------------- /* # -def set_switch_info_ex(ea, switch_info_ex): +def set_switch_info(ea, switch_info): """ Saves the switch information in the database Please refer to the SDK sample 'uiswitch' @@ -103,29 +103,29 @@ def set_switch_info_ex(ea, switch_info_ex): pass # */ -bool py_set_switch_info_ex(ea_t ea, PyObject *py_swi) +bool py_set_switch_info(ea_t ea, PyObject *py_swi) { - switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + switch_info_t *swi = switch_info_t_get_clink(py_swi); if ( swi == NULL ) return false; - set_switch_info_ex(ea, swi); + set_switch_info(ea, *swi); return true; } //------------------------------------------------------------------------- /* # -def del_switch_info_ex(ea): +def del_switch_info(ea): """ Deletes stored switch information """ pass # */ -void py_del_switch_info_ex(ea_t ea) +void py_del_switch_info(ea_t ea) { - del_switch_info_ex(ea); + del_switch_info(ea); } //------------------------------------------------------------------------- @@ -152,28 +152,28 @@ static int py_enum_import_names(int mod_index, PyObject *py_cb) } //------------------------------------------------------------------------- -static PyObject *switch_info_ex_t_create() +static PyObject *switch_info_t_create() { - switch_info_ex_t *inst = new switch_info_ex_t(); + switch_info_t *inst = new switch_info_t(); PYW_GIL_CHECK_LOCKED_SCOPE(); return PyCObject_FromVoidPtr(inst, NULL); } //--------------------------------------------------------------------------- -static bool switch_info_ex_t_destroy(PyObject *py_obj) +static bool switch_info_t_destroy(PyObject *py_obj) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyCObject_Check(py_obj) ) return false; - switch_info_ex_t *inst = (switch_info_ex_t *) PyCObject_AsVoidPtr(py_obj); + switch_info_t *inst = (switch_info_t *) PyCObject_AsVoidPtr(py_obj); delete inst; return true; } -static bool switch_info_ex_t_assign(PyObject *self, PyObject *other) +static bool switch_info_t_assign(PyObject *self, PyObject *other) { - switch_info_ex_t *lhs = switch_info_ex_t_get_clink(self); - switch_info_ex_t *rhs = switch_info_ex_t_get_clink(other); + switch_info_t *lhs = switch_info_t_get_clink(self); + switch_info_t *rhs = switch_info_t_get_clink(other); if ( lhs == NULL || rhs == NULL ) return false; @@ -185,236 +185,219 @@ static bool switch_info_ex_t_assign(PyObject *self, PyObject *other) // Auto generated - begin // -static PyObject *switch_info_ex_t_get_regdtyp(PyObject *self) +static PyObject *switch_info_t_get_regdtype(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue("b", (char)link->regdtyp); + return Py_BuildValue("b", (char)link->regdtype); } -static void switch_info_ex_t_set_regdtyp(PyObject *self, PyObject *value) +static void switch_info_t_set_regdtype(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); - link->regdtyp = (char)PyInt_AsLong(value); + link->regdtype = (char)PyInt_AsLong(value); } -static PyObject *switch_info_ex_t_get_flags2(PyObject *self) +static PyObject *switch_info_t_get_flags(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue("i", link->flags2); + return Py_BuildValue("i", link->flags); } -static void switch_info_ex_t_set_flags2(PyObject *self, PyObject *value) +static void switch_info_t_set_flags(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); - link->flags2 = (int)PyInt_AsLong(value); + link->flags = (uint32)PyInt_AsLong(value); } -static PyObject *switch_info_ex_t_get_jcases(PyObject *self) +static PyObject *switch_info_t_get_jcases(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; return Py_BuildValue("i", link->jcases); } -static void switch_info_ex_t_set_jcases(PyObject *self, PyObject *value) +static void switch_info_t_set_jcases(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); link->jcases = (int)PyInt_AsLong(value); } -static PyObject *switch_info_ex_t_get_regnum(PyObject *self) +static PyObject *switch_info_t_get_regnum(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; return Py_BuildValue("i", (int)link->regnum); } -static void switch_info_ex_t_set_regnum(PyObject *self, PyObject *value) +static void switch_info_t_set_regnum(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); link->regnum = (int)PyInt_AsLong(value); } -static PyObject *switch_info_ex_t_get_flags(PyObject *self) +static PyObject *switch_info_t_get_ncases(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("H", (ushort)link->flags); -} -static void switch_info_ex_t_set_flags(PyObject *self, PyObject *value) -{ - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); - if ( link == NULL ) - return; - PYW_GIL_CHECK_LOCKED_SCOPE(); - link->flags = (uint16)PyInt_AsLong(value); -} - -static PyObject *switch_info_ex_t_get_ncases(PyObject *self) -{ - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; return Py_BuildValue("H", (uint16)link->ncases); } -static void switch_info_ex_t_set_ncases(PyObject *self, PyObject *value) +static void switch_info_t_set_ncases(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); link->ncases = (ushort)PyInt_AsLong(value); } -static PyObject *switch_info_ex_t_get_defjump(PyObject *self) +static PyObject *switch_info_t_get_defjump(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->defjump); + return Py_BuildValue(PY_BV_EA, (bvea_t)link->defjump); } -static void switch_info_ex_t_set_defjump(PyObject *self, PyObject *value) +static void switch_info_t_set_defjump(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); uint64 v(0); PyW_GetNumber(value, &v); - link->defjump = (pyul_t)v; + link->defjump = ea_t(v); } -static PyObject *switch_info_ex_t_get_jumps(PyObject *self) +static PyObject *switch_info_t_get_jumps(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->jumps); + return Py_BuildValue(PY_BV_EA, (bvea_t)link->jumps); } -static void switch_info_ex_t_set_jumps(PyObject *self, PyObject *value) +static void switch_info_t_set_jumps(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; PYW_GIL_CHECK_LOCKED_SCOPE(); uint64 v(0); PyW_GetNumber(value, &v); - link->jumps = (pyul_t)v; + link->jumps = ea_t(v); } -static PyObject *switch_info_ex_t_get_elbase(PyObject *self) +static PyObject *switch_info_t_get_elbase(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->elbase); + return Py_BuildValue(PY_BV_EA, (bvea_t)link->elbase); } -static void switch_info_ex_t_set_elbase(PyObject *self, PyObject *value) +static void switch_info_t_set_elbase(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; uint64 v(0); PYW_GIL_CHECK_LOCKED_SCOPE(); PyW_GetNumber(value, &v); - link->elbase = (pyul_t)v; + link->elbase = ea_t(v); } -static PyObject *switch_info_ex_t_get_startea(PyObject *self) +static PyObject *switch_info_t_get_startea(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->startea); + return Py_BuildValue(PY_BV_EA, (bvea_t)link->startea); } -static void switch_info_ex_t_set_startea(PyObject *self, PyObject *value) +static void switch_info_t_set_startea(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; uint64 v(0); PYW_GIL_CHECK_LOCKED_SCOPE(); PyW_GetNumber(value, &v); - link->startea = (pyul_t)v; + link->startea = ea_t(v); } -static PyObject *switch_info_ex_t_get_custom(PyObject *self) +static PyObject *switch_info_t_get_custom(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->custom); + return Py_BuildValue(PY_BV_UVAL, (bvuval_t)link->custom); } -static void switch_info_ex_t_set_custom(PyObject *self, PyObject *value) +static void switch_info_t_set_custom(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; uint64 v(0); PYW_GIL_CHECK_LOCKED_SCOPE(); PyW_GetNumber(value, &v); - link->custom = (pyul_t)v; + link->custom = uval_t(v); } -static PyObject *switch_info_ex_t_get_ind_lowcase(PyObject *self) +static PyObject *switch_info_t_get_ind_lowcase(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->ind_lowcase); + return Py_BuildValue(PY_BV_SVAL, (bvsval_t)link->ind_lowcase); } -static void switch_info_ex_t_set_ind_lowcase(PyObject *self, PyObject *value) +static void switch_info_t_set_ind_lowcase(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; uint64 v(0); PYW_GIL_CHECK_LOCKED_SCOPE(); PyW_GetNumber(value, &v); - link->ind_lowcase = (pyul_t)v; + link->ind_lowcase = sval_t(v); } -static PyObject *switch_info_ex_t_get_values_lowcase(PyObject *self) +static PyObject *switch_info_t_get_values_lowcase(PyObject *self) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->values); + return Py_BuildValue(PY_BV_EA, (bvea_t)link->values); } -static void switch_info_ex_t_set_values_lowcase(PyObject *self, PyObject *value) +static void switch_info_t_set_values_lowcase(PyObject *self, PyObject *value) { - switch_info_ex_t *link = switch_info_ex_t_get_clink(self); + switch_info_t *link = switch_info_t_get_clink(self); if ( link == NULL ) return; uint64 v(0); PYW_GIL_CHECK_LOCKED_SCOPE(); PyW_GetNumber(value, &v); - link->values = (pyul_t)v; + link->values = ea_t(v); } // diff --git a/pywraps/py_nalt.py b/pywraps/py_nalt.py index 08e323b..b28f7ec 100644 --- a/pywraps/py_nalt.py +++ b/pywraps/py_nalt.py @@ -3,23 +3,36 @@ import _ida_idaapi SWI_SPARSE = 0x1 """sparse switch ( value table present ) otherwise lowcase present""" + SWI_V32 = 0x2 """32-bit values in table""" + SWI_J32 = 0x4 """32-bit jump offsets""" + SWI_VSPLIT = 0x8 """value table is split (only for 32-bit values)""" + SWI_DEFAULT = 0x10 """default case is present""" -SWI_END_IN_TBL = 0x20 -"""switchend in table (default entry)""" + +SWI_DEF_IN_TBL = 0x20 +"""default case is an entry in the jump table. +This flag is only applicable in the case of a sparse +nonindirect switch (i.e. a switch with a values table). + == + 1. +The default case entry is the last one in the table +(or the first one in the case of an inversed jump table).""" + SWI_JMP_INV = 0x40 """jumptable is inversed (last entry is for first entry in values table)""" + SWI_SHIFT_MASK = 0x180 """use formula (element*shift + elbase) to find jump targets""" SWI_ELBASE = 0x200 """elbase is present (if not and shift!=0, endof(jumpea) is used)""" + SWI_JSIZE = 0x400 """jump offset expansion bit""" @@ -33,35 +46,48 @@ SWI_SIGNED = 0x2000 """jump table entries are signed""" SWI_CUSTOM = 0x4000 -"""custom jump table - ph.create_switch_xrefs will be called to create code xrefs for the table. it must return 2. custom jump table must be created by the module""" +"""custom jump table. +\ph{create_switch_xrefs} will be called to create code xrefs for the +table. Custom jump table must be created by the module +(see also #SWI_STDTBL)""" -SWI_EXTENDED = 0x8000 -"""this is switch_info_ex_t""" - -SWI2_INDIRECT = 0x0001 +SWI_INDIRECT = 0x00010000 """value table elements are used as indexes into the jump table""" -SWI2_SUBTRACT = 0x0002 + +SWI_SUBTRACT = 0x00020000 """table values are subtracted from the elbase instead of being addded""" +SWI_HXNOLOWCASE = 0x00040000 +"""lowcase value should not be used by the decompiler (internal flag)""" + +SWI_STDTBL = 0x00080000 +"""custom jump table with standard table formatting. +ATM IDA doesn't use SWI_CUSTOM for switches with standard +table formatting. So this flag can be considered as obsolete.""" + +SWI_DEFRET = 0x00100000 +"""return in the default case (defjump==BADADDR)""" + # -------------------------------------------------------------------------- -class switch_info_ex_t(ida_idaapi.py_clinked_object_t): +class switch_info_t(ida_idaapi.py_clinked_object_t): def __init__(self, lnk = None): ida_idaapi.py_clinked_object_t.__init__(self, lnk) + self.bc695_api = False def _create_clink(self): - return _ida_nalt.switch_info_ex_t_create() + return _ida_nalt.switch_info_t_create() def _del_clink(self, lnk): - return _ida_nalt.switch_info_ex_t_destroy(lnk) + return _ida_nalt.switch_info_t_destroy(lnk) def assign(self, other): - return _ida_nalt.switch_info_ex_t_assign(self, other) + return _ida_nalt.switch_info_t_assign(self, other) def is_indirect(self): - return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_INDIRECT) != 0 + return (self.flags & SWI_INDIRECT) != 0 def is_subtract(self): - return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_SUBTRACT) != 0 + return (self.flags & SWI_SUBTRACT) != 0 def get_jtable_size(self): return self.jcases if self.is_indirect() else self.ncases @@ -71,7 +97,7 @@ class switch_info_ex_t(ida_idaapi.py_clinked_object_t): def set_expr(self, r, dt): self.regnum = r - self.regdtyp = dt + self.regdtype = dt def get_shift(self): return (self.flags & SWI_SHIFT_MASK) >> 7 @@ -113,67 +139,62 @@ class switch_info_ex_t(ida_idaapi.py_clinked_object_t): # # Autogenerated # - def __get_regdtyp__(self): - return _ida_nalt.switch_info_ex_t_get_regdtyp(self) - def __set_regdtyp__(self, v): - _ida_nalt.switch_info_ex_t_set_regdtyp(self, v) - def __get_flags2__(self): - return _ida_nalt.switch_info_ex_t_get_flags2(self) - def __set_flags2__(self, v): - _ida_nalt.switch_info_ex_t_set_flags2(self, v) + def __get_regdtype__(self): + return _ida_nalt.switch_info_t_get_regdtype(self) + def __set_regdtype__(self, v): + _ida_nalt.switch_info_t_set_regdtype(self, v) def __get_jcases__(self): - return _ida_nalt.switch_info_ex_t_get_jcases(self) + return _ida_nalt.switch_info_t_get_jcases(self) def __set_jcases__(self, v): - _ida_nalt.switch_info_ex_t_set_jcases(self, v) + _ida_nalt.switch_info_t_set_jcases(self, v) def __get_regnum__(self): - return _ida_nalt.switch_info_ex_t_get_regnum(self) + return _ida_nalt.switch_info_t_get_regnum(self) def __set_regnum__(self, v): - _ida_nalt.switch_info_ex_t_set_regnum(self, v) + _ida_nalt.switch_info_t_set_regnum(self, v) def __get_flags__(self): - return _ida_nalt.switch_info_ex_t_get_flags(self) + return _ida_nalt.switch_info_t_get_flags(self) def __set_flags__(self, v): - _ida_nalt.switch_info_ex_t_set_flags(self, v) + _ida_nalt.switch_info_t_set_flags(self, v) def __get_ncases__(self): - return _ida_nalt.switch_info_ex_t_get_ncases(self) + return _ida_nalt.switch_info_t_get_ncases(self) def __set_ncases__(self, v): - _ida_nalt.switch_info_ex_t_set_ncases(self, v) + _ida_nalt.switch_info_t_set_ncases(self, v) def __get_defjump__(self): - return _ida_nalt.switch_info_ex_t_get_defjump(self) + return _ida_nalt.switch_info_t_get_defjump(self) def __set_defjump__(self, v): - _ida_nalt.switch_info_ex_t_set_defjump(self, v) + _ida_nalt.switch_info_t_set_defjump(self, v) def __get_jumps__(self): - return _ida_nalt.switch_info_ex_t_get_jumps(self) + return _ida_nalt.switch_info_t_get_jumps(self) def __set_jumps__(self, v): - _ida_nalt.switch_info_ex_t_set_jumps(self, v) + _ida_nalt.switch_info_t_set_jumps(self, v) def __get_elbase__(self): - return _ida_nalt.switch_info_ex_t_get_elbase(self) + return _ida_nalt.switch_info_t_get_elbase(self) def __set_elbase__(self, v): - _ida_nalt.switch_info_ex_t_set_elbase(self, v) + _ida_nalt.switch_info_t_set_elbase(self, v) def __get_startea__(self): - return _ida_nalt.switch_info_ex_t_get_startea(self) + return _ida_nalt.switch_info_t_get_startea(self) def __set_startea__(self, v): - _ida_nalt.switch_info_ex_t_set_startea(self, v) + _ida_nalt.switch_info_t_set_startea(self, v) def __get_custom__(self): - return _ida_nalt.switch_info_ex_t_get_custom(self) + return _ida_nalt.switch_info_t_get_custom(self) def __set_custom__(self, v): - _ida_nalt.switch_info_ex_t_set_custom(self, v) + _ida_nalt.switch_info_t_set_custom(self, v) def __get_ind_lowcase__(self): - return _ida_nalt.switch_info_ex_t_get_ind_lowcase(self) + return _ida_nalt.switch_info_t_get_ind_lowcase(self) def __set_ind_lowcase__(self, v): - _ida_nalt.switch_info_ex_t_set_ind_lowcase(self, v) + _ida_nalt.switch_info_t_set_ind_lowcase(self, v) def __get_values_lowcase__(self): - return _ida_nalt.switch_info_ex_t_get_values_lowcase(self) + return _ida_nalt.switch_info_t_get_values_lowcase(self) def __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__) + _ida_nalt.switch_info_t_set_values_lowcase(self, v) + regdtype = property(__get_regdtype__, __set_regdtype__) + """size of the switch expression register as dtype""" jcases = property(__get_jcases__, __set_jcases__) - """number of entries in the jump table (SWI2_INDIRECT)""" + """number of entries in the jump table (SWI_INDIRECT)""" regnum = property(__get_regnum__, __set_regnum__) """the switch expression as a register number""" flags = property(__get_flags__, __set_flags__) - """the switch expression as a register number""" + """switch info flags""" ncases = property(__get_ncases__, __set_ncases__) """number of cases (excluding default)""" defjump = property(__get_defjump__, __set_defjump__) @@ -191,3 +212,110 @@ class switch_info_ex_t(ida_idaapi.py_clinked_object_t): lowcase = property(__get_values_lowcase__, __set_values_lowcase__) # + +# +ASCSTR_LAST=7 +ASCSTR_LEN2=STRTYPE_LEN2 +ASCSTR_LEN4=STRTYPE_LEN4 +ASCSTR_PASCAL=STRTYPE_PASCAL +ASCSTR_TERMCHR=STRTYPE_TERMCHR +ASCSTR_ULEN2=STRTYPE_LEN2_16 +ASCSTR_ULEN4=STRTYPE_LEN4_16 +ASCSTR_UNICODE=STRTYPE_C_16 +ASCSTR_UTF16=STRTYPE_C_16 +ASCSTR_UTF32=STRTYPE_C_32 +REF_VHIGH=V695_REF_VHIGH +REF_VLOW=V695_REF_VLOW +SWI_END_IN_TBL=SWI_DEF_IN_TBL +SWI_EXTENDED=0x8000 +SWI2_INDIRECT=SWI_INDIRECT >> 16 +SWI2_SUBTRACT=SWI_SUBTRACT >> 16 +import ida_netnode +RIDX_AUTO_PLUGINS=ida_netnode.BADNODE +change_encoding_name=rename_encoding +@bc695redef +def del_tinfo2(ea, n=None): + if n is not None: + return del_op_tinfo(ea, n) + else: + return del_tinfo(ea) +get_encodings_count=get_encoding_qty +def get_op_tinfo(*args): + import ida_typeinf + if isinstance(args[2], ida_typeinf.tinfo_t): # 6.95: ea, n, tinfo_t + ea, n, tif = args + else: # 7.00: tinfo_t, ea, n + tif, ea, n = args + return _ida_nalt.get_op_tinfo(tif, ea, n) +get_op_tinfo2=get_op_tinfo +@bc695redef +def is_unicode(strtype): + return (strtype & STRWIDTH_MASK) > 0 +set_op_tinfo2=set_op_tinfo +set_tinfo2=set_tinfo +switch_info_t.regdtyp = switch_info_t.regdtype +def get_tinfo(*args): + import ida_typeinf + if isinstance(args[1], ida_typeinf.tinfo_t): # 6.95: ea, tinfo_t + ea, tif = args + else: # 7.00: tinfo_t, ea + tif, ea = args + return _ida_nalt.get_tinfo(tif, ea) +get_tinfo2=get_tinfo +def get_refinfo(*args): + if isinstance(args[2], refinfo_t): # 6.95: ea, n, refinfo_t + ea, n, ri = args + else: # 7.00: refinfo_t, ea, n + ri, ea, n = args + return _ida_nalt.get_refinfo(ri, ea, n) + +get_switch_info_ex=get_switch_info +set_switch_info_ex=set_switch_info +del_switch_info_ex=del_switch_info +switch_info_ex_t_assign=switch_info_t_assign +switch_info_ex_t_create=switch_info_t_create +switch_info_ex_t_destroy=switch_info_t_destroy +switch_info_ex_t_get_custom=switch_info_t_get_custom +switch_info_ex_t_get_defjump=switch_info_t_get_defjump +switch_info_ex_t_get_elbase=switch_info_t_get_elbase +switch_info_ex_t_get_flags=switch_info_t_get_flags +switch_info_ex_t_get_ind_lowcase=switch_info_t_get_ind_lowcase +switch_info_ex_t_get_jcases=switch_info_t_get_jcases +switch_info_ex_t_get_jumps=switch_info_t_get_jumps +switch_info_ex_t_get_ncases=switch_info_t_get_ncases +switch_info_ex_t_get_regdtyp=switch_info_t_get_regdtype +switch_info_ex_t_get_regnum=switch_info_t_get_regnum +switch_info_ex_t_get_startea=switch_info_t_get_startea +switch_info_ex_t_get_values_lowcase=switch_info_t_get_values_lowcase +switch_info_ex_t_set_custom=switch_info_t_set_custom +switch_info_ex_t_set_defjump=switch_info_t_set_defjump +switch_info_ex_t_set_elbase=switch_info_t_set_elbase +switch_info_ex_t_set_flags=switch_info_t_set_flags +switch_info_ex_t_set_ind_lowcase=switch_info_t_set_ind_lowcase +switch_info_ex_t_set_jcases=switch_info_t_set_jcases +switch_info_ex_t_set_jumps=switch_info_t_set_jumps +switch_info_ex_t_set_ncases=switch_info_t_set_ncases +switch_info_ex_t_set_regdtyp=switch_info_t_set_regdtype +switch_info_ex_t_set_regnum=switch_info_t_set_regnum +switch_info_ex_t_set_startea=switch_info_t_set_startea +switch_info_ex_t_set_values_lowcase=switch_info_t_set_values_lowcase + +def __switch_info_t_get_flags__(instance): + return switch_info_t.__get_flags__(instance) | SWI_EXTENDED +def __switch_info_t_set_flags__(instance, v): + if instance.bc695_api: + v |= (switch_info_t.__get_flags__(instance) & 0xFFFF0000) + switch_info_t.__set_flags__(instance, v) +switch_info_t.flags = property(__switch_info_t_get_flags__, __switch_info_t_set_flags__) + +def __switch_info_t_get_flags2__(instance): + instance.bc695_api = True + return switch_info_t.__get_flags__(instance) >> 16 +def __switch_info_t_set_flags2__(instance, v): + instance.bc695_api = True + flags = switch_info_t.__get_flags__(instance) + instance.flags = (flags & 0xFFFF) | (v << 16) +switch_info_t.flags2 = property(__switch_info_t_get_flags2__, __switch_info_t_set_flags2__) + +switch_info_ex_t=switch_info_t +# diff --git a/pywraps/py_name.hpp b/pywraps/py_name.hpp index 4da0238..f30469d 100644 --- a/pywraps/py_name.hpp +++ b/pywraps/py_name.hpp @@ -11,7 +11,7 @@ PyObject *py_get_debug_names(ea_t ea1, ea_t ea2) ea_name_vec_t names; PYW_GIL_CHECK_LOCKED_SCOPE(); Py_BEGIN_ALLOW_THREADS; - get_debug_names(ea1, ea2, names); + get_debug_names(&names, ea1, ea2); Py_END_ALLOW_THREADS; PyObject *dict = Py_BuildValue("{}"); if ( dict != NULL ) @@ -19,7 +19,7 @@ PyObject *py_get_debug_names(ea_t ea1, ea_t ea2) for ( ea_name_vec_t::iterator it=names.begin(); it != names.end(); ++it ) { PyDict_SetItem(dict, - Py_BuildValue(PY_FMT64, it->ea), + Py_BuildValue(PY_BV_EA, bvea_t(it->ea)), PyString_FromString(it->name.c_str())); } } @@ -33,6 +33,14 @@ inline qstring py_get_ea_name(ea_t ea, int gtn_flags=0) get_ea_name(&out, ea, gtn_flags); return out; } -//------------------------------------------------------------------------ + +//------------------------------------------------------------------------- +PyObject *py_validate_name(const char *name, nametype_t type, int flags=0) +{ + qstring qname(name); + if ( validate_name(&qname, type, flags) ) + return PyString_FromStringAndSize(qname.c_str(), qname.length()); + else + Py_RETURN_NONE; +} // -//------------------------------------------------------------------------ diff --git a/pywraps/py_name.py b/pywraps/py_name.py index 9fbbd8c..a0e7e49 100644 --- a/pywraps/py_name.py +++ b/pywraps/py_name.py @@ -1,6 +1,9 @@ -import bisect # +import _ida_idaapi +import _ida_funcs +import bisect + class NearestName(object): """ @@ -49,6 +52,64 @@ class NearestName(object): raise StopIteration return self._get_item(index) -extract_name = extract_name2 +def calc_gtn_flags(fromaddr, ea): + """ + Calculate flags for get_ea_name() function + + @param fromaddr: the referring address. May be BADADDR. + @param ea: linear address + + @return: flags + """ + gtn_flags = 0 + if fromaddr != _ida_idaapi.BADADDR: + pfn = _ida_funcs.get_func(fromaddr) + if _ida_funcs.func_contains(pfn, ea): + gtn_flags = GN_LOCAL + return gtn_flags # + +# +GN_INSNLOC=0 +@bc695redef +def demangle_name(name, mask, demreq=DQT_FULL): # make flag optional, so demangle_name & demangle_name2 can use it + return _ida_name.demangle_name(name, mask, demreq) +demangle_name2=demangle_name +@bc695redef +def do_name_anyway(ea, name, maxlen=0): + return force_name(ea, name) +extract_name2=extract_name +get_debug_name2=get_debug_name +@bc695redef +def get_true_name(ea0, ea1=None): + if ea1 is None: + ea = ea0 + else: + ea = ea1 + return get_name(ea) +is_ident_char=is_ident_cp +is_visible_char=is_visible_cp +@bc695redef +def make_visible_name(name, sz=0): + if sz > 0: + name = name[0:sz] + return _ida_name.validate_name(name, VNT_VISIBLE) +@bc695redef +def validate_name2(name, sz=0): + if sz > 0: + name = name[0:sz] + return _ida_name.validate_name(name, VNT_IDENT) +@bc695redef +def validate_name3(name): + return _ida_name.validate_name(name, VNT_IDENT) +isident=is_ident +@bc695redef +def get_name(*args): + if len(args) == 2: + if args[0] != _ida_idaapi.BADADDR: + print("Compatibility get_name(from, ea) was called with non-BADADDR first argument (0x%08x). There is no equivalent in the new API, and the results might be erroneous." % args[0]); + return _ida_name.get_name(args[1]) + else: + return _ida_name.get_name(*args) +# diff --git a/pywraps/py_netnode.py b/pywraps/py_netnode.py new file mode 100644 index 0000000..670d925 --- /dev/null +++ b/pywraps/py_netnode.py @@ -0,0 +1,14 @@ + +# +netnode.alt1st = netnode.altfirst +netnode.alt1st_idx8 = netnode.altfirst_idx8 +netnode.altnxt = netnode.altnext +netnode.char1st = netnode.charfirst +netnode.char1st_idx8 = netnode.charfirst_idx8 +netnode.charnxt = netnode.charnext +netnode.hash1st = netnode.hashfirst +netnode.hashnxt = netnode.hashnext +netnode.sup1st = netnode.supfirst +netnode.sup1st_idx8 = netnode.supfirst_idx8 +netnode.supnxt = netnode.supnext +# diff --git a/pywraps/py_offset.py b/pywraps/py_offset.py new file mode 100644 index 0000000..663064e --- /dev/null +++ b/pywraps/py_offset.py @@ -0,0 +1,10 @@ + +# +calc_reference_basevalue=calc_basevalue +calc_reference_target=calc_target +@bc695redef +def set_offset(ea, n, base): + import ida_idaapi + otype = get_default_reftype(ea) + return op_offset(ea, n, otype, ida_idaapi.BADADDR, base) > 0 +# diff --git a/pywraps/py_pro.hpp b/pywraps/py_pro.hpp index f67a448..1c34647 100644 --- a/pywraps/py_pro.hpp +++ b/pywraps/py_pro.hpp @@ -24,9 +24,9 @@ static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx) static bool qstrvec_t_set( - PyObject *self, - size_t idx, - const char *s) + PyObject *self, + size_t idx, + const char *s) { qstrvec_t *sv = qstrvec_t_get_clink(self); if ( sv == NULL || idx >= sv->size() ) @@ -36,8 +36,8 @@ static bool qstrvec_t_set( } static bool qstrvec_t_from_list( - PyObject *self, - PyObject *py_list) + PyObject *self, + PyObject *py_list) { PYW_GIL_CHECK_LOCKED_SCOPE(); qstrvec_t *sv = qstrvec_t_get_clink(self); @@ -83,9 +83,9 @@ static bool qstrvec_t_clear(PyObject *self, bool qclear) } static bool qstrvec_t_insert( - PyObject *self, - size_t idx, - const char *s) + PyObject *self, + size_t idx, + const char *s) { qstrvec_t *sv = qstrvec_t_get_clink(self); if ( sv == NULL || idx >= sv->size() ) @@ -103,4 +103,24 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx) sv->erase(sv->begin()+idx); return true; } + + +//------------------------------------------------------------------------ +/* +# +def str2user(str): + """ + Insert C-style escape characters to string + + @return: new string with escape characters inserted + """ + pass +# +*/ +PyObject *py_str2user(const char *str) +{ + qstring retstr; + qstr2user(&retstr, str); + return PyString_FromString(retstr.c_str()); +} // diff --git a/pywraps/py_pro.py b/pywraps/py_pro.py index ffc870e..afc419b 100644 --- a/pywraps/py_pro.py +++ b/pywraps/py_pro.py @@ -18,7 +18,7 @@ class _qstrvec_t(ida_idaapi.py_clinked_object_t): 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 + That's because that's what ask_form 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. @@ -85,3 +85,12 @@ class _qstrvec_t(ida_idaapi.py_clinked_object_t): return _ida_pro.qstrvec_t_remove(self, idx) # + +# +@bc695redef +def strlwr(s): + return str(s).lower() +@bc695redef +def strupr(s): + return str(s).upper() +# diff --git a/pywraps/py_problems.py b/pywraps/py_problems.py new file mode 100644 index 0000000..50bd3fa --- /dev/null +++ b/pywraps/py_problems.py @@ -0,0 +1,32 @@ +# +import sys +sys.modules["ida_queue"] = sys.modules["ida_problems"] +Q_Qnum=_ida_problems.cvar.PR_END +Q_att=_ida_problems.cvar.PR_ATTN +Q_badstack=_ida_problems.cvar.PR_BADSTACK +Q_collsn=_ida_problems.cvar.PR_COLLISION +Q_decimp=_ida_problems.cvar.PR_DECIMP +Q_disasm=_ida_problems.cvar.PR_DISASM +Q_final=_ida_problems.cvar.PR_FINAL +Q_head=_ida_problems.cvar.PR_HEAD +Q_jumps=_ida_problems.cvar.PR_JUMP +Q_lines=_ida_problems.cvar.PR_MANYLINES +Q_noBase=_ida_problems.cvar.PR_NOBASE +Q_noComm=_ida_problems.cvar.PR_NOCMT +Q_noFop=_ida_problems.cvar.PR_NOFOP +Q_noName=_ida_problems.cvar.PR_NONAME +Q_noRef=_ida_problems.cvar.PR_NOXREFS +Q_noValid=_ida_problems.cvar.PR_ILLADDR +Q_rolled=_ida_problems.cvar.PR_ROLLED +QueueDel=forget_problem +QueueGetMessage=get_problem_desc +QueueGetType=get_problem +QueueIsPresent=is_problem_present +QueueSet=remember_problem +@bc695redef +def get_long_queue_name(t): + return get_problem_name(t, True) +@bc695redef +def get_short_queue_name(t): + return get_problem_name(t, False) +# diff --git a/pywraps/py_range.hpp b/pywraps/py_range.hpp new file mode 100644 index 0000000..4dfe4a0 --- /dev/null +++ b/pywraps/py_range.hpp @@ -0,0 +1,3 @@ + +// +// diff --git a/pywraps/py_range.py b/pywraps/py_range.py new file mode 100644 index 0000000..bf3f205 --- /dev/null +++ b/pywraps/py_range.py @@ -0,0 +1,13 @@ + +# +import sys +sys.modules["ida_area"] = sys.modules["ida_range"] +area_t = range_t +areaset_t = rangeset_t +def __set_startEA(inst, v): + inst.start_ea = v +range_t.startEA = property(lambda self: self.start_ea, __set_startEA) +def __set_endEA(inst, v): + inst.end_ea = v +range_t.endEA = property(lambda self: self.end_ea, __set_endEA) +# diff --git a/pywraps/py_registry.hpp b/pywraps/py_registry.hpp index e7a5e02..6bc656f 100644 --- a/pywraps/py_registry.hpp +++ b/pywraps/py_registry.hpp @@ -31,20 +31,13 @@ static PyObject *_py_reg_subkey_children(const char *name, bool subkeys) PyObject *py_reg_read_string(const char *name, const char *subkey = NULL, const char *def = NULL) { PYW_GIL_CHECK_LOCKED_SCOPE(); - char utf8[MAXSTR * 10]; + qstring utf8; bool ok; Py_BEGIN_ALLOW_THREADS; - if ( def == NULL ) - { - ok = reg_read_string(name, utf8, sizeof(utf8), subkey); - } - else - { - reg_read_string(name, sizeof(utf8), utf8, def, subkey); - ok = true; - } + if ( !reg_read_string(&utf8, name, subkey) && def != NULL ) + utf8 = def; Py_END_ALLOW_THREADS; - return PyString_FromString(ok ? utf8 : ""); + return PyString_FromString(utf8.c_str()); } //------------------------------------------------------------------------- diff --git a/pywraps/py_search.py b/pywraps/py_search.py new file mode 100644 index 0000000..b63322a --- /dev/null +++ b/pywraps/py_search.py @@ -0,0 +1,4 @@ + +# +find_void=find_suspop +# diff --git a/pywraps/py_segment.hpp b/pywraps/py_segment.hpp index 6078646..6887192 100644 --- a/pywraps/py_segment.hpp +++ b/pywraps/py_segment.hpp @@ -1,37 +1,37 @@ // -void segment_t_startEA_set(segment_t *segm, ea_t newea) +void segment_t_start_ea_set(segment_t *segm, ea_t newea) { - if ( getseg(segm->startEA) == segm ) + if ( getseg(segm->start_ea) == segm ) { - PyErr_SetString(PyExc_AttributeError, "Can't modify startEA, please use set_segm_start() instead"); + PyErr_SetString(PyExc_AttributeError, "Can't modify start_ea, please use set_segm_start() instead"); } else { - segm->startEA = newea; + segm->start_ea = newea; } } -ea_t segment_t_startEA_get(segment_t *segm) +ea_t segment_t_start_ea_get(segment_t *segm) { - return segm->startEA; + return segm->start_ea; } -void segment_t_endEA_set(segment_t *segm, ea_t newea) +void segment_t_end_ea_set(segment_t *segm, ea_t newea) { - if ( getseg(segm->startEA) == segm ) + if ( getseg(segm->start_ea) == segm ) { - PyErr_SetString(PyExc_AttributeError, "Can't modify endEA, please use set_segm_end() instead"); + PyErr_SetString(PyExc_AttributeError, "Can't modify end_ea, please use set_segm_end() instead"); } else { - segm->endEA = newea; + segm->end_ea = newea; } } -ea_t segment_t_endEA_get(segment_t *segm) +ea_t segment_t_end_ea_get(segment_t *segm) { - return segm->endEA; + return segm->end_ea; } // diff --git a/pywraps/py_segment.py b/pywraps/py_segment.py new file mode 100644 index 0000000..d72ccac --- /dev/null +++ b/pywraps/py_segment.py @@ -0,0 +1,18 @@ + +# +CSS_NOAREA=CSS_NORANGE +SEGDEL_KEEP=SEGMOD_KEEP +SEGDEL_KEEP0=SEGMOD_KEEP0 +SEGDEL_PERM=SEGMOD_KILL +SEGDEL_SILENT=SEGMOD_SILENT +@bc695redef +def del_segment_cmt(s, rpt): + set_segment_cmt(s, "", rpt) +ask_selector=sel2para +# In 7.0, those were renamed +# - get_true_segm_name -> get_segm_name +# - get_segm_name -> get_visible_segm_name +# alas, since they have the same prototypes, we cannot do much, +# but redirect all to get_segm_name and hope for the best +get_true_segm_name=get_segm_name +# diff --git a/pywraps/py_segregs.py b/pywraps/py_segregs.py new file mode 100644 index 0000000..698cd15 --- /dev/null +++ b/pywraps/py_segregs.py @@ -0,0 +1,40 @@ + +# +import sys +sys.modules["ida_srarea"] = sys.modules["ida_segregs"] +SetDefaultRegisterValue=set_default_sreg_value +copy_srareas=copy_sreg_ranges +def ___looks_like_ea_not_segreg(thing): + # yay heuristics. Not sure how best to do this... + return (type(thing) == long) or (thing > 0x200) +def del_sreg_range(*args): + if ___looks_like_ea_not_segreg(args[1]): # 6.95: rg, ea + ea, rg = args[1], args[0] + else: # 7.00: ea, rg + ea, rg = args + return _ida_segregs.del_sreg_range(ea, rg) +del_srarea=del_sreg_range +getSR=get_sreg +get_prev_srarea=get_prev_sreg_range +get_srarea2=get_sreg_range +def get_sreg_range_num(*args): + if ___looks_like_ea_not_segreg(args[1]): # 6.95: rg, ea + ea, rg = args[1], args[0] + else: # 7.00: ea, rg + ea, rg = args + return _ida_segregs.get_sreg_range_num(ea, rg) +get_srarea_num=get_sreg_range_num +get_srareas_qty2=get_sreg_ranges_qty +getn_srarea2=getn_sreg_range +import ida_idaapi +is_segreg_locked=ida_idaapi._BC695.false_p +class lock_segreg: + def __init__(): + pass +segreg_area_t=sreg_range_t +splitSRarea1=split_sreg_range +split_srarea=split_sreg_range +get_segreg=get_sreg +set_default_segreg_value=set_default_sreg_value + +# diff --git a/pywraps/py_strlist.py b/pywraps/py_strlist.py new file mode 100644 index 0000000..8f6adc1 --- /dev/null +++ b/pywraps/py_strlist.py @@ -0,0 +1,4 @@ +# +def refresh_strlist(*args): + build_strlist() +# diff --git a/pywraps/py_struct.py b/pywraps/py_struct.py new file mode 100644 index 0000000..1233d93 --- /dev/null +++ b/pywraps/py_struct.py @@ -0,0 +1,28 @@ +# +get_member_name2=get_member_name + +def get_member_tinfo(*args): + import ida_typeinf + if isinstance(args[1], ida_typeinf.tinfo_t): # 6.95: mptr, tinfo_t + mptr, tif = args + else: # 7.00: tinfo_t, mptr + tif, mptr = args + return _ida_struct.get_member_tinfo(tif, mptr); + +def get_or_guess_member_tinfo(*args): + import ida_typeinf + if isinstance(args[1], ida_typeinf.tinfo_t): # 6.95: mptr, tinfo_t + mptr, tif = args + else: # 7.00: tinfo_t, mptr + tif, mptr = args + return _ida_struct.get_or_guess_member_tinfo(tif, mptr); + +# note: if needed we might have to re-implement get_member_tinfo() +# and look whether there is a 2nd, 'tinfo_t' parameter (since the +# original get_member_tinfo function has a different signature) +get_member_tinfo2=get_member_tinfo +# same here +get_or_guess_member_tinfo2=get_or_guess_member_tinfo +save_struc2=save_struc +set_member_tinfo2=set_member_tinfo +# diff --git a/pywraps/py_typeinf.hpp b/pywraps/py_typeinf.hpp index 61788de..4a43453 100644 --- a/pywraps/py_typeinf.hpp +++ b/pywraps/py_typeinf.hpp @@ -8,7 +8,7 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags) tinfo_t tif; qstring name; qtype fields, type; - bool ok = parse_decl2(ti, decl, &name, &tif, flags); + bool ok = parse_decl(&tif, &name, ti, decl, flags); if ( ok ) ok = tif.serialize(&type, &fields, NULL, SUDT_FAST); @@ -27,7 +27,7 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags) def calc_type_size(ti, tp): """ Returns the size of a type - @param ti: Type info. 'idaapi.cvar.idati' can be passed. + @param ti: Type info. 'None' can be passed. @param tp: type string @return: - None on failure @@ -67,7 +67,7 @@ PyObject *py_calc_type_size(const til_t *ti, PyObject *tp) def apply_type(ti, ea, tp_name, py_type, py_fields, flags) """ Apply the specified type to the address - @param ti: Type info library. 'idaapi.cvar.idati' can be used. + @param ti: Type info library. 'None' can be used. @param py_type: type string @param py_fields: fields string (may be empty or None) @param ea: the address of the object @@ -103,7 +103,7 @@ static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_ { rc = has_ti(ea); if ( rc ) - del_tinfo2(ea); + del_tinfo(ea); } } else @@ -113,9 +113,9 @@ static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_ if ( rc ) { if ( mptr != NULL ) - rc = set_member_tinfo2(sptr, mptr, 0, tif, 0); + rc = set_member_tinfo(sptr, mptr, 0, tif, 0); else - rc = apply_tinfo2(ea, tif, flags); + rc = apply_tinfo(ea, tif, flags); } } Py_END_ALLOW_THREADS; @@ -124,26 +124,28 @@ static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_ //------------------------------------------------------------------------- /* +header: typeinf.hpp # -def print_type(ea, one_line): +def get_arg_addrs(caller): """ - Returns the type of an item - @return: - - None on failure - - The type string with a semicolon. Can be used directly with idc.SetType() + Retrieve addresses of argument initialization instructions + + @param caller: the address of the call instruction + @return: list of instruction addresses """ pass # */ -static PyObject *py_print_type(ea_t ea, bool one_line) +PyObject *py_get_arg_addrs(ea_t caller) { - qstring out; - int flags = PRTYPE_SEMI | (one_line ? PRTYPE_1LINE : PRTYPE_MULTI); - bool ok = print_type3(&out, ea, one_line ? PRTYPE_1LINE : PRTYPE_MULTI); - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( ok ) - return PyString_FromString(out.begin()); - Py_RETURN_NONE; + eavec_t addrs; + if ( !get_arg_addrs(&addrs, caller) ) + Py_RETURN_NONE; + int n = addrs.size(); + PyObject *result = PyList_New(n); + for ( size_t i = 0; i < n; ++i ) + PyList_SetItem(result, i, Py_BuildValue(PY_BV_EA, bvea_t(addrs[i]))); + return result; } //------------------------------------------------------------------------- @@ -158,11 +160,11 @@ def py_unpack_object_from_idb(ti, tp, fields, ea, pio_flags = 0): # */ PyObject *py_unpack_object_from_idb( - til_t *ti, - PyObject *py_type, - PyObject *py_fields, - ea_t ea, - int pio_flags = 0) + til_t *ti, + PyObject *py_type, + PyObject *py_fields, + ea_t ea, + int pio_flags = 0) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) ) @@ -176,16 +178,16 @@ PyObject *py_unpack_object_from_idb( borref_t py_fields_ref(py_fields); // Unpack - type_t *type = (type_t *) PyString_AsString(py_type); + const type_t *type = (const type_t *) PyString_AsString(py_type); const p_list *fields = PyW_Fields(py_fields); idc_value_t idc_obj; error_t err; Py_BEGIN_ALLOW_THREADS; - err = unpack_object_from_idb( + tinfo_t tif; + tif.deserialize(ti, &type, &fields); + err = unpack_idcobj_from_idb( &idc_obj, - ti, - type, - fields, + tif, ea, NULL, pio_flags); @@ -213,7 +215,7 @@ def unpack_object_from_bv(ti, tp, fields, bytes, pio_flags = 0): """ Unpacks a buffer into an object. Returns the error_t returned by idaapi.pack_object_to_idb - @param ti: Type info. 'idaapi.cvar.idati' can be passed. + @param ti: Type info. 'None' can be passed. @param tp: type string @param fields: fields string (may be empty or None) @param bytes: the bytes to unpack @@ -226,11 +228,11 @@ def unpack_object_from_bv(ti, tp, fields, bytes, pio_flags = 0): # */ PyObject *py_unpack_object_from_bv( - til_t *ti, - PyObject *py_type, - PyObject *py_fields, - PyObject *py_bytes, - int pio_flags = 0) + til_t *ti, + PyObject *py_type, + PyObject *py_fields, + PyObject *py_bytes, + int pio_flags = 0) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) || !PyString_Check(py_bytes) ) @@ -244,7 +246,7 @@ PyObject *py_unpack_object_from_bv( borref_t py_fields_ref(py_fields); // Get type strings - type_t *type = (type_t *) PyString_AsString(py_type); + const type_t *type = (const type_t *) PyString_AsString(py_type); const p_list *fields = PyW_Fields(py_fields); // Make a byte vector @@ -255,11 +257,11 @@ PyObject *py_unpack_object_from_bv( idc_value_t idc_obj; error_t err; Py_BEGIN_ALLOW_THREADS; - err = unpack_object_from_bv( + tinfo_t tif; + tif.deserialize(ti, &type, &fields); + err = unpack_idcobj_from_bv( &idc_obj, - ti, - type, - fields, + tif, bytes, pio_flags); Py_END_ALLOW_THREADS; @@ -287,7 +289,7 @@ def pack_object_to_idb(obj, ti, tp, fields, ea, pio_flags = 0): Write a typed object to the database. Raises an exception if wrong parameters were passed or conversion fails Returns the error_t returned by idaapi.pack_object_to_idb - @param ti: Type info. 'idaapi.cvar.idati' can be passed. + @param ti: Type info. 'None' can be passed. @param tp: type string @param fields: fields string (may be empty or None) @param ea: ea to be used while packing @@ -297,12 +299,12 @@ def pack_object_to_idb(obj, ti, tp, fields, ea, pio_flags = 0): # */ PyObject *py_pack_object_to_idb( - PyObject *py_obj, - til_t *ti, - PyObject *py_type, - PyObject *py_fields, - ea_t ea, - int pio_flags = 0) + PyObject *py_obj, + til_t *ti, + PyObject *py_type, + PyObject *py_fields, + ea_t ea, + int pio_flags = 0) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) ) @@ -322,14 +324,16 @@ PyObject *py_pack_object_to_idb( borref_t py_fields_ref(py_fields); // Get type strings - type_t *type = (type_t *)PyString_AsString(py_type); + const type_t *type = (const type_t *)PyString_AsString(py_type); const p_list *fields = PyW_Fields(py_fields); // Pack // error_t err; error_t err; Py_BEGIN_ALLOW_THREADS; - err = pack_object_to_idb(&idc_obj, ti, type, fields, ea, pio_flags); + tinfo_t tif; + tif.deserialize(ti, &type, &fields); + err = pack_idcobj_to_idb(&idc_obj, tif, ea, pio_flags); Py_END_ALLOW_THREADS; return PyInt_FromLong(err); } @@ -340,7 +344,7 @@ PyObject *py_pack_object_to_idb( def pack_object_to_bv(obj, ti, tp, fields, base_ea, pio_flags = 0): """ Packs a typed object to a string - @param ti: Type info. 'idaapi.cvar.idati' can be passed. + @param ti: Type info. 'None' can be passed. @param tp: type string @param fields: fields string (may be empty or None) @param base_ea: base ea used to relocate the pointers in the packed object @@ -354,12 +358,12 @@ def pack_object_to_bv(obj, ti, tp, fields, base_ea, pio_flags = 0): */ // Returns a tuple(Boolean, PackedBuffer or Error Code) PyObject *py_pack_object_to_bv( - PyObject *py_obj, - til_t *ti, - PyObject *py_type, - PyObject *py_fields, - ea_t base_ea, - int pio_flags=0) + PyObject *py_obj, + til_t *ti, + PyObject *py_type, + PyObject *py_fields, + ea_t base_ea, + int pio_flags=0) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) ) @@ -379,22 +383,22 @@ PyObject *py_pack_object_to_bv( borref_t py_fields_ref(py_fields); // Get type strings - type_t *type = (type_t *)PyString_AsString(py_type); + const type_t *type = (const type_t *)PyString_AsString(py_type); const p_list *fields = PyW_Fields(py_fields); // Pack relobj_t bytes; error_t err; Py_BEGIN_ALLOW_THREADS; - err = pack_object_to_bv( + tinfo_t tif; + tif.deserialize(ti, &type, &fields); + err = pack_idcobj_to_bv( &idc_obj, - ti, - type, - fields, + tif, &bytes, NULL, pio_flags); - if ( err == eOk && !bytes.relocate(base_ea, inf.mf) ) + if ( err == eOk && !bytes.relocate(base_ea, inf.is_be()) ) err = -1; Py_END_ALLOW_THREADS; if ( err == eOk ) @@ -412,14 +416,17 @@ int idc_parse_types(const char *input, int flags) if ( (flags & 1) != 0 ) hti |= HTI_FIL; - return parse_decls(idati, input, (flags & 2) == 0 ? msg : NULL, hti); + return parse_decls(NULL, input, (flags & 2) == 0 ? msg : NULL, hti); } //------------------------------------------------------------------------- PyObject *py_idc_get_type_raw(ea_t ea) { + tinfo_t tif; qtype type, fields; - bool ok = get_tinfo(ea, &type, &fields); + bool ok = get_tinfo(&tif, ea); + if ( ok ) + ok = tif.serialize(&type, &fields, NULL, SUDT_FAST); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( ok ) return Py_BuildValue("(ss)", (char *)type.c_str(), (char *)fields.c_str()); @@ -432,7 +439,7 @@ PyObject *py_idc_get_local_type_raw(int ordinal) { const type_t *type; const p_list *fields; - bool ok = get_numbered_type(idati, ordinal, &type, &fields); + bool ok = get_numbered_type(NULL, ordinal, &type, &fields); PYW_GIL_CHECK_LOCKED_SCOPE(); if ( ok ) return Py_BuildValue("(ss)", (char *)type, (char *)fields); @@ -443,7 +450,7 @@ PyObject *py_idc_get_local_type_raw(int ordinal) char *idc_guess_type(ea_t ea, char *buf, size_t bufsize) { tinfo_t tif; - if ( guess_tinfo2(ea, &tif) ) + if ( guess_tinfo(&tif, ea) ) { qstring out; if ( tif.print(&out) ) @@ -456,7 +463,7 @@ char *idc_guess_type(ea_t ea, char *buf, size_t bufsize) char *idc_get_type(ea_t ea, char *buf, size_t bufsize) { tinfo_t tif; - if ( get_tinfo2(ea, &tif) ) + if ( get_tinfo(&tif, ea) ) { qstring out; if ( tif.print(&out) ) @@ -473,26 +480,26 @@ int idc_set_local_type(int ordinal, const char *dcl, int flags) { if ( dcl == NULL || dcl[0] == '\0' ) { - if ( !del_numbered_type(idati, ordinal) ) + if ( !del_numbered_type(NULL, ordinal) ) return 0; } else { tinfo_t tif; qstring name; - if ( !parse_decl2(idati, dcl, &name, &tif, flags) ) + if ( !parse_decl(&tif, &name, NULL, dcl, flags) ) return 0; if ( ordinal <= 0 ) { if ( !name.empty() ) - ordinal = get_type_ordinal(idati, name.begin()); + ordinal = get_type_ordinal(NULL, name.begin()); if ( ordinal <= 0 ) - ordinal = alloc_type_ordinal(idati); + ordinal = alloc_type_ordinal(NULL); } - if ( tif.set_numbered_type(idati, ordinal, 0, name.c_str()) != TERR_OK ) + if ( tif.set_numbered_type(NULL, ordinal, 0, name.c_str()) != TERR_OK ) return 0; } return ordinal; @@ -502,14 +509,14 @@ int idc_set_local_type(int ordinal, const char *dcl, int flags) int idc_get_local_type(int ordinal, int flags, char *buf, size_t maxsize) { tinfo_t tif; - if ( !tif.get_numbered_type(idati, ordinal) ) + if ( !tif.get_numbered_type(NULL, ordinal) ) { buf[0] = 0; return false; } qstring res; - const char *name = get_numbered_type_name(idati, ordinal); + const char *name = get_numbered_type_name(NULL, ordinal); if ( !tif.print(&res, name, flags, 2, 40) ) { buf[0] = 0; @@ -540,7 +547,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam bool ok; Py_BEGIN_ALLOW_THREADS; tinfo_t tif; - ok = tif.deserialize(idati, &type, &fields, NULL) + ok = tif.deserialize(NULL, &type, &fields, NULL) && tif.print(&res, name, flags, 2, 40); Py_END_ALLOW_THREADS; if ( ok ) @@ -552,7 +559,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam //------------------------------------------------------------------------- char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize) { - const char *name = get_numbered_type_name(idati, ordinal); + const char *name = get_numbered_type_name(NULL, ordinal); if ( name == NULL ) return false; @@ -582,8 +589,8 @@ PyObject *py_get_named_type(const til_t *til, const char *name, int ntf_flags) const p_list *fields = NULL, *field_cmts = NULL; const char *cmt = NULL; sclass_t sclass = sc_unk; - uint32 value = 0; - int code = get_named_type(til, name, ntf_flags, &type, &fields, &cmt, &field_cmts, &sclass, &value); + uint64 value = 0; + int code = get_named_type(til, name, ntf_flags, &type, &fields, &cmt, &field_cmts, &sclass, (uint32 *) &value); if ( code == 0 ) Py_RETURN_NONE; PyObject *tuple = PyTuple_New(7); @@ -609,7 +616,10 @@ PyObject *py_get_named_type(const til_t *til, const char *name, int ntf_flags) ADD_OR_NONE(cmt != NULL, PyString_FromString(cmt)); ADD_OR_NONE(field_cmts != NULL, PyString_FromString((const char *) field_cmts)); ADD(PyInt_FromLong(long(sclass))); - ADD(PyLong_FromUnsignedLong(long(value))); + if ( (ntf_flags & NTF_64BIT) != 0 ) + ADD(PyLong_FromUnsignedLongLong(value)); + else + ADD(PyLong_FromUnsignedLong(long(value))); #undef ADD_OR_NONE #undef ADD return tuple; @@ -651,69 +661,53 @@ int py_print_decls(text_sink_t &printer, til_t *til, PyObject *py_ordinals, uint } //------------------------------------------------------------------------- -til_t *load_til(const char *tildir, const char *name) +til_t *py_load_til(const char *name, const char *tildir) { - char errbuf[MAXSTR]; - til_t *res = load_til(tildir, name, errbuf, sizeof(errbuf)); + qstring errbuf; + til_t *res = load_til(name, &errbuf, tildir); if ( res == NULL ) - PyErr_SetString(PyExc_RuntimeError, errbuf); + PyErr_SetString(PyExc_RuntimeError, errbuf.c_str()); return res; } //------------------------------------------------------------------------- -til_t *load_til_header_wrap(const char *tildir, const char *name) +til_t *py_load_til_header(const char *tildir, const char *name) { - char errbuf[MAXSTR]; - til_t *res = load_til_header(tildir, name, errbuf, sizeof(errbuf)); + qstring errbuf; + til_t *res = load_til_header(tildir, name, &errbuf); if ( res == NULL ) - PyErr_SetString(PyExc_RuntimeError, errbuf); + PyErr_SetString(PyExc_RuntimeError, errbuf.c_str()); return res; } +#ifdef BC695 +// dummy idati, to generate the cvar. We'll patch the code so +// it does retrieve the real idati through get_idati() +til_t *idati = NULL; +#endif + //------------------------------------------------------------------------- -/* -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) +PyObject *py_remove_tinfo_pointer(tinfo_t *tif, const char *name, const til_t *til) { - 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; - } + const char **pname = name == NULL ? NULL : &name; + bool rc = remove_tinfo_pointer(tif, pname, til); + return Py_BuildValue("(Os)", PyBool_FromLong(rc), pname != NULL ? *pname : NULL); +} + +//------------------------------------------------------------------------- +static PyObject *py_get_numbered_type(const til_t *til, uint32 ordinal) +{ + const type_t *type; + const p_list *fields; + const char *cmt; + const p_list *fieldcmts; + sclass_t sclass; + if ( get_numbered_type(til, ordinal, &type, &fields, &cmt, &fieldcmts, &sclass) ) + return Py_BuildValue("(ssssi)", type, fields, cmt, fieldcmts, sclass); 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; - } + Py_RETURN_NONE; } + // // @@ -751,7 +745,6 @@ static PyObject *py_tinfo_t_serialize( #undef ADD return tuple; } - // diff --git a/pywraps/py_typeinf.py b/pywraps/py_typeinf.py index 9bd7676..f93f7ea 100644 --- a/pywraps/py_typeinf.py +++ b/pywraps/py_typeinf.py @@ -1,19 +1,127 @@ # -def get_type_size0(ti, tp): - """ - DEPRECATED. Please use calc_type_size instead - Returns the size of a type - @param ti: Type info. 'idaapi.cvar.idati' can be passed. - @param tp: type string - @return: - - None on failure - - The size of the type - """ - return calc_type_size(ti, tp) - import ida_idaapi ida_idaapi._listify_types( reginfovec_t) # + +# +BFI_NOCONST=0 +BFI_NOLOCS=0 +NTF_NOIDB=0 +PRVLOC_STKOFF=PRALOC_VERIFY +PRVLOC_VERIFY=PRALOC_STKOFF +TERR_TOOLONGNAME=TERR_WRONGNAME +@bc695redef +def add_til(name, flags=0): + return _ida_typeinf.add_til(name, flags) +add_til2=add_til +@bc695redef +def apply_decl(arg0, arg1, arg2=None, arg3=0): + if type(arg0) in [int, long]: # old apply_cdecl() + return _ida_typeinf.apply_cdecl(cvar.idati, arg0, arg1, 0) + else: + assert(arg2 is not None) + return _ida_typeinf.apply_cdecl(arg0, arg1, arg2, arg3) +apply_cdecl2=apply_decl +apply_tinfo2=apply_tinfo +calc_c_cpp_name4=calc_c_cpp_name +import ida_idaapi +callregs_init_regs=ida_idaapi._BC695.dummy +choose_local_type=choose_local_tinfo +@bc695redef +def choose_named_type2(root_til, title, ntf_flags, func, out_sym): + class func_pred_t(predicate_t): + def __init__(self, func): + predicate_t.__init__(self) + self.func = func + def should_display(self, til, name, tp, flds): + return self.func(name, tp, flds) + fp = func_pred_t(func) + return choose_named_type(out_sym, root_til, title, ntf_flags, fp) +deref_ptr2=deref_ptr +extract_varloc=extract_argloc +const_vloc_visitor_t=const_aloc_visitor_t +for_all_const_varlocs=for_all_const_arglocs +for_all_varlocs=for_all_arglocs +@bc695redef +def gen_decorate_name3(name, mangle, cc): + return gen_decorate_name(name, mangle, cc, None) # ATM gen_decorate_name doesn't use its tinfo_t +get_enum_member_expr2=get_enum_member_expr +get_idainfo_by_type3=get_idainfo_by_type +@bc695redef +def guess_func_tinfo2(pfn, tif): + return guess_tinfo(pfn.start_ea, tif) +@bc695redef +def load_til(name, tildir=None, *args): + # 6.95 C++ prototypes + # idaman til_t *ida_export load_til(const char *tildir, const char *name, char *errbuf, size_t bufsize); + # idaman til_t *ida_export load_til2( const char *name, char *errbuf, size_t bufsize); + # + # 6.95 Python prototypes + # load_til(tildir, name) + # load_til(tildir, name, errbuf, bufsize) + # load_til2(name, errbuf, bufsize=0) + # + # -> it's virtually impossible to tell whether it's load_til2(), + # or load_til() that's called since they both take 2 first string + # arguments. We'll rely the contents of those strings... + if name is None or name == "": # load_til(), with an empty tildir + name = tildir + tildir = "" + return _ida_typeinf.load_til(name, tildir) + else: + return _ida_typeinf.load_til(name, tildir) +load_til2=load_til +lower_type2=lower_type +optimize_varloc=optimize_argloc +@bc695redef +def parse_decl2(til, decl, tif, flags): + return _ida_typeinf.parse_decl(tif, til, decl, flags) +@bc695redef +def print_type(ea, flags): + if isinstance(flags, bool): + flags = PRTYPE_1LINE if flags else 0 + return _ida_typeinf.print_type(ea, flags) +@bc695redef +def print_type2(ea, flags): + return _ida_typeinf.print_type(ea, flags) +print_type3=_ida_typeinf.print_type +print_varloc=print_argloc +@bc695redef +def resolve_typedef2(til, p, *args): + return _ida_typeinf.resolve_typedef(til, p) +scattered_vloc_t=scattered_aloc_t +set_compiler2=set_compiler +varloc_t=argloc_t +varpart_t=argpart_t +verify_varloc=verify_argloc +vloc_visitor_t=aloc_visitor_t +def guess_tinfo(*args): + if isinstance(args[1], tinfo_t): # 6.95: id, tinfo_t + tid, tif = args + else: # 7.00: tinfo_t, id + tif, tid = args + return _ida_typeinf.guess_tinfo(tif, tid) +guess_tinfo2=guess_tinfo +def find_tinfo_udt_member(*args): + if isinstance(args[2], udt_member_t): # 6.95: typid, strmem_flags, udm + typid, strmem_flags, udm = args + else: # 7.00: udm, typid, strmem_flags + udm, typid, strmem_flags = args + return _ida_typeinf.find_tinfo_udt_member(udm, typid, strmem_flags) +def __tinfo_t_find_udt_member(self, *args): + if isinstance(args[1], udt_member_t): # 6.95: strmem_flags, udm + strmem_flags, udm = args + else: # 7.00: udm, strmem_flags + udm, strmem_flags = args + return _ida_typeinf.tinfo_t_find_udt_member(self, udm, strmem_flags) +tinfo_t.find_udt_member=__tinfo_t_find_udt_member +def save_tinfo(*args): + if isinstance(args[4], tinfo_t): # 6.95: til_t, size_t, name, int, tinfo_t + til, _ord, name, ntf_flags, tif = args + else: # 7.00: tinfo_t, til_t, size_t, name, int + tif, til, _ord, name, ntf_flags = args + return _ida_typeinf.save_tinfo(tif, til, _ord, name, ntf_flags) +# diff --git a/pywraps/py_ua.hpp b/pywraps/py_ua.hpp index fefbe04..169d0cf 100644 --- a/pywraps/py_ua.hpp +++ b/pywraps/py_ua.hpp @@ -9,195 +9,22 @@ // /* # -def init_output_buffer(size = MAXSTR): - """ - This function initialize an output buffer with the given size. - It should be called before using any out_xxxx() functions. - @return: It returns a string. This string should then be passed to MakeLine(). - This function could return None if it failed to create a buffer with the given size. - """ - pass -# -*/ -PyObject *py_init_output_buffer(size_t size = MAXSTR) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - - // Let Python allocate a writable string buffer for us - PyObject *py_str = PyString_FromStringAndSize(NULL, size); - if ( py_str == NULL ) - Py_RETURN_NONE; - - init_output_buffer(PyString_AsString(py_str), size); - return py_str; -} - -//------------------------------------------------------------------------- -/* -# -def term_output_buffer(): - """Use this function to terminate an output buffer.""" - pass -# -*/ -void py_term_output_buffer() -{ - term_output_buffer(); -} - -//------------------------------------------------------------------------- -/* -# def decode_preceding_insn(ea): """ Decodes the preceding instruction. Please check ua.hpp / decode_preceding_insn() @param ea: current ea + @param out: instruction storage @return: tuple(preceeding_ea or BADADDR, farref = Boolean) """ pass # */ -PyObject *py_decode_preceding_insn(ea_t ea) +PyObject *py_decode_preceding_insn(insn_t *out, ea_t ea) { bool farref; - ea_t r = decode_preceding_insn(ea, &farref); + ea_t r = decode_preceding_insn(out, ea, &farref); PYW_GIL_CHECK_LOCKED_SCOPE(); - return Py_BuildValue("(" PY_FMT64 "i)", pyul_t(r), farref ? 1 : 0); -} - -//------------------------------------------------------------------------- -/* -# -def OutValue(op, outflags = 0): - """ - Output immediate value - @param op: operand (of type op_t) - @return: flags of the output value - -1: value is output with COLOR_ERROR - 0: value is output as a number or character or segment - """ - pass -# -*/ -flags_t py_OutValue(PyObject *x, int outflags=0) -{ - op_t *op = op_t_get_clink(x); - if ( op == NULL ) - return 0; - - return OutValue(*op, outflags); -} - -//------------------------------------------------------------------------- -/* -# -def OutImmChar(op, outflags = 0): - """ - Output operand value as a commented character constant - @param op: operand (of type op_t) - @return: None - """ - pass -# -*/ -static void py_OutImmChar(PyObject *x) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(x); - if ( op != NULL ) - OutImmChar(*op); -} - -//------------------------------------------------------------------------- -/* -# -def ua_stkvar2(op, outflags = 0): - """ - Create or modify a stack variable in the function frame. - Please check ua.hpp / ua_stkvar2() - @param op: operand (of type op_t) - @return: None - """ - pass -# -*/ -static bool py_ua_stkvar2(PyObject *x, adiff_t v, int flags) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(x); - return op == NULL ? false : ua_stkvar2(*op, v, flags); -} - -//------------------------------------------------------------------------- -/* -# -def ua_add_off_drefs(op, type): - """ - Add xrefs for offset operand of the current instruction - Please check ua.hpp / ua_add_off_drefs() - @param op: operand (of type op_t) - @return: None - """ - pass -# -*/ -ea_t py_ua_add_off_drefs(PyObject *py_op, dref_t type) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - return op == NULL ? BADADDR : ua_add_off_drefs(*op, type); -} - -//------------------------------------------------------------------------- -/* -# -def ua_add_off_drefs2(op, type, outf): - """ - Add xrefs for offset operand of the current instruction - Please check ua.hpp / ua_add_off_drefs2() - @return: ea_t - """ - pass -# -*/ -ea_t py_ua_add_off_drefs2(PyObject *py_op, dref_t type, int outf) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - return op == NULL ? BADADDR : ua_add_off_drefs2(*op, type, outf); -} - -//------------------------------------------------------------------------- -/* -# -def out_name_expr(op, ea, off): - """ - Output a name expression - @param op: operand (of type op_t) - @param ea: address of expression - @param off: the value of name expression. this parameter is used only to - check that the name expression will have the wanted value. - You may pass BADADDR for this parameter. - @return: true if the name expression has been produced - """ - pass -# -*/ -bool py_out_name_expr( - PyObject *py_op, - ea_t ea, - PyObject *py_off) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *op = op_t_get_clink(py_op); - uint64 v(0); - adiff_t off; - if ( PyW_GetNumber(py_off, &v) ) - off = adiff_t(v); - else - off = BADADDR; - - return op == NULL ? false : out_name_expr(*op, ea, off); + return Py_BuildValue("(" PY_BV_EA "i)", bvea_t(r), farref ? 1 : 0); } //------------------------------------------------------------------------- @@ -210,7 +37,7 @@ def construct_macro(insn): pass # */ -bool py_construct_macro(bool enable, PyObject *build_macro) +bool py_construct_macro(insn_t &insn, bool enable, PyObject *build_macro) { PYW_GIL_CHECK_LOCKED_SCOPE(); @@ -222,588 +49,66 @@ bool py_construct_macro(bool enable, PyObject *build_macro) macro_builders.push(newref_t(build_macro)); struct ida_local lambda_t { - static bool idaapi call_build_macro(insn_t &s, bool may_go_forward) + static bool idaapi call_build_macro(insn_t &insn, bool may_go_forward) { PyObject *py_builder = macro_builders.top().o; - newref_t pyres = PyObject_CallFunction( - py_builder, "O", - may_go_forward ? Py_True : Py_False); - PyW_ShowCbErr("build_macro"); - if ( pyres.o == NULL || pyres.o == Py_None ) - return false; - insn_t *_s = insn_t_get_clink(pyres.o); - if ( _s == NULL ) - return false; - s = *_s; - return true; + ref_t py_res; + ref_t py_mod(PyW_TryImportModule(SWIG_name)); + if ( py_mod != NULL ) + { + ref_t py_insn = try_create_swig_wrapper(py_mod, "insn_t", &insn); + if ( py_insn != NULL ) + { + py_res = newref_t( + PyObject_CallFunction( + py_builder, + "OO", + py_insn.o, + may_go_forward ? Py_True : Py_False)); + PyW_ShowCbErr("build_macro"); + } + } + return py_res.o == Py_True; } }; - bool res = construct_macro(enable, lambda_t::call_build_macro); + bool res = construct_macro(insn, enable, lambda_t::call_build_macro); macro_builders.pop(); return res; } //------------------------------------------------------------------------- -static int py_get_dtyp_by_size(asize_t size) +static int py_get_dtype_by_size(asize_t size) { - return int(get_dtyp_by_size(size)); + return int(get_dtype_by_size(size)); } //------------------------------------------------------------------------- -static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( i < 0 || i >= UA_MAXOP || !PyCObject_Check(py_insn_lnk) ) - Py_RETURN_NONE; - - // Extract C link - insn_t *insn = (insn_t *)PyCObject_AsVoidPtr(py_insn_lnk); - - // Return a link to the operand - return PyCObject_FromVoidPtr(&insn->Operands[i], NULL); -} - -//------------------------------------------------------------------------- -static PyObject *insn_t_create() -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyCObject_FromVoidPtr(new insn_t(), NULL); -} - -//------------------------------------------------------------------------- -static PyObject *op_t_create() -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyCObject_FromVoidPtr(new op_t(), NULL); -} - -//------------------------------------------------------------------------- -static bool op_t_assign(PyObject *self, PyObject *other) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *lhs = op_t_get_clink(self); - op_t *rhs = op_t_get_clink(other); - if ( lhs == NULL || rhs == NULL ) - return false; - - *lhs = *rhs; - return true; -} - -//------------------------------------------------------------------------- -static bool insn_t_assign(PyObject *self, PyObject *other) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *lhs = insn_t_get_clink(self); - insn_t *rhs = insn_t_get_clink(other); - if ( lhs == NULL || rhs == NULL ) - return false; - - *lhs = *rhs; - return true; -} - -//------------------------------------------------------------------------- -static bool op_t_destroy(PyObject *py_obj) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( !PyCObject_Check(py_obj) ) - return false; - - op_t *op = (op_t *)PyCObject_AsVoidPtr(py_obj); - delete op; - - return true; -} - -//------------------------------------------------------------------------- -static bool insn_t_destroy(PyObject *py_obj) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( !PyCObject_Check(py_obj) ) - return false; - - delete (insn_t *)PyCObject_AsVoidPtr(py_obj); - return true; -} - -//------------------------------------------------------------------------- -// Returns a C link to the global 'cmd' variable -static PyObject *py_get_global_cmd_link() -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - return PyCObject_FromVoidPtr(&::cmd, NULL); -} - -//------------------------------------------------------------------------- -static PyObject *insn_t_is_canon_insn(int itype) -{ - bool ok = ph.is_canon_insn(itype); - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( ok ) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -//------------------------------------------------------------------------- -static PyObject *insn_t_get_canon_feature(int itype) -{ - uint32 v = ph.is_canon_insn(itype) ? ph.instruc[itype-ph.instruc_start].feature : 0; - PYW_GIL_CHECK_LOCKED_SCOPE(); - return Py_BuildValue("I", v); -} - -//------------------------------------------------------------------------- -static PyObject *insn_t_get_canon_mnem(int itype) -{ - bool ok = ph.is_canon_insn(itype); - PYW_GIL_CHECK_LOCKED_SCOPE(); - if ( ok ) - return Py_BuildValue("s", ph.instruc[itype-ph.instruc_start].name); - else - Py_RETURN_NONE; -} - -//------------------------------------------------------------------------- -static PyObject *insn_t_get_cs(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->cs); -} - -static void insn_t_set_cs(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - - uint64 v(0); - PyW_GetNumber(value, &v); - link->cs = ea_t(v); -} - -static PyObject *insn_t_get_ip(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->ip); -} - -static void insn_t_set_ip(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - uint64 v(0); - PyW_GetNumber(value, &v); - link->ip = ea_t(v); -} - -static PyObject *insn_t_get_ea(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->ea); -} - -static void insn_t_set_ea(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - uint64 v(0); - PyW_GetNumber(value, &v); - link->ea = ea_t(v); -} - -static PyObject *insn_t_get_itype(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("H", link->itype); -} - -static void insn_t_set_itype(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->itype = (uint16)PyInt_AsLong(value); -} - -static PyObject *insn_t_get_size(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("H", link->size); -} - -static void insn_t_set_size(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->size = (uint16)PyInt_AsLong(value); -} - -static PyObject *insn_t_get_auxpref(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("H", link->auxpref); -} - -static void insn_t_set_auxpref(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->auxpref = (uint16)PyInt_AsLong(value); -} - -static PyObject *insn_t_get_segpref(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->segpref); -} - -static void insn_t_set_segpref(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->segpref = (char)PyInt_AsLong(value); -} - -static PyObject *insn_t_get_insnpref(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->insnpref); -} - -static void insn_t_set_insnpref(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->insnpref = (char)PyInt_AsLong(value); -} - -static PyObject *insn_t_get_flags(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->flags); -} - -static void insn_t_set_flags(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - insn_t *link = insn_t_get_clink(self); - if ( link == NULL ) - return; - link->flags = (char)PyInt_AsLong(value); -} - -//------------------------------------------------------------------------- -static PyObject *op_t_get_n(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->n); -} - -static void op_t_set_n(PyObject *self, PyObject *value) -{ - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->n = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_type(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("B", link->type); -} - -static void op_t_set_type(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->type = (optype_t)PyInt_AsLong(value); -} - -static PyObject *op_t_get_offb(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->offb); -} - -static void op_t_set_offb(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->offb = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_offo(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->offo); -} - -static void op_t_set_offo(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->offo = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_flags(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("B", link->flags); -} - -static void op_t_set_flags(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->flags = (uchar)PyInt_AsLong(value); -} - -static PyObject *op_t_get_dtyp(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->dtyp); -} - -static void op_t_set_dtyp(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->dtyp = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_reg_phrase(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("H", link->reg); -} -static void op_t_set_reg_phrase(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->reg = (uint16)PyInt_AsLong(value); -} - -static PyObject *op_t_get_value(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->value); -} - -static void op_t_set_value(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - uint64 v(0); - PyW_GetNumber(value, &v); - link->value = uval_t(v); -} - -static PyObject *op_t_get_addr(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->addr); -} - -static void op_t_set_addr(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - uint64 v(0); - PyW_GetNumber(value, &v); - link->addr = ea_t(v); -} - -static PyObject *op_t_get_specval(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue(PY_FMT64, (pyul_t)link->specval); -} - -static void op_t_set_specval(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - uint64 v(0); - PyW_GetNumber(value, &v); - link->specval = ea_t(v); -} - -static PyObject *op_t_get_specflag1(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->specflag1); -} - -static void op_t_set_specflag1(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->specflag1 = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_specflag2(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->specflag2); -} - -static void op_t_set_specflag2(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->specflag2 = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_specflag3(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->specflag3); -} - -static void op_t_set_specflag3(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->specflag3 = (char)PyInt_AsLong(value); -} - -static PyObject *op_t_get_specflag4(PyObject *self) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("b", link->specflag4); -} - -static void op_t_set_specflag4(PyObject *self, PyObject *value) -{ - PYW_GIL_CHECK_LOCKED_SCOPE(); - op_t *link = op_t_get_clink(self); - if ( link == NULL ) - return; - link->specflag4 = (char)PyInt_AsLong(value); -} - -//------------------------------------------------------------------------- -PyObject *py_get_operand_immvals(ea_t ea, int n) +PyObject *py_get_immvals(ea_t ea, int n) { uvalvec_t storage; storage.resize(2 * UA_MAXOP); - size_t cnt = get_operand_immvals(ea, n, storage.begin()); + flags_t F = get_flags(ea); + size_t cnt = get_immvals(storage.begin(), ea, n, F); PyObject *result = PyList_New(cnt); for ( size_t i = 0; i < cnt; ++i ) - PyList_SetItem(result, i, Py_BuildValue(PY_FMT64, pyul_t(storage[i]))); + PyList_SetItem(result, i, Py_BuildValue(PY_BV_UVAL, bvuval_t(storage[i]))); return result; } +//------------------------------------------------------------------------- +#define DEFINE_WRAP_TYPE_FROM_PTRVAL(Type) \ + static Type *Type##__from_ptrval__(size_t ptrval) \ + { \ + return (Type *) ptrval; \ + } + +DEFINE_WRAP_TYPE_FROM_PTRVAL(insn_t); +DEFINE_WRAP_TYPE_FROM_PTRVAL(op_t); +DEFINE_WRAP_TYPE_FROM_PTRVAL(outctx_base_t); +DEFINE_WRAP_TYPE_FROM_PTRVAL(outctx_t); + +#undef DEFINE_WRAP_TYPE_FROM_PTRVAL + // #endif diff --git a/pywraps/py_ua.py b/pywraps/py_ua.py index d9c8ead..274755d 100644 --- a/pywraps/py_ua.py +++ b/pywraps/py_ua.py @@ -1,294 +1,86 @@ # -import ida_idaapi - -# ----------------------------------------------------------------------- -class op_t(ida_idaapi.py_clinked_object_t): - """Class representing operands""" - def __init__(self, lnk = None): - ida_idaapi.py_clinked_object_t.__init__(self, lnk) - - def _create_clink(self): - return _ida_ua.op_t_create() - - def _del_clink(self, lnk): - return _ida_ua.op_t_destroy(lnk) - - def assign(self, other): - """Copies the contents of 'other' to 'self'""" - 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""" - return (self.reg == other.reg) and (self.dtyp == other.dtyp) - - def is_reg(self, r): - """Checks if the register operand is the given processor register""" - return self.type == o_reg and self.reg == r - - def has_reg(self, r): - """Checks if the operand accesses the given processor register""" - return self.reg == r.reg - - # - # Autogenerated - # - def __get_n__(self): - return _ida_ua.op_t_get_n(self) - def __set_n__(self, v): - _ida_ua.op_t_set_n(self, v) - def __get_type__(self): - return _ida_ua.op_t_get_type(self) - def __set_type__(self, v): - _ida_ua.op_t_set_type(self, v) - def __get_offb__(self): - return _ida_ua.op_t_get_offb(self) - def __set_offb__(self, v): - _ida_ua.op_t_set_offb(self, v) - def __get_offo__(self): - return _ida_ua.op_t_get_offo(self) - def __set_offo__(self, v): - _ida_ua.op_t_set_offo(self, v) - def __get_flags__(self): - return _ida_ua.op_t_get_flags(self) - def __set_flags__(self, v): - _ida_ua.op_t_set_flags(self, v) - def __get_dtyp__(self): - return _ida_ua.op_t_get_dtyp(self) - def __set_dtyp__(self, v): - _ida_ua.op_t_set_dtyp(self, v) - def __get_reg_phrase__(self): - return _ida_ua.op_t_get_reg_phrase(self) - def __set_reg_phrase__(self, v): - _ida_ua.op_t_set_reg_phrase(self, v) - def __get_value__(self): - return _ida_ua.op_t_get_value(self) - def __set_value__(self, v): - _ida_ua.op_t_set_value(self, v) - def __get_addr__(self): - return _ida_ua.op_t_get_addr(self) - def __set_addr__(self, v): - _ida_ua.op_t_set_addr(self, v) - def __get_specval__(self): - return _ida_ua.op_t_get_specval(self) - def __set_specval__(self, v): - _ida_ua.op_t_set_specval(self, v) - def __get_specflag1__(self): - return _ida_ua.op_t_get_specflag1(self) - def __set_specflag1__(self, v): - _ida_ua.op_t_set_specflag1(self, v) - def __get_specflag2__(self): - return _ida_ua.op_t_get_specflag2(self) - def __set_specflag2__(self, v): - _ida_ua.op_t_set_specflag2(self, v) - def __get_specflag3__(self): - return _ida_ua.op_t_get_specflag3(self) - def __set_specflag3__(self, v): - _ida_ua.op_t_set_specflag3(self, v) - def __get_specflag4__(self): - return _ida_ua.op_t_get_specflag4(self) - def __set_specflag4__(self, v): - _ida_ua.op_t_set_specflag4(self, v) - - n = property(__get_n__, __set_n__) - type = property(__get_type__, __set_type__) - offb = property(__get_offb__, __set_offb__) - offo = property(__get_offo__, __set_offo__) - flags = property(__get_flags__, __set_flags__) - dtyp = property(__get_dtyp__, __set_dtyp__) - reg = property(__get_reg_phrase__, __set_reg_phrase__) - phrase = property(__get_reg_phrase__, __set_reg_phrase__) - value = property(__get_value__, __set_value__) - addr = property(__get_addr__, __set_addr__) - specval = property(__get_specval__, __set_specval__) - specflag1 = property(__get_specflag1__, __set_specflag1__) - specflag2 = property(__get_specflag2__, __set_specflag2__) - 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(ida_idaapi.py_clinked_object_t): - """Class representing instructions""" - def __init__(self, lnk = None): - ida_idaapi.py_clinked_object_t.__init__(self, lnk) - - # Create linked operands - self.Operands = [] - for i in xrange(0, UA_MAXOP): - self.Operands.append(op_t(insn_t_get_op_link(self.clink, i))) - - # Convenience operand reference objects - self.Op1 = self.Operands[0] - self.Op2 = self.Operands[1] - self.Op3 = self.Operands[2] - self.Op4 = self.Operands[3] - self.Op5 = self.Operands[4] - self.Op6 = self.Operands[5] - - def assign(self, other): - """Copies the contents of 'other' to 'self'""" - return _ida_ua.insn_t_assign(self, other) - -# -# def copy(self): -# """Returns a new copy of this class""" -# pass -# - - def _create_clink(self): - return _ida_ua.insn_t_create() - - - def _del_clink(self, lnk): - return _ida_ua.insn_t_destroy(lnk) - - - def __iter__(self): - return (self.Operands[idx] for idx in xrange(0, UA_MAXOP)) - - - def __getitem__(self, idx): - """ - Operands can be accessed directly as indexes - @return op_t: Returns an operand of type op_t - """ - if idx >= UA_MAXOP: - raise KeyError - else: - return self.Operands[idx] - - def is_macro(self): - return self.flags & INSN_MACRO != 0 - - def is_canon_insn(self): - return _ida_ua.insn_t_is_canon_insn(self.itype) - - def get_canon_feature(self): - return _ida_ua.insn_t_get_canon_feature(self.itype) - - def get_canon_mnem(self): - return _ida_ua.insn_t_get_canon_mnem(self.itype) - - # - # Autogenerated - # - def __get_cs__(self): - return _ida_ua.insn_t_get_cs(self) - def __set_cs__(self, v): - _ida_ua.insn_t_set_cs(self, v) - def __get_ip__(self): - return _ida_ua.insn_t_get_ip(self) - def __set_ip__(self, v): - _ida_ua.insn_t_set_ip(self, v) - def __get_ea__(self): - return _ida_ua.insn_t_get_ea(self) - def __set_ea__(self, v): - _ida_ua.insn_t_set_ea(self, v) - def __get_itype__(self): - return _ida_ua.insn_t_get_itype(self) - def __set_itype__(self, v): - _ida_ua.insn_t_set_itype(self, v) - def __get_size__(self): - return _ida_ua.insn_t_get_size(self) - def __set_size__(self, v): - _ida_ua.insn_t_set_size(self, v) - def __get_auxpref__(self): - return _ida_ua.insn_t_get_auxpref(self) - def __set_auxpref__(self, v): - _ida_ua.insn_t_set_auxpref(self, v) - def __get_segpref__(self): - return _ida_ua.insn_t_get_segpref(self) - def __set_segpref__(self, v): - _ida_ua.insn_t_set_segpref(self, v) - def __get_insnpref__(self): - return _ida_ua.insn_t_get_insnpref(self) - def __set_insnpref__(self, v): - _ida_ua.insn_t_set_insnpref(self, v) - def __get_flags__(self): - return _ida_ua.insn_t_get_flags(self) - def __set_flags__(self, v): - _ida_ua.insn_t_set_flags(self, v) - - cs = property(__get_cs__, __set_cs__) - ip = property(__get_ip__, __set_ip__) - ea = property(__get_ea__, __set_ea__) - itype = property(__get_itype__, __set_itype__) - size = property(__get_size__, __set_size__) - auxpref = property(__get_auxpref__, __set_auxpref__) - segpref = property(__get_segpref__, __set_segpref__) - insnpref = property(__get_insnpref__, __set_insnpref__) - flags = property(__get_flags__, __set_flags__) - - -# Create 'cmd' into the global scope -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.""" - -# ---------------------------------------------------------------------- -# op_t related constants - -# -# op_t.type -# Description Data field -o_void = 0 # No Operand ---------- -o_reg = 1 # General Register (al,ax,es,ds...) reg -o_mem = 2 # Direct Memory Reference (DATA) addr -o_phrase = 3 # Memory Ref [Base Reg + Index Reg] phrase -o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr -o_imm = 5 # Immediate Value value -o_far = 6 # Immediate Far Address (CODE) addr -o_near = 7 # Immediate Near Address (CODE) addr -o_idpspec0 = 8 # Processor specific type -o_idpspec1 = 9 # Processor specific type -o_idpspec2 = 10 # Processor specific type -o_idpspec3 = 11 # Processor specific type -o_idpspec4 = 12 # Processor specific type -o_idpspec5 = 13 # Processor specific type - # There can be more processor specific types - -# -# op_t.dtyp -# -dt_byte = 0 # 8 bit -dt_word = 1 # 16 bit -dt_dword = 2 # 32 bit -dt_float = 3 # 4 byte -dt_double = 4 # 8 byte -dt_tbyte = 5 # variable size (ph.tbyte_size) -dt_packreal = 6 # packed real format for mc68040 -dt_qword = 7 # 64 bit -dt_byte16 = 8 # 128 bit -dt_code = 9 # ptr to code (not used?) -dt_void = 10 # none -dt_fword = 11 # 48 bit -dt_bitfild = 12 # bit field (mc680x0) -dt_string = 13 # pointer to asciiz string -dt_unicode = 14 # pointer to unicode string -dt_3byte = 15 # 3-byte data -dt_ldbl = 16 # long double (which may be different from tbyte) -dt_byte32 = 17 # 256 bit -dt_byte64 = 18 # 512 bit - -# -# op_t.flags -# -OF_NO_BASE_DISP = 0x80 # o_displ: base displacement doesn't exist meaningful only for o_displ type if set, base displacement (x.addr) doesn't exist. -OF_OUTER_DISP = 0x40 # o_displ: outer displacement exists meaningful only for o_displ type if set, outer displacement (x.value) exists. -PACK_FORM_DEF = 0x20 # !o_reg + dt_packreal: packed factor defined -OF_NUMBER = 0x10 # can be output as number only if set, the operand can be converted to a number only -OF_SHOW = 0x08 # should the operand be displayed? if clear, the operand is hidden and should not be displayed - -# -# insn_t.flags -# -INSN_MACRO = 0x01 # macro instruction -INSN_MODMAC = 0x02 # macros: may modify the database to make room for the macro insn - +ua_mnem = print_insn_mnem # + +# +import ida_idaapi +@bc695redef +def codeSeg(ea, opnum): + insn = insn_t() + if decode_insn(insn, ea): + return _ida_ua.map_code_ea(insn, insn.ops[opnum]) + else: + return ida_idaapi.BADADDR +get_dtyp_by_size=get_dtype_by_size +get_dtyp_flag=get_dtype_flag +get_dtyp_size=get_dtype_size +get_operand_immvals=get_immvals +op_t.dtyp = op_t.dtype +cmd = insn_t() +@bc695redef +def decode_insn(*args): + if len(args) == 1: + tmp = insn_t() + rc = _ida_ua.decode_insn(tmp, args[0]) + cmd.assign(tmp) + return rc + else: + return _ida_ua.decode_insn(*args) +@bc695redef +def create_insn(*args): + if len(args) == 1: + tmp = insn_t() + rc = _ida_ua.create_insn(args[0], tmp) + cmd.assign(tmp) + return rc + else: + return _ida_ua.create_insn(*args) +@bc695redef +def decode_prev_insn(*args): + if len(args) == 1: + tmp = insn_t() + rc = _ida_ua.decode_prev_insn(tmp, args[0]) + cmd.assign(tmp) + return rc + else: + return _ida_ua.decode_prev_insn(*args) +@bc695redef +def decode_preceding_insn(*args): + if len(args) == 1: + tmp = insn_t() + rc = _ida_ua.decode_preceding_insn(tmp, args[0]) + cmd.assign(tmp) + return rc + else: + return _ida_ua.decode_preceding_insn(*args) +import ida_ida +UA_MAXOP=ida_ida.UA_MAXOP +dt_3byte=dt_byte +tbo_123=0 +tbo_132=0 +tbo_213=0 +tbo_231=0 +tbo_312=0 +tbo_321=0 +@bc695redef +def ua_add_cref(opoff, to, rtype): + return cmd.add_cref(to, opoff, rtype) +@bc695redef +def ua_add_dref(opoff, to, rtype): + return cmd.add_dref(to, opoff, rtype) +@bc695redef +def ua_add_off_drefs(x, rtype): + return cmd.add_off_drefs(x, rtype, 0) +@bc695redef +def ua_add_off_drefs2(x, rtype, outf): + return cmd.add_off_drefs(x, rtype, outf) +@bc695redef +def ua_dodata(ea, dtype): + return cmd.create_op_data(ea, 0, dtype) +@bc695redef +def ua_dodata2(opoff, ea, dtype): + return cmd.create_op_data(ea, opoff, dtype) +@bc695redef +def ua_stkvar2(x, v, flags): + return cmd.create_stkvar(x, v, flags) +# diff --git a/pywraps/py_xref.hpp b/pywraps/py_xref.hpp index c5fcdbd..1894994 100644 --- a/pywraps/py_xref.hpp +++ b/pywraps/py_xref.hpp @@ -31,11 +31,11 @@ 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); + switch_info_t *swi = switch_info_t_get_clink(py_swi); if ( swi == NULL ) return false; - create_switch_xrefs(insn_ea, swi); + create_switch_xrefs(insn_ea, *swi); return true; } @@ -74,12 +74,12 @@ 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); + switch_info_t *swi = switch_info_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) ) + if ( !calc_switch_cases(&ct->cases, &ct->targets, insn_ea, *swi) ) { delete ct; return NULL; @@ -108,11 +108,11 @@ 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); + switch_info_t *swi = switch_info_t_get_clink(py_swi); if ( swi == NULL ) return false; - create_switch_table(insn_ea, swi); + create_switch_table(insn_ea, *swi); return true; } // diff --git a/pywraps/pywraps.vcproj b/pywraps/pywraps.vcproj index 50335a9..4bcd7ba 100644 --- a/pywraps/pywraps.vcproj +++ b/pywraps/pywraps.vcproj @@ -1082,7 +1082,7 @@ > - - @@ -1154,7 +1150,7 @@ > = decorate_name) PR_USE64 = 0x002000 # supports 64-bit addressing? PR_SGROTHER = 0x004000 # the segment registers don't contain # the segment selectors, something else @@ -212,13 +212,11 @@ PR_BINMEM = 0x010000 # the processor module provides correct PR_SEGTRANS = 0x020000 # the processor module supports # the segment translation feature # (it means it calculates the code - # addresses using the codeSeg() function) + # addresses using the map_code_ea() 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 @@ -241,7 +239,7 @@ OOFS_NEEDSIGN = 0x0002 # always out sign (+-) OOF_SIGNED = 0x0004 # output as signed if < 0 OOF_NUMBER = 0x0008 # always as a number OOF_WIDTHMASK = 0x0070 # width of value in bits: -OOFW_IMM = 0x0000 # take from x.dtyp +OOFW_IMM = 0x0000 # take from x.dtype OOFW_8 = 0x0010 # 8 bit width OOFW_16 = 0x0020 # 16 bit width OOFW_24 = 0x0030 # 24 bit width @@ -249,7 +247,7 @@ OOFW_32 = 0x0040 # 32 bit width OOFW_64 = 0x0050 # 32 bit width OOF_ADDR = 0x0080 # output x.addr, otherwise x.value OOF_OUTER = 0x0100 # output outer operand -OOF_ZSTROFF = 0x0200 # meaningful only if isStroff(uFlag) +OOF_ZSTROFF = 0x0200 # meaningful only if is_stroff(uFlag) # append a struct field name if # the field offset is zero? # if AFL_ZSTROFF is set, then this flag @@ -272,7 +270,7 @@ class insn_t(object): self.n = 0 self.segpref = 0 self.size = 0 - self.Operands = [] + self.ops = [] # store the number of operands self.n = noperands @@ -281,16 +279,16 @@ class insn_t(object): for i in xrange(0, noperands): op = op_t() op.n = i - self.Operands.append(op) + self.ops.append(op) setattr(self, 'Op%d' % (i+1), op) def __getitem__(self, i): - return self.Operands[i] + return self.ops[i] # ---------------------------------------------------------------------- class op_t(object): def __init__(self): self.addr = 0 - self.dtyp = 0 + self.dtype = 0 self.flags = 0 self.n = 0 self.offb = 0 diff --git a/swig/area.i b/swig/area.i deleted file mode 100644 index adf220c..0000000 --- a/swig/area.i +++ /dev/null @@ -1,56 +0,0 @@ -%ignore ANODE; -%ignore ANODE2; -%ignore AREA_LONG_COMMENT_TAG; -%ignore area_visitor_t; - -// Ignore the private members in areacb_t -%ignore areacb_t::areasCode; -%ignore areacb_t::infosize; -%ignore areacb_t::lastreq; -%ignore areacb_t::reserved; -%ignore areacb_t::areas; -%ignore areacb_t::move_area_comment; -%ignore areacb_t::pack_and_write_area; -%ignore areacb_t::move_away; - -%ignore areacb_t::read_cb; -%ignore areacb_t::write_cb; -%ignore areacb_t::delcache_cb; -%ignore areacb_t::edit_cb; -%ignore areacb_t::kill_cb; -%ignore areacb_t::new_cb; - -%ignore areacb_t::choose_area; -%ignore areacb_t::choose_area2; -%ignore areacb_t::find_prev_gap; -%ignore areacb_t::find_next_gap; - -%ignore areacb_t::move_areas; -%ignore areacb_t::for_all_areas; - -%ignore areaset_t::count; -%ignore areaset_t::lower_bound; -%ignore areaset_t::upper_bound; -%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/auto.i b/swig/auto.i index 65ce048..669ccd3 100644 --- a/swig/auto.i +++ b/swig/auto.i @@ -2,10 +2,5 @@ #include %} -%ignore autoPlanned; -%ignore nextPlanned; -%ignore autoPeek; -%ignore autoProcess; - %include "auto.hpp" diff --git a/swig/bytes.i b/swig/bytes.i index 76a11c4..e98cd8b 100644 --- a/swig/bytes.i +++ b/swig/bytes.i @@ -2,14 +2,12 @@ #include %} -%import "area.i" +%import "range.i" // Unexported and kernel-only declarations -%ignore FlagsEnable; -%ignore FlagsDisable; %ignore testf_t; -%ignore nextthat; -%ignore prevthat; +%ignore next_that; +%ignore prev_that; %ignore adjust_visea; %ignore prev_visea; %ignore next_visea; @@ -17,19 +15,15 @@ %ignore is_first_visea; %ignore is_last_visea; %ignore is_visible_finally; -%ignore fluFlags; %ignore setFlbits; %ignore clrFlbits; %ignore get_8bit; %ignore get_ascii_char; %ignore del_opinfo; %ignore del_one_opinfo; -%ignore doCode; %ignore get_repeatable_cmt; %ignore get_any_indented_cmt; %ignore del_code_comments; -%ignore doFlow; -%ignore noFlow; %ignore coagulate; %ignore FlagsInit; @@ -37,19 +31,23 @@ %ignore FlagsReset; %ignore flush_flags; %ignore get_flags_linput; -%ignore data_type_t; -%ignore data_format_t; -%ignore get_custom_data_type; -%ignore get_custom_data_format; -%ignore unregister_custom_data_format; -%ignore register_custom_data_format; -%ignore unregister_custom_data_type; -%ignore register_custom_data_type; -%ignore get_many_bytes; -%ignore get_many_bytes_ex; -%ignore get_ascii_contents; -%ignore get_ascii_contents2; +%ignore data_type_t::data_type_t(); +%ignore data_type_t::cbsize; +%ignore data_type_t::ud; +%ignore data_type_t::may_create_at; +%ignore data_type_t::calc_item_size; +%ignore data_format_t::data_format_t(); +%ignore data_format_t::cbsize; +%ignore data_format_t::ud; +%ignore data_format_t::print; +%ignore data_format_t::scan; +%ignore data_format_t::analyze; + +%ignore get_bytes; +%ignore get_strlit_contents; %ignore get_hex_string; +%ignore bin_search; // we redefine our own, w/ 2 params swapped, so we can apply the typemaps below +%rename (bin_search) py_bin_search; // TODO: This could be fixed (if needed) %ignore set_dbgmem_source; @@ -64,8 +62,120 @@ } } +%ignore unregister_custom_data_format; +%rename (unregister_custom_data_format) py_unregister_custom_data_format; +%ignore register_custom_data_format; +%rename (register_custom_data_format) py_register_custom_data_format; +%ignore unregister_custom_data_type; +%rename (unregister_custom_data_type) py_unregister_custom_data_type; +%ignore register_custom_data_type; +%rename (register_custom_data_type) py_register_custom_data_type; +%ignore print_strlit_type; +%rename (print_strlit_type) py_print_strlit_type; + +%{ +// +// +%} + +%{ +// +// +%} + +%extend data_type_t +{ + data_type_t( + PyObject *self, + const char *name, + asize_t value_size=0, + const char *menu_name=NULL, + const char *hotkey=NULL, + const char *asm_keyword=NULL, + int props=0) + { + py_custom_data_type_t *inst = new py_custom_data_type_t( + self, + name, + value_size, + menu_name, + hotkey, + asm_keyword, + props); + return inst; + } + + ~data_type_t() + { + delete (py_custom_data_type_t *) $self; + } + + int __get_id() { return py_custom_data_type_t_get_id($self); } + + %pythoncode + { + id = property(__get_id) + __real__init__ = __init__ + def __init__(self, *args): + self.__real__init__(self, *args) # pass 'self' as part of args +#ifdef BC695 + if _BC695: + def __init__(self, name, value_size = 0, menu_name = None, hotkey = None, asm_keyword = None, props = 0): + args = (name, value_size, menu_name, hotkey, asm_keyword, props) + self.__real__init__(self, *args) # pass 'self' as part of args +#endif + } +} + +%extend data_format_t +{ + data_format_t( + PyObject *self, + const char *name, + asize_t value_size=0, + const char *menu_name=NULL, + int props=0, + const char *hotkey=NULL, + int32 text_width=0) + { + py_custom_data_format_t *inst = new py_custom_data_format_t( + self, + name, + value_size, + menu_name, + props, + hotkey, + text_width); + return inst; + } + + ~data_format_t() + { + delete (py_custom_data_format_t *) $self; + } + + int __get_id() { return py_custom_data_format_t_get_id($self); } + + %pythoncode + { + id = property(__get_id) + __real__init__ = __init__ + def __init__(self, *args): + self.__real__init__(self, *args) # pass 'self' as part of args +#ifdef BC695 + if _BC695: + def __init__(self, name, value_size = 0, menu_name = None, props = 0, hotkey = None, text_width = 0): + args = (name, value_size, menu_name, props, hotkey, text_width) + self.__real__init__(self, *args) # pass 'self' as part of args +#endif + } +} + %include "bytes.hpp" +%apply (char *STRING, int LENGTH) { (const uchar *image, size_t len) }; +%apply (char *) { (const uchar *mask) }; + %clear(void *buf, ssize_t size); %clear(const void *buf, size_t size); @@ -73,22 +183,12 @@ %clear(opinfo_t *); %rename (visit_patched_bytes) py_visit_patched_bytes; -%rename (nextthat) py_nextthat; -%rename (prevthat) py_prevthat; -%rename (get_custom_data_type) py_get_custom_data_type; -%rename (get_custom_data_format) py_get_custom_data_format; -%rename (unregister_custom_data_format) py_unregister_custom_data_format; -%rename (register_custom_data_format) py_register_custom_data_format; -%rename (unregister_custom_data_type) py_unregister_custom_data_type; -%rename (register_custom_data_type) py_register_custom_data_type; -%rename (get_many_bytes) py_get_many_bytes; -%rename (get_many_bytes_ex) py_get_many_bytes_ex; -%rename (get_ascii_contents) py_get_ascii_contents; -%rename (get_ascii_contents2) py_get_ascii_contents2; -%{ -// -// -%} +%rename (next_that) py_next_that; +%rename (prev_that) py_prev_that; + +%rename (get_bytes) py_get_bytes; +%rename (get_bytes_and_mask) py_get_bytes_and_mask; +%rename (get_strlit_contents) py_get_strlit_contents; %inline %{ // @@ -100,11 +200,6 @@ # %} -%{ -// -// -%} - %inline %{ // // diff --git a/swig/dbg.i b/swig/dbg.i index 0ddcbc3..35bf83b 100644 --- a/swig/dbg.i +++ b/swig/dbg.i @@ -12,6 +12,8 @@ %ignore internal_cleanup_appcall; %ignore change_bptlocs; %ignore movbpt_info_t; +%ignore lock_dbgmem_config; +%ignore unlock_dbgmem_config; %ignore source_file_t; %ignore source_item_t; diff --git a/swig/diskio.i b/swig/diskio.i index d675a63..070e564 100644 --- a/swig/diskio.i +++ b/swig/diskio.i @@ -8,7 +8,6 @@ // TODO: These could be wrapped %ignore enumerate_files; %rename (enumerate_files) py_enumerate_files; -%ignore enumerate_system_files; %ignore ioport_bit_t; %ignore ioport_bits_t; %ignore ioport_t; @@ -19,7 +18,6 @@ %ignore free_ioports; %ignore lread; %ignore qlread; -%ignore efilelength; %ignore qlgets; %ignore qlgetc; %ignore lreadbytes; @@ -36,18 +34,39 @@ %ignore make_linput; %ignore unmake_linput; -// FIXME: These should be wrapped for completeness %ignore eread; %ignore ewrite; +%ignore eseek; +%ignore ecreate; +%ignore openR; +%ignore openRT; +%ignore openM; +// some of these functions are used in idc.py: +// %ignore eclose; +// %ignore fopenWT; +// %ignore fopenWB; +// %ignore fopenRT; +// %ignore fopenRB; +// %ignore fopenM; +// %ignore fopenA; + +%ignore qfsize; +%ignore echsize; +%ignore get_free_disk_space; +%ignore call_system; // Ignore kernel-only & unexported symbols %ignore get_thread_priority; -%ignore set_thread_priority; -%ignore checkdspace; %ignore lowdiskgo; %ignore ida_argv; %ignore exename; +%ignore create_bytearray_linput; +%rename (create_bytearray_linput) py_create_bytearray_linput; + +%ignore close_linput; +%rename (close_linput) py_close_linput; + %include "diskio.hpp" %{ diff --git a/swig/enum.i b/swig/enum.i index 78fba87..03b76ee 100644 --- a/swig/enum.i +++ b/swig/enum.i @@ -1,29 +1,8 @@ %{ #include %} -// Kernel only & unexported symbols -%ignore enums; -%ignore init_enums; -%ignore save_enums; -%ignore term_enums; -%ignore set_enum_flag(enum_t, uint32, bool); %ignore get_enum_name(tid_t); -%ignore get_selected_enum; -%ignore add_selected_enum; -%ignore unmark_selected_enums; -%ignore ENUM_REVERSE; -%ignore ENUM_SELMEMS; -%ignore ENUM_QTY_IDX; -%ignore ENUM_FLG_IDX; -%ignore ENUM_FLAGS; -%ignore ENUM_FLAGS_IS_BF; -%ignore ENUM_FLAGS_HIDDEN; -%ignore ENUM_MASKS; -%ignore ENUM_MEMBERS; -%ignore CONST_ENUM; -%ignore CONST_VALUE; -%ignore CONST_BMASK; -%ignore CONST_SERIAL; -%ignore CONST_SERIALS; + +%constant bmask_t DEFMASK = bmask_t(-1); %include "enum.hpp" diff --git a/swig/expr.i b/swig/expr.i index 872d5f7..c5291fd 100644 --- a/swig/expr.i +++ b/swig/expr.i @@ -1,17 +1,28 @@ -%ignore extfun_t; -%ignore funcset_t; +%ignore ext_idcfunc_t; +%ignore idcfuncs_t; %ignore extlang_t; -%ignore extlang; +%ignore extlang_object_t; +%ignore extlang_ptr_t; %ignore extlangs_t; %ignore extlangs; -%ignore register_extlang; -%ignore IDCFuncs; -%ignore set_idc_func; +%ignore install_extlang; +%ignore remove_extlang; +%ignore select_extlang; +%ignore get_extlang; +%ignore get_current_extlang; +%ignore find_extlang; +%ignore find_extlang_by_ext; +%ignore find_extlang_by_name; +%ignore find_extlang_by_index; +%ignore find_extlang_kind_t; +%ignore for_all_extlangs; +%ignore extlang_visitor_t; %ignore set_idc_dtor; %ignore set_idc_method; %ignore set_idc_getattr; %ignore set_idc_setattr; -%ignore set_idc_func_ex; +%ignore add_idc_func; +%ignore del_idc_func; %ignore VarLong; %ignore VarNum; %ignore extlang_get_attr_exists; @@ -25,36 +36,38 @@ %ignore get_extlangs; %ignore create_idc_object; %ignore run_script_func; -%ignore VarString; %ignore VarFloat; %ignore VarFree; -%ignore calcexpr_long; -%ignore Run; -%ignore ExecuteLine; -%ignore ExecuteFile; +%ignore eval_expr_long; +%ignore call_idc_func; +%ignore eval_idc_snippet; %ignore set_idc_func_body; %ignore get_idc_func_body; %ignore idc_vars; %ignore setup_lowcnd_regfuncs; %ignore syntax_highlighter_t; %ignore get_idptype_and_data; -%cstring_output_maxstr_none(char *errbuf, size_t errbufsize); +%ignore idc_resolver_t; +%ignore idc_value_t::_set_long; +%ignore idc_value_t::_set_float; +%ignore idc_value_t::_set_int64; +%ignore idc_value_t::_set_pvoid; +%ignore idc_value_t::_set_string; -%ignore CompileEx; -%rename (CompileEx) CompileEx_wrap; -%ignore Compile; -%rename (Compile) Compile_wrap; -%ignore calcexpr; -%rename (calcexpr) calcexpr_wrap; -%ignore calc_idc_expr; -%rename (calc_idc_expr) calc_idc_expr_wrap; -%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL); -%ignore CompileLineEx; -%ignore CompileLine; -%rename (CompileLine) CompileLine_wrap; +%ignore eval_expr; +%rename (eval_expr) py_eval_expr; +%ignore eval_idc_expr; +%rename (eval_idc_expr) py_eval_idc_expr; +%ignore compile_idc_file; +%rename (compile_idc_file) py_compile_idc_file; +%ignore compile_idc_text; +%rename (compile_idc_text) py_compile_idc_text; %nonnul_argument_prototype( - bool CompileLine_wrap(const char *nonnul_line, char *errbuf, size_t errbufsize), + bool py_compile_idc_file(const char *nonnul_line, qstring *errbuf), + const char *nonnul_line); +%nonnul_argument_prototype( + bool py_compile_idc_text(const char *nonnul_line, qstring *errbuf), const char *nonnul_line); %{ // @@ -68,6 +81,21 @@ %include "expr.hpp" +%extend idc_value_t +{ + %pythoncode { + str = property(lambda self: self.c_str(), lambda self, v: self.set_string(v)) + } +} + +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; +%template(idc_values_t) qvector; + %pythoncode %{ # # diff --git a/swig/fixup.i b/swig/fixup.i index 22543ef..009569c 100644 --- a/swig/fixup.i +++ b/swig/fixup.i @@ -3,14 +3,8 @@ %} %ignore apply_fixup; -%ignore custom_fixup_handler_t; -%ignore custom_fixup_handlers_t; +%ignore fixup_handler_t; %ignore register_custom_fixup; %ignore unregister_custom_fixup; -%ignore set_custom_fixup; - -%nonnul_argument_prototype( - idaman void ida_export set_fixup(ea_t source, const fixup_data_t *nonnul_fp), - const fixup_data_t *nonnul_fp); %include "fixup.hpp" diff --git a/swig/frame.i b/swig/frame.i index b76e32c..e5c4d27 100644 --- a/swig/frame.i +++ b/swig/frame.i @@ -2,7 +2,7 @@ #include %} -%import "area.i" +%import "range.i" %ignore add_frame_spec_member; %ignore del_stkvars; @@ -14,9 +14,6 @@ %ignore get_stkvar; %rename (get_stkvar) py_get_stkvar; -%ignore add_stkvar3; -%rename (add_stkvar3) py_add_stkvar3; - %ignore calc_frame_offset; %ignore add_stkvar; diff --git a/swig/funcs.i b/swig/funcs.i index 0678b01..c6322c1 100644 --- a/swig/funcs.i +++ b/swig/funcs.i @@ -1,8 +1,5 @@ -%import "area.i" - -%cstring_bounded_output_none(char *buf, MAXSTR); -%cstring_bounded_output_none(char *optlibs, MAXSTR); +%import "range.i" // FIXME: Are these really useful? %ignore iterate_func_chunks; @@ -17,9 +14,6 @@ %rename (get_idasgn_desc) py_get_idasgn_desc; %rename (get_idasgn_desc_with_matches) py_get_idasgn_desc_with_matches; -%ignore get_func_cmt; -%rename (get_func_cmt) py_get_func_cmt; - %include "funcs.hpp" %clear(char *buf); @@ -29,3 +23,8 @@ // // %} + +%pythoncode %{ +# +# +%} diff --git a/swig/gdl.i b/swig/gdl.i index 3d27551..8bacc3b 100644 --- a/swig/gdl.i +++ b/swig/gdl.i @@ -2,7 +2,7 @@ #include %} -%import "area.i" +%import "range.i" %ignore cancellable_graph_t; %ignore gdl_graph_t; diff --git a/swig/graph.i b/swig/graph.i index 5cf8440..d40069a 100644 --- a/swig/graph.i +++ b/swig/graph.i @@ -1,10 +1,74 @@ %{ #include %} -%ignore mutable_graph_t; -%ignore graph_visitor_t; + +// "Warning 305: Bad constant value (ignored).", on: +// #define GCC_PUREVIRT = 0 +#pragma SWIG nowarn=305 + +// "Warning 473: Returning a pointer or reference in a director method is not recommended." +%warnfilter(473) mutable_graph_t::nrect; +%warnfilter(473) place_t::clone; +%warnfilter(473) place_t::makeplace; +%warnfilter(473) place_t::name; +%warnfilter(473) place_t::enter; + +// "Warning 517: Director class 'mutable_graph_t' can't be constructed" +%warnfilter(517) mutable_graph_t; + +// most of these aren't defined/exported through graph.hpp +%ignore abstract_graph_t::callback; %ignore abstract_graph_t; +%ignore edge_info_t::add_layout_point; +%ignore edge_infos_wrapper_t::edge_infos_wrapper_t; +%ignore edge_infos_wrapper_t::~edge_infos_wrapper_t; +%ignore graph_dispatcher; +%ignore graph_item_t::operator==; +%ignore mutable_graph_t::add_edge; +%ignore mutable_graph_t::add_node; +%ignore mutable_graph_t::calc_center_of; +%ignore mutable_graph_t::change_visibility; +%ignore mutable_graph_t::check_new_group; +%ignore mutable_graph_t::clone; +%ignore mutable_graph_t::del_edge; +%ignore mutable_graph_t::del_node; +%ignore mutable_graph_t::fix_collapsed_group_edges; +%ignore mutable_graph_t::get_edge; +%ignore mutable_graph_t::groups_are_present; +%ignore mutable_graph_t::insert_simple_nodes; +%ignore mutable_graph_t::insert_visible_nodes; +%ignore mutable_graph_t::move_grouped_nodes; +%ignore mutable_graph_t::move_to_same_place; +%ignore mutable_graph_t::mutable_graph_t; +%ignore mutable_graph_t::redo_layout; +%ignore mutable_graph_t::refresh; +%ignore mutable_graph_t::replace_edge; +%ignore mutable_graph_t::resize; +%ignore mutable_graph_t::set_nrect; +%ignore node_ordering_t::clr; +%ignore node_ordering_t::order; +%ignore point_t::dstr; +%ignore point_t::print; +%ignore pointseq_t::dstr; +%ignore pointseq_t::print; +%ignore rect_t::operator<; +%ignore selection_item_t::selection_item_t(class graph_item_t &); +%feature("nodirector") user_graph_place_t; + +// Those were deprecated before they were available +// to IDAPython, so let's keep it that way. +%ignore viewer_add_menu_item; +%ignore viewer_del_menu_item; + +%extend graph_visitor_t { +public: + virtual int idaapi visit_node(int /*n*/, rect_t & /*r*/) { return 0; } + virtual int idaapi visit_edge(edge_t /*e*/, edge_info_t * /*ei*/) { return 0; } +} + %include "graph.hpp" +%ignore graph_visitor_t::visit_node; +%ignore graph_visitor_t::visit_edge; %{ // diff --git a/swig/hexrays.i b/swig/hexrays.i index e4aa107..9828e24 100644 --- a/swig/hexrays.i +++ b/swig/hexrays.i @@ -10,11 +10,6 @@ static void _kludge_use_TPopupMenu(TPopupMenu *) {} %} %inline %{ -namespace Menus -{ - class TPopupMenu; -} -using Menus::TPopupMenu; static void _kludge_use_TPopupMenu(TPopupMenu *m); %} @@ -53,9 +48,11 @@ static void _kludge_use_TPopupMenu(TPopupMenu *m); #define AS_PRINTF(format_idx, varg_idx) %ignore vd_printer_t::vprint; +%ignore vd_printer_t::tmpbuf; %ignore string_printer_t::vprint; %ignore vdui_t::vdui_t; %ignore cblock_t::find; +%ignore citem_t::op; %ignore cfunc_t::cfunc_t; %ignore cfunc_t::sv; // lazy member. Use get_pseudocode() instead %ignore cfunc_t::boundaries; // lazy member. Use get_boundaries() instead @@ -88,6 +85,33 @@ static void _kludge_use_TPopupMenu(TPopupMenu *m); %ignore file_printer_t::_print; %ignore file_printer_t; %ignore qstring_printer_t::qstring_printer_t(const cfunc_t *, qstring &, bool); +%rename (_replace_by) cinsn_t::replace_by; +%rename (_replace_by) cexpr_t::replace_by; +%ignore vcall_helper; +%ignore vcreate_helper; + +%apply uchar { char ignore_micro }; +%feature("nodirector") udc_filter_t::apply; + +// The following must: +// - transfer ownership to the result object, if the argument object had it +// That's because we don't know when one of those functions create +// a new object under the hood +%rename (_ll_lnot) lnot; +%rename (_ll_make_ref) make_ref; +%rename (_ll_dereference) dereference; + +// The following must: +// - mark new object as being owned +// - disown the 'args' object passed as parameter +%rename (_ll_call_helper) call_helper; + +// The following must: +// - mark new object as being owned +%rename (_ll_new_block) new_block; +%rename (_ll_make_num) make_num; +%rename (_ll_create_helper) create_helper; + %extend cfunc_t { %immutable argidx; @@ -120,7 +144,7 @@ static void _kludge_use_TPopupMenu(TPopupMenu *m); %rename(dereference_uint16) operator uint16*; %rename(dereference_const_uint16) operator const uint16*; -#if !defined(__MAC__) || (MACSDKVER >= 1060) +#if !defined(__MAC__) || (MACSDKVER >= 1006) #define HAS_MAP_AT #endif @@ -140,67 +164,223 @@ public: } #endif +//------------------------------------------------------------------------- +%typemap(check) citem_t *self +{ + if ( $1 == INS_EPILOG ) + SWIG_exception_fail(SWIG_ValueError, "invalid INS_EPILOG " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); +} + +%typemap(check) cinsn_t *self +{ + if ( $1 == INS_EPILOG ) + SWIG_exception_fail(SWIG_ValueError, "invalid INS_EPILOG " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); +} + +//------------------------------------------------------------------------- +// citem_t //--------------------------------------------------------------------- %extend citem_t { // define these two struct members that can be used for casting. cinsn_t *cinsn const { return (cinsn_t *)self; } cexpr_t *cexpr const { return (cexpr_t *)self; } + + ctype_t _get_op() const { return self->op; } + void _set_op(ctype_t v) { self->op = v; } + + PyObject *_obj_id() const { return PyLong_FromSize_t(size_t(self)); } + + %pythoncode { + obj_id = property(_obj_id) + op = property( + _get_op, + lambda self, v: self._ensure_no_op() and self._set_op(v)) + + def _ensure_no_op(self): + if self.op not in [cot_empty, cit_empty]: + raise Exception("%s has op %s; cannot be modified" % (self, self.op)) + return True + + def _ensure_no_obj(self, o, attr, attr_is_acquired): + if attr_is_acquired and o is not None: + raise Exception("%s already owns attribute \"%s\" (%s); cannot be modified" % (self, attr, o)) + return True + + def _acquire_ownership(self, v, acquire): + if acquire and (v is not None) and not isinstance(v, (int, long)): + if not v.thisown: + raise Exception("%s is already owned, and cannot be reused" % v) + v.thisown = False + dereg = getattr(v, "_deregister", None) + if dereg: + dereg() + return True + + def _maybe_disown_and_deregister(self): + if self.thisown: + self.thisown = False + self._deregister() + + def _own_and_register(self): + assert(not self.thisown) + self.thisown = True + self._register() + + def replace_by(self, o): + assert(isinstance(o, (cexpr_t, cinsn_t))) + o._maybe_disown_and_deregister() + self._replace_by(o) + } }; -//--------------------------------------------------------------------- -// swig doesn't very much like the way the union is done in this class so we need to wrap all these up. -#define CITEM_MEMBER_REF(name) \ - c##name##_t *c##name const { if ( self->op == cit_##name ) { return self->c##name; } else { return NULL; } } - -%extend cinsn_t { - CITEM_MEMBER_REF(block); - CITEM_MEMBER_REF(expr); - CITEM_MEMBER_REF(if); - CITEM_MEMBER_REF(for); - CITEM_MEMBER_REF(while); - CITEM_MEMBER_REF(do); - CITEM_MEMBER_REF(switch); - CITEM_MEMBER_REF(return); - CITEM_MEMBER_REF(goto); - CITEM_MEMBER_REF(asm); - - bool is_epilog() const { return $self == INS_EPILOG; } -}; -#undef CITEM_MEMBER_REF - //------------------------------------------------------------------------- -#define CEXPR_MEMBER_REF(type, name) \ - type name const { return self->##name; } +#define ___MEMBER_REF_BASE(Type, PName, Cond, Defval, Acquire, Setexpr) \ + Type _get_##PName() const { return self->##PName; } \ + void _set_##PName(Type _v) { self->##PName = Setexpr; } \ + %pythoncode { \ + PName = property( \ + lambda self: self._get_##PName() if Cond else Defval, \ + lambda self, v: Cond \ + and self._ensure_no_obj(self._get_##PName(), #PName, Acquire) \ + and self._acquire_ownership(v, Acquire) \ + and self._set_##PName(v)) \ + } -#define CEXPR_CONDITIONAL_MEMBER_REF(type, name, condition, default_value) \ - type name const { if ( condition ) { return self->##name; } else { return default_value; } } + +//--------------------------------------------------------------------- +// cinsn_t +//--------------------------------------------------------------------- +#define CINSN_MEMBER_REF(Name) \ + ___MEMBER_REF_BASE(c##Name##_t*, c##Name, self.op == cit_##Name, None, True, _v) + +%extend cinsn_t { + cinsn_t(void) + { + cinsn_t *ci = new cinsn_t(); + ci->cblock = NULL; // force clean instance + hexrays_register_python_clearable_instance(ci, hxclr_cinsn); + return ci; + } + + ~cinsn_t(void) + { + hexrays_deregister_python_clearable_instance($self); + delete $self; + } + + void _deregister() { hexrays_deregister_python_clearable_instance($self); } + void _register() { hexrays_register_python_clearable_instance($self, hxclr_cinsn); } + + CINSN_MEMBER_REF(block); + CINSN_MEMBER_REF(expr); + CINSN_MEMBER_REF(if); + CINSN_MEMBER_REF(for); + CINSN_MEMBER_REF(while); + CINSN_MEMBER_REF(do); + CINSN_MEMBER_REF(switch); + CINSN_MEMBER_REF(return); + CINSN_MEMBER_REF(goto); + CINSN_MEMBER_REF(asm); + + static bool insn_is_epilog(const cinsn_t *insn) const { return insn == INS_EPILOG; } + + %pythoncode { + def is_epilog(self): + return cinsn_t.insn_is_epilog(self) + } +}; +%ignore cinsn_t::cinsn_t; +#undef CINSN_MEMBER_REF + +//------------------------------------------------------------------------- +// cexpr_t +//------------------------------------------------------------------------- +#define CEXPR_MEMBER_REF(Type, PName, Cond, Defval, Acquire) \ + ___MEMBER_REF_BASE(Type, PName, Cond, Defval, Acquire, _v) + +#define CEXPR_MEMBER_REF_STR(Type, PName, Cond, Defval) \ + ___MEMBER_REF_BASE(Type, PName, Cond, Defval, False, ::qstrdup(_v)) %extend cexpr_t { - CEXPR_CONDITIONAL_MEMBER_REF(cnumber_t*, n, self->op == cot_num, NULL); - CEXPR_CONDITIONAL_MEMBER_REF(fnumber_t*, fpc, self->op == cot_fnum, NULL); - var_ref_t* v const { if ( self->op == cot_var ) { return &self->v; } else { return NULL; } } - CEXPR_CONDITIONAL_MEMBER_REF(ea_t, obj_ea, self->op == cot_obj, BADADDR); - CEXPR_MEMBER_REF(int, refwidth); - CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, x, op_uses_x(self->op), NULL); - CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, y, op_uses_y(self->op), NULL); - CEXPR_CONDITIONAL_MEMBER_REF(carglist_t*, a, self->op == cot_call, NULL); - CEXPR_CONDITIONAL_MEMBER_REF(int, m, self->op == cot_memptr || self->op == cot_memref, 0); - CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, z, op_uses_z(self->op), NULL); - CEXPR_CONDITIONAL_MEMBER_REF(int, ptrsize, self->op == cot_ptr || self->op == cot_memptr, 0); - CEXPR_MEMBER_REF(cinsn_t*, insn); - CEXPR_CONDITIONAL_MEMBER_REF(char*, helper, self->op == cot_helper, NULL); - CEXPR_CONDITIONAL_MEMBER_REF(char*, string, self->op == cot_str, NULL); -}; + cexpr_t(void) + { + cexpr_t *ce = new cexpr_t(); + hexrays_register_python_clearable_instance(ce, hxclr_cexpr); + return ce; + } -#undef CEXPR_CONDITIONAL_MEMBER_REF + ~cexpr_t(void) + { + hexrays_deregister_python_clearable_instance($self); + delete $self; + } + + void _deregister() { hexrays_deregister_python_clearable_instance($self); } + void _register() { hexrays_register_python_clearable_instance($self, hxclr_cexpr); } + + CEXPR_MEMBER_REF(cnumber_t*, n, self.op == cot_num, None, True); + CEXPR_MEMBER_REF(fnumber_t*, fpc, self.op == cot_fnum, None, True); + var_ref_t* get_v() { if ( self->op == cot_var ) { return &self->v; } else { return NULL; } } + void set_v(const var_ref_t *v) { if ( self->op == cot_var ) { self->v = *v; } } + %pythoncode { + v = property(lambda self: self.get_v(), lambda self, v: self.set_v(v)) + } + CEXPR_MEMBER_REF(ea_t, obj_ea, self.op == cot_obj, ida_idaapi.BADADDR, False); + CEXPR_MEMBER_REF(int, refwidth, True, 0, False); + CEXPR_MEMBER_REF(cexpr_t*, x, op_uses_x(self.op), None, True); + CEXPR_MEMBER_REF(cexpr_t*, y, op_uses_y(self.op), None, True); + CEXPR_MEMBER_REF(carglist_t*, a, self.op == cot_call, None, True); + CEXPR_MEMBER_REF(int, m, (self.op == cot_memptr or self.op == cot_memref), 0, False); + CEXPR_MEMBER_REF(cexpr_t*, z, op_uses_z(self.op), None, True); + CEXPR_MEMBER_REF(int, ptrsize, (self.op == cot_ptr or self.op == cot_memptr), 0, False); + CEXPR_MEMBER_REF(cinsn_t*, insn, self.op == cot_insn, None, True); + CEXPR_MEMBER_REF_STR(char*, helper, self.op == cot_helper, None); + CEXPR_MEMBER_REF_STR(char*, string, self.op == cot_str, None); +}; +%ignore cexpr_t::cexpr_t; + +#undef CEXPR_MEMBER_REF_STR #undef CEXPR_MEMBER_REF //------------------------------------------------------------------------- -#define CTREE_ITEM_MEMBER_REF(type, name) \ - type name const { return self->##name; } +// ctree_item_t +//------------------------------------------------------------------------- +// FIXME: I can't enable setters, because the ctree_item_t doesn't +// have a cleanup() function that would greatly help getting rid of +// objects that were referenced by SWiG proxies, but which have been +// de-owned (see cexpr_t above.) +// #define CTREE_ITEM_MEMBER_REF(type, name) \ +// type get_##name() const { return self->##name; } \ +// void set_##name(type _v) { self->##name = _v; } \ +// %pythoncode { \ +// name = property(lambda self: self.get_##name(), lambda self, v: self.set_##name(v)) \ +// } +// +// #define CTREE_CONDITIONAL_ITEM_MEMBER_REF(type, name, wanted_citype) \ +// type get_##name() const { if ( self->citype == wanted_citype ) { return self->##name; } else { return NULL; } } \ +// void set_##name(type _v) { if ( self->citype == wanted_citype ) { self->##name = _v; } } \ +// %pythoncode { \ +// name = property(lambda self: self.get_##name(), lambda self, v: self.set_##name(v)) \ +// } + +#define CTREE_ITEM_MEMBER_REF(type, name) \ + type _get_##name() const { return self->##name; } \ + %pythoncode { \ + name = property(lambda self: self._get_##name()) \ + } + +#define CTREE_CONDITIONAL_ITEM_MEMBER_REF(type, name, wanted_citype) \ + type _get_##name() const \ + { \ + if ( self->citype == wanted_citype ) \ + return self->##name; \ + else \ + return NULL; \ + } \ + %pythoncode { \ + name = property(lambda self: self._get_##name()) \ + } -#define CTREE_CONDITIONAL_ITEM_MEMBER_REF(type, name, wanted_citype) \ - type name const { if ( self->citype == wanted_citype ) { return self->##name; } else { return NULL; } } %extend ctree_item_t { CTREE_ITEM_MEMBER_REF(citem_t *, it); @@ -259,7 +439,13 @@ typedef qvector strvec_t; %template(user_unions_t) std::map; %template(cinsnptrvec_t) qvector; %template(eamap_t) std::map; -%template(boundaries_t) std::map; +%template(boundaries_t) std::map; + +%ignore boundaries_find; +%rename (boundaries_find) py_boundaries_find; +%ignore boundaries_insert; +%rename (boundaries_insert) py_boundaries_insert; + // WARNING: The order here is VERY important: // 1) The '%extend' directive. Note that // - the template name must be used, not the typedef (i.e., not 'cfuncptr_t') @@ -269,7 +455,7 @@ typedef qvector strvec_t; // - not qualifying the destructor with template parameters // 3) The '%template' directive, that will indeed instantiate // the template for swig. -%{ void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp); %} +%{ void hexrays_deregister_python_clearable_instance(void *ptr); %} %extend qrefcnt_t { // The typemap above will take care of registering newly-constructed cfuncptr_t // instances. However, there's no such thing as a destructor typemap. @@ -278,7 +464,7 @@ typedef qvector strvec_t; // be a different destructor (which, of course, makes a ton of sense.) ~qrefcnt_t(void) { - hexrays_deregister_python_cfuncptr_t_instance($self); + hexrays_deregister_python_clearable_instance($self); delete $self; } } @@ -323,6 +509,24 @@ class qlist_cinsn_t_iterator {}; %template(qvector_ccase_t) qvector; %template(lvar_saved_infos_t) qvector; +%extend cblock_t { + cblock_t(void) + { + cblock_t *cb = new cblock_t(); + hexrays_register_python_clearable_instance(cb, hxclr_cblock); + return cb; + } + + ~cblock_t(void) + { + hexrays_deregister_python_clearable_instance($self); + delete $self; + } + + void _deregister() { hexrays_deregister_python_clearable_instance($self); } +} +%ignore cblock_t::cblock_t; + %extend citem_cmt_t { const char *c_str() const { return self->c_str(); } @@ -349,9 +553,6 @@ void qswap(cinsn_t &a, cinsn_t &b); %ignore init_hexrays_plugin; %rename(init_hexrays_plugin) py_init_hexrays_plugin; -%ignore 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) py_install_hexrays_callback; @@ -361,8 +562,8 @@ void qswap(cinsn_t &a, cinsn_t &b); %ignore decompile_many; %rename (decompile_many) py_decompile_many; -%ignore get_tform_vdui; -%rename (get_tform_vdui) py_get_tform_vdui; +%ignore get_widget_vdui; +%rename (get_widget_vdui) py_get_widget_vdui; //------------------------------------------------------------------------- #if SWIG_VERSION == 0x20012 @@ -371,7 +572,7 @@ void qswap(cinsn_t &a, cinsn_t &b); { // ret cfuncptr_t cfuncptr_t *ni = new cfuncptr_t($1); - hexrays_register_python_cfuncptr_t_instance(ni); + hexrays_register_python_clearable_instance(ni, hxclr_cfuncptr); $result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0); } @@ -381,7 +582,7 @@ void qswap(cinsn_t &a, cinsn_t &b); { // ret cfuncptr_t* cfuncptr_t *ni = new cfuncptr_t(*($1)); - hexrays_register_python_cfuncptr_t_instance(ni); + hexrays_register_python_clearable_instance(ni, hxclr_cfuncptr); $result = SWIG_NewPointerObj(ni, $1_descriptor, SWIG_POINTER_OWN | 0); } #else @@ -424,6 +625,18 @@ void qswap(cinsn_t &a, cinsn_t &b); %possible_director_exc(ctree_visitor_t::apply_to) %possible_director_exc(ctree_visitor_t::apply_to_exprs) +%template (fnum_array) wrapped_array_t; +%extend fnumber_t { + wrapped_array_t __get_fnum() { + return wrapped_array_t($self->fnum); + } + + %pythoncode { + fnum = property(__get_fnum) + } +} + + %inline %{ // // diff --git a/swig/ida.i b/swig/ida.i index ab1af4b..4823cfb 100644 --- a/swig/ida.i +++ b/swig/ida.i @@ -1,9 +1,43 @@ // Ignore kernel-only symbols -%ignore dual_text_options_t; %ignore idainfo::align_short_demnames; %ignore idainfo::align_strtype; %ignore idainfo::align_long_demnames; %ignore idainfo::store_user_info; +%ignore idainfo::zero; +%ignore idainfo::padding; +%ignore idainfo::netdelta; +%ignore idainfo::privrange; +%ignore idainfo::padding2; +%ignore idainfo::idainfo; +%ignore idainfo::~idainfo; + +%extend idainfo +{ + qstring get_abiname() + { + qstring buf; + get_abi_name(&buf); + return buf; + } + +#ifdef BC695 + // Compat 6.95; since inf is a cvar, I can't just add properties to it.. + ea_t get_minEA() const { return $self->min_ea; } + void set_minEA(ea_t ea) { $self->min_ea = ea; } + ea_t get_maxEA() const { return $self->max_ea; } + void set_maxEA(ea_t ea) { $self->max_ea = ea; } + qstring get_procName() const { return $self->procname; } +#endif + + %pythoncode { + abiname = property(get_abiname) +#ifdef BC695 + minEA = property(get_minEA, set_minEA) + maxEA = property(get_maxEA, set_maxEA) + procName = property(get_procName) +#endif + } +} %ignore setflag(uchar &where,uchar bit,int value); %ignore setflag(ushort &where,ushort bit,int value); diff --git a/swig/idc.i b/swig/idc.i new file mode 100644 index 0000000..7cf2299 --- /dev/null +++ b/swig/idc.i @@ -0,0 +1,22 @@ + +// This contains helpers needed for idc.py to work correctly + +%{ +#include +#include +%} + +%{ +// +// +%} + +%inline %{ +// +// +%} + +%pythoncode %{ +# +# +%} diff --git a/swig/idd.i b/swig/idd.i index e8942e5..586f7fb 100644 --- a/swig/idd.i +++ b/swig/idd.i @@ -1,6 +1,7 @@ %{ #include #include +#include #include %} @@ -14,7 +15,7 @@ %ignore appcall; %ignore idd_opinfo_t; %ignore gdecode_t; -%apply unsigned char { char dtyp }; +%apply unsigned char { op_dtype_t dtype }; %ignore qvector::operator==; %ignore qvector::operator!=; @@ -24,6 +25,14 @@ %ignore qvector::add_unique; %template(excvec_t) qvector; +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; +%template(procinfo_vec_t) qvector; + %include "idd.hpp" // SWIG chokes on the original declaration so it is replicated here @@ -33,7 +42,7 @@ typedef struct ushort fval[6]; // 12: floating point value in the internal representation (see ieee.h) } regval_t; -%clear(char dtyp); +%clear(op_dtype_t dtype); %rename (appcall) py_appcall; diff --git a/swig/idp.i b/swig/idp.i index ee0007a..6f95b45 100644 --- a/swig/idp.i +++ b/swig/idp.i @@ -4,10 +4,9 @@ #include #include #include +#include %} // Ignore the following symbols -%ignore WorkReg; -%ignore AbstractRegister; %ignore rginfo; %ignore insn_t::get_canon_mnem; %ignore insn_t::get_canon_feature; @@ -23,7 +22,6 @@ %ignore IDPOPT_BADTYPE; %ignore IDPOPT_BADVALUE; %ignore set_options_t; -%ignore read_user_config_file; %ignore read_config; %ignore read_config_file; %ignore read_config_string; @@ -36,9 +34,8 @@ %ignore _chkarg_cmd; %ignore ENUM_SIZE; -%ignore asm_t::checkarg_dispatch; -%ignore asm_t::func_header; -%ignore asm_t::func_footer; +%ignore asm_t::out_func_header; +%ignore asm_t::out_func_footer; %ignore asm_t::get_type_name; %ignore instruc_t; %ignore processor_t; @@ -46,11 +43,49 @@ %ignore IDP_Callback; %ignore _py_getreg; +%ignore hook_cb_t; +%ignore hook_type_t; +%ignore hook_to_notification_point; +%ignore unhook_from_notification_point; +%ignore invoke_callbacks; + +// @arnaud +%ignore notify__calc_next_eas; +%ignore notify__custom_ana; +%ignore notify__custom_emu; +%ignore notify__custom_mnem; +%ignore notify__custom_out; +%ignore notify__custom_outop; +%ignore notify__get_autocmt; +%ignore notify__get_dbr_opnum; +%ignore notify__get_operand_string; +%ignore notify__insn_reads_tbit; +%ignore notify__is_basic_block_end; +%ignore notify__is_call_insn; +%ignore notify__is_cond_insn; +%ignore notify__is_indirect_jump; +%ignore notify__is_insn_table_jump; +%ignore notify__is_ret_insn; +%ignore notify__is_sane_insn; +%ignore notify__may_be_func; +%ignore notify__make_code; +// @arnaud ^^^ + +// @arnaud ditch this once all modules are ported +// temporary: +%ignore out_old_data; +%ignore out_old_specea; + %nonnul_argument_prototype( static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *nonnul_line), const char *nonnul_line); %include "idp.hpp" +%include "config.hpp" + +%typemap(check) tinfo_t const* optional_type +{ +} %inline %{ // diff --git a/swig/ints.i b/swig/ints.i deleted file mode 100644 index ae0a682..0000000 --- a/swig/ints.i +++ /dev/null @@ -1,2 +0,0 @@ -%include "ints.i" - diff --git a/swig/kernwin.i b/swig/kernwin.i index caccd5a..22ffe02 100644 --- a/swig/kernwin.i +++ b/swig/kernwin.i @@ -11,19 +11,21 @@ extern plugin_t PLUGIN; %} // Ignore the va_list functions -%ignore AskUsingForm_cv; -%ignore AskUsingForm_c; -%ignore OpenForm_cv; -%ignore OpenForm_c; +%ignore vask_form; +%ignore ask_form; +%ignore open_form; +%ignore vopen_form; %ignore close_form; -%ignore vaskstr; +%ignore vask_str; +%ignore ask_str; +%ignore ask_ident; +%ignore vask_buttons; +%ignore vask_file; +%ignore vask_yn; %ignore strvec_t; %ignore load_custom_icon; -%ignore vasktext; -%ignore add_menu_item; -%rename (add_menu_item) py_add_menu_item; -%ignore del_menu_item; -%rename (del_menu_item) py_del_menu_item; +%ignore vask_text; +%ignore ask_text; %ignore vwarning; %ignore choose_idasgn; @@ -46,11 +48,6 @@ extern plugin_t PLUGIN; %ignore vnomem; %ignore vmsg; %ignore show_wait_box_v; -%ignore askbuttons_cv; -%ignore askfile_cv; -%ignore askyn_cv; -%ignore askyn_v; -%ignore add_custom_viewer_popup_item; %ignore create_custom_viewer; %ignore take_database_snapshot; %rename (take_database_snapshot) py_take_database_snapshot; @@ -58,7 +55,6 @@ extern plugin_t PLUGIN; %rename (restore_database_snapshot) py_restore_database_snapshot; %ignore destroy_custom_viewer; %ignore destroy_custom_viewerdestroy_custom_viewer; -%ignore set_custom_viewer_popup_menu; %ignore set_custom_viewer_handler; %ignore set_custom_viewer_range; %ignore is_idaview; @@ -66,24 +62,20 @@ extern plugin_t PLUGIN; %ignore set_custom_viewer_handlers; %ignore get_viewer_name; // Ignore these string functions. There are trivial replacements in Python. -%ignore addblanks; %ignore trim; -%ignore skipSpaces; +%ignore skip_spaces; %ignore stristr; %ignore set_nav_colorizer; %rename (set_nav_colorizer) py_set_nav_colorizer; %rename (call_nav_colorizer) py_call_nav_colorizer; -%ignore get_highlighted_identifier; -%rename (get_highlighted_identifier) py_get_highlighted_identifier; - +%ignore get_highlight; +%rename (get_highlight) py_get_highlight; %ignore action_desc_t::handler; %ignore action_handler_t; %ignore register_action; %rename (register_action) py_register_action; -%ignore unregister_action; -%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; @@ -91,9 +83,9 @@ extern plugin_t PLUGIN; %include "typemaps.i" -%rename (asktext) py_asktext; +%rename (ask_text) py_ask_text; +%rename (ask_str) py_ask_str; %rename (str2ea) py_str2ea; -%rename (str2user) py_str2user; %ignore process_ui_action; %rename (process_ui_action) py_process_ui_action; %ignore execute_sync; @@ -110,11 +102,13 @@ extern plugin_t PLUGIN; %ignore unregister_timer; %rename (unregister_timer) py_unregister_timer; -// Make askaddr(), askseg(), and asklong() return a +%ignore chooser_item_attrs_t::cb; + +// Make ask_addr(), ask_seg(), and ask_long() return a // tuple: (result, value) -%rename (_asklong) asklong; -%rename (_askaddr) askaddr; -%rename (_askseg) askseg; +%rename (_ask_long) ask_long; +%rename (_ask_addr) ask_addr; +%rename (_ask_seg) ask_seg; %ignore qvector::operator==; %ignore qvector::operator!=; @@ -142,6 +136,9 @@ extern plugin_t PLUGIN; %ignore register_loc_converter; %ignore lookup_loc_converter; +%ignore hexplace_t; +%ignore hexplace_gen_t; + %feature("director") UI_Hooks; //------------------------------------------------------------------------- @@ -186,22 +183,20 @@ struct py_action_handler_t : public action_handler_t newref_t pyres(PyObject_CallMethod(pyah.o, (char *)"update", (char *) "O", pyctx.o)); return PyErr_Occurred() ? AST_DISABLE_ALWAYS : ((pyres != NULL && PyInt_Check(pyres.o)) ? action_state_t(PyInt_AsLong(pyres.o)) : AST_DISABLE); } + private: ref_t pyah; bool has_activate; bool has_update; }; -typedef std::map py_action_handlers_t; -static py_action_handlers_t py_action_handlers; - %} %inline %{ -void refresh_lists(void) +void refresh_choosers(void) { Py_BEGIN_ALLOW_THREADS; - callui(ui_list); + callui(ui_refresh_choosers); Py_END_ALLOW_THREADS; } %} @@ -249,7 +244,8 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); PyObject *handler, const char *shortcut = NULL, const char *tooltip = NULL, - int icon = -1) + int icon = -1, + int flags = 0) { action_desc_t *ad = new action_desc_t(); #define DUPSTR(Prop) ad->Prop = Prop == NULL ? NULL : qstrdup(Prop) @@ -260,6 +256,7 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); #undef DUPSTR ad->icon = icon; ad->handler = new py_action_handler_t(handler); + ad->flags = flags | ADF_OWN_HANDLER; ad->owner = &PLUGIN; return ad; } @@ -278,6 +275,22 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); } } +%extend action_ctx_base_t { + + int _get_reg() const { return $self->reg; } + +#ifdef BC695 + twidget_type_t _get_form_type() const { return $self->widget_type; } +#endif + + %pythoncode { + reg = property(_get_reg) +#ifdef BC695 + form_type = property(_get_form_type) +#endif + } +} + //------------------------------------------------------------------------- %extend place_t { static idaplace_t *as_idaplace_t(place_t *p) { return (idaplace_t *) p; } @@ -319,8 +332,13 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); %} //------------------------------------------------------------------------- -// choose +// Choose //------------------------------------------------------------------------- +%{ +// +// +%} + %inline %{ // // @@ -332,39 +350,21 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); %} //------------------------------------------------------------------------- -// choose2 +// ask_form //------------------------------------------------------------------------- %{ -// -// +// +// %} %inline %{ -// -// +// +// %} %pythoncode %{ -# -# -%} - -//------------------------------------------------------------------------- -// askusingform -//------------------------------------------------------------------------- -%{ -// -// -%} - -%inline %{ -// -// -%} - -%pythoncode %{ -# -# +# +# %} @@ -388,8 +388,28 @@ static void _py_unregister_compiled_form(PyObject *py_form, bool shutdown); //------------------------------------------------------------------------- %init %{ -// -// +// +// +%} + +//------------------------------------------------------------------------- +// CustomIDAMemo +//------------------------------------------------------------------------- +%ignore View_Callback; + +%inline %{ +// +// +%} + +%{ +// +// +%} + +%pythoncode %{ +# +# %} diff --git a/swig/lines.i b/swig/lines.i index 008f314..370afbc 100644 --- a/swig/lines.i +++ b/swig/lines.i @@ -1,31 +1,9 @@ // FIXME: These should be fixed %ignore requires_color_esc; -%ignore tag_on; -%ignore tag_off; -%ignore tag_addchr; -%ignore tag_addstr; -%ignore get_user_defined_prefix; // Ignore va_list versions -%ignore printf_line_v; -%ignore gen_colored_cmt_line_v; -%ignore gen_cmt_line_v; -%ignore add_long_cmt_v; -%ignore describex; +%ignore vadd_extra_line; // Kernel-only and unexported symbols -%ignore save_sourcefiles; -%ignore ml_getcmt_t; -%ignore ml_getnam_t; -%ignore ml_genxrf_t; -%ignore ml_saver_t; -%ignore setup_makeline; -%ignore MAKELINE_NONE; -%ignore MAKELINE_BINPREF; -%ignore MAKELINE_VOID; -%ignore MAKELINE_STACK; -%ignore save_line_in_array; -%ignore init_lines_array; -%ignore finish_makeline; -%ignore makeline_producer_t; +%ignore get_last_pfxlen; %ignore closing_comment; %ignore close_comment; %ignore init_lines; diff --git a/swig/loader.i b/swig/loader.i index 8ea78a8..cdfe883 100644 --- a/swig/loader.i +++ b/swig/loader.i @@ -3,7 +3,7 @@ %ignore loader_t::load_file; %ignore loader_t::save_file; %ignore loader_t::move_segm; -%ignore loader_t::init_loader_options; +%ignore loader_t::process_archive; %ignore plugin_t; %ignore vloader_failure; @@ -16,7 +16,6 @@ %ignore free_loaders_list; %ignore get_loader_name_from_dll; %ignore get_loader_name; -%ignore init_loader_options; %ignore load_nonbinary_file; %ignore impinfo_t; %ignore import_module; @@ -33,11 +32,6 @@ %ignore html_line_cb_t; %ignore gen_outline_t; %ignore create_filename_cmt; -%ignore hook_cb_t; -%ignore hook_type_t; -%ignore hook_to_notification_point; -%ignore unhook_from_notification_point; -%ignore invoke_callbacks; // Ignore kernel-only & unexported symbols %ignore LDSC; @@ -58,11 +52,12 @@ %ignore RE_BADATP; %ignore RE_BADMAP; %ignore load_dll_or_die; -%ignore load_dll_or_say; +%ignore load_core_module; +%ignore load_core_module_or_die; +%ignore _load_core_module; %ignore free_dll; %ignore IDP_DESC_START; %ignore IDP_DESC_END; -%ignore get_idp_desc; %ignore get_idp_descs; %ignore init_fileregions; %ignore term_fileregions; @@ -70,9 +65,7 @@ %ignore add_fileregion; %ignore move_fileregions; %ignore del_fileregions; -%ignore enum_processor_modules; %ignore enum_plugins; -%ignore database_id0; %ignore is_database_ext; %ignore is_temp_database; diff --git a/swig/moves.i b/swig/moves.i index 91078b4..4f54de5 100644 --- a/swig/moves.i +++ b/swig/moves.i @@ -11,7 +11,16 @@ %ignore location_t::location_t(bool); %ignore lochist_t::is_hexrays68_compat; %ignore lochist_entry_t::set_place(const place_t &); +%ignore graph_location_info_t::serialize(bytevec_t *) const; +%ignore graph_location_info_t::deserialize(const uchar **, const uchar *); +%ignore renderer_info_pos_t::serialize(bytevec_t *) const; +%ignore renderer_info_pos_t::deserialize(const uchar **, const uchar *); %template(segm_move_info_vec_t) qvector; +%inline %{ +// +// +%} + %include "moves.hpp" diff --git a/swig/nalt.i b/swig/nalt.i index afe8bdd..89c4717 100644 --- a/swig/nalt.i +++ b/swig/nalt.i @@ -8,10 +8,11 @@ %ignore get_import_module_name; %rename (get_import_module_name) py_get_import_module_name; -%ignore NALT_EA; %ignore enum_import_names; %rename (enum_import_names) py_enum_import_names; +%ignore calc_nodeidx; + %ignore get_wide_value; %ignore set_wide_value; %ignore del_wide_value; @@ -41,10 +42,6 @@ %ignore set_ind_purged; -%ignore get_str_type; -%ignore set_str_type; -%ignore del_str_type; - %ignore _get_item_color; %ignore _set_item_color; %ignore _del_item_color; @@ -55,24 +52,6 @@ %ignore get_nalt_rptcmt; %ignore set_nalt_rptcmt; %ignore del_nalt_rptcmt; -%ignore get_fop1; -%ignore set_fop1; -%ignore del_fop1; -%ignore get_fop2; -%ignore set_fop2; -%ignore del_fop2; -%ignore get_fop3; -%ignore set_fop3; -%ignore del_fop3; -%ignore get_fop4; -%ignore set_fop4; -%ignore del_fop4; -%ignore get_fop5; -%ignore set_fop5; -%ignore del_fop5; -%ignore get_fop6; -%ignore set_fop6; -%ignore del_fop6; %ignore get_manual_insn0; %ignore set_manual_insn0; %ignore del_manual_insn0; @@ -80,11 +59,15 @@ %ignore set_graph_groups0; %ignore del_graph_groups0; +%ignore jumptable_info_t; +%ignore del_jumptable_info; +%ignore set_jumptable_info; +%ignore get_jumptable_info; + %ignore switch_info_t; -%ignore switch_info_ex_t; -%ignore get_switch_info_ex; -%ignore set_switch_info_ex; -%ignore del_switch_info_ex; +%ignore get_switch_info; +%ignore set_switch_info; +%ignore del_switch_info; %ignore refinfo_t::_get_target; %ignore refinfo_t::_get_value; @@ -94,7 +77,9 @@ %ignore custom_refinfo_handlers_t; %ignore register_custom_refinfo; %ignore unregister_custom_refinfo; -%ignore get_custom_refinfos; +%ignore get_custom_refinfo_handler; +%ignore refinfo_desc_t; +%ignore get_refinfo_descs; %ignore write_struc_path; %ignore read_struc_path; @@ -113,17 +98,20 @@ %ignore get_switch_info; %ignore set_switch_info; %ignore del_switch_info; -%ignore get_ti; -%ignore set_ti; -%ignore del_ti; -%ignore get_op_tinfo; -%ignore set_op_tinfo; -%ignore del_tinfo; -%ignore get_op_ti; -%ignore set_op_ti; -%ignore del_ti; -%template (ids_array) wrapped_array_t; +%template (custom_data_type_ids_fids_array) wrapped_array_t; + +%extend custom_data_type_ids_t { + wrapped_array_t __getFids() { + return wrapped_array_t($self->fids); + } + + %pythoncode { + fids = property(__getFids) + } +} + +%template (strpath_ids_array) wrapped_array_t; %extend strpath_t { wrapped_array_t __getIds() { @@ -142,9 +130,9 @@ // %} -%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 (get_switch_info) py_get_switch_info; +%rename (set_switch_info) py_set_switch_info; +%rename (del_switch_info) py_del_switch_info; %inline %{ // diff --git a/swig/name.i b/swig/name.i index da18a37..3e95cb2 100644 --- a/swig/name.i +++ b/swig/name.i @@ -18,19 +18,17 @@ %ignore get_ea_name; %rename (get_ea_name) py_get_ea_name; -// 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); -%ignore append_struct_fields(int, const tid_t *, int, flags_t, char *, char *, adiff_t *, adiff_t, bool); - - // Duplicate names, in-out qstring w/ existing // qstring-returning alternatives. %ignore get_visible_name(qstring *, ea_t, int); %ignore get_short_name(qstring *, ea_t, int); %ignore get_long_name(qstring *, ea_t, int); +%ignore get_colored_short_name(qstring *, ea_t, int); +%ignore get_colored_long_name(qstring *, ea_t, int); +%ignore get_demangled_name(qstring *, ea_t, int32, int, int); +%ignore get_colored_demangled_name(qstring *, ea_t, int32, int, int); -// get_true_name & get_colored_name have prototypes such that, +// get_name & get_colored_name have prototypes such that, // once converted to IDAPython, would be problematic because it'd // be impossible for SWiG to tell apart the (ea_t, ea_t) version // from the (ea_t, int) one. @@ -42,18 +40,23 @@ %ignore FNAME(ea_t, int); %rename (FNAME) py_ ## FNAME; +%ignore demangle_name(const char *, uint32, demreq_type_t); + %inline %{ inline qstring py_## FNAME(ea_t ea) { return FNAME(ea); } %} %enddef -%restrict_ambiguous_name_function(get_true_name); +%restrict_ambiguous_name_function(get_name); %restrict_ambiguous_name_function(get_colored_name); %ignore get_debug_names; %rename (get_debug_names) py_get_debug_names; +%ignore validate_name; +%rename (validate_name) py_validate_name; + %{ // // diff --git a/swig/netnode.i b/swig/netnode.i index 4cc4661..f904688 100644 --- a/swig/netnode.i +++ b/swig/netnode.i @@ -6,11 +6,12 @@ %ignore netnode_end; %ignore netnode_next; %ignore netnode_prev; -%ignore netnode_name; %ignore netnode_get_name; %ignore netnode_rename; %ignore netnode_valobj; %ignore netnode_valstr; +%ignore netnode_qvalstr; +%ignore netnode::valstr(char*,size_t) const; %ignore netnode_set; %ignore netnode_delvalue; %ignore netnode_altval; @@ -19,18 +20,27 @@ %ignore netnode_charval_idx8; %ignore netnode_supval; %ignore netnode_supstr; +%ignore netnode_qsupstr; +%ignore netnode::supstr(nodeidx_t,char*,size_t,uchar) const; +%ignore netnode_supstr_ea; +%ignore netnode_qsupstr_ea; +%ignore netnode::supstr_ea(ea_t,char*,size_t,uchar) const; %ignore netnode_supset; %ignore netnode_supdel; -%ignore netnode_sup1st; -%ignore netnode_supnxt; +%ignore netnode_lower_bound; +%ignore netnode_supfirst; +%ignore netnode_supnext; %ignore netnode_suplast; %ignore netnode_supprev; %ignore netnode_supval_idx8; %ignore netnode_supstr_idx8; +%ignore netnode_qsupstr_idx8; +%ignore netnode::supstr_idx8(uchar,char*,size_t,uchar) const; %ignore netnode_supset_idx8; %ignore netnode_supdel_idx8; -%ignore netnode_sup1st_idx8; -%ignore netnode_supnxt_idx8; +%ignore netnode_lower_bound_idx8; +%ignore netnode_supfirst_idx8; +%ignore netnode_supnext_idx8; %ignore netnode_suplast_idx8; %ignore netnode_supprev_idx8; %ignore netnode_supdel_all; @@ -38,15 +48,26 @@ %ignore netnode_supdel_range_idx8; %ignore netnode_hashval; %ignore netnode_hashstr; +%ignore netnode_qhashstr; +%ignore netnode::hashstr(const char*,char*,size_t,uchar) const; %ignore netnode_hashval_long; %ignore netnode_hashset; %ignore netnode_hashdel; -%ignore netnode_hash1st; -%ignore netnode_hashnxt; +%ignore netnode_hashfirst; +%ignore netnode_qhashfirst; +%ignore netnode::hashfirst(char*,size_t,uchar) const; +%ignore netnode_hashnext; +%ignore netnode_qhashnext; +%ignore netnode::hashnext(const char*,char*,size_t,uchar) const; %ignore netnode_hashlast; +%ignore netnode_qhashlast; +%ignore netnode::hashlast(char*,size_t,uchar) const; %ignore netnode_hashprev; +%ignore netnode_qhashprev; +%ignore netnode::hashprev(const char*,char*,size_t,uchar) const; %ignore netnode_blobsize; %ignore netnode_getblob; +%ignore netnode_qgetblob; %ignore netnode_setblob; %ignore netnode_delblob; %ignore netnode_inited; @@ -80,14 +101,18 @@ %ignore netnode::setbase; %ignore netnode::altadjust; -%ignore netnode::getblob(void *buf, size_t *bufsize, nodeidx_t start, char tag); +%ignore netnode::getblob(qstring *buf, nodeidx_t start, uchar tag); +%ignore netnode::getblob(void *buf, size_t *bufsize, nodeidx_t start, uchar tag); +%ignore netnode::getblob_ea(void *buf, size_t *bufsize, ea_t ea, uchar tag); %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); +%rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, uchar tag=htag); + +%apply char { uchar tag }; %include "netnode.hpp" @@ -98,25 +123,26 @@ return self->operator nodeidx_t(); } - PyObject *getblob(nodeidx_t start, const char *tag) + PyObject *getblob(nodeidx_t start, char tag) { - // Get the blob and let IDA allocate the memory - size_t bufsize; - void *buf = self->getblob(NULL, &bufsize, start, *tag); - if ( buf == NULL ) + bytevec_t blob; + if ( self->getblob(&blob, start, uchar(tag)) <= 0 ) Py_RETURN_NONE; - // Create a Python string - PyObject *py_str = PyString_FromStringAndSize((const char *)buf, bufsize); - // Free memory - qfree(buf); + return PyString_FromStringAndSize((const char *)blob.begin(), blob.size()); + } - return py_str; + PyObject *getblob_ea(ea_t ea, char tag) + { + bytevec_t blob; + if ( self->getblob(&blob, ea, tag) <= 0 ) + Py_RETURN_NONE; + return PyString_FromStringAndSize((const char *)blob.begin(), blob.size()); } PyObject *hashstr_buf(const char *idx, char tag=htag) { char buf[MAXSPECSIZE]; - ssize_t sz = self->hashstr(idx, buf, sizeof(buf), tag); + ssize_t sz = self->hashstr(idx, buf, sizeof(buf), uchar(tag)); if ( sz < 0 ) Py_RETURN_NONE; else @@ -127,10 +153,8 @@ { char *buf; Py_ssize_t sz; - if ( PyString_AsStringAndSize(py_str, &buf, &sz) == -1 ) return false; - else - return self->hashset(idx, buf, sz, tag); + return self->hashset(idx, buf, sz, uchar(tag)); } } diff --git a/swig/pro.i b/swig/pro.i index 5b36439..e1652cb 100644 --- a/swig/pro.i +++ b/swig/pro.i @@ -1,4 +1,32 @@ +%ignore user2str; +%ignore back_char; +%ignore qstr2user; +%ignore user2qstr; +%ignore str2user; +%rename (str2user) py_str2user; +%ignore convert_encoding; +%ignore is_valid_utf8; +%ignore qustrlen; +%ignore put_utf8_char; +%ignore idb_utf8; +%ignore scr_utf8; +%ignore utf8_scr; +%ignore change_codepage; +%ignore utf16_utf8; +%ignore utf8_utf16; +%ignore acp_utf8; +%ignore utf8_wchar16; +%ignore utf8_wchar32; +%ignore skip_utf8; +%ignore expand_argv; +%ignore free_argv; +%ignore qwait; +%ignore qwait_for_handles; +%ignore qwait_timed; +%ignore ida_true_type; +%ignore ida_false_type; + %include "pro.h" // we must include those manually here @@ -15,6 +43,7 @@ %template(int64vec_t) qvector; // for EA64 svalvec_t objects %template(boolvec_t) qvector; %template(strvec_t) qvector; +%template(sizevec_t) qvector; SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t) diff --git a/swig/problems.i b/swig/problems.i new file mode 100644 index 0000000..df3780a --- /dev/null +++ b/swig/problems.i @@ -0,0 +1,5 @@ +%{ +#include +%} + +%include "problems.hpp" diff --git a/swig/queue.i b/swig/queue.i deleted file mode 100644 index 04fcfeb..0000000 --- a/swig/queue.i +++ /dev/null @@ -1,13 +0,0 @@ -%{ -#include -%} -// TODO: This could be wrapped. -%ignore QueueGet; - -// Kernel-only & unexported symbols -%ignore QueueDel(ea_t); - -%ignore mark_ida_decision; -%ignore unmark_ida_decision; - -%include "queue.hpp" diff --git a/swig/range.i b/swig/range.i new file mode 100644 index 0000000..ea5d284 --- /dev/null +++ b/swig/range.i @@ -0,0 +1,14 @@ +%ignore rangeset_t::count; +%ignore rangeset_t::lower_bound; +%ignore rangeset_t::upper_bound; +%ignore rangeset_t::move_chunk; +%ignore rangeset_t::check_move_args; + +%template(rangevec_base_t) qvector; + +%inline %{ +// +// +%} + +%include "range.hpp" diff --git a/swig/registry.i b/swig/registry.i index d137b90..2afb0ec 100644 --- a/swig/registry.i +++ b/swig/registry.i @@ -2,7 +2,8 @@ #include %} %ignore reg_bin_op; -%ignore reg_str_op; +%ignore reg_str_get; +%ignore reg_str_set; %ignore reg_int_op; %ignore _RVN_; %ignore REG_VAL_NAME; diff --git a/swig/segment.i b/swig/segment.i index 1d259af..3abd755 100644 --- a/swig/segment.i +++ b/swig/segment.i @@ -1,6 +1,6 @@ // Ignore functions with callbacks -%import "area.i" +%import "range.i" %ignore enumerate_selectors; %ignore enumerate_segments_with_selector; @@ -22,8 +22,20 @@ %extend segment_t { - ea_t startEA; - ea_t endEA; + ea_t start_ea; + ea_t end_ea; +} + +#ifdef __EA64__ +%apply ulonglong *OUTPUT { sel_t *sel, ea_t *base }; // getn_selector() +#else +%apply unsigned int *OUTPUT { sel_t *sel, ea_t *base }; // getn_selector() +#endif + +%typemap(check) (sel_t *sel, ea_t *base) { + // getn_selector() check + *($1) = BADSEL; + *($2) = BADADDR; } %include "segment.hpp" diff --git a/swig/srarea.i b/swig/segregs.i similarity index 56% rename from swig/srarea.i rename to swig/segregs.i index 60f2a36..deeba1e 100644 --- a/swig/srarea.i +++ b/swig/segregs.i @@ -1,18 +1,13 @@ %{ -#include +#include %} -%import "area.i" +%import "range.i" // Ignore kernel-only symbols -%ignore repairSRarea; - %ignore delete_v660_segreg_t; %ignore v660_segreg_t; -%ignore segreg_t::tag(int n); -%ignore segreg_t::reg(int n); - #define R_es 29 #define R_cs 30 #define R_ss 31 @@ -20,4 +15,4 @@ #define R_fs 33 #define R_gs 34 -%include "srarea.hpp" +%include "segregs.hpp" diff --git a/swig/strlist.i b/swig/strlist.i index 92cb7b1..1c70e5b 100644 --- a/swig/strlist.i +++ b/swig/strlist.i @@ -6,4 +6,58 @@ %ignore strwinsetup_t::save_config; %ignore strwinsetup_t::restore_config; +%extend strwinsetup_t { + + PyObject *_get_strtypes() + { + const bytevec_t &t = $self->strtypes; + size_t n = t.size(); + PyObject *py_t = PyList_New(n); + for ( size_t i = 0, n = t.size(); i < n; ++i ) + PyList_SetItem(py_t, i, PyInt_FromLong(t[i])); + return py_t; + } + + PyObject *_set_strtypes(PyObject *py_t) + { + if ( PySequence_Check(py_t) ) + { + Py_ssize_t n = PySequence_Size(py_t); + bytevec_t t; + t.reserve(n); + for ( size_t i = 0; i < n; ++i ) + { + newref_t pyo(PySequence_GetItem(py_t, i)); + if ( PyInt_Check(pyo.o) ) + { + long stype = PyInt_AsLong(pyo.o); + if ( stype < 0 || stype >= 0x100 ) + { + PyErr_SetString(PyExc_ValueError, "values must be between 0 & 0x100"); + return NULL; + } + t.push_back(uchar(stype)); + } + else + { + PyErr_SetString(PyExc_ValueError, "expected an integer"); + return NULL; + } + } + $self->strtypes.swap(t); + } + else + { + PyErr_SetString(PyExc_TypeError, "expected a list"); + return NULL; + } + Py_RETURN_TRUE; + } + + %pythoncode { + strtypes = property(_get_strtypes, _set_strtypes) + } +} +%ignore strwinsetup_t::strtypes; + %include "strlist.hpp" diff --git a/swig/struct.i b/swig/struct.i index 75e2e34..f75660d 100644 --- a/swig/struct.i +++ b/swig/struct.i @@ -2,10 +2,9 @@ #include %} // Kernel-only symbols -%ignore del_ti; %ignore save_structs; %ignore get_struc_name(tid_t); -%ignore get_member_name2(tid_t); +%ignore get_member_name(tid_t); %ignore get_member_by_id(tid_t, struc_t **); // allow version w/ qstring* only //------------------------------------------------------------------------- diff --git a/swig/tryblks.i b/swig/tryblks.i new file mode 100644 index 0000000..5392bbb --- /dev/null +++ b/swig/tryblks.i @@ -0,0 +1,14 @@ +%{ +#include +%} + +%import "range.i" + +%ignore tryblk_t::reserve; +%ignore tryblk_t::cpp() const; +%ignore tryblk_t::seh() const; + +%template(tryblks_t) qvector; +%template(catchvec_t) qvector; + +%include "tryblks.hpp" diff --git a/swig/typeconv.i b/swig/typeconv.i deleted file mode 100644 index 8741098..0000000 --- a/swig/typeconv.i +++ /dev/null @@ -1,454 +0,0 @@ -//------------------------------------------------------------------------- -// 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* } - -#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); -%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 20da251..58dc76f 100644 --- a/swig/typeinf.i +++ b/swig/typeinf.i @@ -8,40 +8,16 @@ // Most of these could be wrapped if needed %ignore get_cc; %ignore get_cc_type_size; -%ignore set_argloc; -%ignore set_dt; -%ignore set_da; -%ignore set_de; -%ignore get_dt; -%ignore get_da; %ignore get_de; %ignore skip_ptr_type_header; %ignore skip_array_type_header; -%ignore unpack_object_from_idb; -%ignore unpack_object_from_bv; %ignore pack_object_to_idb; -%ignore pack_object_to_bv; %ignore typend; %ignore typlen; %ignore typncpy; %ignore tppncpy; %ignore typcmp; %ignore typdup; -%ignore equal_types; -%ignore resolve_typedef; -%ignore is_resolved_type_const; -%ignore is_resolved_type_void; -%ignore is_resolved_type_ptr; -%ignore is_resolved_type_func; -%ignore is_resolved_type_array; -%ignore is_resolved_type_complex; -%ignore is_resolved_type_struct; -%ignore is_resolved_type_union; -%ignore is_resolved_type_enum; -%ignore is_resolved_type_bitfld; -%ignore is_castable; -%ignore remove_constness; -%ignore remove_pointerness; %ignore get_int_type_bit; %ignore get_unk_type_bit; %ignore tns; @@ -57,17 +33,9 @@ %ignore parse_subtype; %ignore calc_type_size; -%ignore get_type_size; -%ignore get_type_size0; -%ignore skip_type; -%ignore get_pointer_object_size; %ignore descr_t; -%ignore unpack_type; -%ignore print_type_to_one_line; -%ignore print_type_to_many_lines; -%ignore print_type; %ignore show_type; %ignore show_plist; %ignore show_bytes; @@ -77,18 +45,17 @@ %ignore argloc_t::dstr; %ignore argpart_t::copy_from; -%ignore extract_pstr; +%ignore get_numbered_type(const til_t *, uint32, const type_t **, const p_list **, const char **, const p_list **, sclass_t *); +%rename (get_numbered_type) py_get_numbered_type; + %ignore skipName; %ignore extract_comment; %ignore skipComment; %ignore extract_fargcmt; %ignore skip_argloc; -%ignore extract_argloc; %ignore h2ti; %ignore h2ti_warning; -%ignore parse_type; -%ignore parse_types; // We want to handle 'get_named_type()' in a special way, // but not tinfo_t::get_named_type(). // http://stackoverflow.com/questions/27417884/how-do-i-un-ignore-a-specific-method-on-a-templated-class-in-swig @@ -115,18 +82,9 @@ %ignore get_named_type_size; %ignore decorate_name; -%ignore decorate_name3; -%ignore gen_decorate_name; -%ignore calc_bare_name; %ignore calc_bare_name3; -%ignore calc_cpp_name; -%ignore calc_c_cpp_name; -%ignore calc_c_cpp_name3; -%ignore predicate_t; -%ignore local_predicate_t; %ignore tinfo_predicate_t; %ignore local_tinfo_predicate_t; -%ignore choose_named_type; %ignore get_default_align; %ignore align_size; %ignore align_size; @@ -135,56 +93,33 @@ %ignore get_default_enum_size; %ignore max_ptr_size; %ignore based_ptr_name_and_size; -%ignore calc_arglocs; %ignore apply_type; %ignore apply_callee_type; -%ignore guess_func_type; -%ignore guess_type; +%ignore get_arg_addrs; +%rename (get_arg_addrs) py_get_arg_addrs; -%ignore build_funcarg_arrays; -%ignore free_funcarg_arrays; -%ignore extract_func_ret_type; %ignore calc_names_cmts; -%ignore resolve_complex_type; -%ignore visit_strmems; -%ignore foreach_strmem; -%ignore is_type_scalar; -%ignore get_type_signness; -%ignore is_type_signed; -%ignore is_type_unsigned; -%ignore get_struct_member; %ignore idb_type_to_til; %ignore get_idb_type; -%ignore apply_type_to_stkarg; -%rename (apply_type_to_stkarg) py_apply_type_to_stkarg; -%ignore print_type; -%rename (print_type) py_print_type; %rename (calc_type_size) py_calc_type_size; %rename (apply_type) py_apply_type; %ignore use_regarg_type_cb; -%ignore set_op_type_t; %ignore is_stkarg_load_t; %ignore has_delay_slot_t; %ignore gen_use_arg_types; %ignore enable_numbered_types; %ignore compact_numbered_types; -%ignore type_pair_vec_t::add_names; - %ignore callregs_t::findreg; %ignore format_data_info_t; %ignore valinfo_t; -%ignore print_c_data; %ignore print_cdata; -%ignore format_c_data; %ignore format_cdata; -%ignore format_cdata2; %ignore format_c_number; -%ignore get_enum_member_expr; %ignore extend_sign; // Kernel-only symbols @@ -192,10 +127,6 @@ %ignore bitfield_type_data_t::serialize; %ignore func_type_data_t::serialize; %ignore func_type_data_t::deserialize; -%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; @@ -292,14 +223,42 @@ %template(funcargvec_t) qvector; %template(udtmembervec_t) qvector; %template(reginfovec_t) qvector; +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; +%template(type_attrs_t) qvector; + +%extend tinfo_t { + PyObject *get_attr(const qstring &key, bool all_attrs=true) + { + bytevec_t bv; + if ( $self->get_attr(key, &bv, all_attrs) ) + return PyString_FromStringAndSize( + (const char *) bv.begin(), + bv.size()); + else + Py_RETURN_NONE; + } +} +%ignore tinfo_t::get_attr; + +%feature("director") predicate_t; + +%ignore load_til; +%rename (load_til) py_load_til; +%ignore load_til_header; +%rename (load_til_header) py_load_til_header; + +%ignore remove_tinfo_pointer; +%rename (remove_tinfo_pointer) py_remove_tinfo_pointer; %include "typeinf.hpp" // Custom wrappers -%rename (load_til) load_til_wrap; -%rename (load_til_header) load_til_header_wrap; -%rename (get_type_size0) py_get_type_size0; %rename (idc_get_type_raw) py_idc_get_type_raw; %rename (idc_get_local_type_raw) py_idc_get_local_type_raw; %rename (unpack_object_from_idb) py_unpack_object_from_idb; diff --git a/swig/ua.i b/swig/ua.i index fbc30c6..e427dfd 100644 --- a/swig/ua.i +++ b/swig/ua.i @@ -3,49 +3,145 @@ #include %} -%ignore insn_t; -%ignore op_t; -%ignore cmd; -%ignore showAsChar; -%ignore out_real; -%ignore init_output_buffer; -%ignore term_output_buffer; -%ignore OutValue; -%ignore OutImmChar; -%ignore out_name_expr; -%ignore ua_stkvar2; -%ignore ua_add_off_drefs; -%ignore ua_add_off_drefs2; -%ignore out_snprintf; -%ignore set_output_ptr; -%ignore get_output_ptr; -%ignore out_insert; -%ignore get_immval; +%ignore print_charlit; +%ignore print_fpval; %ignore get_spoiled_reg; %ignore decode_preceding_insn; -%ignore term_uaterm_ua; %ignore get_operand_immvals; - +%ignore get_immvals; %ignore get_immval; -%ignore ua_stkvar; +%ignore insn_create_op_data; %ignore construct_macro; +%ignore API70_construct_macro; %rename (construct_macro) py_construct_macro; -%ignore get_dtyp_by_size; -%rename (get_dtyp_by_size) py_get_dtyp_by_size; +%ignore get_dtype_by_size; +%rename (get_dtype_by_size) py_get_dtype_by_size; +%ignore outctx_base_t::print_hex_dump; +%ignore outctx_base_t::add_spaces; +%ignore outctx_base_t::nowarn_out_printf; +%ignore outctx_base_t::out_vprintf; +%ignore outctx_base_t::gen_colored_cmt_line_v; +%ignore outctx_base_t::gen_cmt_line_v; +%ignore outctx_base_t::gen_vprintf; +%ignore outctx_base_t::get_xrefgen_state; +%ignore outctx_base_t::get_cmtgen_state; + +%ignore outctx_base_t::regname_idx; +%ignore outctx_base_t::suspop; +%ignore outctx_base_t::F; +%ignore outctx_base_t::outvalues; +%ignore outctx_base_t::outvalue_getn_flags; +%ignore outctx_base_t::user_data; +%ignore outctx_base_t::kern_data; +%ignore outctx_base_t::lnar; +%ignore outctx_base_t::lnar_maxsize; +%ignore outctx_base_t::line_prefix; +%ignore outctx_base_t::prefix_len; +%ignore outctx_base_t::ctxflags; +%ignore outctx_base_t::ind0; +%ignore outctx_base_t::cmt_ea; +%ignore outctx_base_t::cmtbuf; +%ignore outctx_base_t::cmtptr; +%ignore outctx_base_t::cmtcolor; + +%template (operands_array) wrapped_array_t; + +%feature("nodirector") outctx_base_t; +%feature("nodirector") outctx_t; + +%ignore outctx_base_t::outctx_base_t; +%ignore outctx_base_t::~outctx_base_t; +%ignore outctx_t::outctx_t; +%ignore outctx_t::~outctx_t; + +%extend insn_t +{ + wrapped_array_t __get_ops__() + { + return wrapped_array_t($self->ops); + } + op_t *__get_operand__(int n) { QASSERT(30502, n >= 0 && n < UA_MAXOP); return &($self->ops[n]); } + uint16 __get_auxpref__() { return $self->auxpref; } + void __set_auxpref__(uint16 v) { $self->auxpref = v; } + + void assign(const insn_t &other) { *($self) = other; } + + %pythoncode { + ops = property(__get_ops__) +#ifdef BC695 + if _BC695: + Operands = ops +#endif + Op1 = property(lambda self: self.__get_operand__(0)) + Op2 = property(lambda self: self.__get_operand__(1)) + Op3 = property(lambda self: self.__get_operand__(2)) + Op4 = property(lambda self: self.__get_operand__(3)) + Op5 = property(lambda self: self.__get_operand__(4)) + Op6 = property(lambda self: self.__get_operand__(5)) + + auxpref = property(__get_auxpref__, __set_auxpref__) + + def __iter__(self): + return (self.ops[idx] for idx in xrange(0, UA_MAXOP)) + + def __getitem__(self, idx): + """ + Operands can be accessed directly as indexes + @return op_t: Returns an operand of type op_t + """ + if idx >= UA_MAXOP: + raise KeyError + else: + return self.ops[idx] + } +} + +%extend op_t +{ + uint16 __get_reg_phrase__() { return $self->reg; } + void __set_reg_phrase__(uint16 r) { $self->reg = r; } + + // use ea_t so the right value decoders will be used (for the next three) + ea_t __get_value__() { return $self->value; } + void __set_value__(ea_t v) { $self->value = v; } + ea_t __get_addr__() { return $self->addr; } + void __set_addr__(ea_t v) { $self->addr = v; } + ea_t __get_specval__() { return $self->specval; } + void __set_specval__(ea_t v) { $self->specval = v; } + + void assign(const op_t &other) { *($self) = other; } + + %pythoncode { + def has_reg(self, r): + """Checks if the operand accesses the given processor register""" + return self.reg == r.reg + + reg = property(__get_reg_phrase__, __set_reg_phrase__) + phrase = property(__get_reg_phrase__, __set_reg_phrase__) + value = property(__get_value__, __set_value__) + addr = property(__get_addr__, __set_addr__) + specval = property(__get_specval__, __set_specval__) + } +} +/* // @arnaud types! */ +%apply uchar { char offb }; +%apply uchar { char offo }; +%apply uchar { op_dtype_t dtype }; +%apply uchar { char specflag1 }; +%apply uchar { char specflag2 }; +%apply uchar { char specflag3 }; +%apply uchar { char specflag4 }; +%apply uchar { char flags }; + + +%apply ea_t { adiff_t off }; +%apply ea_t { adiff_t off }; %include "ua.hpp" -%rename (init_output_buffer) py_init_output_buffer; -%rename (term_output_buffer) py_term_output_buffer; -%rename (OutValue) py_OutValue; -%rename (OutImmChar) py_OutImmChar; -%rename (out_name_expr) py_out_name_expr; -%rename (ua_stkvar2) py_ua_stkvar2; -%rename (ua_add_off_drefs) py_ua_add_off_drefs; -%rename (ua_add_off_drefs2) py_ua_add_off_drefs2; %rename (decode_preceding_insn) py_decode_preceding_insn; -%rename (get_operand_immvals) py_get_operand_immvals; +%rename (get_immvals) py_get_immvals; %{ // diff --git a/tools/bc695.org b/tools/bc695.org new file mode 100644 index 0000000..38eaf23 --- /dev/null +++ b/tools/bc695.org @@ -0,0 +1,9 @@ +* DONE need to support all modules +* DONE cleanup idc.idc; have a map of correspondances so that we don't need /*ida_...*/ in idc.idc. +* TODO need a chooser_t-backed Chooser2 impl. +* TODO need a graph_viewer_t(or something)-backed GraphViewer impl. +* TODO re-enalbe those: EMPTY_SEL=chooser_t.NO_SELECTION +* TODO kernwin.py: add tests about add_menu_item/del_menu_item; it should be trivial to simulate with actions +* DONE inf.minEA, inf.maxEA -- super frequent! +* DONE ida_typeinf.cvar.idati doesn't exist anymore. Make it re-appear +* DONE re-instate AddCommand on Choose2 & GraphViewer diff --git a/tools/call_dmpapis.sh b/tools/call_dmpapis.sh new file mode 100755 index 0000000..02087a0 --- /dev/null +++ b/tools/call_dmpapis.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +PWD=`pwd` +API695=${PWD}/api695.txt +API700=${PWD}/api700.txt +TVHEADLESS=1 $IDAXBIN/idat -t -A "-S${PWD}/dmpapi.py ${API700}" > /dev/null +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IDA695OPTBIN TVHEADLESS=1 $IDA695OPTBIN/idal -t -A "-S${PWD}/dmpapi.py ${API695}" > /dev/null + +python cmpapi.py --api-695 ${API695} --api-700 ${API700} diff --git a/tools/chkapi.py b/tools/chkapi.py index 4428f85..6a01435 100644 --- a/tools/chkapi.py +++ b/tools/chkapi.py @@ -2,10 +2,6 @@ from __future__ import with_statement import sys, optparse, re, pprint -ignorable_api_contents = [ - "qwait" - ] - class TextStream: def __init__(self, text): self.text = text @@ -13,7 +9,6 @@ class TextStream: self.maxpoint = len(self.text) self.line_nr = 0 self.char_nr = 0 - self.curline = None def line(self): pt = self.point @@ -84,65 +79,49 @@ def check_cpp(opts): # # 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" : { + # "_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_linput_buffer_t_read" : { + # "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_tinfo" : { "mustcall" : "PyW_GetNumber", }, - "_wrap_IDP_Hooks_adjust_refinfo" : { + "_wrap_IDP_Hooks_ev_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;", - }, "_wrap_warning__varargs__" : { "nullptrcheck" : 1, # 1st arg @@ -155,11 +134,11 @@ def check_cpp(opts): "_wrap_tag_remove" : { "nullptrcheck" : 1, }, - "_wrap_CompileLine" : { + "_wrap_compile_idc_file" : { "nullptrcheck" : 1, }, - "_wrap_set_fixup" : { - "nullptrcheck" : 2, + "_wrap_compile_idc_text" : { + "nullptrcheck" : 1, }, "_wrap_get_member_size" : { "nullptrcheck" : 1, @@ -175,14 +154,11 @@ def check_cpp(opts): "_wrap_get_opinfo" : { "string" : ["Py_XDECREF(resultobj)", "Py_INCREF(resultobj)"], }, - "_wrap_get_typeinfo" : { - "string" : ["Py_XDECREF(resultobj)", "Py_INCREF(resultobj)"], + + "_wrap_file2base" : { + "nostring" : ["SWIGTYPE_p_qoff64_t", "qoff64_t *"], }, - # no autoEnabled present - "SWIG_init" : { - "nostring" : "autoEnabled", - }, } functions_coherence_hexrays = { @@ -202,14 +178,36 @@ def check_cpp(opts): "mustcall" : "PyString_FromStringAndSize", }, "delete_qrefcnt_t_Sl_cfunc_t_Sg_" : { - "mustcall" : "hexrays_deregister_python_cfuncptr_t_instance", + "mustcall" : "hexrays_deregister_python_clearable_instance", }, "_wrap__decompile" : { - "mustcall" : "hexrays_register_python_cfuncptr_t_instance", + "mustcall" : "hexrays_register_python_clearable_instance", }, "_wrap_vdui_t_cfunc_get" : { - "mustcall" : "hexrays_register_python_cfuncptr_t_instance", + "mustcall" : "hexrays_register_python_clearable_instance", }, + " delete_cexpr_t" : { + "mustcall" : "hexrays_deregister_python_clearable_instance", + }, + " delete_cinsn_t" : { + "mustcall" : "hexrays_deregister_python_clearable_instance", + }, + " delete_cblock_t" : { + "mustcall" : "hexrays_deregister_python_clearable_instance", + }, + "*new_cexpr_t" : { + "mustcall" : "hexrays_register_python_clearable_instance", + }, + "*new_cinsn_t" : { + "mustcall" : "hexrays_register_python_clearable_instance", + }, + "*new_cblock_t" : { + "mustcall" : "hexrays_register_python_clearable_instance", + }, + "_wrap_boundaries_find" : { + "nostring" : "SWIGTYPE_p_p_cinsn_t", + }, + # # qvector # @@ -275,7 +273,11 @@ def check_cpp(opts): # Read and go through lines for one_file in opts.files.split(","): with open(one_file, "r") as f: - ts = TextStream(f.read()) + raw = f.read() + # ensure we have improved director out type reporting + if raw.find("""in output value of type '""int""'");""") > -1: + raise Exception("Director output value type reporting doesn't appear to be patched") + ts = TextStream(raw) # Process lines STATE_UNKNOWN = 0 @@ -284,6 +286,7 @@ def check_cpp(opts): 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 @@ -291,10 +294,9 @@ def check_cpp(opts): match = api_fname_regex.match(funstart) if match: fname = match.group(1) - if fname not in ignorable_api_contents: - api_contents["functions"].append(fname) + api_contents["functions"].append(fname) funlines = collect_funbody_lines(ts) - KICKME_functions_lines[fname] = funlines + KICKME_functions_lines[fname] = funlines # Do we care about this function? check_for = None for fname in functions_coherence.keys(): @@ -305,12 +307,12 @@ def check_cpp(opts): 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): + def look_for_stuff(stuff, is_funcall, lookForPresence=True): if isinstance(stuff, str): stuff = [stuff] for bit in stuff: found = False - bit_pat = ("%s(" % bit) if isFuncall else bit + bit_pat = ("%s(" % bit) if is_funcall else bit dbg("Thing to look for: '%s'" % bit_pat) for funline in funlines: # dbg("Testing line: '%s'" % funline) @@ -360,16 +362,15 @@ def check_cpp(opts): 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" }, + "func_t" : { "mustinherit" : "ida_range.range_t" }, + "hidden_range_t" : { "mustinherit" : "ida_range.range_t" }, + "qbasic_block_t" : { "mustinherit" : "ida_range.range_t" }, + "regvar_t" : { "mustinherit" : "ida_range.range_t" }, + "segment_t" : { "mustinherit" : "ida_range.range_t" }, + "sreg_range_t" : { "mustinherit" : "ida_range.range_t" }, - "GraphViewer" : { "mustinherit" : "ida_idaapi.CustomIDAMemo" }, - "IDAViewWrapper" : { "mustinherit" : "ida_idaapi.CustomIDAMemo" }, + "GraphViewer" : { "mustinherit" : "ida_kernwin.CustomIDAMemo" }, + "IDAViewWrapper" : { "mustinherit" : "CustomIDAMemo" }, "PyIdc_cvt_int64__" : { "mustinherit" : "pyidc_cvt_helper__" }, "PyIdc_cvt_refclass__" : { "mustinherit" : "pyidc_cvt_helper__" }, "_qstrvec_t" : { "mustinherit" : "ida_idaapi.py_clinked_object_t" }, @@ -381,19 +382,17 @@ def check_python(opts): "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" }, + "insn_t" : { "mustinherit" : "object" }, + "op_t" : { "mustinherit" : "object" }, "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" }, + "switch_info_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" : {}, diff --git a/tools/cmpapi.py b/tools/cmpapi.py new file mode 100644 index 0000000..d107d3e --- /dev/null +++ b/tools/cmpapi.py @@ -0,0 +1,671 @@ + +import argparse +p = argparse.ArgumentParser() +p.add_argument("--api-695", required=True, help="Path to the 6.95 API desc file") +p.add_argument("--api-700", required=True, help="Path to the 7.00 API desc file") + +args = p.parse_args() +with open(args.api_695, "r") as fin: + api_695 = eval(fin.read()) +with open(args.api_700, "r") as fin: + api_700 = eval(fin.read()) + +renamed_modules = { + "ida_area" : "ida_range", + "ida_queue" : "ida_problems", + "ida_srarea" : "ida_segregs", + "ida_queue" : "ida_problems", +} + +renamed_symbols = { + "ida_area" : { + "AREACB_TYPE_FUNC" : "RANGE_KIND_FUNC", + "AREACB_TYPE_FUNC" : "RANGE_KIND_FUNC", + "AREACB_TYPE_HIDDEN_AREA" : "RANGE_KIND_HIDDEN_RANGE", + "AREACB_TYPE_SEGMENT" : "RANGE_KIND_SEGMENT", + "AREACB_TYPE_UNKNOWN" : "RANGE_KIND_UNKNOWN", + "area_t_print(*args)" : "range_t_print(*args)", + "areavec_t" : "rangevec_t", + }, + + "ida_auto" : { + "analyze_area" : "plan_and_wait", + "autoCancel" : "auto_cancel", + "autoIsOk" : "auto_is_ok", + "autoMark" : "auto_mark", + "autoUnmark" : "auto_unmark", + "autoWait" : "auto_wait", + }, + + "ida_bytes" : { + "doExtra(_)" : "doExtra(_, *args)", + "noExtra(_)" : "noExtra(_, *args)", + "do3byte(*args)" : "do3byte(_, *args)", + "f_is3byte(*args)" : "f_is3byte(_, *args)", + "get_3byte(*args)" : "get_3byte(_, *args)", + "is3byte(*args)" : "is3byte(_, *args)", + }, + + "ida_dbg" : { + "get_tev_reg_mem_ea(*args)" : "get_tev_reg_mem_ea(_, _)", + "get_tev_reg_mem_qty(*args)" : "get_tev_reg_mem_qty(_)", + "get_tev_reg_val(*args)" : "get_tev_reg_val(_, _)", + }, + + "ida_frame" : { + "ida_area" : "ida_range", + + }, + + "ida_funcs" : { + "ida_area" : "ida_range", + + }, + + "ida_gdl" : { + "ida_area" : "ida_range", + + }, + + "ida_hexrays" : { + "call_helper(*args)" : "call_helper(_, _, *rest)", + "dereference(*args)" : "dereference(_, _, =False)", + "lnot(*args)" : "lnot(_)", + "make_ref(*args)" : "make_ref(_)", + "new_block(*args)" : "new_block()", + }, + + "ida_ida" : { + "ansi2idb(*args)" : "ansi2idb(_, _)", + "idb2scr(*args)" : "idb2scr(_, _)", + "scr2idb(*args)" : "scr2idb(_, _)", + }, + + "ida_kernwin" : { + "TODO" : [ + "Choose", + "EMPTY_SEL", + "END_SEL", + "START_SEL", + ], + "askident(*args)" : "askident(_, _)", + }, + + "ida_segment" : { + "ida_area" : "ida_range", + }, + + "ida_srarea" : { + "ida_area" : "ida_range", + "is_segreg_locked(*args)" : "is_segreg_locked(_, *args)", + }, + + "ida_typeinf" : { + "callregs_init_regs(*args)" : "callregs_init_regs(_, *args)", + "print_type3(*args)" : "print_type", + }, + + "idc" : { + "Fatal(_)" : "Fatal(*args)", + "Warning(_)" : "Warning(*args)", + }, +} + +removed_symbols = { + + "ida_allins" : [ + "NN_vmovntsd", + "NN_vmovntss", + ], + + "ida_area" : [ + "AREACB_TYPE_SRAREA", + "area_visitor2_t", + "areacb_t", + "lock_area", + ], + + "ida_auto" : [ + "autoGetName", + "autoStep", + ], + + "ida_bytes" : [ + "cvar", + # the following have been removed + "doVar", + "f_isUnknown", + "getRadixEA", + "get_data_type_size", + "get_typeinfo", + "ida_area", + "isVar", + "lowbits", + "noImmd", + "power2", + "setFlags", + "set_typeinfo", + ], + + "ida_dbg" : [ + "SRCIT_REGVAR", + "SRCIT_RRLVAR", + "SRCIT_STKVAR", + ], + + "ida_diskio" : [ + "call_system", + "echsize", + "echsize64", + "ecreate", + "ecreateT", + "enumerate_system_files", + "eseek", + "eseek64", + "getdspace", + "openM", + "openR", + "openRT", + "qfsize", + "qfsize64", + "qlgetz64", + "qlseek64", + "qlsize64", + "qltell64", + ], + + "ida_enum" : [ + "const_visitor_t", + "for_all_consts", + "get_bmask_node", + "ENUM_FLAGS_FROMTIL", + "ENUM_FLAGS_GHOST", + "ENUM_FLAGS_WIDTH", + ], + + "ida_expr" : [ + "call_idc_method", + "call_script_method", + "compile_script_file", + "compile_script_func", + "extlang_call_method_exists", + "extlang_compile_file_exists", + "extlang_run_statements_exists", + "extlang_set_attr_exists", + "extlang_unload_procmod", + "get_extlang_fileext", + "get_idcpath", + "install_extlang", + "remove_extlang", + "run_statements", + "select_extlang", + "VarAssign", + "find_extlang_by_ext", + "find_extlang_by_name", + "_IDCFUNC_CB_T", + "call_idc_func__", + ], + + "ida_fixup" : [ + "FIXUP_MASK", + "FIXUP_SELFREL", + "FIXUP_UNUSED", + "FIXUP_VHIGH", + "FIXUP_VLOW", + "get_fixup_base", + "get_fixup_extdef_ea", + "get_fixup_segdef_sel", + "set_custom_fixup_ex", + "set_fixup_ex", + ], + + "ida_frame" : [ + "add_stkvar2", + "add_stkvar3", + ], + + "ida_funcs" : [ + "a2funcoff", + "get_sig_filename", + "std_gen_func_header", + ], + + "ida_gdl" : [ + "display_complex_call_chart", + "display_flow_graph", + "display_simple_call_chart", + "ida_area", + ], + + "ida_graph" : [ + "pyg_add_command", + ], + + "ida_hexrays" : [ + "add_custom_viewer_popup_item", + "vcall_helper", + "vcreate_helper", + ], + + "ida_ida" : [ + "IDAPLACE_HEXDUMP", + "LFLG_UNUSED", + "PREF_VARMARK", + "text_options_t", + "dto_copy_from_inf", + "dto_copy_to_inf", + "dto_init", + ], + + "ida_idd" : [ + "BPT_OLD_EXEC", + "idd_opinfo_old_t", + ], + + "ida_idp" : [ + "create_custom_fixup", + "deleting_enum_const", + "enum_const_created", + "enum_const_deleted", + "gen_abssym", + "gen_comvar", + "gen_extern", + "gen_spcdef", + "intel_data", + "ph_get_high_fixup_bits", + ], + + "ida_kernwin" : [ + "CHOOSER_HOTKEY", + "add_chooser_command", + "add_menu_item", + "add_output_popup", + "choose2_add_command", + "choose_choose", + "create_ea_viewer", + "create_tform", + "del_menu_item", + "enable_menu_item", + "get_tform_idaview", + "obsolete_msg_popup", + "obsolete_view_popup", + "py_menu_item_callback", + "pyscv_add_popup_menu", + "pyscv_clear_popup_menu", + "set_menu_item_icon", + "vumsg", + "choose_enter", + "choose_getl", + "choose_segreg", + "choose_sizer", + "askfile2_cv", + "vaskqstr", + + # ctypes vars + "DEFAULT_MODE", + "RTLD_GLOBAL", + "RTLD_LOCAL", + ], + + "ida_lines" : [ + "ExtraFree", + "MakeBorder", + "MakeLine", + "MakeNull", + "MakeSolidBorder", + "gen_cmt_line", + "gen_collapsed_line", + "generate_big_comment", + "generate_many_lines", + "printf_line", + ], + + "ida_loader" : [ + "load_loader_module", + ], + + "ida_moves" : [ + "CURLOC_SISTACK_ITEMS", + "UNHID_AREA", + "curloc", + "location_t", + ], + + "ida_nalt" : [ + "SWI_SHIFT1", + "del_jumptable_info", + "get_auto_plugins", + "get_jumptable_info", + "ids_array", + "jumptable_info_t", + "set_auto_plugins", + "set_jumptable_info", + "switch_info_t_get_regdtyp", + "switch_info_t_set_regdtyp", + ], + + "ida_name" : [ + "append_struct_fields2", + "gen_name_decl", + ], + + "ida_pro" : [ + "convert_encoding", # wasn't usable (bytevec_t not exposed) + "init_process", + "qsplitpath", # wasn't usable (char **) + "replace_tabs", # wasn't usable (wasn't returning the string) + "vinterr", # wasn't usable (va_list) + "expand_argv", + "free_argv", + "qwait", + "qwait_timed", + ], + + "ida_queue" : [ + "QueueMark", + ], + + "ida_segment" : [ + "std_gen_segm_footer", + ], + + "ida_srarea" : [ + "get_srarea", + "get_srareas_qty", + "getn_srarea", + "segreg_t", + ], + + "ida_strlist" : [ + "set_strlist_options", + ], + + "ida_struct" : [ + "get_member_ti", + "set_member_ti", + "get_or_guess_member_type", + ], + + "ida_typeinf" : [ + "ARGLOC_REG", + "ARGLOC_REG2", + "BAD_VARLOC", + "append_complex_n", + "append_da", + "append_de", + "append_dt", + "append_name", + "append_varloc", + "apply_once_type_and_name", + "apply_type2", + "apply_type_to_stkarg", + "build_array_type", + "build_func_type", + "build_func_type2", + "build_funcarg_info", + "calc_argloc_info", + "calc_func_nargs", + "calc_max_children_qty", + "calc_max_number_of_children", + "calc_varloc_info", + "check_skip_type", + "convert_argloc_to_varloc", + "convert_varloc_to_argloc", + "create_numbered_type_reference", + "extract_and_convert_old_argloc", + "extract_old_argloc", + "for_all_types", + "func_type_info_t", + "funcarg_info_t", + "get_argloc_r1", + "get_argloc_r2", + "get_complex_n", + "get_enum_base_type", + "get_func_cc", + "get_func_cvtarg_map", + "get_func_nargs", + "get_func_rettype", + "get_funcarg_size", + "get_idainfo_by_type2", + "get_name_of_named_type", + "get_ptr_object_size", + "get_referred_ordinal", + "get_scattered_varloc", + "get_spoil_cnt", + "get_stkarg_offset", + "get_strmem", + "get_strmem2", + "get_strmem_by_name", + "get_strmem_t", + "get_tilpath", + "get_type_sign", + "get_type_size0", + "guess_func_tinfo", + "is_castable2", + "is_reg2_argloc", + "is_reg_argloc", + "cleanup_varloc", + "copy_varloc", + "is_resolved_type_struni", + "is_restype_array", + "is_restype_bitfld", + "is_restype_complex", + "is_restype_const", + "is_restype_floating", + "is_restype_func", + "is_restype_ptr", + "is_restype_union", + "is_stack_argloc", + "is_type_only_size", + "is_type_resolvable", + "is_type_scalar2", + "is_type_unk", + "is_type_void_obsolete", + "is_type_voiddef", + "is_valid_full_type", + "make_array_type", + "make_old_argloc", + "parse_types2", + "print_type_to_qstring", + "remove_type_pointer", + "rename_named_type", + "replace_subtypes", + "replace_subtypes2", + "resolve_complex_type2", + "set_complex_n", + "set_named_type64", + "set_scattered_varloc", + "set_spoils", + "skip_spoiled_info", + "skip_varloc", + "split_old_argloc", + "til2idb", + "type_mapper_t", + "type_pair_t", + "type_pair_vec_t", + "type_visitor_t", + "valstrs_deprecated2_t", + "valstrs_deprecated_t", + ], + + "ida_ua" : [ + "OutBadInstruction", + "OutChar", + "OutImmChar", + "OutLine", + "OutLong", + "OutMnem", + "OutValue", + "cmd", + # can't simulate those; they rely on cmd + "dataSeg", + "dataSeg_op", + "dataSeg_opreg", + "init_output_buffer", + "out_addr_tag", + "out_colored_register_line", + "out_keyword", + "out_line", + "out_long", + "out_name_expr", + "out_one_operand", + "out_register", + "out_symbol", + "out_tagoff", + "out_tagon", + "py_get_global_cmd_link", + "term_output_buffer", + "ua_add_off_drefs2", + "ua_ana0", + "ua_code", + "ua_dodata2", + "ua_outop", + "ua_outop2", + "ua_next_byte", + "ua_next_word", + "ua_next_long", + "ua_next_qword", + + # these guys are now handled by SWiG (no more c-link stuff.) + "insn_t_assign", + "insn_t_create", + "insn_t_destroy", + "insn_t_get_auxpref", + "insn_t_get_canon_feature", + "insn_t_get_canon_mnem", + "insn_t_get_cs", + "insn_t_get_ea", + "insn_t_get_flags", + "insn_t_get_insnpref", + "insn_t_get_ip", + "insn_t_get_itype", + "insn_t_get_op_link", + "insn_t_get_segpref", + "insn_t_get_size", + "insn_t_is_canon_insn", + "insn_t_set_auxpref", + "insn_t_set_cs", + "insn_t_set_ea", + "insn_t_set_flags", + "insn_t_set_insnpref", + "insn_t_set_ip", + "insn_t_set_itype", + "insn_t_set_segpref", + "insn_t_set_size", + "op_t_assign", + "op_t_create", + "op_t_destroy", + "op_t_get_addr", + "op_t_get_dtyp", + "op_t_get_flags", + "op_t_get_n", + "op_t_get_offb", + "op_t_get_offo", + "op_t_get_reg_phrase", + "op_t_get_specflag1", + "op_t_get_specflag2", + "op_t_get_specflag3", + "op_t_get_specflag4", + "op_t_get_specval", + "op_t_get_type", + "op_t_get_value", + "op_t_set_addr", + "op_t_set_dtyp", + "op_t_set_flags", + "op_t_set_n", + "op_t_set_offb", + "op_t_set_offo", + "op_t_set_reg_phrase", + "op_t_set_specflag1", + "op_t_set_specflag2", + "op_t_set_specflag3", + "op_t_set_specflag4", + "op_t_set_specval", + "op_t_set_type", + "op_t_set_value", + ], + + "idc" : [ + "ida_srarea", + "ASCSTR_LAST", + "FIXUP_MASK", + "GetOpnd", + "MakeCustomDataEx", + "SW_MICRO", + "SetFlags", + "SetHiddenArea", + "FF_VAR", + "INFFL_LZERO", + "INF_WIDE_HIGH_BYTE_FIRST", + "INF_ABINAME", + "INF_ASCIIFLAGS", + "INF_ASCIIPREF", + "INF_ASCIISERNUM", + "INF_ASCIIZEROES", + "INF_ASCII_BREAK", + "INF_ASSUME", + "INF_AUTO", + "INF_BEGIN_EA", + "INF_CHECKARG", + "INF_CORESTART", + "INF_ENTAB", + "INF_FCORESIZ", + "INF_MF", + "INF_NAMELEN", + "INF_NULL", + "INF_ORG", + "INF_PACKBASE", + "INF_PREFSEG", + "INF_SHOWAUTO", + "INF_SHOWBADS", + "INF_SHOWPREF", + "INF_START_AF", + "INF_VOIDS", + "REF_VHIGH", + "REF_VLOW", + "_invoke_idc_setprm", + "byteValue", + "isFop0", + "isFop1", + "isVar", + "Tabs", + "o_fpreg_arm", + ], +} + +for modname in sorted(api_695.keys()): + m6 = api_695[modname] + new_modname = modname + m7 = api_700[renamed_modules.get(modname, modname)] + for symbol in m6: + symbol_root = symbol + params = "" + paren_idx = symbol_root.find("(") + if paren_idx > -1: + symbol_root, params = symbol_root[0:paren_idx], symbol_root[paren_idx:] + removed_set = removed_symbols.get(modname, []) + if symbol_root in removed_set: + continue + renamed_set = renamed_symbols.get(modname, {}) + if symbol_root in renamed_set.get("TODO", []): + continue + target_symbol = renamed_set.get(symbol_root, symbol_root) + if target_symbol not in m7: + # try looking for a full prototype then + target_symbol = renamed_set.get(symbol, symbol) + if target_symbol not in m7: + add = "" + is_redef = False + if params: + # search for something that might correspond + x = "%s(" % symbol_root + for s in m7: + if s.startswith(x): + # print ("Candidate for '%s': '%s'" % (x, s)) + if s.endswith("bc695redef"): + is_redef = True # symbol was redefined, and marked as such. We assume we know what we're doing + break + else: + add = " => %s" % s + if not is_redef: + print("Missing: '%s.%s'%s" % (modname, symbol, add)) diff --git a/tools/deploy.py b/tools/deploy.py index 8c6cc6c..420f136 100644 --- a/tools/deploy.py +++ b/tools/deploy.py @@ -9,10 +9,10 @@ import sys, re, os, glob major, minor, micro, _, _ = sys.version_info try: - from argparse import ArgumentParser + 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 + 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) @@ -20,7 +20,9 @@ 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("-l", "--lifecycle-aware", default=False, action="store_true") parser.add_argument("-v", "--verbose", default=False, action="store_true") +parser.add_argument("-b", "--bc695", default=False, action="store_true") args = parser.parse_args() # creates a regular expression @@ -34,7 +36,7 @@ def convert_path(path_in): return os.sep.join(parts) -def apply_tags(template_str, input_str, tags, verbose): +def apply_tags(template_str, input_str, tags, verbose, path): for desc, (expr_str, expr) in tags: # find source pattern matches = expr.findall(input_str) @@ -43,22 +45,35 @@ def apply_tags(template_str, input_str, tags, verbose): print("Failed to match <%s> source expression against '%s', skipping...!" % (desc, expr_str)) continue - # 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, expr)) + is_695_bwcompat = desc == "pycode_BC695" + + if not is_695_bwcompat: + # find pattern in destination + dest = expr.search(template_str) + if not dest: + raise Exception("Found <%s> for module '%s' in input (%s), but failed to match in destination" % ( + desc, expr_str, path)) # accumulate all the strings to be replaced replaces = [] for src in matches: replaces.append(src) - template_str = template_str[:dest.start(1)] + "\n".join(replaces) + template_str[dest.end(1):] + if is_695_bwcompat: + if args.bc695: + r2 = [] + for r in replaces: + rlines = r.split("\n") + rlines = map(lambda l: " %s" % l, filter(lambda l: len(l.strip()), rlines)) + r2.append("\n".join(rlines)) + replaces = ["", "if _BC695:"] + r2 + ["\n"] + template_str = template_str + "%pythoncode %{" + "\n".join(replaces) + "%}" + else: + template_str = template_str[:dest.start(1)] + "\n".join(replaces) + template_str[dest.end(1):] return template_str -def deploy(module, template, output, pywraps, iface_deps, verbose): +def deploy(module, template, output, pywraps, iface_deps, lifecycle_aware, verbose): template = convert_path(template) output = convert_path(output) @@ -81,10 +96,11 @@ def deploy(module, template, output, pywraps, iface_deps, verbose): ('inline', make_re('inline', tagname, '//')), ('decls', make_re('decls', tagname, '//')), ('init', make_re('init', tagname, '//')), + ('pycode_BC695', make_re('pycode_BC695', tagname, '#')), ) input_str = "".join(file(path, "r").readlines()) - template_str = apply_tags(template_str, input_str, tags, verbose) + template_str = apply_tags(template_str, input_str, tags, verbose, path) # write output file with open(output, 'w') as f: @@ -105,4 +121,24 @@ def deploy(module, template, output, pywraps, iface_deps, verbose): f.write("%include \"header.i\"\n") f.write(template_str) -deploy(args.module, args.template, args.output, args.pywraps, args.interface_dependencies, args.verbose) + if lifecycle_aware: + f.write(""" +%%init %%{ +{ + module_callbacks_t module_lfc; + module_lfc.closebase = ida_%s_closebase; + module_lfc.term = ida_%s_term; + register_module_lifecycle_callbacks(module_lfc); +} +%%} +""" % (module, module)) + +deploy( + args.module, + args.template, + args.output, + args.pywraps, + args.interface_dependencies, + args.lifecycle_aware, + args.verbose) + diff --git a/tools/deploy/header.i.in b/tools/deploy/header.i.in index 8d3c090..720cef4 100644 --- a/tools/deploy/header.i.in +++ b/tools/deploy/header.i.in @@ -9,8 +9,6 @@ // 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; @@ -20,11 +18,8 @@ %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; @@ -57,6 +52,8 @@ void qvector::grow(const long long &x=0); %ignore qvector::grow; %ignore qvector::at(size_t); +%ignore qvector::front; +%ignore qvector::back; // simpleline_t doesn't implement '=='. Therefore, all these cannot be present in the instantiated template. %ignore qvector::operator==; @@ -98,7 +95,6 @@ void qvector::grow(const long long &x=0); %ignore qpipe_read; %ignore qpipe_write; %ignore qpipe_close; -%ignore qwait_for_handles; %ignore qstrlen; %ignore qstrcmp; %ignore qstrstr; @@ -113,6 +109,7 @@ void qvector::grow(const long long &x=0); %ignore c2ustr; %ignore base64_encode; %ignore base64_decode; +%ignore replace_tabs; %ignore utf8_unicode; %ignore unicode_utf8; %ignore win_utf2idb; @@ -174,6 +171,24 @@ ${ALL_IMPORTS} import ida_idaapi } +#ifdef BC695 +%pythoncode { +import sys +_BC695 = sys.modules["__main__"].IDAPYTHON_COMPAT_695_API + +if _BC695: + # This is a decorator for eliminating false-positives when automatically + # performing diffs of API7.0 vs API6.95 (typically, the prototypes for the + # functions using this decorator will have changed, and this is used to + # mark that that change is on-purpose, under control, and should in fact + # provide bw-compat. Usually those prototypes went from '(*args)', to a + # more specialized argument list.) + def bc695redef(func): + func.func_dict["bc695redef"] = True + return func +} +#endif // BC695 + //--------------------------------------------------------------------- %extend qvector { inline size_t __len__() const { return $self->size(); } @@ -199,11 +214,13 @@ import ida_idaapi $self->at(i) = v; } - inline const T&at(size_t i) { + inline const T &at(size_t i) { return __getitem__(i); } %pythoncode { + front = ida_idaapi._qvector_front + back = ida_idaapi._qvector_back __iter__ = ida_idaapi._bounded_getitem_iterator } } @@ -339,11 +356,13 @@ static PyObject *type##_get_clink_ptr(PyObject *self) %set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0))); } - -%typemap(out) ssize_t -{ - $result = PyLong_FromLongLong($1); -} +#ifdef __X64__ +%apply unsigned long long { size_t } +%apply long long { ssize_t } +#else +%apply unsigned long { size_t } +%apply long { ssize_t } +#endif //--------------------------------------------------------------------- // Convert an incoming Python list to a tid_t[] array @@ -405,15 +424,12 @@ static PyObject *type##_get_clink_ptr(PyObject *self) //--------------------------------------------------------------------- %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) @@ -429,28 +445,6 @@ static PyObject *type##_get_clink_ptr(PyObject *self) } %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 { @@ -474,30 +468,6 @@ static PyObject *type##_get_clink_ptr(PyObject *self) } %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 //--------------------------------------------------------------------- @@ -506,7 +476,7 @@ static PyObject *type##_get_clink_ptr(PyObject *self) } %typemap(argout) qstring *result { Py_XDECREF(resultobj); - if (result) + if (result > 0) { resultobj = PyString_FromStringAndSize($1->begin(), $1->length()); } @@ -592,31 +562,46 @@ static PyObject *type##_get_clink_ptr(PyObject *self) //--------------------------------------------------------------------- // IN qstring //--------------------------------------------------------------------- -// This is used to set/retrieve qstring that are structure members. -%typemap(in) qstring* +%define %bytes_container(REFTYPE, CONTAINER_TYPE, START_ACCESSOR, SIZE_ACCESSOR) +%typemap(in) REFTYPE { - char *buf; - Py_ssize_t length; - int success = PyString_AsStringAndSize($input, &buf, &length); - if ( success > -1 ) + if ( PyString_Check($input) ) { - $1 = new qstring(buf, length); + // init properly, so ctor can't crash + char *buf = NULL; + Py_ssize_t length = 0; + /*int success =*/ PyString_AsStringAndSize($input, &buf, &length); + $1 = new CONTAINER_TYPE(buf, length); // build regardless of success + } + else + { + SWIG_exception_fail( + SWIG_ValueError, + "Expected string " "in method '" "$symname" "', argument " "$argnum"" of type 'str'"); } } -%typemap(freearg) qstring* +%typemap(freearg) REFTYPE { delete $1; } -%typemap(out) qstring* +%typemap(out) REFTYPE // e.g., %typemap(out) qstring* { - $result = PyString_FromStringAndSize($1->c_str(), $1->length()); + $result = PyString_FromStringAndSize((const char *) $1->START_ACCESSOR(), $1->SIZE_ACCESSOR()); } -%typemap(out) qstring +%typemap(out) CONTAINER_TYPE // e.g., %typemap(out) qstring { - $result = PyString_FromStringAndSize($1.c_str(), $1.length()); + $result = PyString_FromStringAndSize((const char *) $1.START_ACCESSOR(), $1.SIZE_ACCESSOR()); } -%apply qstring { _qstring } -%apply qstring* { _qstring* } +%typemap(varout) CONTAINER_TYPE // e.g., %typemap(varout) qstring +{ + $result = PyString_FromStringAndSize((const char *) $1.START_ACCESSOR(), $1.SIZE_ACCESSOR()); +} +%enddef + +%bytes_container(qstring *, qstring, c_str, length); +%bytes_container(qstring &, qstring, c_str, length); +%bytes_container(bytevec_t *, bytevec_t, begin, size); +%bytes_container(bytevec_t &, bytevec_t, begin, size); //--------------------------------------------------------------------- // varargs (mostly kernwin.hpp) @@ -634,6 +619,13 @@ static PyObject *type##_get_clink_ptr(PyObject *self) "invalid null pointer " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); }; +//------------------------------------------------------------------------- +// for use with insn_t, op_t wrappers +%typemap(in) (size_t ptrval) +{ + $1 = size_t(PyLong_AsUnsignedLongLong($input)); +} + // Help SWIG to figure out the ulonglong type #ifdef SWIGWIN typedef unsigned __int64 ulonglong; @@ -648,20 +640,25 @@ typedef long long longlong; %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() +%apply ulonglong *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_range_selection() +%apply ulonglong *OUTPUT { ea_t *from, ea_t *to, asize_t *size }; // get_mapping() #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() +%apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_range_selection() +%apply unsigned int *OUTPUT { ea_t *from, ea_t *to, asize_t *size }; // get_mapping() #endif +%apply long long { qoff64_t }; + %apply qstring *result { qstring *label }; %apply qstring *result { qstring *shortcut }; %apply qstring *result { qstring *tooltip }; %apply qstring *result { qstring *out }; %apply qstring *result { qstring *buf }; +%apply qstring *result { qstring *errbuf }; %apply int *OUTPUT { int *icon }; %apply int *OUTPUT { action_state_t *state }; %apply bool *OUTPUT { bool *checkable }; @@ -789,7 +786,6 @@ static PyObject *qstrvec2pylist(qstrvec_t &vec) $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); } -//--------------------------------------------------------------------- %typemap(in) uint64 { uint64 $1_temp; @@ -801,21 +797,22 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); $1 = $1_temp; } -%inline %{ -namespace Controls -{ - class TWinControl; - class TCustomControl; // ptr to custom ida viewer +%typemap(in,numinputs=0) uint64 *result (uint64 temp) { + $1 = &temp; } -using Controls::TWinControl; -using Controls::TCustomControl; -%} - -namespace Forms -{ - class TForm; +%typemap(argout) uint64 *result { + Py_XDECREF(resultobj); + if (result > 0) + { + resultobj = PyLong_FromUnsignedLongLong(*(unsigned long long *) $1); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } } -using Forms::TForm; +%apply uint64 *result { uint64 *out }; // Make get_any_cmt() work %apply unsigned char *OUTPUT { color_t *cmttype }; diff --git a/tools/dmpapi.py b/tools/dmpapi.py new file mode 100644 index 0000000..c3da559 --- /dev/null +++ b/tools/dmpapi.py @@ -0,0 +1,60 @@ + +# helper script, used to dump the contents of the IDA +# APIs (used for 7.00 -> 6.95 compat support) + +import os + +import idc +import idaapi +import inspect +outfile = idc.ARGV[1] + +def formatargspec(argspec): + # only format the default args + values + parts = [] + dflts = argspec.defaults or [] + for i in xrange(len(argspec.args) - len(dflts)): + parts.append("_") + for i in xrange(len(dflts)): + parts.append("=%s" % str(dflts[i])) + if argspec.varargs: + parts.append("*%s" % argspec.varargs) + if argspec.keywords: + parts.append("**%s" % argspec.keywords) + return ", ".join(parts) + + +def dump_module(module, out): + mname = module.__name__ + outmod = [] + out[mname] = outmod + for symbol in sorted(dir(module)): + if symbol.endswith("_swigregister"): + continue + if symbol == "_%s" % mname: # _ida_area + continue + if symbol == "cvar": + continue + srcmod = inspect.getmodule(getattr(module, symbol)) + if srcmod and (srcmod.__name__.find("ctypes") > -1): + continue + thing = getattr(module, symbol) + if inspect.isfunction(thing) or inspect.ismethod(thing): + argspec = inspect.getargspec(thing) + symbol = "%s(%s)" % (symbol, formatargspec(argspec)) + if thing.func_dict.get("bc695redef", False): + symbol = "%s!bc695redef" % symbol + outmod.append(symbol) + +out = {} +for modname in sorted(sys.modules): + module = sys.modules[modname] + if modname.startswith("ida_") or modname in ["idc"]: + # if modname not in ignorable_modules: + dump_module(module, out) + +with open(outfile, "w") as fout: + import pprint + fout.write("%s" % pprint.pformat(out)) + +idc.Exit(0) diff --git a/tools/docs/hrdoc.cfg b/tools/docs/hrdoc.cfg deleted file mode 100644 index 3c1f8e3..0000000 --- a/tools/docs/hrdoc.cfg +++ /dev/null @@ -1,147 +0,0 @@ -[epydoc] -# 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, ida_allins ida_area ida_auto ida_bytes ida_dbg ida_diskio ida_entry ida_enum ida_expr ida_fixup ida_fpro ida_frame ida_funcs ida_gdl ida_graph ida_hexrays ida_ida ida_idaapi ida_idd ida_idp ida_ints ida_kernwin ida_lines ida_loader ida_moves ida_nalt ida_name ida_netnode ida_offset ida_pro ida_queue ida_registry ida_search ida_segment ida_srarea ida_strlist ida_struct ida_typeinf ida_ua ida_xref - -# The type of output that should be generated. Should be one -# of: html, text, latex, dvi, ps, pdf. -output: html - -# The path to the output directory. May be relative or absolute. -target: hr-html/ - -# An integer indicating how verbose epydoc should be. The default -# value is 0; negative values will supress warnings and errors; -# positive values will give more verbose output. -verbosity: 0 - -# A boolean value indicating that Epydoc should show a tracaback -# in case of unexpected error. By default don't show tracebacks -debug: 0 - -# If True, don't try to use colors or cursor control when doing -# textual output. The default False assumes a rich text prompt -simple-term: 0 - - -### Generation options - -# The default markup language for docstrings, for modules that do -# not define __docformat__. Defaults to epytext. -docformat: epytext - -# Whether or not parsing should be used to examine objects. -parse: yes - -# Whether or not introspection should be used to examine objects. -introspect: yes - -# Don't examine in any way the modules whose dotted name match this -# regular expression pattern. -#exclude - -# Don't perform introspection on the modules whose dotted name match this -# regular expression pattern. -#exclude-introspect - -# Don't perform parsing on the modules whose dotted name match this -# regular expression pattern. -#exclude-parse - -# The format for showing inheritance objects. -# It should be one of: 'grouped', 'listed', 'included'. -inheritance: listed - -# Whether or not to inclue private variables. (Even if included, -# private variables will be hidden by default.) -private: no - -# Whether or not to list each module's imports. -imports: no - -# Whether or not to include syntax highlighted source code in -# the output (HTML only). -sourcecode: no - -# Whether or not to includea a page with Epydoc log, containing -# effective option at the time of generation and the reported logs. -include-log: no - - -### Output options - -# The documented project's name. -name: IDAPython - -# The CSS stylesheet for HTML output. Can be the name of a builtin -# stylesheet, or the name of a file. -css: white - -# The documented project's URL. -url: http://code.google.com/p/idapython/ - -# HTML code for the project link in the navigation bar. If left -# unspecified, the project link will be generated based on the -# project's name and URL. -link: Hex-Rays - -# The "top" page for the documentation. Can be a URL, the name -# of a module or class, or one of the special names "trees.html", -# "indices.html", or "help.html" -#top: os.path - -# An alternative help file. The named file should contain the -# body of an HTML file; navigation bars will be added to it. -#help: my_helpfile.html - -# Whether or not to include a frames-based table of contents. -frames: yes - -# Whether each class should be listed in its own section when -# generating LaTeX or PDF output. -separate-classes: no - - -### API linking options - -# Define a new API document. A new interpreted text role -# will be created -#external-api: epydoc - -# Use the records in this file to resolve objects in the API named NAME. -#external-api-file: epydoc:api-objects.txt - -# Use this URL prefix to configure the string returned for external API. -#external-api-root: epydoc:http://epydoc.sourceforge.net/api - - -### Graph options - -# The list of graph types that should be automatically included -# in the output. Graphs are generated using the Graphviz "dot" -# executable. Graph types include: "classtree", "callgraph", -# "umlclass". Use "all" to include all graph types -#graph: classtree - -# The path to the Graphviz "dot" executable, used to generate -# graphs. -#dotpath: /usr/local/bin/dot - -# The name of one or more pstat files (generated by the profile -# or hotshot module). These are used to generate call graphs. -#pstat: profile.out - -# Specify the font used to generate Graphviz graphs. -# (e.g., helvetica or times). -graph-font: Helvetica - -# Specify the font size used to generate Graphviz graphs. -#graph-font-size: 10 - - -### Return value options - -# The condition upon which Epydoc should exit with a non-zero -# exit status. Possible values are error, warning, docstring_warning -#fail-on: error diff --git a/tools/docs/hrdoc.py b/tools/docs/hrdoc.py index 0a1849e..65c49d8 100644 --- a/tools/docs/hrdoc.py +++ b/tools/docs/hrdoc.py @@ -9,8 +9,8 @@ try: except ImportError as e: import idc import traceback - idc.Message("Couldn't import module %s\n" % traceback.format_exc()) - idc.Exit(-1) + idc.msg("Couldn't import module %s\n" % traceback.format_exc()) + idc.qexit(-1) # -------------------------------------------------------------------------- DOC_DIR = 'hr-html' @@ -111,6 +111,13 @@ def main(): try: print "Generating documentation....." + import ida_pro + try: + ida_pro._BC695 + print "'ida_pro._BC695' exists. Please recompile with BC695=0 (see makefile). Bailing out." + return -1 + except: + pass # ok os.chdir('docs') gen_docs() @@ -126,4 +133,4 @@ def main(): # -------------------------------------------------------------------------- if __name__ == '__main__': main() - Exit(0) + qexit(0) diff --git a/tools/gen_idc_bc695.py b/tools/gen_idc_bc695.py new file mode 100644 index 0000000..23c12a9 --- /dev/null +++ b/tools/gen_idc_bc695.py @@ -0,0 +1,208 @@ + +# This script will do the following things: +# - open idc.idc +# - advance to the compatibility macros section +# - read, and parse each of those +# - if the symbol doesn't exist in the 'idc' module, dump its alias into the output file + +import argparse +p = argparse.ArgumentParser() +p.add_argument("-i", "--idc", required=True, help="Path to the idc.idc file") +p.add_argument("-o", "--output", required=True, help="Path to the output file") +p.add_argument("-d", "--debug-out", default=False, action="store_true", help="Dump code that shows, at ida start-time, what symbols would be overriden by the compat layer") +args = p.parse_args() + +import os + +with open(args.idc, "r") as fin: + inlines = fin.readlines() + +# search for compat macros section, and remove uninteresting lines +for idx in xrange(len(inlines)): + if inlines[idx].replace(" ", "").find("COMPATIBILITYMACROS") > -1: + break +assert(idx < len(inlines)) +inlines=inlines[idx:] + +def nextline(): + global inlines + l = inlines[0].strip() + inlines=inlines[1:] + idx = l.find("//") + if idx > -1: + l = l[0:idx].strip() + return l + +# set of symbols that must not be redefined +forbidden = [ + "GetLocalType", + "AddSeg", + "SetType", + "GetDisasm", + "SetPrcsr", + "GetFloat", + "GetDouble", + "AutoMark", + "is_pack_real", + "set_local_type", + "WriteMap", + "WriteTxt", + "WriteExe", + "CompileEx", + "uprint", + "form", + "Appcall", + "ApplyType", + "GetManyBytes", + "GetString", + "ClearTraceFile", + "FindBinary", + "NextHead", + "ParseTypes", + "PrevHead", + "ProcessUiAction", + "SaveBase", + "eval", + "MakeStr", +] + +symbols_modules = { + "AF_ANORET" : "ida_ida", + "AF_ANORET" : "ida_ida", + "AF_CHKUNI" : "ida_ida", + "AF_DATOFF" : "ida_ida", + "AF_DOCODE" : "ida_ida", + "AF_DODATA" : "ida_ida", + "AF_FTAIL" : "ida_ida", + "AF_HFLIRT" : "ida_ida", + "AF_JUMPTBL" : "ida_ida", + "AF_PURDAT" : "ida_ida", + "AF_REGARG" : "ida_ida", + "AF_SIGCMT" : "ida_ida", + "AF_SIGMLT" : "ida_ida", + "AF_STKARG" : "ida_ida", + "AF_STRLIT" : "ida_ida", + "AF_TRFUNC" : "ida_ida", + "AF_VERSP" : "ida_ida", + "BADADDR" : "ida_idaapi", + "FF_UNUSED" : "ida_bytes", + "FIXUPF_CREATED" : "ida_fixup", + "FIXUPF_EXTDEF" : "ida_fixup", + "FIXUPF_REL" : "ida_fixup", + "FIXUPF_UNUSED" : "ida_fixup", + "FIXUP_OFF8" : "ida_fixup", + "GN_VISIBLE" : "ida_name", + "SEGMOD_KEEP" : "ida_segment", + "SEGMOD_KILL" : "ida_segment", + "SEGMOD_SILENT" : "ida_segment", + "SETPROC_IDB" : "ida_idp", + "SETPROC_LOADER" : "ida_idp", + "SETPROC_LOADER_NON_FATAL" : "ida_idp", + "STRF_AUTO" : "ida_ida", + "STRF_COMMENT" : "ida_ida", + "STRF_GEN" : "ida_ida", + "STRF_SAVECASE" : "ida_ida", + "STRF_SERIAL" : "ida_ida", + "STRTYPE_C" : "ida_nalt", + "STRTYPE_C_16" : "ida_nalt", + "STRTYPE_C_32" : "ida_nalt", + "STRTYPE_LEN2_16" : "ida_nalt", + "STRTYPE_LEN4_16" : "ida_nalt", + "STRTYPE_PASCAL" : "ida_nalt", + "STRTYPE_TERMCHR" : "ida_nalt", + "V695_REF_VHIGH" : "ida_nalt", + "V695_REF_VLOW" : "ida_nalt", + "error" : "ida_kernwin", + "warning" : "ida_kernwin", + "ask_str" : "ida_kernwin", + "ask_file" : "ida_kernwin", + "ask_addr" : "ida_kernwin", + "ask_long" : "ida_kernwin", + "is_mapped" : "ida_bytes", + "decode_insn" : "ida_ua", +} + +import re +def maybe_qualify(s): + last_idx = -1 + for sym, mod in symbols_modules.items(): + idx = s.find(sym) + if idx > last_idx: + s = s.replace(sym, "%s.%s" % (mod, sym)) + last_idx = idx + 1 + len(mod) + return s + +def remove_parens(arg): + m = re.match(r'\s*\((.*)\)\s*$', arg) + if m: + arg = m.group(1) + return arg.strip() + +def fix_ternary_operator(code): + match = re.match(r'([^(]+)\((.*)\)', code) + if match: + changed = False + func = match.group(1) + args = match.group(2) + out = [] + for arg in args.split(','): + m2 = re.match(r'([^?]+)\?(.*):(.*)', arg) + if m2: + cond = remove_parens(m2.group(1)) + ithen = remove_parens(m2.group(2)) + ielse = remove_parens(m2.group(3)) + arg = ithen + ' if ' + cond + ' else ' + ielse + changed = True + out.append(arg.strip()) + if changed: + code = func + '(' + ', '.join(out) + ')' + return code + +import time +funcall_pat = re.compile(r"#define\s+([a-zA-Z0-9_]*)\s*(\([^\)]*\))\s*(.*)") +alias_pat = re.compile(r"#define\s+([a-zA-Z0-9_]*)\s*([a-zA-Z0-9_/\*\.]*)\s*$") +with open(args.output, "w") as fout: + fout.write("# Autogenerated on: %s\n\n" % time.strftime("%c")) + for mod in sorted(list(set(symbols_modules.values()))): + fout.write("import %s\n" % mod) + fout.write("from idc import *\n\n") + while len(inlines): + l = nextline() + if l == "": + continue + repl = None + match = funcall_pat.match(l) + if match: + symbol = match.group(1) + parms = match.group(2) + code = match.group(3) + while True: + has_more = code.endswith("\\") + if has_more: + code = code[0:-1] + code = code + nextline() + else: + break + code = fix_ternary_operator(code) + code = maybe_qualify(code) + repl = "def %s%s: return %s\n" % (symbol, parms, code) + else: + match = alias_pat.match(l) + if match: + symbol = match.group(1) + newsym = match.group(2) + newsym = maybe_qualify(newsym) + repl = "%s=%s\n" % (symbol, newsym) + + if repl and symbol not in forbidden: + if not args.debug_out: + fout.write(repl) + else: + fout.write(""" +try: + import idc + x = idc.%s + print("Would override %s") +except: + pass +""" % (symbol, symbol)) diff --git a/tools/genhooks/genhooks.py b/tools/genhooks/genhooks.py index 61da495..d36ffea 100644 --- a/tools/genhooks/genhooks.py +++ b/tools/genhooks/genhooks.py @@ -81,7 +81,7 @@ def add_enum_value(enumval_el, name, enum_name): rtype = None rdefault = None rexpr = None - recipe_data = recipe[name] if name in recipe else {} + recipe_data = recipe.get(name, {}) if "ignore" in recipe_data and recipe_data["ignore"]: return @@ -197,6 +197,7 @@ def gen_methods(out): pname = p["name"] ptype = p["type"] suppress_for_call = False + final_name = pname if "params" in recipe_data: all_pdata = recipe_data["params"] if pname in all_pdata: @@ -205,9 +206,11 @@ def gen_methods(out): ptype = pdata["type"] if "suppress_for_call" in pdata: suppress_for_call = pdata["suppress_for_call"] + if "rename" in pdata: + final_name = pdata["rename"] if not suppress_for_call: - arg_strs.append("%s %s" % (ptype, pname)) - qnotused_decls += "qnotused(%s); " % pname + arg_strs.append("%s %s" % (ptype, final_name)) + qnotused_decls += "qnotused(%s); " % final_name text = "virtual %s %s(%s) {%s%s}\n" % ( rdata["type"], method_name, @@ -236,7 +239,7 @@ def gen_notifications(out): pname = p["name"] ptype = p["type"] pick_type = ptype - if ptype in ["bool", "char", "uchar", "uint16", "cref_t", "dref_t", "cm_t", "ui_notification_t", "dbg_notification_t"]: + if ptype in ["bool", "char", "uchar", "uint16", "cref_t", "dref_t", "cm_t", "ui_notification_t", "dbg_notification_t", "tcc_renderer_type_t", "range_kind_t", "demreq_type_t"]: cast = ptype pick_type = "int" else: diff --git a/tools/genhooks/recipe_idphooks.py b/tools/genhooks/recipe_idphooks.py index df4381d..26a4b4c 100644 --- a/tools/genhooks/recipe_idphooks.py +++ b/tools/genhooks/recipe_idphooks.py @@ -1,61 +1,40 @@ 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" : { + "ev_last_cb_before_debugger" : {"ignore" : True}, + "ev_last_cb_before_type_callbacks" : {"ignore" : True}, + "ev_get_idd_opinfo" : {"ignore" : True}, + "ev_loader_elf_machine" : {"ignore" : True}, + "ev_ana_insn" : { "return" : { "type" : "bool", "default" : "false", - "convertor" : "IDP_Hooks::bool_to_cmdsize", - } - }, - "custom_out" : { - "return" : { - "type" : "bool", - "default" : "false", - "convertor" : "IDP_Hooks::bool_to_2or0", - } - }, - "custom_emu" : { - "return" : { - "type" : "bool", - "default" : "false", - "convertor" : "IDP_Hooks::bool_to_2or0", - } - }, - "custom_outop" : { - "params" : { - "op" : { - "type" : "PyObject *", - "clinked" : { - "module_define" : "S_IDA_UA_MODNAME", - "class_define" : "S_PY_OP_T_CLSNAME", - }, - }, - }, - "return" : { - "type" : "bool", - "default" : "false", - "convertor" : "IDP_Hooks::bool_to_2or0", - } - }, - "custom_mnem" : { - "params" : { - "buf" : { "suppress_for_call" : True, }, - "bufsize" : { "suppress_for_call" : True, }, - }, - "return" : { - "type" : "PyObject *", - "retexpr" : "Py_RETURN_NONE", - "convertor" : "IDP_Hooks::handle_custom_mnem_output", + "convertor" : "IDP_Hooks::bool_to_insn_t_size", "convertor_pass_args" : True, } }, - "rename" : { + "ev_out_insn" : { + "return" : { + "type" : "bool", + "default" : "false", + "convertor" : "IDP_Hooks::bool_to_1or0", + } + }, + "ev_emu_insn" : { + "return" : { + "type" : "bool", + "default" : "false", + "convertor" : "IDP_Hooks::bool_to_1or0", + } + }, + "ev_out_operand" : { + "return" : { + "type" : "bool", + "default" : "false", + "convertor" : "IDP_Hooks::bool_to_1or0", + } + }, + "ev_rename" : { "params" : { "flags" : { "suppress_for_call" : True, @@ -63,12 +42,7 @@ recipe = { }, }, }, - "savebase" : { - "return" : { - "type" : "void" - } - }, - "assemble" : { + "ev_assemble" : { "return" : { "type" : "PyObject *", "retexpr" : "Py_RETURN_NONE", @@ -81,13 +55,16 @@ recipe = { }, }, }, - "decorate_name3" : { + "ev_decorate_name" : { "params" : { "cc" : { "type" : "int", "convertor" : "IDP_Hooks::cm_t_to_int", }, "outbuf" : { "suppress_for_call" : True, }, + "type" : { + "rename" : "optional_type", + } }, "return" : { "type" : "PyObject *", @@ -96,10 +73,9 @@ recipe = { "convertor_pass_args" : True, } }, - "get_reg_name" : { + "ev_get_reg_name" : { "params" : { "buf" : { "suppress_for_call" : True, }, - "bufsize" : { "suppress_for_call" : True, }, }, "return" : { "type" : "PyObject *", @@ -108,7 +84,7 @@ recipe = { "convertor_pass_args" : True, } }, - "delay_slot_insn" : { + "ev_delay_slot_insn" : { "params" : { "ea" : { "type" : "ea_t", @@ -130,4 +106,28 @@ recipe = { "convertor_pass_args" : True, }, }, + "ev_use_regarg_type" : { + "params" : { + "idx" : { "suppress_for_call" : True, }, + }, + "return" : { + "type" : "PyObject *", + "retexpr" : "Py_RETURN_NONE", + "convertor" : "IDP_Hooks::handle_use_regarg_type_output", + "convertor_pass_args" : True, + }, + }, + "ev_demangle_name" : { + "params" : { + "outbuf" : { "suppress_for_call" : True, }, + "res" : { "suppress_for_call" : True, }, + "demreq" : { "cast_needed" : "int", "type" : "int" }, + }, + "return" : { + "type" : "PyObject *", + "retexpr" : "Py_RETURN_NONE", + "convertor" : "IDP_Hooks::handle_demangle_name_output", + "convertor_pass_args" : True, + }, + }, } diff --git a/tools/genhooks/recipe_uihooks.py b/tools/genhooks/recipe_uihooks.py index e75461a..8fc2826 100644 --- a/tools/genhooks/recipe_uihooks.py +++ b/tools/genhooks/recipe_uihooks.py @@ -12,8 +12,7 @@ recipe = { }, "get_ea_hint" : { "params" : { - "buf" : { "suppress_for_call" : True, }, - "bufsize" : { "suppress_for_call" : True, }, + "buf" : { "suppress_for_call" : True, }, }, "return" : { "type" : "PyObject *", @@ -47,10 +46,8 @@ recipe = { } }, - "genfile_callback" : {"ignore" : True}, - "get_chooser_item_attrs" : {"ignore" : True}, "idp_event" : {"ignore" : True}, - "list" : {"ignore" : True}, + "refresh_choosers" : {"ignore" : True}, "load_dbg_dbginfo" : {"ignore" : True}, } diff --git a/tools/genhooks/recipe_viewhooks.py b/tools/genhooks/recipe_viewhooks.py new file mode 100644 index 0000000..b81fdce --- /dev/null +++ b/tools/genhooks/recipe_viewhooks.py @@ -0,0 +1,3 @@ + +recipe = { +} diff --git a/tools/genswigheader.py b/tools/genswigheader.py index 6bc5ee3..67ef267 100644 --- a/tools/genswigheader.py +++ b/tools/genswigheader.py @@ -31,7 +31,7 @@ with open(args.input, "rb") as fin: 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"] + required_headers = ["pro", "ida", "xref", "typeinf", "enum", "netnode", "range", "lines", "kernwin", "bytes", "auto", "nalt"] for rh in required_headers: add_imports_from_dep(rh) parts.append("#endif") diff --git a/tools/idapython_implib.def.in b/tools/idapython_implib.def.in index 913ec40..5b56539 100644 --- a/tools/idapython_implib.def.in +++ b/tools/idapython_implib.def.in @@ -6,11 +6,11 @@ EXPORTS PyW_GetNumber PyW_GetNumberAsIDC PyW_GetStringAttr - PyW_IntVecToPyList + PyW_SizeVecToPyList PyW_IsSequenceType PyW_ObjectToString PyW_PyListToEaVec - PyW_PyListToIntVec + PyW_PyListToSizeVec PyW_PyListToStrVec PyW_register_compiled_form PyW_ShowCbErr @@ -25,8 +25,8 @@ EXPORTS 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_find_by_view lookup_info_t_new_entry meminfo_vec_t_to_py py_customidamemo_t_bind @@ -35,10 +35,8 @@ EXPORTS 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 @@ -52,6 +50,7 @@ EXPORTS pyvar_walk_list pyw_convert_idc_args set_script_timeout + set_interruptible_state til_deregister_python_array_type_data_t_instance til_deregister_python_func_type_data_t_instance til_deregister_python_ptr_type_data_t_instance @@ -62,5 +61,9 @@ EXPORTS til_register_python_ptr_type_data_t_instance til_register_python_tinfo_t_instance til_register_python_udt_type_data_t_instance + try_create_swig_wrapper + idapython_hook_to_notification_point + idapython_unhook_from_notification_point + register_module_lifecycle_callbacks pycim_lookup_info DATA - PLUGIN DATA + %PLUGIN_DATA_EXP% diff --git a/tools/patch_codegen.py b/tools/patch_codegen.py index 1a726d4..3b4db59 100644 --- a/tools/patch_codegen.py +++ b/tools/patch_codegen.py @@ -2,44 +2,68 @@ import os, re try: - from argparse import ArgumentParser + 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 + 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 some code generation, so it builds') parser.add_argument("-f", "--file", required=True) parser.add_argument("-p", "--patches", required=True) parser.add_argument("-v", "--verbose", default=False, action="store_true") +parser.add_argument("-V", "--apply-valist-patches", default=False, action="store_true") args = parser.parse_args() +patched_cmt = "// patched by patch_codegen.py" if os.path.isfile(args.patches): with open(args.patches, "r") as fin: patches = eval(fin.read()) - regex = re.compile(r"SWIGINTERN PyObject \*_wrap_([a-zA-Z0-9_]*)\(.*") + wrap_regex = re.compile(r"SWIGINTERN PyObject \*_wrap_([a-zA-Z0-9_]*)\(.*") + director_method_regex = re.compile(r".*(SwigDirector_[a-zA-Z0-9_]*::[a-zA-Z0-9_]*)\(.*") + swig_clink_var_get_regex = re.compile(r"SWIGINTERN PyObject \*(Swig_var_[a-zA-Z0-9_]*_get).*") + swig_clink_var_set_regex = re.compile(r"SWIGINTERN int (Swig_var_[a-zA-Z0-9_]*_set).*") + lines = [] with open(args.file, "rb") as f: STAT_UNKNOWN = {} STAT_IN_FUNCTION = {} stat = STAT_UNKNOWN func_patches = [] + entered_function = False for line in f: - m = regex.match(line) + m = wrap_regex.match(line) + if not m: + m = director_method_regex.match(line) + if not m: + m = swig_clink_var_get_regex.match(line) + if not m: + m = swig_clink_var_set_regex.match(line) if m: stat = STAT_IN_FUNCTION fname = m.group(1) + entered_function = True func_patches = patches.get(fname, []) else: for patch_kind, patch_data in func_patches: if patch_kind == "va_copy": - dst_va, src_va = patch_data - target = "%s = *%s;" % (dst_va, src_va) - if line.strip() == target: - line = "set_vva(%s, *%s); // patched by patch_codegen.py\n" % (dst_va, src_va) + if args.apply_valist_patches: + dst_va, src_va = patch_data + target = "%s = *%s;" % (dst_va, src_va) + if line.strip() == target: + line = "set_vva(%s, *%s); %s\n" % (dst_va, src_va, patched_cmt) + elif patch_kind == "acquire_gil": + if entered_function: + line = " PYW_GIL_GET; %s\n%s" % (patched_cmt, line) + elif patch_kind == "repl_text": + idx = line.find(patch_data[0]) + if idx > -1: + line = line.rstrip().replace(patch_data[0], patch_data[1]) + line = "%s %s\n" % (line, patched_cmt) else: raise Exception("Unknown patch kind: %s" % patch_kind) + entered_function = False lines.append(line) tmp_file = "%s.tmp" % args.file diff --git a/tools/patch_codegen/hexrays.py b/tools/patch_codegen/hexrays.py index 0b91764..647d5c9 100644 --- a/tools/patch_codegen/hexrays.py +++ b/tools/patch_codegen/hexrays.py @@ -5,4 +5,13 @@ "vcall_helper" : [ ("va_copy", ("arg4", "temp")), ], + "SwigDirector_microcode_filter_t::match" : [ + ("acquire_gil", True) + ], + "SwigDirector_microcode_filter_t::apply" : [ + ("acquire_gil", True) + ], + "SwigDirector_udc_filter_t::match" : [ + ("acquire_gil", True) + ], } diff --git a/tools/patch_codegen/kernwin.py b/tools/patch_codegen/kernwin.py index d2f095e..cd6b38f 100644 --- a/tools/patch_codegen/kernwin.py +++ b/tools/patch_codegen/kernwin.py @@ -1,11 +1,5 @@ { - "askfile2_cv" : [ - ("va_copy", ("arg5", "temp")), - ], - "vaskqstr" : [ - ("va_copy", ("arg3", "temp")), - ], - "vumsg" : [ - ("va_copy", ("arg2", "temp")), + "vask_file" : [ + ("va_copy", ("arg4", "temp")), ], } diff --git a/tools/patch_codegen/pro.py b/tools/patch_codegen/pro.py deleted file mode 100644 index 24bcf52..0000000 --- a/tools/patch_codegen/pro.py +++ /dev/null @@ -1,5 +0,0 @@ -{ - "vinterr" : [ - ("va_copy", ("arg4", "temp")), - ] -} diff --git a/tools/patch_codegen/typeinf.py b/tools/patch_codegen/typeinf.py new file mode 100644 index 0000000..cd3f3fb --- /dev/null +++ b/tools/patch_codegen/typeinf.py @@ -0,0 +1,10 @@ +{ + "Swig_var_idati_set" : [ + ("repl_text" , ( + "idati = reinterpret_cast< til_t * >(argp);", + "// idati = reinterpret_cast< til_t * >(argp);")), + ], + "Swig_var_idati_get" : [ + ("repl_text" , ("SWIG_as_voidptr(idati)", "SWIG_as_voidptr(/*idati*/ get_idati())")), + ], +} diff --git a/tools/patch_directors_cc.py b/tools/patch_directors_cc.py index 6af3529..6adbc25 100644 --- a/tools/patch_directors_cc.py +++ b/tools/patch_directors_cc.py @@ -50,14 +50,52 @@ patches = [ # const_aloc_visitor_t "virtual int idaapi visit_location", - # area_visitor2_t - "virtual int idaapi visit_area", + # range_visitor_t + "virtual int idaapi visit_range", # 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", + + # predicate_t + "virtual bool idaapi should_display", + + # graph_visitor_t + "virtual int idaapi visit_node", + "virtual int idaapi visit_edge", + + # graph_node_visitor_t + "virtual int idaapi visit_node", + "virtual bool idaapi is_forbidden_edge", + + # graph_path_visitor_t + "virtual int idaapi walk_forward", + "virtual int idaapi walk_backward", + + # mutable_graph_t + "virtual rect_t &idaapi nrect", + "virtual edge_info_t *idaapi get_edge", + "virtual abstract_graph_t *idaapi clone", + "virtual bool idaapi set_nrect", + "virtual bool idaapi set_edge", + "virtual int idaapi add_node", + "virtual ssize_t idaapi del_node", + "virtual bool idaapi add_edge", + "virtual bool idaapi del_edge", + "virtual bool idaapi replace_edge", + "virtual bool idaapi refresh", + "virtual mutable_graph_t *idaapi clone", + "virtual bool idaapi redo_layout", + "virtual void idaapi resize", + "virtual ea_t idaapi calc_group_ea", + "virtual bool idaapi is_user_graph", + + # codegen_t + "virtual mreg_t idaapi load_operand", + "virtual int idaapi analyze_prolog", + "virtual int idaapi gen_micro", ] diff --git a/tools/typemaps-supplement/pymacros.swg b/tools/typemaps-supplement/pymacros.swg new file mode 100644 index 0000000..b9044e0 --- /dev/null +++ b/tools/typemaps-supplement/pymacros.swg @@ -0,0 +1,9 @@ + +// We'll take advantage of the fact that SWiG's 'python.swg' includes +// an "unqualified" 'pymacros.swg', for us to override a SWiG define +// that will be used for generating exception text (and which I have +// found no other way to redefine). Then, we'll include the real +// 'pymacros.swg' file, as if nothing happened. +#define SWIG_DirOutFail(code, msg) Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(code), msg " in method '$symname'") + +%include