IDA Pro 6.7 support

This commit is contained in:
elias.bachaalany@gmail.com 2015-02-08 02:59:53 +00:00
parent 49dcdc5ed3
commit bbf628d3a3
69 changed files with 5070 additions and 1802 deletions

View File

@ -16,8 +16,10 @@ REQUIREMENTS
- Python [2.5.1, 2.6.1, 2.7] - Python [2.5.1, 2.6.1, 2.7]
http://www.python.org/ http://www.python.org/
- Simplified Wrapper Interface Generator (SWIG) [2.0] - Simplified Wrapper Interface Generator (SWIG) [2.0.12]
http://www.swig.org/ http://www.swig.org/
Hex-Rays cannot guarantee support for IDAPython
versions built with other versions of SWIG.
- Unix utilities (GNU patch on Windows): - Unix utilities (GNU patch on Windows):
http://www.research.att.com/sw/tools/uwin/ or http://www.research.att.com/sw/tools/uwin/ or

View File

@ -24,19 +24,23 @@ from distutils import sysconfig
VERBOSE = True VERBOSE = True
IDA_MAJOR_VERSION = 6 IDA_MAJOR_VERSION = 6
IDA_MINOR_VERSION = 6 IDA_MINOR_VERSION = 7
if 'IDA' in os.environ: if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA'] IDA_SDK = os.environ['IDA']
else: else:
IDA_SDK = os.path.join("..", "..", "include")
if not os.path.exists(IDA_SDK):
IDA_SDK = os.path.join("..", "swigsdk-versions", ("%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION))) IDA_SDK = os.path.join("..", "swigsdk-versions", ("%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION)))
assert os.path.exists(IDA_SDK), "Could not find IDA SDK include path"
# End of user configurable options # End of user configurable options
# IDAPython version # IDAPython version
VERSION_MAJOR = 1 VERSION_MAJOR = 1
VERSION_MINOR = 7 VERSION_MINOR = 7
VERSION_PATCH = 0 VERSION_PATCH = 1
# Determine Python version # Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0]) PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -89,7 +93,7 @@ BINDIST_MANIFEST = [
"examples/structure.py", "examples/structure.py",
"examples/ex_gdl_qflow_chart.py", "examples/ex_gdl_qflow_chart.py",
"examples/ex_strings.py", "examples/ex_strings.py",
"examples/ex_add_menu_item.py", "examples/ex_actions.py",
"examples/ex_func_chooser.py", "examples/ex_func_chooser.py",
"examples/ex_choose2.py", "examples/ex_choose2.py",
"examples/ex_debug_names.py", "examples/ex_debug_names.py",
@ -157,7 +161,6 @@ SRCDIST_MANIFEST = [
"swig/graph.i", "swig/graph.i",
"swig/fpro.i", "swig/fpro.i",
"swig/hexrays.i", "swig/hexrays.i",
"tools/gendocs.py",
] ]
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -396,7 +399,8 @@ def build_plugin(
platform_macros.append("WITH_HEXRAYS") platform_macros.append("WITH_HEXRAYS")
SWIG_OPTIONS += ' -DWITH_HEXRAYS ' SWIG_OPTIONS += ' -DWITH_HEXRAYS '
platform_macros.append("NDEBUG") platform_macros.append("DEBUG")
# platform_macros.append("NDEBUG")
if not '--no-early-load' in sys.argv: if not '--no-early-load' in sys.argv:
platform_macros.append("PLUGINFIX") platform_macros.append("PLUGINFIX")
@ -411,6 +415,13 @@ def build_plugin(
res = os.system(swigcmd) res = os.system(swigcmd)
assert res == 0, "Failed to build the wrapper with SWIG" assert res == 0, "Failed to build the wrapper with SWIG"
# If we are running on windows, we have to patch some directors'
# virtual methods, so they have the right calling convention.
# Without that, compilation just won't succeed.
if platform == "win32":
res = os.system("python patch_directors_cc.py -f idaapi.h")
assert res == 0, "Failed to patch directors' calling conventions"
# Compile the wrapper # Compile the wrapper
res = builder.compile("idaapi", res = builder.compile("idaapi",
includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ], includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ],

119
examples/ex_actions.py Normal file
View File

@ -0,0 +1,119 @@
import idaapi
class SayHi(idaapi.action_handler_t):
def __init__(self, message):
idaapi.action_handler_t.__init__(self)
self.message = message
def activate(self, ctx):
print "Hi, %s" % (self.message)
return 1
# You can implement update(), to inform IDA when:
# * your action is enabled
# * update() should queried again
# E.g., returning 'idaapi.AST_ENABLE_FOR_FORM' will
# tell IDA that this action is available while the
# user is in the current widget, and that update()
# must be queried again once the user gives focus
# to another widget.
#
# For example, the following update() implementation
# will let IDA know that the action is available in
# "IDA View-*" views, and that it's not even worth
# querying update() anymore until the user has moved
# to another view..
def update(self, ctx):
return idaapi.AST_ENABLE_FOR_FORM if ctx.form_type == idaapi.BWN_DISASM else idaapi.AST_DISABLE_FOR_FORM
print "Creating a custom icon from raw data!"
# Stunned panda face icon data.
icon_data = "".join([
"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1F\xF3\xFF\x61\x00\x00\x02\xCA\x49\x44\x41\x54\x78\x5E\x65",
"\x53\x6D\x48\x53\x6F\x14\x3F\xBA\xB5\xB7\xA0\x8D\x20\x41\xF2\xBA\x5D\xB6\x0F\x56\xF4\x41\xA2\xC0\x9C\xE9\xB4\x29\x4A\x7D\xB0\x22\x7A\x11\x02\x23\x48\x2A\xD4\x74\x53\x33\x3F\xD4",
"\x3E\x4A\x50\x19\xE4\xB0\xD0\x22\xCD\x44\x45\x4A\x31\x8C\x92\xA2\x3E\x65\x0A\x4D\xCB\x96\x7E\xE8\xD5\x97\xCC\xFE\xFE\x37\xA7\x77\xDB\xBD\xA7\xE7\x3C\xBE\x05\x9E\xED\xB7\xB3\xF3",
"\x7B\x39\xF7\xEE\x19\x17\xA8\xAC\x56\xDB\x54\x82\x60\x41\xB3\x59\xBC\xFF\xAC\xF9\xCA\xB5\xAE\x86\xCA\xF9\x4E\xAF\x1B\x3B\xEA\x5D\x48\x9D\x66\xE2\x49\x27\x9F\xD5\x66\x9B\xA2\x1C",
"\x22\x02\xD0\x40\xE4\x81\x6C\x3B\x76\x37\x56\xE3\x37\x5F\x2F\x62\xE8\x0B\xD3\x66\x19\x7E\x53\xA7\x99\x78\xAE\x1F\x64\x3E\x21\x71\x69\x09\x5F\x20\x98\x2D\x58\x70\x24\x07\x07\x7B",
"\x6F\xB0\x79\x82\x61\x81\x21\xCC\xDE\x21\x54\x16\x02\xD4\x69\x26\x9E\x74\xEE\xCB\xCF\x4D\xC7\x44\xB3\x88\x7C\x81\xC5\x22\xFE\x6C\xB9\xE9\x46\x67\x46\x1A\x8A\x16\x2B\x0A\x5B\x05",
"\x74\x66\x65\xE1\x98\x6F\x00\x31\x32\x87\x9F\x59\x77\x66\x66\x61\x42\xBC\xC0\xF5\x6C\x47\x1A\x36\xD7\xB9\x51\x14\xC5\x1E\xBE\xA0\xC3\x5B\xD9\x98\x99\xE1\xC0\xCE\xBE\x57\x48\xD7",
"\x9A\x63\x68\xEA\x7C\x8A\xF6\x14\x3B\x9F\xF6\xA6\xA4\x60\xEB\xE3\x3E\x9C\x5F\xD6\x5A\x7A\xFA\x71\xBF\xC3\x81\x3D\x4D\x35\x0D\x7C\xC1\xF3\x87\x57\x43\xF9\x87\x8F\x21\x95\x5E\xAB",
"\x41\x83\x4E\x83\x54\xDB\x92\x76\x20\xCA\xBF\xD0\x99\x9D\xBB\x4E\xDB\xBD\xC7\x8E\x2F\x5A\x3D\x74\x3D\x50\x03\x80\x7E\x7A\x7A\x06\x46\x47\xFD\xA0\x33\x6C\x84\x18\x46\x0C\xBD\x1F",
"\x86\x2D\x71\x71\x00\x52\x10\x16\x17\xE6\xC1\xE7\x1B\x61\x9A\x81\x69\x31\x30\xFC\x61\x14\xB4\x3A\x3D\x20\x82\x1E\x58\xA9\x15\x05\x41\x14\x05\xB8\x58\xEE\x82\x7D\xE9\x99\x20\xCB",
"\x32\x94\x95\x95\xC3\xA5\xD2\x53\x00\x51\x09\xAA\x4B\x0B\xA1\xB8\xA4\x0C\x52\x53\x33\x40\xA5\x52\x81\xDB\x5D\x01\xA2\x45\x00\x45\x51\x80\x2A\x36\x12\x8D\x42\x49\x51\x01\x44\xE5",
"\x18\x90\x22\x0A\x98\x8C\x46\xF0\x54\x14\x42\x6D\x7D\x3B\xE4\x1C\x75\x41\xAD\xB7\x1D\x3C\x55\x85\x60\x32\x19\x41\x8A\x2A\xDC\x57\x5C\x74\x12\x28\x47\xA5\x8E\x44\xE4\xF0\x76\x5B",
"\x82\xA6\xCD\x5B\x0D\xB2\x12\xE6\xE4\x06\xB5\x1A\x66\xA7\x26\x41\x92\xC2\xA0\xD5\x6A\x60\x67\x92\x19\xAE\x7B\xCE\x70\x4D\x15\xAB\x01\xAD\xC1\x08\x3F\x46\x64\x6E\x8E\x9D\xF9\x13",
"\xE8\x1A\xFF\xE4\x63\x8A\x0E\xE6\x02\x41\xF8\x3F\x18\x82\x40\x28\x04\xFD\xDD\x75\xF0\xB6\xFF\x2E\x75\x9A\x89\x27\x9D\xFB\xC8\x4F\x39\xBE\xE0\xB4\xAB\xCE\x35\xFE\x71\x00\x16\x17",
"\x25\x76\x50\x26\x76\x6B\x61\x86\x08\xE4\x1D\xAF\x81\xBC\x13\x97\xA9\xD3\x4C\x3C\xE9\xDC\x47\x7E\xCA\xF1\x05\x0C\x5F\x7D\xFE\xEF\x35\x03\xAF\x9F\x00\xB0\x73\x30\x9A\xE2\x81\x0E",
"\xF6\xC1\xED\x52\xB8\x77\xAB\x98\x3A\xCD\xC4\x73\x9D\x7C\x6F\xDE\xF9\xCF\x53\x0E\xFE\xA9\xCD\xAE\xB3\x87\xCE\x75\x35\x54\xE1\xD0\xCB\x47\x38\x39\x36\x88\xFF\x4D\xF8\x57\x41\x33",
"\xF1\xA4\x93\x0F\x00\x36\xAD\x3E\x4C\x6B\xC5\xC9\x5D\x77\x6A\x2F\xB4\x31\xA3\xC4\x40\x4F\x21\x0F\xD1\x4C\x3C\xE9\x2B\xE1\xF5\x0B\xD6\x90\xC8\x90\x4C\xE6\x35\xD0\xCC\x79\x5E\xFF",
"\x2E\xF8\x0B\x2F\x3D\xE5\xC3\x97\x06\xCF\xCF\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"])
act_icon = idaapi.load_custom_icon(data=icon_data, format="png")
hooks = None
act_name = "example:add_action"
if idaapi.register_action(idaapi.action_desc_t(
act_name, # Name. Acts as an ID. Must be unique.
"Say hi!", # Label. That's what users see.
SayHi("developer"), # Handler. Called when activated, and for updating
"Ctrl+F12", # Shortcut (optional)
"Greets the user", # Tooltip (optional)
act_icon)): # Icon ID (optional)
print "Action registered. Attaching to menu."
# Insert the action in the menu
if idaapi.attach_action_to_menu("Edit/Export data", act_name, idaapi.SETMENU_APP):
print "Attached to menu."
else:
print "Failed attaching to menu."
# Insert the action in a toolbar
if idaapi.attach_action_to_toolbar("AnalysisToolBar", act_name):
print "Attached to toolbar."
else:
print "Failed attaching to toolbar."
# We will also want our action to be available in the context menu
# for the "IDA View-A" widget.
#
# To do that, we could in theory retrieve a reference to "IDA View-A", and
# then request to "permanently" attach the action to it, using something
# like this:
# idaapi.attach_action_to_popup(ida_view_a, None, act_name, None)
#
# but alas, that won't do: widgets in IDA are very "volatile", and
# can be deleted & re-created on some occasions (e.g., starting a
# debugging session), and our efforts to permanently register our
# action on "IDA View-A" would be annihilated as soon as "IDA View-A"
# is deleted.
#
# Instead, we can opt for a different method: attach our action on-the-fly,
# when the popup for "IDA View-A" is being populated, right before
# it is displayed.
class Hooks(idaapi.UI_Hooks):
def finish_populating_tform_popup(self, form, popup):
# We'll add our action to all "IDA View-*"s.
# If we wanted to add it only to "IDA View-A", we could
# also discriminate on the widget's title:
#
# if idaapi.get_tform_title(form) == "IDA View-A":
# ...
#
if idaapi.get_tform_type(form) == idaapi.BWN_DISASM:
idaapi.attach_action_to_popup(form, popup, act_name, None)
hooks = Hooks()
hooks.hook()
else:
print "Action found; unregistering."
# No need to call detach_action_from_menu(); it'll be
# done automatically on destruction of the action.
if idaapi.unregister_action(act_name):
print "Unregistered."
else:
print "Failed to unregister action."
if hooks is not None:
hooks.unhook()
hooks = None

View File

@ -344,7 +344,7 @@ Dropdown list test
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
def test_dropdown(execute=True): def test_dropdown(execute=True):
"""Test the combobox controls""" """Test the combobox controls, in a modal dialog"""
f = MyForm3() f = MyForm3()
f, args = f.Compile() f, args = f.Compile()
if execute: if execute:
@ -360,6 +360,18 @@ def test_dropdown(execute=True):
f.Free() f.Free()
# --------------------------------------------------------------------------
tdn_form = None
def test_dropdown_nomodal():
"""Test the combobox controls, in a non-modal form"""
global tdn_form
if tdn_form is None:
tdn_form = MyForm3()
tdn_form.modal = False
tdn_form.openform_flags = idaapi.PluginForm.FORM_TAB
tdn_form, _ = tdn_form.Compile()
tdn_form.Open()
#</pycode(ex_askusingform)> #</pycode(ex_askusingform)>

View File

@ -1,16 +1,42 @@
import idaapi import idaapi
from idaapi import Choose2 from idaapi import Choose2
#<pycode(py_choose2ex1)>
class chooser_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
self.thing = thing
def activate(self, ctx):
sel = []
for i in xrange(len(ctx.chooser_selection)):
sel.append(str(ctx.chooser_selection.at(i)))
print "command %s selected @ %s" % (self.thing, ", ".join(sel))
def update(self, ctx):
return idaapi.AST_ENABLE_FOR_FORM if idaapi.is_chooser_tform(ctx.form_type) else idaapi.AST_DISABLE_FOR_FORM
class MyChoose2(Choose2): class MyChoose2(Choose2):
def __init__(self, title, nb = 5, deflt=1): def __init__(self, title, nb = 5, flags=0, width=None, height=None, embedded=False, modal=False):
Choose2.__init__(self, title, [ ["Address", 10], ["Name", 30] ]) Choose2.__init__(
self,
title,
[ ["Address", 10], ["Name", 30] ],
flags = flags,
width = width,
height = height,
embedded = embedded)
self.n = 0 self.n = 0
self.items = [ self.make_item() for x in xrange(0, nb+1) ] self.items = [ self.make_item() for x in xrange(0, nb+1) ]
self.icon = 5 self.icon = 5
self.selcount = 0 self.selcount = 0
self.deflt = deflt self.modal = modal
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"] self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
print("created %s" % str(self)) print("created %s" % str(self))
def OnClose(self): def OnClose(self):
@ -46,15 +72,6 @@ class MyChoose2(Choose2):
print("refresh %d" % n) print("refresh %d" % n)
return n return n
def OnCommand(self, n, cmd_id):
if cmd_id == self.cmd_a:
print "command A selected @", n
elif cmd_id == self.cmd_b:
print "command B selected @", n
else:
print "Unknown command:", cmd_id, "@", n
return 1
def OnGetIcon(self, n): def OnGetIcon(self, n):
r = self.items[n] r = self.items[n]
t = self.icon + r[1].count("*") t = self.icon + r[1].count("*")
@ -62,12 +79,7 @@ class MyChoose2(Choose2):
return t return t
def show(self): def show(self):
t = self.Show() return self.Show(self.modal) >= 0
if t < 0:
return False
self.cmd_a = self.AddCommand("command A")
self.cmd_b = self.AddCommand("command B")
return True
def make_item(self): def make_item(self):
r = [str(self.n), "func_%04d" % self.n] r = [str(self.n), "func_%04d" % self.n]
@ -79,7 +91,43 @@ class MyChoose2(Choose2):
if n == 1: if n == 1:
return [0xFF0000, 0] return [0xFF0000, 0]
for i in xrange(1, 5+1):
c = MyChoose2("choose2 - sample %d" % i, i*2, deflt=i) # -----------------------------------------------------------------------
def test_choose2(modal=False):
global c
c = MyChoose2("Choose2 - sample 1", nb=10, modal=modal)
r = c.show() r = c.show()
print r form = idaapi.get_current_tform()
for thing in ["A", "B"]:
idaapi.attach_action_to_popup(form, None, "choose2:act%s" % thing)
# -----------------------------------------------------------------------
def test_choose2_embedded():
global c
c = MyChoose2("Choose2 - embedded", nb=12, embedded = True, width=123, height=222)
r = c.Embedded()
if r == 1:
try:
if test_embedded:
o, sel = _idaapi.choose2_get_embedded(c)
print("o=%s, type(o)=%s" % (str(o), type(o)))
test_embedded(o)
finally:
c.Close()
# -----------------------------------------------------------------------
if __name__ == '__main__':
# Register actions
for thing in ["A", "B"]:
actname = "choose2:act%s" % thing
idaapi.register_action(
idaapi.action_desc_t(
actname,
"command %s" % thing,
chooser_handler_t(thing)))
#test_choose2_embedded()
test_choose2(False)
#</pycode(py_choose2ex1)>

View File

@ -7,6 +7,18 @@ import idc
from idaapi import simplecustviewer_t from idaapi import simplecustviewer_t
#<pycode(py_custviewerex1)> #<pycode(py_custviewerex1)>
class say_something_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
self.thing = thing
def activate(self, ctx):
print self.thing
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
class mycv_t(simplecustviewer_t): class mycv_t(simplecustviewer_t):
def Create(self, sn=None): def Create(self, sn=None):
@ -18,8 +30,6 @@ class mycv_t(simplecustviewer_t):
# Create the customviewer # Create the customviewer
if not simplecustviewer_t.Create(self, title): if not simplecustviewer_t.Create(self, title):
return False return False
self.menu_hello = self.AddPopupMenu("Hello")
self.menu_world = self.AddPopupMenu("World")
for i in xrange(0, 100): for i in xrange(0, 100):
self.AddLine("Line %d" % i) self.AddLine("Line %d" % i)
@ -120,13 +130,6 @@ class mycv_t(simplecustviewer_t):
return False return False
return True return True
def OnPopup(self):
"""
Context menu popup is about to be shown. Create items dynamically if you wish
@return: Boolean. True if you handled the event
"""
print "OnPopup"
def OnHint(self, lineno): def OnHint(self, lineno):
""" """
Hint requested for the given line number. Hint requested for the given line number.
@ -137,22 +140,6 @@ class mycv_t(simplecustviewer_t):
""" """
return (1, "OnHint, line=%d" % lineno) return (1, "OnHint, line=%d" % lineno)
def OnPopupMenu(self, menu_id):
"""
A context (or popup) menu item was executed.
@param menu_id: ID previously registered with AddPopupMenu()
@return: Boolean
"""
print "OnPopupMenu, menu_id=%d" % menu_id
if menu_id == self.menu_hello:
print "Hello"
elif menu_id == self.menu_world:
print "World"
else:
# Unhandled
return False
return True
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
try: try:
# created already? # created already?
@ -169,7 +156,16 @@ def show_win():
print "Failed to create!" print "Failed to create!"
return None return None
x.Show() x.Show()
tcc = x.GetTCustomControl()
# Register actions
for thing in ["Hello", "World"]:
actname = "custview:say_%s" % thing
idaapi.register_action(
idaapi.action_desc_t(actname, "Say %s" % thing, say_something_handler_t(thing)))
idaapi.attach_action_to_popup(tcc, None, actname)
return x return x
mycv = show_win() mycv = show_win()
if not mycv: if not mycv:
del mycv del mycv

View File

@ -3,11 +3,24 @@
# in Python # in Python
# (c) Hex-Rays # (c) Hex-Rays
# #
from idaapi import GraphViewer from idaapi import *
class GraphCloser(action_handler_t):
def __init__(self, graph):
action_handler_t.__init__(self)
self.graph = graph
def activate(self, ctx):
self.graph.Close()
def update(self, ctx):
return AST_ENABLE_ALWAYS
class MyGraph(GraphViewer): class MyGraph(GraphViewer):
def __init__(self, funcname, result): def __init__(self, funcname, result):
GraphViewer.__init__(self, "call graph of " + funcname) self.title = "call graph of " + funcname
GraphViewer.__init__(self, self.title)
self.funcname = funcname self.funcname = funcname
self.result = result self.result = result
@ -23,25 +36,15 @@ class MyGraph(GraphViewer):
def OnGetText(self, node_id): def OnGetText(self, node_id):
return str(self[node_id]) return str(self[node_id])
def OnCommand(self, cmd_id):
"""
Triggered when a menu command is selected through the menu or its hotkey
@return: None
"""
if self.cmd_close == cmd_id:
self.Close()
return
print "command:", cmd_id
def Show(self): def Show(self):
if not GraphViewer.Show(self): if not GraphViewer.Show(self):
return False return False
self.cmd_close = self.AddCommand("Close", "F2") actname = "graph_closer:%s" % self.title
if self.cmd_close == 0: register_action(action_desc_t(actname, "Close %s" % self.title, GraphCloser(self)))
print "Failed to add popup menu item!" attach_action_to_popup(self.GetTCustomControl(), None, actname)
return True return True
def show_graph(): def show_graph():
f = idaapi.get_func(here()) f = idaapi.get_func(here())
if not f: if not f:

View File

@ -16,10 +16,28 @@ import idautils
import idaapi import idaapi
import idc import idc
import traceback
NETNODE_NAME = '$ hexrays-inverted-if' NETNODE_NAME = '$ hexrays-inverted-if'
inverter_actname = "vds3:invert"
class invert_action_handler_t(idaapi.action_handler_t):
def __init__(self, inverter):
idaapi.action_handler_t.__init__(self)
self.inverter = inverter
def activate(self, ctx):
vdui = idaapi.get_tform_vdui(ctx.form)
self.inverter.invert_if_event(vdui)
return 1
def update(self, ctx):
vdui = idaapi.get_tform_vdui(ctx.form)
if vdui:
return idaapi.AST_ENABLE_FOR_FORM
else:
return idaapi.AST_DISABLE_FOR_FORM
class hexrays_callback_info(object): class hexrays_callback_info(object):
def __init__(self): def __init__(self):
@ -123,14 +141,12 @@ class hexrays_callback_info(object):
def invert_if_event(self, vu): def invert_if_event(self, vu):
cfunc = vu.cfunc.__deref__() cfunc = vu.cfunc.__deref__()
i = self.find_if_statement(vu) i = self.find_if_statement(vu)
if not i: if not i:
return False return False
if self.invert_if(cfunc, i): if self.invert_if(cfunc, i):
vu.refresh_ctext() vu.refresh_ctext()
self.add_location(i.ea) self.add_location(i.ea)
return True return True
@ -157,39 +173,27 @@ class hexrays_callback_info(object):
return return
def menu_callback(self):
try:
self.invert_if_event(self.vu)
except:
traceback.print_exc()
return 0
def event_callback(self, event, *args): def event_callback(self, event, *args):
try: if event == idaapi.hxe_populating_popup:
if event == idaapi.hxe_keyboard: form, phandle, vu = args
vu, keycode, shift = args res = idaapi.attach_action_to_popup(vu.ct, None, inverter_actname)
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: elif event == idaapi.hxe_maturity:
cfunc, maturity = args cfunc, maturity = args
if maturity == idaapi.CMAT_FINAL: if maturity == idaapi.CMAT_FINAL:
self.restore(cfunc) self.restore(cfunc)
except:
traceback.print_exc()
return 0 return 0
if idaapi.init_hexrays_plugin(): if idaapi.init_hexrays_plugin():
i = hexrays_callback_info() i = hexrays_callback_info()
idaapi.register_action(
idaapi.action_desc_t(
inverter_actname,
"Invert then/else",
invert_action_handler_t(i),
"I"))
idaapi.install_hexrays_callback(i.event_callback) idaapi.install_hexrays_callback(i.event_callback)
else: else:
print 'invert-if: hexrays is not available.' print 'invert-if: hexrays is not available.'

View File

@ -221,7 +221,10 @@ class XrefsForm(idaapi.PluginForm):
addresses.append(parent.ea) addresses.append(parent.ea)
self.functions.append(cfunc.entry_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)))) self.items.append((
parent.ea,
idc.GetFunctionName(cfunc.entry_ea),
self.get_decompiled_line(cfunc, parent.ea)))
return [] return []
@ -260,57 +263,62 @@ class XrefsForm(idaapi.PluginForm):
def OnClose(self, form): def OnClose(self, form):
pass pass
class hexrays_callback_info(object):
class show_xrefs_ah_t(idaapi.action_handler_t):
def __init__(self): def __init__(self):
self.vu = None idaapi.action_handler_t.__init__(self)
return self.sel = None
def show_xrefs(self, vu): def activate(self, ctx):
vu = idaapi.get_tform_vdui(ctx.form)
if not vu or not self.sel:
print "No vdui? Strange, since this action should be enabled only for pseudocode views."
return 0
form = XrefsForm(self.sel)
form.Show()
return 1
def update(self, ctx):
vu = idaapi.get_tform_vdui(ctx.form)
if not vu:
return idaapi.AST_DISABLE_FOR_FORM
else:
vu.get_current_item(idaapi.USE_KEYBOARD) vu.get_current_item(idaapi.USE_KEYBOARD)
item = vu.item item = vu.item
self.sel = None
sel = None
if item.citype == idaapi.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'): 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 # if an expression is selected. verify that it's either a cot_obj, cot_memref or cot_memptr
sel = item.it.to_specific_type self.sel = item.it.to_specific_type
elif item.citype == idaapi.VDI_FUNC: elif item.citype == idaapi.VDI_FUNC:
# if the function itself is selected, show xrefs to it. # if the function itself is selected, show xrefs to it.
sel = item.f self.sel = item.f
else:
return False
form = XrefsForm(sel) return idaapi.AST_ENABLE if self.sel else idaapi.AST_DISABLE
form.Show()
return True
def menu_callback(self): class hexrays_callback_info(object):
self.show_xrefs(self.vu)
return 0 def __init__(self):
return
def event_callback(self, event, *args): def event_callback(self, event, *args):
try: try:
if event == idaapi.hxe_keyboard: if event == idaapi.hxe_populating_popup:
vu, keycode, shift = args form, phandle, vu = args
idaapi.attach_action_to_popup(form, phandle, "vdsxrefs:show", None)
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: except:
traceback.print_exc() traceback.print_exc()
return 0 return 0
if idaapi.init_hexrays_plugin(): if idaapi.init_hexrays_plugin():
adesc = idaapi.action_desc_t('vdsxrefs:show', 'Show xrefs', show_xrefs_ah_t(), "Ctrl+X")
if idaapi.register_action(adesc):
i = hexrays_callback_info() i = hexrays_callback_info()
idaapi.install_hexrays_callback(i.event_callback) idaapi.install_hexrays_callback(i.event_callback)
else: else:
print 'invert-if: hexrays is not available.' print "Couldn't register action."
else:
print 'hexrays is not available.'

148
hrdoc.cfg Normal file
View File

@ -0,0 +1,148 @@
[epydoc]
# The list of objects to document. Objects can be named using
# dotted names, module filenames, or package directory names.
# Aliases for this option include "objects" and "values".
modules: idc, idautils, idaapi
#modules: pywraps
# The type of output that should be generated. Should be one
# of: html, text, latex, dvi, ps, pdf.
output: html
# The path to the output directory. May be relative or absolute.
target: hr-html/
# An integer indicating how verbose epydoc should be. The default
# value is 0; negative values will supress warnings and errors;
# positive values will give more verbose output.
verbosity: 0
# A boolean value indicating that Epydoc should show a tracaback
# in case of unexpected error. By default don't show tracebacks
debug: 0
# If True, don't try to use colors or cursor control when doing
# textual output. The default False assumes a rich text prompt
simple-term: 0
### Generation options
# The default markup language for docstrings, for modules that do
# not define __docformat__. Defaults to epytext.
docformat: epytext
# Whether or not parsing should be used to examine objects.
parse: yes
# Whether or not introspection should be used to examine objects.
introspect: yes
# Don't examine in any way the modules whose dotted name match this
# regular expression pattern.
#exclude
# Don't perform introspection on the modules whose dotted name match this
# regular expression pattern.
#exclude-introspect
# Don't perform parsing on the modules whose dotted name match this
# regular expression pattern.
#exclude-parse
# The format for showing inheritance objects.
# It should be one of: 'grouped', 'listed', 'included'.
inheritance: listed
# Whether or not to inclue private variables. (Even if included,
# private variables will be hidden by default.)
private: no
# Whether or not to list each module's imports.
imports: no
# Whether or not to include syntax highlighted source code in
# the output (HTML only).
sourcecode: no
# Whether or not to includea a page with Epydoc log, containing
# effective option at the time of generation and the reported logs.
include-log: no
### Output options
# The documented project's name.
name: IDAPython
# The CSS stylesheet for HTML output. Can be the name of a builtin
# stylesheet, or the name of a file.
css: white
# The documented project's URL.
url: http://code.google.com/p/idapython/
# HTML code for the project link in the navigation bar. If left
# unspecified, the project link will be generated based on the
# project's name and URL.
link: <a href="http://www.hex-rays.com/">Hex-Rays</a>
# The "top" page for the documentation. Can be a URL, the name
# of a module or class, or one of the special names "trees.html",
# "indices.html", or "help.html"
#top: os.path
# An alternative help file. The named file should contain the
# body of an HTML file; navigation bars will be added to it.
#help: my_helpfile.html
# Whether or not to include a frames-based table of contents.
frames: yes
# Whether each class should be listed in its own section when
# generating LaTeX or PDF output.
separate-classes: no
### API linking options
# Define a new API document. A new interpreted text role
# will be created
#external-api: epydoc
# Use the records in this file to resolve objects in the API named NAME.
#external-api-file: epydoc:api-objects.txt
# Use this URL prefix to configure the string returned for external API.
#external-api-root: epydoc:http://epydoc.sourceforge.net/api
### Graph options
# The list of graph types that should be automatically included
# in the output. Graphs are generated using the Graphviz "dot"
# executable. Graph types include: "classtree", "callgraph",
# "umlclass". Use "all" to include all graph types
#graph: classtree
# The path to the Graphviz "dot" executable, used to generate
# graphs.
#dotpath: /usr/local/bin/dot
# The name of one or more pstat files (generated by the profile
# or hotshot module). These are used to generate call graphs.
#pstat: profile.out
# Specify the font used to generate Graphviz graphs.
# (e.g., helvetica or times).
graph-font: Helvetica
# Specify the font size used to generate Graphviz graphs.
#graph-font-size: 10
### Return value options
# The condition upon which Epydoc should exit with a non-zero
# exit status. Possible values are error, warning, docstring_warning
#fail-on: error

