diff --git a/api_contents.txt b/api_contents.txt index af05240..e7f5b5a 100644 --- a/api_contents.txt +++ b/api_contents.txt @@ -2372,6 +2372,7 @@ 'e_exception_t_ea_set', 'e_exception_t_info_get', 'e_exception_t_info_set', + 'ea2str', 'ea_array___getitem__', 'ea_array___setitem__', 'ea_array_cast', diff --git a/build.py b/build.py index a5d4648..4f18a8a 100644 --- a/build.py +++ b/build.py @@ -39,7 +39,7 @@ parser.add_argument("--swig-bin", type=str, help="Path to the SWIG binary", defa parser.add_argument("--swig-inc", type=str, help="Path(s) to the SWIG includes directory(ies)", default=None) parser.add_argument("--with-hexrays", help="Build Hex-Rays decompiler bindings (requires the 'hexrays.hpp' header to be present in the SDK's include/ directory)", default=False, action="store_true") parser.add_argument("--debug", help="Build debug version of the plugin", default=False, action="store_true") -parser.add_argument("--python-home", help="Python home, where the 'include' directory can be found", default=None) +parser.add_argument("--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") args = parser.parse_args() @@ -72,7 +72,7 @@ def main(): if not args.debug: env["NDEBUG"] = "1" if args.python_home: - env["IDAPYTHON_PYTHONHOME"] = args.python_home + env["LINUX_PYTHON_HOME"] = args.python_home if args.verbose: argv.append("-d") for ea64 in [False, True]: diff --git a/docs/notes.txt b/docs/notes.txt deleted file mode 100644 index ab89347..0000000 --- a/docs/notes.txt +++ /dev/null @@ -1,53 +0,0 @@ -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/ex_custview.py b/examples/ex_custview.py index c38b03b..36a9997 100644 --- a/examples/ex_custview.py +++ b/examples/ex_custview.py @@ -32,9 +32,13 @@ class mycv_t(simplecustviewer_t): return False for i in xrange(0, 100): - self.AddLine("Line %d" % i) - -# self.Jump(0) + fg, bg = idaapi.COLOR_PREFIX, None + # make every 10th line a bit special + if i % 10 == 0: + fg = idaapi.COLOR_DEFAULT # i.e., white... + bg = 0xFFFF00 # ...on cyan + pfx = idaapi.COLSTR("%3d" % i, idaapi.SCOLOR_PREFIX) + self.AddLine("%s: Line %d" % (pfx, i), fgcolor=fg, bgcolor=bg) return True diff --git a/makefile b/makefile index 4552454..578aa53 100644 --- a/makefile +++ b/makefile @@ -15,17 +15,6 @@ # uses os.path.join()) # -ifdef __X64__ - ifdef __LINUX__ - LINUX64=1 - endif -endif - -ifdef LINUX64 -all: - @echo "Not building Python for Linux x64" -else - PROC=python API_CONTENTS=api_contents.txt PYDOC_INJECTIONS=pydoc_injections.txt @@ -37,37 +26,36 @@ DIST=$(F)dist ifdef __NT__ SYSNAME=win MSRUNTIME=/MD -else endif + ifdef __LINUX__ SYSNAME=linux DEFS=-D__LINUX__ PYTHON32_LIBRARY_PATH?=/usr/lib PYTHON32_LIBRARY_INCLUDE=-L$(PYTHON32_LIBRARY_PATH) endif + ifdef __BSD__ SYSNAME=bsd DEFS=-D__BSD__ endif + ifdef __MAC__ SYSNAME=mac DEFS=-D__MAC__ endif -# O1=idaapi - -# __USE_RTTI__=1 - - DONT_ERASE_LIB=1 include ../plugin.mak +include ../pyplg.mak + PLUGIN_SCRIPT= ifdef __LINUX__ -OUTDLLOPTS=-Wl,-soname,$(notdir $(BINARY)) + OUTDLLOPTS=-Wl,-soname,$(notdir $(BINARY)) else ifdef __MAC__ - OUTDLLOPTS=-Wl,-install_name,@executable_path/plugins/$(notdir $(BINARY)) + OUTDLLOPTS=-Wl,-install_name,@executable_path/plugins/$(notdir $(BINARY)) endif endif @@ -114,16 +102,27 @@ $(DEPLOY_PYDIR): -@if [ ! -d "$(DEPLOY_PYDIR)" ] ; then mkdir -p 2>/dev/null $(DEPLOY_PYDIR) ; fi ifdef __NT__ -MODULE_SFX=.pyd + MODULE_SFX=.pyd else -MODULE_SFX=.so + MODULE_SFX=.so +endif + +ifneq ($(OUT_OF_TREE_BUILD),) + # envvar HAS_HEXRAYS must have been set by build.py if needed +else + HAS_HEXRAYS=1 # force hexrays bindings +endif +ifneq ($(HAS_HEXRAYS),) + WITH_HEXRAYS=-DWITH_HEXRAYS + WITH_HEXRAYS_CHKAPI=--with-hexrays + HEXRAYS_MODNAME=hexrays endif # We are building 'MODULES_NAMES' from subvars because it appears some versions # of make do not deal too well with '\'s, and introduce spaces, which later is # problematic when substituting ' ' for ',' & passing modules list to scripts MNAMES_0=allins area auto bytes dbg diskio entry enum expr fixup -MNAMES_1=fpro frame funcs gdl graph hexrays ida idaapi idd idp ints +MNAMES_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) @@ -139,23 +138,19 @@ ALL_ST_WRAP_PY=$(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/ida_$(mod).py) PYTHON_MODULES=$(MODULES_NAMES:%=$(DEPLOY_PYDIR)/ida_%.py) ifdef __NT__ -MODULE_LINKIDA= -CREATE_IMPLIB=$(RS)lib32.bat -IDAPYTHON_IMPLIB_DEF=$(F)idapython_implib.def -IDAPYTHON_IMPLIB_DEF_IN=tools/idapython_implib.def.in -IDAPYTHON_IMPLIB_PATH=$(F)python.lib -BINARY_LINKOPTS=/def:$(IDAPYTHON_IMPLIB_DEF) /IMPLIB:$(IDAPYTHON_IMPLIB_PATH) -RESFILES=$(IDAPYTHON_IMPLIB_DEF) + MODULE_LINKIDA= + CREATE_IMPLIB=$(RS)lib32.bat + IDAPYTHON_IMPLIB_DEF=$(F)idapython_implib.def + IDAPYTHON_IMPLIB_DEF_IN=tools/idapython_implib.def.in + IDAPYTHON_IMPLIB_PATH=$(F)python.lib + BINARY_LINKOPTS=/def:$(IDAPYTHON_IMPLIB_DEF) /IMPLIB:$(IDAPYTHON_IMPLIB_PATH) + RESFILES=$(IDAPYTHON_IMPLIB_DEF) else -MODULE_LINKIDA=-L$(R) $(LINKIDA) $(BINARY) + MODULE_LINKIDA=-L$(R) $(LINKIDA) $(BINARY) endif all: objdir pyfiles config $(DEPLOYED_MODULES) $(PYTHON_MODULES) $(ST_API_CONTENTS) $(IDAPYTHON_IMPLIB) $(ST_PYDOC_INJECTIONS) #$(TEST_IDC) -# used python version -PYTHON_VERSION_MAJOR?=2 -PYTHON_VERSION_MINOR?=7 - # IDAPython version IDAPYTHON_VERSION_MAJOR=6 IDAPYTHON_VERSION_MINOR=9 @@ -172,17 +167,10 @@ ifdef __CODE_CHECKER__ endif ifdef __NT__ # os and compiler specific flags -ifneq ($(UCRT_INCLUDE),) - I_UCRT_INCLUDE=/I$(UCRT_INCLUDE) -endif - PYTHON_ROOT?=c: - PYTHON_DIR=$(PYTHON_ROOT)/python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR) - IDAPYTHON_CFLAGS=-w -Z7 /EHsc /bigobj /I$(MSVCDIR)Include $(I_UCRT_INCLUDE) - ifdef __X64__ - PYTHONLIB=vcx64_python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR).lib -nodefaultlib:python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR).lib - else - PYTHONLIB=$(PYTHON_DIR)/libs/python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR).lib + ifneq ($(UCRT_INCLUDE),) + I_UCRT_INCLUDE=/I$(UCRT_INCLUDE) endif + IDAPYTHON_CFLAGS=$(PYTHON_CFLAGS) -w -Z7 /bigobj /I$(MSVCDIR)Include $(I_UCRT_INCLUDE) _SWIGFLAGS=-D__NT__ -DWIN32 -D_USRDLL -I$(PYTHON_DIR)/include SWIGINCLUDES?= # nothing # FIXME: Cannot enable the .cfg file ATM, because there's just too many errors if I do. @@ -190,28 +178,18 @@ endif else # unix/mac ifdef __LINUX__ # use the precompiled 2.7 - ifeq ($(OUT_OF_TREE_BUILD),) - # assign right away, so it won't be eval'd 10301829 times - PYDIR:=$(shell pwd)/precompiled - PYLIBDIR=$(PYDIR) - # copy these files to IDA's directory - PYLIBFILES:=$(shell find precompiled/lib -type f) - PRECOMPILED_COPY=$(R)$(PYTHONLIBNAME) $(patsubst precompiled/%,$(DEPLOY_PYDIR)/%,$(PYLIBFILES)) - else - PYDIR=$(IDAPYTHON_PYTHONHOME) - PYLIBDIR=$(PYDIR)/lib + ifndef __X64__ + ifeq ($(OUT_OF_TREE_BUILD),) + # copy these files to IDA's directory + PYLIBFILES:=$(shell find precompiled/lib -type f) + PRECOMPILED_COPY=$(R)$(LIBPYTHON_NAME) $(R)$(LIBPYTHON_NAME) $(patsubst precompiled/%,$(DEPLOY_PYDIR)/%,$(PYLIBFILES)) + endif endif - PYTHON32_INCLUDE:=-I$(PYDIR)/include/python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR) - PYTHONLIBNAME=libpython$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR).so.1.0 - PYTHONLIB=$(PYLIBDIR)/$(PYTHONLIBNAME) -ldl else - PYVER=$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR) - PYTHON32_INCLUDE:=$(shell python$(PYVER)-config --includes) - PYTHONLIB:=$(shell python$(PYVER)-config --ldflags) MACDEFINES=-DMACSDKVER=$(MACSDKVER) endif IDAPYTHON_CFLAGS=-w -g - PLATFORM_CFLAGS=$(SYS) -g $(PYTHON32_INCLUDE) $(ARCH_CFLAGS) $(PIC) -UNO_OBSOLETE_FUNCS # gcc flags + PLATFORM_CFLAGS=$(SYS) -g $(PYTHON_CFLAGS) $(ARCH_CFLAGS) $(PIC) -UNO_OBSOLETE_FUNCS # gcc flags _SWIGFLAGS=$(DEFS) SWIGINCLUDES?=-I$(SWIGDIR)share/swig/$(SWIG_VERSION)/python -I$(SWIGDIR)share/swig/$(SWIG_VERSION) endif @@ -224,7 +202,7 @@ endif DEF_TYPE_TABLE=-DSWIG_TYPE_TABLE=idaapi SWIGFLAGS=$(_SWIGFLAGS) $(SWIGINCLUDES) $(DEF_TYPE_TABLE) -ADDITIONAL_LIBS=$(PYTHONLIB) +ADDITIONAL_LIBS=$(PYTHON_LDFLAGS) PUBTREE_DIR=$(F)/public_tree .PHONY: pyfiles docs $(TEST_IDC) staging_dirs clean check_python package public_tree @@ -262,7 +240,7 @@ $(DEPLOY_PYDIR)/lib/%: precompiled/lib/% $(C)python.cfg: python.cfg $(CP) $? $@ -$(R)$(PYTHONLIBNAME): $(PYDIR)/$(PYTHONLIBNAME) +$(R)$(LIBPYTHON_NAME): $(PRECOMPILED_DIR)/$(LIBPYTHON_NAME) $(CP) $? $@ # ------------------------------------------------------------------------- @@ -304,13 +282,6 @@ $(ST_PYW)/%.py: pywraps/%.py | staging_dirs @$(CP) $^ $@ && chmod +rw $@ -ifneq ($(OUT_OF_TREE_BUILD),) - # envvar HAS_HEXRAYS must have been set by build.py if needed -else - HAS_HEXRAYS=1 # force hexrays bindings -endif - - # These require special care, as they will have to be injected w/ hooks -- this # only happens if we are sitting in the hexrays source tree; when published to # the outside world, the pywraps must already contain the injected code. @@ -352,15 +323,10 @@ $(ST_PYW)/py_kernwin.hpp: pywraps/py_kernwin.hpp \ -R $(GENHOOKS)recipe_uihooks.py \ -d "ui_dbg_,ui_obsolete" -D "ui:" -s "ui_" -ifneq ($(HAS_HEXRAYS),) - WITH_HEXRAYS=-DWITH_HEXRAYS - WITH_HEXRAYS_CHKAPI=--with-hexrays -endif - CFLAGS= $(CCOPT) $(PLATFORM_CFLAGS) $(MSRUNTIME) -D__EXPR_SRC -I. -I$(ST_SWIG) -I$(ST_SDK) -I$(F) \ -DVER_MAJOR="1" -DVER_MINOR="7" -DVER_PATCH="0" -D__IDP__ \ -DUSE_STANDARD_FILE_FUNCTIONS $(IDAPYTHON_CFLAGS) \ - $(SWITCH64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) $(DEF_TYPE_TABLE) + $(SWITCH64) $(SWITCHX64) $(ARCH_CFLAGS) $(WITH_HEXRAYS) $(DEF_TYPE_TABLE) ST_SWIG_HEADER=$(ST_SWIG)/header.i $(ST_SWIG)/header.i: tools/deploy/header.i.in tools/genswigheader.py $(ST_SDK_TARGETS) | staging_dirs @@ -413,11 +379,14 @@ define make-module-rules $(PYTHON) tools/deploy.py --pywraps $(ST_PYW) --template $$(subst $(F),,$$@) --output $$@ --module $$(subst .i,,$$(notdir $$@)) --interface-dependencies=$(subst $(_SPACE),$(_COMMA),$(SWIG_IFACE_$1)) # obj/x86_linux_gcc/wrappers/X.cpp - $(ST_WRAP)/$1.cpp: $(ST_SWIG)/$1.i + $(ST_WRAP)/$1.cpp: $(ST_SWIG)/$1.i tools/patch_codegen.py $(SWIG) -modern $(WITH_HEXRAYS) -python -threads -c++ -shadow \ - $(MACDEFINES) -D__GNUC__ $(SWIGFLAGS) $(SWITCH64) -I$(ST_SWIG) \ + $(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 ifdef __NT__ @$(PYTHON) tools/patch_directors_cc.py --file $(ST_WRAP)/$1.h endif @@ -456,19 +425,23 @@ $(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),) @(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 # Check that doc injection is stable PYDOC_INJECTIONS_RESULTS=$(MODULES_NAMES:%=$(ST_WRAP)/ida_%.pydoc_injection) $(ST_PYDOC_INJECTIONS): $(PYTHON_MODULES) cat $(PYDOC_INJECTIONS_RESULTS) > $@ +ifeq ($(OUT_OF_TREE_BUILD),) @(diff -w $(PYDOC_INJECTIONS) $(ST_PYDOC_INJECTIONS)) > /dev/null || \ (echo "PYDOC INJECTION CHANGED! update $(PYDOC_INJECTIONS) or fix .. what needs fixing" && \ echo "(New API: $(ST_PYDOC_INJECTIONS)) ***" && \ (diff -U 1 -w $(PYDOC_INJECTIONS) $(ST_PYDOC_INJECTIONS) && false)) +endif # Require a strict SWiG version (other versions might generate different code.) @@ -548,4 +521,3 @@ $(F)python$(O) : $(I)area.hpp $(I)bitrange.hpp $(I)bytes.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) -endif diff --git a/out_of_tree/parsed_notifications.zip b/out_of_tree/parsed_notifications.zip index ce4c83c..847d62b 100644 Binary files a/out_of_tree/parsed_notifications.zip and b/out_of_tree/parsed_notifications.zip differ diff --git a/pydoc_injections.txt b/pydoc_injections.txt index 246f96f..74e4b0a 100644 --- a/pydoc_injections.txt +++ b/pydoc_injections.txt @@ -5,6 +5,7 @@ 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 register_custom_data_type diff --git a/python.cpp b/python.cpp index 712c862..a02a6a2 100644 --- a/python.cpp +++ b/python.cpp @@ -1476,6 +1476,10 @@ static int idaapi on_ui_notification(void *, int code, va_list) PYW_GIL_GET; // This hook gets called from the kernel. Ensure we hold the GIL. // Let's make sure there are no non-Free()d forms. free_compiled_form_instances(); + // and no live python timers + // Note: It's ok to put this here, because 'ui_term' is guaranteed + // to be sent before the PLUGIN_FIX plugins are terminated. + clear_python_timer_instances(); } break; @@ -1515,8 +1519,6 @@ static int idaapi on_idp_notification(void *, int code, va_list) // through all the tinfo_t objects that are embedded in SWIG wrappers, // (i.e., that were created from Python) and clear those. til_clear_python_tinfo_t_instances(); - // Same thing for live python timers - clear_python_timer_instances(); break; } return 0; diff --git a/python/idc.py b/python/idc.py index 935cbb2..ed9edc9 100644 --- a/python/idc.py +++ b/python/idc.py @@ -38,7 +38,6 @@ import ida_expr import ida_fixup import ida_frame import ida_funcs -import ida_funcs import ida_gdl import ida_ida import ida_bytes @@ -316,7 +315,6 @@ def strlen(s): def xtol(s): raise DeprecatedIDCError, "xtol() is deprecated. Use python long() instead." - def atoa(ea): """ Convert address value to a string @@ -325,13 +323,7 @@ def atoa(ea): @param ea: address to format """ - segname = SegName(ea) - - if segname == "": - segname = "0" - - return "%s:%X" % (segname, ea) - + return ida_kernwin.ea2str(ea) def ltoa(n, radix): raise DeprecatedIDCError, "ltoa() is deprecated. Use python string operations instead." @@ -2508,12 +2500,11 @@ def GetStringType(ea): @return: One of ASCSTR_... constants """ - ti = ida_nalt.opinfo_t() - - if ida_bytes.get_opinfo(ea, 0, GetFlags(ea), ti): - return ti.strtype - else: - return None + flags = ida_bytes.getFlags(ea) + if ida_bytes.isASCII(flags): + oi = ida_nalt.opinfo_t() + if ida_bytes.get_opinfo(ea, 0, flags, oi): + return oi.strtype # The following functions search for the specified byte # ea - address to start from @@ -2779,6 +2770,13 @@ LN_WEAK = 0x08 # weak names 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? @@ -2910,6 +2908,7 @@ if __EA64__: INF_ASCIIPREF = 154 INF_ASCIISERNUM = 170 INF_ASCIIZEROES = 178 + INF_TRIBYTE_ORDER = 181 INF_MF = 182 INF_ORG = 183 INF_ASSUME = 184 @@ -2990,6 +2989,7 @@ INF_LISTNAMES : (False, 'listnames'), # uchar; What names should be inclu INF_ASCIIPREF : (False, 'ASCIIpref'), # char[16];ASCII names prefix INF_ASCIISERNUM : (False, 'ASCIIsernum'), # ulong; serial number INF_ASCIIZEROES : (False, 'ASCIIzeroes'), # char; leading zeroes +INF_TRIBYTE_ORDER:(False, 'tribyte_order'),# char; order of bytes in 3-byte items INF_MF : (False, 'mf'), # uchar; Byte order: 1==MSB first INF_ORG : (False, 's_org'), # char; Generate 'org' directives? INF_ASSUME : (False, 's_assume'), # char; Generate 'assume' directives? diff --git a/pywraps/py_bytes.hpp b/pywraps/py_bytes.hpp index e60cea6..13d7d98 100644 --- a/pywraps/py_bytes.hpp +++ b/pywraps/py_bytes.hpp @@ -138,6 +138,59 @@ static PyObject *py_get_many_bytes(ea_t ea, unsigned int size) Py_RETURN_NONE; } +//--------------------------------------------------------------------------- +/* +# +def get_many_bytes_ex(ea, size, mask): + """ + Get the specified number of bytes of the program into the buffer. + @param ea: program address + @param size: number of bytes to return + @return: None or (string buffer, string mask) + """ + pass +# +*/ +static PyObject *py_get_many_bytes_ex(ea_t ea, unsigned int size) +{ + 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; +} + //--------------------------------------------------------------------------- /* # diff --git a/pywraps/py_graph.py b/pywraps/py_graph.py index 943c619..d05d58b 100644 --- a/pywraps/py_graph.py +++ b/pywraps/py_graph.py @@ -60,9 +60,10 @@ class GraphViewer(ida_idaapi.CustomIDAMemo): @return: Boolean """ if self._close_open: - frm = _ida_kernwin.find_tform(self._title) + import ida_kernwin + frm = ida_kernwin.find_tform(self._title) if frm: - _ida_kernwin.close_tform(frm, 0) + ida_kernwin.close_tform(frm, 0) return _ida_graph.pyg_show(self) def Select(self, node_id): diff --git a/pywraps/py_idp.hpp b/pywraps/py_idp.hpp index fcb9bea..a71a88d 100644 --- a/pywraps/py_idp.hpp +++ b/pywraps/py_idp.hpp @@ -748,6 +748,29 @@ class IDP_Hooks { return _handle_qstring_output(o, outbuf) ? 2 : 0; } + static int handle_delay_slot_insn_output(PyObject *o, ea_t *pea, bool *pbexec, bool *pfexec) + { + if ( PySequence_Check(o) && PySequence_Size(o) == 3 ) + { + newref_t py_ea(PySequence_GetItem(o, 0)); + newref_t py_bexec(PySequence_GetItem(o, 1)); + newref_t py_fexec(PySequence_GetItem(o, 2)); + uint64 nea = 0; + if ( PyW_GetNumber(py_ea.o, &nea, NULL) + && PyBool_Check(py_bexec.o) + && PyBool_Check(py_fexec.o) ) + { + if ( pea != NULL ) + *pea = nea; + if ( pbexec != NULL ) + *pbexec = py_bexec.o == Py_True; + if ( pfexec != NULL ) + *pfexec = py_fexec.o == Py_True; + return 2; + } + } + return -1; + } public: virtual ~IDP_Hooks() diff --git a/pywraps/py_kernwin_custview.hpp b/pywraps/py_kernwin_custview.hpp index 4840539..8476978 100644 --- a/pywraps/py_kernwin_custview.hpp +++ b/pywraps/py_kernwin_custview.hpp @@ -542,6 +542,23 @@ private: PyObject *py_self, *py_this, *py_last_link; int features; + //------------------------------------------------------------------------- + static bool get_color(uint32 *out, ref_t obj) + { + bool ok = PyLong_Check(obj.o); + if ( ok ) + { + *out = uint32(PyLong_AsUnsignedLong(obj.o)); + } + else + { + ok = PyInt_Check(obj.o); + if ( ok ) + *out = uint32(PyInt_AsLong(obj.o)); + } + return ok; + } + //-------------------------------------------------------------------------- // Convert a tuple (String, [color, [bgcolor]]) to a simpleline_t static bool py_to_simpleline(PyObject *py, simpleline_t &sl) @@ -562,13 +579,11 @@ private: return false; sl.line = PyString_AsString(py_val); - - if ( (sz > 1) && (py_val = PyTuple_GetItem(py, 1)) && PyLong_Check(py_val) ) - sl.color = color_t(PyLong_AsUnsignedLong(py_val)); - - if ( (sz > 2) && (py_val = PyTuple_GetItem(py, 2)) && PyLong_Check(py_val) ) - sl.bgcolor = PyLong_AsUnsignedLong(py_val); - + uint32 col; + if ( sz > 1 && get_color(&col, borref_t(PyTuple_GetItem(py, 1))) ) + sl.color = color_t(col); + if ( sz > 2 && get_color(&col, borref_t(PyTuple_GetItem(py, 2))) ) + sl.bgcolor = bgcolor_t(col); return true; } diff --git a/pywraps/py_ua.hpp b/pywraps/py_ua.hpp index 566fa3e..fefbe04 100644 --- a/pywraps/py_ua.hpp +++ b/pywraps/py_ua.hpp @@ -243,6 +243,12 @@ bool py_construct_macro(bool enable, PyObject *build_macro) return res; } +//------------------------------------------------------------------------- +static int py_get_dtyp_by_size(asize_t size) +{ + return int(get_dtyp_by_size(size)); +} + //------------------------------------------------------------------------- static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i) { @@ -786,6 +792,18 @@ static void op_t_set_specflag4(PyObject *self, PyObject *value) link->specflag4 = (char)PyInt_AsLong(value); } +//------------------------------------------------------------------------- +PyObject *py_get_operand_immvals(ea_t ea, int n) +{ + uvalvec_t storage; + storage.resize(2 * UA_MAXOP); + size_t cnt = get_operand_immvals(ea, n, storage.begin()); + 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]))); + return result; +} + // #endif diff --git a/swig/bytes.i b/swig/bytes.i index 1fdd7a6..76a11c4 100644 --- a/swig/bytes.i +++ b/swig/bytes.i @@ -46,6 +46,7 @@ %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 get_hex_string; @@ -53,6 +54,16 @@ // TODO: This could be fixed (if needed) %ignore set_dbgmem_source; +%typemap(argout) opinfo_t *buf { + if ( result != NULL ) + { + // kludge: discard newly-constructed object; return input + Py_XDECREF($result); + $result = $input; + Py_INCREF($result); + } +} + %include "bytes.hpp" %clear(void *buf, ssize_t size); @@ -71,6 +82,7 @@ %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; %{ diff --git a/swig/ua.i b/swig/ua.i index c585e0d..fbc30c6 100644 --- a/swig/ua.i +++ b/swig/ua.i @@ -24,12 +24,15 @@ %ignore get_spoiled_reg; %ignore decode_preceding_insn; %ignore term_uaterm_ua; +%ignore get_operand_immvals; %ignore get_immval; %ignore ua_stkvar; %ignore construct_macro; %rename (construct_macro) py_construct_macro; +%ignore get_dtyp_by_size; +%rename (get_dtyp_by_size) py_get_dtyp_by_size; %include "ua.hpp" @@ -42,6 +45,7 @@ %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; %{ // diff --git a/tools/chkapi.py b/tools/chkapi.py index 0b8da92..4428f85 100644 --- a/tools/chkapi.py +++ b/tools/chkapi.py @@ -172,6 +172,13 @@ def check_cpp(opts): "nullptrcheck" : 5, }, + "_wrap_get_opinfo" : { + "string" : ["Py_XDECREF(resultobj)", "Py_INCREF(resultobj)"], + }, + "_wrap_get_typeinfo" : { + "string" : ["Py_XDECREF(resultobj)", "Py_INCREF(resultobj)"], + }, + # no autoEnabled present "SWIG_init" : { "nostring" : "autoEnabled", diff --git a/tools/deploy/header.i.in b/tools/deploy/header.i.in index 159f354..8d3c090 100644 --- a/tools/deploy/header.i.in +++ b/tools/deploy/header.i.in @@ -661,6 +661,7 @@ typedef long long longlong; %apply qstring *result { qstring *shortcut }; %apply qstring *result { qstring *tooltip }; %apply qstring *result { qstring *out }; +%apply qstring *result { qstring *buf }; %apply int *OUTPUT { int *icon }; %apply int *OUTPUT { action_state_t *state }; %apply bool *OUTPUT { bool *checkable }; diff --git a/tools/genhooks/genhooks.py b/tools/genhooks/genhooks.py index 854aafb..61da495 100644 --- a/tools/genhooks/genhooks.py +++ b/tools/genhooks/genhooks.py @@ -272,12 +272,15 @@ def gen_notifications(out): qnotused = False clinked = None cast_needed = False + deref = None if "params" in recipe_data: all_pdata = recipe_data["params"] if pname in all_pdata: pdata = all_pdata[pname] if "convertor" in pdata: param_convertor = pdata["convertor"] + if "deref" in pdata: + deref = pdata["deref"] if "suppress_for_call" in pdata: suppress_for_call = pdata["suppress_for_call"] if "qnotused" in pdata: @@ -288,6 +291,11 @@ def gen_notifications(out): cast_needed = pdata["cast_needed"] pass_expr = pname + if deref: + pass_expr = "%s != NULL ? *(%s) : (%s)" % ( + pname, + pname, + deref["ifNULL"]) if clinked: out.write(" ref_t clinked_%s = create_linked_class_instance(%s, %s, %s);\n" % (pname, clinked["module_define"], clinked["class_define"], pname)) diff --git a/tools/genhooks/recipe_idphooks.py b/tools/genhooks/recipe_idphooks.py index 24e4b01..df4381d 100644 --- a/tools/genhooks/recipe_idphooks.py +++ b/tools/genhooks/recipe_idphooks.py @@ -108,4 +108,26 @@ recipe = { "convertor_pass_args" : True, } }, + "delay_slot_insn" : { + "params" : { + "ea" : { + "type" : "ea_t", + "deref" : {"ifNULL" : "BADADDR"}, + }, + "bexec" : { + "type" : "bool", + "deref" : {"ifNULL" : "false"}, + }, + "fexec" : { + "type" : "bool", + "deref" : {"ifNULL" : "false"}, + }, + }, + "return" : { + "type" : "PyObject *", + "retexpr" : "Py_RETURN_NONE", + "convertor" : "IDP_Hooks::handle_delay_slot_insn_output", + "convertor_pass_args" : True, + }, + }, } diff --git a/tools/patch_codegen.py b/tools/patch_codegen.py new file mode 100644 index 0000000..1a726d4 --- /dev/null +++ b/tools/patch_codegen.py @@ -0,0 +1,49 @@ + +import os, re + +try: + from argparse import ArgumentParser +except: + print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'" + raise + +parser = ArgumentParser(description='Patch 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") +args = parser.parse_args() + + +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_]*)\(.*") + lines = [] + with open(args.file, "rb") as f: + STAT_UNKNOWN = {} + STAT_IN_FUNCTION = {} + stat = STAT_UNKNOWN + func_patches = [] + for line in f: + m = regex.match(line) + if m: + stat = STAT_IN_FUNCTION + fname = m.group(1) + 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) + else: + raise Exception("Unknown patch kind: %s" % patch_kind) + lines.append(line) + + tmp_file = "%s.tmp" % args.file + with open(tmp_file, "w") as f: + f.writelines(lines) + os.unlink(args.file) + os.rename(tmp_file, args.file) diff --git a/tools/patch_codegen/hexrays.py b/tools/patch_codegen/hexrays.py new file mode 100644 index 0000000..0b91764 --- /dev/null +++ b/tools/patch_codegen/hexrays.py @@ -0,0 +1,8 @@ +{ + "vcreate_helper" : [ + ("va_copy", ("arg4", "temp")), + ], + "vcall_helper" : [ + ("va_copy", ("arg4", "temp")), + ], +} diff --git a/tools/patch_codegen/kernwin.py b/tools/patch_codegen/kernwin.py new file mode 100644 index 0000000..d2f095e --- /dev/null +++ b/tools/patch_codegen/kernwin.py @@ -0,0 +1,11 @@ +{ + "askfile2_cv" : [ + ("va_copy", ("arg5", "temp")), + ], + "vaskqstr" : [ + ("va_copy", ("arg3", "temp")), + ], + "vumsg" : [ + ("va_copy", ("arg2", "temp")), + ], +} diff --git a/tools/patch_codegen/pro.py b/tools/patch_codegen/pro.py new file mode 100644 index 0000000..24bcf52 --- /dev/null +++ b/tools/patch_codegen/pro.py @@ -0,0 +1,5 @@ +{ + "vinterr" : [ + ("va_copy", ("arg4", "temp")), + ] +}