diff --git a/AUTHORS.txt b/AUTHORS.txt index e7bc0b6..015a165 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -8,11 +8,11 @@ The IDAPython Team: * Hex-Rays - http://www.hex-rays.com/ - Hex-Rays joined the IDAPython project in September 2009 and started contributing. - It is primarily maintained by Arnaud Diederen. + It is primarily maintained, updated and improved by Arnaud Diederen of Hex-Rays. -* Elias Bachaalany - http://0xeb.wordpress.com/ - - Current project owner and maintainer +* Elias Bachaalany - elias.bachaalany@gmail.com + Maintains IDAPython online source code repository and coordinates patches/updates/contributions from Hex-Rays and 3rd party contributors + * Ero Carrera - http://dkbza.org/ diff --git a/build.py b/build.py index 4086611..f817d22 100644 --- a/build.py +++ b/build.py @@ -24,7 +24,7 @@ from distutils import sysconfig VERBOSE = True IDA_MAJOR_VERSION = 6 -IDA_MINOR_VERSION = 5 +IDA_MINOR_VERSION = 6 if 'IDA' in os.environ: IDA_SDK = os.environ['IDA'] @@ -35,7 +35,7 @@ else: # IDAPython version VERSION_MAJOR = 1 -VERSION_MINOR = 6 +VERSION_MINOR = 7 VERSION_PATCH = 0 # Determine Python version @@ -339,13 +339,14 @@ def build_plugin( idasdkdir, plugin_name, options): + """ Build the plugin from the SWIG wrapper and plugin main source """ + + global SWIG_OPTIONS # Get the arguments ea64 = options[S_EA64] with_hexrays = options[S_WITH_HEXRAYS] - global SWIG_OPTIONS - """ Build the plugin from the SWIG wrapper and plugin main source """ # Path to the IDA SDK headers ida_include_directory = os.path.join(idasdkdir, "include") diff --git a/examples/ex_graph.py b/examples/ex_graph.py index 13d8b3b..a53298d 100644 --- a/examples/ex_graph.py +++ b/examples/ex_graph.py @@ -1,5 +1,6 @@ # ----------------------------------------------------------------------- -# This is an example illustrating how to use the graphing functionality in Python +# This is an example illustrating how to use the user graphing functionality +# in Python # (c) Hex-Rays # from idaapi import GraphViewer diff --git a/examples/vds1.py b/examples/vds1.py index a1fb772..b811c27 100644 --- a/examples/vds1.py +++ b/examples/vds1.py @@ -1,27 +1,26 @@ -import idaapi - -def main(): - if not idaapi.init_hexrays_plugin(): - return False - - print "Hex-rays version %s has been detected" % idaapi.get_hexrays_version() - - f = idaapi.get_func(idaapi.get_screen_ea()); - if f is None: - print "Please position the cursor within a function" - return True - - cfunc = idaapi.decompile(f); - if cfunc is None: - print "Failed to decompile!" - return True - - sv = cfunc.get_pseudocode(); - for i in xrange(0, sv.size()): - line = idaapi.tag_remove(str(sv[i])); - print line - - return True - -if main(): - idaapi.term_hexrays_plugin(); +import idaapi + +def main(): + if not idaapi.init_hexrays_plugin(): + return False + + print "Hex-rays version %s has been detected" % idaapi.get_hexrays_version() + + f = idaapi.get_func(idaapi.get_screen_ea()); + if f is None: + print "Please position the cursor within a function" + return True + + cfunc = idaapi.decompile(f); + if cfunc is None: + print "Failed to decompile!" + return True + + sv = cfunc.get_pseudocode(); + for sline in sv: + print idaapi.tag_remove(sline.line); + + return True + +if main(): + idaapi.term_hexrays_plugin(); diff --git a/examples/vds3.py b/examples/vds3.py index 2bf89f7..faf0673 100644 --- a/examples/vds3.py +++ b/examples/vds3.py @@ -1,196 +1,196 @@ -""" Invert the then and else blocks of a cif_t. - -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' - -class hexrays_callback_info(object): - - def __init__(self): - self.vu = None - - self.node = idaapi.netnode() - if not self.node.create(NETNODE_NAME): - # node exists - self.load() - else: - self.stored = [] - - return - - def load(self): - - self.stored = [] - - try: - data = self.node.getblob(0, 'I') - if data: - self.stored = eval(data) - print 'Invert-if: Loaded %s' % (repr(self.stored), ) - except: - print 'Failed to load invert-if locations' - traceback.print_exc() - return - - return - - def save(self): - - try: - self.node.setblob(repr(self.stored), 0, 'I') - except: - print 'Failed to save invert-if locations' - traceback.print_exc() - return - - return - - def invert_if(self, cfunc, insn): - - if insn.opname != 'if': - return False - - cif = insn.details - - if not cif.ithen or not cif.ielse: - return False - - 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) - - return True - - def add_location(self, ea): - if ea in self.stored: - self.stored.remove(ea) - else: - self.stored.append(ea) - self.save() - return - - def find_if_statement(self, vu): - - vu.get_current_item(idaapi.USE_KEYBOARD) - item = vu.item - - if item.is_citem() and item.it.op == idaapi.cit_if and item.it.to_specific_type.cif.ielse is not None: - return item.it.to_specific_type - - if vu.tail.citype == idaapi.VDI_TAIL and vu.tail.loc.itp == idaapi.ITP_ELSE: - # for tail marks, we know only the corresponding ea, - # not the pointer to if-statement - # find it by walking the whole ctree - class if_finder_t(idaapi.ctree_visitor_t): - def __init__(self, ea): - idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS) - - self.ea = ea - self.found = None - return - - def visit_insn(self, i): - if i.op == idaapi.cit_if and i.ea == self.ea: - self.found = i - return 1 # stop enumeration - return 0 - - iff = if_finder_t(vu.tail.loc.ea) - if iff.apply_to(vu.cfunc.body, None): - return iff.found - - return - - def invert_if_event(self, vu): - - cfunc = vu.cfunc.__deref__() - - i = self.find_if_statement(vu) - if not i: - return False - - if self.invert_if(cfunc, i): - vu.refresh_ctext() - - self.add_location(i.ea) - - return True - - def restore(self, cfunc): - - class visitor(idaapi.ctree_visitor_t): - - def __init__(self, inverter, cfunc): - idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS) - self.inverter = inverter - self.cfunc = cfunc - return - - def visit_insn(self, i): - try: - if i.op == idaapi.cit_if and i.ea in self.inverter.stored: - self.inverter.invert_if(self.cfunc, i) - except: - traceback.print_exc() - return 0 # continue enumeration - - visitor(self, cfunc).apply_to(cfunc.body, None) - - return - - def menu_callback(self): - try: - self.invert_if_event(self.vu) - except: - traceback.print_exc() - return 0 - - def event_callback(self, event, *args): - - try: - if event == idaapi.hxe_keyboard: - vu, keycode, shift = args - - if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("I") and shift == 0: - if self.invert_if_event(vu): - return 1 - - elif event == idaapi.hxe_right_click: - self.vu, = args - idaapi.add_custom_viewer_popup_item(self.vu.ct, "Invert then/else", "I", self.menu_callback) - - elif event == idaapi.hxe_maturity: - cfunc, maturity = args - - if maturity == idaapi.CMAT_FINAL: - self.restore(cfunc) - except: - traceback.print_exc() - - return 0 - -if idaapi.init_hexrays_plugin(): - i = hexrays_callback_info() - idaapi.install_hexrays_callback(i.event_callback) -else: - print 'invert-if: hexrays is not available.' - +""" Invert the then and else blocks of a cif_t. + +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' + +class hexrays_callback_info(object): + + def __init__(self): + self.vu = None + + self.node = idaapi.netnode() + if not self.node.create(NETNODE_NAME): + # node exists + self.load() + else: + self.stored = [] + + return + + def load(self): + + self.stored = [] + + try: + data = self.node.getblob(0, 'I') + if data: + self.stored = eval(data) + print 'Invert-if: Loaded %s' % (repr(self.stored), ) + except: + print 'Failed to load invert-if locations' + traceback.print_exc() + return + + return + + def save(self): + + try: + self.node.setblob(repr(self.stored), 0, 'I') + except: + print 'Failed to save invert-if locations' + traceback.print_exc() + return + + return + + def invert_if(self, cfunc, insn): + + if insn.opname != 'if': + return False + + cif = insn.details + + if not cif.ithen or not cif.ielse: + return False + + 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) + + return True + + def add_location(self, ea): + if ea in self.stored: + self.stored.remove(ea) + else: + self.stored.append(ea) + self.save() + return + + def find_if_statement(self, vu): + + vu.get_current_item(idaapi.USE_KEYBOARD) + item = vu.item + + if item.is_citem() and item.it.op == idaapi.cit_if and item.it.to_specific_type.cif.ielse is not None: + return item.it.to_specific_type + + if vu.tail.citype == idaapi.VDI_TAIL and vu.tail.loc.itp == idaapi.ITP_ELSE: + # for tail marks, we know only the corresponding ea, + # not the pointer to if-statement + # find it by walking the whole ctree + class if_finder_t(idaapi.ctree_visitor_t): + def __init__(self, ea): + idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS) + + self.ea = ea + self.found = None + return + + def visit_insn(self, i): + if i.op == idaapi.cit_if and i.ea == self.ea: + self.found = i + return 1 # stop enumeration + return 0 + + iff = if_finder_t(vu.tail.loc.ea) + if iff.apply_to(vu.cfunc.body, None): + return iff.found + + return + + def invert_if_event(self, vu): + + cfunc = vu.cfunc.__deref__() + + i = self.find_if_statement(vu) + if not i: + return False + + if self.invert_if(cfunc, i): + vu.refresh_ctext() + + self.add_location(i.ea) + + return True + + def restore(self, cfunc): + + class visitor(idaapi.ctree_visitor_t): + + def __init__(self, inverter, cfunc): + idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS) + self.inverter = inverter + self.cfunc = cfunc + return + + def visit_insn(self, i): + try: + if i.op == idaapi.cit_if and i.ea in self.inverter.stored: + self.inverter.invert_if(self.cfunc, i) + except: + traceback.print_exc() + return 0 # continue enumeration + + visitor(self, cfunc).apply_to(cfunc.body, None) + + return + + def menu_callback(self): + try: + self.invert_if_event(self.vu) + except: + traceback.print_exc() + return 0 + + def event_callback(self, event, *args): + + try: + if event == idaapi.hxe_keyboard: + vu, keycode, shift = args + + if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("I") and shift == 0: + if self.invert_if_event(vu): + return 1 + + elif event == idaapi.hxe_right_click: + self.vu, = args + idaapi.add_custom_viewer_popup_item(self.vu.ct, "Invert then/else", "I", self.menu_callback) + + elif event == idaapi.hxe_maturity: + cfunc, maturity = args + + if maturity == idaapi.CMAT_FINAL: + self.restore(cfunc) + except: + traceback.print_exc() + + return 0 + +if idaapi.init_hexrays_plugin(): + i = hexrays_callback_info() + idaapi.install_hexrays_callback(i.event_callback) +else: + print 'invert-if: hexrays is not available.' + diff --git a/examples/vds4.py b/examples/vds4.py index 27c11a9..5c8e02d 100644 --- a/examples/vds4.py +++ b/examples/vds4.py @@ -1,123 +1,123 @@ -""" Print user-defined details to the output window. - -Author: EiNSTeiN_ - -This is a rewrite in Python of the vds4 example that comes with hexrays sdk. -""" - -import idautils -import idaapi -import idc - -import traceback - -def run(): - - cfunc = idaapi.decompile(idaapi.get_screen_ea()) - if not cfunc: - print 'Please move the cursor into a function.' - return - - entry_ea = cfunc.entry_ea - print "Dump of user-defined information for function at %x" % (entry_ea, ) - - # Display user defined labels. - labels = idaapi.restore_user_labels(entry_ea); - if labels is not None: - print "------- %u user defined labels" % (len(labels), ) - for org_label, name in labels.iteritems(): - print "Label %d: %s" % (org_label, str(name)) - idaapi.user_labels_free(labels) - - # Display user defined comments - cmts = idaapi.restore_user_cmts(entry_ea); - if cmts is not None: - print "------- %u user defined comments" % (len(cmts), ) - for tl, cmt in cmts.iteritems(): - print "Comment at %x, preciser %x:\n%s\n" % (tl.ea, tl.itp, str(cmt)) - idaapi.user_cmts_free(cmts) - - # Display user defined citem iflags - iflags = idaapi.restore_user_iflags(entry_ea) - if iflags is not None: - print "------- %u user defined citem iflags" % (len(iflags), ) - for cl, t in iflags.iteritems(): - print "%a(%d): %08X%s" % (cl.ea, cl.op, f, " CIT_COLLAPSED" if f & CIT_COLLAPSED else "") - idaapi.user_iflags_free(iflags) - - # Display user defined number formats - numforms = idaapi.restore_user_numforms(entry_ea) - if numforms is not None: - print "------- %u user defined number formats" % (len(numforms), ) - for ol, nf in numforms.iteritems(): - - print "Number format at %a, operand %d: %s" % (ol.ea, ol.opnum, "negated " if (nf.props & NF_NEGATE) != 0 else "") - - if nf.isEnum(): - print "enum %s (serial %d)" % (str(nf.type_name), nf.serial) - - elif nf.isChar(): - print "char" - - elif nf.isStroff(): - print "struct offset %s" % (str(nf.type_name), ) - - else: - print "number base=%d" % (idaapi.getRadix(nf.flags, ol.opnum), ) - - idaapi.user_numforms_free(numforms) - - # Display user-defined local variable information - # First defined the visitor class - class dump_lvar_info_t(idaapi.user_lvar_visitor_t): - - def __init__(self): - idaapi.user_lvar_visitor_t.__init__(self) - self.displayed_header = False - return - - def get_info_qty_for_saving(self): - return 0 - - def get_info_for_saving(self, lv): - return False - - def handle_retrieved_info(self, lv): - - try: - if not self.displayed_header: - self.displayed_header = True; - print "------- User defined local variable information" - - print "Lvar defined at %x" % (lv.ll.defea, ) - - if len(str(lv.name)): - print " Name: %s" % (str(lv.name), ) - - if len(str(lv.type)): - #~ print_type_to_one_line(buf, sizeof(buf), idati, .c_str()); - print " Type: %s" % (str(lv.type), ) - - if len(str(lv.cmt)): - print " Comment: %s" % (str(lv.cmt), ) - except: - traceback.print_exc() - return 0 - - def handle_retrieved_mapping(self, lm): - return 0 - - def get_info_mapping_for_saving(self): - return None - - # Now iterate over all user definitions - dli = dump_lvar_info_t(); - idaapi.restore_user_lvar_settings(entry_ea, dli) - - return - - -if idaapi.init_hexrays_plugin(): - run() -else: - print 'dump user info: hexrays is not available.' +""" Print user-defined details to the output window. + +Author: EiNSTeiN_ + +This is a rewrite in Python of the vds4 example that comes with hexrays sdk. +""" + +import idautils +import idaapi +import idc + +import traceback + +def run(): + + cfunc = idaapi.decompile(idaapi.get_screen_ea()) + if not cfunc: + print 'Please move the cursor into a function.' + return + + entry_ea = cfunc.entry_ea + print "Dump of user-defined information for function at %x" % (entry_ea, ) + + # Display user defined labels. + labels = idaapi.restore_user_labels(entry_ea); + if labels is not None: + print "------- %u user defined labels" % (len(labels), ) + for org_label, name in labels.iteritems(): + print "Label %d: %s" % (org_label, str(name)) + idaapi.user_labels_free(labels) + + # Display user defined comments + cmts = idaapi.restore_user_cmts(entry_ea); + if cmts is not None: + print "------- %u user defined comments" % (len(cmts), ) + for tl, cmt in cmts.iteritems(): + print "Comment at %x, preciser %x:\n%s\n" % (tl.ea, tl.itp, str(cmt)) + idaapi.user_cmts_free(cmts) + + # Display user defined citem iflags + iflags = idaapi.restore_user_iflags(entry_ea) + if iflags is not None: + print "------- %u user defined citem iflags" % (len(iflags), ) + for cl, t in iflags.iteritems(): + print "%a(%d): %08X%s" % (cl.ea, cl.op, f, " CIT_COLLAPSED" if f & CIT_COLLAPSED else "") + idaapi.user_iflags_free(iflags) + + # Display user defined number formats + numforms = idaapi.restore_user_numforms(entry_ea) + if numforms is not None: + print "------- %u user defined number formats" % (len(numforms), ) + for ol, nf in numforms.iteritems(): + + print "Number format at %a, operand %d: %s" % (ol.ea, ol.opnum, "negated " if (nf.props & NF_NEGATE) != 0 else "") + + if nf.isEnum(): + print "enum %s (serial %d)" % (str(nf.type_name), nf.serial) + + elif nf.isChar(): + print "char" + + elif nf.isStroff(): + print "struct offset %s" % (str(nf.type_name), ) + + else: + print "number base=%d" % (idaapi.getRadix(nf.flags, ol.opnum), ) + + idaapi.user_numforms_free(numforms) + + # Display user-defined local variable information + # First defined the visitor class + class dump_lvar_info_t(idaapi.user_lvar_visitor_t): + + def __init__(self): + idaapi.user_lvar_visitor_t.__init__(self) + self.displayed_header = False + return + + def get_info_qty_for_saving(self): + return 0 + + def get_info_for_saving(self, lv): + return False + + def handle_retrieved_info(self, lv): + + try: + if not self.displayed_header: + self.displayed_header = True; + print "------- User defined local variable information" + + print "Lvar defined at %x" % (lv.ll.defea, ) + + if len(str(lv.name)): + print " Name: %s" % (str(lv.name), ) + + if len(str(lv.type)): + #~ print_type_to_one_line(buf, sizeof(buf), idati, .c_str()); + print " Type: %s" % (str(lv.type), ) + + if len(str(lv.cmt)): + print " Comment: %s" % (str(lv.cmt), ) + except: + traceback.print_exc() + return 0 + + def handle_retrieved_mapping(self, lm): + return 0 + + def get_info_mapping_for_saving(self): + return None + + # Now iterate over all user definitions + dli = dump_lvar_info_t(); + idaapi.restore_user_lvar_settings(entry_ea, dli) + + return + + +if idaapi.init_hexrays_plugin(): + run() +else: + print 'dump user info: hexrays is not available.' diff --git a/examples/vds7.py b/examples/vds7.py index 455ac0b..bb2dd11 100644 --- a/examples/vds7.py +++ b/examples/vds7.py @@ -1,62 +1,62 @@ -""" It demonstrates how to iterate a cblock_t object. - -Author: EiNSTeiN_ - -This is a rewrite in Python of the vds7 example that comes with hexrays sdk. -""" - -import idautils -import idaapi -import idc - -import traceback - -class cblock_visitor_t(idaapi.ctree_visitor_t): - - def __init__(self): - idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST) - return - - def visit_insn(self, ins): - - try: - if ins.op == idaapi.cit_block: - self.dump_block(ins.ea, ins.cblock) - except: - traceback.print_exc() - - return 0 - - def dump_block(self, ea, b): - # iterate over all block instructions - print "dumping block %x" % (ea, ) - for ins in b: - print " %x: insn %s" % (ins.ea, ins.opname) - - return - -class hexrays_callback_info(object): - - def __init__(self): - return - - def event_callback(self, event, *args): - - try: - if event == idaapi.hxe_maturity: - cfunc, maturity = args - - if maturity == idaapi.CMAT_BUILT: - cbv = cblock_visitor_t() - cbv.apply_to(cfunc.body, None) - - except: - traceback.print_exc() - - return 0 - -if idaapi.init_hexrays_plugin(): - i = hexrays_callback_info() - idaapi.install_hexrays_callback(i.event_callback) -else: - print 'cblock visitor: hexrays is not available.' +""" It demonstrates how to iterate a cblock_t object. + +Author: EiNSTeiN_ + +This is a rewrite in Python of the vds7 example that comes with hexrays sdk. +""" + +import idautils +import idaapi +import idc + +import traceback + +class cblock_visitor_t(idaapi.ctree_visitor_t): + + def __init__(self): + idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST) + return + + def visit_insn(self, ins): + + try: + if ins.op == idaapi.cit_block: + self.dump_block(ins.ea, ins.cblock) + except: + traceback.print_exc() + + return 0 + + def dump_block(self, ea, b): + # iterate over all block instructions + print "dumping block %x" % (ea, ) + for ins in b: + print " %x: insn %s" % (ins.ea, ins.opname) + + return + +class hexrays_callback_info(object): + + def __init__(self): + return + + def event_callback(self, event, *args): + + try: + if event == idaapi.hxe_maturity: + cfunc, maturity = args + + if maturity == idaapi.CMAT_BUILT: + cbv = cblock_visitor_t() + cbv.apply_to(cfunc.body, None) + + except: + traceback.print_exc() + + return 0 + +if idaapi.init_hexrays_plugin(): + i = hexrays_callback_info() + idaapi.install_hexrays_callback(i.event_callback) +else: + print 'cblock visitor: hexrays is not available.' diff --git a/examples/vds_xrefs.py b/examples/vds_xrefs.py index cf06e9d..d748add 100644 --- a/examples/vds_xrefs.py +++ b/examples/vds_xrefs.py @@ -1,319 +1,316 @@ -""" Xref plugin for Hexrays Decompiler - -Author: EiNSTeiN_ - -Show decompiler-style Xref when the X key is pressed in the Decompiler window. - -- It supports any global name: functions, strings, integers, etc. -- It supports structure member. - -""" - -import idautils -import idaapi -import idc - -import traceback - -try: - from PyQt4 import QtCore, QtGui - print 'Using PyQt' -except: - print 'PyQt not available' - - try: - from PySide import QtGui, QtCore - print 'Using PySide' - except: - print 'PySide not available' - -XREF_EA = 0 -XREF_STRUC_MEMBER = 1 - -class XrefsForm(idaapi.PluginForm): - - def __init__(self, target): - - idaapi.PluginForm.__init__(self) - - self.target = target - - if type(self.target) == idaapi.cfunc_t: - - self.__type = XREF_EA - self.__ea = self.target.entry_ea - self.__name = 'Xrefs of %x' % (self.__ea, ) - - elif type(self.target) == idaapi.cexpr_t and self.target.opname == 'obj': - - self.__type = XREF_EA - self.__ea = self.target.obj_ea - self.__name = 'Xrefs of %x' % (self.__ea, ) - - elif type(self.target) == idaapi.cexpr_t and self.target.opname in ('memptr', 'memref'): - - self.__type = XREF_STRUC_MEMBER - name = self.get_struc_name() - self.__name = 'Xrefs of %s' % (name, ) - - else: - raise ValueError('cannot show xrefs for this kind of target') - - return - - def get_struc_name(self): - - x = self.target.operands['x'] - m = self.target.operands['m'] - - xtype = typestring(x.type.u_str()) - xtype.remove_ptr_or_array() - typename = str(xtype) - - sid = idc.GetStrucIdByName(typename) - member = idc.GetMemberName(sid, m) - - return '%s::%s' % (typename, member) - - def OnCreate(self, form): - - # Get parent widget - try: - self.parent = self.FormToPySideWidget(form) - except: - self.parent = self.FormToPyQtWidget(form) - - self.populate_form() - - return - - def Show(self): - idaapi.PluginForm.Show(self, self.__name) - return - - def populate_form(self): - # Create layout - layout = QtGui.QVBoxLayout() - - layout.addWidget(QtGui.QLabel(self.__name)) - self.table = QtGui.QTableWidget() - layout.addWidget(self.table) - - self.table.setColumnCount(3) - self.table.setHorizontalHeaderItem(0, QtGui.QTableWidgetItem("Address")) - self.table.setHorizontalHeaderItem(1, QtGui.QTableWidgetItem("Function")) - self.table.setHorizontalHeaderItem(2, QtGui.QTableWidgetItem("Line")) - - self.table.setColumnWidth(0, 80) - self.table.setColumnWidth(1, 150) - self.table.setColumnWidth(2, 450) - - self.table.cellDoubleClicked.connect(self.double_clicked) - - #~ self.table.setSelectionMode(QtGui.QAbstractItemView.NoSelection) - self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows ) - self.parent.setLayout(layout) - - self.populate_table() - - return - - def double_clicked(self, row, column): - - ea = self.functions[row] - idaapi.open_pseudocode(ea, True) - - return - - def get_decompiled_line(self, cfunc, ea): - - print repr(ea) - if ea not in cfunc.eamap: - print 'strange, %x is not in %x eamap' % (ea, cfunc.entry_ea) - return - - insnvec = cfunc.eamap[ea] - - lines = [] - for stmt in insnvec: - - qs = idaapi.qstring() - qp = idaapi.qstring_printer_t(cfunc.__deref__(), qs, False) - - stmt._print(0, qp) - s = str(qs).split('\n')[0] - - #~ s = idaapi.tag_remove(s) - lines.append(s) - - return '\n'.join(lines) - - def get_items_for_ea(self, ea): - - frm = [x.frm for x in idautils.XrefsTo(self.__ea)] - - items = [] - for ea in frm: - try: - cfunc = idaapi.decompile(ea) - cfunc.refcnt += 1 - - self.functions.append(cfunc.entry_ea) - self.items.append((ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea))) - - except Exception as e: - print 'could not decompile: %s' % (str(e), ) - raise - - return - - def get_items_for_type(self): - - x = self.target.operands['x'] - m = self.target.operands['m'] - - xtype = typestring(x.type.u_str()) - xtype.remove_ptr_or_array() - typename = str(xtype) - - addresses = [] - for ea in idautils.Functions(): - - try: - cfunc = idaapi.decompile(ea) - cfunc.refcnt += 1 - except: - print 'Decompilation of %x failed' % (ea, ) - continue - - str(cfunc) - - for citem in cfunc.treeitems: - citem = citem.to_specific_type - if not (type(citem) == idaapi.cexpr_t and citem.opname in ('memptr', 'memref')): - continue - - _x = citem.operands['x'] - _m = citem.operands['m'] - _xtype = typestring(_x.type.u_str()) - _xtype.remove_ptr_or_array() - _typename = str(_xtype) - - #~ print 'in', hex(cfunc.entry_ea), _typename, _m - - if not (_typename == typename and _m == m): - continue - - parent = citem - while parent: - if type(parent.to_specific_type) == idaapi.cinsn_t: - break - parent = cfunc.body.find_parent_of(parent) - - if not parent: - print 'cannot find parent statement (?!)' - continue - - if parent.ea in addresses: - continue - - if parent.ea == idaapi.BADADDR: - print 'parent.ea is BADADDR' - continue - - addresses.append(parent.ea) - - self.functions.append(cfunc.entry_ea) - self.items.append((parent.ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, int(parent.ea)))) - - - return [] - - def populate_table(self): - - self.functions = [] - self.items = [] - - if self.__type == XREF_EA: - self.get_items_for_ea(self.__ea) - else: - self.get_items_for_type() - - self.table.setRowCount(len(self.items)) - - i = 0 - for item in self.items: - address, func, line = item - item = QtGui.QTableWidgetItem('0x%x' % (address, )) - item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) - self.table.setItem(i, 0, item) - item = QtGui.QTableWidgetItem(func) - item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) - self.table.setItem(i, 1, item) - item = QtGui.QTableWidgetItem(line) - item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) - self.table.setItem(i, 2, item) - - i += 1 - - self.table.resizeRowsToContents() - - return - - def OnClose(self, form): - pass - -class hexrays_callback_info(object): - - def __init__(self): - self.vu = None - return - - def show_xrefs(self, vu): - - vu.get_current_item(idaapi.USE_KEYBOARD) - item = vu.item - - 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 - sel = item.it.to_specific_type - - elif item.citype == idaapi.VDI_FUNC: - # if the function itself is selected, show xrefs to it. - sel = item.f - else: - return False - - form = XrefsForm(sel) - form.Show() - return True - - def menu_callback(self): - self.show_xrefs(self.vu) - return 0 - - def event_callback(self, event, *args): - - try: - if event == idaapi.hxe_keyboard: - vu, keycode, shift = args - - if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("X") and shift == 0: - if self.show_xrefs(vu): - return 1 - - elif event == idaapi.hxe_right_click: - self.vu = args[0] - idaapi.add_custom_viewer_popup_item(self.vu.ct, "Xrefs", "X", self.menu_callback) - - except: - traceback.print_exc() - - return 0 - -if idaapi.init_hexrays_plugin(): - i = hexrays_callback_info() - idaapi.install_hexrays_callback(i.event_callback) -else: - print 'invert-if: hexrays is not available.' +""" Xref plugin for Hexrays Decompiler + +Author: EiNSTeiN_ + +Show decompiler-style Xref when the X key is pressed in the Decompiler window. + +- It supports any global name: functions, strings, integers, etc. +- It supports structure member. + +""" + +import idautils +import idaapi +import idc + +import traceback + +try: + from PyQt4 import QtCore, QtGui + print 'Using PyQt' +except: + print 'PyQt not available' + + try: + from PySide import QtGui, QtCore + print 'Using PySide' + except: + print 'PySide not available' + +XREF_EA = 0 +XREF_STRUC_MEMBER = 1 + +class XrefsForm(idaapi.PluginForm): + + def __init__(self, target): + + idaapi.PluginForm.__init__(self) + + self.target = target + + if type(self.target) == idaapi.cfunc_t: + + self.__type = XREF_EA + self.__ea = self.target.entry_ea + self.__name = 'Xrefs of %x' % (self.__ea, ) + + elif type(self.target) == idaapi.cexpr_t and self.target.opname == 'obj': + + self.__type = XREF_EA + self.__ea = self.target.obj_ea + self.__name = 'Xrefs of %x' % (self.__ea, ) + + elif type(self.target) == idaapi.cexpr_t and self.target.opname in ('memptr', 'memref'): + + self.__type = XREF_STRUC_MEMBER + name = self.get_struc_name() + self.__name = 'Xrefs of %s' % (name, ) + + else: + raise ValueError('cannot show xrefs for this kind of target') + + return + + def get_struc_name(self): + + x = self.target.operands['x'] + m = self.target.operands['m'] + + xtype = x.type + xtype.remove_ptr_or_array() + typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') + + sid = idc.GetStrucIdByName(typename) + member = idc.GetMemberName(sid, m) + + return '%s::%s' % (typename, member) + + def OnCreate(self, form): + + # Get parent widget + try: + self.parent = self.FormToPySideWidget(form) + except: + self.parent = self.FormToPyQtWidget(form) + + self.populate_form() + + return + + def Show(self): + idaapi.PluginForm.Show(self, self.__name) + return + + def populate_form(self): + # Create layout + layout = QtGui.QVBoxLayout() + + layout.addWidget(QtGui.QLabel(self.__name)) + self.table = QtGui.QTableWidget() + layout.addWidget(self.table) + + self.table.setColumnCount(3) + self.table.setHorizontalHeaderItem(0, QtGui.QTableWidgetItem("Address")) + self.table.setHorizontalHeaderItem(1, QtGui.QTableWidgetItem("Function")) + self.table.setHorizontalHeaderItem(2, QtGui.QTableWidgetItem("Line")) + + self.table.setColumnWidth(0, 80) + self.table.setColumnWidth(1, 150) + self.table.setColumnWidth(2, 450) + + self.table.cellDoubleClicked.connect(self.double_clicked) + + #~ self.table.setSelectionMode(QtGui.QAbstractItemView.NoSelection) + self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows ) + self.parent.setLayout(layout) + + self.populate_table() + + return + + def double_clicked(self, row, column): + + ea = self.functions[row] + idaapi.open_pseudocode(ea, True) + + return + + def get_decompiled_line(self, cfunc, ea): + + print repr(ea) + if ea not in cfunc.eamap: + print 'strange, %x is not in %x eamap' % (ea, cfunc.entry_ea) + return + + insnvec = cfunc.eamap[ea] + + lines = [] + for stmt in insnvec: + + qp = idaapi.qstring_printer_t(cfunc.__deref__(), False) + + stmt._print(0, qp) + s = qp.s.split('\n')[0] + + #~ s = idaapi.tag_remove(s) + lines.append(s) + + return '\n'.join(lines) + + def get_items_for_ea(self, ea): + + frm = [x.frm for x in idautils.XrefsTo(self.__ea)] + + items = [] + for ea in frm: + try: + 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))) + + except Exception as e: + print 'could not decompile: %s' % (str(e), ) + raise + + return + + def get_items_for_type(self): + + x = self.target.operands['x'] + m = self.target.operands['m'] + + xtype = x.type + xtype.remove_ptr_or_array() + typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') + + addresses = [] + for ea in idautils.Functions(): + + try: + cfunc = idaapi.decompile(ea) + except: + print 'Decompilation of %x failed' % (ea, ) + continue + + str(cfunc) + + for citem in cfunc.treeitems: + citem = citem.to_specific_type + if not (type(citem) == idaapi.cexpr_t and citem.opname in ('memptr', 'memref')): + continue + + _x = citem.operands['x'] + _m = citem.operands['m'] + _xtype = _x.type + _xtype.remove_ptr_or_array() + _typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, _xtype, '', '') + + #~ print 'in', hex(cfunc.entry_ea), _typename, _m + + if not (_typename == typename and _m == m): + continue + + parent = citem + while parent: + if type(parent.to_specific_type) == idaapi.cinsn_t: + break + parent = cfunc.body.find_parent_of(parent) + + if not parent: + print 'cannot find parent statement (?!)' + continue + + if parent.ea in addresses: + continue + + if parent.ea == idaapi.BADADDR: + print 'parent.ea is BADADDR' + continue + + addresses.append(parent.ea) + + self.functions.append(cfunc.entry_ea) + self.items.append((parent.ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, int(parent.ea)))) + + + return [] + + def populate_table(self): + + self.functions = [] + self.items = [] + + if self.__type == XREF_EA: + self.get_items_for_ea(self.__ea) + else: + self.get_items_for_type() + + self.table.setRowCount(len(self.items)) + + i = 0 + for item in self.items: + address, func, line = item + item = QtGui.QTableWidgetItem('0x%x' % (address, )) + item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) + self.table.setItem(i, 0, item) + item = QtGui.QTableWidgetItem(func) + item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) + self.table.setItem(i, 1, item) + item = QtGui.QTableWidgetItem(line) + item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) + self.table.setItem(i, 2, item) + + i += 1 + + self.table.resizeRowsToContents() + + return + + def OnClose(self, form): + pass + +class hexrays_callback_info(object): + + def __init__(self): + self.vu = None + return + + def show_xrefs(self, vu): + + vu.get_current_item(idaapi.USE_KEYBOARD) + item = vu.item + + 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 + sel = item.it.to_specific_type + + elif item.citype == idaapi.VDI_FUNC: + # if the function itself is selected, show xrefs to it. + sel = item.f + else: + return False + + form = XrefsForm(sel) + form.Show() + return True + + def menu_callback(self): + self.show_xrefs(self.vu) + return 0 + + def event_callback(self, event, *args): + + try: + if event == idaapi.hxe_keyboard: + vu, keycode, shift = args + + if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("X") and shift == 0: + if self.show_xrefs(vu): + return 1 + + elif event == idaapi.hxe_right_click: + self.vu = args[0] + idaapi.add_custom_viewer_popup_item(self.vu.ct, "Xrefs", "X", self.menu_callback) + + except: + traceback.print_exc() + + return 0 + +if idaapi.init_hexrays_plugin(): + i = hexrays_callback_info() + idaapi.install_hexrays_callback(i.event_callback) +else: + print 'invert-if: hexrays is not available.' diff --git a/idapython.vcxproj b/idapython.vcxproj index f5e81e4..1c9c107 100644 --- a/idapython.vcxproj +++ b/idapython.vcxproj @@ -96,7 +96,7 @@ Disabled - .\pywraps;..\..\include;\python27\include;%(AdditionalIncludeDirectories) + .\pywraps;..\..\include;c:\python27\include;%(AdditionalIncludeDirectories) WITH_HEXRAYS;NO_OBSOLETE_FUNCS;_DEBUG;__NT__;__IDP__;MAXSTR=1024;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_STANDARD_FILE_FUNCTIONS;VER_MAJOR=1;VER_MINOR=5;VER_PATCH=3;PLUGINFIX;%(PreprocessorDefinitions) true EnableFastChecks diff --git a/python.cpp b/python.cpp index 61a051f..b03e932 100644 --- a/python.cpp +++ b/python.cpp @@ -69,7 +69,8 @@ enum script_run_when //------------------------------------------------------------------------- // Global variables -static bool g_initialized = false; +static bool g_instance_initialized = false; // This instance of the plugin is the one + // that initialized the python interpreter. static int g_run_when = -1; static char g_run_script[QMAXPATH]; static char g_idapython_dir[QMAXPATH]; @@ -133,7 +134,8 @@ static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg) if ( wasBreak() ) { // User pressed Cancel in the waitbox; send KeyboardInterrupt exception - PyErr_SetInterrupt(); + PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted"); + return -1; } else if ( !box_displayed && ++ninsns > 10 ) { @@ -637,48 +639,6 @@ static bool parse_py_modname( return p != NULL; } -//------------------------------------------------------------------------- -// 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) -{ - PYW_GIL_GET; - PyObject *globals = GetMainGlobals(); - - PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "", Py_eval_input); - if ( code == NULL ) - { - handle_python_error(errbuf, errbufsize); - return false; - } - - // Set the desired function name - Py_XDECREF(code->co_name); - code->co_name = PyString_FromString(name); - - // Create a function out of code - PyObject *func = PyFunction_New((PyObject *)code, globals); - - if ( func == NULL ) - { -ERR: - handle_python_error(errbuf, errbufsize); - Py_XDECREF(code); - return false; - } - - int err = PyDict_SetItemString(globals, name, func); - Py_XDECREF(func); - if ( err ) - goto ERR; - - return true; -} - //------------------------------------------------------------------------- // Run callback for Python external language evaluator bool idaapi IDAPython_extlang_run( @@ -743,6 +703,68 @@ bool idaapi IDAPython_extlang_run( return ok; } +//------------------------------------------------------------------------- +// 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) +{ + PYW_GIL_GET; + PyObject *globals = GetMainGlobals(); + bool is_func = 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); + qstring expr_copy = expr; + expr_copy.replace("\n", "\n "); + qstring qexpr; + qexpr.sprnt("def %s():\n %s", name, expr_copy.c_str()); + code = (PyCodeObject *)Py_CompileString(qexpr.c_str(), "", Py_file_input); + if ( code == NULL ) + { + handle_python_error(errbuf, errbufsize); + return false; + } + is_func = true; + } + + // Set the desired function name + Py_XDECREF(code->co_name); + code->co_name = PyString_FromString(name); + + // Create a function out of code + PyObject *func = PyFunction_New((PyObject *)code, globals); + + if ( func == NULL ) + { +ERR: + handle_python_error(errbuf, errbufsize); + Py_XDECREF(code); + return false; + } + + int err = PyDict_SetItemString(globals, name, func); + Py_XDECREF(func); + + if ( err ) + goto ERR; + + if ( is_func ) + { + const idc_value_t args; + idc_value_t result; + return IDAPython_extlang_run(name, 0, &args, &result, errbuf, errbufsize); + } + return true; +} + //------------------------------------------------------------------------- // Compile callback for Python external language evaluator bool idaapi IDAPython_extlang_compile_file( @@ -1273,8 +1295,11 @@ void convert_idc_args() } //------------------------------------------------------------------------ -static int idaapi script_runner_cb(void *, int code, va_list) +static int idaapi on_ui_notification(void *, int code, va_list va) { +#ifdef WITH_HEXRAYS + qnotused(va); +#endif switch ( code ) { case ui_ready_to_run: @@ -1296,12 +1321,66 @@ static int idaapi script_runner_cb(void *, int code, va_list) RunScript(g_run_script); } break; + +#ifdef WITH_HEXRAYS + // FIXME: HACK! THERE SHOULD BE A UI (or IDB?) NOTIFICATION + // WHEN A PLUGIN GETS [UN]LOADED! + // In the meantime, we're checking to see whether the Hex-Rays + // plugin gets loaded/pulled away. + case ui_add_menu_item: + if ( hexdsp == NULL ) + { + const char *name = va_arg(va, char *); + name = va_arg(va, char *); // Drop 'menupath'. Look for 'name'. + if ( streq(name, "Jump to pseudocode") ) + { + init_hexrays_plugin(0); + if ( hexdsp != NULL ) + msg("IDAPython Hex-Rays bindings initialized.\n"); + } + } + break; + + case ui_del_menu_item: + { + if ( hexdsp != NULL ) + { + // Hex-Rays will close. Make sure all the refcounted cfunc_t objects + // are cleared right away. + const char *menupath = va_arg(va, char *); + if ( streq(menupath, "Jump/Jump to pseudocode") ) + { + hexrays_clear_python_cfuncptr_t_references(); + hexdsp = NULL; + } + } + } + break; +#endif + default: break; } return 0; } +//------------------------------------------------------------------------- +//lint -esym(526,til_clear_python_tinfo_t_instances) not defined +extern void til_clear_python_tinfo_t_instances(void); +static int idaapi on_idp_notification(void *, int code, va_list) +{ + switch ( code ) + { + case processor_t::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(); + break; + } + return 0; +} + #ifdef _DEBUG //------------------------------------------------------------------------ // extern int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag); @@ -1379,8 +1458,7 @@ static bool initsite(void) // Initialize the Python environment bool IDAPython_Init(void) { - // Already initialized? - if ( g_initialized ) + if ( Py_IsInitialized() != 0 ) return true; // Form the absolute path to IDA\python folder @@ -1404,7 +1482,7 @@ bool IDAPython_Init(void) #ifdef __MAC__ // We should set python home to the module's path, otherwise it can pick up stray modules from $PATH - NSModule pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); + NSModule pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_InitializeEx")); // Use dylib functions to find out where the framework was loaded from const char *buf = (char *)NSLibraryNameForModule(pythonModule); if ( buf != NULL ) @@ -1443,11 +1521,11 @@ bool IDAPython_Init(void) Py_NoSiteFlag = 1; // Start the interpreter - Py_Initialize(); + Py_InitializeEx(0 /* Don't catch SIGPIPE, SIGXFZ, SIGXFSZ & SIGINT signals */); if ( !Py_IsInitialized() ) { - warning("IDAPython: Py_Initialize() failed"); + warning("IDAPython: Py_InitializeEx() failed"); return false; } @@ -1505,6 +1583,7 @@ bool IDAPython_Init(void) "%s\n" "\n" "Refer to the message window to see the full error log.", tmp); + remove_extlang(&extlang_python); return false; } @@ -1512,6 +1591,7 @@ bool IDAPython_Init(void) if ( !init_pywraps() || !pywraps_nw_init() ) { warning("IDAPython: init_pywraps() failed!"); + remove_extlang(&extlang_python); return false; } @@ -1536,16 +1616,17 @@ bool IDAPython_Init(void) #ifdef _DEBUG hook_to_notification_point(HT_UI, ui_debug_handler_cb, NULL); #endif - hook_to_notification_point(HT_UI, script_runner_cb, NULL); + hook_to_notification_point(HT_UI, on_ui_notification, NULL); + hook_to_notification_point(HT_IDP, on_idp_notification, NULL); // Enable the CLI by default enable_python_cli(true); - g_initialized = true; pywraps_nw_notify(NW_INITIDA_SLOT); PyEval_ReleaseThread(PyThreadState_Get()); + g_instance_initialized = true; return true; } @@ -1553,6 +1634,9 @@ bool IDAPython_Init(void) // Cleaning up Python void IDAPython_Term(void) { + if ( !g_instance_initialized || Py_IsInitialized() == 0 ) + return; + if ( PyGILState_GetThisThreadState() ) { // Note: No 'PYW_GIL_GET' here, as it would try to release @@ -1563,7 +1647,8 @@ void IDAPython_Term(void) PyGILState_Ensure(); } - unhook_from_notification_point(HT_UI, script_runner_cb, NULL); + unhook_from_notification_point(HT_IDP, on_idp_notification, NULL); + unhook_from_notification_point(HT_UI, on_ui_notification, NULL); #ifdef _DEBUG unhook_from_notification_point(HT_UI, ui_debug_handler_cb, NULL); #endif @@ -1588,8 +1673,7 @@ void IDAPython_Term(void) // Shut the interpreter down Py_Finalize(); - - g_initialized = false; + g_instance_initialized = false; } //------------------------------------------------------------------------- diff --git a/python/idc.py b/python/idc.py index 0d82fbc..4fc2345 100644 --- a/python/idc.py +++ b/python/idc.py @@ -481,6 +481,12 @@ def SaveBase(idbname, flags=0): DBFL_BAK = idaapi.DBFL_BAK # for compatiblity with older versions, eventually delete this +def ValidateNames(): + """ + check consistency of IDB name records + @return: number of inconsistent name records + """ + return idaapi.validate_idb_names() def Exit(code): """ @@ -2245,8 +2251,12 @@ def GetOpnd(ea, n): 0 - the first operand 1 - the second operand - @return: the current text representation of operand + @return: the current text representation of operand or "" """ + + if not isCode(idaapi.get_flags_novalue(ea)): + return "" + res = idaapi.ua_outop2(ea, n) if not res: @@ -6931,7 +6941,10 @@ def SetType(ea, newtype): @return: 1-ok, 0-failed. """ if newtype is not '': - pt = ParseType(newtype, 0)[1:] + pt = ParseType(newtype, 0) + if pt is None: + # parsing failed + return None else: pt = None return ApplyType(ea, pt, TINFO_DEFINITE) @@ -8132,6 +8145,13 @@ def CheckTraceFile(filename): """ return idaapi.is_valid_trace_file(filename) +def DiffTraceFile(filename): + """ + Diff current trace buffer against given trace + @param filename: trace file + """ + return idaapi.diff_trace_file(filename) + def ClearTraceFile(filename): """ Clear the current trace buffer diff --git a/pywraps.hpp b/pywraps.hpp index c43b3e1..10a9612 100644 --- a/pywraps.hpp +++ b/pywraps.hpp @@ -58,40 +58,6 @@ #define CIP_OK 1 // Success #define CIP_OK_OPAQUE 2 // Success, but the data pointed to by the PyObject* is an opaque object. -//--------------------------------------------------------------------------- -// Helper macro to create C counterparts of Python py_clinked_object_t object -#ifdef __PYWRAPS__ -#define DECLARE_PY_CLINKED_OBJECT(type) \ - static PyObject *type##_create() \ - { \ - PYW_GIL_CHECK_LOCKED_SCOPE(); \ - return PyCObject_FromVoidPtr(new type(), NULL); \ - } \ - static bool type##_destroy(PyObject *py_obj) \ - { \ - PYW_GIL_CHECK_LOCKED_SCOPE(); \ - if ( !PyCObject_Check(py_obj) ) \ - return false; \ - delete (type *)PyCObject_AsVoidPtr(py_obj); \ - return true; \ - } \ - static type *type##_get_clink(PyObject *self) \ - { \ - PYW_GIL_CHECK_LOCKED_SCOPE(); \ - return (type *)pyobj_get_clink(self); \ - } \ - static PyObject *type##_get_clink_ptr(PyObject *self) \ - { \ - PYW_GIL_CHECK_LOCKED_SCOPE(); \ - return PyLong_FromUnsignedLongLong( \ - (unsigned PY_LONG_LONG)pyobj_get_clink(self)); \ - } -#else -// SWIG does not expand macros and thus those definitions won't be wrapped -// Use DECLARE_PY_CLINKED_OBJECT(type) inside the .i file -#define DECLARE_PY_CLINKED_OBJECT(type) -#endif // __PYWRAPS__ - //--------------------------------------------------------------------------- class gil_lock_t { @@ -367,4 +333,6 @@ bool pywraps_check_autoscripts(char *buf, size_t bufsize); bool init_pywraps(); void deinit_pywraps(); +void hexrays_clear_python_cfuncptr_t_references(void); + #endif diff --git a/pywraps/py_askusingform.hpp b/pywraps/py_askusingform.hpp index 3de1233..88f6b3c 100644 --- a/pywraps/py_askusingform.hpp +++ b/pywraps/py_askusingform.hpp @@ -9,8 +9,6 @@ #define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa; //--------------------------------------------------------------------------- -DECLARE_PY_CLINKED_OBJECT(textctrl_info_t); - static bool textctrl_info_t_assign(PyObject *self, PyObject *other) { textctrl_info_t *lhs = textctrl_info_t_get_clink(self); @@ -145,20 +143,21 @@ static PyObject *formchgcbfa_get_field_value( PYW_GIL_CHECK_LOCKED_SCOPE(); switch ( ft ) { + // dropdown list case 8: { // Readonly? Then return the selected index if ( sz == 1 ) { int sel_idx; - if ( fa->get_field_value(fid, &sel_idx) ) + if ( fa->get_combobox_value(fid, &sel_idx) ) return PyLong_FromLong(sel_idx); } // Not readonly? Then return the qstring else { qstring val; - if ( fa->get_field_value(fid, &val) ) + if ( fa->get_combobox_value(fid, &val) ) return PyString_FromString(val.c_str()); } break; @@ -167,15 +166,15 @@ static PyObject *formchgcbfa_get_field_value( case 7: { textctrl_info_t ti; - if ( fa->get_field_value(fid, &ti) ) + if ( fa->get_text_value(fid, &ti) ) return Py_BuildValue("(sII)", ti.text.c_str(), ti.flags, ti.tabsize); break; } // button - uint32 case 4: { - uint32 val; - if ( fa->get_field_value(fid, &val) ) + uval_t val; + if ( fa->get_unsigned_value(fid, &val) ) return PyLong_FromUnsignedLong(val); break; } @@ -183,7 +182,7 @@ static PyObject *formchgcbfa_get_field_value( case 2: { ushort val; - if ( fa->get_field_value(fid, &val) ) + if ( fa->_get_field_value(fid, &val) ) return PyLong_FromUnsignedLong(val); break; } @@ -191,7 +190,7 @@ static PyObject *formchgcbfa_get_field_value( case 1: { char val[MAXSTR]; - if ( fa->get_field_value(fid, val) ) + if ( fa->get_ascii_value(fid, val, sizeof(val)) ) return PyString_FromString(val); break; } @@ -200,7 +199,7 @@ static PyObject *formchgcbfa_get_field_value( { qstring val; val.resize(sz + 1); - if ( fa->get_field_value(fid, val.begin()) ) + if ( fa->get_ascii_value(fid, val.begin(), val.size()) ) return PyString_FromString(val.begin()); break; } @@ -208,12 +207,11 @@ static PyObject *formchgcbfa_get_field_value( { intvec_t intvec; // Returned as 1-base - if (fa->get_field_value(fid, &intvec)) + if (fa->get_chooser_value(fid, &intvec)) { // Make 0-based for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it) (*it)--; - ref_t l(PyW_IntVecToPyList(intvec)); l.incref(); return l.o; @@ -234,33 +232,38 @@ static PyObject *formchgcbfa_get_field_value( { case 'S': // sel_t { - if ( fa->get_field_value(fid, &u.sel) ) + if ( fa->get_segment_value(fid, &u.sel) ) return Py_BuildValue(PY_FMT64, u.sel); break; } // sval_t case 'n': - case 'N': case 'D': case 'O': case 'Y': case 'H': { - if ( fa->get_field_value(fid, &u.sval) ) + if ( fa->get_signed_value(fid, &u.sval) ) return Py_BuildValue(PY_SFMT64, u.sval); break; } case 'L': // uint64 case 'l': // int64 { - if ( fa->get_field_value(fid, &u.ull) ) - return Py_BuildValue(sz == 'L' ? "K" : "L", u.ull); + if ( fa->_get_field_value(fid, &u.ull) ) + return Py_BuildValue("K", u.ull); break; } + case 'N': case 'M': // uval_t + { + if ( fa->get_unsigned_value(fid, &u.uval) ) + return Py_BuildValue(PY_FMT64, u.uval); + break; + } case '$': // ea_t { - if ( fa->get_field_value(fid, &u.uval) ) + if ( fa->get_ea_value(fid, &u.uval) ) return Py_BuildValue(PY_FMT64, u.uval); break; } @@ -290,13 +293,13 @@ static bool formchgcbfa_set_field_value( if ( PyString_Check(py_val) ) { qstring val(PyString_AsString(py_val)); - return fa->set_field_value(fid, &val); + return fa->set_combobox_value(fid, &val); } // Readonly dropdown list else { int sel_idx = PyLong_AsLong(py_val); - return fa->set_field_value(fid, &sel_idx); + return fa->set_combobox_value(fid, &sel_idx); } break; } @@ -304,24 +307,24 @@ static bool formchgcbfa_set_field_value( case 7: { textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(py_val); - return ti == NULL ? false : fa->set_field_value(fid, ti); + return ti == NULL ? false : fa->set_text_value(fid, ti); } // button - uint32 case 4: { - uint32 val = PyLong_AsUnsignedLong(py_val); - return fa->set_field_value(fid, &val); + uval_t val = PyLong_AsUnsignedLong(py_val); + return fa->set_unsigned_value(fid, &val); } // ushort case 2: { ushort val = PyLong_AsUnsignedLong(py_val) & 0xffff; - return fa->set_field_value(fid, &val); + return fa->_set_field_value(fid, &val); } // strings case 3: case 1: - return fa->set_field_value(fid, PyString_AsString(py_val)); + return fa->set_ascii_value(fid, PyString_AsString(py_val)); // intvec_t case 5: { @@ -334,14 +337,14 @@ static bool formchgcbfa_set_field_value( for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it) (*it)++; - return fa->set_field_value(fid, &intvec); + return fa->set_chooser_value(fid, &intvec); } // Numeric case 6: { uint64 num; if ( PyW_GetNumber(py_val, &num) ) - return fa->set_field_value(fid, &num); + return fa->_set_field_value(fid, &num); } } return false; @@ -351,6 +354,11 @@ static bool formchgcbfa_set_field_value( static size_t py_get_AskUsingForm() { + // Return a pointer to the function. Note that, although + // the C implementation of AskUsingForm_cv will do some + // Qt/txt widgets generation, the Python's ctypes + // implementation through which the call well go will first + // unblock other threads. No need to do it ourselves. return (size_t)AskUsingForm_c; } diff --git a/pywraps/py_askusingform.py b/pywraps/py_askusingform.py index b46e86e..ada80d3 100644 --- a/pywraps/py_askusingform.py +++ b/pywraps/py_askusingform.py @@ -8,7 +8,7 @@ try: from _idaapi import set_script_timeout import idaapi from idaapi import py_clinked_object_t - from idaapi import qstrvec_t + from idaapi import _qstrvec_t stdalone = False except: stdalone = True @@ -50,7 +50,7 @@ try: from py_choose2 import * py_clinked_object_t = idaapi.py_clinked_object_t textctrl_info_t = idaapi.textctrl_info_t - qstrvec_t = idaapi.qstrvec_t + _qstrvec_t = idaapi._qstrvec_t _idaapi.BADADDR = 0xFFFFFFFF _idaapi.MAXSTR = 1024 @@ -776,7 +776,7 @@ class Form(object): Form.Control.free(self) - class DropdownListControl(InputControl, qstrvec_t): + class DropdownListControl(InputControl, _qstrvec_t): """ Dropdown control This control allows manipulating a dropdown control @@ -803,7 +803,7 @@ class Form(object): hlp) # Init the associated qstrvec - qstrvec_t.__init__(self, items) + _qstrvec_t.__init__(self, items) # Remember if readonly or not self.readonly = readonly @@ -814,7 +814,7 @@ class Form(object): val_addr = addressof(self.__selval) else: # Create an strvec with one qstring - self.__selval = qstrvec_t([selval]) + self.__selval = _qstrvec_t([selval]) # Get address of the first element val_addr = self.__selval.addressof(0) diff --git a/pywraps/py_choose2.hpp b/pywraps/py_choose2.hpp index 9fa8846..4e317fb 100644 --- a/pywraps/py_choose2.hpp +++ b/pywraps/py_choose2.hpp @@ -289,8 +289,8 @@ private: self, (char *)S_ON_DELETE_LINE, "i", - lineno - 1)); - return pyres == NULL ? lineno : PyInt_AsLong(pyres.o) + 1; + IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1)); + return pyres == NULL ? 1 : PyInt_AsLong(pyres.o); } int on_refresh(int lineno) diff --git a/pywraps/py_graph.hpp b/pywraps/py_graph.hpp index 73f5c8e..1d30e62 100644 --- a/pywraps/py_graph.hpp +++ b/pywraps/py_graph.hpp @@ -112,7 +112,6 @@ private: static cmdid_map_t cmdid_pyg; - // TForm *form; bool refresh_needed; nodetext_cache_map_t node_cache; @@ -122,6 +121,7 @@ private: // static callback static int idaapi s_callback(void *obj, int code, va_list va) { + QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj)); PYW_GIL_GET; return ((py_graph_t *)obj)->gr_callback(code, va); } @@ -255,13 +255,13 @@ private: } // a group is being created - int on_creating_group(mutable_graph_t *my_g, intset_t *my_nodes) + int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes) { PYW_GIL_CHECK_LOCKED_SCOPE(); printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes); newref_t py_nodes(PyList_New(my_nodes->size())); int i; - intset_t::const_iterator p; + intvec_t::const_iterator p; for ( i = 0, p=my_nodes->begin(); p != my_nodes->end(); ++p, ++i ) PyList_SetItem(py_nodes.o, i, PyInt_FromLong(*p)); newref_t py_result( @@ -331,6 +331,7 @@ private: TForm *form = create_tform(title, &hwnd); if ( hwnd != NULL ) // Created new tform { + lookup_info_t::entry_t &e = lookup_info.new_entry(this); // get a unique graph id netnode id; char grnode[MAXSTR]; @@ -342,8 +343,7 @@ private: viewer_fit_window(pview); bind(self, pview); refresh(); - // Link "form" and "py_graph" - lookup_info.add(form, view, this); + lookup_info.commit(e, form, view); } else { @@ -700,7 +700,7 @@ int py_graph_t::gr_callback(int code, va_list va) case grcode_creating_group: // a group is being created { mutable_graph_t *g = va_arg(va, mutable_graph_t*); - intset_t *nodes = va_arg(va, intset_t*); + intvec_t *nodes = va_arg(va, intvec_t*); ret = on_creating_group(g, nodes); } break; diff --git a/pywraps/py_idaapi.hpp b/pywraps/py_idaapi.hpp index 8b19f72..d7247ce 100644 --- a/pywraps/py_idaapi.hpp +++ b/pywraps/py_idaapi.hpp @@ -726,12 +726,9 @@ def RunPythonStatement(stmt): # */ -/* //--------------------------------------------------------------------------- -// qstrvec_t wrapper +// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py) //--------------------------------------------------------------------------- -DECLARE_PY_CLINKED_OBJECT(qstrvec_t); - static bool qstrvec_t_assign(PyObject *self, PyObject *other) { qstrvec_t *lhs = qstrvec_t_get_clink(self); @@ -833,7 +830,7 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx) sv->erase(sv->begin()+idx); return true; } -*/ + //--------------------------------------------------------------------------- // diff --git a/pywraps/py_idaapi.py b/pywraps/py_idaapi.py index 63a9370..6071ea3 100644 --- a/pywraps/py_idaapi.py +++ b/pywraps/py_idaapi.py @@ -171,6 +171,12 @@ class object_t(object): """Allow access to object attributes by index (like dictionaries)""" return getattr(self, idx) +# ----------------------------------------------------------------------- +def _bounded_getitem_iterator(self): + """Helper function, to be set as __iter__ method for qvector-, or array-based classes.""" + for i in range(len(self)): + yield self[i] + # ----------------------------------------------------------------------- class plugin_t(pyidc_opaque_object_t): """Base class for all scripted plugins.""" @@ -237,72 +243,79 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__): # ----------------------------------------------------------------------- # qstrvec_t clinked object -# class qstrvec_t(py_clinked_object_t): -# """Class representing an qstrvec_t""" +class _qstrvec_t(py_clinked_object_t): + """ + WARNING: It is very unlikely an IDAPython user should ever, ever + have to use this type. It should only be used for IDAPython internals. -# def __init__(self, items=None): -# py_clinked_object_t.__init__(self) -# # Populate the list if needed -# if items: -# self.from_list(items) + For example, in py_askusingform.py, we ctypes-expose to the IDA + kernel & UI a qstrvec instance, in case a DropdownListControl is + constructed. + That's because that's what AskUsingForm expects, and we have no + choice but to make a DropdownListControl hold a qstrvec_t. + This is, afaict, the only situation where a Python + _qstrvec_t is required. + """ -# def _create_clink(self): -# return _idaapi.qstrvec_t_create() + def __init__(self, items=None): + py_clinked_object_t.__init__(self) + # Populate the list if needed + if items: + self.from_list(items) -# def _del_clink(self, lnk): -# return _idaapi.qstrvec_t_destroy(lnk) + def _create_clink(self): + return _idaapi.qstrvec_t_create() -# def _get_clink_ptr(self): -# return _idaapi.qstrvec_t_get_clink_ptr(self) + def _del_clink(self, lnk): + return _idaapi.qstrvec_t_destroy(lnk) -# def assign(self, other): -# """Copies the contents of 'other' to 'self'""" -# return _idaapi.qstrvec_t_assign(self, other) + def _get_clink_ptr(self): + return _idaapi.qstrvec_t_get_clink_ptr(self) -# def __setitem__(self, idx, s): -# """Sets string at the given index""" -# return _idaapi.qstrvec_t_set(self, idx, s) + def assign(self, other): + """Copies the contents of 'other' to 'self'""" + return _idaapi.qstrvec_t_assign(self, other) -# def __getitem__(self, idx): -# """Gets the string at the given index""" -# return _idaapi.qstrvec_t_get(self, idx) + def __setitem__(self, idx, s): + """Sets string at the given index""" + return _idaapi.qstrvec_t_set(self, idx, s) -# def __get_size(self): -# return _idaapi.qstrvec_t_size(self) + def __getitem__(self, idx): + """Gets the string at the given index""" + return _idaapi.qstrvec_t_get(self, idx) -# size = property(__get_size) -# """Returns the count of elements""" + def __get_size(self): + return _idaapi.qstrvec_t_size(self) -# def addressof(self, idx): -# """Returns the address (as number) of the qstring at the given index""" -# return _idaapi.qstrvec_t_addressof(self, idx) + size = property(__get_size) + """Returns the count of elements""" -# def add(self, s): -# """Add a string to the vector""" -# return _idaapi.qstrvec_t_add(self, s) + def addressof(self, idx): + """Returns the address (as number) of the qstring at the given index""" + return _idaapi.qstrvec_t_addressof(self, idx) + def add(self, s): + """Add a string to the vector""" + return _idaapi.qstrvec_t_add(self, s) -# def from_list(self, lst): -# """Populates the vector from a Python string list""" -# return _idaapi.qstrvec_t_from_list(self, lst) + def from_list(self, lst): + """Populates the vector from a Python string list""" + return _idaapi.qstrvec_t_from_list(self, lst) + def clear(self, qclear=False): + """ + Clears all strings from the vector. + @param qclear: Just reset the size but do not actually free the memory + """ + return _idaapi.qstrvec_t_clear(self, qclear) -# def clear(self, qclear=False): -# """ -# Clears all strings from the vector. -# @param qclear: Just reset the size but do not actually free the memory -# """ -# return _idaapi.qstrvec_t_clear(self, qclear) + def insert(self, idx, s): + """Insert a string into the vector""" + return _idaapi.qstrvec_t_insert(self, idx, s) - -# def insert(self, idx, s): -# """Insert a string into the vector""" -# return _idaapi.qstrvec_t_insert(self, idx, s) - - -# def remove(self, idx): -# """Removes a string from the vector""" -# return _idaapi.qstrvec_t_remove(self, idx) + def remove(self, idx): + """Removes a string from the vector""" + return _idaapi.qstrvec_t_remove(self, idx) # ----------------------------------------------------------------------- class PyIdc_cvt_refclass__(pyidc_cvt_helper__): @@ -580,7 +593,13 @@ class __IDAPython_Completion_Util(object): return s -# Instantiate a completion object +# Instantiate an IDAPython command completion object (for use with IDA's CLI bar) IDAPython_Completion = __IDAPython_Completion_Util() +def _listify_types(*classes): + for cls in classes: + cls.__getitem__ = cls.at + cls.__len__ = cls.size + cls.__iter__ = _bounded_getitem_iterator + # diff --git a/pywraps/py_idaview.hpp b/pywraps/py_idaview.hpp index 12f31ea..3449a3e 100644 --- a/pywraps/py_idaview.hpp +++ b/pywraps/py_idaview.hpp @@ -42,7 +42,8 @@ bool py_idaview_t::Bind(PyObject *self) else { py_view = new py_idaview_t(); - lookup_info.add(tform, v, py_view); + lookup_info_t::entry_t &e = lookup_info.new_entry(py_view); + lookup_info.commit(e, tform, v); } // Finally, bind: diff --git a/pywraps/py_idp.hpp b/pywraps/py_idp.hpp index 83f9b81..d322a38 100644 --- a/pywraps/py_idp.hpp +++ b/pywraps/py_idp.hpp @@ -807,6 +807,15 @@ public: } }; +enum areacb_type_t +{ + AREACB_TYPE_UNKNOWN, + AREACB_TYPE_FUNC, + AREACB_TYPE_SEGMENT, + AREACB_TYPE_HIDDEN_AREA, + AREACB_TYPE_SRAREA, +}; + //--------------------------------------------------------------------------- // IDB hooks //--------------------------------------------------------------------------- @@ -827,8 +836,9 @@ public: // Hook functions to override in Python virtual int byte_patched(ea_t /*ea*/) { return 0; }; virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }; - virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("ti_changed hook not supported yet\n"); return 0; }; - virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("op_ti_changed hook not supported yet\n"); return 0; }; + virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; } + virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }; + virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }; virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }; virtual int enum_created(enum_t /*id*/) { return 0; }; virtual int enum_deleted(enum_t /*id*/) { return 0; }; @@ -1365,8 +1375,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va) class IDB_Hooks *proxy = (class IDB_Hooks *)ud; ea_t ea, ea2; bool repeatable_cmt; - /*type_t *type;*/ - /* p_list *fnames; */ + type_t *type; + p_list *fnames; int n; enum_t id; const_t cid; @@ -1382,152 +1392,161 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va) try { switch (notification_code) { - case idb_event::byte_patched: - ea = va_arg(va, ea_t); - return proxy->byte_patched(ea); + case idb_event::byte_patched: + ea = va_arg(va, ea_t); + return proxy->byte_patched(ea); - case idb_event::cmt_changed: - ea = va_arg(va, ea_t); - repeatable_cmt = va_arg(va, int); - return proxy->cmt_changed(ea, repeatable_cmt); -#if 0 - case idb_event::ti_changed: - ea = va_arg(va, ea_t); - type = va_arg(va, type_t *); - fnames = va_arg(va, fnames); - return proxy->ti_changed(ea, type, fnames); + case idb_event::cmt_changed: + ea = va_arg(va, ea_t); + repeatable_cmt = va_arg(va, int); + return proxy->cmt_changed(ea, repeatable_cmt); - case idb_event::op_ti_changed: - ea = va_arg(va, ea_t); - n = va_arg(va, int); - type = va_arg(va, type_t *); - fnames = va_arg(va, fnames); - return proxy->op_ti_changed(ea, n, type, fnames); -#endif - case idb_event::op_type_changed: - ea = va_arg(va, ea_t); - n = va_arg(va, int); - return proxy->op_type_changed(ea, n); + case idb_event::area_cmt_changed: + { + areacb_t *cb = va_arg(va, areacb_t*); + area_t *area = va_arg(va, area_t*); + const char *cmt = va_arg(va, char*); + repeatable_cmt = va_arg(va, int); + return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt); + } - case idb_event::enum_created: - id = va_arg(va, enum_t); - return proxy->enum_created(id); + case idb_event::ti_changed: + ea = va_arg(va, ea_t); + type = va_arg(va, type_t *); + fnames = va_arg(va, p_list *); + return proxy->ti_changed(ea, type, fnames); - case idb_event::enum_deleted: - id = va_arg(va, enum_t); - return proxy->enum_deleted(id); + case idb_event::op_ti_changed: + ea = va_arg(va, ea_t); + n = va_arg(va, int); + type = va_arg(va, type_t *); + fnames = va_arg(va, p_list *); + return proxy->op_ti_changed(ea, n, type, fnames); - case idb_event::enum_bf_changed: - id = va_arg(va, enum_t); - return proxy->enum_bf_changed(id); + case idb_event::op_type_changed: + ea = va_arg(va, ea_t); + n = va_arg(va, int); + return proxy->op_type_changed(ea, n); - case idb_event::enum_cmt_changed: - id = va_arg(va, enum_t); - return proxy->enum_cmt_changed(id); + case idb_event::enum_created: + id = va_arg(va, enum_t); + return proxy->enum_created(id); + + case idb_event::enum_deleted: + id = va_arg(va, enum_t); + return proxy->enum_deleted(id); + + case idb_event::enum_bf_changed: + id = va_arg(va, enum_t); + return proxy->enum_bf_changed(id); + + case idb_event::enum_cmt_changed: + id = va_arg(va, enum_t); + return proxy->enum_cmt_changed(id); #ifdef NO_OBSOLETE_FUNCS - case idb_event::enum_member_created: + case idb_event::enum_member_created: #else - case idb_event::enum_const_created: + case idb_event::enum_const_created: #endif - id = va_arg(va, enum_t); - cid = va_arg(va, const_t); - return proxy->enum_member_created(id, cid); + id = va_arg(va, enum_t); + cid = va_arg(va, const_t); + return proxy->enum_member_created(id, cid); #ifdef NO_OBSOLETE_FUNCS - case idb_event::enum_member_deleted: + case idb_event::enum_member_deleted: #else - case idb_event::enum_const_deleted: + case idb_event::enum_const_deleted: #endif - id = va_arg(va, enum_t); - cid = va_arg(va, const_t); - return proxy->enum_member_deleted(id, cid); + id = va_arg(va, enum_t); + cid = va_arg(va, const_t); + return proxy->enum_member_deleted(id, cid); - case idb_event::struc_created: - struc_id = va_arg(va, tid_t); - return proxy->struc_created(struc_id); + case idb_event::struc_created: + struc_id = va_arg(va, tid_t); + return proxy->struc_created(struc_id); - case idb_event::struc_deleted: - struc_id = va_arg(va, tid_t); - return proxy->struc_deleted(struc_id); + case idb_event::struc_deleted: + struc_id = va_arg(va, tid_t); + return proxy->struc_deleted(struc_id); - case idb_event::struc_renamed: - sptr = va_arg(va, struc_t *); - return proxy->struc_renamed(sptr); + case idb_event::struc_renamed: + sptr = va_arg(va, struc_t *); + return proxy->struc_renamed(sptr); - case idb_event::struc_expanded: - sptr = va_arg(va, struc_t *); - return proxy->struc_expanded(sptr); + case idb_event::struc_expanded: + sptr = va_arg(va, struc_t *); + return proxy->struc_expanded(sptr); - case idb_event::struc_cmt_changed: - struc_id = va_arg(va, tid_t); - return proxy->struc_cmt_changed(struc_id); + case idb_event::struc_cmt_changed: + struc_id = va_arg(va, tid_t); + return proxy->struc_cmt_changed(struc_id); - case idb_event::struc_member_created: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_created(sptr, mptr); + case idb_event::struc_member_created: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_created(sptr, mptr); - case idb_event::struc_member_deleted: - sptr = va_arg(va, struc_t *); - member_id = va_arg(va, tid_t); - ea = va_arg(va, ea_t); - return proxy->struc_member_deleted(sptr, member_id, ea); + case idb_event::struc_member_deleted: + sptr = va_arg(va, struc_t *); + member_id = va_arg(va, tid_t); + ea = va_arg(va, ea_t); + return proxy->struc_member_deleted(sptr, member_id, ea); - case idb_event::struc_member_renamed: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_renamed(sptr, mptr); + case idb_event::struc_member_renamed: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_renamed(sptr, mptr); - case idb_event::struc_member_changed: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_changed(sptr, mptr); + case idb_event::struc_member_changed: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_changed(sptr, mptr); - case idb_event::thunk_func_created: - pfn = va_arg(va, func_t *); - return proxy->thunk_func_created(pfn); + case idb_event::thunk_func_created: + pfn = va_arg(va, func_t *); + return proxy->thunk_func_created(pfn); - case idb_event::func_tail_appended: - pfn = va_arg(va, func_t *); - tail = va_arg(va, func_t *); - return proxy->func_tail_appended(pfn, tail); + case idb_event::func_tail_appended: + pfn = va_arg(va, func_t *); + tail = va_arg(va, func_t *); + return proxy->func_tail_appended(pfn, tail); - case idb_event::func_tail_removed: - pfn = va_arg(va, func_t *); - ea = va_arg(va, ea_t); - return proxy->func_tail_removed(pfn, ea); + case idb_event::func_tail_removed: + pfn = va_arg(va, func_t *); + ea = va_arg(va, ea_t); + return proxy->func_tail_removed(pfn, ea); - case idb_event::tail_owner_changed: - tail = va_arg(va, func_t *); - ea = va_arg(va, ea_t); - return proxy->tail_owner_changed(tail, ea); + case idb_event::tail_owner_changed: + tail = va_arg(va, func_t *); + ea = va_arg(va, ea_t); + return proxy->tail_owner_changed(tail, ea); - case idb_event::func_noret_changed: - pfn = va_arg(va, func_t *); - return proxy->func_noret_changed(pfn); + case idb_event::func_noret_changed: + pfn = va_arg(va, func_t *); + return proxy->func_noret_changed(pfn); - case idb_event::segm_added: - seg = va_arg(va, segment_t *); - return proxy->segm_added(seg); + case idb_event::segm_added: + seg = va_arg(va, segment_t *); + return proxy->segm_added(seg); - case idb_event::segm_deleted: - ea = va_arg(va, ea_t); - return proxy->segm_deleted(ea); + case idb_event::segm_deleted: + ea = va_arg(va, ea_t); + return proxy->segm_deleted(ea); - case idb_event::segm_start_changed: - seg = va_arg(va, segment_t *); - return proxy->segm_start_changed(seg); + case idb_event::segm_start_changed: + seg = va_arg(va, segment_t *); + return proxy->segm_start_changed(seg); - case idb_event::segm_end_changed: - seg = va_arg(va, segment_t *); - return proxy->segm_end_changed(seg); + case idb_event::segm_end_changed: + seg = va_arg(va, segment_t *); + return proxy->segm_end_changed(seg); - case idb_event::segm_moved: - ea = va_arg(va, ea_t); - ea2 = va_arg(va, ea_t); - size = va_arg(va, asize_t); - return proxy->segm_moved(ea, ea2, size); + case idb_event::segm_moved: + ea = va_arg(va, ea_t); + ea2 = va_arg(va, ea_t); + size = va_arg(va, asize_t); + return proxy->segm_moved(ea, ea2, size); } } catch (Swig::DirectorException &e) diff --git a/pywraps/py_kernwin.hpp b/pywraps/py_kernwin.hpp index 50df98a..40916b6 100644 --- a/pywraps/py_kernwin.hpp +++ b/pywraps/py_kernwin.hpp @@ -5,30 +5,6 @@ // //------------------------------------------------------------------------ -//------------------------------------------------------------------------ -/* -# -def read_selection(): - """ - Returns selected area boundaries - - @return: tuple(ok: bool, start_ea, end_ea) - """ - pass -# -*/ -static PyObject *py_read_selection() -{ - ea_t ea1, ea2; - bool b = read_selection(&ea1, &ea2); - - PYW_GIL_CHECK_LOCKED_SCOPE(); - return Py_BuildValue( - "(i" PY_FMT64 PY_FMT64 ")", - b ? 1 : 0, - pyul_t(ea1), pyul_t(ea2)); -} - //------------------------------------------------------------------------ /* # @@ -203,6 +179,45 @@ def free_custom_icon(icon_id): # */ +//------------------------------------------------------------------------- +/* +# +def readsel2(view, p0, p1): + """ + Read the user selection, and store its information in p0 (from) and p1 (to). + + This can be used as follows: + + + >>> p0 = idaapi.twinpos_t() + p1 = idaapi.twinpos_t() + view = idaapi.get_current_viewer() + idaapi.readsel2(view, p0, p1) + + + At that point, p0 and p1 hold information for the selection. + But, the 'at' property of p0 and p1 is not properly typed. + To specialize it, call #place() on it, passing it the view + they were retrieved from. Like so: + + + >>> place0 = p0.place(view) + place1 = p1.place(view) + + + This will effectively "cast" the place into a specialized type, + holding proper information, depending on the view type (e.g., + disassembly, structures, enums, ...) + + @param view: The view to retrieve the selection for. + @param p0: Storage for the "from" part of the selection. + @param p1: Storage for the "to" part of the selection. + @return: a bool value indicating success. + """ + pass +# +*/ + //------------------------------------------------------------------------ /* # diff --git a/pywraps/py_nalt.hpp b/pywraps/py_nalt.hpp index 8d0a795..bf8ae46 100644 --- a/pywraps/py_nalt.hpp +++ b/pywraps/py_nalt.hpp @@ -135,6 +135,54 @@ idaman bool ida_export py_create_switch_xrefs( return true; } +//------------------------------------------------------------------------- +struct cases_and_targets_t +{ + casevec_t cases; + eavec_t targets; +}; + +//------------------------------------------------------------------------- +/* +# +def calc_switch_cases(insn_ea, si): + """ + Get information about a switch's cases. + + The returned information can be used as follows: + + for idx in xrange(len(results.cases)): + cur_case = results.cases[idx] + for cidx in xrange(len(cur_case)): + print "case: %d" % cur_case[cidx] + print " goto 0x%x" % results.targets[idx] + + @param insn_ea: address of the 'indirect jump' instruction + @param si: switch information + + @return: a structure with 2 members: 'cases', and 'targets'. + """ + pass +# +*/ +idaman cases_and_targets_t *ida_export py_calc_switch_cases( + ea_t insn_ea, + PyObject *py_swi) +{ + switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + if ( swi == NULL ) + return NULL; + + cases_and_targets_t *ct = new cases_and_targets_t; + if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) ) + { + delete ct; + return NULL; + } + + return ct; +} + //------------------------------------------------------------------------- /* diff --git a/pywraps/py_typeinf.hpp b/pywraps/py_typeinf.hpp index a809ebe..3411e48 100644 --- a/pywraps/py_typeinf.hpp +++ b/pywraps/py_typeinf.hpp @@ -532,7 +532,49 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize) qstrncpy(buf, name, bufsize); return true; } - // +// +//------------------------------------------------------------------------- +// A set of tinfo_t objects that were created from IDAPython. +// This is necessary in order to clear all the "type details" that are +// associated, in the kernel, with the tinfo_t instances. +// +// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is +// closed, but the "type details" must be cleared _before_ the IDB is closed. +static qvector python_tinfos; +void til_clear_python_tinfo_t_instances(void) +{ + // Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that + // were not done here, ~tinfo_t() calls happening as part of the python shutdown + // process will try and clear() their details. ..but the kernel's til-related + // functions will already have deleted those details at that point. + for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i ) + python_tinfos[i]->clear(); + // NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t + // instances will be deleted through the python shutdown/ref-decrementing + // process anyway (which will cause til_deregister_..() calls), and the + // entries will be properly pulled out of the vector when that happens. +} + +void til_register_python_tinfo_t_instance(tinfo_t *tif) +{ + // Let's add_unique() it, because every reference to an object's + // tinfo_t property will end up trying to register it. + python_tinfos.add_unique(tif); +} + +void til_deregister_python_tinfo_t_instance(tinfo_t *tif) +{ + qvector::iterator found = python_tinfos.find(tif); + if ( found != python_tinfos.end() ) + { + tif->clear(); + python_tinfos.erase(found); + } +} + +// + + #endif diff --git a/pywraps/py_ua.hpp b/pywraps/py_ua.hpp index 56d3df1..aad6b0c 100644 --- a/pywraps/py_ua.hpp +++ b/pywraps/py_ua.hpp @@ -746,7 +746,7 @@ static PyObject *op_t_get_value(PyObject *self) op_t *link = op_t_get_clink(self); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue("I", link->value); + return Py_BuildValue(PY_FMT64, (pyul_t)link->value); } static void op_t_set_value(PyObject *self, PyObject *value) @@ -755,7 +755,9 @@ static void op_t_set_value(PyObject *self, PyObject *value) op_t *link = op_t_get_clink(self); if ( link == NULL ) return; - link->value = PyInt_AsLong(value); + uint64 v(0); + PyW_GetNumber(value, &v); + link->value = uval_t(v); } static PyObject *op_t_get_addr(PyObject *self) diff --git a/pywraps/py_view_base.hpp b/pywraps/py_view_base.hpp index f98f35f..79be7a4 100644 --- a/pywraps/py_view_base.hpp +++ b/pywraps/py_view_base.hpp @@ -15,16 +15,33 @@ class py_customidamemo_t; class lookup_info_t { public: - void add(TForm *form, TCustomControl *view, py_customidamemo_t *py_view) + struct entry_t { - QASSERT(0, form != NULL && view != NULL && py_view != NULL - && !find_by_form(NULL, NULL, form) - && !find_by_view(NULL, NULL, view) - && !find_by_py_view(NULL, NULL, py_view)); + entry_t() : form(NULL), view(NULL), py_view(NULL) {} + private: + TForm *form; + TCustomControl *view; + py_customidamemo_t *py_view; + friend class lookup_info_t; + }; + + entry_t &new_entry(py_customidamemo_t *py_view) + { + QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view)); entry_t &e = entries.push_back(); + e.py_view = py_view; + return e; + } + + void commit(entry_t &e, TForm *form, TCustomControl *view) + { + QASSERT(30455, &e >= entries.begin() && &e < entries.end()); + QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL + && !find_by_form(NULL, NULL, form) + && !find_by_view(NULL, NULL, view) + && find_by_py_view(NULL, NULL, e.py_view)); e.form = form; e.view = view; - e.py_view = py_view; } #define FIND_BY__BODY(crit, res1, res2) \ @@ -62,12 +79,6 @@ public: } private: - struct entry_t - { - TForm *form; - TCustomControl *view; - py_customidamemo_t *py_view; - }; typedef qvector entries_t; entries_t entries; }; @@ -131,6 +142,8 @@ class py_customidamemo_t static void ensure_view_callbacks_installed(); int cb_flags; + // number of arguments for OnViewClick implementation + int ovc_num_args; protected: ref_t self; @@ -199,6 +212,7 @@ public: void on_view_switched(tcc_renderer_type_t rt); void on_view_mouse_over(const view_mouse_event_t *event); inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } + int get_py_method_arg_count(char *method_name); }; //------------------------------------------------------------------------- @@ -208,6 +222,7 @@ py_customidamemo_t::py_customidamemo_t() { PYGLOG("%p: py_customidamemo_t()\n", this); ensure_view_callbacks_installed(); + ovc_num_args = -1; } //------------------------------------------------------------------------- @@ -402,7 +417,7 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) { newref_t node(PySequence_GetItem(nodes.o, k)); if ( PyInt_Check(node.o) ) - gi.nodes.insert(PyInt_AsLong(node.o)); + gi.nodes.add_unique(PyInt_AsLong(node.o)); } if ( !gi.nodes.empty() ) { @@ -410,18 +425,18 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) gis.push_back(gi); } } - intset_t groups; + intvec_t groups; if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() ) Py_RETURN_NONE; PyObject *py_groups = PyList_New(0); - for ( intset_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) + for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) PyList_Append(py_groups, PyInt_FromLong(long(*it))); return py_groups; } //------------------------------------------------------------------------- -static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes) +static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes) { Py_ssize_t sz = PySequence_Size(pynodes.o); for ( Py_ssize_t i = 0; i < sz; ++i ) @@ -429,7 +444,7 @@ static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes) newref_t item(PySequence_GetItem(pynodes.o, i)); if ( !PyInt_Check(item.o) ) continue; - idanodes->insert(PyInt_AsLong(item.o)); + idanodes->add_unique(PyInt_AsLong(item.o)); } } @@ -440,7 +455,7 @@ PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_cu Py_RETURN_NONE; borref_t groups(_groups); borref_t new_current(_new_current); - intset_t ida_groups; + intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; @@ -460,7 +475,7 @@ PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject borref_t groups(_groups); borref_t expand(_expand); borref_t new_current(_new_current); - intset_t ida_groups; + intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; @@ -499,6 +514,23 @@ void py_customidamemo_t::unbind() view = NULL; } +//------------------------------------------------------------------------- +int py_customidamemo_t::get_py_method_arg_count(char *method_name) +{ + newref_t method(PyObject_GetAttrString(self.o, method_name)); + if ( method != NULL && PyCallable_Check(method.o) ) + { + newref_t fc(PyObject_GetAttrString(method.o, "func_code")); + if ( fc != NULL ) + { + newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount")); + if ( ac != NULL ) + return PyInt_AsLong(ac.o); + } + } + return -1; +} + //------------------------------------------------------------------------- void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out) { @@ -604,12 +636,26 @@ void py_customidamemo_t::on_view_popup() void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_CLICK); - newref_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CLICK, - "iii", - event->x, event->y, event->state)); + if ( ovc_num_args < 0 ) + ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); + if ( ovc_num_args == 5 ) + { + newref_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iiii", + event->x, event->y, event->state, event->button)); + } + else + { + newref_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iii", + event->x, event->y, event->state)); + } CHK_RES(); } diff --git a/swig/bytes.i b/swig/bytes.i index 14bec39..32ed0ba 100644 --- a/swig/bytes.i +++ b/swig/bytes.i @@ -67,6 +67,7 @@ %ignore term_flags; %ignore reset_flags; %ignore flush_flags; +%ignore get_flags_linput; %ignore data_type_t; %ignore data_format_t; %ignore get_custom_data_type; diff --git a/swig/dbg.i b/swig/dbg.i index 5bc8a19..572d250 100644 --- a/swig/dbg.i +++ b/swig/dbg.i @@ -22,6 +22,8 @@ typedef struct %ignore bpt_t::write; %ignore bpt_t::erase; %ignore bpt_t::cndbody; +%ignore bpt_t::get_cnd_elang; +%ignore bpt_t::set_cnd_elang; %rename (get_manual_regions) py_get_manual_regions; %ignore set_manual_regions; %ignore inform_idc_about_debthread; @@ -45,6 +47,7 @@ static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas); %extend bpt_t { PyObject *condition; + PyObject *elang; } %{ PyObject *bpt_t_condition_get(bpt_t *bpt) @@ -56,6 +59,27 @@ void bpt_t_condition_set(bpt_t *bpt, PyObject *val) { if ( PyString_Check(val) ) bpt->cndbody = PyString_AsString(val); + else + PyErr_SetString(PyExc_ValueError, "expected a string"); +} + +PyObject *bpt_t_elang_get(bpt_t *bpt) +{ + return PyString_FromString(bpt->get_cnd_elang()); +} + +void bpt_t_elang_set(bpt_t *bpt, PyObject *val) +{ + if ( PyString_Check(val) ) + { + char *cval = PyString_AsString(val); + if ( !bpt->set_cnd_elang(cval) ) + PyErr_SetString(PyExc_ValueError, "too many extlangs"); + } + else + { + PyErr_SetString(PyExc_ValueError, "expected a string"); + } } %} %inline %{ diff --git a/swig/diskio.i b/swig/diskio.i index 500b2a8..466f4e5 100644 --- a/swig/diskio.i +++ b/swig/diskio.i @@ -29,6 +29,7 @@ %ignore make_linput; %ignore unmake_linput; %ignore create_remote_linput; +%ignore make_filehandle_linput; // FIXME: These should be wrapped for completeness %ignore eread; diff --git a/swig/expr.i b/swig/expr.i index 14ab043..b2d9cce 100644 --- a/swig/expr.i +++ b/swig/expr.i @@ -43,6 +43,7 @@ %ignore init_idc; %ignore term_idc; %ignore create_default_idc_classes; +%ignore notify_extlang_changed; %ignore insn_to_idc; %ignore find_builtin_idc_func; %ignore idc_mutex; diff --git a/swig/graph.i b/swig/graph.i index af71529..15c9332 100644 --- a/swig/graph.i +++ b/swig/graph.i @@ -115,7 +115,6 @@ private: static cmdid_map_t cmdid_pyg; - // TForm *form; bool refresh_needed; nodetext_cache_map_t node_cache; @@ -125,6 +124,7 @@ private: // static callback static int idaapi s_callback(void *obj, int code, va_list va) { + QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj)); PYW_GIL_GET; return ((py_graph_t *)obj)->gr_callback(code, va); } @@ -258,13 +258,13 @@ private: } // a group is being created - int on_creating_group(mutable_graph_t *my_g, intset_t *my_nodes) + int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes) { PYW_GIL_CHECK_LOCKED_SCOPE(); printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes); newref_t py_nodes(PyList_New(my_nodes->size())); int i; - intset_t::const_iterator p; + intvec_t::const_iterator p; for ( i = 0, p=my_nodes->begin(); p != my_nodes->end(); ++p, ++i ) PyList_SetItem(py_nodes.o, i, PyInt_FromLong(*p)); newref_t py_result( @@ -334,6 +334,7 @@ private: TForm *form = create_tform(title, &hwnd); if ( hwnd != NULL ) // Created new tform { + lookup_info_t::entry_t &e = lookup_info.new_entry(this); // get a unique graph id netnode id; char grnode[MAXSTR]; @@ -345,8 +346,7 @@ private: viewer_fit_window(pview); bind(self, pview); refresh(); - // Link "form" and "py_graph" - lookup_info.add(form, view, this); + lookup_info.commit(e, form, view); } else { @@ -703,7 +703,7 @@ int py_graph_t::gr_callback(int code, va_list va) case grcode_creating_group: // a group is being created { mutable_graph_t *g = va_arg(va, mutable_graph_t*); - intset_t *nodes = va_arg(va, intset_t*); + intvec_t *nodes = va_arg(va, intvec_t*); ret = on_creating_group(g, nodes); } break; diff --git a/swig/hexrays.i b/swig/hexrays.i index b99c881..1e1da9f 100644 --- a/swig/hexrays.i +++ b/swig/hexrays.i @@ -1,1000 +1,1105 @@ -//--------------------------------------------------------------------- -// SWIG bindings for Hexray Decompiler's hexrays.hpp -// -// Author: EiNSTeiN_ -// Copyright (C) 2013 ESET -// -// Integrated into IDAPython project by the IDAPython Team -//--------------------------------------------------------------------- - -// Suppress 'previous definition of XX' warnings -#pragma SWIG nowarn=302 -// and others... -#pragma SWIG nowarn=312 -#pragma SWIG nowarn=325 -#pragma SWIG nowarn=314 -#pragma SWIG nowarn=362 -#pragma SWIG nowarn=383 -#pragma SWIG nowarn=389 -#pragma SWIG nowarn=401 -#pragma SWIG nowarn=451 -#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory - -#define _STD_BEGIN -#define typename - -%{ -#include "hexrays.hpp" -%} - -//--------------------------------------------------------------------- -// some defines to calm SWIG down. -#define DEFINE_MEMORY_ALLOCATION_FUNCS() -//#define DECLARE_UNCOPYABLE(f) -#define AS_PRINTF(format_idx, varg_idx) -#define idaapi -#define __fastcall - -%ignore vd_printer_t::vprint; -%ignore string_printer_t::vprint; -%ignore typestring::dstr; -%ignore typestring::multiprint; -%ignore vdui_t::vdui_t; -%ignore cblock_t::find; -%ignore cfunc_t::cfunc_t; -%ignore ctree_item_t::verify; -%ignore ccases_t::find_value; -%ignore ccases_t::print; -%ignore ccase_t::set_insn; -%ignore ccase_t::print; -%ignore carglist_t::print; -%ignore cblock_t::remove_gotos; -%ignore casm_t::genasm; -%ignore cblock_t::use_curly_braces; -%ignore casm_t::print; -%ignore cgoto_t::print; -%ignore cexpr_t::is_aliasable; -%ignore cexpr_t::contains_expr; -%ignore cexpr_t::contains_expr; -%ignore cexpr_t::cexpr_t(mbl_array_t *mba, const lvar_t &v); -%ignore lvar_t::is_promoted_arg; -%ignore lvar_t::lvar_t; -%ignore strtype_info_t::find_strmem; -%ignore typestring::resolve_func_type; -%ignore typestring::common_type; -%ignore typestring::noarray_size; -%ignore file_printer_t::_print; -%ignore file_printer_t; - -%extend cfunc_t { - %immutable rgas; - %immutable stas; -}; - -%rename(dereference_uint16) operator uint16*; -%rename(dereference_const_uint16) operator const uint16*; - -// this is a dummy class template to allow swig to do its thing. -template class std::map { -public: - mapped_type& at(const key_type& _Keyval); - size_t size() const; -}; - -//--------------------------------------------------------------------- -%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; } -}; - -#define CITEM_MEMBER_REF(name) \ - name##_t *name const { return self->##name; } - -//--------------------------------------------------------------------- -// swig doesn't very much like the way the union is done in this class so we need to wrap all these up. -%extend cinsn_t { - CITEM_MEMBER_REF(cblock) - CITEM_MEMBER_REF(cexpr) - CITEM_MEMBER_REF(cif) - CITEM_MEMBER_REF(cfor) - CITEM_MEMBER_REF(cwhile) - CITEM_MEMBER_REF(cdo) - CITEM_MEMBER_REF(cswitch) - CITEM_MEMBER_REF(creturn) - CITEM_MEMBER_REF(cgoto) - CITEM_MEMBER_REF(casm) -}; - -#define CEXPR_MEMBER_REF(type, name) \ - type name const { return self->##name; } - -%extend cexpr_t { - CEXPR_MEMBER_REF(cnumber_t*, n) - CEXPR_MEMBER_REF(fnumber_t*, fpc) - const var_ref_t& v { return self->v; } - CEXPR_MEMBER_REF(ea_t, obj_ea) - CEXPR_MEMBER_REF(int, refwidth) - CEXPR_MEMBER_REF(cexpr_t*, x) - CEXPR_MEMBER_REF(cexpr_t*, y) - CEXPR_MEMBER_REF(carglist_t*, a) - CEXPR_MEMBER_REF(int, m) - CEXPR_MEMBER_REF(cexpr_t*, z) - CEXPR_MEMBER_REF(int, ptrsize) - CEXPR_MEMBER_REF(cinsn_t*, insn) - CEXPR_MEMBER_REF(char*, helper) - CEXPR_MEMBER_REF(char*, string) -}; - -%extend ctree_item_t { - CEXPR_MEMBER_REF(citem_t *, it) - CEXPR_MEMBER_REF(lvar_t*, l) - CEXPR_MEMBER_REF(cfunc_t*, f) - const treeloc_t& loc { return self->loc; } -}; - -/* for qvector instanciations where the class is a pointer (cinsn_t, citem_t) we need - to fix the at() return type, otherwise swig mistakenly thinks it is "cinsn_t *&" and nonsense ensues. */ -%extend qvector< cinsn_t *> { - cinsn_t *at(size_t n) { return self->at(n); } -}; -%extend qvector< citem_t *> { - citem_t *at(size_t n) { return self->at(n); } -}; - -// ignore future declarations of at() for these classes -%ignore qvector< cinsn_t *>::at(size_t) const; -%ignore qvector< cinsn_t *>::at(size_t); -%ignore qvector< citem_t *>::at(size_t) const; -%ignore qvector< citem_t *>::at(size_t); -%ignore qvector< citem_t *>::grow; -%ignore qvector< cinsn_t *>::grow; - -//~ %template(qwstrvec_t) qvector; // vector of unicode strings -typedef intvec_t svalvec_t; // vector of signed values -typedef intvec_t eavec_t;// vector of addresses - -// director classes make it possible to override virtual functions from python. -%feature("director") ctree_visitor_t; -%feature("director") ctree_parentee_t; -%feature("director") cfunc_parentee_t; -%feature("director") user_lvar_visitor_t; - -// hexrays templates -%template(user_numforms_t) std::map; -%template(lvar_mapping_t) std::map; -%template(hexwarns_t) qvector; -%template(ctree_items_t) qvector; -%template(user_labels_t) std::map; -%template(user_cmts_t) std::map; -%template(user_iflags_t) std::map; -%template(user_unions_t) std::map; -%template(cinsnptrvec_t) qvector; -%template(eamap_t) std::map; -%template(boundaries_t) std::map; -%template(cfuncptr_t) qrefcnt_t; -%template(qvector_history_t) qvector; -%template(history_t) qstack; -typedef int iterator_word; - -/* no support for nested classes in swig means we need to wrap - this iterator and do some magic... - - to use it, call qlist< cinsn_t >::begin() which will return the - proper iterator type which can then be used to get the current item. -*/ -%{ -typedef qlist::iterator qlist_cinsn_t_iterator; -%} -class qlist_cinsn_t_iterator {}; -%extend qlist_cinsn_t_iterator { - const cinsn_t &cur { return *(*self); } - qlist_cinsn_t_iterator &next(void) { (*self)++; return *self; } -}; - -%extend qlist { - qlist_cinsn_t_iterator begin() { return self->begin(); } - qlist_cinsn_t_iterator end(void) { return self->end(); } - qlist_cinsn_t_iterator insert(qlist_cinsn_t_iterator p, const cinsn_t& x) { return self->insert(p, x); } - void erase(qlist_cinsn_t_iterator p) { self->erase(p); } -}; -%ignore qlist< cinsn_t >::insert(); -%ignore qlist< cinsn_t >::erase(); -%ignore qlist< cinsn_t >::begin(); -%ignore qlist< cinsn_t >::begin() const; -%ignore qlist< cinsn_t >::end(); -%ignore qlist< cinsn_t >::end() const; - -//%template(qvector_meminfo_t) qvector; -%template(qvector_lvar_t) qvector; -%template(qlist_cinsn_t) qlist; -%template(qvector_carg_t) qvector; -%template(qvector_ccase_t) qvector; - -%extend citem_cmt_t { - const char *c_str() const { return self->c_str(); } -}; - -%{ -cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf) -{ - try - { - cfuncptr_t cfunc = decompile(pfn, hf); - return cfunc; - } - catch(...) - { - error("Hex-Rays Python: decompiler threw an exception.\n"); - } - return cfuncptr_t(0); -} -%} - -cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf); -%ignore decompile; - -void qswap(cinsn_t &a, cinsn_t &b); -%include "typemaps.i" - -%typemap(out) void -{ - Py_INCREF(Py_None); - $1obj = Py_None; -} - -%{ - -//--------------------------------------------------------------------- -static int hexrays_python_call(ref_t fct, ref_t args) -{ - PYW_GIL_GET; - - int result; - int ecode1 = 0 ; - - newref_t resultobj(PyEval_CallObject(fct.o, args.o)); - if ( resultobj == NULL ) - { - msg("IDAPython: Hex-rays python callback raised an exception.\n"); - - // we can't do much else than clear the exception since this was not called from Python. - // XXX: print stack trace? - PyErr_Clear(); - return 0; - } - - ecode1 = SWIG_AsVal_int(resultobj.o, &result); - if (SWIG_IsOK(ecode1)) - return result; - - msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n"); - return 0; -} - -//--------------------------------------------------------------------- -static bool idaapi __python_custom_viewer_popup_item_callback(void *ud) -{ - PYW_GIL_GET; - - int ret; - borref_t fct((PyObject *)ud); - newref_t nil(NULL); - ret = hexrays_python_call(fct, nil); - return ret ? true : false; -} - -//--------------------------------------------------------------------- -static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_list va) -{ - PYW_GIL_GET; - - int ret; - borref_t fct((PyObject *)ud); - switch(event) - { - case hxe_maturity: - ///< Ctree maturity level is being changed. - ///< cfunc_t *cfunc - ///< ctree_maturity_t new_maturity - { - cfunc_t *arg0 = va_arg(va, cfunc_t *); - ctree_maturity_t arg1 = va_argi(va, ctree_maturity_t); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 )); - newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_interr: - ///< Internal error has occurred. - ///< int errcode - { - int arg0 = va_argi(va, int); - newref_t args(Py_BuildValue("(ii)", event, arg0)); - ret = hexrays_python_call(fct, args); - } - break; - - case hxe_print_func: - ///< Printing ctree and generating text. - ///< cfunc_t *cfunc - ///< vc_printer_t *vp - ///< Returns: 1 if text has been generated by the plugin - { - cfunc_t *arg0 = va_arg(va, cfunc_t *); - vc_printer_t *arg1 = va_arg(va, vc_printer_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 )); - newref_t arg1obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg1), SWIGTYPE_p_vc_printer_t, 0 )); - newref_t args(Py_BuildValue("(iOO)", event, arg0obj.o, arg1obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - - // User interface related events: - case hxe_open_pseudocode: - ///< New pseudocode view has been opened. - ///< vdui_t *vu - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_switch_pseudocode: - ///< Existing pseudocode view has been reloaded - ///< with a new function. Its text has not been - ///< refreshed yet, only cfunc and mba pointers are ready. - ///< vdui_t *vu - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_refresh_pseudocode: - ///< Existing pseudocode text has been refreshed. - ///< vdui_t *vu - ///< See also hxe_text_ready, which happens earlier - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_close_pseudocode: - ///< Pseudocode view is being closed. - ///< vdui_t *vu - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_keyboard: - ///< Keyboard has been hit. - ///< vdui_t *vu - ///< int key_code (VK_...) - ///< int shift_state - ///< Should return: 1 if the event has been handled - { - vdui_t *arg0 = va_arg(va, vdui_t *); - int arg1 = va_argi(va, int); - int arg2 = va_argi(va, int); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iOii)", event, arg0obj.o, arg1, arg2)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_right_click: - ///< Mouse right click. We can add menu items now. - ///< vdui_t *vu - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_double_click: - ///< Mouse double click. - ///< vdui_t *vu - ///< int shift_state - ///< Should return: 1 if the event has been handled - { - vdui_t *arg0 = va_arg(va, vdui_t *); - int arg1 = va_argi(va, int); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_curpos: - ///< Current cursor position has been changed. - ///< (for example, by left-clicking or using keyboard) - ///< vdui_t *vu - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_create_hint: - ///< Create a hint for the current item. - ///< vdui_t *vu - ///< qstring *result_hint - ///< int *implines - ///< Possible return values: - ///< 0: the event has not been handled - ///< 1: hint has been created (should set *implines to nonzero as well) - ///< 2: hint has been created but the standard hints must be - ///< appended by the decompiler - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - case hxe_text_ready: - ///< Decompiled text is ready. - ///< vdui_t *vu - ///< This event can be used to modify the output text (sv). - ///< The text uses regular color codes (see lines.hpp) - ///< COLOR_ADDR is used to store pointers to ctree elements - { - vdui_t *arg0 = va_arg(va, vdui_t *); - newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); - newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); - ret = hexrays_python_call(fct, args); - } - break; - default: - //~ msg("IDAPython: Unknown event `%u' occured\n", event); - ret = 0; - break; - } - - return ret; -} - -%} - -%ignore init_hexrays_plugin; -%rename(init_hexrays_plugin) __init_hexrays_plugin; - -%ignore add_custom_viewer_popup_item; -%rename(add_custom_viewer_popup_item) __add_custom_viewer_popup_item; - -%ignore install_hexrays_callback; -%rename(install_hexrays_callback) __install_hexrays_callback; - -%ignore remove_hexrays_callback; -%rename(remove_hexrays_callback) __remove_hexrays_callback; - -%inline %{ - -//--------------------------------------------------------------------- -extern hexdsp_t *hexdsp; -bool __init_hexrays_plugin(int flags=0) -{ - // Only initialize one time - if (hexdsp == NULL) - return init_hexrays_plugin(flags); - else - return true; -} - -//--------------------------------------------------------------------- -void __add_custom_viewer_popup_item( - TCustomControl *custom_viewer, - const char *title, - const char *hotkey, - PyObject *custom_viewer_popup_item_callback) -{ - PYW_GIL_GET; - Py_INCREF(custom_viewer_popup_item_callback); - add_custom_viewer_popup_item(custom_viewer, title, hotkey, __python_custom_viewer_popup_item_callback, custom_viewer_popup_item_callback); -}; - -//--------------------------------------------------------------------- -bool __install_hexrays_callback(PyObject *hx_cblist_callback) -{ - PYW_GIL_GET; - if (install_hexrays_callback(__hexrays_python_callback, hx_cblist_callback)) - { - Py_INCREF(hx_cblist_callback); - return true; - } - return false; -} - -//--------------------------------------------------------------------- -int __remove_hexrays_callback(PyObject *hx_cblist_callback) -{ - PYW_GIL_GET; - int result, i; - result = remove_hexrays_callback(__hexrays_python_callback, hx_cblist_callback); - for (i=0;i= cot_empty and self.op <= cot_last: - return self.cexpr - elif self.op >= cit_empty and self.op < cit_end: - return self.cinsn - - raise RuntimeError('unknown op type %s' % (repr(self.op), )) -citem_t.to_specific_type = property(citem_to_specific_type) - -""" array used for translating cinsn_t->op type to their names. """ -cinsn_t.op_to_typename = {} -for k in dir(_idaapi): - if k.startswith('cit_'): - cinsn_t.op_to_typename[getattr(_idaapi, k)] = k[4:] - -""" array used for translating cexpr_t->op type to their names. """ -cexpr_t.op_to_typename = {} -for k in dir(_idaapi): - if k.startswith('cot_'): - cexpr_t.op_to_typename[getattr(_idaapi, k)] = k[4:] - -def property_op_to_typename(self): - return self.op_to_typename[self.op] -cinsn_t.opname = property(property_op_to_typename) -cexpr_t.opname = property(property_op_to_typename) - -def cexpr_operands(self): - """ return a dictionary with the operands of a cexpr_t. """ - - if self.op >= cot_comma and self.op <= cot_asgumod or \ - self.op >= cot_lor and self.op <= cot_fdiv or \ - self.op == cot_idx: - return {'x': self.x, 'y': self.y} - - elif self.op == cot_tern: - return {'x': self.x, 'y': self.y, 'z': self.z} - - elif self.op in [cot_fneg, cot_neg, cot_sizeof] or \ - self.op >= cot_lnot and self.op <= cot_predec: - return {'x': self.x} - - elif self.op == cot_cast: - return {'type': self.type, 'x': self.x} - - elif self.op == cot_call: - return {'x': self.x, 'a': self.a} - - elif self.op in [cot_memref, cot_memptr]: - return {'x': self.x, 'm': self.m} - - elif self.op == cot_num: - return {'n': self.n} - - elif self.op == cot_fnum: - return {'fpc': self.fpc} - - elif self.op == cot_str: - return {'string': self.string} - - elif self.op == cot_obj: - return {'obj_ea': self.obj_ea} - - elif self.op == cot_var: - return {'v': self.v} - - elif self.op == cot_helper: - return {'helper': self.helper} - - raise RuntimeError('unknown op type %s' % self.opname) -cexpr_t.operands = property(cexpr_operands) - -def cinsn_details(self): - """ return the details pointer for the cinsn_t object depending on the value of its op member. \ - this is one of the cblock_t, cif_t, etc. objects. """ - - if self.op not in self.op_to_typename: - raise RuntimeError('unknown item->op type') - - opname = self.opname - if opname == 'empty': - return self - - if opname in ['break', 'continue']: - return None - - return getattr(self, 'c' + opname) -cinsn_t.details = property(cinsn_details) - -def cblock_iter(self): - - iter = self.begin() - for i in range(self.size()): - yield iter.cur - iter.next() - - return -cblock_t.__iter__ = cblock_iter -cblock_t.__len__ = cblock_t.size - -# cblock.find(cinsn_t) -> returns the iterator positioned at the given item -def cblock_find(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return iter - iter.next() - - return -cblock_t.find = cblock_find - -# cblock.index(cinsn_t) -> returns the index of the given item -def cblock_index(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return i - iter.next() - - return -cblock_t.index = cblock_index - -# cblock.at(int) -> returns the item at the given index index -def cblock_at(self, index): - - iter = self.begin() - for i in range(self.size()): - if i == index: - return iter.cur - iter.next() - - return -cblock_t.at = cblock_at - -# cblock.remove(cinsn_t) -def cblock_remove(self, item): - - iter = self.find(item) - self.erase(iter) - - return -cblock_t.remove = cblock_remove - -# cblock.insert(index, cinsn_t) -def cblock_insert(self, index, item): - - pos = self.at(index) - iter = self.find(pos) - self.insert(iter, item) - - return -cblock_t.insert = cblock_insert - -def cfunc___str__(self): - qs = qstring() - p = qstring_printer_t(self, qs, 0) - self.print_func(p) - return qs.c_str() -cfunc_t.__str__ = cfunc___str__ -cfuncptr_t.__str__ = lambda self: str(self.__deref__()) - -def cfunc_typestring(self): - """ Get the function's return type typestring object. The full prototype \ - can be obtained via typestring._print() method. """ - - ts = typestring() - qt = qtype() - - result = self.get_func_type(ts, qt) - if not result: return - - return ts -cfunc_t.typestring = property(cfunc_typestring) -cfuncptr_t.typestring = property(lambda self: self.__deref__().typestring) - -cfunc_t.arguments = property(lambda self: [o for o in self.lvars if o.is_arg_var]) -cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments) - -cfunc_t.lvars = property(cfunc_t.get_lvars) -cfuncptr_t.lvars = property(lambda self: self.__deref__().lvars) -cfunc_t.warnings = property(cfunc_t.get_warnings) -cfuncptr_t.warnings = property(lambda self: self.__deref__().warnings) -cfunc_t.pseudocode = property(cfunc_t.get_pseudocode) -cfuncptr_t.pseudocode = property(lambda self: self.__deref__().get_pseudocode()) -cfunc_t.eamap = property(cfunc_t.get_eamap) -cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap()) -cfunc_t.boundaries = property(cfunc_t.get_boundaries) -cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries()) - -lvar_t.used = property(lvar_t.used) -lvar_t.typed = property(lvar_t.typed) -lvar_t.mreg_done = property(lvar_t.mreg_done) -lvar_t.has_nice_name = property(lvar_t.has_nice_name) -lvar_t.is_unknown_width = property(lvar_t.is_unknown_width) -lvar_t.has_user_info = property(lvar_t.has_user_info) -lvar_t.has_user_name = property(lvar_t.has_user_name) -lvar_t.has_user_type = property(lvar_t.has_user_type) -lvar_t.is_result_var = property(lvar_t.is_result_var) -lvar_t.is_arg_var = property(lvar_t.is_arg_var) -lvar_t.is_fake_var = property(lvar_t.is_fake_var) -lvar_t.is_overlapped_var = property(lvar_t.is_overlapped_var) -lvar_t.is_floating_var = property(lvar_t.is_floating_var) -lvar_t.is_spoiled_var = property(lvar_t.is_spoiled_var) -lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var) - -# dictify all dict-like types - -def _map___getitem__(self, key): - """ Returns the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of key should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - return self.second(self.find(key)) - -def _map___setitem__(self, key, value): - """ Returns the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if not isinstance(value, self.valuetype): - raise KeyError('type of `value` should be ' + repr(self.valuetype) + ' but got ' + type(value)) - self.insert(key, value) - return - -def _map___delitem__(self, key): - """ Removes the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - self.erase(self.find(key)) - return - -def _map___contains__(self, key): - """ Returns true if the specified key exists in the . """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if self.find(key) != self.end(): - return True - return False - -def _map_clear(self): - self.clear() - return - -def _map_copy(self): - ret = {} - for k in self.iterkeys(): - ret[k] = self[k] - return ret - -def _map_get(self, key, default=None): - if key in self: - return self[key] - return default - -def _map_iterkeys(self): - iter = self.begin() - while iter != self.end(): - yield self.first(iter) - iter = self.next(iter) - return - -def _map_itervalues(self): - iter = self.begin() - while iter != self.end(): - yield self.second(iter) - iter = self.next(iter) - return - -def _map_iteritems(self): - iter = self.begin() - while iter != self.end(): - yield (self.first(iter), self.second(iter)) - iter = self.next(iter) - return - -def _map_keys(self): - return list(self.iterkeys()) - -def _map_values(self): - return list(self.itervalues()) - -def _map_items(self): - return list(self.iteritems()) - -def _map_has_key(self, key): - return key in self - -def _map_pop(self, key): - """ Sets the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key not in self: - raise KeyError('key not found') - ret = self[key] - del self[key] - return ret - -def _map_popitem(self): - """ Sets the value associated with the provided key. """ - if len(self) == 0: - raise KeyError('key not found') - key = self.keys()[0] - return (key, self.pop(key)) - -def _map_setdefault(self, key, default=None): - """ Sets the value associated with the provided key. """ - if not isinstance(key, self.keytype): - raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) - if key in self: - return self[key] - self[key] = default - return default - -def _map_as_dict(maptype, name, keytype, valuetype): - - maptype.keytype = keytype - maptype.valuetype = valuetype - - for fctname in ['begin', 'end', 'first', 'second', 'next', \ - 'find', 'insert', 'erase', 'clear', 'size']: - fct = getattr(_idaapi, name + '_' + fctname) - setattr(maptype, '__' + fctname, fct) - - maptype.__len__ = maptype.size - maptype.__getitem__ = maptype.at - - maptype.begin = lambda self, *args: self.__begin(self, *args) - maptype.end = lambda self, *args: self.__end(self, *args) - maptype.first = lambda self, *args: self.__first(*args) - maptype.second = lambda self, *args: self.__second(*args) - maptype.next = lambda self, *args: self.__next(*args) - maptype.find = lambda self, *args: self.__find(self, *args) - maptype.insert = lambda self, *args: self.__insert(self, *args) - maptype.erase = lambda self, *args: self.__erase(self, *args) - maptype.clear = lambda self, *args: self.__clear(self, *args) - maptype.size = lambda self, *args: self.__size(self, *args) - maptype.__getitem__ = _map___getitem__ - maptype.__setitem__ = _map___setitem__ - maptype.__delitem__ = _map___delitem__ - maptype.__contains__ = _map___contains__ - maptype.clear = _map_clear - maptype.copy = _map_copy - maptype.get = _map_get - maptype.iterkeys = _map_iterkeys - maptype.itervalues = _map_itervalues - maptype.iteritems = _map_iteritems - maptype.keys = _map_keys - maptype.values = _map_values - maptype.items = _map_items - maptype.has_key = _map_has_key - maptype.pop = _map_pop - maptype.popitem = _map_popitem - maptype.setdefault = _map_setdefault - -_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring) -_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t) -_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t) -_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, (int, long)) -_map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t) -_map_as_dict(eamap_t, 'eamap', int, cinsnptrvec_t) -#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t) - -%} +//--------------------------------------------------------------------- +// SWIG bindings for Hexray Decompiler's hexrays.hpp +// +// Author: EiNSTeiN_ +// Copyright (C) 2013 ESET +// +// Integrated into IDAPython project by the IDAPython Team +//--------------------------------------------------------------------- + +// Suppress 'previous definition of XX' warnings +#pragma SWIG nowarn=302 +// and others... +#pragma SWIG nowarn=312 +#pragma SWIG nowarn=325 +#pragma SWIG nowarn=314 +#pragma SWIG nowarn=362 +#pragma SWIG nowarn=383 +#pragma SWIG nowarn=389 +#pragma SWIG nowarn=401 +#pragma SWIG nowarn=451 +#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory + +#define _STD_BEGIN + +#ifdef __NT__ +%include +#endif + +//--------------------------------------------------------------------- +// some defines to calm SWIG down. +#define DEFINE_MEMORY_ALLOCATION_FUNCS() +//#define DECLARE_UNCOPYABLE(f) +#define AS_PRINTF(format_idx, varg_idx) + +%ignore vd_printer_t::vprint; +%ignore string_printer_t::vprint; +%ignore vdui_t::vdui_t; +%ignore cblock_t::find; +%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 +%ignore cfunc_t::eamap; // lazy member. Use get_eamap() instead +%ignore ctree_item_t::verify; +%ignore ccases_t::find_value; +%ignore ccases_t::print; +%ignore ccase_t::set_insn; +%ignore ccase_t::print; +%ignore carglist_t::print; +%ignore cblock_t::remove_gotos; +%ignore casm_t::genasm; +%ignore cblock_t::use_curly_braces; +%ignore casm_t::print; +%ignore cgoto_t::print; +%ignore cexpr_t::is_aliasable; +%ignore cexpr_t::contains_expr; +%ignore cexpr_t::contains_expr; +%ignore cexpr_t::cexpr_t(mbl_array_t *mba, const lvar_t &v); +%ignore lvar_t::is_promoted_arg; +%ignore lvar_t::lvar_t; +%ignore strtype_info_t::find_strmem; +%ignore file_printer_t::_print; +%ignore file_printer_t; +%ignore qstring_printer_t::qstring_printer_t(const cfunc_t *, qstring &, bool); + +%extend cfunc_t { + %immutable argidx; + + qstring __str__() { + qstring qs; + qstring_printer_t p($self, qs, 0); + $self->print_func(p); + return qs; + } +}; + +%ignore qstring_printer_t::qstring_printer_t(const cfunc_t *, qstring &, bool); +%ignore qstring_printer_t::~qstring_printer_t(); + +%extend qstring_printer_t { + + qstring_printer_t(const cfunc_t *f, bool tags); + ~qstring_printer_t(); + + qstring get_s() { + return $self->s; + } + + %pythoncode { + s = property(lambda self: self.get_s()) + } +}; + +%rename(dereference_uint16) operator uint16*; +%rename(dereference_const_uint16) operator const uint16*; + +#if !defined(__MAC__) || (MACSDKVER >= 1060) +#define HAS_MAP_AT +#endif + +// Provide trivial std::map facade so basic operations are available. +template class std::map { +public: +#ifdef HAS_MAP_AT + mapped_type& at(const key_type& _Keyval); +#endif + size_t size() const; +}; + +#ifndef HAS_MAP_AT +#warning "std::map doesn't provide at(). Augmenting it." +%extend std::map { + mapped_type& at(const key_type& _Keyval) { return $self->operator[](_Keyval); } +} +#endif + +//--------------------------------------------------------------------- +%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; } +}; + +#define CITEM_MEMBER_REF(name) \ + name##_t *name const { return self->##name; } + +//--------------------------------------------------------------------- +// swig doesn't very much like the way the union is done in this class so we need to wrap all these up. +%extend cinsn_t { + CITEM_MEMBER_REF(cblock) + CITEM_MEMBER_REF(cexpr) + CITEM_MEMBER_REF(cif) + CITEM_MEMBER_REF(cfor) + CITEM_MEMBER_REF(cwhile) + CITEM_MEMBER_REF(cdo) + CITEM_MEMBER_REF(cswitch) + CITEM_MEMBER_REF(creturn) + CITEM_MEMBER_REF(cgoto) + CITEM_MEMBER_REF(casm) +}; + +#define CEXPR_MEMBER_REF(type, name) \ + type name const { return self->##name; } + +%extend cexpr_t { + CEXPR_MEMBER_REF(cnumber_t*, n) + CEXPR_MEMBER_REF(fnumber_t*, fpc) + const var_ref_t& v { return self->v; } + CEXPR_MEMBER_REF(ea_t, obj_ea) + CEXPR_MEMBER_REF(int, refwidth) + CEXPR_MEMBER_REF(cexpr_t*, x) + CEXPR_MEMBER_REF(cexpr_t*, y) + CEXPR_MEMBER_REF(carglist_t*, a) + CEXPR_MEMBER_REF(int, m) + CEXPR_MEMBER_REF(cexpr_t*, z) + CEXPR_MEMBER_REF(int, ptrsize) + CEXPR_MEMBER_REF(cinsn_t*, insn) + CEXPR_MEMBER_REF(char*, helper) + CEXPR_MEMBER_REF(char*, string) +}; + +%extend ctree_item_t { + CEXPR_MEMBER_REF(citem_t *, it) + CEXPR_MEMBER_REF(lvar_t*, l) + CEXPR_MEMBER_REF(cfunc_t*, f) + const treeloc_t& loc { return self->loc; } +}; + +/* for qvector instanciations where the class is a pointer (cinsn_t, citem_t) we need + to fix the at() return type, otherwise swig mistakenly thinks it is "cinsn_t *&" and nonsense ensues. */ +%extend qvector< cinsn_t *> { + cinsn_t *at(size_t n) { return self->at(n); } +}; +%extend qvector< citem_t *> { + citem_t *at(size_t n) { return self->at(n); } +}; + +// ignore future declarations of at() for these classes +%ignore qvector< cinsn_t *>::at(size_t) const; +%ignore qvector< cinsn_t *>::at(size_t); +%ignore qvector< citem_t *>::at(size_t) const; +%ignore qvector< citem_t *>::at(size_t); +%ignore qvector< citem_t *>::grow; +%ignore qvector< cinsn_t *>::grow; + + +//~ %template(qwstrvec_t) qvector; // vector of unicode strings +typedef intvec_t svalvec_t; // vector of signed values +typedef intvec_t eavec_t;// vector of addresses + +// At this point, SWIG doesn't know about this +// type yet (kernwin.i is included later). Therefore, +// unless we do this, swig will consider 'strvec_t' to be +// just a regular type, and when retrieving structure +// members of type 'strvec_t', 2 issues: +// - an additional copy will be made, and +// - SWIG will use SWIGTYPE_p_strvec_t, which has a != Python type +// information than SWIGTYPE_p_qvectorT_simpleline_t_t, and no +// proper Python 'strvec_t' proxy instance will be created. +typedef qvector strvec_t; + +// hexrays templates +%template(user_numforms_t) std::map; +%template(lvar_mapping_t) std::map; +%template(hexwarns_t) qvector; +%template(ctree_items_t) qvector; +%template(user_labels_t) std::map; +%template(user_cmts_t) std::map; +%template(user_iflags_t) std::map; +%template(user_unions_t) std::map; +%template(cinsnptrvec_t) qvector; +%template(eamap_t) std::map; +%template(boundaries_t) std::map; +// 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') +// - to override the destructor, the destructor must have the template parameters. +// 2) The '%ignore' directive. +// - Again, using the template name, but this time +// - 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); %} +%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. + // Therefore, we need to do the grunt work of de-registering ourselves. + // Note: The 'void' here is important: Without it, SWIG considers it to + // be a different destructor (which, of course, makes a ton of sense.) + ~qrefcnt_t(void) + { + hexrays_deregister_python_cfuncptr_t_instance($self); + delete $self; + } +} +%ignore qrefcnt_t::~qrefcnt_t(void); +%template(cfuncptr_t) qrefcnt_t; +%template(qvector_history_t) qvector; +%template(history_t) qstack; +typedef int iterator_word; + +/* no support for nested classes in swig means we need to wrap + this iterator and do some magic... + + to use it, call qlist< cinsn_t >::begin() which will return the + proper iterator type which can then be used to get the current item. +*/ +%{ +typedef qlist::iterator qlist_cinsn_t_iterator; +%} +class qlist_cinsn_t_iterator {}; +%extend qlist_cinsn_t_iterator { + const cinsn_t &cur { return *(*self); } + qlist_cinsn_t_iterator &next(void) { (*self)++; return *self; } +}; + +%extend qlist { + qlist_cinsn_t_iterator begin() { return self->begin(); } + qlist_cinsn_t_iterator end(void) { return self->end(); } + qlist_cinsn_t_iterator insert(qlist_cinsn_t_iterator p, const cinsn_t& x) { return self->insert(p, x); } + void erase(qlist_cinsn_t_iterator p) { self->erase(p); } +}; +%ignore qlist< cinsn_t >::insert(); +%ignore qlist< cinsn_t >::erase(); +%ignore qlist< cinsn_t >::begin(); +%ignore qlist< cinsn_t >::begin() const; +%ignore qlist< cinsn_t >::end(); +%ignore qlist< cinsn_t >::end() const; + +//%template(qvector_meminfo_t) qvector; +%template(qvector_lvar_t) qvector; +%template(qlist_cinsn_t) qlist; +%template(qvector_carg_t) qvector; +%template(qvector_ccase_t) qvector; + +%extend citem_cmt_t { + const char *c_str() const { return self->c_str(); } +}; + +void qswap(cinsn_t &a, cinsn_t &b); +%include "typemaps.i" + +%typemap(out) void +{ + Py_INCREF(Py_None); + $1obj = Py_None; +} + +%{ + +//------------------------------------------------------------------------- +qstring_printer_t *new_qstring_printer_t(const cfunc_t *f, bool tags) +{ + return new qstring_printer_t(f, * (new qstring()), tags); +} + +//------------------------------------------------------------------------- +void delete_qstring_printer_t(qstring_printer_t *qs) +{ + delete &(qs->s); + delete qs; +} + +//--------------------------------------------------------------------- +static int hexrays_python_call(ref_t fct, ref_t args) +{ + PYW_GIL_GET; + + int result; + int ecode1 = 0 ; + + newref_t resultobj(PyEval_CallObject(fct.o, args.o)); + if ( resultobj == NULL ) + { + msg("IDAPython: Hex-rays python callback raised an exception.\n"); + + // we can't do much else than clear the exception since this was not called from Python. + // XXX: print stack trace? + PyErr_Clear(); + return 0; + } + + ecode1 = SWIG_AsVal_int(resultobj.o, &result); + if (SWIG_IsOK(ecode1)) + return result; + + msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n"); + return 0; +} + +//--------------------------------------------------------------------- +static bool idaapi __python_custom_viewer_popup_item_callback(void *ud) +{ + PYW_GIL_GET; + + int ret; + borref_t fct((PyObject *)ud); + newref_t nil(NULL); + ret = hexrays_python_call(fct, nil); + return ret ? true : false; +} + +//--------------------------------------------------------------------- +static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_list va) +{ + PYW_GIL_GET; + + int ret; + borref_t fct((PyObject *)ud); + switch(event) + { + case hxe_maturity: + ///< Ctree maturity level is being changed. + ///< cfunc_t *cfunc + ///< ctree_maturity_t new_maturity + { + cfunc_t *arg0 = va_arg(va, cfunc_t *); + ctree_maturity_t arg1 = va_argi(va, ctree_maturity_t); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 )); + newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_interr: + ///< Internal error has occurred. + ///< int errcode + { + int arg0 = va_argi(va, int); + newref_t args(Py_BuildValue("(ii)", event, arg0)); + ret = hexrays_python_call(fct, args); + } + break; + + case hxe_print_func: + ///< Printing ctree and generating text. + ///< cfunc_t *cfunc + ///< vc_printer_t *vp + ///< Returns: 1 if text has been generated by the plugin + { + cfunc_t *arg0 = va_arg(va, cfunc_t *); + vc_printer_t *arg1 = va_arg(va, vc_printer_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_cfunc_t, 0 )); + newref_t arg1obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg1), SWIGTYPE_p_vc_printer_t, 0 )); + newref_t args(Py_BuildValue("(iOO)", event, arg0obj.o, arg1obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + + // User interface related events: + case hxe_open_pseudocode: + ///< New pseudocode view has been opened. + ///< vdui_t *vu + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_switch_pseudocode: + ///< Existing pseudocode view has been reloaded + ///< with a new function. Its text has not been + ///< refreshed yet, only cfunc and mba pointers are ready. + ///< vdui_t *vu + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_refresh_pseudocode: + ///< Existing pseudocode text has been refreshed. + ///< vdui_t *vu + ///< See also hxe_text_ready, which happens earlier + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_close_pseudocode: + ///< Pseudocode view is being closed. + ///< vdui_t *vu + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_keyboard: + ///< Keyboard has been hit. + ///< vdui_t *vu + ///< int key_code (VK_...) + ///< int shift_state + ///< Should return: 1 if the event has been handled + { + vdui_t *arg0 = va_arg(va, vdui_t *); + int arg1 = va_argi(va, int); + int arg2 = va_argi(va, int); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iOii)", event, arg0obj.o, arg1, arg2)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_right_click: + ///< Mouse right click. We can add menu items now. + ///< vdui_t *vu + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_double_click: + ///< Mouse double click. + ///< vdui_t *vu + ///< int shift_state + ///< Should return: 1 if the event has been handled + { + vdui_t *arg0 = va_arg(va, vdui_t *); + int arg1 = va_argi(va, int); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iOi)", event, arg0obj.o, arg1)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_curpos: + ///< Current cursor position has been changed. + ///< (for example, by left-clicking or using keyboard) + ///< vdui_t *vu + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_create_hint: + ///< Create a hint for the current item. + ///< vdui_t *vu + ///< qstring *result_hint + ///< int *implines + ///< Possible return values: + ///< 0: the event has not been handled + ///< 1: hint has been created (should set *implines to nonzero as well) + ///< 2: hint has been created but the standard hints must be + ///< appended by the decompiler + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + case hxe_text_ready: + ///< Decompiled text is ready. + ///< vdui_t *vu + ///< This event can be used to modify the output text (sv). + ///< The text uses regular color codes (see lines.hpp) + ///< COLOR_ADDR is used to store pointers to ctree elements + { + vdui_t *arg0 = va_arg(va, vdui_t *); + newref_t arg0obj(SWIG_NewPointerObj(SWIG_as_voidptr(arg0), SWIGTYPE_p_vdui_t, 0 )); + newref_t args(Py_BuildValue("(iO)", event, arg0obj.o)); + ret = hexrays_python_call(fct, args); + } + break; + default: + //~ msg("IDAPython: Unknown event `%u' occured\n", event); + ret = 0; + break; + } + + return ret; +} + +%} + +%ignore init_hexrays_plugin; +%rename(init_hexrays_plugin) __init_hexrays_plugin; + +%ignore add_custom_viewer_popup_item; +%rename(add_custom_viewer_popup_item) __add_custom_viewer_popup_item; + +%ignore install_hexrays_callback; +%rename(install_hexrays_callback) __install_hexrays_callback; + +%ignore remove_hexrays_callback; +%rename(remove_hexrays_callback) __remove_hexrays_callback; + +%inline %{ + +//--------------------------------------------------------------------- +extern hexdsp_t *hexdsp; +bool __init_hexrays_plugin(int flags=0) +{ + // Only initialize one time + if (hexdsp == NULL) + return init_hexrays_plugin(flags); + else + return true; +} + +//--------------------------------------------------------------------- +void __add_custom_viewer_popup_item( + TCustomControl *custom_viewer, + const char *title, + const char *hotkey, + PyObject *custom_viewer_popup_item_callback) +{ + PYW_GIL_GET; + Py_INCREF(custom_viewer_popup_item_callback); + add_custom_viewer_popup_item(custom_viewer, title, hotkey, __python_custom_viewer_popup_item_callback, custom_viewer_popup_item_callback); +}; + +//--------------------------------------------------------------------- +bool __install_hexrays_callback(PyObject *hx_cblist_callback) +{ + PYW_GIL_GET; + if (install_hexrays_callback(__hexrays_python_callback, hx_cblist_callback)) + { + Py_INCREF(hx_cblist_callback); + return true; + } + return false; +} + +//--------------------------------------------------------------------- +int __remove_hexrays_callback(PyObject *hx_cblist_callback) +{ + PYW_GIL_GET; + int result, i; + result = remove_hexrays_callback(__hexrays_python_callback, hx_cblist_callback); + for (i=0;i python_cfuncptrs; +void hexrays_clear_python_cfuncptr_t_references(void) +{ + for ( size_t i = 0, n = python_cfuncptrs.size(); i < n; ++i ) + python_cfuncptrs[i]->reset(); + // NOTE: Don't clear() the array of pointers. All the python-exposed + // cfuncptr_t instances will be deleted through the python + // shutdown/ref-decrementing process anyway, and the entries will be + // properly pulled out of the vector when that happens. +} + +void hexrays_register_python_cfuncptr_t_instance(cfuncptr_t *fp) +{ + QASSERT(30457, !python_cfuncptrs.has(fp)); + python_cfuncptrs.push_back(fp); +} + +void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp) +{ + qvector::iterator found = python_cfuncptrs.find(fp); + if ( found != python_cfuncptrs.end() ) + { + fp->reset(); + python_cfuncptrs.erase(found); + } +} + +%} + +//------------------------------------------------------------------------- +#if SWIG_VERSION == 0x20012 +%typemap(out) cfuncptr_t {} +%typemap(ret) cfuncptr_t +{ + // ret cfuncptr_t + cfuncptr_t *ni = new cfuncptr_t($1); + hexrays_register_python_cfuncptr_t_instance(ni); + $result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0); +} + + +%typemap(out) cfuncptr_t *{} +%typemap(ret) cfuncptr_t * +{ + // ret cfuncptr_t* + cfuncptr_t *ni = new cfuncptr_t(*($1)); + hexrays_register_python_cfuncptr_t_instance(ni); + $result = SWIG_NewPointerObj(ni, $1_descriptor, SWIG_POINTER_OWN | 0); +} +#else +#error Ensure cfuncptr_t wrapping is compatible with this version of SWIG +#endif + +%{ +cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf) +{ + try + { + cfuncptr_t cfunc = decompile(pfn, hf); + return cfunc; + } + catch(...) + { + error("Hex-Rays Python: decompiler threw an exception.\n"); + } + return cfuncptr_t(0); +} +%} + +cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf); +%ignore decompile; + +//--------------------------------------------------------------------- +%define %python_callback_in(CB) +%typemap(check) CB { + if (!PyCallable_Check($1)) + { + PyErr_SetString(PyExc_TypeError, "Need a callable object!"); + return NULL; + } +} +%enddef + +%python_callback_in(PyObject *hx_cblist_callback); +%python_callback_in(PyObject *custom_viewer_popup_item_callback); + +%ignore cexpr_t::get_1num_op(const cexpr_t **, const cexpr_t **) const; +#pragma SWIG nowarn=503 +%warnfilter(514) user_lvar_visitor_t; // Director base class 'x' has no virtual destructor. +%warnfilter(514) ctree_visitor_t; // ditto +%warnfilter(514) ctree_parentee_t; // ditto +%warnfilter(514) cfunc_parentee_t; // ditto +%warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended. +%feature("director") ctree_visitor_t; +%feature("director") ctree_parentee_t; +%feature("director") cfunc_parentee_t; +%feature("director") user_lvar_visitor_t; +%include "hexrays.hpp" + +%pythoncode %{ + +import idaapi + +hexrays_failure_t.__str__ = lambda self: str(self.str) + +# --------------------------------------------------------------------- +class DecompilationFailure(Exception): + """ Raised on a decompilation error. + + The associated hexrays_failure_t object is stored in the + 'info' member of this exception. """ + + def __init__(self, info): + Exception.__init__(self, 'Decompilation failed: %s' % (str(info), )) + self.info = info + return + +# --------------------------------------------------------------------- +def decompile(ea, hf=None): + if isinstance(ea, (int, long)): + func = idaapi.get_func(ea) + if not func: return + elif type(ea) == idaapi.func_t: + func = ea + else: + raise RuntimeError('arg 1 of decompile expects either ea_t or cfunc_t argument') + + if hf is None: + hf = hexrays_failure_t() + + ptr = _decompile(func, hf) + + if ptr.__deref__() is None: + raise DecompilationFailure(hf) + + return ptr + +# --------------------------------------------------------------------- +# stringify all string types +#qtype.__str__ = qtype.c_str +#qstring.__str__ = qstring.c_str +#citem_cmt_t.__str__ = citem_cmt_t.c_str + +# --------------------------------------------------------------------- +# listify all list types +_listify_types(cinsnptrvec_t, + ctree_items_t, + qvector_lvar_t, + qvector_carg_t, + qvector_ccase_t, + hexwarns_t, + history_t) + +def citem_to_specific_type(self): + """ cast the citem_t object to its more specific type, either cexpr_t or cinsn_t. """ + + if self.op >= cot_empty and self.op <= cot_last: + return self.cexpr + elif self.op >= cit_empty and self.op < cit_end: + return self.cinsn + + raise RuntimeError('unknown op type %s' % (repr(self.op), )) +citem_t.to_specific_type = property(citem_to_specific_type) + +""" array used for translating cinsn_t->op type to their names. """ +cinsn_t.op_to_typename = {} +for k in dir(_idaapi): + if k.startswith('cit_'): + cinsn_t.op_to_typename[getattr(_idaapi, k)] = k[4:] + +""" array used for translating cexpr_t->op type to their names. """ +cexpr_t.op_to_typename = {} +for k in dir(_idaapi): + if k.startswith('cot_'): + cexpr_t.op_to_typename[getattr(_idaapi, k)] = k[4:] + +def property_op_to_typename(self): + return self.op_to_typename[self.op] +cinsn_t.opname = property(property_op_to_typename) +cexpr_t.opname = property(property_op_to_typename) + +def cexpr_operands(self): + """ return a dictionary with the operands of a cexpr_t. """ + + if self.op >= cot_comma and self.op <= cot_asgumod or \ + self.op >= cot_lor and self.op <= cot_fdiv or \ + self.op == cot_idx: + return {'x': self.x, 'y': self.y} + + elif self.op == cot_tern: + return {'x': self.x, 'y': self.y, 'z': self.z} + + elif self.op in [cot_fneg, cot_neg, cot_sizeof] or \ + self.op >= cot_lnot and self.op <= cot_predec: + return {'x': self.x} + + elif self.op == cot_cast: + return {'type': self.type, 'x': self.x} + + elif self.op == cot_call: + return {'x': self.x, 'a': self.a} + + elif self.op in [cot_memref, cot_memptr]: + return {'x': self.x, 'm': self.m} + + elif self.op == cot_num: + return {'n': self.n} + + elif self.op == cot_fnum: + return {'fpc': self.fpc} + + elif self.op == cot_str: + return {'string': self.string} + + elif self.op == cot_obj: + return {'obj_ea': self.obj_ea} + + elif self.op == cot_var: + return {'v': self.v} + + elif self.op == cot_helper: + return {'helper': self.helper} + + raise RuntimeError('unknown op type %s' % self.opname) +cexpr_t.operands = property(cexpr_operands) + +def cinsn_details(self): + """ return the details pointer for the cinsn_t object depending on the value of its op member. \ + this is one of the cblock_t, cif_t, etc. objects. """ + + if self.op not in self.op_to_typename: + raise RuntimeError('unknown item->op type') + + opname = self.opname + if opname == 'empty': + return self + + if opname in ['break', 'continue']: + return None + + return getattr(self, 'c' + opname) +cinsn_t.details = property(cinsn_details) + +def cblock_iter(self): + + iter = self.begin() + for i in range(self.size()): + yield iter.cur + iter.next() + + return +cblock_t.__iter__ = cblock_iter +cblock_t.__len__ = cblock_t.size + +# cblock.find(cinsn_t) -> returns the iterator positioned at the given item +def cblock_find(self, item): + + iter = self.begin() + for i in range(self.size()): + if iter.cur == item: + return iter + iter.next() + + return +cblock_t.find = cblock_find + +# cblock.index(cinsn_t) -> returns the index of the given item +def cblock_index(self, item): + + iter = self.begin() + for i in range(self.size()): + if iter.cur == item: + return i + iter.next() + + return +cblock_t.index = cblock_index + +# cblock.at(int) -> returns the item at the given index index +def cblock_at(self, index): + + iter = self.begin() + for i in range(self.size()): + if i == index: + return iter.cur + iter.next() + + return +cblock_t.at = cblock_at + +# cblock.remove(cinsn_t) +def cblock_remove(self, item): + + iter = self.find(item) + self.erase(iter) + + return +cblock_t.remove = cblock_remove + +# cblock.insert(index, cinsn_t) +def cblock_insert(self, index, item): + + pos = self.at(index) + iter = self.find(pos) + self.insert(iter, item) + + return +cblock_t.insert = cblock_insert + +cfuncptr_t.__str__ = lambda self: str(self.__deref__()) + +def cfunc_type(self): + """ Get the function's return type tinfo_t object. """ + tif = tinfo_t() + result = self.get_func_type(tif) + if not result: + return + return tif +cfunc_t.type = property(cfunc_type) +cfuncptr_t.type = property(lambda self: self.__deref__().type) + +cfunc_t.arguments = property(lambda self: [o for o in self.lvars if o.is_arg_var]) +cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments) + +cfunc_t.lvars = property(cfunc_t.get_lvars) +cfuncptr_t.lvars = property(lambda self: self.__deref__().lvars) +cfunc_t.warnings = property(cfunc_t.get_warnings) +cfuncptr_t.warnings = property(lambda self: self.__deref__().warnings) +cfunc_t.pseudocode = property(cfunc_t.get_pseudocode) +cfuncptr_t.pseudocode = property(lambda self: self.__deref__().get_pseudocode()) +cfunc_t.eamap = property(cfunc_t.get_eamap) +cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap()) +cfunc_t.boundaries = property(cfunc_t.get_boundaries) +cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries()) + +#pragma SWIG nowarn=+503 + +lvar_t.used = property(lvar_t.used) +lvar_t.typed = property(lvar_t.typed) +lvar_t.mreg_done = property(lvar_t.mreg_done) +lvar_t.has_nice_name = property(lvar_t.has_nice_name) +lvar_t.is_unknown_width = property(lvar_t.is_unknown_width) +lvar_t.has_user_info = property(lvar_t.has_user_info) +lvar_t.has_user_name = property(lvar_t.has_user_name) +lvar_t.has_user_type = property(lvar_t.has_user_type) +lvar_t.is_result_var = property(lvar_t.is_result_var) +lvar_t.is_arg_var = property(lvar_t.is_arg_var) +lvar_t.is_fake_var = property(lvar_t.is_fake_var) +lvar_t.is_overlapped_var = property(lvar_t.is_overlapped_var) +lvar_t.is_floating_var = property(lvar_t.is_floating_var) +lvar_t.is_spoiled_var = property(lvar_t.is_spoiled_var) +lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var) + +# dictify all dict-like types + +def _map___getitem__(self, key): + """ Returns the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of key should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + return self.second(self.find(key)) + +def _map___setitem__(self, key, value): + """ Returns the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if not isinstance(value, self.valuetype): + raise KeyError('type of `value` should be ' + repr(self.valuetype) + ' but got ' + type(value)) + self.insert(key, value) + return + +def _map___delitem__(self, key): + """ Removes the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + self.erase(self.find(key)) + return + +def _map___contains__(self, key): + """ Returns true if the specified key exists in the . """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if self.find(key) != self.end(): + return True + return False + +def _map_clear(self): + self.clear() + return + +def _map_copy(self): + ret = {} + for k in self.iterkeys(): + ret[k] = self[k] + return ret + +def _map_get(self, key, default=None): + if key in self: + return self[key] + return default + +def _map_iterkeys(self): + iter = self.begin() + while iter != self.end(): + yield self.first(iter) + iter = self.next(iter) + return + +def _map_itervalues(self): + iter = self.begin() + while iter != self.end(): + yield self.second(iter) + iter = self.next(iter) + return + +def _map_iteritems(self): + iter = self.begin() + while iter != self.end(): + yield (self.first(iter), self.second(iter)) + iter = self.next(iter) + return + +def _map_keys(self): + return list(self.iterkeys()) + +def _map_values(self): + return list(self.itervalues()) + +def _map_items(self): + return list(self.iteritems()) + +def _map_has_key(self, key): + return key in self + +def _map_pop(self, key): + """ Sets the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key not in self: + raise KeyError('key not found') + ret = self[key] + del self[key] + return ret + +def _map_popitem(self): + """ Sets the value associated with the provided key. """ + if len(self) == 0: + raise KeyError('key not found') + key = self.keys()[0] + return (key, self.pop(key)) + +def _map_setdefault(self, key, default=None): + """ Sets the value associated with the provided key. """ + if not isinstance(key, self.keytype): + raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key))) + if key in self: + return self[key] + self[key] = default + return default + +def _map_as_dict(maptype, name, keytype, valuetype): + + maptype.keytype = keytype + maptype.valuetype = valuetype + + for fctname in ['begin', 'end', 'first', 'second', 'next', \ + 'find', 'insert', 'erase', 'clear', 'size']: + fct = getattr(_idaapi, name + '_' + fctname) + setattr(maptype, '__' + fctname, fct) + + maptype.__len__ = maptype.size + maptype.__getitem__ = maptype.at + + maptype.begin = lambda self, *args: self.__begin(self, *args) + maptype.end = lambda self, *args: self.__end(self, *args) + maptype.first = lambda self, *args: self.__first(*args) + maptype.second = lambda self, *args: self.__second(*args) + maptype.next = lambda self, *args: self.__next(*args) + maptype.find = lambda self, *args: self.__find(self, *args) + maptype.insert = lambda self, *args: self.__insert(self, *args) + maptype.erase = lambda self, *args: self.__erase(self, *args) + maptype.clear = lambda self, *args: self.__clear(self, *args) + maptype.size = lambda self, *args: self.__size(self, *args) + maptype.__getitem__ = _map___getitem__ + maptype.__setitem__ = _map___setitem__ + maptype.__delitem__ = _map___delitem__ + maptype.__contains__ = _map___contains__ + maptype.clear = _map_clear + maptype.copy = _map_copy + maptype.get = _map_get + maptype.iterkeys = _map_iterkeys + maptype.itervalues = _map_itervalues + maptype.iteritems = _map_iteritems + maptype.keys = _map_keys + maptype.values = _map_values + maptype.items = _map_items + maptype.has_key = _map_has_key + maptype.pop = _map_pop + maptype.popitem = _map_popitem + maptype.setdefault = _map_setdefault + +#_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring) +_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t) +_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t) +_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, (int, long)) +_map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t) +_map_as_dict(eamap_t, 'eamap', int, cinsnptrvec_t) +#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t) + +%} diff --git a/swig/idaapi.i b/swig/idaapi.i index 89638cc..9de2edb 100644 --- a/swig/idaapi.i +++ b/swig/idaapi.i @@ -25,10 +25,12 @@ %inline %{ static PyObject *type##_create() { + PYW_GIL_CHECK_LOCKED_SCOPE(); return PyCObject_FromVoidPtr(new type(), NULL); } static bool type##_destroy(PyObject *py_obj) { + PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyCObject_Check(py_obj) ) return false; delete (type *)PyCObject_AsVoidPtr(py_obj); @@ -36,11 +38,14 @@ static bool type##_destroy(PyObject *py_obj) } static type *type##_get_clink(PyObject *self) { + PYW_GIL_CHECK_LOCKED_SCOPE(); return (type *)pyobj_get_clink(self); } static PyObject *type##_get_clink_ptr(PyObject *self) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)pyobj_get_clink(self)); + PYW_GIL_CHECK_LOCKED_SCOPE(); + return PyLong_FromUnsignedLongLong( + (unsigned PY_LONG_LONG)pyobj_get_clink(self)); } %} %enddef @@ -2266,6 +2271,12 @@ class object_t(object): """Allow access to object attributes by index (like dictionaries)""" return getattr(self, idx) +# ----------------------------------------------------------------------- +def _bounded_getitem_iterator(self): + """Helper function, to be set as __iter__ method for qvector-, or array-based classes.""" + for i in range(len(self)): + yield self[i] + # ----------------------------------------------------------------------- class plugin_t(pyidc_opaque_object_t): """Base class for all scripted plugins.""" @@ -2332,72 +2343,79 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__): # ----------------------------------------------------------------------- # qstrvec_t clinked object -# class qstrvec_t(py_clinked_object_t): -# """Class representing an qstrvec_t""" +class _qstrvec_t(py_clinked_object_t): + """ + WARNING: It is very unlikely an IDAPython user should ever, ever + have to use this type. It should only be used for IDAPython internals. -# def __init__(self, items=None): -# py_clinked_object_t.__init__(self) -# # Populate the list if needed -# if items: -# self.from_list(items) + For example, in py_askusingform.py, we ctypes-expose to the IDA + kernel & UI a qstrvec instance, in case a DropdownListControl is + constructed. + That's because that's what AskUsingForm expects, and we have no + choice but to make a DropdownListControl hold a qstrvec_t. + This is, afaict, the only situation where a Python + _qstrvec_t is required. + """ -# def _create_clink(self): -# return _idaapi.qstrvec_t_create() + def __init__(self, items=None): + py_clinked_object_t.__init__(self) + # Populate the list if needed + if items: + self.from_list(items) -# def _del_clink(self, lnk): -# return _idaapi.qstrvec_t_destroy(lnk) + def _create_clink(self): + return _idaapi.qstrvec_t_create() -# def _get_clink_ptr(self): -# return _idaapi.qstrvec_t_get_clink_ptr(self) + def _del_clink(self, lnk): + return _idaapi.qstrvec_t_destroy(lnk) -# def assign(self, other): -# """Copies the contents of 'other' to 'self'""" -# return _idaapi.qstrvec_t_assign(self, other) + def _get_clink_ptr(self): + return _idaapi.qstrvec_t_get_clink_ptr(self) -# def __setitem__(self, idx, s): -# """Sets string at the given index""" -# return _idaapi.qstrvec_t_set(self, idx, s) + def assign(self, other): + """Copies the contents of 'other' to 'self'""" + return _idaapi.qstrvec_t_assign(self, other) -# def __getitem__(self, idx): -# """Gets the string at the given index""" -# return _idaapi.qstrvec_t_get(self, idx) + def __setitem__(self, idx, s): + """Sets string at the given index""" + return _idaapi.qstrvec_t_set(self, idx, s) -# def __get_size(self): -# return _idaapi.qstrvec_t_size(self) + def __getitem__(self, idx): + """Gets the string at the given index""" + return _idaapi.qstrvec_t_get(self, idx) -# size = property(__get_size) -# """Returns the count of elements""" + def __get_size(self): + return _idaapi.qstrvec_t_size(self) -# def addressof(self, idx): -# """Returns the address (as number) of the qstring at the given index""" -# return _idaapi.qstrvec_t_addressof(self, idx) + size = property(__get_size) + """Returns the count of elements""" -# def add(self, s): -# """Add a string to the vector""" -# return _idaapi.qstrvec_t_add(self, s) + def addressof(self, idx): + """Returns the address (as number) of the qstring at the given index""" + return _idaapi.qstrvec_t_addressof(self, idx) + def add(self, s): + """Add a string to the vector""" + return _idaapi.qstrvec_t_add(self, s) -# def from_list(self, lst): -# """Populates the vector from a Python string list""" -# return _idaapi.qstrvec_t_from_list(self, lst) + def from_list(self, lst): + """Populates the vector from a Python string list""" + return _idaapi.qstrvec_t_from_list(self, lst) + def clear(self, qclear=False): + """ + Clears all strings from the vector. + @param qclear: Just reset the size but do not actually free the memory + """ + return _idaapi.qstrvec_t_clear(self, qclear) -# def clear(self, qclear=False): -# """ -# Clears all strings from the vector. -# @param qclear: Just reset the size but do not actually free the memory -# """ -# return _idaapi.qstrvec_t_clear(self, qclear) + def insert(self, idx, s): + """Insert a string into the vector""" + return _idaapi.qstrvec_t_insert(self, idx, s) - -# def insert(self, idx, s): -# """Insert a string into the vector""" -# return _idaapi.qstrvec_t_insert(self, idx, s) - - -# def remove(self, idx): -# """Removes a string from the vector""" -# return _idaapi.qstrvec_t_remove(self, idx) + def remove(self, idx): + """Removes a string from the vector""" + return _idaapi.qstrvec_t_remove(self, idx) # ----------------------------------------------------------------------- class PyIdc_cvt_refclass__(pyidc_cvt_helper__): @@ -2678,6 +2696,12 @@ class __IDAPython_Completion_Util(object): # Instantiate a completion object IDAPython_Completion = __IDAPython_Completion_Util() +def _listify_types(*classes): + for cls in classes: + cls.__getitem__ = cls.at + cls.__len__ = cls.size + cls.__iter__ = _bounded_getitem_iterator + # The general callback format of notify_when() is: @@ -2744,10 +2768,13 @@ NW_REMOVE = 0x0010 %include "fixup.i" %include "frame.i" %include "funcs.i" +%include "typeinf.i" #ifdef WITH_HEXRAYS %include "hexrays.i" #endif +SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t) + %inline %{ // @@ -2852,12 +2879,9 @@ def RunPythonStatement(stmt): # */ -/* //--------------------------------------------------------------------------- -// qstrvec_t wrapper +// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py) //--------------------------------------------------------------------------- -DECLARE_PY_CLINKED_OBJECT(qstrvec_t); - static bool qstrvec_t_assign(PyObject *self, PyObject *other) { qstrvec_t *lhs = qstrvec_t_get_clink(self); @@ -2959,7 +2983,7 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx) sv->erase(sv->begin()+idx); return true; } -*/ + //--------------------------------------------------------------------------- @@ -3006,7 +3030,6 @@ static bool notify_when(int when, PyObject *py_callable) %include "srarea.i" %include "strlist.i" %include "struct.i" -%include "typeinf.i" %include "ua.i" %include "xref.i" %include "view.i" diff --git a/swig/idp.i b/swig/idp.i index c1c4def..6caa2f1 100644 --- a/swig/idp.i +++ b/swig/idp.i @@ -42,6 +42,23 @@ %include "idp.hpp" %feature("director") IDB_Hooks; %feature("director") IDP_Hooks; + +%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; + else if ( $self == &SRareas ) + t = AREACB_TYPE_SRAREA; + return t; + } +} + %inline %{ // @@ -849,6 +866,15 @@ public: } }; +enum areacb_type_t +{ + AREACB_TYPE_UNKNOWN, + AREACB_TYPE_FUNC, + AREACB_TYPE_SEGMENT, + AREACB_TYPE_HIDDEN_AREA, + AREACB_TYPE_SRAREA, +}; + //--------------------------------------------------------------------------- // IDB hooks //--------------------------------------------------------------------------- @@ -869,8 +895,9 @@ public: // Hook functions to override in Python virtual int byte_patched(ea_t /*ea*/) { return 0; }; virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }; - virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("ti_changed hook not supported yet\n"); return 0; }; - virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("op_ti_changed hook not supported yet\n"); return 0; }; + virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; } + virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }; + virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }; virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }; virtual int enum_created(enum_t /*id*/) { return 0; }; virtual int enum_deleted(enum_t /*id*/) { return 0; }; @@ -1408,8 +1435,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va) class IDB_Hooks *proxy = (class IDB_Hooks *)ud; ea_t ea, ea2; bool repeatable_cmt; - /*type_t *type;*/ - /* p_list *fnames; */ + type_t *type; + p_list *fnames; int n; enum_t id; const_t cid; @@ -1425,152 +1452,161 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va) try { switch (notification_code) { - case idb_event::byte_patched: - ea = va_arg(va, ea_t); - return proxy->byte_patched(ea); + case idb_event::byte_patched: + ea = va_arg(va, ea_t); + return proxy->byte_patched(ea); - case idb_event::cmt_changed: - ea = va_arg(va, ea_t); - repeatable_cmt = va_arg(va, int); - return proxy->cmt_changed(ea, repeatable_cmt); -#if 0 - case idb_event::ti_changed: - ea = va_arg(va, ea_t); - type = va_arg(va, type_t *); - fnames = va_arg(va, fnames); - return proxy->ti_changed(ea, type, fnames); + case idb_event::cmt_changed: + ea = va_arg(va, ea_t); + repeatable_cmt = va_arg(va, int); + return proxy->cmt_changed(ea, repeatable_cmt); - case idb_event::op_ti_changed: - ea = va_arg(va, ea_t); - n = va_arg(va, int); - type = va_arg(va, type_t *); - fnames = va_arg(va, fnames); - return proxy->op_ti_changed(ea, n, type, fnames); -#endif - case idb_event::op_type_changed: - ea = va_arg(va, ea_t); - n = va_arg(va, int); - return proxy->op_type_changed(ea, n); + case idb_event::area_cmt_changed: + { + areacb_t *cb = va_arg(va, areacb_t*); + area_t *area = va_arg(va, area_t*); + const char *cmt = va_arg(va, char*); + repeatable_cmt = va_arg(va, int); + return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt); + } - case idb_event::enum_created: - id = va_arg(va, enum_t); - return proxy->enum_created(id); + case idb_event::ti_changed: + ea = va_arg(va, ea_t); + type = va_arg(va, type_t *); + fnames = va_arg(va, p_list *); + return proxy->ti_changed(ea, type, fnames); - case idb_event::enum_deleted: - id = va_arg(va, enum_t); - return proxy->enum_deleted(id); + case idb_event::op_ti_changed: + ea = va_arg(va, ea_t); + n = va_arg(va, int); + type = va_arg(va, type_t *); + fnames = va_arg(va, p_list *); + return proxy->op_ti_changed(ea, n, type, fnames); - case idb_event::enum_bf_changed: - id = va_arg(va, enum_t); - return proxy->enum_bf_changed(id); + case idb_event::op_type_changed: + ea = va_arg(va, ea_t); + n = va_arg(va, int); + return proxy->op_type_changed(ea, n); - case idb_event::enum_cmt_changed: - id = va_arg(va, enum_t); - return proxy->enum_cmt_changed(id); + case idb_event::enum_created: + id = va_arg(va, enum_t); + return proxy->enum_created(id); + + case idb_event::enum_deleted: + id = va_arg(va, enum_t); + return proxy->enum_deleted(id); + + case idb_event::enum_bf_changed: + id = va_arg(va, enum_t); + return proxy->enum_bf_changed(id); + + case idb_event::enum_cmt_changed: + id = va_arg(va, enum_t); + return proxy->enum_cmt_changed(id); #ifdef NO_OBSOLETE_FUNCS - case idb_event::enum_member_created: + case idb_event::enum_member_created: #else - case idb_event::enum_const_created: + case idb_event::enum_const_created: #endif - id = va_arg(va, enum_t); - cid = va_arg(va, const_t); - return proxy->enum_member_created(id, cid); + id = va_arg(va, enum_t); + cid = va_arg(va, const_t); + return proxy->enum_member_created(id, cid); #ifdef NO_OBSOLETE_FUNCS - case idb_event::enum_member_deleted: + case idb_event::enum_member_deleted: #else - case idb_event::enum_const_deleted: + case idb_event::enum_const_deleted: #endif - id = va_arg(va, enum_t); - cid = va_arg(va, const_t); - return proxy->enum_member_deleted(id, cid); + id = va_arg(va, enum_t); + cid = va_arg(va, const_t); + return proxy->enum_member_deleted(id, cid); - case idb_event::struc_created: - struc_id = va_arg(va, tid_t); - return proxy->struc_created(struc_id); + case idb_event::struc_created: + struc_id = va_arg(va, tid_t); + return proxy->struc_created(struc_id); - case idb_event::struc_deleted: - struc_id = va_arg(va, tid_t); - return proxy->struc_deleted(struc_id); + case idb_event::struc_deleted: + struc_id = va_arg(va, tid_t); + return proxy->struc_deleted(struc_id); - case idb_event::struc_renamed: - sptr = va_arg(va, struc_t *); - return proxy->struc_renamed(sptr); + case idb_event::struc_renamed: + sptr = va_arg(va, struc_t *); + return proxy->struc_renamed(sptr); - case idb_event::struc_expanded: - sptr = va_arg(va, struc_t *); - return proxy->struc_expanded(sptr); + case idb_event::struc_expanded: + sptr = va_arg(va, struc_t *); + return proxy->struc_expanded(sptr); - case idb_event::struc_cmt_changed: - struc_id = va_arg(va, tid_t); - return proxy->struc_cmt_changed(struc_id); + case idb_event::struc_cmt_changed: + struc_id = va_arg(va, tid_t); + return proxy->struc_cmt_changed(struc_id); - case idb_event::struc_member_created: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_created(sptr, mptr); + case idb_event::struc_member_created: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_created(sptr, mptr); - case idb_event::struc_member_deleted: - sptr = va_arg(va, struc_t *); - member_id = va_arg(va, tid_t); - ea = va_arg(va, ea_t); - return proxy->struc_member_deleted(sptr, member_id, ea); + case idb_event::struc_member_deleted: + sptr = va_arg(va, struc_t *); + member_id = va_arg(va, tid_t); + ea = va_arg(va, ea_t); + return proxy->struc_member_deleted(sptr, member_id, ea); - case idb_event::struc_member_renamed: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_renamed(sptr, mptr); + case idb_event::struc_member_renamed: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_renamed(sptr, mptr); - case idb_event::struc_member_changed: - sptr = va_arg(va, struc_t *); - mptr = va_arg(va, member_t *); - return proxy->struc_member_changed(sptr, mptr); + case idb_event::struc_member_changed: + sptr = va_arg(va, struc_t *); + mptr = va_arg(va, member_t *); + return proxy->struc_member_changed(sptr, mptr); - case idb_event::thunk_func_created: - pfn = va_arg(va, func_t *); - return proxy->thunk_func_created(pfn); + case idb_event::thunk_func_created: + pfn = va_arg(va, func_t *); + return proxy->thunk_func_created(pfn); - case idb_event::func_tail_appended: - pfn = va_arg(va, func_t *); - tail = va_arg(va, func_t *); - return proxy->func_tail_appended(pfn, tail); + case idb_event::func_tail_appended: + pfn = va_arg(va, func_t *); + tail = va_arg(va, func_t *); + return proxy->func_tail_appended(pfn, tail); - case idb_event::func_tail_removed: - pfn = va_arg(va, func_t *); - ea = va_arg(va, ea_t); - return proxy->func_tail_removed(pfn, ea); + case idb_event::func_tail_removed: + pfn = va_arg(va, func_t *); + ea = va_arg(va, ea_t); + return proxy->func_tail_removed(pfn, ea); - case idb_event::tail_owner_changed: - tail = va_arg(va, func_t *); - ea = va_arg(va, ea_t); - return proxy->tail_owner_changed(tail, ea); + case idb_event::tail_owner_changed: + tail = va_arg(va, func_t *); + ea = va_arg(va, ea_t); + return proxy->tail_owner_changed(tail, ea); - case idb_event::func_noret_changed: - pfn = va_arg(va, func_t *); - return proxy->func_noret_changed(pfn); + case idb_event::func_noret_changed: + pfn = va_arg(va, func_t *); + return proxy->func_noret_changed(pfn); - case idb_event::segm_added: - seg = va_arg(va, segment_t *); - return proxy->segm_added(seg); + case idb_event::segm_added: + seg = va_arg(va, segment_t *); + return proxy->segm_added(seg); - case idb_event::segm_deleted: - ea = va_arg(va, ea_t); - return proxy->segm_deleted(ea); + case idb_event::segm_deleted: + ea = va_arg(va, ea_t); + return proxy->segm_deleted(ea); - case idb_event::segm_start_changed: - seg = va_arg(va, segment_t *); - return proxy->segm_start_changed(seg); + case idb_event::segm_start_changed: + seg = va_arg(va, segment_t *); + return proxy->segm_start_changed(seg); - case idb_event::segm_end_changed: - seg = va_arg(va, segment_t *); - return proxy->segm_end_changed(seg); + case idb_event::segm_end_changed: + seg = va_arg(va, segment_t *); + return proxy->segm_end_changed(seg); - case idb_event::segm_moved: - ea = va_arg(va, ea_t); - ea2 = va_arg(va, ea_t); - size = va_arg(va, asize_t); - return proxy->segm_moved(ea, ea2, size); + case idb_event::segm_moved: + ea = va_arg(va, ea_t); + ea2 = va_arg(va, ea_t); + size = va_arg(va, asize_t); + return proxy->segm_moved(ea, ea2, size); } } catch (Swig::DirectorException &e) diff --git a/swig/kernwin.i b/swig/kernwin.i index 43bb3d9..0ad12a4 100644 --- a/swig/kernwin.i +++ b/swig/kernwin.i @@ -43,7 +43,6 @@ %ignore restore_database_snapshot; %ignore destroy_custom_viewer; %ignore destroy_custom_viewerdestroy_custom_viewer; -%ignore get_custom_viewer_place; %ignore set_custom_viewer_popup_menu; %ignore set_custom_viewer_handler; %ignore set_custom_viewer_range; @@ -72,18 +71,12 @@ %rename (asktext) py_asktext; %rename (str2ea) py_str2ea; %rename (str2user) py_str2user; - %ignore process_ui_action; %rename (process_ui_action) py_process_ui_action; - -%ignore exec_request_t; - %ignore execute_sync; +%ignore exec_request_t; %rename (execute_sync) py_execute_sync; -%ignore read_selection; -%rename (read_selection) py_read_selection; - %ignore ui_request_t; %ignore execute_ui_requests; %rename (execute_ui_requests) py_execute_ui_requests; @@ -136,39 +129,12 @@ void refresh_lists(void) # This is for get_cursor() %apply int *OUTPUT {int *x, int *y}; -# This is for read_selection() -%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 }; - SWIG_DECLARE_PY_CLINKED_OBJECT(textctrl_info_t) %inline %{ // //------------------------------------------------------------------------ -//------------------------------------------------------------------------ -/* -# -def read_selection(): - """ - Returns selected area boundaries - - @return: tuple(ok: bool, start_ea, end_ea) - """ - pass -# -*/ -static PyObject *py_read_selection() -{ - ea_t ea1, ea2; - bool b = read_selection(&ea1, &ea2); - - PYW_GIL_CHECK_LOCKED_SCOPE(); - return Py_BuildValue( - "(i" PY_FMT64 PY_FMT64 ")", - b ? 1 : 0, - pyul_t(ea1), pyul_t(ea2)); -} - //------------------------------------------------------------------------ /* # @@ -343,6 +309,45 @@ def free_custom_icon(icon_id): # */ +//------------------------------------------------------------------------- +/* +# +def readsel2(view, p0, p1): + """ + Read the user selection, and store its information in p0 (from) and p1 (to). + + This can be used as follows: + + + >>> p0 = idaapi.twinpos_t() + p1 = idaapi.twinpos_t() + view = idaapi.get_current_viewer() + idaapi.readsel2(view, p0, p1) + + + At that point, p0 and p1 hold information for the selection. + But, the 'at' property of p0 and p1 is not properly typed. + To specialize it, call #place() on it, passing it the view + they were retrieved from. Like so: + + + >>> place0 = p0.place(view) + place1 = p1.place(view) + + + This will effectively "cast" the place into a specialized type, + holding proper information, depending on the view type (e.g., + disassembly, structures, enums, ...) + + @param view: The view to retrieve the selection for. + @param p0: Storage for the "from" part of the selection. + @param p1: Storage for the "to" part of the selection. + @return: a bool value indicating success. + """ + pass +# +*/ + //------------------------------------------------------------------------ /* # @@ -1086,8 +1091,6 @@ PyObject *choose2_get_embedded_selection(PyObject *self); #define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa; //--------------------------------------------------------------------------- -DECLARE_PY_CLINKED_OBJECT(textctrl_info_t); - static bool textctrl_info_t_assign(PyObject *self, PyObject *other) { textctrl_info_t *lhs = textctrl_info_t_get_clink(self); @@ -1222,20 +1225,21 @@ static PyObject *formchgcbfa_get_field_value( PYW_GIL_CHECK_LOCKED_SCOPE(); switch ( ft ) { + // dropdown list case 8: { // Readonly? Then return the selected index if ( sz == 1 ) { int sel_idx; - if ( fa->get_field_value(fid, &sel_idx) ) + if ( fa->get_combobox_value(fid, &sel_idx) ) return PyLong_FromLong(sel_idx); } // Not readonly? Then return the qstring else { qstring val; - if ( fa->get_field_value(fid, &val) ) + if ( fa->get_combobox_value(fid, &val) ) return PyString_FromString(val.c_str()); } break; @@ -1244,15 +1248,15 @@ static PyObject *formchgcbfa_get_field_value( case 7: { textctrl_info_t ti; - if ( fa->get_field_value(fid, &ti) ) + if ( fa->get_text_value(fid, &ti) ) return Py_BuildValue("(sII)", ti.text.c_str(), ti.flags, ti.tabsize); break; } // button - uint32 case 4: { - uint32 val; - if ( fa->get_field_value(fid, &val) ) + uval_t val; + if ( fa->get_unsigned_value(fid, &val) ) return PyLong_FromUnsignedLong(val); break; } @@ -1260,7 +1264,7 @@ static PyObject *formchgcbfa_get_field_value( case 2: { ushort val; - if ( fa->get_field_value(fid, &val) ) + if ( fa->_get_field_value(fid, &val) ) return PyLong_FromUnsignedLong(val); break; } @@ -1268,7 +1272,7 @@ static PyObject *formchgcbfa_get_field_value( case 1: { char val[MAXSTR]; - if ( fa->get_field_value(fid, val) ) + if ( fa->get_ascii_value(fid, val, sizeof(val)) ) return PyString_FromString(val); break; } @@ -1277,7 +1281,7 @@ static PyObject *formchgcbfa_get_field_value( { qstring val; val.resize(sz + 1); - if ( fa->get_field_value(fid, val.begin()) ) + if ( fa->get_ascii_value(fid, val.begin(), val.size()) ) return PyString_FromString(val.begin()); break; } @@ -1285,12 +1289,11 @@ static PyObject *formchgcbfa_get_field_value( { intvec_t intvec; // Returned as 1-base - if (fa->get_field_value(fid, &intvec)) + if (fa->get_chooser_value(fid, &intvec)) { // Make 0-based for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it) (*it)--; - ref_t l(PyW_IntVecToPyList(intvec)); l.incref(); return l.o; @@ -1311,33 +1314,38 @@ static PyObject *formchgcbfa_get_field_value( { case 'S': // sel_t { - if ( fa->get_field_value(fid, &u.sel) ) + if ( fa->get_segment_value(fid, &u.sel) ) return Py_BuildValue(PY_FMT64, u.sel); break; } // sval_t case 'n': - case 'N': case 'D': case 'O': case 'Y': case 'H': { - if ( fa->get_field_value(fid, &u.sval) ) + if ( fa->get_signed_value(fid, &u.sval) ) return Py_BuildValue(PY_SFMT64, u.sval); break; } case 'L': // uint64 case 'l': // int64 { - if ( fa->get_field_value(fid, &u.ull) ) - return Py_BuildValue(sz == 'L' ? "K" : "L", u.ull); + if ( fa->_get_field_value(fid, &u.ull) ) + return Py_BuildValue("K", u.ull); break; } + case 'N': case 'M': // uval_t + { + if ( fa->get_unsigned_value(fid, &u.uval) ) + return Py_BuildValue(PY_FMT64, u.uval); + break; + } case '$': // ea_t { - if ( fa->get_field_value(fid, &u.uval) ) + if ( fa->get_ea_value(fid, &u.uval) ) return Py_BuildValue(PY_FMT64, u.uval); break; } @@ -1367,13 +1375,13 @@ static bool formchgcbfa_set_field_value( if ( PyString_Check(py_val) ) { qstring val(PyString_AsString(py_val)); - return fa->set_field_value(fid, &val); + return fa->set_combobox_value(fid, &val); } // Readonly dropdown list else { int sel_idx = PyLong_AsLong(py_val); - return fa->set_field_value(fid, &sel_idx); + return fa->set_combobox_value(fid, &sel_idx); } break; } @@ -1381,24 +1389,24 @@ static bool formchgcbfa_set_field_value( case 7: { textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(py_val); - return ti == NULL ? false : fa->set_field_value(fid, ti); + return ti == NULL ? false : fa->set_text_value(fid, ti); } // button - uint32 case 4: { - uint32 val = PyLong_AsUnsignedLong(py_val); - return fa->set_field_value(fid, &val); + uval_t val = PyLong_AsUnsignedLong(py_val); + return fa->set_unsigned_value(fid, &val); } // ushort case 2: { ushort val = PyLong_AsUnsignedLong(py_val) & 0xffff; - return fa->set_field_value(fid, &val); + return fa->_set_field_value(fid, &val); } // strings case 3: case 1: - return fa->set_field_value(fid, PyString_AsString(py_val)); + return fa->set_ascii_value(fid, PyString_AsString(py_val)); // intvec_t case 5: { @@ -1411,14 +1419,14 @@ static bool formchgcbfa_set_field_value( for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it) (*it)++; - return fa->set_field_value(fid, &intvec); + return fa->set_chooser_value(fid, &intvec); } // Numeric case 6: { uint64 num; if ( PyW_GetNumber(py_val, &num) ) - return fa->set_field_value(fid, &num); + return fa->_set_field_value(fid, &num); } } return false; @@ -1428,6 +1436,11 @@ static bool formchgcbfa_set_field_value( static size_t py_get_AskUsingForm() { + // Return a pointer to the function. Note that, although + // the C implementation of AskUsingForm_cv will do some + // Qt/txt widgets generation, the Python's ctypes + // implementation through which the call well go will first + // unblock other threads. No need to do it ourselves. return (size_t)AskUsingForm_c; } @@ -1813,8 +1826,8 @@ private: self, (char *)S_ON_DELETE_LINE, "i", - lineno - 1)); - return pyres == NULL ? lineno : PyInt_AsLong(pyres.o) + 1; + IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1)); + return pyres == NULL ? 1 : PyInt_AsLong(pyres.o); } int on_refresh(int lineno) @@ -3980,8 +3993,39 @@ uint32 choose_choose(PyObject *self, int deflt, int icon); +%extend place_t { + static idaplace_t *as_idaplace_t(place_t *p) { return (idaplace_t *) p; } + static enumplace_t *as_enumplace_t(place_t *p) { return (enumplace_t *) p; } + static structplace_t *as_structplace_t(place_t *p) { return (structplace_t *) p; } + static simpleline_place_t *as_simpleline_place_t(place_t *p) { return (simpleline_place_t *) p; } +} +%extend twinpos_t { + %pythoncode { + def place_as_idaplace_t(self): + return place_t.as_idaplace_t(self.at) + def place_as_enumplace_t(self): + return place_t.as_enumplace_t(self.at) + def place_as_structplace_t(self): + return place_t.as_structplace_t(self.at) + def place_as_simpleline_place_t(self): + return place_t.as_simpleline_place_t(self.at) + + def place(self, view): + ptype = get_viewer_place_type(view) + if ptype == TCCPT_IDAPLACE: + return self.place_as_idaplace_t() + elif ptype == TCCPT_ENUMPLACE: + return self.place_as_enumplace_t() + elif ptype == TCCPT_STRUCTPLACE: + return self.place_as_structplace_t() + elif ptype == TCCPT_SIMPLELINE_PLACE: + return self.place_as_simpleline_place_t() + else: + return self.at + } +} %pythoncode %{ @@ -4995,7 +5039,7 @@ class Form(object): Form.Control.free(self) - class DropdownListControl(InputControl, qstrvec_t): + class DropdownListControl(InputControl, _qstrvec_t): """ Dropdown control This control allows manipulating a dropdown control @@ -5022,7 +5066,7 @@ class Form(object): hlp) # Init the associated qstrvec - qstrvec_t.__init__(self, items) + _qstrvec_t.__init__(self, items) # Remember if readonly or not self.readonly = readonly @@ -5033,7 +5077,7 @@ class Form(object): val_addr = addressof(self.__selval) else: # Create an strvec with one qstring - self.__selval = qstrvec_t([selval]) + self.__selval = _qstrvec_t([selval]) # Get address of the first element val_addr = self.__selval.addressof(0) @@ -6094,5 +6138,3 @@ class simplecustviewer_t(object): # # %} - - diff --git a/swig/moves.i b/swig/moves.i index b4154b7..9255d0b 100644 --- a/swig/moves.i +++ b/swig/moves.i @@ -4,6 +4,8 @@ %ignore term_marks; %ignore change_jumps_stack_format; %ignore move_marks; +%ignore curloc_after_segments_moved; +%ignore curloc::rebase_stack; %ignore loc_gtag; %ignore DEFINE_CURLOC_HELPERS; %ignore DEFINE_LOCATION_HELPERS; diff --git a/swig/nalt.i b/swig/nalt.i index 1e9a716..4893158 100644 --- a/swig/nalt.i +++ b/swig/nalt.i @@ -12,11 +12,11 @@ %ignore unregister_custom_refinfo; %ignore get_custom_refinfos; -%template (ids_array) wrapped_array; +%template (ids_array) wrapped_array_t; %extend strpath_t { - wrapped_array __getIds() { - return wrapped_array($self->ids); + wrapped_array_t __getIds() { + return wrapped_array_t($self->ids); } %pythoncode { @@ -85,6 +85,7 @@ switch_info_ex_t *switch_info_ex_t_get_clink(PyObject *self) %rename (del_switch_info_ex) py_del_switch_info_ex; %rename (create_switch_xrefs) py_create_switch_xrefs; %rename (create_switch_table) py_create_switch_table; +%rename (calc_switch_cases) py_calc_switch_cases; %inline %{ // @@ -169,6 +170,54 @@ idaman bool ida_export py_create_switch_xrefs( return true; } +//------------------------------------------------------------------------- +struct cases_and_targets_t +{ + casevec_t cases; + eavec_t targets; +}; + +//------------------------------------------------------------------------- +/* +# +def calc_switch_cases(insn_ea, si): + """ + Get information about a switch's cases. + + The returned information can be used as follows: + + for idx in xrange(len(results.cases)): + cur_case = results.cases[idx] + for cidx in xrange(len(cur_case)): + print "case: %d" % cur_case[cidx] + print " goto 0x%x" % results.targets[idx] + + @param insn_ea: address of the 'indirect jump' instruction + @param si: switch information + + @return: a structure with 2 members: 'cases', and 'targets'. + """ + pass +# +*/ +idaman cases_and_targets_t *ida_export py_calc_switch_cases( + ea_t insn_ea, + PyObject *py_swi) +{ + switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi); + if ( swi == NULL ) + return NULL; + + cases_and_targets_t *ct = new cases_and_targets_t; + if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) ) + { + delete ct; + return NULL; + } + + return ct; +} + //------------------------------------------------------------------------- /* diff --git a/swig/netnode.i b/swig/netnode.i index f72930f..2fb850c 100644 --- a/swig/netnode.i +++ b/swig/netnode.i @@ -87,6 +87,7 @@ %ignore netnode::altadjust; %ignore netnode::getblob(void *buf, size_t *bufsize, nodeidx_t start, char tag); %ignore netnode::operator nodeidx_t; +%ignore netnode::validate_names; // 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); @@ -136,4 +137,3 @@ return self->hashset(idx, buf, sz, tag); } } - diff --git a/swig/pro.i b/swig/pro.i index c8860bc..9c95d5b 100644 --- a/swig/pro.i +++ b/swig/pro.i @@ -16,6 +16,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); } //--------------------------------------------------------------------- + %ignore wchar2char; %ignore hit_counter_t; %ignore reg_hit_counter; @@ -55,6 +56,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); %ignore qstrchr; %ignore qstrrchr; %ignore bytevec_t; +%ignore qstrvec_t; %ignore reloc_info_t; %ignore relobj_t; %ignore wchar2char; @@ -63,6 +65,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); %ignore base64_encode; %ignore base64_decode; %ignore utf8_unicode; +%ignore unicode_utf8; %ignore win_utf2idb; %ignore char2oem; %ignore oem2char; @@ -112,22 +115,59 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1); void qvector::grow(const unsigned int &x=0); %ignore qvector::grow; +%ignore qvector::at(size_t); + +// simpleline_t doesn't implement '=='. Therefore, all these cannot be present in the instantiated template. +%ignore qvector::operator==; +%ignore qvector::operator!=; +%ignore qvector::find; +%ignore qvector::has; +%ignore qvector::del; +%ignore qvector::add_unique; %include "pro.h" //--------------------------------------------------------------------- -%template(uvalvec_t) qvector; // vector of unsigned values -%template(intvec_t) qvector; // vector of integers -%template(qstrvec_t) qvector; // vector of strings -%template(boolvec_t) qvector; // vector of bools +%extend qvector { + inline size_t __len__() const { return $self->size(); } + + // The fact that we are returning a const version of a reference to the + // type is what allows SWIG to generate a wrapper for this method, that + // will build an proper object (int, unsigned int, ...) instead + // of a pointer. Remove the 'const', and you'll see that, in + // SWIGINTERN PyObject *_wrap_uvalvec_t___getitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + // it will produce this: + // resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 ); + // instead of that: + // resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result)); + inline const T& __getitem__(size_t i) const throw(std::out_of_range) { + if (i >= $self->size() || i < 0) + throw std::out_of_range("out of bounds access"); + return $self->at(i); + } + + inline void __setitem__(size_t i, const T& v) throw(std::out_of_range) { + if (i >= $self->size() || i < 0) + throw std::out_of_range("out of bounds access"); + $self->at(i) = v; + } + + %pythoncode { + __iter__ = _bounded_getitem_iterator + } +} //--------------------------------------------------------------------- -class qstring { -public: - const char *c_str() const { return self->c_str(); } -}; +%template(uvalvec_t) qvector; // unsigned values +%template(intvec_t) qvector; +%template(boolvec_t) qvector; +%template(casevec_t) qvector >; // signed values +%template(strvec_t) qvector; -class qtype { -public: - const uchar *c_str() const { return self->c_str(); } -}; +%pythoncode %{ +_listify_types(uvalvec_t, + intvec_t, + boolvec_t, + casevec_t, + strvec_t) +%} diff --git a/swig/segment.i b/swig/segment.i index f6818b5..9e8f416 100644 --- a/swig/segment.i +++ b/swig/segment.i @@ -31,10 +31,12 @@ void segment_t_startEA_set(segment_t *segm, ea_t newea) segm->startEA = newea; } } + ea_t segment_t_startEA_get(segment_t *segm) { return segm->startEA; } + void segment_t_endEA_set(segment_t *segm, ea_t newea) { if ( getseg(segm->startEA) == segm ) @@ -46,6 +48,7 @@ void segment_t_endEA_set(segment_t *segm, ea_t newea) segm->endEA = newea; } } + ea_t segment_t_endEA_get(segment_t *segm) { return segm->endEA; @@ -56,6 +59,7 @@ ea_t segment_t_endEA_get(segment_t *segm) ea_t startEA; ea_t endEA; } + %include "segment.hpp" %inline %{ diff --git a/swig/typeconv.i b/swig/typeconv.i index 0cfb718..a7c7578 100644 --- a/swig/typeconv.i +++ b/swig/typeconv.i @@ -133,8 +133,32 @@ } %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. +} + //--------------------------------------------------------------------- // 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"); @@ -155,8 +179,10 @@ $1 = ea_t($1_temp); } -//------------------------------------------------------------------------- -// Convert qstring +//--------------------------------------------------------------------- +// IN qstring +//--------------------------------------------------------------------- +// This is used to set/retrieve qstring that are structure members. %typemap(in) qstring* { char *buf; @@ -167,25 +193,32 @@ $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 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 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 @@ -200,14 +233,14 @@ %immutable; %inline %{ template -struct wrapped_array { +struct wrapped_array_t { Type (&data)[N]; - wrapped_array(Type (&data)[N]) : data(data) { } + wrapped_array_t(Type (&data)[N]) : data(data) { } }; %} %mutable; -%extend wrapped_array { +%extend wrapped_array_t { inline size_t __len__() const { return N; } inline const Type& __getitem__(size_t i) const throw(std::out_of_range) { @@ -221,5 +254,49 @@ struct wrapped_array { throw std::out_of_range("out of bounds access"); $self->data[i] = v; } + + %pythoncode { + __iter__ = _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 diff --git a/swig/typeinf.i b/swig/typeinf.i index a1f2bbc..6fbee7b 100644 --- a/swig/typeinf.i +++ b/swig/typeinf.i @@ -68,6 +68,7 @@ %ignore skip_function_arg_names; %ignore perform_funcarg_conversion; %ignore get_argloc_info; +%ignore argloc_t::dstr; %ignore extract_pstr; %ignore extract_name; @@ -148,7 +149,10 @@ %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; @@ -165,6 +169,81 @@ %ignore enum_type_data_t::deserialize_enum; %ignore valstr_deprecated_t; %ignore valinfo_deprecated_t; +%ignore valstr_deprecated2_t; +%ignore valinfo_deprecated2_t; + +%ignore custloc_desc_t; +%ignore install_custom_argloc; +%ignore remove_custom_argloc; +%ignore retrieve_custom_argloc; + +%{ +// +//------------------------------------------------------------------------- +// A set of tinfo_t objects that were created from IDAPython. +// This is necessary in order to clear all the "type details" that are +// associated, in the kernel, with the tinfo_t instances. +// +// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is +// closed, but the "type details" must be cleared _before_ the IDB is closed. +static qvector python_tinfos; +void til_clear_python_tinfo_t_instances(void) +{ + // Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that + // were not done here, ~tinfo_t() calls happening as part of the python shutdown + // process will try and clear() their details. ..but the kernel's til-related + // functions will already have deleted those details at that point. + for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i ) + python_tinfos[i]->clear(); + // NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t + // instances will be deleted through the python shutdown/ref-decrementing + // process anyway (which will cause til_deregister_..() calls), and the + // entries will be properly pulled out of the vector when that happens. +} + +void til_register_python_tinfo_t_instance(tinfo_t *tif) +{ + // Let's add_unique() it, because every reference to an object's + // tinfo_t property will end up trying to register it. + python_tinfos.add_unique(tif); +} + +void til_deregister_python_tinfo_t_instance(tinfo_t *tif) +{ + qvector::iterator found = python_tinfos.find(tif); + if ( found != python_tinfos.end() ) + { + tif->clear(); + python_tinfos.erase(found); + } +} + +// +%} + +%extend tinfo_t { + + bool deserialize( + const til_t *til, + const type_t *type, + const p_list *fields, + const p_list *cmts = NULL) + { + return $self->deserialize(til, &type, &fields, cmts == NULL ? NULL : &cmts); + } + + // The typemap in typeconv.i will take care of registering newly-constructed + // tinfo_t instances. However, there's no such thing as a destructor typemap. + // Therefore, we need to do the grunt work of de-registering ourselves. + // Note: The 'void' here is important: Without it, SWIG considers it to + // be a different destructor (which, of course, makes a ton of sense.) + ~tinfo_t(void) + { + til_deregister_python_tinfo_t_instance($self); + delete $self; + } +} +%ignore tinfo_t::~tinfo_t(void); %include "typeinf.hpp" @@ -710,7 +789,6 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize) qstrncpy(buf, name, bufsize); return true; } - // til_t *load_til(const char *tildir, const char *name) { diff --git a/swig/ua.i b/swig/ua.i index 96ffe05..f6b6896 100644 --- a/swig/ua.i +++ b/swig/ua.i @@ -771,7 +771,7 @@ static PyObject *op_t_get_value(PyObject *self) op_t *link = op_t_get_clink(self); if ( link == NULL ) Py_RETURN_NONE; - return Py_BuildValue("I", link->value); + return Py_BuildValue(PY_FMT64, (pyul_t)link->value); } static void op_t_set_value(PyObject *self, PyObject *value) @@ -780,7 +780,9 @@ static void op_t_set_value(PyObject *self, PyObject *value) op_t *link = op_t_get_clink(self); if ( link == NULL ) return; - link->value = PyInt_AsLong(value); + uint64 v(0); + PyW_GetNumber(value, &v); + link->value = uval_t(v); } static PyObject *op_t_get_addr(PyObject *self) diff --git a/swig/view.i b/swig/view.i index 56b5d67..9d32214 100644 --- a/swig/view.i +++ b/swig/view.i @@ -14,16 +14,33 @@ class py_customidamemo_t; class lookup_info_t { public: - void add(TForm *form, TCustomControl *view, py_customidamemo_t *py_view) + struct entry_t { - QASSERT(0, form != NULL && view != NULL && py_view != NULL - && !find_by_form(NULL, NULL, form) - && !find_by_view(NULL, NULL, view) - && !find_by_py_view(NULL, NULL, py_view)); + entry_t() : form(NULL), view(NULL), py_view(NULL) {} + private: + TForm *form; + TCustomControl *view; + py_customidamemo_t *py_view; + friend class lookup_info_t; + }; + + entry_t &new_entry(py_customidamemo_t *py_view) + { + QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view)); entry_t &e = entries.push_back(); + e.py_view = py_view; + return e; + } + + void commit(entry_t &e, TForm *form, TCustomControl *view) + { + QASSERT(30455, &e >= entries.begin() && &e < entries.end()); + QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL + && !find_by_form(NULL, NULL, form) + && !find_by_view(NULL, NULL, view) + && find_by_py_view(NULL, NULL, e.py_view)); e.form = form; e.view = view; - e.py_view = py_view; } #define FIND_BY__BODY(crit, res1, res2) \ @@ -61,12 +78,6 @@ public: } private: - struct entry_t - { - TForm *form; - TCustomControl *view; - py_customidamemo_t *py_view; - }; typedef qvector entries_t; entries_t entries; }; @@ -130,6 +141,8 @@ class py_customidamemo_t static void ensure_view_callbacks_installed(); int cb_flags; + // number of arguments for OnViewClick implementation + int ovc_num_args; protected: ref_t self; @@ -198,6 +211,7 @@ public: void on_view_switched(tcc_renderer_type_t rt); void on_view_mouse_over(const view_mouse_event_t *event); inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } + int get_py_method_arg_count(char *method_name); }; //------------------------------------------------------------------------- @@ -207,6 +221,7 @@ py_customidamemo_t::py_customidamemo_t() { PYGLOG("%p: py_customidamemo_t()\n", this); ensure_view_callbacks_installed(); + ovc_num_args = -1; } //------------------------------------------------------------------------- @@ -401,7 +416,7 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) { newref_t node(PySequence_GetItem(nodes.o, k)); if ( PyInt_Check(node.o) ) - gi.nodes.insert(PyInt_AsLong(node.o)); + gi.nodes.add_unique(PyInt_AsLong(node.o)); } if ( !gi.nodes.empty() ) { @@ -409,18 +424,18 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) gis.push_back(gi); } } - intset_t groups; + intvec_t groups; if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() ) Py_RETURN_NONE; PyObject *py_groups = PyList_New(0); - for ( intset_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) + for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) PyList_Append(py_groups, PyInt_FromLong(long(*it))); return py_groups; } //------------------------------------------------------------------------- -static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes) +static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes) { Py_ssize_t sz = PySequence_Size(pynodes.o); for ( Py_ssize_t i = 0; i < sz; ++i ) @@ -428,7 +443,7 @@ static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes) newref_t item(PySequence_GetItem(pynodes.o, i)); if ( !PyInt_Check(item.o) ) continue; - idanodes->insert(PyInt_AsLong(item.o)); + idanodes->add_unique(PyInt_AsLong(item.o)); } } @@ -439,7 +454,7 @@ PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_cu Py_RETURN_NONE; borref_t groups(_groups); borref_t new_current(_new_current); - intset_t ida_groups; + intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; @@ -459,7 +474,7 @@ PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject borref_t groups(_groups); borref_t expand(_expand); borref_t new_current(_new_current); - intset_t ida_groups; + intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; @@ -498,6 +513,23 @@ void py_customidamemo_t::unbind() view = NULL; } +//------------------------------------------------------------------------- +int py_customidamemo_t::get_py_method_arg_count(char *method_name) +{ + newref_t method(PyObject_GetAttrString(self.o, method_name)); + if ( method != NULL && PyCallable_Check(method.o) ) + { + newref_t fc(PyObject_GetAttrString(method.o, "func_code")); + if ( fc != NULL ) + { + newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount")); + if ( ac != NULL ) + return PyInt_AsLong(ac.o); + } + } + return -1; +} + //------------------------------------------------------------------------- void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out) { @@ -603,12 +635,26 @@ void py_customidamemo_t::on_view_popup() void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_CLICK); - newref_t result( - PyObject_CallMethod( - self.o, - (char *)S_ON_VIEW_CLICK, - "iii", - event->x, event->y, event->state)); + if ( ovc_num_args < 0 ) + ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); + if ( ovc_num_args == 5 ) + { + newref_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iiii", + event->x, event->y, event->state, event->button)); + } + else + { + newref_t result( + PyObject_CallMethod( + self.o, + (char *)S_ON_VIEW_CLICK, + "iii", + event->x, event->y, event->state)); + } CHK_RES(); } @@ -958,7 +1004,8 @@ bool py_idaview_t::Bind(PyObject *self) else { py_view = new py_idaview_t(); - lookup_info.add(tform, v, py_view); + lookup_info_t::entry_t &e = lookup_info.new_entry(py_view); + lookup_info.commit(e, tform, v); } // Finally, bind: diff --git a/swig/xref.i b/swig/xref.i index 289a34b..54ebe21 100644 --- a/swig/xref.i +++ b/swig/xref.i @@ -11,6 +11,7 @@ %ignore destroy_switch_info; %ignore create_switch_xrefs; %ignore create_switch_table; +%rename (calc_switch_cases) py_calc_switch_cases; // These functions should not be called directly (according to docs) %ignore xrefblk_t_first_from;