334
hrdoc.css Normal file
View File

@ -0,0 +1,334 @@
a { text-decoration: none; }
a:link {color: #0033CC}
a:visited {color: #0033CC}
a:hover {color: #0099FF}
a:active {color: #0033CC}
h3
{
margin-top: 22px;
}
p
{
margin-left: 12px;
margin-right: 12px;
margin-top: 12px;
}
body
{
background-color:#ffffff;
font-family: Verdana;
font-size: 12px;
}
.pre
{
font-family: FixedSys, Courier, Monospace;
white-space: pre;
color: #0000A0;
display: inline;
}
.checkpoint
{
font-weight: bold;
background-color: #FFFF80;
}
.hi /* highlight */
{
display: inline;
background-color: #FFFF70;
}
/*---------------------- The main page, not used now -------------------*/
#main
{
margin: 0 auto 0 auto;
position: relative;
background-image:url(/images/main.jpg);
width: 845px;
height: 568px;
color:#0033CC;
font-family: Verdana;
font-style: italic;
border: 1px solid blue;
}
#logo
{
position: absolute;
right: 10px;
top: 15px;
background-image: url(/images/bigname.png);
width: 357px;
height: 78px;
}
#menu
{
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
#menu li
{
display: block;
list-style-type: none;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
#menu a, #action a
{
margin: 0px 0px 0px 0px;
padding-left: 8px;
padding-right: 8px;
display: block;
width: 140px;
}
#action a
{
margin: 0px 0px 0px 0px;
padding-left: 8px;
padding-right: 8px;
display: block;
width: 100%;
}
#menu li a:hover, #action:hover
{
background-image: url(/images/bigbutton.jpg);
color: white;
}
#menu a:hover, #action a:hover { color:#0033CC }
#action
{
position: absolute;
top: 300px;
left: 600px;
display: block;
width:220px;
padding-right: 8px;
border: 2px solid red;
}
/*--------------------------------------------------------------------------*/
#regular-page
{
margin: 0 auto;
padding: 0;
width: 800px;
display: block;
border: 1px solid blue;
position: relative;
}
#navmenu
{
padding: 0px 0px 0px 0px;
margin: 0px 0px 4px 0px;
position: relative;
background-color: #000000;
height: 28px;
}
#navigation
{
text-align: center;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
#navigation li
{
display: inline;
list-style-type: none;
}
#navigation a
{
width: 99px;
height: 20px;
margin: 0px 0px 0px 0px;
padding: 6px 0px 2px 0px;
position: absolute;
font-weight: bold;
display: inline;
}
#b1 { left: 0px; }
#b2 { left: 99px; }
#b3 { left: 198px; }
#b4 { left: 297px; }
#b5 { left: 396px; }
#b6 { left: 495px; }
#b7 { left: 594px; }
#b8 { left: 693px; }
#navigation li a
{
color: #77BBFF;
}
#navigation li a:hover
{
color: white;
}
#navigation a:hover
{
background-image:url(/images/bigbutton.jpg);
}
#header
{
display: block;
background-image:url(/images/header.jpg);
background-repeat: no-repeat;
background-color: #000000;
height: 160px;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
position: relative;
}
#header-text
{
margin: 0px 0px 0px 0px;
font-size: 24px;
/* font-style: italic;*/
color: #77BBFF;
position: absolute;
bottom: 1px;
right: 10px;
padding-right: 5px;
text-align: right;
}
#col1, #col2
{
padding: 10px 7px 10px 7px;
}
#col1
{
float: left;
width: 170px;
font-size: 24px;
font-style: italic;
}
#col2
{
float: right;
width: 600px;
border-left: 1px solid #0000FF;
}
#bmenu
{
color: #77BBFF;
text-align: center;
font-size: 10px;
clear: both;
list-style-type: none;
margin-bottom: 2px;
}
#bmenu li
{
display: inline;
}
#footer
{
color: #77BBFF;
text-align: center;
font-size: 10px;
clear: both;
margin-top: 0px;
padding-left: 2px;
padding-bottom: 2px;
}
#footer a:link {color: #0099FF}
#footer a:visited {color: #0099FF}
#footer a:hover {color: #0033CC}
/*------ User Manual ------------------------------------------------------*/
#manual h1
{
font-family: "Trebuchet MS", Trebuchet, Verdana, Arial, sans-serif;
font-size: 22px;
background: #bfffbf;
text-align: center;
}
#manual h3
{
font-size: 18px;
font-weight: bold;
line-height: 20px;
background: #bfffff;
}
#manual
{
padding: 0;
font-family: "Trebuchet MS", Trebuchet, Verdana, Arial, sans-serif;
font-size: medium;
width: 570px;
}
/*------ Comparison Page --------------------------------------------------*/
.compare
{
border-top: 1px solid blue;
}
.cmphdr
{
font-size: 22px;
text-align: center;
padding: 10px 7px 10px 7px;
}
.cmptext
{
white-space: pre;
font-family: FixedSys, Courier, Monospace;
font-size: x-small;
color: blue;
background: white;
}
.cmpasm
{
background: #DDEEFF;
}
.cmpc
{
background: #EEFFEE;
}
.cmptell
{
padding: 10px 7px 10px 7px;
clear: both;
font-size: small;
width: 600px;
}

116
hrdoc.py Normal file
View File

@ -0,0 +1,116 @@
import os
import sys
import shutil
from glob import glob
# --------------------------------------------------------------------------
DOC_DIR = 'hr-html'
PYWRAPS_FN = 'idaapi.py'
# --------------------------------------------------------------------------
def add_footer(lines):
S1 = 'Generated by Epydoc'
S2 = '</table>'
p = lines.find(S1)
if p == -1:
return None
p = lines.find(S2, p)
if p == -1:
return None
p += len(S2)
return lines[0:p] + '\n<!--#include virtual="/footer.shtml" -->' + lines[p:]
# --------------------------------------------------------------------------
def define_idaapi_resolver():
"""
Whenever a module named \"idaapi_<something>\" is
spotted, turn it into \"idaapi\".
"""
import epydoc.apidoc
dn = epydoc.apidoc.DottedName.__init__
def resolver(piece):
if piece is not None and isinstance(piece, basestring) and piece.startswith("idaapi_"):
return "idaapi"
else:
return piece
def wrapper(self, *pieces, **options):
return dn(self, *map(resolver, pieces), **options);
epydoc.apidoc.DottedName.__init__ = wrapper
# --------------------------------------------------------------------------
def gen_docs():
import epydoc.cli
import swigdocs
define_idaapi_resolver()
swigdocs.gen_docs(outfn = 'pywraps.py')
# append obj/x86_win_vc_32/idaapi.py to it
# os.system(r'copy /b idaapi.py+..\obj\x86_win_vc_32\idaapi.py idaapi.py')
# delete all output files
for fn in glob('hr-html/*'):
os.unlink(fn)
epydoc.cli.optparse.sys.argv = [ 'epydoc',
'--config', '../hrdoc.cfg',
'--simple-term'
]
# Generate the documentation
epydoc.cli.cli()
# --------------------------------------------------------------------------
def patch_docs():
shutil.copy('../../hrdoc.css', 'epydoc.css')
os.system('chmod +w epydoc.css')
for fn in glob('*.html'):
f = open(fn, 'r')
lines = f.read()
f.close()
r = add_footer(lines)
if not r:
print "-",
continue
f = open(fn, 'w')
f.write(r)
f.close()
print "+",
print "\nDocumentation patched!"
# --------------------------------------------------------------------------
def main():
# Save old directory and adjust import path
curdir = os.getcwd() + os.sep
sys.path.append(curdir + 'python')
sys.path.append(curdir + 'tools')
sys.path.append(curdir + 'docs')
old_dir = os.getcwd()
try:
print "Generating documentation....."
os.chdir('docs')
gen_docs()
os.chdir(DOC_DIR)
patch_docs()
print "Documentation generated!"
finally:
os.chdir(old_dir)
# --------------------------------------------------------------------------
if __name__ == '__main__':
main()
Exit(0)

4
idaapi.i Normal file
View File

@ -0,0 +1,4 @@
// We need this file just to avoid a warning from swig that the input file is not
// specifed precisely and swig had to find it using the header path.
%include "swig/idaapi.i"

340
inject_pydoc.py Normal file
View File

@ -0,0 +1,340 @@
#
# This (non-idiomatic) python script is in charge of
# 1) Parsing all .i files in the 'swig/' directory, and
# collecting all function, classes & methods comments
# that can be found between <pydoc>/</pydoc> tags.
# 2) Reading, line by line, the idaapi_<platform>.py.raw
# file, and for each function, class & method found
# there, associate a possily previously-harvested
# pydoc documentation.
# 3) Generating the idaapi_<platform>.py file.
#
import re
import os
import os.path
DOCSTR_MARKER = "\"\"\""
# --------------------------------------------------------------------------
def split_oneliner_comments(lines):
out_lines = []
for line in lines:
line = line.rstrip()
if line.startswith("#"):
out_lines.append(line)
continue
if len(line) == 0:
out_lines.append("")
continue
pfx = None
while line.find(DOCSTR_MARKER) > -1:
idx = line.find(DOCSTR_MARKER)
meat = line[0:idx]
try:
if len(meat.strip()) == 0:
pfx = meat
out_lines.append(pfx + DOCSTR_MARKER)
else:
out_lines.append((pfx if pfx is not None else "") + meat)
out_lines.append((pfx if pfx is not None else "") + DOCSTR_MARKER)
except:
raise BaseException("Error at line: " + line)
line = line[idx + len(DOCSTR_MARKER):]
if len(line.strip()) > 0:
out_lines.append((pfx if pfx is not None else "") + line)
return out_lines
# --------------------------------------------------------------------------
def dedent(lines):
if len(lines) < 1:
return lines
line0 = lines[0]
indent = len(line0) - len(line0.lstrip())
if indent < 0:
raise BaseException("Couldn't find \" in '" + line0 + "'")
expect = " " * indent
def proc(l):
#print "DE-INDENTING '%s'" % l
if len(l) == 0:
return l # Keep empty lines
prefix = l[0:indent]
if prefix != expect:
raise BaseException("Line: '" + l + "' has wrong indentation. Expected " + str(indent) + " spaces.")
return l[indent:]
return map(proc, lines)
# --------------------------------------------------------------------------
def get_fun_name(line):
return re.search("def ([^\(]*)\(", line).group(1)
# --------------------------------------------------------------------------
def get_class_name(line):
return re.search("class ([^\(:]*)[\(:]?", line).group(1)
# --------------------------------------------------------------------------
def get_indent_string(line):
indent = len(line) - len(line.lstrip())
return " " * indent
# --------------------------------------------------------------------------
class collect_idaapi_pydoc_t(object):
"""
Search in all files in the 'plugins/idapython/swig/' directory
for possible additional <pydoc> we could use later.
"""
S_UNKNOWN = 0
S_IN_PYDOC = 1
S_IN_DOCSTR = 2
# S_STOP = 5
PYDOC_START = "#<pydoc>"
PYDOC_END = "#</pydoc>"
DOCSTR_MARKER = DOCSTR_MARKER #"\"\"\""
state = S_UNKNOWN
lines = None
def __init__(self):
self.idaapi_pydoc = {"funcs" : {}, "classes" : {}}
def next(self):
line = self.lines[0]
self.lines = self.lines[1:]
return line
def set_fun(self, name, collected):
self.idaapi_pydoc["funcs"][name] = dedent(collected)
def collect_fun(self, fun_name):
collected = []
while len(self.lines) > 0:
line = self.next()
if self.state is self.S_IN_PYDOC:
if line.startswith(self.PYDOC_END):
self.state = self.S_UNKNOWN
return self.set_fun(fun_name, collected)
elif line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_DOCSTR
elif not line.startswith(" "):
return self.set_fun(fun_name, collected)
elif self.state is self.S_IN_DOCSTR:
if line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_PYDOC
return self.set_fun(fun_name, collected)
else:
collected.append(line)
else:
raise BaseException("Unexpected state: " + str(self.state))
def set_method(self, cls, method_name, collected):
cls["methods"][method_name] = dedent(collected)
def collect_method(self, cls, method_name):
collected = []
while len(self.lines) > 0:
line = self.next()
if self.state is self.S_IN_PYDOC:
if line.startswith(self.PYDOC_END):
self.state = self.S_UNKNOWN
return self.set_method(cls, method_name, collected)
elif line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_DOCSTR
elif self.state is self.S_IN_DOCSTR:
if line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_PYDOC
return self.set_method(cls, method_name, collected)
else:
collected.append(line)
def set_class(self, name, cls_data, collected):
cls_data["doc"] = dedent(collected) if len(collected) > 0 else None
self.idaapi_pydoc["classes"][name] = cls_data
def collect_cls(self, cls_name):
collected = []
cls = {"methods":{},"doc":None}
while len(self.lines) > 0:
line = self.next()
if self.state is self.S_IN_PYDOC:
if line.startswith(" def "):
self.collect_method(cls, get_fun_name(line))
if self.state == self.S_UNKNOWN: # method marked end of <pydoc>
return self.set_class(cls_name, cls, collected)
elif line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_DOCSTR
elif line.startswith(self.PYDOC_END):
self.state = self.S_UNKNOWN
return self.set_class(cls_name, cls, collected)
elif len(line) > 1 and not line.startswith(" "):
return self.set_class(cls_name, cls, collected)
elif self.state is self.S_IN_DOCSTR:
if line.find(self.DOCSTR_MARKER) > -1:
self.state = self.S_IN_PYDOC
else:
collected.append(line)
def collect_file_pydoc(self, filename):
self.state = self.S_UNKNOWN
with open(filename, "rt") as f:
self.lines = split_oneliner_comments(f.readlines())
context = None
doc = []
while len(self.lines) > 0:
line = self.next()
if self.state is self.S_UNKNOWN:
if line.startswith(self.PYDOC_START):
self.state = self.S_IN_PYDOC
elif self.state is self.S_IN_PYDOC:
if line.startswith("def "):
self.collect_fun(get_fun_name(line))
elif line.startswith("class "):
self.collect_cls(get_class_name(line))
elif line.startswith(self.PYDOC_END):
self.state = self.S_UNKNOWN
def collect(self, dirpath):
for root, dirs, files in os.walk(dirpath):
for f in files:
self.collect_file_pydoc(os.path.join(root, f))
return self.idaapi_pydoc
# --------------------------------------------------------------------------
class idaapi_fixer_t(object):
lines = None
def __init__(self, collected_info):
self.collected_info = collected_info
def next(self):
line = self.lines[0]
self.lines = self.lines[1:]
return line
def copy(self, out):
line = self.next()
out.append(line)
return line
def push_front(self, line):
self.lines.insert(0, line)
def get_fun_info(self, fun_name):
if fun_name in self.collected_info["funcs"]:
return self.collected_info["funcs"][fun_name]
else:
return None
def get_class_info(self, class_name):
if class_name in self.collected_info["classes"]:
return self.collected_info["classes"][class_name]
else:
return None
def get_method_info(self, class_info, method_name):
if method_name in class_info["methods"]:
return class_info["methods"][method_name]
else:
return None
def fix_fun(self, out, class_info=None):
line = self.copy(out)
fun_name = get_fun_name(line)
line = self.copy(out)
if line.find(DOCSTR_MARKER) > -1:
# Determine indentation level
indent = get_indent_string(line)
while True:
line = self.next()
if line.find(DOCSTR_MARKER) > -1:
if class_info is None:
found = self.get_fun_info(fun_name)
else:
found = self.get_method_info(class_info, fun_name)
if found is not None:
out.append("\n")
for fl in found:
out.append(indent + fl)
out.append(line)
break
else:
out.append(line)
def fix_method(self, class_info, out):
return self.fix_fun(out, class_info)
def fix_cls(self, out):
line = self.copy(out)
cls_name = get_class_name(line)
class_info = self.get_class_info(cls_name)
if class_info is None:
return
line = self.copy(out)
indent = get_indent_string(line)
# If class has doc, maybe inject additional <pydoc>
if line.find(DOCSTR_MARKER) > -1:
while True:
line = self.next()
if line.find(DOCSTR_MARKER) > -1:
doc = class_info["doc"]
if doc is not None:
out.append("\n")
for dl in doc:
out.append(indent + dl)
out.append(line)
break
else:
out.append(line)
# Iterate on class methods, and possibly patch
# their docstring
method_start = indent + "def "
while True:
line = self.next()
# print "Fixing methods.. Line is '%s'" % line
if line.startswith(indent) or line.strip() == "":
if line.startswith(method_start):
self.push_front(line)
self.fix_method(class_info, out)
else:
out.append(line)
else:
self.push_front(line)
break
def fix_file(self, idaapi_filename, out_filename):
with open(idaapi_filename, "rt") as f:
self.lines = split_oneliner_comments(f.readlines())
out = []
while len(self.lines) > 0:
line = self.next()
# print "LINE: %s" % line
if line.startswith("def "):
self.push_front(line)
self.fix_fun(out)
elif line.startswith("class "):
self.push_front(line)
self.fix_cls(out)
else:
out.append(line)
with open(out_filename, "wt") as o:
for ol in out:
o.write(ol)
o.write("\n")
# --------------------------------------------------------------------------
if __name__ == '__main__':
import sys
collecter = collect_idaapi_pydoc_t()
collected = collecter.collect(sys.argv[1])
# import pprint
# pprint.pprint(collected, indent=2)
fixer = idaapi_fixer_t(collected)
target_file = sys.argv[2]
result_file = sys.argv[3]
fixer.fix_file(target_file, result_file)

57
patch_directors_cc.py Normal file
View File

@ -0,0 +1,57 @@
import os, shutil, sys, optparse
if __name__ == "__main__":
p = optparse.OptionParser(description='Patch calling conventions for some functions, so it builds on windows')
p.add_option('-v', "--verbose", dest="verbose", action="store_true")
p.add_option('-f', "--file", dest="path", type="string", help="File name, without extension.")
opts, _ = p.parse_args(sys.argv[1:])
if not opts.path:
p.print_help()
sys.exit(1)
patches = [
# user_lvar_visitor_t
"virtual int idaapi handle_retrieved_info",
"virtual int idaapi handle_retrieved_mapping",
"virtual int idaapi get_info_qty_for_saving",
"virtual bool idaapi get_info_for_saving",
"virtual lvar_mapping_t const *idaapi get_info_mapping_for_saving",
# ctree_visitor_t
"virtual int idaapi visit_insn",
"virtual int idaapi visit_expr",
"virtual int idaapi leave_insn",
"virtual int idaapi leave_expr",
# ctree_parentee_t
"virtual int idaapi visit_insn",
"virtual int idaapi visit_expr",
"virtual int idaapi leave_insn",
"virtual int idaapi leave_expr",
# cfunc_parentee_t
"virtual int idaapi visit_insn",
"virtual int idaapi visit_expr",
"virtual int idaapi leave_insn",
"virtual int idaapi leave_expr",
]
path = opts.path
outlines = []
outpath = "%s.cc" % path
with open(path, "r") as f:
lines = f.readlines()
for line in lines:
for patch in patches:
from_text = patch.replace("idaapi ", "")
if line.find(from_text) > -1:
line = line.replace(from_text, patch)
patches.remove(patch)
break
outlines.append(line)
with open(outpath, "w") as f:
f.writelines(outlines)
shutil.move(outpath, path)

View File

@ -287,11 +287,29 @@ static void PythonEvalOrExec(
PyErr_Print(); PyErr_Print();
} }
else else
{
if ( py_result.o != Py_None )
{
bool ok = false;
if ( PyUnicode_Check(py_result.o) )
{
newref_t py_result_utf8(PyUnicode_AsUTF8String(py_result.o));
ok = py_result_utf8 != NULL;
if ( ok )
umsg("%s\n", PyString_AS_STRING(py_result_utf8.o));
}
else
{ {
qstring result_str; qstring result_str;
if ( py_result.o != Py_None && PyW_ObjectToString(py_result.o, &result_str) ) ok = PyW_ObjectToString(py_result.o, &result_str);
if ( ok )
msg("%s\n", result_str.c_str()); msg("%s\n", result_str.c_str());
} }
if ( !ok )
msg("*** IDAPython: Couldn't convert evaluation result\n");
}
}
} }
} }
@ -419,8 +437,9 @@ static int PyRunFile(const char *FileName)
// C runtime library could not be loaded. So we check the disk space before // C runtime library could not be loaded. So we check the disk space before
// calling it. // calling it.
char curdir[QMAXPATH]; char curdir[QMAXPATH];
if ( _getcwd(curdir, sizeof(curdir)) == NULL // check if the current directory is accessible. if not, qgetcwd won't return
|| getdspace(curdir) == 0 ) qgetcwd(curdir, sizeof(curdir));
if ( getdspace(curdir) == 0 )
{ {
warning("No free disk space on %s, python will not be available", curdir); warning("No free disk space on %s, python will not be available", curdir);
return 0; return 0;
@ -428,7 +447,7 @@ static int PyRunFile(const char *FileName)
#endif #endif
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *file_obj = PyFile_FromString((char*)FileName, "r"); //lint !e1776 PyObject *file_obj = PyFile_FromString((char*)FileName, "r"); //lint !e605
PyObject *globals = GetMainGlobals(); PyObject *globals = GetMainGlobals();
if ( globals == NULL || file_obj == NULL ) if ( globals == NULL || file_obj == NULL )
{ {
@ -703,6 +722,18 @@ bool idaapi IDAPython_extlang_run(
return ok; return ok;
} }
//-------------------------------------------------------------------------
static void wrap_in_function(qstring *out, const qstring &body, const char *name)
{
out->sprnt("def %s():\n", name);
// dont copy trailing whitespace
int i = body.length()-1;
while ( i >= 0 && qisspace(body.at(i)) )
i--;
out->append(body.substr(0, i+1));
out->replace("\n", "\n ");
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Compile callback for Python external language evaluator // Compile callback for Python external language evaluator
bool idaapi IDAPython_extlang_compile( bool idaapi IDAPython_extlang_compile(
@ -722,11 +753,9 @@ bool idaapi IDAPython_extlang_compile(
// try compiling as a list of statements // try compiling as a list of statements
// wrap them into a function // wrap them into a function
handle_python_error(errbuf, errbufsize); handle_python_error(errbuf, errbufsize);
qstring expr_copy = expr; qstring func;
expr_copy.replace("\n", "\n "); wrap_in_function(&func, expr, name);
qstring qexpr; code = (PyCodeObject *)Py_CompileString(func.c_str(), "<string>", Py_file_input);
qexpr.sprnt("def %s():\n %s", name, expr_copy.c_str());
code = (PyCodeObject *)Py_CompileString(qexpr.c_str(), "<string>", Py_file_input);
if ( code == NULL ) if ( code == NULL )
{ {
handle_python_error(errbuf, errbufsize); handle_python_error(errbuf, errbufsize);
@ -1200,7 +1229,7 @@ bool idaapi IDAPYthon_cli_complete_line(
if ( py_complete == NULL ) if ( py_complete == NULL )
return false; return false;
newref_t py_ret(PyObject_CallFunction(py_complete.o, "sisi", prefix, n, line, x)); //lint !e1776 newref_t py_ret(PyObject_CallFunction(py_complete.o, "sisi", prefix, n, line, x)); //lint !e605
// Swallow the error // Swallow the error
PyW_GetError(completion); PyW_GetError(completion);
@ -1294,7 +1323,24 @@ void convert_idc_args()
PyObject_SetAttrString(py_mod.o, S_IDC_ARGS_VARNAME, py_args.o); PyObject_SetAttrString(py_mod.o, S_IDC_ARGS_VARNAME, py_args.o);
} }
#ifdef WITH_HEXRAYS
//-------------------------------------------------------------------------
static bool is_hexrays_plugin(const plugin_info_t *pinfo)
{
bool is_hx = false;
if ( pinfo != NULL && pinfo->entry != NULL )
{
const plugin_t *p = pinfo->entry;
if ( streq(p->wanted_name, "Hex-Rays Decompiler") )
is_hx = true;
}
return is_hx;
}
#endif
//------------------------------------------------------------------------ //------------------------------------------------------------------------
//lint -esym(715,va) Symbol not referenced
static int idaapi on_ui_notification(void *, int code, va_list va) static int idaapi on_ui_notification(void *, int code, va_list va)
{ {
#ifdef WITH_HEXRAYS #ifdef WITH_HEXRAYS
@ -1323,16 +1369,10 @@ static int idaapi on_ui_notification(void *, int code, va_list va)
break; break;
#ifdef WITH_HEXRAYS #ifdef WITH_HEXRAYS
// FIXME: HACK! THERE SHOULD BE A UI (or IDB?) NOTIFICATION case ui_plugin_loaded:
// 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 ) if ( hexdsp == NULL )
{ {
(void)va_arg(va, char *); // Drop 'menupath' if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
const char *name = va_arg(va, char *); // Look for 'name'.
if ( streq(name, "Jump to pseudocode") )
{ {
init_hexrays_plugin(0); init_hexrays_plugin(0);
if ( hexdsp != NULL ) if ( hexdsp != NULL )
@ -1341,14 +1381,13 @@ static int idaapi on_ui_notification(void *, int code, va_list va)
} }
break; break;
case ui_del_menu_item: case ui_plugin_unloading:
{ {
if ( hexdsp != NULL ) if ( hexdsp != NULL )
{ {
// Hex-Rays will close. Make sure all the refcounted cfunc_t objects // Hex-Rays will close. Make sure all the refcounted cfunc_t objects
// are cleared right away. // are cleared right away.
const char *menupath = va_arg(va, char *); if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
if ( streq(menupath, "Jump/Jump to pseudocode") )
{ {
hexrays_clear_python_cfuncptr_t_references(); hexrays_clear_python_cfuncptr_t_references();
hexdsp = NULL; hexdsp = NULL;

View File

@ -374,8 +374,8 @@ def DecodePreviousInstruction(ea):
@param ea: address to decode @param ea: address to decode
@return: None or a new insn_t instance @return: None or a new insn_t instance
""" """
inslen = idaapi.decode_prev_insn(ea) prev_addr = idaapi.decode_prev_insn(ea)
if inslen == 0: if prev_addr == idaapi.BADADDR:
return None return None
return idaapi.cmd.copy() return idaapi.cmd.copy()
@ -462,7 +462,8 @@ def GetInputFileMD5():
class Strings(object): class Strings(object):
""" """
Returns the string list. Allows iterating over the string list. The set of strings will not be modified.
, unless asked explicitly at setup()-time..
Example: Example:
s = Strings() s = Strings()
@ -483,8 +484,34 @@ class Strings(object):
self.length = si.length self.length = si.length
"""string length""" """string length"""
def is_1_byte_encoding(self):
return not self.is_2_bytes_encoding() and not self.is_4_bytes_encoding()
def is_2_bytes_encoding(self):
return (self.type & 7) in [idaapi.ASCSTR_UTF16, idaapi.ASCSTR_ULEN2, idaapi.ASCSTR_ULEN4]
def is_4_bytes_encoding(self):
return (self.type & 7) == idaapi.ASCSTR_UTF32
def _toseq(self, as_unicode):
if self.is_2_bytes_encoding():
conv = idaapi.ACFOPT_UTF16
pyenc = "utf-16"
elif self.is_4_bytes_encoding():
conv = idaapi.ACFOPT_UTF8
pyenc = "utf-8"
else:
conv = idaapi.ACFOPT_ASCII
pyenc = 'ascii'
strbytes = idaapi.get_ascii_contents2(self.ea, self.length, self.type, conv)
return unicode(strbytes, pyenc, 'replace') if as_unicode else strbytes
def __str__(self): def __str__(self):
return idc.GetString(self.ea, self.length, self.type) return self._toseq(False)
def __unicode__(self):
return self._toseq(True)
STR_C = 0x0001 STR_C = 0x0001
"""C-style ASCII string""" """C-style ASCII string"""
@ -505,8 +532,7 @@ class Strings(object):
"""Clears the strings list cache""" """Clears the strings list cache"""
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
def __init__(self, default_setup = False):
def __init__(self, default_setup = True):
""" """
Initializes the Strings enumeration helper class Initializes the Strings enumeration helper class
@ -515,10 +541,11 @@ class Strings(object):
self.size = 0 self.size = 0
if default_setup: if default_setup:
self.setup() self.setup()
else:
self.refresh()
self._si = idaapi.string_info_t() self._si = idaapi.string_info_t()
def refresh(self, ea1=None, ea2=None): def refresh(self, ea1=None, ea2=None):
"""Refreshes the strings list""" """Refreshes the strings list"""
if ea1 is None: if ea1 is None:
@ -750,14 +777,6 @@ def ProcessUiActions(actions, flags=0):
helper = __process_ui_actions_helper(actions, flags) helper = __process_ui_actions_helper(actions, flags)
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,)) return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
# ----------------------------------------------------------------------------
def IsBatchMode():
"""
Checks if batch mode is enabled
@return: True if batch mode is enabled and False otherwise
"""
return idaapi.cvar.batch != 0
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
class peutils_t(object): class peutils_t(object):

View File

@ -1450,7 +1450,11 @@ def PatchByte(ea, value):
@param ea: linear address @param ea: linear address
@param value: new value of the byte @param value: new value of the byte
@return: 1 if successful, 0 if not @return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
""" """
return idaapi.patch_byte(ea, value) return idaapi.patch_byte(ea, value)
@ -1462,7 +1466,11 @@ def PatchWord(ea, value):
@param ea: linear address @param ea: linear address
@param value: new value of the word @param value: new value of the word
@return: 1 if successful, 0 if not @return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
""" """
return idaapi.patch_word(ea, value) return idaapi.patch_word(ea, value)
@ -1474,11 +1482,31 @@ def PatchDword(ea, value):
@param ea: linear address @param ea: linear address
@param value: new value of the double word @param value: new value of the double word
@return: 1 if successful, 0 if not @return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
""" """
return idaapi.patch_long(ea, value) return idaapi.patch_long(ea, value)
def PatchQword(ea, value):
"""
Change value of a quad word
@param ea: linear address
@param value: new value of the quad word
@return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
"""
return idaapi.patch_qword(ea, value)
def SetFlags(ea, flags): def SetFlags(ea, flags):
""" """
Set new value of flags Set new value of flags
@ -2288,13 +2316,13 @@ o_displ = idaapi.o_displ # Memory Reg [Base Reg + Index Reg + Displacem
o_imm = idaapi.o_imm # Immediate Value value o_imm = idaapi.o_imm # Immediate Value value
o_far = idaapi.o_far # Immediate Far Address (CODE) addr o_far = idaapi.o_far # Immediate Far Address (CODE) addr
o_near = idaapi.o_near # Immediate Near Address (CODE) addr o_near = idaapi.o_near # Immediate Near Address (CODE) addr
o_idpspec0 = idaapi.o_idpspec0 # IDP specific type o_idpspec0 = idaapi.o_idpspec0 # Processor specific type
o_idpspec1 = idaapi.o_idpspec1 # IDP specific type o_idpspec1 = idaapi.o_idpspec1 # Processor specific type
o_idpspec2 = idaapi.o_idpspec2 # IDP specific type o_idpspec2 = idaapi.o_idpspec2 # Processor specific type
o_idpspec3 = idaapi.o_idpspec3 # IDP specific type o_idpspec3 = idaapi.o_idpspec3 # Processor specific type
o_idpspec4 = idaapi.o_idpspec4 # IDP specific type o_idpspec4 = idaapi.o_idpspec4 # Processor specific type
o_idpspec5 = idaapi.o_idpspec5 # IDP specific type o_idpspec5 = idaapi.o_idpspec5 # Processor specific type
o_last = idaapi.o_last # first unused type # There can be more processor specific types
# x86 # x86
o_trreg = idaapi.o_idpspec0 # trace register o_trreg = idaapi.o_idpspec0 # trace register
@ -2308,7 +2336,7 @@ o_xmmreg = idaapi.o_idpspec5 # xmm register
o_reglist = idaapi.o_idpspec1 # Register list (for LDM/STM) o_reglist = idaapi.o_idpspec1 # Register list (for LDM/STM)
o_creglist = idaapi.o_idpspec2 # Coprocessor register list (for CDP) o_creglist = idaapi.o_idpspec2 # Coprocessor register list (for CDP)
o_creg = idaapi.o_idpspec3 # Coprocessor register (for LDC/STC) o_creg = idaapi.o_idpspec3 # Coprocessor register (for LDC/STC)
o_fpreg = idaapi.o_idpspec4 # Floating point register o_fpreg_arm = idaapi.o_idpspec4 # Floating point register
o_fpreglist = idaapi.o_idpspec5 # Floating point register list o_fpreglist = idaapi.o_idpspec5 # Floating point register list
o_text = (idaapi.o_idpspec5+1) # Arbitrary text stored in the operand o_text = (idaapi.o_idpspec5+1) # Arbitrary text stored in the operand
@ -3116,6 +3144,20 @@ def Message(msg):
idaapi.msg(msg) idaapi.msg(msg)
def UMessage(msg):
"""
Display an UTF-8 string in the message window
The result of the stringification of the arguments
will be treated as an UTF-8 string.
@param msg: message to print (formatting is done in Python)
This function can be used to debug IDC scripts
"""
idaapi.umsg(msg)
def Warning(msg): def Warning(msg):
""" """
Display a message in a message box Display a message in a message box
@ -6917,16 +6959,16 @@ def ApplyType(ea, py_type, flags = TINFO_DEFINITE):
@return: Boolean @return: Boolean
""" """
if py_type != None: if py_type is None:
py_type = ""
if isinstance(py_type, basestring) and len(py_type) == 0:
pt = ("", "")
else:
if len(py_type) == 3: if len(py_type) == 3:
pt = py_type[1:] # skip name component pt = py_type[1:] # skip name component
else: else:
pt = py_type pt = py_type
return idaapi.apply_type(idaapi.cvar.idati, pt[0], pt[1], ea, flags) return idaapi.apply_type(idaapi.cvar.idati, pt[0], pt[1], ea, flags)
if idaapi.has_ti(ea):
idaapi.del_tinfo(ea)
return True
return False
def SetType(ea, newtype): def SetType(ea, newtype):
""" """
@ -6941,7 +6983,7 @@ def SetType(ea, newtype):
@return: 1-ok, 0-failed. @return: 1-ok, 0-failed.
""" """
if newtype is not '': if newtype is not '':
pt = ParseType(newtype, 0) pt = ParseType(newtype, 1) # silent
if pt is None: if pt is None:
# parsing failed # parsing failed
return None return None

View File

@ -28,9 +28,8 @@ class IDAPythonStdOut:
Dummy file-like class that receives stout and stderr Dummy file-like class that receives stout and stderr
""" """
def write(self, text): def write(self, text):
# Swap out the unprintable characters # NB: in case 'text' is Unicode, msg() will decode it
text = text.decode('ascii', 'replace').encode('ascii', 'replace') # and call umsg() to print it
# Print to IDA message window
_idaapi.msg(text) _idaapi.msg(text)
def flush(self): def flush(self):

View File

@ -93,6 +93,18 @@ public:
} while ( false ) } while ( false )
//-------------------------------------------------------------------------
struct exc_report_t
{
~exc_report_t()
{
if ( PyErr_Occurred() )
PyErr_Print();
}
};
#define PYW_GIL_GET_AND_REPORT_ERROR PYW_GIL_GET; exc_report_t exc;
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// All the exported functions from PyWraps are forward declared here // All the exported functions from PyWraps are forward declared here
insn_t *insn_t_get_clink(PyObject *self); insn_t *insn_t_get_clink(PyObject *self);
@ -125,25 +137,38 @@ struct ref_t
~ref_t() { decref(); } ~ref_t() { decref(); }
ref_t &operator=(const ref_t &other) ref_t &operator=(const ref_t &other)
{ {
decref(); // We *must* first (possibly) set & incref the other object,
// because decref() might call the Python's deallocator, which
// might have side-effects, that might affect this ref_t
// instance.
// If that's too many 'might' to your taste, let me illustrate.
//
// py_plgform.hpp's 'plgform_t' holds a 'ref_t' instance, named 'py_obj'.
// If the actual, Qt widget wrapped by that plgform_t gets destroyed,
// plgform_t::unhook() will be called, which will assign an
// empty ref_t instance to its 'py_obj'.
// That will decrement the refcount, and might call the deallocator:
// the plgform_t::destroy static function.
// That function will 'delete' the plgform_t object.
// But, in the ~plgform_t() destructor, the 'py_obj' object will be
// destroyed too: decreasing once again the refcnt (which now falls to -1).
// At this point, all hell breaks loose (or is allowed to).
PyObject *was = o;
o = other.o; o = other.o;
incref(); incref();
if ( was != NULL )
Py_DECREF(was);
return *this; return *this;
} }
void incref() const { if ( o != NULL ) Py_INCREF(o); } void incref() const { if ( o != NULL ) Py_INCREF(o); }
void decref() const { if ( o != NULL ) Py_DECREF(o); } void decref() const { if ( o != NULL ) { QASSERT(30469, o->ob_refcnt > 0); Py_DECREF(o); } }
bool operator==(PyObject *other) const { return o == other; } bool operator==(PyObject *other) const { return o == other; }
bool operator!=(PyObject *other) const { return ! ((*this) == other); } bool operator!=(PyObject *other) const { return ! ((*this) == other); }
bool operator==(const ref_t &other) const { return o == other.o; } bool operator==(const ref_t &other) const { return o == other.o; }
bool operator!=(const ref_t &other) const { return ! ((*this) == other); } bool operator!=(const ref_t &other) const { return ! ((*this) == other); }
// operator PyObject *() const { return o; }
// PyObject *operator ->() const { return o; }
// PyObject &operator *() const { return *o; }
//protected:
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -318,6 +343,21 @@ bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec);
// Converts a Python list to a qstrvec // Converts a Python list to a qstrvec
bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec); bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec);
//-------------------------------------------------------------------------
PyObject *qstrvec2pylist(qstrvec_t &vec);
//-------------------------------------------------------------------------
inline bool PyWStringOrNone_Check(PyObject *tp)
{
return tp == Py_None || PyString_Check(tp);
}
//-------------------------------------------------------------------------
inline const p_list * PyW_Fields(PyObject *tp)
{
return tp == Py_None ? NULL : (const p_list *) PyString_AsString(tp);
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// notify_when() // notify_when()

View File

@ -1,2 +1,2 @@
@echo off @echo off
c:\python27\python.exe deploy_all.py deploy_all.py

View File

@ -143,6 +143,12 @@ deploys = {
"tgt" : "../swig/lines.i" "tgt" : "../swig/lines.i"
}, },
"registry" : {
"tag" : "py_registry",
"src" : ["py_registry.hpp"],
"tgt" : "../swig/registry.i"
},
"pc_win32_appcall" : { "pc_win32_appcall" : {
"tag" : "appcalltest", "tag" : "appcalltest",
"src" : ["py_appcall.py"], "src" : ["py_appcall.py"],
@ -155,6 +161,12 @@ deploys = {
"tgt" : "../../../tests/input/pc_win32_custdata1.pe.hints" "tgt" : "../../../tests/input/pc_win32_custdata1.pe.hints"
}, },
"ex_choose2" : {
"tag" : "py_choose2ex1",
"src" : ["py_choose2.py"],
"tgt" : "../examples/ex_choose2.py"
},
"ex_formchooser" : { "ex_formchooser" : {
"tag" : "ex_formchooser", "tag" : "ex_formchooser",
"src" : ["py_askusingform.py"], "src" : ["py_askusingform.py"],

View File

@ -126,7 +126,7 @@ static void formchgcbfa_refresh_field(size_t p_fa, int fid)
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static void formchgcbfa_close(size_t p_fa, int fid, int close_normally) static void formchgcbfa_close(size_t p_fa, int close_normally)
{ {
DECLARE_FORM_ACTIONS; DECLARE_FORM_ACTIONS;
fa->close(close_normally); fa->close(close_normally);
@ -362,6 +362,12 @@ static size_t py_get_AskUsingForm()
return (size_t)AskUsingForm_c; return (size_t)AskUsingForm_c;
} }
static size_t py_get_OpenForm()
{
// See comments above.
return (size_t)OpenForm_c;
}
//</inline(py_kernwin)> //</inline(py_kernwin)>
#endif // __PY_ASKUSINGFORM__ #endif // __PY_ASKUSINGFORM__

View File

@ -29,6 +29,7 @@ try:
_idaapi.CHOOSER_POPUP_MENU = 1 _idaapi.CHOOSER_POPUP_MENU = 1
pywraps = object_t() pywraps = object_t()
pywraps.py_get_AskUsingForm = lambda: 0 pywraps.py_get_AskUsingForm = lambda: 0
pywraps.py_get_OpenForm = lambda: 0
class Choose2(object): class Choose2(object):
CH_MULTI = 1 CH_MULTI = 1
@ -891,7 +892,7 @@ class Form(object):
def __init__(self, form, controls): def __init__(self, form, controls):
""" """
Contruct a Form class. Contruct a Form class.
This class wraps around AskUsingForm() and provides an easier / alternative syntax for describing forms. This class wraps around AskUsingForm() or OpenForm() and provides an easier / alternative syntax for describing forms.
The form control names are wrapped inside the opening and closing curly braces and the control themselves are The form control names are wrapped inside the opening and closing curly braces and the control themselves are
defined and instantiated via various form controls (subclasses of Form). defined and instantiated via various form controls (subclasses of Form).
@ -908,6 +909,15 @@ class Form(object):
self.title = None self.title = None
"""The Form title. It will be filled when the form is compiled""" """The Form title. It will be filled when the form is compiled"""
self.modal = True
"""By default, forms are modal"""
self.openform_flags = 0
"""
If non-modal, these flags will be passed to OpenForm.
This is an OR'ed combination of the PluginForm.FORM_* values.
"""
def Free(self): def Free(self):
""" """
@ -1039,6 +1049,11 @@ class Form(object):
""" """
# First argument is the form string # First argument is the form string
args = [None] args = [None]
# Second argument, if form is not modal, is the set of flags
if not self.modal:
args.append(self.openform_flags | 0x80) # Add FORM_QWIDGET
ctrlcnt = 1 ctrlcnt = 1
# Reset all group control internal flags # Reset all group control internal flags
@ -1121,6 +1136,22 @@ class Form(object):
ctrlcnt += 1 ctrlcnt += 1
# If no FormChangeCb instance was passed, and thus there's no '%/'
# in the resulting form string, let's provide a minimal one, so that
# we will retrieve 'p_fa', and thus actions that rely on it will work.
if form.find(Form.FT_FORMCHG) < 0:
form = form + Form.FT_FORMCHG
fccb = Form.FormChangeCb(lambda *args: 1)
self.Add("___dummyfchgcb", fccb)
# Regardless of the actual position of '%/' in the form
# string, a formchange callback _must_ be right after
# the form string.
if self.modal:
inspos = 1
else:
inspos = 2
args.insert(inspos, fccb.get_arg())
# Patch in the final form string # Patch in the final form string
args[0] = form args[0] = form
@ -1157,18 +1188,34 @@ class Form(object):
return self.__args is not None return self.__args is not None
def Execute(self): def _ChkCompiled(self):
"""
Displays a compiled form.
@return: 1 - ok ; 0 - cancel
"""
if not self.Compiled(): if not self.Compiled():
raise SyntaxError("Form is not compiled") raise SyntaxError("Form is not compiled")
# Call AskUsingForm()
def Execute(self):
"""
Displays a modal dialog containing the compiled form.
@return: 1 - ok ; 0 - cancel
"""
self._ChkCompiled()
if not self.modal:
raise SyntaxError("Form is not modal. Open() should be instead")
return AskUsingForm(*self.__args) return AskUsingForm(*self.__args)
def Open(self):
"""
Opens a widget containing the compiled form.
"""
self._ChkCompiled()
if self.modal:
raise SyntaxError("Form is modal. Execute() should be instead")
OpenForm(*self.__args)
def EnableField(self, ctrl, enable): def EnableField(self, ctrl, enable):
""" """
Enable or disable an input field Enable or disable an input field
@ -1311,15 +1358,18 @@ try:
# Setup the numeric argument size # Setup the numeric argument size
Form.NumericArgument.DefI64 = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL Form.NumericArgument.DefI64 = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
AskUsingForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_AskUsingForm()) AskUsingForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_AskUsingForm())
OpenForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_OpenForm())
except: except:
def AskUsingForm__(*args): def AskUsingForm__(*args):
warning("AskUsingForm() needs ctypes library in order to work") warning("AskUsingForm() needs ctypes library in order to work")
return 0 return 0
def OpenForm__(*args):
warning("OpenForm() needs ctypes library in order to work")
def AskUsingForm(*args): def AskUsingForm(*args):
""" """
Calls the AskUsingForm() Calls AskUsingForm()
@param: Compiled Arguments obtain through the Form.Compile() function @param: Compiled Arguments obtain through the Form.Compile() function
@return: 1 = ok, 0 = cancel @return: 1 = ok, 0 = cancel
""" """
@ -1328,6 +1378,15 @@ def AskUsingForm(*args):
set_script_timeout(old) set_script_timeout(old)
return r return r
def OpenForm(*args):
"""
Calls OpenForm()
@param: Compiled Arguments obtain through the Form.Compile() function
"""
old = set_script_timeout(0)
r = OpenForm__(*args)
set_script_timeout(old)
#</pycode(py_kernwin)> #</pycode(py_kernwin)>
@ -1671,7 +1730,7 @@ Dropdown list test
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
def test_dropdown(execute=True): def test_dropdown(execute=True):
"""Test the combobox controls""" """Test the combobox controls, in a modal dialog"""
f = MyForm3() f = MyForm3()
f, args = f.Compile() f, args = f.Compile()
if execute: if execute:
@ -1687,6 +1746,18 @@ def test_dropdown(execute=True):
f.Free() f.Free()
# --------------------------------------------------------------------------
tdn_form = None
def test_dropdown_nomodal():
"""Test the combobox controls, in a non-modal form"""
global tdn_form
if tdn_form is None:
tdn_form = MyForm3()
tdn_form.modal = False
tdn_form.openform_flags = idaapi.PluginForm.FORM_TAB
tdn_form, _ = tdn_form.Compile()
tdn_form.Open()
#</pycode(ex_askusingform)> #</pycode(ex_askusingform)>
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------

View File

@ -153,15 +153,21 @@ ACFOPT_ESCAPE = 0x00000010 # for ACFOPT_ASCII, convert non-printable
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII): def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
""" """
Get contents of ascii string Get bytes contents at location, possibly converted.
This function returns the displayed part of the string
It works even if the string has not been created in the database yet. It works even if the string has not been created in the database yet.
Note that this will <b>always</b> return a simple string of bytes
(i.e., a 'str' instance), and not a string of unicode characters.
If you want auto-conversion to unicode strings (that is: real strings),
you should probably be using the idautils.Strings class.
@param ea: linear address of the string @param ea: linear address of the string
@param len: length of the string in bytes (including terminating 0) @param len: length of the string in bytes (including terminating 0)
@param type: type of the string @param type: type of the string. Represents both the character encoding,
@param flags: combination of ACFOPT_... <u>and</u> the 'type' of string at the given location.
@return: string contents (not including terminating 0) or None @param flags: combination of ACFOPT_..., to perform output conversion.
@return: a bytes-filled str object.
""" """
pass pass
#</pydoc> #</pydoc>
@ -177,7 +183,7 @@ static PyObject *py_get_ascii_contents2(
return NULL; return NULL;
size_t used_size; size_t used_size;
if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size) ) if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size, flags) )
{ {
qfree(buf); qfree(buf);
Py_RETURN_NONE; Py_RETURN_NONE;

View File

@ -375,6 +375,56 @@ private:
} }
} }
bool split_chooser_caption(qstring *out_title, qstring *out_caption, const char *caption) const
{
if ( get_embedded() != NULL )
{
// For embedded chooser, the "caption" will be overloaded to encode
// the AskUsingForm's title, caption and embedded chooser id
// Title:EmbeddedChooserID:Caption
char title_buf[MAXSTR];
const char *ptitle;
static const char delimiter[] = ":";
char temp[MAXSTR];
qstrncpy(temp, caption, sizeof(temp));
char *ctx;
char *p = qstrtok(temp, delimiter, &ctx);
if ( p == NULL )
return false;
// Copy the title
char title_str[MAXSTR];
qstrncpy(title_str, p, sizeof(title_str));
// Copy the echooser ID
p = qstrtok(NULL, delimiter, &ctx);
if ( p == NULL )
return false;
char id_str[10];
qstrncpy(id_str, p, sizeof(id_str));
// Form the new title of the form: "AskUsingFormTitle:EchooserId"
qsnprintf(title_buf, sizeof(title_buf), "%s:%s", title_str, id_str);
// Adjust the title
*out_title = title_buf;
// Adjust the caption
p = qstrtok(NULL, delimiter, &ctx);
*out_caption = caption + (p - temp);
}
else
{
*out_title = title;
*out_caption = caption;
}
return true;
}
public: public:
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Public methods // Public methods
@ -420,7 +470,7 @@ public:
} }
int add_command( int add_command(
const char *caption, const char *_caption,
int flags=0, int flags=0,
int menu_index=-1, int menu_index=-1,
int icon=-1) int icon=-1)
@ -428,60 +478,16 @@ public:
if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS ) if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS )
return -1; return -1;
// For embedded chooser, the "caption" will be overloaded to encode qstring title, caption;
// the AskUsingForm's title, caption and embedded chooser id if ( !split_chooser_caption(&title, &caption, _caption)
// Title:EmbeddedChooserID:Caption || !add_chooser_command(
char title_buf[MAXSTR]; title.c_str(),
const char *ptitle; caption.c_str(),
// Embedded chooser?
if ( get_embedded() != NULL )
{
static const char delimiter[] = ":";
char temp[MAXSTR];
qstrncpy(temp, caption, sizeof(temp));
char *p = strtok(temp, delimiter);
if ( p == NULL )
return -1;
// Copy the title
char title_str[MAXSTR];
qstrncpy(title_str, p, sizeof(title_str));
// Copy the echooser ID
p = strtok(NULL, delimiter);
if ( p == NULL )
return -1;
char id_str[10];
qstrncpy(id_str, p, sizeof(id_str));
// Form the new title of the form: "AskUsingFormTitle:EchooserId"
qsnprintf(title_buf, sizeof(title_buf), "%s:%s", title_str, id_str);
// Adjust the title
ptitle = title_buf;
// Adjust the caption
p = strtok(NULL, delimiter);
caption += (p - temp);
}
else
{
ptitle = title.c_str();
}
if ( !add_chooser_command(
ptitle,
caption,
menu_cbs[menu_cb_idx], menu_cbs[menu_cb_idx],
menu_index, menu_index,
icon, icon,
flags) ) flags) )
{
return -1; return -1;
}
return menu_cb_idx++; return menu_cb_idx++;
} }
@ -869,10 +875,7 @@ int choose2_add_command(
int icon=-1) int icon=-1)
{ {
py_choose2_t *c2 = choose2_find_instance(self); py_choose2_t *c2 = choose2_find_instance(self);
if ( c2 != NULL ) return c2 == NULL ? -2 : c2->add_command(caption, flags, menu_index, icon);
return c2->add_command(caption, flags, menu_index, icon);
else
return -2;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------

View File

@ -54,6 +54,8 @@ class Choose2(object):
CH_ATTRS = 0x10 CH_ATTRS = 0x10
CH_NOIDB = 0x20 CH_NOIDB = 0x20
"""use the chooser even without an open database, same as x0=-2""" """use the chooser even without an open database, same as x0=-2"""
CH_UTF8 = 0x40
"""string encoding is utf-8"""
CH_BUILTIN_MASK = 0xF80000 CH_BUILTIN_MASK = 0xF80000
@ -162,12 +164,11 @@ class Choose2(object):
icon = -1, icon = -1,
emb=None): emb=None):
""" """
Adds a new chooser command Deprecated: Use
Save the returned value and later use it in the OnCommand handler - register_action()
- attach_action_to_menu()
@return: Returns a negative value on failure or the command index - attach_action_to_popup()
""" """
# Use the 'emb' as a sentinel. It will be passed the correct value from the EmbeddedChooserControl # Use the 'emb' as a sentinel. It will be passed the correct value from the EmbeddedChooserControl
if self.embedded and ((emb is None) or (emb != 2002)): if self.embedded and ((emb is None) or (emb != 2002)):
raise RuntimeError("Please add a command through EmbeddedChooserControl.AddCommand()") raise RuntimeError("Please add a command through EmbeddedChooserControl.AddCommand()")
@ -275,6 +276,24 @@ class Choose2(object):
#</pycode(py_kernwin)> #</pycode(py_kernwin)>
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
#<pycode(py_choose2ex1)>
class chooser_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
self.thing = thing
def activate(self, ctx):
sel = []
for i in xrange(len(ctx.chooser_selection)):
sel.append(str(ctx.chooser_selection.at(i)))
print "command %s selected @ %s" % (self.thing, ", ".join(sel))
def update(self, ctx):
return idaapi.AST_ENABLE_FOR_FORM if idaapi.is_chooser_tform(ctx.form_type) else idaapi.AST_DISABLE_FOR_FORM
class MyChoose2(Choose2): class MyChoose2(Choose2):
def __init__(self, title, nb = 5, flags=0, width=None, height=None, embedded=False, modal=False): def __init__(self, title, nb = 5, flags=0, width=None, height=None, embedded=False, modal=False):
@ -328,15 +347,6 @@ class MyChoose2(Choose2):
print("refresh %d" % n) print("refresh %d" % n)
return n return n
def OnCommand(self, n, cmd_id):
if cmd_id == self.cmd_a:
print "command A selected @", n
elif cmd_id == self.cmd_b:
print "command B selected @", n
else:
print "Unknown command:", cmd_id, "@", n
return 1
def OnGetIcon(self, n): def OnGetIcon(self, n):
r = self.items[n] r = self.items[n]
t = self.icon + r[1].count("*") t = self.icon + r[1].count("*")
@ -344,14 +354,7 @@ class MyChoose2(Choose2):
return t return t
def show(self): def show(self):
t = self.Show(self.modal) return self.Show(self.modal) >= 0
if t < 0:
return False
if not self.modal:
self.cmd_a = self.AddCommand("command A")
self.cmd_b = self.AddCommand("command B")
print("Show() returned: %d\n" % t)
return True
def make_item(self): def make_item(self):
r = [str(self.n), "func_%04d" % self.n] r = [str(self.n), "func_%04d" % self.n]
@ -369,6 +372,9 @@ def test_choose2(modal=False):
global c global c
c = MyChoose2("Choose2 - sample 1", nb=10, modal=modal) c = MyChoose2("Choose2 - sample 1", nb=10, modal=modal)
r = c.show() r = c.show()
form = idaapi.get_current_tform()
for thing in ["A", "B"]:
idaapi.attach_action_to_popup(form, None, "choose2:act%s" % thing)
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
def test_choose2_embedded(): def test_choose2_embedded():
@ -386,5 +392,17 @@ def test_choose2_embedded():
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
if __name__ == '__main__': if __name__ == '__main__':
# Register actions
for thing in ["A", "B"]:
actname = "choose2:act%s" % thing
idaapi.register_action(
idaapi.action_desc_t(
actname,
"command %s" % thing,
chooser_handler_t(thing)))
#test_choose2_embedded() #test_choose2_embedded()
test_choose2(False) test_choose2(False)
#</pycode(py_choose2ex1)>

View File

@ -134,6 +134,9 @@ public:
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// FIXME: This should inherit py_view_base.hpp's py_customidamemo_t,
// just like py_graph.hpp's py_graph_t does.
// There should be a way to "merge" the two mechanisms; they are similar.
class customviewer_t class customviewer_t
{ {
protected: protected:
@ -166,13 +169,6 @@ private:
qstring _curline; qstring _curline;
intvec_t _installed_popups; intvec_t _installed_popups;
static bool idaapi s_popup_cb(void *ud)
{
PYW_GIL_GET;
customviewer_t *_this = (customviewer_t *)ud;
return _this->on_popup();
}
static bool idaapi s_popup_menu_cb(void *ud) static bool idaapi s_popup_menu_cb(void *ud)
{ {
size_t mid = (size_t)ud; size_t mid = (size_t)ud;
@ -271,6 +267,10 @@ private:
} }
public: public:
inline TForm *get_tform() { return _form; }
inline TCustomControl *get_tcustom_control() { return _cv; }
// //
// All the overridable callbacks // All the overridable callbacks
// //
@ -1111,6 +1111,22 @@ bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl)
DECL_THIS; DECL_THIS;
return _this == NULL ? false : _this->edit_line(nline, py_sl); return _this == NULL ? false : _this->edit_line(nline, py_sl);
} }
//-------------------------------------------------------------------------
TForm *pyscv_get_tform(PyObject *py_this)
{
DECL_THIS;
return _this == NULL ? NULL : _this->get_tform();
}
//-------------------------------------------------------------------------
TCustomControl *pyscv_get_tcustom_control(PyObject *py_this)
{
DECL_THIS;
return _this == NULL ? NULL : _this->get_tcustom_control();
}
#undef DECL_THIS #undef DECL_THIS
//</inline(py_custviewer)> //</inline(py_custviewer)>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -204,6 +204,24 @@ class simplecustviewer_t(object):
"""Returns True if the current view is the focused view""" """Returns True if the current view is the focused view"""
return _idaapi.pyscv_is_focused(self.__this) return _idaapi.pyscv_is_focused(self.__this)
def GetTForm(self):
"""
Return the TForm hosting this view.
@return: The TForm that hosts this view, or None.
"""
return _idaapi.pyscv_get_tform(self.__this)
def GetTCustomControl(self):
"""
Return the TCustomControl underlying this view.
@return: The TCustomControl underlying this view, or None.
"""
return _idaapi.pyscv_get_tcustom_control(self.__this)
# Here are all the supported events # Here are all the supported events
#<pydoc> #<pydoc>
# def OnClick(self, shift): # def OnClick(self, shift):
@ -278,6 +296,18 @@ class simplecustviewer_t(object):
#<pycode(py_custviewerex1)> #<pycode(py_custviewerex1)>
class say_something_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
self.thing = thing
def activate(self, ctx):
print self.thing
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
class mycv_t(simplecustviewer_t): class mycv_t(simplecustviewer_t):
def Create(self, sn=None): def Create(self, sn=None):
@ -289,8 +319,6 @@ class mycv_t(simplecustviewer_t):
# Create the customviewer # Create the customviewer
if not simplecustviewer_t.Create(self, title): if not simplecustviewer_t.Create(self, title):
return False return False
self.menu_hello = self.AddPopupMenu("Hello")
self.menu_world = self.AddPopupMenu("World")
for i in xrange(0, 100): for i in xrange(0, 100):
self.AddLine("Line %d" % i) self.AddLine("Line %d" % i)
@ -391,13 +419,6 @@ class mycv_t(simplecustviewer_t):
return False return False
return True return True
def OnPopup(self):
"""
Context menu popup is about to be shown. Create items dynamically if you wish
@return: Boolean. True if you handled the event
"""
print "OnPopup"
def OnHint(self, lineno): def OnHint(self, lineno):
""" """
Hint requested for the given line number. Hint requested for the given line number.
@ -408,22 +429,6 @@ class mycv_t(simplecustviewer_t):
""" """
return (1, "OnHint, line=%d" % lineno) return (1, "OnHint, line=%d" % lineno)
def OnPopupMenu(self, menu_id):
"""
A context (or popup) menu item was executed.
@param menu_id: ID previously registered with AddPopupMenu()
@return: Boolean
"""
print "OnPopupMenu, menu_id=%d" % menu_id
if menu_id == self.menu_hello:
print "Hello"
elif menu_id == self.menu_world:
print "World"
else:
# Unhandled
return False
return True
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
try: try:
# created already? # created already?
@ -440,7 +445,16 @@ def show_win():
print "Failed to create!" print "Failed to create!"
return None return None
x.Show() x.Show()
tcc = x.GetTCustomControl()
# Register actions
for thing in ["Hello", "World"]:
actname = "custview:say_%s" % thing
idaapi.register_action(
idaapi.action_desc_t(actname, "Say %s" % thing, say_something_handler_t(thing)))
idaapi.attach_action_to_popup(tcc, None, actname)
return x return x
mycv = show_win() mycv = show_win()
if not mycv: if not mycv:
del mycv del mycv

View File

@ -61,323 +61,6 @@ struct scfld_t
#define FT_BAD_TYPE -2 #define FT_BAD_TYPE -2
#define FT_OK 1 #define FT_OK 1
// //-----------------------------------------------------------------------
// class pycvt_t
// {
// struct attr_t
// {
// qstring str;
// uint64 u64;
// // User is responsible to release this attribute when done
// PyObject *py_obj;
// };
// //-----------------------------------------------------------------------
// static int get_attr(
// PyObject *py_obj,
// const char *attrname,
// int ft,
// attr_t &val)
// {
// ref_t py_attr(PyW_TryGetAttrString(py_obj, attrname));
// if ( py_attr == NULL )
// return FT_NOT_FOUND;
// int cvt = FT_OK;
// if ( ft == FT_STR || ft == FT_CHAR && PyString_Check(py_attr.o) )
// val.str = PyString_AsString(py_attr.o);
// else if ( (ft > FT_FIRST_NUM && ft < FT_LAST_NUM) && PyW_GetNumber(py_attr.o, &val.u64) )
// ; // nothing to be done
// // A string array?
// else if ( (ft == FT_STRARR || ft == FT_NUM16ARR || ft == FT_CHRARR_STATIC )
// && (PyList_CheckExact(py_attr.o) || PyW_IsSequenceType(py_attr.o)) )
// {
// // Return a reference to the attribute
// val.py_obj = py_attr.o;
// // Do not decrement the reference to this attribute
// py_attr = NULL;
// }
// else
// cvt = FT_BAD_TYPE;
// return cvt;
// }
// //-----------------------------------------------------------------------
// static int idaapi make_str_list_cb(
// PyObject *py_item,
// Py_ssize_t index,
// void *ud)
// {
// if ( !PyString_Check(py_item) )
// return CIP_FAILED;
// char **a = (char **)ud;
// a[index] = qstrdup(PyString_AsString(py_item));
// return CIP_OK;
// }
// //-----------------------------------------------------------------------
// // Converts an IDC list of strings to a C string list
// static Py_ssize_t str_list_to_str_arr(
// PyObject *py_list,
// char ***arr)
// {
// // Take the size
// Py_ssize_t size = pyvar_walk_list(py_list);
// // Allocate a buffer
// char **a = (char **)qalloc((size + 1) * sizeof(char *));
// // Walk and populate
// size = pyvar_walk_list(py_list, make_str_list_cb, a);
// // Make the list NULL terminated
// a[size] = NULL;
// // Return the list to the user
// *arr = a;
// // Return the size of items processed
// return size;
// }
// //-----------------------------------------------------------------------
// typedef qvector<uint64> uint64vec_t;
// static int idaapi make_int_list(
// PyObject *py_item,
// Py_ssize_t /*index*/,
// void *ud)
// {
// uint64 val;
// if ( !PyW_GetNumber(py_item, &val) )
// return CIP_FAILED;
// uint64vec_t *vec = (uint64vec_t *)ud;
// vec->push_back(val);
// return CIP_OK;
// }
// public:
// //-----------------------------------------------------------------------
// // Frees a NULL terminated list of fields
// static void free_fields(
// const scfld_t *fields,
// void *store_area)
// {
// for ( int i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// break;
// void *store = (void *)((char *)store_area + fd.field_offs);
// int ft = fd.field_type & ~FT_VALUE_MASK;
// switch ( ft )
// {
// case FT_STR: // Simple string
// {
// char **s = (char **)store;
// if ( *s != NULL )
// {
// qfree(*s);
// *s = NULL;
// }
// }
// break;
// case FT_STRARR: // Array of strings
// {
// char ***op = (char ***)store, **p = *op;
// while ( *p != NULL )
// qfree((void *)*p++);
// qfree(*op);
// *op = NULL;
// }
// break;
// case FT_NUM16ARR:
// {
// uint16 **arr = (uint16 **)store;
// if ( *arr != NULL )
// {
// qfree(*arr);
// *arr = NULL;
// }
// }
// break;
// }
// }
// }
// //-----------------------------------------------------------------------
// // Converts from a C structure to Python
// static int from_c(
// const scfld_t *fields,
// void *read_area,
// PyObject *py_obj)
// {
// PyObject *py_attr;
// int i;
// bool ok = false;
// for ( i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// {
// ok = true;
// break;
// }
// // Point to structure member
// int ft = fd.field_type & ~FT_VALUE_MASK;
// void *read = (void *)((char *)read_area + fd.field_offs);
// // Create the python attribute properly
// if ( ft > FT_FIRST_NUM && ft < FT_LAST_NUM )
// {
// if ( ft == FT_NUM16 )
// py_attr = Py_BuildValue("H", *(uint16 *)read);
// else if ( ft == FT_NUM32 )
// py_attr = Py_BuildValue("I", *(uint32 *)read);
// else if ( ft == FT_INT )
// py_attr = Py_BuildValue("i", *(int *)read);
// else if ( ft == FT_SIZET )
// py_attr = Py_BuildValue(PY_FMT64,*(size_t *)read);
// else if ( ft == FT_SSIZET )
// py_attr = Py_BuildValue(PY_SFMT64,*(ssize_t *)read);
// }
// else if ( ft == FT_STR || ft == FT_CHAR )
// {
// if ( ft == FT_STR )
// py_attr = PyString_FromString(*(char **)read);
// else
// py_attr = Py_BuildValue("c", *(char *)read);
// }
// else if ( ft == FT_STRARR )
// {
// char **arr = *(char ***)read;
// py_attr = PyList_New(0);
// while ( *arr != NULL )
// PyList_Append(py_attr, PyString_FromString(*arr++));
// }
// else
// continue;
// PyObject_SetAttrString(py_obj, fd.field_name, py_attr);
// Py_XDECREF(py_attr);
// }
// return ok ? -1 : i;
// }
// //-----------------------------------------------------------------------
// // Converts fields from IDC and field description into a C structure
// // If 'use_extlang' is specified, then the passed idc_obj is considered
// // to be an opaque object and thus can be queried only through extlang
// static int from_script(
// const scfld_t *fields,
// void *store_area,
// PyObject *py_obj)
// {
// int i;
// bool ok = false;
// attr_t attr;
// for ( i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// {
// ok = true;
// break;
// }
// // Get field type
// int ft = fd.field_type & ~FT_VALUE_MASK;
// // Point to structure member
// void *store = (void *)((char *)store_area + fd.field_offs);
// // Retrieve attribute and type
// int cvt = get_attr(py_obj, fd.field_name, ft, attr);
// // Attribute not found?
// if ( cvt == FT_NOT_FOUND )
// {
// // Skip optional fields
// if ( fd.is_optional )
// continue;
// break;
// }
// if ( ft == FT_STR )
// *(char **)store = qstrdup(attr.str.c_str());
// else if ( ft == FT_NUM32 )
// *(uint32 *)store = uint32(attr.u64);
// else if ( ft == FT_NUM16 )
// *(uint16 *)store = attr.u64 & 0xffff;
// else if ( ft == FT_INT )
// *(int *)store = int(attr.u64);
// else if ( ft == FT_SIZET )
// *(size_t *)store = size_t(attr.u64);
// else if ( ft == FT_SSIZET )
// *(ssize_t *)store = ssize_t(attr.u64);
// else if ( ft == FT_CHAR )
// *(char *)store = *attr.str.c_str();
// else if ( ft == FT_STRARR )
// {
// str_list_to_str_arr(attr.py_obj, (char ***)store);
// Py_DECREF(attr.py_obj);
// }
// else if ( ft == FT_CHRARR_STATIC )
// {
// size_t sz = (fd.field_type & FT_VALUE_MASK) >> 16;
// if ( sz == 0 )
// break;
// uint64vec_t w;
// char *a = (char *) store;
// if ( pyvar_walk_list(attr.py_obj, make_int_list, &w) )
// {
// sz = qmin(w.size(), sz);
// for ( size_t i=0; i < sz; i++ )
// a[i] = w[i] & 0xFF;
// }
// }
// else if ( ft == FT_NUM16ARR )
// {
// uint64vec_t w;
// if ( pyvar_walk_list(attr.py_obj, make_int_list, &w) > 0 )
// {
// size_t max_sz = (fd.field_type & FT_VALUE_MASK) >> 16;
// bool zero_term;
// if ( max_sz == 0 )
// {
// zero_term = true;
// max_sz = w.size();
// }
// else
// {
// zero_term = false;
// max_sz = qmin(max_sz, w.size());
// }
// // Allocate as much as we parsed elements
// // Add one more element if list was zero terminated
// uint16 *a = (uint16 *)qalloc(sizeof(uint16) * (max_sz + (zero_term ? 1 : 0))) ;
// for ( size_t i=0; i < max_sz; i++ )
// a[i] = w[i] & 0xFF;
// if ( zero_term )
// a[max_sz] = 0;
// *(uint16 **)store = a;
// }
// }
// else
// {
// // Unsupported field type!
// break;
// }
// }
// return ok ? -1 : i;
// }
// };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
Py_ssize_t pyvar_walk_list( Py_ssize_t pyvar_walk_list(
const ref_t &py_list, const ref_t &py_list,
@ -1052,9 +735,6 @@ bool pyw_convert_idc_args(
{ {
// PyTuple_SetItem() steals the reference. // PyTuple_SetItem() steals the reference.
py_obj.incref(); py_obj.incref();
if ( cvt == CIP_OK_OPAQUE )
// We want opaque objects to still exist even when the tuple is gone.
py_obj.incref();
QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0); QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0);
} }
else else

View File

@ -723,5 +723,63 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
} }
return code; return code;
} }
//------------------------------------------------------------------------
/*
#<pydoc>
def py_list_bptgrps():
"""
Returns list of breakpoint group names
@return: A list of strings or None on failure
"""
pass
#</pydoc>
*/
static PyObject *py_list_bptgrps()
{
PYW_GIL_CHECK_LOCKED_SCOPE();
qstrvec_t args;
if ( list_bptgrps(&args) == 0 )
Py_RETURN_NONE;
return qstrvec2pylist(args);
}
//------------------------------------------------------------------------
/*
#<pydoc>
def move_bpt_to_grp():
"""
Sets new group for the breakpoint
"""
pass
#</pydoc>
*/
static void move_bpt_to_grp(bpt_t *bpt, const char *grp_name)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
set_bpt_group(*bpt, grp_name);
}
/*
#<pydoc>
def internal_get_sreg_base():
"""
Get the sreg base, for the given thread.
@return: The sreg base, or BADADDR on failure.
"""
pass
#</pydoc>
*/
static ea_t py_internal_get_sreg_base(thid_t tid, int sreg_value)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
ea_t answer;
return internal_get_sreg_base(tid, sreg_value, &answer) < 1
? BADADDR
: answer;
}
//</inline(py_dbg)> //</inline(py_dbg)>
#endif #endif

View File

@ -38,7 +38,10 @@ private:
GRCODE_HAVE_GOTFOCUS = 0x00080000, GRCODE_HAVE_GOTFOCUS = 0x00080000,
GRCODE_HAVE_LOSTFOCUS = 0x00100000, GRCODE_HAVE_LOSTFOCUS = 0x00100000,
GRCODE_HAVE_CHANGED_CURRENT = 0x00200000, GRCODE_HAVE_CHANGED_CURRENT = 0x00200000,
GRCODE_HAVE_COMMAND = 0x00400000 GRCODE_HAVE_COMMAND = 0x00400000,
GRCODE_HAVE_CREATING_GROUP = 0x00800000,
GRCODE_HAVE_DELETING_GROUP = 0x01000000,
GRCODE_HAVE_GROUP_VISIBILITY = 0x02000000,
}; };
struct nodetext_cache_t struct nodetext_cache_t
{ {
@ -142,6 +145,7 @@ private:
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id)); newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id));
PyW_ShowCbErr(S_ON_COMMAND);
} }
// Refresh user-defined graph node number and edges // Refresh user-defined graph node number and edges
@ -189,6 +193,7 @@ private:
(char *)S_ON_CLICK, (char *)S_ON_CLICK,
"i", "i",
item2->n)); item2->n));
PyW_ShowCbErr(S_ON_CLICK);
return result == NULL || !PyObject_IsTrue(result.o); return result == NULL || !PyObject_IsTrue(result.o);
} }
@ -210,29 +215,38 @@ private:
(char *)S_ON_DBL_CLICK, (char *)S_ON_DBL_CLICK,
"i", "i",
item->node)); item->node));
PyW_ShowCbErr(S_ON_DBL_CLICK);
return result == NULL || !PyObject_IsTrue(result.o); return result == NULL || !PyObject_IsTrue(result.o);
} }
// a graph viewer got focus // a graph viewer got focus
void on_gotfocus(graph_viewer_t * /*view*/) void on_gotfocus(graph_viewer_t * /*view*/)
{ {
if ( self.o == NULL )
return;
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_ACTIVATE, (char *)S_ON_ACTIVATE,
NULL)); NULL));
PyW_ShowCbErr(S_ON_ACTIVATE);
} }
// a graph viewer lost focus // a graph viewer lost focus
void on_lostfocus(graph_viewer_t * /*view*/) void on_lostfocus(graph_viewer_t * /*view*/)
{ {
if ( self.o == NULL )
return;
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_DEACTIVATE, (char *)S_ON_DEACTIVATE,
NULL)); NULL));
PyW_ShowCbErr(S_ON_DEACTIVATE);
} }
// a new graph node became the current node // a new graph node became the current node
@ -251,6 +265,7 @@ private:
(char *)S_ON_SELECT, (char *)S_ON_SELECT,
"i", "i",
curnode)); curnode));
PyW_ShowCbErr(S_ON_SELECT);
return !(result != NULL && PyObject_IsTrue(result.o)); return !(result != NULL && PyObject_IsTrue(result.o));
} }
@ -258,7 +273,6 @@ private:
int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes) int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); 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())); newref_t py_nodes(PyList_New(my_nodes->size()));
int i; int i;
intvec_t::const_iterator p; intvec_t::const_iterator p;
@ -270,6 +284,7 @@ private:
(char *)S_ON_CREATING_GROUP, (char *)S_ON_CREATING_GROUP,
"O", "O",
py_nodes.o)); py_nodes.o));
PyW_ShowCbErr(S_ON_CREATING_GROUP);
return (py_result == NULL || !PyInt_Check(py_result.o)) ? 1 : PyInt_AsLong(py_result.o); return (py_result == NULL || !PyInt_Check(py_result.o)) ? 1 : PyInt_AsLong(py_result.o);
} }
@ -299,6 +314,10 @@ private:
void jump_to_node(int nid) void jump_to_node(int nid)
{ {
ref_t nodes(PyW_TryGetAttrString(self.o, S_M_NODES));
if ( nid >= PyList_Size(nodes.o) )
return;
viewer_center_on(view, nid); viewer_center_on(view, nid);
int x, y; int x, y;
@ -342,6 +361,7 @@ private:
if ( pview != NULL ) if ( pview != NULL )
viewer_fit_window(pview); viewer_fit_window(pview);
bind(self, pview); bind(self, pview);
install_custom_viewer_handlers();
refresh(); refresh();
lookup_info.commit(e, form, view); lookup_info.commit(e, form, view);
} }
@ -379,13 +399,16 @@ public:
cmdid_pyg.clear(this); cmdid_pyg.clear(this);
} }
static void SelectNode(PyObject *self, int /*nid*/) static void SelectNode(PyObject *self, int nid)
{ {
if ( nid < 0 )
return;
py_graph_t *_this = view_extract_this<py_graph_t>(self); py_graph_t *_this = view_extract_this<py_graph_t>(self);
if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) ) if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) )
return; return;
_this->jump_to_node(0); _this->jump_to_node(nid);
} }
static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey) static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey)
@ -465,6 +488,9 @@ void py_graph_t::collect_class_callbacks_ids(callbacks_ids_t *out)
out->add(S_ON_SELECT, GRCODE_HAVE_CHANGED_CURRENT); out->add(S_ON_SELECT, GRCODE_HAVE_CHANGED_CURRENT);
out->add(S_ON_ACTIVATE, GRCODE_HAVE_GOTFOCUS); out->add(S_ON_ACTIVATE, GRCODE_HAVE_GOTFOCUS);
out->add(S_ON_DEACTIVATE, GRCODE_HAVE_LOSTFOCUS); out->add(S_ON_DEACTIVATE, GRCODE_HAVE_LOSTFOCUS);
out->add(S_ON_CREATING_GROUP, GRCODE_HAVE_CREATING_GROUP);
out->add(S_ON_DELETING_GROUP, GRCODE_HAVE_DELETING_GROUP);
out->add(S_ON_GROUP_VISIBILITY, GRCODE_HAVE_GROUP_VISIBILITY);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -476,6 +502,7 @@ void py_graph_t::on_user_refresh(mutable_graph_t *g)
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL)); newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL));
PyW_ShowCbErr(S_ON_REFRESH);
if ( ret != NULL && PyObject_IsTrue(ret.o) ) if ( ret != NULL && PyObject_IsTrue(ret.o) )
{ {
// Refer to the nodes // Refer to the nodes
@ -547,6 +574,7 @@ bool py_graph_t::on_user_text(mutable_graph_t * /*g*/, int node, const char **st
// Not cached, call Python // Not cached, call Python
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node)); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node));
PyW_ShowCbErr(S_ON_GETTEXT);
if ( result == NULL ) if ( result == NULL )
return false; return false;
@ -594,6 +622,7 @@ int py_graph_t::on_user_hint(mutable_graph_t *, int mousenode, int /*mouseedge_s
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_HINT, "i", mousenode)); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_HINT, "i", mousenode));
PyW_ShowCbErr(S_ON_HINT);
bool ok = result != NULL && PyString_Check(result.o); bool ok = result != NULL && PyString_Check(result.o);
if ( ok ) if ( ok )
*hint = qstrdup(PyString_AsString(result.o)); *hint = qstrdup(PyString_AsString(result.o));
@ -647,7 +676,10 @@ int py_graph_t::gr_callback(int code, va_list va)
ret = on_dblclicked(view, item); ret = on_dblclicked(view, item);
} }
else else
ret = 1; // ignore ret = 0; // We don't want to ignore the double click, but rather
// fallback to the default behavior (e.g., double-clicking
// on an edge will to jump to the node on the other side
// of that edge.)
break; break;
// //
case grcode_gotfocus: case grcode_gotfocus:
@ -698,28 +730,43 @@ int py_graph_t::gr_callback(int code, va_list va)
break; break;
// //
case grcode_creating_group: // a group is being created case grcode_creating_group: // a group is being created
if ( has_callback(GRCODE_HAVE_CREATING_GROUP) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
intvec_t *nodes = va_arg(va, intvec_t*); intvec_t *nodes = va_arg(va, intvec_t*);
ret = on_creating_group(g, nodes); ret = on_creating_group(g, nodes);
} }
else
{
ret = 0; // Ok to create
}
break; break;
// //
case grcode_deleting_group: // a group is being deleted case grcode_deleting_group: // a group is being deleted
if ( has_callback(GRCODE_HAVE_DELETING_GROUP) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
int old_group = va_arg(va, int); int old_group = va_arg(va, int);
ret = on_deleting_group(g, old_group); ret = on_deleting_group(g, old_group);
} }
else
{
ret = 0; // Ok to delete
}
break; break;
// //
case grcode_group_visibility: // a group is being collapsed/uncollapsed case grcode_group_visibility: // a group is being collapsed/uncollapsed
if ( has_callback(GRCODE_HAVE_GROUP_VISIBILITY) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
int group = va_arg(va, int); int group = va_arg(va, int);
bool expand = bool(va_arg(va, int)); bool expand = bool(va_arg(va, int));
ret = on_group_visibility(g, group, expand); ret = on_group_visibility(g, group, expand);
} }
else
{
ret = 0; // Ok.
}
break; break;
// //
default: default:

View File

@ -70,10 +70,9 @@ class GraphViewer(CustomIDAMemo):
def AddCommand(self, title, hotkey): def AddCommand(self, title, hotkey):
""" """
Adds a menu command to the graph. Call this command after the graph is shown (with Show()). Deprecated: Use
Once a command is added, a command id is returned. The commands are handled inside the OnCommand() handler - register_action()
- attach_action_to_popup()
@return: 0 on failure or the command id
""" """
return _idaapi.pyg_add_command(self, title, hotkey) return _idaapi.pyg_add_command(self, title, hotkey)
@ -155,9 +154,8 @@ class GraphViewer(CustomIDAMemo):
# #
# def OnCommand(self, cmd_id): # def OnCommand(self, cmd_id):
# """ # """
# Triggered when a menu command is selected through the menu or its hotkey # Deprecated
# @return: None
# """ # """
# print "command:", cmd_id # pass
#</pydoc> #</pydoc>
#</pycode(py_graph)> #</pycode(py_graph)>

View File

@ -69,6 +69,7 @@ static const char S_ON_VIEW_DBLCLICK[] = "OnViewDblclick";
static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos"; static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos";
static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched"; static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched";
static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver"; static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver";
static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved";
#ifdef __PYWRAPS__ #ifdef __PYWRAPS__
@ -623,7 +624,6 @@ void *pyobj_get_clink(PyObject *pyobj)
} }
//</code(py_idaapi)> //</code(py_idaapi)>
//<inline(py_idaapi)> //<inline(py_idaapi)>
//------------------------------------------------------------------------ //------------------------------------------------------------------------
/* /*
@ -644,12 +644,7 @@ static PyObject *py_parse_command_line(const char *cmdline)
qstrvec_t args; qstrvec_t args;
if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 ) if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 )
Py_RETURN_NONE; Py_RETURN_NONE;
return qstrvec2pylist(args);
PyObject *py_list = PyList_New(args.size());
for ( size_t i=0; i<args.size(); i++ )
PyList_SetItem(py_list, i, PyString_FromString(args[i].c_str()));
return py_list;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------

View File

@ -8,6 +8,7 @@ class py_idaview_t : public py_customidamemo_t
public: public:
static bool Bind(PyObject *self); static bool Bind(PyObject *self);
static bool Unbind(PyObject *self);
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -53,24 +54,43 @@ bool py_idaview_t::Bind(PyObject *self)
if ( ok ) if ( ok )
{ {
ok = py_view->collect_pyobject_callbacks(self); ok = py_view->collect_pyobject_callbacks(self);
if ( !ok ) if ( ok )
py_view->install_custom_viewer_handlers();
else
delete py_view; delete py_view;
} }
return ok; return ok;
} }
//-------------------------------------------------------------------------
bool py_idaview_t::Unbind(PyObject *self)
{
py_idaview_t *_this = view_extract_this<py_idaview_t>(self);
if ( _this == NULL )
return false;
_this->unbind();
return true;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
bool pyidag_bind(PyObject *self) bool pyidag_bind(PyObject *self)
{ {
return py_idaview_t::Bind(self); return py_idaview_t::Bind(self);
} }
//-------------------------------------------------------------------------
bool pyidag_unbind(PyObject *self)
{
return py_idaview_t::Unbind(self);
}
//</code(py_idaview)> //</code(py_idaview)>
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
//<inline(py_idaview)> //<inline(py_idaview)>
bool pyidag_bind(PyObject *self); bool pyidag_bind(PyObject *self);
bool pyidag_unbind(PyObject *self);
//</inline(py_idaview)> //</inline(py_idaview)>
#endif // __PY_IDA_VIEW__ #endif // __PY_IDA_VIEW__

View File

@ -13,4 +13,8 @@ class IDAViewWrapper(CustomIDAMemo):
def Bind(self): def Bind(self):
return _idaapi.pyidag_bind(self) return _idaapi.pyidag_bind(self)
def Unbind(self):
return _idaapi.pyidag_unbind(self)
#</pycode(py_idaview)> #</pycode(py_idaview)>

View File

@ -748,6 +748,10 @@ public:
{ {
} }
virtual void auto_empty_finally()
{
}
virtual int rename(ea_t ea, const char *new_name) virtual int rename(ea_t ea, const char *new_name)
{ {
return 0; return 0;
@ -776,6 +780,15 @@ public:
{ {
} }
virtual void auto_empty()
{
}
virtual int auto_queue_empty(atype_t type)
{
return 1; // Keep the queue empty.
}
virtual void add_func(func_t *func) virtual void add_func(func_t *func)
{ {
} }
@ -834,38 +847,38 @@ public:
return unhook_from_notification_point(HT_IDB, IDB_Callback, this); return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
} }
// Hook functions to override in Python // Hook functions to override in Python
virtual int byte_patched(ea_t /*ea*/) { return 0; }; virtual int byte_patched(ea_t /*ea*/) { return 0; }
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }; virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { 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 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_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 op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }
virtual int enum_created(enum_t /*id*/) { return 0; }; virtual int enum_created(enum_t /*id*/) { return 0; }
virtual int enum_deleted(enum_t /*id*/) { return 0; }; virtual int enum_deleted(enum_t /*id*/) { return 0; }
virtual int enum_bf_changed(enum_t /*id*/) { return 0; }; virtual int enum_bf_changed(enum_t /*id*/) { return 0; }
virtual int enum_renamed(enum_t /*id*/) { return 0; }; virtual int enum_renamed(enum_t /*id*/) { return 0; }
virtual int enum_cmt_changed(enum_t /*id*/) { return 0; }; virtual int enum_cmt_changed(enum_t /*id*/) { return 0; }
virtual int enum_member_created(enum_t /*id*/, const_t cid) { return 0; }; virtual int enum_member_created(enum_t /*id*/, const_t cid) { return 0; }
virtual int enum_member_deleted(enum_t /*id*/, const_t cid) { return 0; }; virtual int enum_member_deleted(enum_t /*id*/, const_t cid) { return 0; }
virtual int struc_created(tid_t /*struc_id*/) { return 0; }; virtual int struc_created(tid_t /*struc_id*/) { return 0; }
virtual int struc_deleted(tid_t /*struc_id*/) { return 0; }; virtual int struc_deleted(tid_t /*struc_id*/) { return 0; }
virtual int struc_renamed(struc_t * /*sptr*/) { return 0; }; virtual int struc_renamed(struc_t * /*sptr*/) { return 0; }
virtual int struc_expanded(struc_t * /*sptr*/) { return 0; }; virtual int struc_expanded(struc_t * /*sptr*/) { return 0; }
virtual int struc_cmt_changed(tid_t /*struc_id*/) { return 0; }; virtual int struc_cmt_changed(tid_t /*struc_id*/) { return 0; }
virtual int struc_member_created(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_created(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int struc_member_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { return 0; }; virtual int struc_member_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { return 0; }
virtual int struc_member_renamed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_renamed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int struc_member_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int thunk_func_created(func_t * /*pfn*/) { return 0; }; virtual int thunk_func_created(func_t * /*pfn*/) { return 0; }
virtual int func_tail_appended(func_t * /*pfn*/, func_t * /*tail*/) { return 0; }; virtual int func_tail_appended(func_t * /*pfn*/, func_t * /*tail*/) { return 0; }
virtual int func_tail_removed(func_t * /*pfn*/, ea_t /*tail_ea*/) { return 0; }; virtual int func_tail_removed(func_t * /*pfn*/, ea_t /*tail_ea*/) { return 0; }
virtual int tail_owner_changed(func_t * /*tail*/, ea_t /*owner_func*/) { return 0; }; virtual int tail_owner_changed(func_t * /*tail*/, ea_t /*owner_func*/) { return 0; }
virtual int func_noret_changed(func_t * /*pfn*/) { return 0; }; virtual int func_noret_changed(func_t * /*pfn*/) { return 0; }
virtual int segm_added(segment_t * /*s*/) { return 0; }; virtual int segm_added(segment_t * /*s*/) { return 0; }
virtual int segm_deleted(ea_t /*startEA*/) { return 0; }; virtual int segm_deleted(ea_t /*startEA*/) { return 0; }
virtual int segm_start_changed(segment_t * /*s*/) { return 0; }; virtual int segm_start_changed(segment_t * /*s*/) { return 0; }
virtual int segm_end_changed(segment_t * /*s*/) { return 0; }; virtual int segm_end_changed(segment_t * /*s*/) { return 0; }
virtual int segm_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }; virtual int segm_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }
}; };
//</inline(py_idp)> //</inline(py_idp)>
@ -951,6 +964,12 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
break; break;
} }
case processor_t::auto_empty_finally:
{
proxy->auto_empty_finally();
break;
}
case processor_t::rename: case processor_t::rename:
{ {
ea_t ea = va_arg(va, ea_t); ea_t ea = va_arg(va, ea_t);
@ -1000,6 +1019,19 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
break; break;
} }
case processor_t::auto_empty:
{
proxy->auto_empty();
break;
}
case processor_t::auto_queue_empty:
{
atype_t type = va_arg(va, atype_t);
ret = proxy->auto_queue_empty(type);
break;
}
case processor_t::add_func: case processor_t::add_func:
{ {
func_t *func = va_arg(va, func_t *); func_t *func = va_arg(va, func_t *);

View File

@ -218,6 +218,72 @@ def readsel2(view, p0, p1):
#</pydoc> #</pydoc>
*/ */
//------------------------------------------------------------------------
/*
#<pydoc>
def umsg(text):
"""
Prints text into IDA's Output window
@param text: text to print
Can be Unicode, or string in UTF-8 encoding
@return: number of bytes printed
"""
pass
#</pydoc>
*/
static PyObject* py_umsg(PyObject *o)
{
PyObject* utf8 = NULL;
if ( PyUnicode_Check(o) )
{
utf8 = PyUnicode_AsUTF8String(o);
o = utf8;
}
else if ( !PyString_Check(o) )
{
PyErr_SetString(PyExc_TypeError, "A unicode or UTF-8 string expected");
return NULL;
}
int rc;
Py_BEGIN_ALLOW_THREADS;
rc = umsg("%s", PyString_AsString(o));
Py_END_ALLOW_THREADS;
Py_XDECREF(utf8);
return PyInt_FromLong(rc);
}
//------------------------------------------------------------------------
/*
#<pydoc>
def msg(text):
"""
Prints text into IDA's Output window
@param text: text to print
Can be Unicode, or string in local encoding
@return: number of bytes printed
"""
pass
#</pydoc>
*/
static PyObject* py_msg(PyObject *o)
{
if ( PyUnicode_Check(o) )
return py_umsg(o);
if ( !PyString_Check(o) )
{
PyErr_SetString(PyExc_TypeError, "A string expected");
return NULL;
}
int rc;
Py_BEGIN_ALLOW_THREADS;
rc = msg("%s", PyString_AsString(o));
Py_END_ALLOW_THREADS;
return PyInt_FromLong(rc);
}
//------------------------------------------------------------------------ //------------------------------------------------------------------------
/* /*
#<pydoc> #<pydoc>
@ -299,18 +365,17 @@ PyObject *py_str2user(const char *str)
//------------------------------------------------------------------------ //------------------------------------------------------------------------
/* /*
#<pydoc> #<pydoc>
def process_ui_action(name, flags): def process_ui_action(name):
""" """
Invokes an IDA UI action by name Invokes an IDA UI action by name
@param name: action name @param name: action name
@param flags: Reserved. Must be zero
@return: Boolean @return: Boolean
""" """
pass pass
#</pydoc> #</pydoc>
*/ */
static bool py_process_ui_action(const char *name, int flags) static bool py_process_ui_action(const char *name, int flags = 0)
{ {
return process_ui_action(name, flags, NULL); return process_ui_action(name, flags, NULL);
} }
@ -319,12 +384,7 @@ static bool py_process_ui_action(const char *name, int flags)
/* /*
#<pydoc> #<pydoc>
def del_menu_item(menu_ctx): def del_menu_item(menu_ctx):
""" """Deprecated. Use detach_menu_item()/unregister_action() instead."""
Deletes a menu item previously added with add_menu_item()
@param menu_ctx: value returned by add_menu_item()
@return: Boolean
"""
pass pass
#</pydoc> #</pydoc>
*/ */
@ -337,7 +397,6 @@ static bool py_del_menu_item(PyObject *py_ctx)
py_add_del_menu_item_ctx *ctx = (py_add_del_menu_item_ctx *)PyCObject_AsVoidPtr(py_ctx); py_add_del_menu_item_ctx *ctx = (py_add_del_menu_item_ctx *)PyCObject_AsVoidPtr(py_ctx);
bool ok = del_menu_item(ctx->menupath.c_str()); bool ok = del_menu_item(ctx->menupath.c_str());
if ( ok ) if ( ok )
{ {
Py_DECREF(ctx->cb_data); Py_DECREF(ctx->cb_data);
@ -455,21 +514,7 @@ PyObject *py_add_hotkey(const char *hotkey, PyObject *pyfunc)
/* /*
#<pydoc> #<pydoc>
def add_menu_item(menupath, name, hotkey, flags, callback, args): def add_menu_item(menupath, name, hotkey, flags, callback, args):
""" """Deprecated. Use register_action()/attach_menu_item() instead."""
Adds a menu item
@param menupath: path to the menu item after or before which the insertion will take place
@param name: name of the menu item (~x~ is used to denote Alt-x hot letter)
@param hotkey: hotkey for the menu item (may be empty)
@param flags: one of SETMENU_... consts
@param callback: function which gets called when the user selects the menu item.
The function callback is of the form:
def callback(*args):
pass
@param args: tuple containing the arguments
@return: None or a menu context (to be used by del_menu_item())
"""
pass pass
#</pydoc> #</pydoc>
*/ */
@ -816,6 +861,45 @@ class UI_Hooks(object):
""" """
pass pass
def updating_actions(self, ctx):
"""
The UI is about to batch-update some actions.
@param ctx: The action_update_ctx_t instance
@return: Ignored
"""
pass
def updated_actions(self):
"""
The UI is done updating actions.
@return: Ignored
"""
pass
def populating_tform_popup(self, form, popup):
"""
The UI is populating the TForm's popup menu.
Now is a good time to call idaapi.attach_action_to_popup()
@param form: The form
@param popup: The popup menu.
@return: Ignored
"""
pass
def finish_populating_tform_popup(self, form, popup):
"""
The UI is about to be done populating the TForm's popup menu.
Now is a good time to call idaapi.attach_action_to_popup()
@param form: The form
@param popup: The popup menu.
@return: Ignored
"""
pass
def term(self): def term(self):
""" """
IDA is terminated and the database is already closed. IDA is terminated and the database is already closed.
@ -873,7 +957,242 @@ public:
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
Py_RETURN_NONE; Py_RETURN_NONE;
}; };
virtual void current_tform_changed(TForm * /*form*/, TForm * /*previous_form*/)
{
}
virtual void updating_actions(action_update_ctx_t *ctx)
{
}
virtual void updated_actions()
{
}
virtual void populating_tform_popup(TForm * /*form*/, TPopupMenu * /*popup*/)
{
}
virtual void finish_populating_tform_popup(TForm * /*form*/, TPopupMenu * /*popup*/)
{
}
}; };
//-------------------------------------------------------------------------
bool py_register_action(action_desc_t *desc)
{
bool ok = register_action(*desc);
if ( ok )
{
// Success. We are managing this handler from now on,
// and must prevent it from being destroyed.
py_action_handlers[desc->name] = desc->handler;
// Let's set this to NULL, so when the wrapping Python action_desc_t
// instance is deleted, it doesn't try to delete the handler (See
// kernwin.i's action_desc_t::~action_desc_t()).
desc->handler = NULL;
}
return ok;
}
//-------------------------------------------------------------------------
bool py_unregister_action(const char *name)
{
bool ok = unregister_action(name);
if ( ok )
{
py_action_handler_t *handler =
(py_action_handler_t *) py_action_handlers[name];
delete handler;
py_action_handlers.erase(name);
}
return ok;
}
//-------------------------------------------------------------------------
bool py_attach_dynamic_action_to_popup(
TForm *form,
TPopupMenu *popup_handle,
action_desc_t *desc,
const char *popuppath = NULL,
int flags = 0)
{
bool ok = attach_dynamic_action_to_popup(
form, popup_handle, *desc, popuppath, flags);
if ( ok )
// Set the handler to null, so the desc won't destroy
// it, as it noticed ownership was taken by IDA.
// In addition, we don't need to register into the
// 'py_action_handlers', because IDA will destroy the
// handler as soon as the popup menu is closed.
desc->handler = NULL;
return ok;
}
// This is similar to a twinline_t, with improved memory management:
// twinline_t has a dummy destructor, that performs no cleanup.
struct disasm_line_t
{
disasm_line_t() : at(NULL) {}
~disasm_line_t() { qfree(at); }
disasm_line_t(const disasm_line_t &other) { *this = other; }
disasm_line_t &operator=(const disasm_line_t &other)
{
qfree(at);
at = other.at == NULL ? NULL : other.at->clone();
return *this;
}
place_t *at;
qstring line;
color_t prefix_color;
bgcolor_t bg_color;
bool is_default;
};
DECLARE_TYPE_AS_MOVABLE(disasm_line_t);
typedef qvector<disasm_line_t> disasm_text_t;
//-------------------------------------------------------------------------
void py_gen_disasm_text(ea_t ea1, ea_t ea2, disasm_text_t &text, bool truncate_lines)
{
text_t _text;
gen_disasm_text(ea1, ea2, _text, truncate_lines);
for ( size_t i = 0, n = _text.size(); i < n; ++i )
{
const twinline_t &tl = _text[i];
disasm_line_t &dl = text.push_back();
dl.at = tl.at; // Transfer ownership
dl.line.inject(tl.line); // Transfer ownership
}
}
//-------------------------------------------------------------------------
// Although 'TCustomControl*' and 'TForm*' instances can both be used
// for attach_action_to_popup() at a binary-level, IDAPython SWIG bindings
// require that a 'TForm *' wrapper be passed to wrap_attach_action_to_popup().
// Thus, we provide another attach_action_to_popup() version, that
// accepts a 'TCustomControl' as first argument.
//
// Since user-created GraphViewer are created like so:
// +-------- PluginForm ----------+
// |+----- TCustomControl -------+|
// || ||
// || ||
// || ||
// || ||
// || ||
// |+----------------------------+|
// +------------------------------+
// The user cannot use GetTForm(), and use that to attach
// an action to, because that'll attach the action to the PluginForm
// instance.
// Instead, the user must use GetTCustomControl(), and call
// this function below with it.
bool attach_action_to_popup(
TCustomControl *tcc,
TPopupMenu *popup_handle,
const char *name,
const char *popuppath = NULL,
int flags = 0)
{
return attach_action_to_popup((TForm*) tcc, popup_handle, name, popuppath, flags);
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def set_nav_colorizer(callback):
"""
Set a new colorizer for the navigation band.
The 'callback' is a function of 2 arguments:
- ea (the EA to colorize for)
- nbytes (the number of bytes at that EA)
and must return a 'long' value.
The previous colorizer is returned, allowing
the new 'callback' to use 'call_nav_colorizer'
with it.
Note that the previous colorizer is returned
only the first time set_nav_colorizer() is called:
due to the way the colorizers API is defined in C,
it is impossible to chain more than 2 colorizers
in IDAPython: the original, IDA-provided colorizer,
and a user-provided one.
Example: colorizer inverting the color provided by the IDA colorizer:
def my_colorizer(ea, nbytes):
global ida_colorizer
orig = idaapi.call_nav_colorizer(ida_colorizer, ea, nbytes)
return long(~orig)
ida_colorizer = idaapi.set_nav_colorizer(my_colorizer)
"""
pass
#</pydoc>
*/
nav_colorizer_t *py_set_nav_colorizer(PyObject *new_py_colorizer)
{
static ref_t py_colorizer;
struct ida_local lambda_t
{
static uint32 idaapi call_py_colorizer(ea_t ea, asize_t nbytes)
{
PYW_GIL_GET;
if ( py_colorizer == NULL ) // Shouldn't happen.
return 0;
newref_t pyres = PyObject_CallFunction(
py_colorizer.o, "KK",
(unsigned long long) ea,
(unsigned long long) nbytes);
PyW_ShowCbErr("nav_colorizer");
if ( pyres.o == NULL )
return 0;
if ( !PyLong_Check(pyres.o) )
{
static bool warned = false;
if ( !warned )
{
msg("WARNING: set_nav_colorizer() callback must return a 'long'.\n");
warned = true;
}
return 0;
}
return PyLong_AsLong(pyres.o);
}
};
bool need_install = py_colorizer == NULL;
py_colorizer = borref_t(new_py_colorizer);
return need_install
? set_nav_colorizer(lambda_t::call_py_colorizer)
: NULL;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def call_nav_colorizer(colorizer, ea, nbytes):
"""
To be used with the IDA-provided colorizer, that is
returned as result of the first call to set_nav_colorizer().
This is a trivial trampoline, so that SWIG can generate a
wrapper that will do the types checking.
"""
pass
#</pydoc>
*/
uint32 py_call_nav_colorizer(
nav_colorizer_t *col,
ea_t ea,
asize_t nbytes)
{
return col(ea, nbytes);
}
//</inline(py_kernwin)> //</inline(py_kernwin)>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -932,6 +1251,44 @@ int idaapi UI_Callback(void *ud, int notification_code, va_list va)
} }
break; break;
} }
case ui_current_tform_changed:
{
TForm *form = va_arg(va, TForm *);
TForm *prev_form = va_arg(va, TForm *);
proxy->current_tform_changed(form, prev_form);
}
break;
case ui_updating_actions:
{
action_update_ctx_t *ctx = va_arg(va, action_update_ctx_t *);
proxy->updating_actions(ctx);
}
break;
case ui_updated_actions:
{
proxy->updated_actions();
}
break;
case ui_populating_tform_popup:
{
TForm *form = va_arg(va, TForm *);
TPopupMenu *popup = va_arg(va, TPopupMenu *);
proxy->populating_tform_popup(form, popup);
}
break;
case ui_finish_populating_tform_popup:
{
TForm *form = va_arg(va, TForm *);
TPopupMenu *popup = va_arg(va, TPopupMenu *);
proxy->finish_populating_tform_popup(form, popup);
}
break;
} }
} }
catch (Swig::DirectorException &e) catch (Swig::DirectorException &e)

View File

@ -32,7 +32,7 @@ DP_INSIDE = 0x0010
# this flag alone cannot be used to determine orientation # this flag alone cannot be used to determine orientation
DP_BEFORE = 0x0020 DP_BEFORE = 0x0020
# used with combination of other flags # used with combination of other flags
DP_RAW = 0x0040 DP_TAB = 0x0040
DP_FLOATING = 0x0080 DP_FLOATING = 0x0080
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
@ -83,6 +83,17 @@ def askseg(defval, format):
else: else:
return None return None
# ----------------------------------------------------------------------
class action_handler_t:
def __init__(self):
pass
def activate(self, ctx):
return 0
def update(self, ctx):
pass
#</pycode(py_kernwin)> #</pycode(py_kernwin)>
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

112
pywraps/py_registry.hpp Normal file
View File

@ -0,0 +1,112 @@
#ifndef __PY_REGISTRY__
#define __PY_REGISTRY__
//<code(py_registry)>
//-------------------------------------------------------------------------
static PyObject *_py_reg_subkey_children(const char *name, bool subkeys)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *result = NULL;
qstrvec_t children;
Py_BEGIN_ALLOW_THREADS;
if ( reg_subkey_children(&children, name, subkeys) )
{
result = PyList_New(children.size());
if ( result != NULL )
for ( size_t i = 0, n = children.size(); i < n; ++i )
PyList_SET_ITEM(result, i, PyString_FromString(children[i].c_str()));
}
Py_END_ALLOW_THREADS;
if ( result == NULL )
Py_RETURN_NONE;
else
return result;
}
//</code(py_registry)>
//<inline(py_registry)>
//-------------------------------------------------------------------------
PyObject *py_reg_read_string(const char *name, const char *subkey = NULL, const char *def = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
char utf8[MAXSTR * 10];
bool ok;
Py_BEGIN_ALLOW_THREADS;
if ( def == NULL )
{
ok = reg_read_string(name, utf8, sizeof(utf8), subkey);
}
else
{
reg_read_string(name, sizeof(utf8), utf8, def, subkey);
ok = true;
}
Py_END_ALLOW_THREADS;
return PyString_FromString(ok ? utf8 : "");
}
//-------------------------------------------------------------------------
regval_type_t py_reg_data_type(const char *name, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
regval_type_t rt = reg_unknown;
Py_BEGIN_ALLOW_THREADS;
reg_data_type(&rt, name, subkey);
Py_END_ALLOW_THREADS;
return rt;
}
//-------------------------------------------------------------------------
PyObject *py_reg_read_binary(const char *name, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
bytevec_t bytes;
bool ok;
Py_BEGIN_ALLOW_THREADS;
ok = reg_read_binary(name, &bytes, subkey);
Py_END_ALLOW_THREADS;
if ( ok )
return PyString_FromStringAndSize((const char *) bytes.begin(), bytes.size());
else
Py_RETURN_NONE;
}
//-------------------------------------------------------------------------
void py_reg_write_binary(const char *name, PyObject *py_bytes, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( PyString_Check(py_bytes) )
{
char *py_bytes_raw = NULL;
Py_ssize_t py_size = 0;
PyString_AsStringAndSize(py_bytes, &py_bytes_raw, &py_size);
bytevec_t bytes;
bytes.append(py_bytes_raw, py_size);
Py_BEGIN_ALLOW_THREADS;
reg_write_binary(name, bytes.begin(), bytes.size(), subkey);
Py_END_ALLOW_THREADS;
}
else
{
PyErr_SetString(PyExc_ValueError, "Bytes string expected!");
}
}
//-------------------------------------------------------------------------
PyObject *py_reg_subkey_subkeys(const char *name)
{
return _py_reg_subkey_children(name, true);
}
//-------------------------------------------------------------------------
PyObject *py_reg_subkey_values(const char *name)
{
return _py_reg_subkey_children(name, false);
}
//</inline(py_registry)>
#endif // __PY_REGISTRY__

View File

@ -67,9 +67,9 @@ PyObject *py_calc_type_size(const til_t *ti, PyObject *tp)
def apply_type(ti, ea, tp_name, py_type, py_fields, flags) def apply_type(ti, ea, tp_name, py_type, py_fields, flags)
""" """
Apply the specified type to the address Apply the specified type to the address
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info library. 'idaapi.cvar.idati' can be used.
@param py_type: type string @param py_type: type string
@param py_fields: type fields @param py_fields: fields string (may be empty or None)
@param ea: the address of the object @param ea: the address of the object
@param flags: combination of TINFO_... constants or 0 @param flags: combination of TINFO_... constants or 0
@return: Boolean @return: Boolean
@ -80,17 +80,44 @@ def apply_type(ti, ea, tp_name, py_type, py_fields, flags)
static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_t ea, int flags) static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_t ea, int flags)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
} }
const type_t *type = (const type_t *) PyString_AsString(py_type); const type_t *type = (const type_t *) PyString_AsString(py_type);
const p_list *fields = (const p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
bool rc; bool rc;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
struc_t *sptr;
member_t *mptr = get_member_by_id(ea, &sptr);
if ( type[0] == '\0' )
{
if ( mptr != NULL )
{
rc = mptr->has_ti();
if ( rc )
del_member_tinfo(sptr, mptr);
}
else
{
rc = has_ti(ea);
if ( rc )
del_tinfo2(ea);
}
}
else
{
tinfo_t tif; tinfo_t tif;
rc = tif.deserialize(ti, &type, &fields, NULL) && apply_tinfo2(ea, tif, flags); rc = tif.deserialize(ti, &type, &fields, NULL);
if ( rc )
{
if ( mptr != NULL )
rc = set_member_tinfo2(sptr, mptr, 0, tif, 0);
else
rc = apply_tinfo2(ea, tif, flags);
}
}
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
return rc; return rc;
} }
@ -138,7 +165,7 @@ PyObject *py_unpack_object_from_idb(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -150,7 +177,7 @@ PyObject *py_unpack_object_from_idb(
// Unpack // Unpack
type_t *type = (type_t *) PyString_AsString(py_type); type_t *type = (type_t *) PyString_AsString(py_type);
p_list *fields = (p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
idc_value_t idc_obj; idc_value_t idc_obj;
error_t err; error_t err;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
@ -188,7 +215,7 @@ def unpack_object_from_bv(ti, tp, fields, bytes, pio_flags = 0):
Returns the error_t returned by idaapi.pack_object_to_idb Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param bytes: the bytes to unpack @param bytes: the bytes to unpack
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
@return: @return:
@ -206,7 +233,7 @@ PyObject *py_unpack_object_from_bv(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) && !PyString_Check(py_bytes) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) || !PyString_Check(py_bytes) )
{ {
PyErr_SetString(PyExc_ValueError, "Incorrect argument type!"); PyErr_SetString(PyExc_ValueError, "Incorrect argument type!");
return NULL; return NULL;
@ -218,7 +245,7 @@ PyObject *py_unpack_object_from_bv(
// Get type strings // Get type strings
type_t *type = (type_t *) PyString_AsString(py_type); type_t *type = (type_t *) PyString_AsString(py_type);
p_list *fields = (p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Make a byte vector // Make a byte vector
bytevec_t bytes; bytevec_t bytes;
@ -262,7 +289,7 @@ def pack_object_to_idb(obj, ti, tp, fields, ea, pio_flags = 0):
Returns the error_t returned by idaapi.pack_object_to_idb Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param ea: ea to be used while packing @param ea: ea to be used while packing
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
""" """
@ -278,7 +305,7 @@ PyObject *py_pack_object_to_idb(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -296,7 +323,7 @@ PyObject *py_pack_object_to_idb(
// Get type strings // Get type strings
type_t *type = (type_t *)PyString_AsString(py_type); type_t *type = (type_t *)PyString_AsString(py_type);
p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Pack // Pack
// error_t err; // error_t err;
@ -315,7 +342,7 @@ def pack_object_to_bv(obj, ti, tp, fields, base_ea, pio_flags = 0):
Packs a typed object to a string Packs a typed object to a string
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param base_ea: base ea used to relocate the pointers in the packed object @param base_ea: base ea used to relocate the pointers in the packed object
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
@return: @return:
@ -335,7 +362,7 @@ PyObject *py_pack_object_to_bv(
int pio_flags=0) int pio_flags=0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -353,7 +380,7 @@ PyObject *py_pack_object_to_bv(
// Get type strings // Get type strings
type_t *type = (type_t *)PyString_AsString(py_type); type_t *type = (type_t *)PyString_AsString(py_type);
p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Pack // Pack
relobj_t bytes; relobj_t bytes;
@ -497,7 +524,7 @@ int idc_get_local_type(int ordinal, int flags, char *buf, size_t maxsize)
PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *name, int flags) PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *name, int flags)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -509,7 +536,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam
qstring res; qstring res;
const type_t *type = (type_t *)PyString_AsString(py_type); const type_t *type = (type_t *)PyString_AsString(py_type);
const p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
bool ok; bool ok;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
tinfo_t tif; tinfo_t tif;
@ -536,43 +563,78 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize)
//<code(py_typeinf)> //<code(py_typeinf)>
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// A set of tinfo_t objects that were created from IDAPython. // A set of tinfo_t & details objects that were created from IDAPython.
// This is necessary in order to clear all the "type details" that are // This is necessary in order to clear all the "type details" that are
// associated, in the kernel, with the tinfo_t instances. // associated, in the kernel, with the tinfo_t instances.
// //
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is // Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
// closed, but the "type details" must be cleared _before_ the IDB is closed. // closed, but the "type details" must be cleared _before_ the IDB is closed.
static qvector<tinfo_t*> python_tinfos; static qvector<tinfo_t*> py_tinfo_t_vec;
static qvector<ptr_type_data_t*> py_ptr_type_data_t_vec;
static qvector<array_type_data_t*> py_array_type_data_t_vec;
static qvector<func_type_data_t*> py_func_type_data_t_vec;
static qvector<udt_type_data_t*> py_udt_type_data_t_vec;
static void __clear(tinfo_t *inst) { inst->clear(); }
static void __clear(ptr_type_data_t *inst) { inst->obj_type.clear(); inst->closure.clear(); }
static void __clear(array_type_data_t *inst) { inst->elem_type.clear(); }
static void __clear(func_type_data_t *inst) { inst->clear(); inst->rettype.clear(); }
static void __clear(udt_type_data_t *inst) { inst->clear(); }
void til_clear_python_tinfo_t_instances(void) void til_clear_python_tinfo_t_instances(void)
{ {
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that // Pre-emptive strike: clear all the python-exposed tinfo_t
// were not done here, ~tinfo_t() calls happening as part of the python shutdown // (& related types) instances: if that were not done here,
// process will try and clear() their details. ..but the kernel's til-related // ~tinfo_t() calls happening as part of the python shutdown
// functions will already have deleted those details at that point. // process will try and clear() their details. ..but the kernel's
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i ) // til-related functions will already have deleted those details
python_tinfos[i]->clear(); // at that point.
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t //
// NOTE: Don't clear() the arrays of pointers. All the python-exposed
// instances will be deleted through the python shutdown/ref-decrementing // instances will be deleted through the python shutdown/ref-decrementing
// process anyway (which will cause til_deregister_..() calls), and the // process anyway (which will cause til_deregister_..() calls), and the
// entries will be properly pulled out of the vector when that happens. // entries will be properly pulled out of the vector when that happens.
#define BATCH_CLEAR(Type) \
do \
{ \
for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \
__clear(py_##Type##_vec[i]); \
} while ( false )
BATCH_CLEAR(tinfo_t);
BATCH_CLEAR(ptr_type_data_t);
BATCH_CLEAR(array_type_data_t);
BATCH_CLEAR(func_type_data_t);
BATCH_CLEAR(udt_type_data_t);
#undef BATCH_CLEAR
} }
void til_register_python_tinfo_t_instance(tinfo_t *tif) #define DEF_REG_UNREG_REFCOUNTED(Type) \
{ void til_register_python_##Type##_instance(Type *inst) \
// Let's add_unique() it, because every reference to an object's { \
// tinfo_t property will end up trying to register it. /* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \
python_tinfos.add_unique(tif); /* to an object's tinfo_t property will end up trying to register it. */ \
py_##Type##_vec.add_unique(inst); \
} \
\
void til_deregister_python_##Type##_instance(Type *inst) \
{ \
qvector<Type*>::iterator found = py_##Type##_vec.find(inst); \
if ( found != py_##Type##_vec.end() ) \
{ \
__clear(inst); \
/* tif->clear();*/ \
py_##Type##_vec.erase(found); \
} \
} }
void til_deregister_python_tinfo_t_instance(tinfo_t *tif) DEF_REG_UNREG_REFCOUNTED(tinfo_t);
{ DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t);
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif); DEF_REG_UNREG_REFCOUNTED(array_type_data_t);
if ( found != python_tinfos.end() ) DEF_REG_UNREG_REFCOUNTED(func_type_data_t);
{ DEF_REG_UNREG_REFCOUNTED(udt_type_data_t);
tif->clear();
python_tinfos.erase(found); #undef DEF_REG_UNREG_REFCOUNTED
}
}
//</code(py_typeinf)> //</code(py_typeinf)>

View File

@ -14,7 +14,6 @@ op_t *op_t_get_clink(PyObject *self)
{ {
return (op_t *)pyobj_get_clink(self); return (op_t *)pyobj_get_clink(self);
} }
//</code(py_ua)> //</code(py_ua)>
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -329,6 +328,49 @@ bool py_out_name_expr(
return op == NULL ? false : out_name_expr(*op, ea, off); return op == NULL ? false : out_name_expr(*op, ea, off);
} }
//-------------------------------------------------------------------------
/*
#<pydoc>
def construct_macro(insn):
"""
See ua.hpp's construct_macro().
"""
pass
#</pydoc>
*/
bool py_construct_macro(bool enable, PyObject *build_macro)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyCallable_Check(build_macro) )
return false;
static qstack<ref_t> macro_builders;
macro_builders.push(newref_t(build_macro));
struct ida_local lambda_t
{
static bool idaapi call_build_macro(insn_t &s, bool may_go_forward)
{
PyObject *py_builder = macro_builders.top().o;
newref_t pyres = PyObject_CallFunction(
py_builder, "O",
may_go_forward ? Py_True : Py_False);
PyW_ShowCbErr("build_macro");
if ( pyres.o == NULL || pyres.o == Py_None )
return false;
insn_t *_s = insn_t_get_clink(pyres.o);
if ( _s == NULL )
return false;
s = *_s;
return true;
}
};
bool res = construct_macro(enable, lambda_t::call_build_macro);
macro_builders.pop();
return res;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i) static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
{ {

View File

@ -412,13 +412,13 @@ o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
o_imm = 5 # Immediate Value value o_imm = 5 # Immediate Value value
o_far = 6 # Immediate Far Address (CODE) addr o_far = 6 # Immediate Far Address (CODE) addr
o_near = 7 # Immediate Near Address (CODE) addr o_near = 7 # Immediate Near Address (CODE) addr
o_idpspec0 = 8 # IDP specific type o_idpspec0 = 8 # Processor specific type
o_idpspec1 = 9 # IDP specific type o_idpspec1 = 9 # Processor specific type
o_idpspec2 = 10 # IDP specific type o_idpspec2 = 10 # Processor specific type
o_idpspec3 = 11 # IDP specific type o_idpspec3 = 11 # Processor specific type
o_idpspec4 = 12 # IDP specific type o_idpspec4 = 12 # Processor specific type
o_idpspec5 = 13 # IDP specific type o_idpspec5 = 13 # Processor specific type
o_last = 14 # first unused type # There can be more processor specific types
# #
# op_t.dtyp # op_t.dtyp
@ -485,7 +485,7 @@ class processor_t(pyidc_opaque_object_t):
short processor names similar to the one in ph.psnames. short processor names similar to the one in ph.psnames.
This method can be overridden to return to the kernel a different IDP description. This method can be overridden to return to the kernel a different IDP description.
""" """
return self.plnames[0] + ':' + ':'.join(self.psnames) return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames)))
def get_uFlag(self): def get_uFlag(self):
"""Use this utility function to retrieve the 'uFlag' global variable""" """Use this utility function to retrieve the 'uFlag' global variable"""

View File

@ -138,12 +138,16 @@ class py_customidamemo_t
GRBASE_HAVE_CLOSE = 0x080, GRBASE_HAVE_CLOSE = 0x080,
GRBASE_HAVE_VIEW_SWITCHED = 0x100, GRBASE_HAVE_VIEW_SWITCHED = 0x100,
GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200, GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200,
GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400,
}; };
static void ensure_view_callbacks_installed(); static void ensure_view_callbacks_installed();
int cb_flags; int cb_flags;
// number of arguments for OnViewClick implementation // number of arguments for:
int ovc_num_args; int ovc_num_args; // OnViewClick implementation
int ovdc_num_args; // OnViewDblclick implementation
int ovmo_num_args; // OnViewMouseOver implementation
int ovmm_num_args; // OnViewMouseMoved implementation
protected: protected:
ref_t self; ref_t self;
@ -177,11 +181,15 @@ protected:
bool collect_pyobject_callbacks(PyObject *self); bool collect_pyobject_callbacks(PyObject *self);
virtual void collect_class_callbacks_ids(callbacks_ids_t *out); virtual void collect_class_callbacks_ids(callbacks_ids_t *out);
void install_custom_viewer_handlers();
// Bi-directionally bind/unbind the Python object and this controller. // Bi-directionally bind/unbind the Python object and this controller.
bool bind(PyObject *_self, TCustomControl *view); bool bind(PyObject *_self, TCustomControl *view);
void unbind(); void unbind();
static lookup_info_t lookup_info; static lookup_info_t lookup_info;
friend TForm *pycim_get_tform(PyObject *self);
friend TCustomControl *pycim_get_tcustom_control(PyObject *self);
public: public:
py_customidamemo_t(); py_customidamemo_t();
@ -211,8 +219,16 @@ public:
void on_view_close(); void on_view_close();
void on_view_switched(tcc_renderer_type_t rt); void on_view_switched(tcc_renderer_type_t rt);
void on_view_mouse_over(const view_mouse_event_t *event); void on_view_mouse_over(const view_mouse_event_t *event);
void on_view_mouse_moved(const view_mouse_event_t *event);
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
int get_py_method_arg_count(char *method_name); int get_py_method_arg_count(char *method_name);
// View events that are bound with 'set_custom_viewer_handler()'.
static void idaapi s_on_view_mouse_moved(
TCustomControl *cv,
int shift,
view_mouse_event_t *e,
void *ud);
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -223,6 +239,9 @@ py_customidamemo_t::py_customidamemo_t()
PYGLOG("%p: py_customidamemo_t()\n", this); PYGLOG("%p: py_customidamemo_t()\n", this);
ensure_view_callbacks_installed(); ensure_view_callbacks_installed();
ovc_num_args = -1; ovc_num_args = -1;
ovdc_num_args = -1;
ovmo_num_args = -1;
ovmm_num_args = -1;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -262,7 +281,7 @@ void py_customidamemo_t::ensure_view_callbacks_installed()
py_view->on_view_keydown(key, state); py_view->on_view_keydown(key, state);
} }
break; break;
case view_popup: case obsolete_view_popup:
py_view->on_view_popup(); py_view->on_view_popup();
break; break;
case view_click: case view_click:
@ -514,6 +533,18 @@ void py_customidamemo_t::unbind()
view = NULL; view = NULL;
} }
//-------------------------------------------------------------------------
void idaapi py_customidamemo_t::s_on_view_mouse_moved(
TCustomControl *cv,
int shift,
view_mouse_event_t *e,
void *ud)
{
PYW_GIL_GET;
py_customidamemo_t *_this = (py_customidamemo_t *) ud;
_this->on_view_mouse_moved(e);
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
int py_customidamemo_t::get_py_method_arg_count(char *method_name) int py_customidamemo_t::get_py_method_arg_count(char *method_name)
{ {
@ -544,6 +575,7 @@ void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out)
out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE); out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE);
out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED); out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED);
out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER); out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER);
out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -567,9 +599,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
if ( have > 0 && attr != NULL ) if ( have > 0 && attr != NULL )
cb_flags |= have; cb_flags |= have;
} }
return true; return true;
} }
//-------------------------------------------------------------------------
void py_customidamemo_t::install_custom_viewer_handlers()
{
if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) )
{
// Set user-data
set_custom_viewer_handler(view, CVH_USERDATA, (void *)this);
//
set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved);
}
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#define CHK_EVT(flag_needed) \ #define CHK_EVT(flag_needed) \
@ -577,10 +622,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
return; \ return; \
PYW_GIL_CHECK_LOCKED_SCOPE() PYW_GIL_CHECK_LOCKED_SCOPE()
#ifdef PYGDBG_ENABLED #ifdef PYGDBG_ENABLED
#define CHK_RES() PYGLOG("%s: return code: %p\n", __FUNCTION__, result.o) #define CHK_RES() \
do \
{ \
PYGLOG("%s: return code: %p\n", __FUNCTION__, result.o); \
if (PyErr_Occurred()) \
PyErr_Print(); \
} while ( false )
#else #else
#define CHK_RES() #define CHK_RES() \
do \
{ \
if (PyErr_Occurred()) \
PyErr_Print(); \
} while ( false )
#endif #endif
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -632,13 +689,33 @@ void py_customidamemo_t::on_view_popup()
CHK_RES(); CHK_RES();
} }
//-------------------------------------------------------------------------
static PyObject *build_renderer_pos_swig_proxy(const view_mouse_event_t *event)
{
return SWIG_NewPointerObj(
SWIG_as_voidptr(&event->renderer_pos),
SWIGTYPE_p_renderer_pos_info_t,
0);
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
{ {
CHK_EVT(GRBASE_HAVE_VIEW_CLICK); CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
if ( ovc_num_args < 0 ) if ( ovc_num_args < 0 )
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
if ( ovc_num_args == 5 ) if ( ovc_num_args == 6 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iiiiO",
event->x, event->y, event->state, event->button, rpos));
CHK_RES();
}
else if ( ovc_num_args == 5 )
{ {
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
@ -646,6 +723,7 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
(char *)S_ON_VIEW_CLICK, (char *)S_ON_VIEW_CLICK,
"iiii", "iiii",
event->x, event->y, event->state, event->button)); event->x, event->y, event->state, event->button));
CHK_RES();
} }
else else
{ {
@ -655,14 +733,29 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
(char *)S_ON_VIEW_CLICK, (char *)S_ON_VIEW_CLICK,
"iii", "iii",
event->x, event->y, event->state)); event->x, event->y, event->state));
}
CHK_RES(); CHK_RES();
} }
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event) void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
{ {
CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK); CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK);
if ( ovdc_num_args < 0 )
ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK);
if ( ovdc_num_args == 5 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_DBLCLICK,
"iiiO",
event->x, event->y, event->state, rpos));
CHK_RES();
}
else
{
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
@ -671,6 +764,7 @@ void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
event->x, event->y, event->state)); event->x, event->y, event->state));
CHK_RES(); CHK_RES();
} }
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_curpos() void py_customidamemo_t::on_view_curpos()
@ -701,32 +795,55 @@ void py_customidamemo_t::on_view_switched(tcc_renderer_type_t rt)
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event) static ref_t build_current_graph_item_tuple(int *out_icode, const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
if ( event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY )
{ {
const selection_item_t *item = event->location.item; const selection_item_t *item = event->location.item;
int icode;
ref_t tuple; ref_t tuple;
if ( item != NULL ) if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY)
&& item != NULL )
{ {
if ( item->is_node ) if ( item->is_node )
{ {
icode = 1; *out_icode = 1;
tuple = newref_t(Py_BuildValue("(i)", item->node)); tuple = newref_t(Py_BuildValue("(i)", item->node));
} }
else else
{ {
icode = 2; *out_icode = 2;
tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst)); tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst));
} }
} }
else else
{ {
icode = 0; *out_icode = 0;
tuple = newref_t(Py_BuildValue("()")); tuple = newref_t(Py_BuildValue("()"));
} }
return tuple;
}
//-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
if ( ovmo_num_args < 0 )
ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER);
if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY )
return;
int icode;
ref_t tuple = build_current_graph_item_tuple(&icode, event);
if ( ovmo_num_args == 7 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_MOUSE_OVER,
"iiiiOO",
event->x, event->y, event->state, icode, tuple.o, rpos));
CHK_RES();
}
else
{
newref_t result(PyObject_CallMethod( newref_t result(PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_VIEW_MOUSE_OVER, (char *)S_ON_VIEW_MOUSE_OVER,
@ -736,6 +853,27 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
} }
} }
//-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_moved(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_MOVED);
if ( ovmm_num_args < 0 )
ovmm_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_MOVED);
int icode;
ref_t tuple = build_current_graph_item_tuple(&icode, event);
if ( ovmm_num_args == 7 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_MOUSE_MOVED,
"iiiiOO",
event->x, event->y, event->state, icode, tuple.o, rpos));
CHK_RES();
}
}
#undef CHK_RES #undef CHK_RES
#undef CHK_EVT #undef CHK_EVT
@ -748,6 +886,10 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
GET_THIS(); \ GET_THIS(); \
if ( _this == NULL ) \ if ( _this == NULL ) \
return return
#define CHK_THIS_OR_NULL() \
GET_THIS(); \
if ( _this == NULL ) \
return NULL;
#define CHK_THIS_OR_NONE() \ #define CHK_THIS_OR_NONE() \
GET_THIS(); \ GET_THIS(); \
if ( _this == NULL ) \ if ( _this == NULL ) \
@ -829,7 +971,28 @@ PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject
return _this->set_groups_visibility(groups, expand, new_current); return _this->set_groups_visibility(groups, expand, new_current);
} }
//-------------------------------------------------------------------------
TForm *pycim_get_tform(PyObject *self)
{
CHK_THIS_OR_NULL();
TForm *form = NULL;
if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) )
return NULL;
return form;
}
//-------------------------------------------------------------------------
TCustomControl *pycim_get_tcustom_control(PyObject *self)
{
CHK_THIS_OR_NULL();
TCustomControl *tcc = NULL;
if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) )
return NULL;
return tcc;
}
#undef CHK_THIS_OR_NONE #undef CHK_THIS_OR_NONE
#undef CHK_THIS_OR_NULL
#undef CHK_THIS #undef CHK_THIS
#undef GET_THIS #undef GET_THIS
@ -848,6 +1011,8 @@ void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt);
PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos); PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos);
PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current); PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current);
PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current); PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current);
TForm *pycim_get_tform(PyObject *self);
TCustomControl *pycim_get_tcustom_control(PyObject *self);
//</inline(py_view_base)> //</inline(py_view_base)>

View File

@ -104,4 +104,21 @@ class CustomIDAMemo(object):
""" """
return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current) return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current)
def GetTForm(self):
"""
Return the TForm hosting this view.
@return: The TForm that hosts this view, or None.
"""
return _idaapi.pycim_get_tform(self)
def GetTCustomControl(self):
"""
Return the TCustomControl underlying this view.
@return: The TCustomControl underlying this view, or None.
"""
return _idaapi.pycim_get_tcustom_control(self)
#</pycode(py_view_base)> #</pycode(py_view_base)>

View File

@ -985,7 +985,7 @@
> >
</File> </File>
<File <File
RelativePath="..\examples\ex_add_menu_item.py" RelativePath="..\examples\ex_actions.py"
> >
</File> </File>
<File <File

View File

@ -92,7 +92,6 @@ BADADDR = 0xFFFFFFFFFFFFFFFFL
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
UA_MAXOP = 6 UA_MAXOP = 6
o_last = 14
o_void = 0 o_void = 0
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

View File

@ -42,13 +42,13 @@ o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
o_imm = 5 # Immediate Value value o_imm = 5 # Immediate Value value
o_far = 6 # Immediate Far Address (CODE) addr o_far = 6 # Immediate Far Address (CODE) addr
o_near = 7 # Immediate Near Address (CODE) addr o_near = 7 # Immediate Near Address (CODE) addr
o_idpspec0 = 8 # IDP specific type o_idpspec0 = 8 # Processor specific type
o_idpspec1 = 9 # IDP specific type o_idpspec1 = 9 # Processor specific type
o_idpspec2 = 10 # IDP specific type o_idpspec2 = 10 # Processor specific type
o_idpspec3 = 11 # IDP specific type o_idpspec3 = 11 # Processor specific type
o_idpspec4 = 12 # IDP specific type o_idpspec4 = 12 # Processor specific type
o_idpspec5 = 13 # IDP specific type o_idpspec5 = 13 # Processor specific type
o_last = 14 # first unused type # There can be more processor specific types
# #
# op_t.dtyp # op_t.dtyp

View File

@ -751,15 +751,21 @@ ACFOPT_ESCAPE = 0x00000010 # for ACFOPT_ASCII, convert non-printable
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII): def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
""" """
Get contents of ascii string Get bytes contents at location, possibly converted.
This function returns the displayed part of the string
It works even if the string has not been created in the database yet. It works even if the string has not been created in the database yet.
Note that this will <b>always</b> return a simple string of bytes
(i.e., a 'str' instance), and not a string of unicode characters.
If you want auto-conversion to unicode strings (that is: real strings),
you should probably be using the idautils.Strings class.
@param ea: linear address of the string @param ea: linear address of the string
@param len: length of the string in bytes (including terminating 0) @param len: length of the string in bytes (including terminating 0)
@param type: type of the string @param type: type of the string. Represents both the character encoding,
@param flags: combination of ACFOPT_... <u>and</u> the 'type' of string at the given location.
@return: string contents (not including terminating 0) or None @param flags: combination of ACFOPT_..., to perform output conversion.
@return: a bytes-filled str object.
""" """
pass pass
#</pydoc> #</pydoc>
@ -775,7 +781,7 @@ static PyObject *py_get_ascii_contents2(
return NULL; return NULL;
size_t used_size; size_t used_size;
if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size) ) if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size, flags) )
{ {
qfree(buf); qfree(buf);
Py_RETURN_NONE; Py_RETURN_NONE;

View File

@ -28,6 +28,20 @@ typedef struct
%ignore set_manual_regions; %ignore set_manual_regions;
%ignore inform_idc_about_debthread; %ignore inform_idc_about_debthread;
%ignore is_dbgmem_valid; %ignore is_dbgmem_valid;
%rename (list_bptgrps) py_list_bptgrps;
%apply qstring *result { qstring *grp_name };
%ignore qvector<bpt_t>::operator==;
%ignore qvector<bpt_t>::operator!=;
%ignore qvector<bpt_t>::find;
%ignore qvector<bpt_t>::has;
%ignore qvector<bpt_t>::del;
%ignore qvector<bpt_t>::add_unique;
%template(bpt_vec_t) qvector<bpt_t>;
%ignore internal_get_sreg_base;
%rename (internal_get_sreg_base) py_internal_get_sreg_base;
// We want ALL wrappers around what is declared in dbg.hpp // We want ALL wrappers around what is declared in dbg.hpp
// to release the GIL when calling into the IDA api: those // to release the GIL when calling into the IDA api: those
// might be very long operations, that even require some // might be very long operations, that even require some
@ -384,6 +398,64 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
} }
return code; return code;
} }
//------------------------------------------------------------------------
/*
#<pydoc>
def py_list_bptgrps():
"""
Returns list of breakpoint group names
@return: A list of strings or None on failure
"""
pass
#</pydoc>
*/
static PyObject *py_list_bptgrps()
{
PYW_GIL_CHECK_LOCKED_SCOPE();
qstrvec_t args;
if ( list_bptgrps(&args) == 0 )
Py_RETURN_NONE;
return qstrvec2pylist(args);
}
//------------------------------------------------------------------------
/*
#<pydoc>
def move_bpt_to_grp():
"""
Sets new group for the breakpoint
"""
pass
#</pydoc>
*/
static void move_bpt_to_grp(bpt_t *bpt, const char *grp_name)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
set_bpt_group(*bpt, grp_name);
}
/*
#<pydoc>
def internal_get_sreg_base():
"""
Get the sreg base, for the given thread.
@return: The sreg base, or BADADDR on failure.
"""
pass
#</pydoc>
*/
static ea_t py_internal_get_sreg_base(thid_t tid, int sreg_value)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
ea_t answer;
return internal_get_sreg_base(tid, sreg_value, &answer) < 1
? BADADDR
: answer;
}
//</inline(py_dbg)> //</inline(py_dbg)>
%} %}

View File

@ -2,6 +2,7 @@
%ignore enumerate_files; %ignore enumerate_files;
%rename (enumerate_files) py_enumerate_files; %rename (enumerate_files) py_enumerate_files;
%ignore enumerate_system_files; %ignore enumerate_system_files;
%ignore enumerate_sorted_files;
%ignore ioport_bit_t; %ignore ioport_bit_t;
%ignore ioport_bits_t; %ignore ioport_bits_t;
%ignore ioport_t; %ignore ioport_t;

View File

@ -38,6 +38,7 @@
%ignore idc_stacksize; %ignore idc_stacksize;
%ignore idc_calldepth; %ignore idc_calldepth;
%ignore expr_printf; %ignore expr_printf;
%ignore expr_uprintf;
%ignore expr_sprintf; %ignore expr_sprintf;
%ignore expr_printfer; %ignore expr_printfer;
%ignore init_idc; %ignore init_idc;

View File

@ -29,4 +29,6 @@
%ignore calc_frame_offset; %ignore calc_frame_offset;
%ignore add_stkvar; %ignore add_stkvar;
%template(xreflist_t) qvector<xreflist_entry_t>;
%include "frame.hpp" %include "frame.hpp"

View File

@ -41,7 +41,10 @@ private:
GRCODE_HAVE_GOTFOCUS = 0x00080000, GRCODE_HAVE_GOTFOCUS = 0x00080000,
GRCODE_HAVE_LOSTFOCUS = 0x00100000, GRCODE_HAVE_LOSTFOCUS = 0x00100000,
GRCODE_HAVE_CHANGED_CURRENT = 0x00200000, GRCODE_HAVE_CHANGED_CURRENT = 0x00200000,
GRCODE_HAVE_COMMAND = 0x00400000 GRCODE_HAVE_COMMAND = 0x00400000,
GRCODE_HAVE_CREATING_GROUP = 0x00800000,
GRCODE_HAVE_DELETING_GROUP = 0x01000000,
GRCODE_HAVE_GROUP_VISIBILITY = 0x02000000,
}; };
struct nodetext_cache_t struct nodetext_cache_t
{ {
@ -145,6 +148,7 @@ private:
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id)); newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id));
PyW_ShowCbErr(S_ON_COMMAND);
} }
// Refresh user-defined graph node number and edges // Refresh user-defined graph node number and edges
@ -192,6 +196,7 @@ private:
(char *)S_ON_CLICK, (char *)S_ON_CLICK,
"i", "i",
item2->n)); item2->n));
PyW_ShowCbErr(S_ON_CLICK);
return result == NULL || !PyObject_IsTrue(result.o); return result == NULL || !PyObject_IsTrue(result.o);
} }
@ -213,29 +218,38 @@ private:
(char *)S_ON_DBL_CLICK, (char *)S_ON_DBL_CLICK,
"i", "i",
item->node)); item->node));
PyW_ShowCbErr(S_ON_DBL_CLICK);
return result == NULL || !PyObject_IsTrue(result.o); return result == NULL || !PyObject_IsTrue(result.o);
} }
// a graph viewer got focus // a graph viewer got focus
void on_gotfocus(graph_viewer_t * /*view*/) void on_gotfocus(graph_viewer_t * /*view*/)
{ {
if ( self.o == NULL )
return;
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_ACTIVATE, (char *)S_ON_ACTIVATE,
NULL)); NULL));
PyW_ShowCbErr(S_ON_ACTIVATE);
} }
// a graph viewer lost focus // a graph viewer lost focus
void on_lostfocus(graph_viewer_t * /*view*/) void on_lostfocus(graph_viewer_t * /*view*/)
{ {
if ( self.o == NULL )
return;
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_DEACTIVATE, (char *)S_ON_DEACTIVATE,
NULL)); NULL));
PyW_ShowCbErr(S_ON_DEACTIVATE);
} }
// a new graph node became the current node // a new graph node became the current node
@ -254,6 +268,7 @@ private:
(char *)S_ON_SELECT, (char *)S_ON_SELECT,
"i", "i",
curnode)); curnode));
PyW_ShowCbErr(S_ON_SELECT);
return !(result != NULL && PyObject_IsTrue(result.o)); return !(result != NULL && PyObject_IsTrue(result.o));
} }
@ -261,7 +276,6 @@ private:
int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes) int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); 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())); newref_t py_nodes(PyList_New(my_nodes->size()));
int i; int i;
intvec_t::const_iterator p; intvec_t::const_iterator p;
@ -273,6 +287,7 @@ private:
(char *)S_ON_CREATING_GROUP, (char *)S_ON_CREATING_GROUP,
"O", "O",
py_nodes.o)); py_nodes.o));
PyW_ShowCbErr(S_ON_CREATING_GROUP);
return (py_result == NULL || !PyInt_Check(py_result.o)) ? 1 : PyInt_AsLong(py_result.o); return (py_result == NULL || !PyInt_Check(py_result.o)) ? 1 : PyInt_AsLong(py_result.o);
} }
@ -302,6 +317,10 @@ private:
void jump_to_node(int nid) void jump_to_node(int nid)
{ {
ref_t nodes(PyW_TryGetAttrString(self.o, S_M_NODES));
if ( nid >= PyList_Size(nodes.o) )
return;
viewer_center_on(view, nid); viewer_center_on(view, nid);
int x, y; int x, y;
@ -345,6 +364,7 @@ private:
if ( pview != NULL ) if ( pview != NULL )
viewer_fit_window(pview); viewer_fit_window(pview);
bind(self, pview); bind(self, pview);
install_custom_viewer_handlers();
refresh(); refresh();
lookup_info.commit(e, form, view); lookup_info.commit(e, form, view);
} }
@ -382,13 +402,16 @@ public:
cmdid_pyg.clear(this); cmdid_pyg.clear(this);
} }
static void SelectNode(PyObject *self, int /*nid*/) static void SelectNode(PyObject *self, int nid)
{ {
if ( nid < 0 )
return;
py_graph_t *_this = view_extract_this<py_graph_t>(self); py_graph_t *_this = view_extract_this<py_graph_t>(self);
if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) ) if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) )
return; return;
_this->jump_to_node(0); _this->jump_to_node(nid);
} }
static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey) static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey)
@ -468,6 +491,9 @@ void py_graph_t::collect_class_callbacks_ids(callbacks_ids_t *out)
out->add(S_ON_SELECT, GRCODE_HAVE_CHANGED_CURRENT); out->add(S_ON_SELECT, GRCODE_HAVE_CHANGED_CURRENT);
out->add(S_ON_ACTIVATE, GRCODE_HAVE_GOTFOCUS); out->add(S_ON_ACTIVATE, GRCODE_HAVE_GOTFOCUS);
out->add(S_ON_DEACTIVATE, GRCODE_HAVE_LOSTFOCUS); out->add(S_ON_DEACTIVATE, GRCODE_HAVE_LOSTFOCUS);
out->add(S_ON_CREATING_GROUP, GRCODE_HAVE_CREATING_GROUP);
out->add(S_ON_DELETING_GROUP, GRCODE_HAVE_DELETING_GROUP);
out->add(S_ON_GROUP_VISIBILITY, GRCODE_HAVE_GROUP_VISIBILITY);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -479,6 +505,7 @@ void py_graph_t::on_user_refresh(mutable_graph_t *g)
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL)); newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL));
PyW_ShowCbErr(S_ON_REFRESH);
if ( ret != NULL && PyObject_IsTrue(ret.o) ) if ( ret != NULL && PyObject_IsTrue(ret.o) )
{ {
// Refer to the nodes // Refer to the nodes
@ -550,6 +577,7 @@ bool py_graph_t::on_user_text(mutable_graph_t * /*g*/, int node, const char **st
// Not cached, call Python // Not cached, call Python
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node)); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node));
PyW_ShowCbErr(S_ON_GETTEXT);
if ( result == NULL ) if ( result == NULL )
return false; return false;
@ -597,6 +625,7 @@ int py_graph_t::on_user_hint(mutable_graph_t *, int mousenode, int /*mouseedge_s
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_HINT, "i", mousenode)); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_HINT, "i", mousenode));
PyW_ShowCbErr(S_ON_HINT);
bool ok = result != NULL && PyString_Check(result.o); bool ok = result != NULL && PyString_Check(result.o);
if ( ok ) if ( ok )
*hint = qstrdup(PyString_AsString(result.o)); *hint = qstrdup(PyString_AsString(result.o));
@ -650,7 +679,10 @@ int py_graph_t::gr_callback(int code, va_list va)
ret = on_dblclicked(view, item); ret = on_dblclicked(view, item);
} }
else else
ret = 1; // ignore ret = 0; // We don't want to ignore the double click, but rather
// fallback to the default behavior (e.g., double-clicking
// on an edge will to jump to the node on the other side
// of that edge.)
break; break;
// //
case grcode_gotfocus: case grcode_gotfocus:
@ -701,28 +733,43 @@ int py_graph_t::gr_callback(int code, va_list va)
break; break;
// //
case grcode_creating_group: // a group is being created case grcode_creating_group: // a group is being created
if ( has_callback(GRCODE_HAVE_CREATING_GROUP) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
intvec_t *nodes = va_arg(va, intvec_t*); intvec_t *nodes = va_arg(va, intvec_t*);
ret = on_creating_group(g, nodes); ret = on_creating_group(g, nodes);
} }
else
{
ret = 0; // Ok to create
}
break; break;
// //
case grcode_deleting_group: // a group is being deleted case grcode_deleting_group: // a group is being deleted
if ( has_callback(GRCODE_HAVE_DELETING_GROUP) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
int old_group = va_arg(va, int); int old_group = va_arg(va, int);
ret = on_deleting_group(g, old_group); ret = on_deleting_group(g, old_group);
} }
else
{
ret = 0; // Ok to delete
}
break; break;
// //
case grcode_group_visibility: // a group is being collapsed/uncollapsed case grcode_group_visibility: // a group is being collapsed/uncollapsed
if ( has_callback(GRCODE_HAVE_GROUP_VISIBILITY) )
{ {
mutable_graph_t *g = va_arg(va, mutable_graph_t*); mutable_graph_t *g = va_arg(va, mutable_graph_t*);
int group = va_arg(va, int); int group = va_arg(va, int);
bool expand = bool(va_arg(va, int)); bool expand = bool(va_arg(va, int));
ret = on_group_visibility(g, group, expand); ret = on_group_visibility(g, group, expand);
} }
else
{
ret = 0; // Ok.
}
break; break;
// //
default: default:
@ -844,10 +891,9 @@ class GraphViewer(CustomIDAMemo):
def AddCommand(self, title, hotkey): def AddCommand(self, title, hotkey):
""" """
Adds a menu command to the graph. Call this command after the graph is shown (with Show()). Deprecated: Use
Once a command is added, a command id is returned. The commands are handled inside the OnCommand() handler - register_action()
- attach_action_to_popup()
@return: 0 on failure or the command id
""" """
return _idaapi.pyg_add_command(self, title, hotkey) return _idaapi.pyg_add_command(self, title, hotkey)
@ -929,10 +975,9 @@ class GraphViewer(CustomIDAMemo):
# #
# def OnCommand(self, cmd_id): # def OnCommand(self, cmd_id):
# """ # """
# Triggered when a menu command is selected through the menu or its hotkey # Deprecated
# @return: None
# """ # """
# print "command:", cmd_id # pass
#</pydoc> #</pydoc>
#</pycode(py_graph)> #</pycode(py_graph)>
%} %}

View File

@ -57,6 +57,7 @@
%ignore cexpr_t::cexpr_t(mbl_array_t *mba, const lvar_t &v); %ignore cexpr_t::cexpr_t(mbl_array_t *mba, const lvar_t &v);
%ignore lvar_t::is_promoted_arg; %ignore lvar_t::is_promoted_arg;
%ignore lvar_t::lvar_t; %ignore lvar_t::lvar_t;
%ignore vdloc_t::is_fpu_mreg;
%ignore strtype_info_t::find_strmem; %ignore strtype_info_t::find_strmem;
%ignore file_printer_t::_print; %ignore file_printer_t::_print;
%ignore file_printer_t; %ignore file_printer_t;
@ -120,51 +121,72 @@ public:
cexpr_t *cexpr const { return (cexpr_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. // 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 { #define CITEM_MEMBER_REF(name) \
CITEM_MEMBER_REF(cblock) c##name##_t *c##name const { if ( self->op == cit_##name ) { return self->c##name; } else { return NULL; } }
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)
};
%extend cinsn_t {
CITEM_MEMBER_REF(block);
CITEM_MEMBER_REF(expr);
CITEM_MEMBER_REF(if);
CITEM_MEMBER_REF(for);
CITEM_MEMBER_REF(while);
CITEM_MEMBER_REF(do);
CITEM_MEMBER_REF(switch);
CITEM_MEMBER_REF(return);
CITEM_MEMBER_REF(goto);
CITEM_MEMBER_REF(asm);
};
#undef CITEM_MEMBER_REF
//-------------------------------------------------------------------------
#define CEXPR_MEMBER_REF(type, name) \ #define CEXPR_MEMBER_REF(type, name) \
type name const { return self->##name; } type name const { return self->##name; }
#define CEXPR_CONDITIONAL_MEMBER_REF(type, name, condition, default_value) \
type name const { if ( condition ) { return self->##name; } else { return default_value; } }
%extend cexpr_t { %extend cexpr_t {
CEXPR_MEMBER_REF(cnumber_t*, n) CEXPR_CONDITIONAL_MEMBER_REF(cnumber_t*, n, self->op == cot_num, NULL);
CEXPR_MEMBER_REF(fnumber_t*, fpc) CEXPR_CONDITIONAL_MEMBER_REF(fnumber_t*, fpc, self->op == cot_fnum, NULL);
const var_ref_t& v { return self->v; } var_ref_t* v const { if ( self->op == cot_var ) { return &self->v; } else { return NULL; } }
CEXPR_MEMBER_REF(ea_t, obj_ea) CEXPR_CONDITIONAL_MEMBER_REF(ea_t, obj_ea, self->op == cot_obj, BADADDR);
CEXPR_MEMBER_REF(int, refwidth) CEXPR_MEMBER_REF(int, refwidth);
CEXPR_MEMBER_REF(cexpr_t*, x) CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, x, op_uses_x(self->op), NULL);
CEXPR_MEMBER_REF(cexpr_t*, y) CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, y, op_uses_y(self->op), NULL);
CEXPR_MEMBER_REF(carglist_t*, a) CEXPR_CONDITIONAL_MEMBER_REF(carglist_t*, a, self->op == cot_call, NULL);
CEXPR_MEMBER_REF(int, m) CEXPR_CONDITIONAL_MEMBER_REF(int, m, self->op == cot_memptr || self->op == cot_memref, 0);
CEXPR_MEMBER_REF(cexpr_t*, z) CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, z, op_uses_z(self->op), NULL);
CEXPR_MEMBER_REF(int, ptrsize) CEXPR_CONDITIONAL_MEMBER_REF(int, ptrsize, self->op == cot_ptr || self->op == cot_memptr, 0);
CEXPR_MEMBER_REF(cinsn_t*, insn) CEXPR_MEMBER_REF(cinsn_t*, insn);
CEXPR_MEMBER_REF(char*, helper) CEXPR_CONDITIONAL_MEMBER_REF(char*, helper, self->op == cot_helper, NULL);
CEXPR_MEMBER_REF(char*, string) CEXPR_CONDITIONAL_MEMBER_REF(char*, string, self->op == cot_str, NULL);
}; };
#undef CEXPR_CONDITIONAL_MEMBER_REF
#undef CEXPR_MEMBER_REF
//-------------------------------------------------------------------------
#define CTREE_ITEM_MEMBER_REF(type, name) \
type name const { return self->##name; }
#define CTREE_CONDITIONAL_ITEM_MEMBER_REF(type, name, wanted_citype) \
type name const { if ( self->citype == wanted_citype ) { return self->##name; } else { return NULL; } }
%extend ctree_item_t { %extend ctree_item_t {
CEXPR_MEMBER_REF(citem_t *, it) CTREE_ITEM_MEMBER_REF(citem_t *, it);
CEXPR_MEMBER_REF(lvar_t*, l) CTREE_CONDITIONAL_ITEM_MEMBER_REF(cexpr_t*, e, VDI_EXPR);
CEXPR_MEMBER_REF(cfunc_t*, f) CTREE_CONDITIONAL_ITEM_MEMBER_REF(cinsn_t*, i, VDI_EXPR);
const treeloc_t& loc { return self->loc; } CTREE_CONDITIONAL_ITEM_MEMBER_REF(lvar_t*, l, VDI_LVAR);
CTREE_CONDITIONAL_ITEM_MEMBER_REF(cfunc_t*, f, VDI_FUNC);
treeloc_t* loc const { if ( self->citype == VDI_TAIL ) { return &self->loc; } else { return NULL; } }
}; };
#undef CTREE_CONDITIONAL_ITEM_MEMBER_REF
#undef CTREE_ITEM_MEMBER_REF
//-------------------------------------------------------------------------
/* for qvector instanciations where the class is a pointer (cinsn_t, citem_t) we need /* 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. */ to fix the at() return type, otherwise swig mistakenly thinks it is "cinsn_t *&" and nonsense ensues. */
%extend qvector< cinsn_t *> { %extend qvector< cinsn_t *> {
@ -305,24 +327,16 @@ static int hexrays_python_call(ref_t fct, ref_t args)
{ {
PYW_GIL_GET; PYW_GIL_GET;
int result;
int ecode1 = 0 ;
newref_t resultobj(PyEval_CallObject(fct.o, args.o)); newref_t resultobj(PyEval_CallObject(fct.o, args.o));
if ( resultobj == NULL ) if (PyErr_Occurred())
{ {
msg("IDAPython: Hex-rays python callback raised an exception.\n"); PyErr_Print();
// 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; return 0;
} }
ecode1 = SWIG_AsVal_int(resultobj.o, &result); int result;
if (SWIG_IsOK(ecode1)) if ( SWIG_IsOK(SWIG_AsVal_int(resultobj.o, &result)) )
return result; return result;
msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n"); msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n");
return 0; return 0;
} }
@ -508,6 +522,22 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_
ret = hexrays_python_call(fct, args); ret = hexrays_python_call(fct, args);
} }
break; break;
case hxe_populating_popup:
///< Populating popup menu. We can add menu items now.
///< TForm *form
///< TPopupMenu *popup_handle
///< vdui_t *vu
{
TForm *form = va_arg(va, TForm *);
TPopupMenu *pp = va_arg(va, TPopupMenu*);
vdui_t *vdui = va_arg(va, vdui_t *);
newref_t py_form(SWIG_NewPointerObj(SWIG_as_voidptr(form), SWIGTYPE_p_Forms__TForm, 0));
newref_t py_popup(SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_Menus__TPopupMenu, 0));
newref_t py_vdui(SWIG_NewPointerObj(SWIG_as_voidptr(vdui), SWIGTYPE_p_vdui_t, 0 ));
newref_t py_args(Py_BuildValue("(iOOO)", event, py_form.o, py_popup.o, py_vdui.o));
ret = hexrays_python_call(fct, py_args);
}
break;
default: default:
//~ msg("IDAPython: Unknown event `%u' occured\n", event); //~ msg("IDAPython: Unknown event `%u' occured\n", event);
ret = 0; ret = 0;
@ -677,17 +707,37 @@ cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf);
%python_callback_in(PyObject *custom_viewer_popup_item_callback); %python_callback_in(PyObject *custom_viewer_popup_item_callback);
%ignore cexpr_t::get_1num_op(const cexpr_t **, const cexpr_t **) const; %ignore cexpr_t::get_1num_op(const cexpr_t **, const cexpr_t **) const;
%ignore cexpr_t::find_ptr_or_array(bool) const;
#pragma SWIG nowarn=503 #pragma SWIG nowarn=503
%warnfilter(514) user_lvar_visitor_t; // Director base class 'x' has no virtual destructor. %warnfilter(514) user_lvar_visitor_t; // Director base class 'x' has no virtual destructor.
%warnfilter(514) ctree_visitor_t; // ditto %warnfilter(514) ctree_visitor_t; // ditto
%warnfilter(514) ctree_parentee_t; // ditto %warnfilter(514) ctree_parentee_t; // ditto
%warnfilter(514) cfunc_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. %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_visitor_t;
%feature("director") ctree_parentee_t; %feature("director") ctree_parentee_t;
%feature("director") cfunc_parentee_t; %feature("director") cfunc_parentee_t;
%feature("director") user_lvar_visitor_t; %feature("director") user_lvar_visitor_t;
// http://www.swig.org/Doc2.0/SWIGDocumentation.html#Python_nn36
// http://www.swig.org/Doc2.0/SWIGDocumentation.html#Customization_exception_special_variables
%define %possible_director_exc(Method)
%exception Method {
try {
$action
} catch ( Swig::DirectorException & ) {
// A DirectorException might be raised in deeper layers.
SWIG_fail;
}
}
%enddef
%possible_director_exc(ctree_visitor_t::apply_to)
%possible_director_exc(ctree_visitor_t::apply_to_exprs)
%include "hexrays.hpp" %include "hexrays.hpp"
%exception; // Delete & restore handlers
%exception_set_default_handlers();
%pythoncode %{ %pythoncode %{
@ -1099,7 +1149,7 @@ _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_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_iflags_t, 'user_iflags', citem_locator_t, (int, long))
_map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t) _map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t)
_map_as_dict(eamap_t, 'eamap', int, cinsnptrvec_t) _map_as_dict(eamap_t, 'eamap', long, cinsnptrvec_t)
#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t) #_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t)
%} %}

View File

@ -17,10 +17,73 @@
#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory #pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory
%constant size_t SIZE_MAX = size_t(-1); %constant size_t SIZE_MAX = size_t(-1);
%{
#ifndef USE_DANGEROUS_FUNCTIONS
#define USE_DANGEROUS_FUNCTIONS 1
#endif
#include <pro.h>
void raise_python_stl_bad_alloc(const std::bad_alloc &ba)
{
Py_INCREF(PyExc_MemoryError);
PyErr_SetString(PyExc_MemoryError, "Out of memory (bad_alloc)");
}
void raise_python_unknown_exception()
{
Py_INCREF(PyExc_RuntimeError);
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
void raise_python_stl_exception(const std::exception &e)
{
const char *what = e.what();
if ( what == NULL || what[0] == '\0' )
{
raise_python_unknown_exception();
}
else
{
Py_INCREF(PyExc_RuntimeError);
PyErr_SetString(PyExc_RuntimeError, what);
}
}
%}
%define %exception_set_default_handlers()
%exception {
try
{
$action
}
catch ( const std::bad_alloc &ba ) { raise_python_stl_bad_alloc(ba); SWIG_fail; }
catch ( const std::exception &e ) { raise_python_stl_exception(e); SWIG_fail; }
catch (...) { raise_python_unknown_exception(); SWIG_fail; }
}
%enddef
%exception_set_default_handlers();
// Enable automatic docstring generation // Enable automatic docstring generation
%feature(autodoc,0); %feature(autodoc,0);
%{
/* strnlen() arrived on OSX at v10.7. Provide it ourselves if needed. */
#ifdef __MAC__
#ifndef MAC_OS_X_VERSION_10_7
#define MAC_OS_X_VERSION_10_7 1070
#endif
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
inline size_t strnlen(const char *s, size_t maxlen)
{
const char *found = (const char *) memchr(s, 0, maxlen);
return found != NULL ? size_t(found - s) : maxlen;
}
#endif
#endif
%}
%define SWIG_DECLARE_PY_CLINKED_OBJECT(type) %define SWIG_DECLARE_PY_CLINKED_OBJECT(type)
%inline %{ %inline %{
static PyObject *type##_create() static PyObject *type##_create()
@ -59,10 +122,6 @@ static PyObject *type##_get_clink_ptr(PyObject *self)
%{ %{
#include <Python.h> #include <Python.h>
#ifndef USE_DANGEROUS_FUNCTIONS
#define USE_DANGEROUS_FUNCTIONS 1
#endif
#ifdef HAVE_SSIZE_T #ifdef HAVE_SSIZE_T
#define _SSIZE_T_DEFINED 1 #define _SSIZE_T_DEFINED 1
#endif #endif
@ -102,6 +161,7 @@ static PyObject *type##_get_clink_ptr(PyObject *self)
#include "strlist.hpp" #include "strlist.hpp"
#include "struct.hpp" #include "struct.hpp"
#include "typeinf.hpp" #include "typeinf.hpp"
#include "registry.hpp"
#include "ua.hpp" #include "ua.hpp"
#include "xref.hpp" #include "xref.hpp"
#include "ieee.h" #include "ieee.h"
@ -174,323 +234,6 @@ struct scfld_t
#define FT_BAD_TYPE -2 #define FT_BAD_TYPE -2
#define FT_OK 1 #define FT_OK 1
// //-----------------------------------------------------------------------
// class pycvt_t
// {
// struct attr_t
// {
// qstring str;
// uint64 u64;
// // User is responsible to release this attribute when done
// PyObject *py_obj;
// };
// //-----------------------------------------------------------------------
// static int get_attr(
// PyObject *py_obj,
// const char *attrname,
// int ft,
// attr_t &val)
// {
// ref_t py_attr(PyW_TryGetAttrString(py_obj, attrname));
// if ( py_attr == NULL )
// return FT_NOT_FOUND;
// int cvt = FT_OK;
// if ( ft == FT_STR || ft == FT_CHAR && PyString_Check(py_attr.o) )
// val.str = PyString_AsString(py_attr.o);
// else if ( (ft > FT_FIRST_NUM && ft < FT_LAST_NUM) && PyW_GetNumber(py_attr.o, &val.u64) )
// ; // nothing to be done
// // A string array?
// else if ( (ft == FT_STRARR || ft == FT_NUM16ARR || ft == FT_CHRARR_STATIC )
// && (PyList_CheckExact(py_attr.o) || PyW_IsSequenceType(py_attr.o)) )
// {
// // Return a reference to the attribute
// val.py_obj = py_attr.o;
// // Do not decrement the reference to this attribute
// py_attr = NULL;
// }
// else
// cvt = FT_BAD_TYPE;
// return cvt;
// }
// //-----------------------------------------------------------------------
// static int idaapi make_str_list_cb(
// PyObject *py_item,
// Py_ssize_t index,
// void *ud)
// {
// if ( !PyString_Check(py_item) )
// return CIP_FAILED;
// char **a = (char **)ud;
// a[index] = qstrdup(PyString_AsString(py_item));
// return CIP_OK;
// }
// //-----------------------------------------------------------------------
// // Converts an IDC list of strings to a C string list
// static Py_ssize_t str_list_to_str_arr(
// PyObject *py_list,
// char ***arr)
// {
// // Take the size
// Py_ssize_t size = pyvar_walk_list(py_list);
// // Allocate a buffer
// char **a = (char **)qalloc((size + 1) * sizeof(char *));
// // Walk and populate
// size = pyvar_walk_list(py_list, make_str_list_cb, a);
// // Make the list NULL terminated
// a[size] = NULL;
// // Return the list to the user
// *arr = a;
// // Return the size of items processed
// return size;
// }
// //-----------------------------------------------------------------------
// typedef qvector<uint64> uint64vec_t;
// static int idaapi make_int_list(
// PyObject *py_item,
// Py_ssize_t /*index*/,
// void *ud)
// {
// uint64 val;
// if ( !PyW_GetNumber(py_item, &val) )
// return CIP_FAILED;
// uint64vec_t *vec = (uint64vec_t *)ud;
// vec->push_back(val);
// return CIP_OK;
// }
// public:
// //-----------------------------------------------------------------------
// // Frees a NULL terminated list of fields
// static void free_fields(
// const scfld_t *fields,
// void *store_area)
// {
// for ( int i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// break;
// void *store = (void *)((char *)store_area + fd.field_offs);
// int ft = fd.field_type & ~FT_VALUE_MASK;
// switch ( ft )
// {
// case FT_STR: // Simple string
// {
// char **s = (char **)store;
// if ( *s != NULL )
// {
// qfree(*s);
// *s = NULL;
// }
// }
// break;
// case FT_STRARR: // Array of strings
// {
// char ***op = (char ***)store, **p = *op;
// while ( *p != NULL )
// qfree((void *)*p++);
// qfree(*op);
// *op = NULL;
// }
// break;
// case FT_NUM16ARR:
// {
// uint16 **arr = (uint16 **)store;
// if ( *arr != NULL )
// {
// qfree(*arr);
// *arr = NULL;
// }
// }
// break;
// }
// }
// }
// //-----------------------------------------------------------------------
// // Converts from a C structure to Python
// static int from_c(
// const scfld_t *fields,
// void *read_area,
// PyObject *py_obj)
// {
// PyObject *py_attr;
// int i;
// bool ok = false;
// for ( i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// {
// ok = true;
// break;
// }
// // Point to structure member
// int ft = fd.field_type & ~FT_VALUE_MASK;
// void *read = (void *)((char *)read_area + fd.field_offs);
// // Create the python attribute properly
// if ( ft > FT_FIRST_NUM && ft < FT_LAST_NUM )
// {
// if ( ft == FT_NUM16 )
// py_attr = Py_BuildValue("H", *(uint16 *)read);
// else if ( ft == FT_NUM32 )
// py_attr = Py_BuildValue("I", *(uint32 *)read);
// else if ( ft == FT_INT )
// py_attr = Py_BuildValue("i", *(int *)read);
// else if ( ft == FT_SIZET )
// py_attr = Py_BuildValue(PY_FMT64,*(size_t *)read);
// else if ( ft == FT_SSIZET )
// py_attr = Py_BuildValue(PY_SFMT64,*(ssize_t *)read);
// }
// else if ( ft == FT_STR || ft == FT_CHAR )
// {
// if ( ft == FT_STR )
// py_attr = PyString_FromString(*(char **)read);
// else
// py_attr = Py_BuildValue("c", *(char *)read);
// }
// else if ( ft == FT_STRARR )
// {
// char **arr = *(char ***)read;
// py_attr = PyList_New(0);
// while ( *arr != NULL )
// PyList_Append(py_attr, PyString_FromString(*arr++));
// }
// else
// continue;
// PyObject_SetAttrString(py_obj, fd.field_name, py_attr);
// Py_XDECREF(py_attr);
// }
// return ok ? -1 : i;
// }
// //-----------------------------------------------------------------------
// // Converts fields from IDC and field description into a C structure
// // If 'use_extlang' is specified, then the passed idc_obj is considered
// // to be an opaque object and thus can be queried only through extlang
// static int from_script(
// const scfld_t *fields,
// void *store_area,
// PyObject *py_obj)
// {
// int i;
// bool ok = false;
// attr_t attr;
// for ( i=0; ; i++ )
// {
// // End of list?
// const scfld_t &fd = fields[i];
// if ( fd.field_name == NULL )
// {
// ok = true;
// break;
// }
// // Get field type
// int ft = fd.field_type & ~FT_VALUE_MASK;
// // Point to structure member
// void *store = (void *)((char *)store_area + fd.field_offs);
// // Retrieve attribute and type
// int cvt = get_attr(py_obj, fd.field_name, ft, attr);
// // Attribute not found?
// if ( cvt == FT_NOT_FOUND )
// {
// // Skip optional fields
// if ( fd.is_optional )
// continue;
// break;
// }
// if ( ft == FT_STR )
// *(char **)store = qstrdup(attr.str.c_str());
// else if ( ft == FT_NUM32 )
// *(uint32 *)store = uint32(attr.u64);
// else if ( ft == FT_NUM16 )
// *(uint16 *)store = attr.u64 & 0xffff;
// else if ( ft == FT_INT )
// *(int *)store = int(attr.u64);
// else if ( ft == FT_SIZET )
// *(size_t *)store = size_t(attr.u64);
// else if ( ft == FT_SSIZET )
// *(ssize_t *)store = ssize_t(attr.u64);
// else if ( ft == FT_CHAR )
// *(char *)store = *attr.str.c_str();
// else if ( ft == FT_STRARR )
// {
// str_list_to_str_arr(attr.py_obj, (char ***)store);
// Py_DECREF(attr.py_obj);
// }
// else if ( ft == FT_CHRARR_STATIC )
// {
// size_t sz = (fd.field_type & FT_VALUE_MASK) >> 16;
// if ( sz == 0 )
// break;
// uint64vec_t w;
// char *a = (char *) store;
// if ( pyvar_walk_list(attr.py_obj, make_int_list, &w) )
// {
// sz = qmin(w.size(), sz);
// for ( size_t i=0; i < sz; i++ )
// a[i] = w[i] & 0xFF;
// }
// }
// else if ( ft == FT_NUM16ARR )
// {
// uint64vec_t w;
// if ( pyvar_walk_list(attr.py_obj, make_int_list, &w) > 0 )
// {
// size_t max_sz = (fd.field_type & FT_VALUE_MASK) >> 16;
// bool zero_term;
// if ( max_sz == 0 )
// {
// zero_term = true;
// max_sz = w.size();
// }
// else
// {
// zero_term = false;
// max_sz = qmin(max_sz, w.size());
// }
// // Allocate as much as we parsed elements
// // Add one more element if list was zero terminated
// uint16 *a = (uint16 *)qalloc(sizeof(uint16) * (max_sz + (zero_term ? 1 : 0))) ;
// for ( size_t i=0; i < max_sz; i++ )
// a[i] = w[i] & 0xFF;
// if ( zero_term )
// a[max_sz] = 0;
// *(uint16 **)store = a;
// }
// }
// else
// {
// // Unsupported field type!
// break;
// }
// }
// return ok ? -1 : i;
// }
// };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
Py_ssize_t pyvar_walk_list( Py_ssize_t pyvar_walk_list(
const ref_t &py_list, const ref_t &py_list,
@ -1165,9 +908,6 @@ bool pyw_convert_idc_args(
{ {
// PyTuple_SetItem() steals the reference. // PyTuple_SetItem() steals the reference.
py_obj.incref(); py_obj.incref();
if ( cvt == CIP_OK_OPAQUE )
// We want opaque objects to still exist even when the tuple is gone.
py_obj.incref();
QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0); QASSERT(30412, PyTuple_SetItem(py_tuple.o, i, py_obj.o) == 0);
} }
else else
@ -1254,6 +994,7 @@ static const char S_ON_VIEW_DBLCLICK[] = "OnViewDblclick";
static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos"; static const char S_ON_VIEW_CURPOS[] = "OnViewCurpos";
static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched"; static const char S_ON_VIEW_SWITCHED[] = "OnViewSwitched";
static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver"; static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver";
static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved";
#ifdef __PYWRAPS__ #ifdef __PYWRAPS__
@ -2693,7 +2434,7 @@ class __IDAPython_Completion_Util(object):
return s return s
# Instantiate a completion object # Instantiate an IDAPython command completion object (for use with IDA's CLI bar)
IDAPython_Completion = __IDAPython_Completion_Util() IDAPython_Completion = __IDAPython_Completion_Util()
def _listify_types(*classes): def _listify_types(*classes):
@ -2775,6 +2516,17 @@ NW_REMOVE = 0x0010
SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t) SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t)
%{
PyObject *qstrvec2pylist(qstrvec_t &vec)
{
size_t n = vec.size();
PyObject *py_list = PyList_New(n);
for ( size_t i=0; i < n; ++i )
PyList_SetItem(py_list, i, PyString_FromString(vec[i].c_str()));
return py_list;
}
%}
%inline %{ %inline %{
//<inline(py_idaapi)> //<inline(py_idaapi)>
@ -2797,12 +2549,7 @@ static PyObject *py_parse_command_line(const char *cmdline)
qstrvec_t args; qstrvec_t args;
if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 ) if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 )
Py_RETURN_NONE; Py_RETURN_NONE;
return qstrvec2pylist(args);
PyObject *py_list = PyList_New(args.size());
for ( size_t i=0; i<args.size(); i++ )
PyList_SetItem(py_list, i, PyString_FromString(args[i].c_str()));
return py_list;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -3035,3 +2782,4 @@ static bool notify_when(int when, PyObject *py_callable)
%include "view.i" %include "view.i"
%include "graph.i" %include "graph.i"
%include "fpro.i" %include "fpro.i"
%include "registry.i"

View File

@ -53,8 +53,6 @@
t = AREACB_TYPE_SEGMENT; t = AREACB_TYPE_SEGMENT;
else if ( $self == &hidden_areas ) else if ( $self == &hidden_areas )
t = AREACB_TYPE_HIDDEN_AREA; t = AREACB_TYPE_HIDDEN_AREA;
else if ( $self == &SRareas )
t = AREACB_TYPE_SRAREA;
return t; return t;
} }
} }
@ -807,6 +805,10 @@ public:
{ {
} }
virtual void auto_empty_finally()
{
}
virtual int rename(ea_t ea, const char *new_name) virtual int rename(ea_t ea, const char *new_name)
{ {
return 0; return 0;
@ -835,6 +837,15 @@ public:
{ {
} }
virtual void auto_empty()
{
}
virtual int auto_queue_empty(atype_t type)
{
return 1; // Keep the queue empty.
}
virtual void add_func(func_t *func) virtual void add_func(func_t *func)
{ {
} }
@ -893,38 +904,38 @@ public:
return unhook_from_notification_point(HT_IDB, IDB_Callback, this); return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
} }
// Hook functions to override in Python // Hook functions to override in Python
virtual int byte_patched(ea_t /*ea*/) { return 0; }; virtual int byte_patched(ea_t /*ea*/) { return 0; }
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }; virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; }
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { 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 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_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 op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }
virtual int enum_created(enum_t /*id*/) { return 0; }; virtual int enum_created(enum_t /*id*/) { return 0; }
virtual int enum_deleted(enum_t /*id*/) { return 0; }; virtual int enum_deleted(enum_t /*id*/) { return 0; }
virtual int enum_bf_changed(enum_t /*id*/) { return 0; }; virtual int enum_bf_changed(enum_t /*id*/) { return 0; }
virtual int enum_renamed(enum_t /*id*/) { return 0; }; virtual int enum_renamed(enum_t /*id*/) { return 0; }
virtual int enum_cmt_changed(enum_t /*id*/) { return 0; }; virtual int enum_cmt_changed(enum_t /*id*/) { return 0; }
virtual int enum_member_created(enum_t /*id*/, const_t cid) { return 0; }; virtual int enum_member_created(enum_t /*id*/, const_t cid) { return 0; }
virtual int enum_member_deleted(enum_t /*id*/, const_t cid) { return 0; }; virtual int enum_member_deleted(enum_t /*id*/, const_t cid) { return 0; }
virtual int struc_created(tid_t /*struc_id*/) { return 0; }; virtual int struc_created(tid_t /*struc_id*/) { return 0; }
virtual int struc_deleted(tid_t /*struc_id*/) { return 0; }; virtual int struc_deleted(tid_t /*struc_id*/) { return 0; }
virtual int struc_renamed(struc_t * /*sptr*/) { return 0; }; virtual int struc_renamed(struc_t * /*sptr*/) { return 0; }
virtual int struc_expanded(struc_t * /*sptr*/) { return 0; }; virtual int struc_expanded(struc_t * /*sptr*/) { return 0; }
virtual int struc_cmt_changed(tid_t /*struc_id*/) { return 0; }; virtual int struc_cmt_changed(tid_t /*struc_id*/) { return 0; }
virtual int struc_member_created(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_created(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int struc_member_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { return 0; }; virtual int struc_member_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { return 0; }
virtual int struc_member_renamed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_renamed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int struc_member_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }; virtual int struc_member_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { return 0; }
virtual int thunk_func_created(func_t * /*pfn*/) { return 0; }; virtual int thunk_func_created(func_t * /*pfn*/) { return 0; }
virtual int func_tail_appended(func_t * /*pfn*/, func_t * /*tail*/) { return 0; }; virtual int func_tail_appended(func_t * /*pfn*/, func_t * /*tail*/) { return 0; }
virtual int func_tail_removed(func_t * /*pfn*/, ea_t /*tail_ea*/) { return 0; }; virtual int func_tail_removed(func_t * /*pfn*/, ea_t /*tail_ea*/) { return 0; }
virtual int tail_owner_changed(func_t * /*tail*/, ea_t /*owner_func*/) { return 0; }; virtual int tail_owner_changed(func_t * /*tail*/, ea_t /*owner_func*/) { return 0; }
virtual int func_noret_changed(func_t * /*pfn*/) { return 0; }; virtual int func_noret_changed(func_t * /*pfn*/) { return 0; }
virtual int segm_added(segment_t * /*s*/) { return 0; }; virtual int segm_added(segment_t * /*s*/) { return 0; }
virtual int segm_deleted(ea_t /*startEA*/) { return 0; }; virtual int segm_deleted(ea_t /*startEA*/) { return 0; }
virtual int segm_start_changed(segment_t * /*s*/) { return 0; }; virtual int segm_start_changed(segment_t * /*s*/) { return 0; }
virtual int segm_end_changed(segment_t * /*s*/) { return 0; }; virtual int segm_end_changed(segment_t * /*s*/) { return 0; }
virtual int segm_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }; virtual int segm_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }
}; };
//</inline(py_idp)> //</inline(py_idp)>
@ -1011,6 +1022,12 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
break; break;
} }
case processor_t::auto_empty_finally:
{
proxy->auto_empty_finally();
break;
}
case processor_t::rename: case processor_t::rename:
{ {
ea_t ea = va_arg(va, ea_t); ea_t ea = va_arg(va, ea_t);
@ -1060,6 +1077,19 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
break; break;
} }
case processor_t::auto_empty:
{
proxy->auto_empty();
break;
}
case processor_t::auto_queue_empty:
{
atype_t type = va_arg(va, atype_t);
ret = proxy->auto_queue_empty(type);
break;
}
case processor_t::add_func: case processor_t::add_func:
{ {
func_t *func = va_arg(va, func_t *); func_t *func = va_arg(va, func_t *);

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,9 @@
%ignore save_line_in_array; %ignore save_line_in_array;
%ignore init_lines_array; %ignore init_lines_array;
%ignore finish_makeline; %ignore finish_makeline;
%ignore finish_makeline_ex;
%ignore generate_many_lines_ex;
%ignore MakeNull_ex;
%ignore gen_labeled_line; %ignore gen_labeled_line;
%ignore gen_lname_line; %ignore gen_lname_line;
%ignore makeline_producer_t; %ignore makeline_producer_t;
@ -43,6 +46,7 @@
%ignore term_lines; %ignore term_lines;
%ignore gl_namedone; %ignore gl_namedone;
%ignore data_as_stack; %ignore data_as_stack;
%ignore unhide_hint_text;
%ignore calc_stack_alignment; %ignore calc_stack_alignment;
%ignore align_down_to_stack; %ignore align_down_to_stack;
%ignore align_up_to_stack; %ignore align_up_to_stack;

View File

@ -111,6 +111,7 @@
%ignore is_embedded_dbfile_ext; %ignore is_embedded_dbfile_ext;
%ignore cpp_namespaces; %ignore cpp_namespaces;
%ignore max_trusted_idb_count; %ignore max_trusted_idb_count;
%ignore no_disk_space_handler;
%ignore mem2base; %ignore mem2base;
%rename (mem2base) py_mem2base; %rename (mem2base) py_mem2base;

View File

@ -6,12 +6,120 @@
%ignore NALT_EA; %ignore NALT_EA;
%ignore enum_import_names; %ignore enum_import_names;
%rename (enum_import_names) py_enum_import_names; %rename (enum_import_names) py_enum_import_names;
%ignore get_wide_value;
%ignore set_wide_value;
%ignore del_wide_value;
%ignore get_strid;
%ignore _set_strid;
%ignore _del_strid;
%ignore set_strid;
%ignore del_strid;
%ignore xrefpos_t;
%ignore get_xrefpos;
%ignore set_xrefpos;
%ignore del_xrefpos;
%ignore set_aflags0;
%ignore get_aflags0;
%ignore del_aflags0;
%ignore get_linnum0;
%ignore set_linnum0;
%ignore del_linnum0;
%ignore get_enum_id0;
%ignore set_enum_id0;
%ignore del_enum_id0;
%ignore get_enum_id1;
%ignore set_enum_id1;
%ignore del_enum_id1;
%ignore set_ind_purged;
%ignore get_str_type;
%ignore set_str_type;
%ignore del_str_type;
%ignore _get_item_color;
%ignore _set_item_color;
%ignore _del_item_color;
%ignore get_nalt_cmt;
%ignore set_nalt_cmt;
%ignore del_nalt_cmt;
%ignore get_nalt_rptcmt;
%ignore set_nalt_rptcmt;
%ignore del_nalt_rptcmt;
%ignore get_fop1;
%ignore set_fop1;
%ignore del_fop1;
%ignore get_fop2;
%ignore set_fop2;
%ignore del_fop2;
%ignore get_fop3;
%ignore set_fop3;
%ignore del_fop3;
%ignore get_fop4;
%ignore set_fop4;
%ignore del_fop4;
%ignore get_fop5;
%ignore set_fop5;
%ignore del_fop5;
%ignore get_fop6;
%ignore set_fop6;
%ignore del_fop6;
%ignore get_manual_insn0;
%ignore set_manual_insn0;
%ignore del_manual_insn0;
%ignore get_graph_groups0;
%ignore set_graph_groups0;
%ignore del_graph_groups0;
%ignore switch_info_t;
%ignore switch_info_ex_t;
%ignore get_switch_info_ex;
%ignore set_switch_info_ex;
%ignore del_switch_info_ex;
%ignore refinfo_t::_get_target;
%ignore refinfo_t::_get_value;
%ignore refinfo_t::_get_opval;
%ignore custom_refinfo_handler_t; %ignore custom_refinfo_handler_t;
%ignore custom_refinfo_handlers_t; %ignore custom_refinfo_handlers_t;
%ignore register_custom_refinfo; %ignore register_custom_refinfo;
%ignore unregister_custom_refinfo; %ignore unregister_custom_refinfo;
%ignore get_custom_refinfos; %ignore get_custom_refinfos;
%ignore write_struc_path;
%ignore read_struc_path;
%ignore del_struc_path;
%ignore get_stroff0;
%ignore set_stroff0;
%ignore del_stroff0;
%ignore get_stroff1;
%ignore set_stroff1;
%ignore del_stroff1;
%ignore get__segtrans;
%ignore set__segtrans;
%ignore del__segtrans;
%ignore get_switch_info;
%ignore set_switch_info;
%ignore del_switch_info;
%ignore get_ti;
%ignore set_ti;
%ignore del_ti;
%ignore get_op_tinfo;
%ignore set_op_tinfo;
%ignore del_tinfo;
%ignore get_op_ti;
%ignore set_op_ti;
%ignore del_ti;
%template (ids_array) wrapped_array_t<tid_t,32>; %template (ids_array) wrapped_array_t<tid_t,32>;
%extend strpath_t { %extend strpath_t {

View File

@ -4,6 +4,7 @@
%ignore RootNode; %ignore RootNode;
%ignore for_all_supvals; %ignore for_all_supvals;
%ignore netErrorHandler; %ignore netErrorHandler;
%ignore netNoDiskSpaceHandler;
%ignore netnode_key_count; %ignore netnode_key_count;
%ignore netnode_check; %ignore netnode_check;

View File

@ -2,7 +2,7 @@
%ignore QueueGet; %ignore QueueGet;
// Kernel-only & unexported symbols // Kernel-only & unexported symbols
%ignore QueueDel; %ignore QueueDel(ea_t);
%ignore init_queue; %ignore init_queue;
%ignore save_queue; %ignore save_queue;
%ignore term_queue; %ignore term_queue;

145
swig/registry.i Normal file
View File

@ -0,0 +1,145 @@
%ignore reg_bin_op;
%ignore reg_str_op;
%ignore reg_int_op;
%ignore _RVN_;
%ignore REG_VAL_NAME;
%ignore REG_BOOL_FUNC;
%ignore REG_INT_FUNC;
%ignore MAX_HISTORY_FILES_DEF;
%ignore regkey_history;
%ignore max_history_files;
%ignore regget_history;
%ignore reg_update_history;
%ignore reg_history_size_truncate;
%ignore reg_read_string;
%rename (reg_read_string) py_reg_read_string;
%ignore reg_data_type;
%rename (reg_data_type) py_reg_data_type;
%ignore reg_read_binary;
%rename (reg_read_binary) py_reg_read_binary;
%ignore reg_write_binary;
%rename (reg_write_binary) py_reg_write_binary;
%ignore reg_read_binary_part;
/* inline bool reg_subkey_subkeys(qstrvec_t *out, const char *name) */
%ignore reg_subkey_subkeys;
%rename (reg_subkey_subkeys) py_reg_subkey_subkeys;
%ignore reg_subkey_values;
%rename (reg_subkey_values) py_reg_subkey_values;
%ignore reg_subkey_children;
%{
//<code(py_registry)>
//-------------------------------------------------------------------------
static PyObject *_py_reg_subkey_children(const char *name, bool subkeys)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
PyObject *result = NULL;
qstrvec_t children;
Py_BEGIN_ALLOW_THREADS;
if ( reg_subkey_children(&children, name, subkeys) )
{
result = PyList_New(children.size());
if ( result != NULL )
for ( size_t i = 0, n = children.size(); i < n; ++i )
PyList_SET_ITEM(result, i, PyString_FromString(children[i].c_str()));
}
Py_END_ALLOW_THREADS;
if ( result == NULL )
Py_RETURN_NONE;
else
return result;
}
//</code(py_registry)>
%}
%inline %{
//<inline(py_registry)>
//-------------------------------------------------------------------------
PyObject *py_reg_read_string(const char *name, const char *subkey = NULL, const char *def = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
char utf8[MAXSTR * 10];
bool ok;
Py_BEGIN_ALLOW_THREADS;
if ( def == NULL )
{
ok = reg_read_string(name, utf8, sizeof(utf8), subkey);
}
else
{
reg_read_string(name, sizeof(utf8), utf8, def, subkey);
ok = true;
}
Py_END_ALLOW_THREADS;
return PyString_FromString(ok ? utf8 : "");
}
//-------------------------------------------------------------------------
regval_type_t py_reg_data_type(const char *name, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
regval_type_t rt = reg_unknown;
Py_BEGIN_ALLOW_THREADS;
reg_data_type(&rt, name, subkey);
Py_END_ALLOW_THREADS;
return rt;
}
//-------------------------------------------------------------------------
PyObject *py_reg_read_binary(const char *name, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
bytevec_t bytes;
bool ok;
Py_BEGIN_ALLOW_THREADS;
ok = reg_read_binary(name, &bytes, subkey);
Py_END_ALLOW_THREADS;
if ( ok )
return PyString_FromStringAndSize((const char *) bytes.begin(), bytes.size());
else
Py_RETURN_NONE;
}
//-------------------------------------------------------------------------
void py_reg_write_binary(const char *name, PyObject *py_bytes, const char *subkey = NULL)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( PyString_Check(py_bytes) )
{
char *py_bytes_raw = NULL;
Py_ssize_t py_size = 0;
PyString_AsStringAndSize(py_bytes, &py_bytes_raw, &py_size);
bytevec_t bytes;
bytes.append(py_bytes_raw, py_size);
Py_BEGIN_ALLOW_THREADS;
reg_write_binary(name, bytes.begin(), bytes.size(), subkey);
Py_END_ALLOW_THREADS;
}
else
{
PyErr_SetString(PyExc_ValueError, "Bytes string expected!");
}
}
//-------------------------------------------------------------------------
PyObject *py_reg_subkey_subkeys(const char *name)
{
return _py_reg_subkey_children(name, true);
}
//-------------------------------------------------------------------------
PyObject *py_reg_subkey_values(const char *name)
{
return _py_reg_subkey_children(name, false);
}
//</inline(py_registry)>
%}
%include "registry.hpp"

View File

@ -1,14 +1,44 @@
// Ignore kernel-only symbols // Ignore kernel-only symbols
%ignore create_srarea;
%ignore kill_srareras;
%ignore del_srarea;
%ignore break_srarea;
%ignore set_srarea_start;
%ignore set_srarea_end;
%ignore repairSRarea; %ignore repairSRarea;
%ignore init_srarea; %ignore init_srarea;
%ignore term_srarea; %ignore term_srarea;
%ignore reset_srarea;
%ignore add_srarea_from_cache;
%ignore srareas_got_loaded;
%ignore save_srarea; %ignore save_srarea;
%ignore create_segment_registers_area;
%ignore set_segment_register_start;
%ignore set_segment_register_end;
%ignore kill_srareras;
%ignore create_srarea;
%ignore del_srareas;
%ignore move_srareas;
%ignore delete_v660_segreg_t;
%ignore v660_segreg_t;
%ignore SRareas_get_area;
%ignore SRareas_get_area_qty;
%ignore SRareas_getn_area;
%ignore SRareas_update;
%ignore SRareas_get_area_num;
%ignore SRareas_get_next_area;
%ignore SRareas_get_prev_area;
%ignore SRareas_next_area_ptr;
%ignore SRareas_prev_area_ptr;
%ignore SRareas_first_area_ptr;
%ignore SRareas_choose_area2;
%ignore SRareas_may_start_at;
%ignore SRareas_may_end_at;
%ignore SRareas_set_start;
%ignore SRareas_set_end;
%ignore SRareas_prepare_to_create;
%ignore SRareas_create_area;
%ignore SRareas_for_all_areas2;
%ignore SRareas_del_area;
%ignore segreg_t::tag(int n);
%ignore segreg_t::reg(int n);
#define R_es 29 #define R_es 29
#define R_cs 30 #define R_cs 30

View File

@ -1,3 +1,30 @@
//-------------------------------------------------------------------------
// For some reason, SWIG converts char arrays by computing the size
// from the end of the array, and stops when it encounters a '\0'.
// That doesn't work for us, as our API doesn't guarantee that
// bytes past the length we are interested in will be zeroed-out.
// In other words, the following code should *never* be present
// in idaapi_include.cpp:
// -------------------------
// while (size && (<name-of-variable>[size - 1] == '\0')) --size;
// -------------------------
//
%typemap(out) char [ANY], const char[ANY]
{
%set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0)));
}
%typemap(varout) char [ANY], const char[ANY]
{
%set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0)));
}
%typemap(out) ssize_t
{
$result = PyLong_FromLongLong($1);
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Convert an incoming Python list to a tid_t[] array // Convert an incoming Python list to a tid_t[] array
%typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) { %typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) {
@ -39,10 +66,6 @@
$1 = ($1_ltype) qalloc(MAXSTR+1); $1 = ($1_ltype) qalloc(MAXSTR+1);
} }
%typemap(out) ssize_t {
/* REMOVING ssize_t return value in $symname */
}
%typemap(argout) (TYPEMAP,SIZE) { %typemap(argout) (TYPEMAP,SIZE) {
Py_XDECREF(resultobj); Py_XDECREF(resultobj);
if (result > 0) if (result > 0)
@ -88,9 +111,6 @@
%typemap(in,numinputs=0) (TYPEMAP, SIZE) { %typemap(in,numinputs=0) (TYPEMAP, SIZE) {
$1 = (char *) qalloc(MAXSPECSIZE+1); $1 = (char *) qalloc(MAXSPECSIZE+1);
} }
%typemap(out) ssize_t {
/* REMOVING ssize_t return value in $symname */
}
%typemap(argout) (TYPEMAP,SIZE) { %typemap(argout) (TYPEMAP,SIZE) {
Py_XDECREF(resultobj); Py_XDECREF(resultobj);
if (result > 0) if (result > 0)
@ -115,9 +135,6 @@
%typemap(in,numinputs=0) (TYPEMAP, SIZE) { %typemap(in,numinputs=0) (TYPEMAP, SIZE) {
$1 = (char *) qalloc(MAXSPECSIZE+1); $1 = (char *) qalloc(MAXSPECSIZE+1);
} }
%typemap(out) ssize_t {
/* REMOVING ssize_t return value in $symname */
}
%typemap(argout) (TYPEMAP,SIZE) { %typemap(argout) (TYPEMAP,SIZE) {
Py_XDECREF(resultobj); Py_XDECREF(resultobj);
if (result) if (result)
@ -166,8 +183,6 @@
} }
$1 = $input; $1 = $input;
} }
// Convert ea_t
%typemap(in) ea_t %typemap(in) ea_t
{ {
uint64 $1_temp; uint64 $1_temp;
@ -178,6 +193,10 @@
} }
$1 = ea_t($1_temp); $1 = ea_t($1_temp);
} }
// Use PyLong_FromUnsignedLongLong, because 'long' is 4 bytes on
// windows, and thus the ea_t would be truncated at the
// PyLong_FromUnsignedLong(unsigned int) call time.
%typemap(out) ea_t "$result = PyLong_FromUnsignedLongLong($1);"
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// IN qstring // IN qstring
@ -208,6 +227,15 @@
%apply qstring { _qstring<char> } %apply qstring { _qstring<char> }
%apply qstring* { _qstring<char>* } %apply qstring* { _qstring<char>* }
//---------------------------------------------------------------------
// varargs (mostly kernwin.hpp)
//---------------------------------------------------------------------
// This is used for functions like warning(), info() and so on
%typemap(in) (const char *format, ...)
{
$1 = "%s"; /* Fix format string to %s */
$2 = (void *) PyString_AsString($input); /* Get string argument */
};
#ifdef __EA64__ #ifdef __EA64__
%apply longlong *INOUT { sval_t *value }; %apply longlong *INOUT { sval_t *value };
@ -221,6 +249,14 @@
%apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection() %apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection()
#endif #endif
%apply qstring *result { qstring *label };
%apply qstring *result { qstring *shortcut };
%apply qstring *result { qstring *tooltip };
%apply int *OUTPUT { int *icon };
%apply int *OUTPUT { action_state_t *state };
%apply bool *OUTPUT { bool *checkable };
%apply bool *OUTPUT { bool *checked };
%apply bool *OUTPUT { bool *visibility };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// The following is to be used to expose an array of items // The following is to be used to expose an array of items

View File

@ -71,7 +71,6 @@
%ignore argloc_t::dstr; %ignore argloc_t::dstr;
%ignore extract_pstr; %ignore extract_pstr;
%ignore extract_name;
%ignore skipName; %ignore skipName;
%ignore extract_comment; %ignore extract_comment;
%ignore skipComment; %ignore skipComment;
@ -180,43 +179,78 @@
%{ %{
//<code(py_typeinf)> //<code(py_typeinf)>
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// A set of tinfo_t objects that were created from IDAPython. // A set of tinfo_t & details objects that were created from IDAPython.
// This is necessary in order to clear all the "type details" that are // This is necessary in order to clear all the "type details" that are
// associated, in the kernel, with the tinfo_t instances. // associated, in the kernel, with the tinfo_t instances.
// //
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is // Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
// closed, but the "type details" must be cleared _before_ the IDB is closed. // closed, but the "type details" must be cleared _before_ the IDB is closed.
static qvector<tinfo_t*> python_tinfos; static qvector<tinfo_t*> py_tinfo_t_vec;
static qvector<ptr_type_data_t*> py_ptr_type_data_t_vec;
static qvector<array_type_data_t*> py_array_type_data_t_vec;
static qvector<func_type_data_t*> py_func_type_data_t_vec;
static qvector<udt_type_data_t*> py_udt_type_data_t_vec;
static void __clear(tinfo_t *inst) { inst->clear(); }
static void __clear(ptr_type_data_t *inst) { inst->obj_type.clear(); inst->closure.clear(); }
static void __clear(array_type_data_t *inst) { inst->elem_type.clear(); }
static void __clear(func_type_data_t *inst) { inst->clear(); inst->rettype.clear(); }
static void __clear(udt_type_data_t *inst) { inst->clear(); }
void til_clear_python_tinfo_t_instances(void) void til_clear_python_tinfo_t_instances(void)
{ {
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that // Pre-emptive strike: clear all the python-exposed tinfo_t
// were not done here, ~tinfo_t() calls happening as part of the python shutdown // (& related types) instances: if that were not done here,
// process will try and clear() their details. ..but the kernel's til-related // ~tinfo_t() calls happening as part of the python shutdown
// functions will already have deleted those details at that point. // process will try and clear() their details. ..but the kernel's
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i ) // til-related functions will already have deleted those details
python_tinfos[i]->clear(); // at that point.
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t //
// NOTE: Don't clear() the arrays of pointers. All the python-exposed
// instances will be deleted through the python shutdown/ref-decrementing // instances will be deleted through the python shutdown/ref-decrementing
// process anyway (which will cause til_deregister_..() calls), and the // process anyway (which will cause til_deregister_..() calls), and the
// entries will be properly pulled out of the vector when that happens. // entries will be properly pulled out of the vector when that happens.
#define BATCH_CLEAR(Type) \
do \
{ \
for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \
__clear(py_##Type##_vec[i]); \
} while ( false )
BATCH_CLEAR(tinfo_t);
BATCH_CLEAR(ptr_type_data_t);
BATCH_CLEAR(array_type_data_t);
BATCH_CLEAR(func_type_data_t);
BATCH_CLEAR(udt_type_data_t);
#undef BATCH_CLEAR
} }
void til_register_python_tinfo_t_instance(tinfo_t *tif) #define DEF_REG_UNREG_REFCOUNTED(Type) \
{ void til_register_python_##Type##_instance(Type *inst) \
// Let's add_unique() it, because every reference to an object's { \
// tinfo_t property will end up trying to register it. /* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \
python_tinfos.add_unique(tif); /* to an object's tinfo_t property will end up trying to register it. */ \
py_##Type##_vec.add_unique(inst); \
} \
\
void til_deregister_python_##Type##_instance(Type *inst) \
{ \
qvector<Type*>::iterator found = py_##Type##_vec.find(inst); \
if ( found != py_##Type##_vec.end() ) \
{ \
__clear(inst); \
/* tif->clear();*/ \
py_##Type##_vec.erase(found); \
} \
} }
void til_deregister_python_tinfo_t_instance(tinfo_t *tif) DEF_REG_UNREG_REFCOUNTED(tinfo_t);
{ DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t);
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif); DEF_REG_UNREG_REFCOUNTED(array_type_data_t);
if ( found != python_tinfos.end() ) DEF_REG_UNREG_REFCOUNTED(func_type_data_t);
{ DEF_REG_UNREG_REFCOUNTED(udt_type_data_t);
tif->clear();
python_tinfos.erase(found); #undef DEF_REG_UNREG_REFCOUNTED
}
}
//</code(py_typeinf)> //</code(py_typeinf)>
%} %}
@ -245,6 +279,34 @@ void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
} }
%ignore tinfo_t::~tinfo_t(void); %ignore tinfo_t::~tinfo_t(void);
//---------------------------------------------------------------------
// NOTE: This will ***NOT*** work for tinfo_t objects. Those must
// be created and owned (or not) according to the kind of access.
// To implement that, we use typemaps (see typeconv.i).
%define %simple_tinfo_t_container_lifecycle(Type, CtorSig, ParamsList)
%extend Type {
Type CtorSig
{
Type *inst = new Type ParamsList;
til_register_python_##Type##_instance(inst);
return inst;
}
~Type(void)
{
til_deregister_python_##Type##_instance($self);
delete $self;
}
}
%enddef
%simple_tinfo_t_container_lifecycle(ptr_type_data_t, (tinfo_t c=tinfo_t(), uchar bps=0), (c, bps));
%simple_tinfo_t_container_lifecycle(array_type_data_t, (size_t b=0, size_t n=0), (b, n));
%simple_tinfo_t_container_lifecycle(func_type_data_t, (), ());
%simple_tinfo_t_container_lifecycle(udt_type_data_t, (), ());
%template(funcargvec_t) qvector<funcarg_t>;
%template(udtmembervec_t) qvector<udt_member_t>;
%include "typeinf.hpp" %include "typeinf.hpp"
// Custom wrappers // Custom wrappers
@ -324,9 +386,9 @@ PyObject *py_calc_type_size(const til_t *ti, PyObject *tp)
def apply_type(ti, ea, tp_name, py_type, py_fields, flags) def apply_type(ti, ea, tp_name, py_type, py_fields, flags)
""" """
Apply the specified type to the address Apply the specified type to the address
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info library. 'idaapi.cvar.idati' can be used.
@param py_type: type string @param py_type: type string
@param py_fields: type fields @param py_fields: fields string (may be empty or None)
@param ea: the address of the object @param ea: the address of the object
@param flags: combination of TINFO_... constants or 0 @param flags: combination of TINFO_... constants or 0
@return: Boolean @return: Boolean
@ -337,17 +399,44 @@ def apply_type(ti, ea, tp_name, py_type, py_fields, flags)
static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_t ea, int flags) static bool py_apply_type(til_t *ti, PyObject *py_type, PyObject *py_fields, ea_t ea, int flags)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
} }
const type_t *type = (const type_t *) PyString_AsString(py_type); const type_t *type = (const type_t *) PyString_AsString(py_type);
const p_list *fields = (const p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
bool rc; bool rc;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
struc_t *sptr;
member_t *mptr = get_member_by_id(ea, &sptr);
if ( type[0] == '\0' )
{
if ( mptr != NULL )
{
rc = mptr->has_ti();
if ( rc )
del_member_tinfo(sptr, mptr);
}
else
{
rc = has_ti(ea);
if ( rc )
del_tinfo2(ea);
}
}
else
{
tinfo_t tif; tinfo_t tif;
rc = tif.deserialize(ti, &type, &fields, NULL) && apply_tinfo2(ea, tif, flags); rc = tif.deserialize(ti, &type, &fields, NULL);
if ( rc )
{
if ( mptr != NULL )
rc = set_member_tinfo2(sptr, mptr, 0, tif, 0);
else
rc = apply_tinfo2(ea, tif, flags);
}
}
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
return rc; return rc;
} }
@ -395,7 +484,7 @@ PyObject *py_unpack_object_from_idb(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -407,7 +496,7 @@ PyObject *py_unpack_object_from_idb(
// Unpack // Unpack
type_t *type = (type_t *) PyString_AsString(py_type); type_t *type = (type_t *) PyString_AsString(py_type);
p_list *fields = (p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
idc_value_t idc_obj; idc_value_t idc_obj;
error_t err; error_t err;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
@ -445,7 +534,7 @@ def unpack_object_from_bv(ti, tp, fields, bytes, pio_flags = 0):
Returns the error_t returned by idaapi.pack_object_to_idb Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param bytes: the bytes to unpack @param bytes: the bytes to unpack
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
@return: @return:
@ -463,7 +552,7 @@ PyObject *py_unpack_object_from_bv(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) && !PyString_Check(py_bytes) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) || !PyString_Check(py_bytes) )
{ {
PyErr_SetString(PyExc_ValueError, "Incorrect argument type!"); PyErr_SetString(PyExc_ValueError, "Incorrect argument type!");
return NULL; return NULL;
@ -475,7 +564,7 @@ PyObject *py_unpack_object_from_bv(
// Get type strings // Get type strings
type_t *type = (type_t *) PyString_AsString(py_type); type_t *type = (type_t *) PyString_AsString(py_type);
p_list *fields = (p_list *) PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Make a byte vector // Make a byte vector
bytevec_t bytes; bytevec_t bytes;
@ -519,7 +608,7 @@ def pack_object_to_idb(obj, ti, tp, fields, ea, pio_flags = 0):
Returns the error_t returned by idaapi.pack_object_to_idb Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param ea: ea to be used while packing @param ea: ea to be used while packing
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
""" """
@ -535,7 +624,7 @@ PyObject *py_pack_object_to_idb(
int pio_flags = 0) int pio_flags = 0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -553,7 +642,7 @@ PyObject *py_pack_object_to_idb(
// Get type strings // Get type strings
type_t *type = (type_t *)PyString_AsString(py_type); type_t *type = (type_t *)PyString_AsString(py_type);
p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Pack // Pack
// error_t err; // error_t err;
@ -572,7 +661,7 @@ def pack_object_to_bv(obj, ti, tp, fields, base_ea, pio_flags = 0):
Packs a typed object to a string Packs a typed object to a string
@param ti: Type info. 'idaapi.cvar.idati' can be passed. @param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string @param tp: type string
@param fields: type fields @param fields: fields string (may be empty or None)
@param base_ea: base ea used to relocate the pointers in the packed object @param base_ea: base ea used to relocate the pointers in the packed object
@param pio_flags: flags used while unpacking @param pio_flags: flags used while unpacking
@return: @return:
@ -592,7 +681,7 @@ PyObject *py_pack_object_to_bv(
int pio_flags=0) int pio_flags=0)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -610,7 +699,7 @@ PyObject *py_pack_object_to_bv(
// Get type strings // Get type strings
type_t *type = (type_t *)PyString_AsString(py_type); type_t *type = (type_t *)PyString_AsString(py_type);
p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
// Pack // Pack
relobj_t bytes; relobj_t bytes;
@ -754,7 +843,7 @@ int idc_get_local_type(int ordinal, int flags, char *buf, size_t maxsize)
PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *name, int flags) PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *name, int flags)
{ {
PYW_GIL_CHECK_LOCKED_SCOPE(); PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) ) if ( !PyString_Check(py_type) || !PyWStringOrNone_Check(py_fields) )
{ {
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!"); PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL; return NULL;
@ -766,7 +855,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam
qstring res; qstring res;
const type_t *type = (type_t *)PyString_AsString(py_type); const type_t *type = (type_t *)PyString_AsString(py_type);
const p_list *fields = (p_list *)PyString_AsString(py_fields); const p_list *fields = PyW_Fields(py_fields);
bool ok; bool ok;
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
tinfo_t tif; tinfo_t tif;

View File

@ -18,7 +18,6 @@
%ignore out_insert; %ignore out_insert;
%ignore get_immval; %ignore get_immval;
%ignore get_spoiled_reg; %ignore get_spoiled_reg;
%ignore construct_macro;
%ignore decode_preceding_insn; %ignore decode_preceding_insn;
%ignore init_ua; %ignore init_ua;
%ignore term_ua; %ignore term_ua;
@ -30,6 +29,9 @@
%ignore get_immval; %ignore get_immval;
%ignore ua_stkvar; %ignore ua_stkvar;
%ignore construct_macro;
%rename (construct_macro) py_construct_macro;
%include "ua.hpp" %include "ua.hpp"
%rename (init_output_buffer) py_init_output_buffer; %rename (init_output_buffer) py_init_output_buffer;
@ -354,6 +356,49 @@ bool py_out_name_expr(
return op == NULL ? false : out_name_expr(*op, ea, off); return op == NULL ? false : out_name_expr(*op, ea, off);
} }
//-------------------------------------------------------------------------
/*
#<pydoc>
def construct_macro(insn):
"""
See ua.hpp's construct_macro().
"""
pass
#</pydoc>
*/
bool py_construct_macro(bool enable, PyObject *build_macro)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyCallable_Check(build_macro) )
return false;
static qstack<ref_t> macro_builders;
macro_builders.push(newref_t(build_macro));
struct ida_local lambda_t
{
static bool idaapi call_build_macro(insn_t &s, bool may_go_forward)
{
PyObject *py_builder = macro_builders.top().o;
newref_t pyres = PyObject_CallFunction(
py_builder, "O",
may_go_forward ? Py_True : Py_False);
PyW_ShowCbErr("build_macro");
if ( pyres.o == NULL || pyres.o == Py_None )
return false;
insn_t *_s = insn_t_get_clink(pyres.o);
if ( _s == NULL )
return false;
s = *_s;
return true;
}
};
bool res = construct_macro(enable, lambda_t::call_build_macro);
macro_builders.pop();
return res;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i) static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
{ {
@ -913,7 +958,6 @@ op_t *op_t_get_clink(PyObject *self)
{ {
return (op_t *)pyobj_get_clink(self); return (op_t *)pyobj_get_clink(self);
} }
//</code(py_ua)> //</code(py_ua)>
%} %}
@ -1332,13 +1376,13 @@ o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
o_imm = 5 # Immediate Value value o_imm = 5 # Immediate Value value
o_far = 6 # Immediate Far Address (CODE) addr o_far = 6 # Immediate Far Address (CODE) addr
o_near = 7 # Immediate Near Address (CODE) addr o_near = 7 # Immediate Near Address (CODE) addr
o_idpspec0 = 8 # IDP specific type o_idpspec0 = 8 # Processor specific type
o_idpspec1 = 9 # IDP specific type o_idpspec1 = 9 # Processor specific type
o_idpspec2 = 10 # IDP specific type o_idpspec2 = 10 # Processor specific type
o_idpspec3 = 11 # IDP specific type o_idpspec3 = 11 # Processor specific type
o_idpspec4 = 12 # IDP specific type o_idpspec4 = 12 # Processor specific type
o_idpspec5 = 13 # IDP specific type o_idpspec5 = 13 # Processor specific type
o_last = 14 # first unused type # There can be more processor specific types
# #
# op_t.dtyp # op_t.dtyp
@ -1405,7 +1449,7 @@ class processor_t(pyidc_opaque_object_t):
short processor names similar to the one in ph.psnames. short processor names similar to the one in ph.psnames.
This method can be overridden to return to the kernel a different IDP description. This method can be overridden to return to the kernel a different IDP description.
""" """
return self.plnames[0] + ':' + ':'.join(self.psnames) return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames)))
def get_uFlag(self): def get_uFlag(self):
"""Use this utility function to retrieve the 'uFlag' global variable""" """Use this utility function to retrieve the 'uFlag' global variable"""

View File

@ -137,12 +137,16 @@ class py_customidamemo_t
GRBASE_HAVE_CLOSE = 0x080, GRBASE_HAVE_CLOSE = 0x080,
GRBASE_HAVE_VIEW_SWITCHED = 0x100, GRBASE_HAVE_VIEW_SWITCHED = 0x100,
GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200, GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200,
GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400,
}; };
static void ensure_view_callbacks_installed(); static void ensure_view_callbacks_installed();
int cb_flags; int cb_flags;
// number of arguments for OnViewClick implementation // number of arguments for:
int ovc_num_args; int ovc_num_args; // OnViewClick implementation
int ovdc_num_args; // OnViewDblclick implementation
int ovmo_num_args; // OnViewMouseOver implementation
int ovmm_num_args; // OnViewMouseMoved implementation
protected: protected:
ref_t self; ref_t self;
@ -176,11 +180,15 @@ protected:
bool collect_pyobject_callbacks(PyObject *self); bool collect_pyobject_callbacks(PyObject *self);
virtual void collect_class_callbacks_ids(callbacks_ids_t *out); virtual void collect_class_callbacks_ids(callbacks_ids_t *out);
void install_custom_viewer_handlers();
// Bi-directionally bind/unbind the Python object and this controller. // Bi-directionally bind/unbind the Python object and this controller.
bool bind(PyObject *_self, TCustomControl *view); bool bind(PyObject *_self, TCustomControl *view);
void unbind(); void unbind();
static lookup_info_t lookup_info; static lookup_info_t lookup_info;
friend TForm *pycim_get_tform(PyObject *self);
friend TCustomControl *pycim_get_tcustom_control(PyObject *self);
public: public:
py_customidamemo_t(); py_customidamemo_t();
@ -210,8 +218,16 @@ public:
void on_view_close(); void on_view_close();
void on_view_switched(tcc_renderer_type_t rt); void on_view_switched(tcc_renderer_type_t rt);
void on_view_mouse_over(const view_mouse_event_t *event); void on_view_mouse_over(const view_mouse_event_t *event);
void on_view_mouse_moved(const view_mouse_event_t *event);
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
int get_py_method_arg_count(char *method_name); int get_py_method_arg_count(char *method_name);
// View events that are bound with 'set_custom_viewer_handler()'.
static void idaapi s_on_view_mouse_moved(
TCustomControl *cv,
int shift,
view_mouse_event_t *e,
void *ud);
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -222,6 +238,9 @@ py_customidamemo_t::py_customidamemo_t()
PYGLOG("%p: py_customidamemo_t()\n", this); PYGLOG("%p: py_customidamemo_t()\n", this);
ensure_view_callbacks_installed(); ensure_view_callbacks_installed();
ovc_num_args = -1; ovc_num_args = -1;
ovdc_num_args = -1;
ovmo_num_args = -1;
ovmm_num_args = -1;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -261,7 +280,7 @@ void py_customidamemo_t::ensure_view_callbacks_installed()
py_view->on_view_keydown(key, state); py_view->on_view_keydown(key, state);
} }
break; break;
case view_popup: case obsolete_view_popup:
py_view->on_view_popup(); py_view->on_view_popup();
break; break;
case view_click: case view_click:
@ -513,6 +532,18 @@ void py_customidamemo_t::unbind()
view = NULL; view = NULL;
} }
//-------------------------------------------------------------------------
void idaapi py_customidamemo_t::s_on_view_mouse_moved(
TCustomControl *cv,
int shift,
view_mouse_event_t *e,
void *ud)
{
PYW_GIL_GET;
py_customidamemo_t *_this = (py_customidamemo_t *) ud;
_this->on_view_mouse_moved(e);
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
int py_customidamemo_t::get_py_method_arg_count(char *method_name) int py_customidamemo_t::get_py_method_arg_count(char *method_name)
{ {
@ -543,6 +574,7 @@ void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out)
out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE); out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE);
out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED); out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED);
out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER); out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER);
out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -566,9 +598,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
if ( have > 0 && attr != NULL ) if ( have > 0 && attr != NULL )
cb_flags |= have; cb_flags |= have;
} }
return true; return true;
} }
//-------------------------------------------------------------------------
void py_customidamemo_t::install_custom_viewer_handlers()
{
if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) )
{
// Set user-data
set_custom_viewer_handler(view, CVH_USERDATA, (void *)this);
//
set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved);
}
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#define CHK_EVT(flag_needed) \ #define CHK_EVT(flag_needed) \
@ -576,10 +621,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
return; \ return; \
PYW_GIL_CHECK_LOCKED_SCOPE() PYW_GIL_CHECK_LOCKED_SCOPE()
#ifdef PYGDBG_ENABLED #ifdef PYGDBG_ENABLED
#define CHK_RES() PYGLOG("%s: return code: %p\n", __FUNCTION__, result.o) #define CHK_RES() \
do \
{ \
PYGLOG("%s: return code: %p\n", __FUNCTION__, result.o); \
if (PyErr_Occurred()) \
PyErr_Print(); \
} while ( false )
#else #else
#define CHK_RES() #define CHK_RES() \
do \
{ \
if (PyErr_Occurred()) \
PyErr_Print(); \
} while ( false )
#endif #endif
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -631,13 +688,33 @@ void py_customidamemo_t::on_view_popup()
CHK_RES(); CHK_RES();
} }
//-------------------------------------------------------------------------
static PyObject *build_renderer_pos_swig_proxy(const view_mouse_event_t *event)
{
return SWIG_NewPointerObj(
SWIG_as_voidptr(&event->renderer_pos),
SWIGTYPE_p_renderer_pos_info_t,
0);
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
{ {
CHK_EVT(GRBASE_HAVE_VIEW_CLICK); CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
if ( ovc_num_args < 0 ) if ( ovc_num_args < 0 )
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
if ( ovc_num_args == 5 ) if ( ovc_num_args == 6 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iiiiO",
event->x, event->y, event->state, event->button, rpos));
CHK_RES();
}
else if ( ovc_num_args == 5 )
{ {
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
@ -645,6 +722,7 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
(char *)S_ON_VIEW_CLICK, (char *)S_ON_VIEW_CLICK,
"iiii", "iiii",
event->x, event->y, event->state, event->button)); event->x, event->y, event->state, event->button));
CHK_RES();
} }
else else
{ {
@ -654,14 +732,29 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
(char *)S_ON_VIEW_CLICK, (char *)S_ON_VIEW_CLICK,
"iii", "iii",
event->x, event->y, event->state)); event->x, event->y, event->state));
}
CHK_RES(); CHK_RES();
} }
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event) void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
{ {
CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK); CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK);
if ( ovdc_num_args < 0 )
ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK);
if ( ovdc_num_args == 5 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_DBLCLICK,
"iiiO",
event->x, event->y, event->state, rpos));
CHK_RES();
}
else
{
newref_t result( newref_t result(
PyObject_CallMethod( PyObject_CallMethod(
self.o, self.o,
@ -670,6 +763,7 @@ void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
event->x, event->y, event->state)); event->x, event->y, event->state));
CHK_RES(); CHK_RES();
} }
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_curpos() void py_customidamemo_t::on_view_curpos()
@ -700,32 +794,55 @@ void py_customidamemo_t::on_view_switched(tcc_renderer_type_t rt)
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event) static ref_t build_current_graph_item_tuple(int *out_icode, const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
if ( event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY )
{ {
const selection_item_t *item = event->location.item; const selection_item_t *item = event->location.item;
int icode;
ref_t tuple; ref_t tuple;
if ( item != NULL ) if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY)
&& item != NULL )
{ {
if ( item->is_node ) if ( item->is_node )
{ {
icode = 1; *out_icode = 1;
tuple = newref_t(Py_BuildValue("(i)", item->node)); tuple = newref_t(Py_BuildValue("(i)", item->node));
} }
else else
{ {
icode = 2; *out_icode = 2;
tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst)); tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst));
} }
} }
else else
{ {
icode = 0; *out_icode = 0;
tuple = newref_t(Py_BuildValue("()")); tuple = newref_t(Py_BuildValue("()"));
} }
return tuple;
}
//-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
if ( ovmo_num_args < 0 )
ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER);
if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY )
return;
int icode;
ref_t tuple = build_current_graph_item_tuple(&icode, event);
if ( ovmo_num_args == 7 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_MOUSE_OVER,
"iiiiOO",
event->x, event->y, event->state, icode, tuple.o, rpos));
CHK_RES();
}
else
{
newref_t result(PyObject_CallMethod( newref_t result(PyObject_CallMethod(
self.o, self.o,
(char *)S_ON_VIEW_MOUSE_OVER, (char *)S_ON_VIEW_MOUSE_OVER,
@ -735,6 +852,27 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
} }
} }
//-------------------------------------------------------------------------
void py_customidamemo_t::on_view_mouse_moved(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_MOVED);
if ( ovmm_num_args < 0 )
ovmm_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_MOVED);
int icode;
ref_t tuple = build_current_graph_item_tuple(&icode, event);
if ( ovmm_num_args == 7 )
{
PyObject *rpos = build_renderer_pos_swig_proxy(event);
newref_t result(PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_MOUSE_MOVED,
"iiiiOO",
event->x, event->y, event->state, icode, tuple.o, rpos));
CHK_RES();
}
}
#undef CHK_RES #undef CHK_RES
#undef CHK_EVT #undef CHK_EVT
@ -747,6 +885,10 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
GET_THIS(); \ GET_THIS(); \
if ( _this == NULL ) \ if ( _this == NULL ) \
return return
#define CHK_THIS_OR_NULL() \
GET_THIS(); \
if ( _this == NULL ) \
return NULL;
#define CHK_THIS_OR_NONE() \ #define CHK_THIS_OR_NONE() \
GET_THIS(); \ GET_THIS(); \
if ( _this == NULL ) \ if ( _this == NULL ) \
@ -828,7 +970,28 @@ PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject
return _this->set_groups_visibility(groups, expand, new_current); return _this->set_groups_visibility(groups, expand, new_current);
} }
//-------------------------------------------------------------------------
TForm *pycim_get_tform(PyObject *self)
{
CHK_THIS_OR_NULL();
TForm *form = NULL;
if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) )
return NULL;
return form;
}
//-------------------------------------------------------------------------
TCustomControl *pycim_get_tcustom_control(PyObject *self)
{
CHK_THIS_OR_NULL();
TCustomControl *tcc = NULL;
if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) )
return NULL;
return tcc;
}
#undef CHK_THIS_OR_NONE #undef CHK_THIS_OR_NONE
#undef CHK_THIS_OR_NULL
#undef CHK_THIS #undef CHK_THIS
#undef GET_THIS #undef GET_THIS
@ -850,6 +1013,8 @@ void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt);
PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos); PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos);
PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current); PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current);
PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current); PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current);
TForm *pycim_get_tform(PyObject *self);
TCustomControl *pycim_get_tcustom_control(PyObject *self);
//</inline(py_view_base)> //</inline(py_view_base)>
%} %}
@ -959,6 +1124,23 @@ class CustomIDAMemo(object):
""" """
return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current) return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current)
def GetTForm(self):
"""
Return the TForm hosting this view.
@return: The TForm that hosts this view, or None.
"""
return _idaapi.pycim_get_tform(self)
def GetTCustomControl(self):
"""
Return the TCustomControl underlying this view.
@return: The TCustomControl underlying this view, or None.
"""
return _idaapi.pycim_get_tcustom_control(self)
#</pycode(py_view_base)> #</pycode(py_view_base)>
%} %}
@ -970,6 +1152,7 @@ class py_idaview_t : public py_customidamemo_t
public: public:
static bool Bind(PyObject *self); static bool Bind(PyObject *self);
static bool Unbind(PyObject *self);
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -1015,24 +1198,43 @@ bool py_idaview_t::Bind(PyObject *self)
if ( ok ) if ( ok )
{ {
ok = py_view->collect_pyobject_callbacks(self); ok = py_view->collect_pyobject_callbacks(self);
if ( !ok ) if ( ok )
py_view->install_custom_viewer_handlers();
else
delete py_view; delete py_view;
} }
return ok; return ok;
} }
//-------------------------------------------------------------------------
bool py_idaview_t::Unbind(PyObject *self)
{
py_idaview_t *_this = view_extract_this<py_idaview_t>(self);
if ( _this == NULL )
return false;
_this->unbind();
return true;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
bool pyidag_bind(PyObject *self) bool pyidag_bind(PyObject *self)
{ {
return py_idaview_t::Bind(self); return py_idaview_t::Bind(self);
} }
//-------------------------------------------------------------------------
bool pyidag_unbind(PyObject *self)
{
return py_idaview_t::Unbind(self);
}
//</code(py_idaview)> //</code(py_idaview)>
%} %}
%inline %{ %inline %{
//<inline(py_idaview)> //<inline(py_idaview)>
bool pyidag_bind(PyObject *self); bool pyidag_bind(PyObject *self);
bool pyidag_unbind(PyObject *self);
//</inline(py_idaview)> //</inline(py_idaview)>
%} %}
@ -1051,5 +1253,9 @@ class IDAViewWrapper(CustomIDAMemo):
def Bind(self): def Bind(self):
return _idaapi.pyidag_bind(self) return _idaapi.pyidag_bind(self)
def Unbind(self):
return _idaapi.pyidag_unbind(self)
#</pycode(py_idaview)> #</pycode(py_idaview)>
%} %}