mirror of
https://github.com/cemu-project/idapython.git
synced 2024-11-24 01:59:18 +01:00
IDA Pro 6.7 support
This commit is contained in:
parent
49dcdc5ed3
commit
bbf628d3a3
@ -16,8 +16,10 @@ REQUIREMENTS
|
||||
- Python [2.5.1, 2.6.1, 2.7]
|
||||
http://www.python.org/
|
||||
|
||||
- Simplified Wrapper Interface Generator (SWIG) [2.0]
|
||||
- Simplified Wrapper Interface Generator (SWIG) [2.0.12]
|
||||
http://www.swig.org/
|
||||
Hex-Rays cannot guarantee support for IDAPython
|
||||
versions built with other versions of SWIG.
|
||||
|
||||
- Unix utilities (GNU patch on Windows):
|
||||
http://www.research.att.com/sw/tools/uwin/ or
|
||||
|
21
build.py
21
build.py
@ -24,19 +24,23 @@ from distutils import sysconfig
|
||||
VERBOSE = True
|
||||
|
||||
IDA_MAJOR_VERSION = 6
|
||||
IDA_MINOR_VERSION = 6
|
||||
IDA_MINOR_VERSION = 7
|
||||
|
||||
if 'IDA' in os.environ:
|
||||
IDA_SDK = os.environ['IDA']
|
||||
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)))
|
||||
assert os.path.exists(IDA_SDK), "Could not find IDA SDK include path"
|
||||
|
||||
|
||||
# End of user configurable options
|
||||
|
||||
# IDAPython version
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 7
|
||||
VERSION_PATCH = 0
|
||||
VERSION_PATCH = 1
|
||||
|
||||
# Determine Python version
|
||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||
@ -89,7 +93,7 @@ BINDIST_MANIFEST = [
|
||||
"examples/structure.py",
|
||||
"examples/ex_gdl_qflow_chart.py",
|
||||
"examples/ex_strings.py",
|
||||
"examples/ex_add_menu_item.py",
|
||||
"examples/ex_actions.py",
|
||||
"examples/ex_func_chooser.py",
|
||||
"examples/ex_choose2.py",
|
||||
"examples/ex_debug_names.py",
|
||||
@ -157,7 +161,6 @@ SRCDIST_MANIFEST = [
|
||||
"swig/graph.i",
|
||||
"swig/fpro.i",
|
||||
"swig/hexrays.i",
|
||||
"tools/gendocs.py",
|
||||
]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
@ -396,7 +399,8 @@ def build_plugin(
|
||||
platform_macros.append("WITH_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:
|
||||
platform_macros.append("PLUGINFIX")
|
||||
@ -411,6 +415,13 @@ def build_plugin(
|
||||
res = os.system(swigcmd)
|
||||
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
|
||||
res = builder.compile("idaapi",
|
||||
includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ],
|
||||
|
119
examples/ex_actions.py
Normal file
119
examples/ex_actions.py
Normal 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
|
@ -344,7 +344,7 @@ Dropdown list test
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def test_dropdown(execute=True):
|
||||
"""Test the combobox controls"""
|
||||
"""Test the combobox controls, in a modal dialog"""
|
||||
f = MyForm3()
|
||||
f, args = f.Compile()
|
||||
if execute:
|
||||
@ -360,6 +360,18 @@ def test_dropdown(execute=True):
|
||||
|
||||
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)>
|
||||
|
||||
|
||||
|
@ -1,16 +1,42 @@
|
||||
import idaapi
|
||||
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):
|
||||
|
||||
def __init__(self, title, nb = 5, deflt=1):
|
||||
Choose2.__init__(self, title, [ ["Address", 10], ["Name", 30] ])
|
||||
def __init__(self, title, nb = 5, flags=0, width=None, height=None, embedded=False, modal=False):
|
||||
Choose2.__init__(
|
||||
self,
|
||||
title,
|
||||
[ ["Address", 10], ["Name", 30] ],
|
||||
flags = flags,
|
||||
width = width,
|
||||
height = height,
|
||||
embedded = embedded)
|
||||
self.n = 0
|
||||
self.items = [ self.make_item() for x in xrange(0, nb+1) ]
|
||||
self.icon = 5
|
||||
self.selcount = 0
|
||||
self.deflt = deflt
|
||||
self.modal = modal
|
||||
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
|
||||
|
||||
print("created %s" % str(self))
|
||||
|
||||
def OnClose(self):
|
||||
@ -46,15 +72,6 @@ class MyChoose2(Choose2):
|
||||
print("refresh %d" % 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):
|
||||
r = self.items[n]
|
||||
t = self.icon + r[1].count("*")
|
||||
@ -62,12 +79,7 @@ class MyChoose2(Choose2):
|
||||
return t
|
||||
|
||||
def show(self):
|
||||
t = self.Show()
|
||||
if t < 0:
|
||||
return False
|
||||
self.cmd_a = self.AddCommand("command A")
|
||||
self.cmd_b = self.AddCommand("command B")
|
||||
return True
|
||||
return self.Show(self.modal) >= 0
|
||||
|
||||
def make_item(self):
|
||||
r = [str(self.n), "func_%04d" % self.n]
|
||||
@ -79,7 +91,43 @@ class MyChoose2(Choose2):
|
||||
if n == 1:
|
||||
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()
|
||||
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)>
|
||||
|
@ -7,6 +7,18 @@ import idc
|
||||
from idaapi import simplecustviewer_t
|
||||
#<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):
|
||||
def Create(self, sn=None):
|
||||
@ -18,8 +30,6 @@ class mycv_t(simplecustviewer_t):
|
||||
# Create the customviewer
|
||||
if not simplecustviewer_t.Create(self, title):
|
||||
return False
|
||||
self.menu_hello = self.AddPopupMenu("Hello")
|
||||
self.menu_world = self.AddPopupMenu("World")
|
||||
|
||||
for i in xrange(0, 100):
|
||||
self.AddLine("Line %d" % i)
|
||||
@ -120,13 +130,6 @@ class mycv_t(simplecustviewer_t):
|
||||
return False
|
||||
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):
|
||||
"""
|
||||
Hint requested for the given line number.
|
||||
@ -137,22 +140,6 @@ class mycv_t(simplecustviewer_t):
|
||||
"""
|
||||
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:
|
||||
# created already?
|
||||
@ -169,7 +156,16 @@ def show_win():
|
||||
print "Failed to create!"
|
||||
return None
|
||||
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
|
||||
|
||||
mycv = show_win()
|
||||
if not mycv:
|
||||
del mycv
|
||||
|
@ -3,11 +3,24 @@
|
||||
# in Python
|
||||
# (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):
|
||||
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.result = result
|
||||
|
||||
@ -23,25 +36,15 @@ class MyGraph(GraphViewer):
|
||||
def OnGetText(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):
|
||||
if not GraphViewer.Show(self):
|
||||
return False
|
||||
self.cmd_close = self.AddCommand("Close", "F2")
|
||||
if self.cmd_close == 0:
|
||||
print "Failed to add popup menu item!"
|
||||
actname = "graph_closer:%s" % self.title
|
||||
register_action(action_desc_t(actname, "Close %s" % self.title, GraphCloser(self)))
|
||||
attach_action_to_popup(self.GetTCustomControl(), None, actname)
|
||||
return True
|
||||
|
||||
|
||||
def show_graph():
|
||||
f = idaapi.get_func(here())
|
||||
if not f:
|
||||
|
@ -16,10 +16,28 @@ import idautils
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
import traceback
|
||||
|
||||
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):
|
||||
|
||||
def __init__(self):
|
||||
@ -123,14 +141,12 @@ class hexrays_callback_info(object):
|
||||
def invert_if_event(self, vu):
|
||||
|
||||
cfunc = vu.cfunc.__deref__()
|
||||
|
||||
i = self.find_if_statement(vu)
|
||||
if not i:
|
||||
return False
|
||||
|
||||
if self.invert_if(cfunc, i):
|
||||
vu.refresh_ctext()
|
||||
|
||||
self.add_location(i.ea)
|
||||
|
||||
return True
|
||||
@ -157,39 +173,27 @@ class hexrays_callback_info(object):
|
||||
|
||||
return
|
||||
|
||||
def menu_callback(self):
|
||||
try:
|
||||
self.invert_if_event(self.vu)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return 0
|
||||
|
||||
def event_callback(self, event, *args):
|
||||
|
||||
try:
|
||||
if event == idaapi.hxe_keyboard:
|
||||
vu, keycode, shift = args
|
||||
|
||||
if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("I") and shift == 0:
|
||||
if self.invert_if_event(vu):
|
||||
return 1
|
||||
|
||||
elif event == idaapi.hxe_right_click:
|
||||
self.vu, = args
|
||||
idaapi.add_custom_viewer_popup_item(self.vu.ct, "Invert then/else", "I", self.menu_callback)
|
||||
if event == idaapi.hxe_populating_popup:
|
||||
form, phandle, vu = args
|
||||
res = idaapi.attach_action_to_popup(vu.ct, None, inverter_actname)
|
||||
|
||||
elif event == idaapi.hxe_maturity:
|
||||
cfunc, maturity = args
|
||||
|
||||
if maturity == idaapi.CMAT_FINAL:
|
||||
self.restore(cfunc)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
return 0
|
||||
|
||||
if idaapi.init_hexrays_plugin():
|
||||
i = hexrays_callback_info()
|
||||
idaapi.register_action(
|
||||
idaapi.action_desc_t(
|
||||
inverter_actname,
|
||||
"Invert then/else",
|
||||
invert_action_handler_t(i),
|
||||
"I"))
|
||||
idaapi.install_hexrays_callback(i.event_callback)
|
||||
else:
|
||||
print 'invert-if: hexrays is not available.'
|
||||
|
@ -221,7 +221,10 @@ class XrefsForm(idaapi.PluginForm):
|
||||
addresses.append(parent.ea)
|
||||
|
||||
self.functions.append(cfunc.entry_ea)
|
||||
self.items.append((parent.ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, int(parent.ea))))
|
||||
self.items.append((
|
||||
parent.ea,
|
||||
idc.GetFunctionName(cfunc.entry_ea),
|
||||
self.get_decompiled_line(cfunc, parent.ea)))
|
||||
|
||||
|
||||
return []
|
||||
@ -260,57 +263,62 @@ class XrefsForm(idaapi.PluginForm):
|
||||
def OnClose(self, form):
|
||||
pass
|
||||
|
||||
class hexrays_callback_info(object):
|
||||
|
||||
class show_xrefs_ah_t(idaapi.action_handler_t):
|
||||
def __init__(self):
|
||||
self.vu = None
|
||||
return
|
||||
idaapi.action_handler_t.__init__(self)
|
||||
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)
|
||||
item = vu.item
|
||||
|
||||
sel = None
|
||||
self.sel = None
|
||||
if item.citype == idaapi.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'):
|
||||
# if an expression is selected. verify that it's either a cot_obj, cot_memref or cot_memptr
|
||||
sel = item.it.to_specific_type
|
||||
self.sel = item.it.to_specific_type
|
||||
|
||||
elif item.citype == idaapi.VDI_FUNC:
|
||||
# if the function itself is selected, show xrefs to it.
|
||||
sel = item.f
|
||||
else:
|
||||
return False
|
||||
self.sel = item.f
|
||||
|
||||
form = XrefsForm(sel)
|
||||
form.Show()
|
||||
return True
|
||||
return idaapi.AST_ENABLE if self.sel else idaapi.AST_DISABLE
|
||||
|
||||
def menu_callback(self):
|
||||
self.show_xrefs(self.vu)
|
||||
return 0
|
||||
class hexrays_callback_info(object):
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
def event_callback(self, event, *args):
|
||||
|
||||
try:
|
||||
if event == idaapi.hxe_keyboard:
|
||||
vu, keycode, shift = args
|
||||
|
||||
if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("X") and shift == 0:
|
||||
if self.show_xrefs(vu):
|
||||
return 1
|
||||
|
||||
elif event == idaapi.hxe_right_click:
|
||||
self.vu = args[0]
|
||||
idaapi.add_custom_viewer_popup_item(self.vu.ct, "Xrefs", "X", self.menu_callback)
|
||||
|
||||
if event == idaapi.hxe_populating_popup:
|
||||
form, phandle, vu = args
|
||||
idaapi.attach_action_to_popup(form, phandle, "vdsxrefs:show", None)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
return 0
|
||||
|
||||
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()
|
||||
idaapi.install_hexrays_callback(i.event_callback)
|
||||
else:
|
||||
print "Couldn't register action."
|
||||
else:
|
||||
print 'invert-if: hexrays is not available.'
|
||||
print 'hexrays is not available.'
|
||||
|
148
hrdoc.cfg
Normal file
148
hrdoc.cfg
Normal 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
334
hrdoc.css
Normal 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
116
hrdoc.py
Normal 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
4
idaapi.i
Normal 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
340
inject_pydoc.py
Normal 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
57
patch_directors_cc.py
Normal 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)
|
81
python.cpp
81
python.cpp
@ -287,11 +287,29 @@ static void PythonEvalOrExec(
|
||||
PyErr_Print();
|
||||
}
|
||||
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;
|
||||
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());
|
||||
}
|
||||
|
||||
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
|
||||
// calling it.
|
||||
char curdir[QMAXPATH];
|
||||
if ( _getcwd(curdir, sizeof(curdir)) == NULL
|
||||
|| getdspace(curdir) == 0 )
|
||||
// check if the current directory is accessible. if not, qgetcwd won't return
|
||||
qgetcwd(curdir, sizeof(curdir));
|
||||
if ( getdspace(curdir) == 0 )
|
||||
{
|
||||
warning("No free disk space on %s, python will not be available", curdir);
|
||||
return 0;
|
||||
@ -428,7 +447,7 @@ static int PyRunFile(const char *FileName)
|
||||
#endif
|
||||
|
||||
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();
|
||||
if ( globals == NULL || file_obj == NULL )
|
||||
{
|
||||
@ -703,6 +722,18 @@ bool idaapi IDAPython_extlang_run(
|
||||
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
|
||||
bool idaapi IDAPython_extlang_compile(
|
||||
@ -722,11 +753,9 @@ bool idaapi IDAPython_extlang_compile(
|
||||
// try compiling as a list of statements
|
||||
// wrap them into a function
|
||||
handle_python_error(errbuf, errbufsize);
|
||||
qstring expr_copy = expr;
|
||||
expr_copy.replace("\n", "\n ");
|
||||
qstring qexpr;
|
||||
qexpr.sprnt("def %s():\n %s", name, expr_copy.c_str());
|
||||
code = (PyCodeObject *)Py_CompileString(qexpr.c_str(), "<string>", Py_file_input);
|
||||
qstring func;
|
||||
wrap_in_function(&func, expr, name);
|
||||
code = (PyCodeObject *)Py_CompileString(func.c_str(), "<string>", Py_file_input);
|
||||
if ( code == NULL )
|
||||
{
|
||||
handle_python_error(errbuf, errbufsize);
|
||||
@ -1200,7 +1229,7 @@ bool idaapi IDAPYthon_cli_complete_line(
|
||||
if ( py_complete == NULL )
|
||||
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
|
||||
PyW_GetError(completion);
|
||||
@ -1294,7 +1323,24 @@ void convert_idc_args()
|
||||
PyObject_SetAttrString(py_mod.o, S_IDC_ARGS_VARNAME, py_args.o);
|
||||
}
|
||||
|
||||
#ifdef WITH_HEXRAYS
|
||||
//-------------------------------------------------------------------------
|
||||
static bool is_hexrays_plugin(const plugin_info_t *pinfo)
|
||||
{
|
||||
bool is_hx = false;
|
||||
if ( pinfo != NULL && pinfo->entry != NULL )
|
||||
{
|
||||
const plugin_t *p = pinfo->entry;
|
||||
if ( streq(p->wanted_name, "Hex-Rays Decompiler") )
|
||||
is_hx = true;
|
||||
}
|
||||
return is_hx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//lint -esym(715,va) Symbol not referenced
|
||||
static int idaapi on_ui_notification(void *, int code, va_list va)
|
||||
{
|
||||
#ifdef WITH_HEXRAYS
|
||||
@ -1323,16 +1369,10 @@ static int idaapi on_ui_notification(void *, int code, va_list va)
|
||||
break;
|
||||
|
||||
#ifdef WITH_HEXRAYS
|
||||
// FIXME: HACK! THERE SHOULD BE A UI (or IDB?) NOTIFICATION
|
||||
// WHEN A PLUGIN GETS [UN]LOADED!
|
||||
// In the meantime, we're checking to see whether the Hex-Rays
|
||||
// plugin gets loaded/pulled away.
|
||||
case ui_add_menu_item:
|
||||
case ui_plugin_loaded:
|
||||
if ( hexdsp == NULL )
|
||||
{
|
||||
(void)va_arg(va, char *); // Drop 'menupath'
|
||||
const char *name = va_arg(va, char *); // Look for 'name'.
|
||||
if ( streq(name, "Jump to pseudocode") )
|
||||
if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
|
||||
{
|
||||
init_hexrays_plugin(0);
|
||||
if ( hexdsp != NULL )
|
||||
@ -1341,14 +1381,13 @@ static int idaapi on_ui_notification(void *, int code, va_list va)
|
||||
}
|
||||
break;
|
||||
|
||||
case ui_del_menu_item:
|
||||
case ui_plugin_unloading:
|
||||
{
|
||||
if ( hexdsp != NULL )
|
||||
{
|
||||
// Hex-Rays will close. Make sure all the refcounted cfunc_t objects
|
||||
// are cleared right away.
|
||||
const char *menupath = va_arg(va, char *);
|
||||
if ( streq(menupath, "Jump/Jump to pseudocode") )
|
||||
if ( is_hexrays_plugin(va_arg(va, plugin_info_t *)) )
|
||||
{
|
||||
hexrays_clear_python_cfuncptr_t_references();
|
||||
hexdsp = NULL;
|
||||
|
@ -374,8 +374,8 @@ def DecodePreviousInstruction(ea):
|
||||
@param ea: address to decode
|
||||
@return: None or a new insn_t instance
|
||||
"""
|
||||
inslen = idaapi.decode_prev_insn(ea)
|
||||
if inslen == 0:
|
||||
prev_addr = idaapi.decode_prev_insn(ea)
|
||||
if prev_addr == idaapi.BADADDR:
|
||||
return None
|
||||
|
||||
return idaapi.cmd.copy()
|
||||
@ -462,7 +462,8 @@ def GetInputFileMD5():
|
||||
|
||||
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:
|
||||
s = Strings()
|
||||
@ -483,8 +484,34 @@ class Strings(object):
|
||||
self.length = si.length
|
||||
"""string length"""
|
||||
|
||||
def is_1_byte_encoding(self):
|
||||
return not self.is_2_bytes_encoding() and not self.is_4_bytes_encoding()
|
||||
|
||||
def is_2_bytes_encoding(self):
|
||||
return (self.type & 7) in [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):
|
||||
return idc.GetString(self.ea, self.length, self.type)
|
||||
return self._toseq(False)
|
||||
|
||||
def __unicode__(self):
|
||||
return self._toseq(True)
|
||||
|
||||
|
||||
STR_C = 0x0001
|
||||
"""C-style ASCII string"""
|
||||
@ -505,8 +532,7 @@ class Strings(object):
|
||||
"""Clears the strings list cache"""
|
||||
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
|
||||
|
||||
|
||||
def __init__(self, default_setup = True):
|
||||
def __init__(self, default_setup = False):
|
||||
"""
|
||||
Initializes the Strings enumeration helper class
|
||||
|
||||
@ -515,10 +541,11 @@ class Strings(object):
|
||||
self.size = 0
|
||||
if default_setup:
|
||||
self.setup()
|
||||
else:
|
||||
self.refresh()
|
||||
|
||||
self._si = idaapi.string_info_t()
|
||||
|
||||
|
||||
def refresh(self, ea1=None, ea2=None):
|
||||
"""Refreshes the strings list"""
|
||||
if ea1 is None:
|
||||
@ -750,14 +777,6 @@ def ProcessUiActions(actions, flags=0):
|
||||
helper = __process_ui_actions_helper(actions, flags)
|
||||
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):
|
||||
|
@ -1450,7 +1450,11 @@ def PatchByte(ea, value):
|
||||
@param ea: linear address
|
||||
@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)
|
||||
|
||||
@ -1462,7 +1466,11 @@ def PatchWord(ea, value):
|
||||
@param ea: linear address
|
||||
@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)
|
||||
|
||||
@ -1474,11 +1482,31 @@ def PatchDword(ea, value):
|
||||
@param ea: linear address
|
||||
@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)
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
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_far = idaapi.o_far # Immediate Far Address (CODE) addr
|
||||
o_near = idaapi.o_near # Immediate Near Address (CODE) addr
|
||||
o_idpspec0 = idaapi.o_idpspec0 # IDP specific type
|
||||
o_idpspec1 = idaapi.o_idpspec1 # IDP specific type
|
||||
o_idpspec2 = idaapi.o_idpspec2 # IDP specific type
|
||||
o_idpspec3 = idaapi.o_idpspec3 # IDP specific type
|
||||
o_idpspec4 = idaapi.o_idpspec4 # IDP specific type
|
||||
o_idpspec5 = idaapi.o_idpspec5 # IDP specific type
|
||||
o_last = idaapi.o_last # first unused type
|
||||
o_idpspec0 = idaapi.o_idpspec0 # Processor specific type
|
||||
o_idpspec1 = idaapi.o_idpspec1 # Processor specific type
|
||||
o_idpspec2 = idaapi.o_idpspec2 # Processor specific type
|
||||
o_idpspec3 = idaapi.o_idpspec3 # Processor specific type
|
||||
o_idpspec4 = idaapi.o_idpspec4 # Processor specific type
|
||||
o_idpspec5 = idaapi.o_idpspec5 # Processor specific type
|
||||
# There can be more processor specific types
|
||||
|
||||
# x86
|
||||
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_creglist = idaapi.o_idpspec2 # Coprocessor register list (for CDP)
|
||||
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_text = (idaapi.o_idpspec5+1) # Arbitrary text stored in the operand
|
||||
|
||||
@ -3116,6 +3144,20 @@ def Message(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):
|
||||
"""
|
||||
Display a message in a message box
|
||||
@ -6917,16 +6959,16 @@ def ApplyType(ea, py_type, flags = TINFO_DEFINITE):
|
||||
@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:
|
||||
pt = py_type[1:] # skip name component
|
||||
else:
|
||||
pt = py_type
|
||||
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):
|
||||
"""
|
||||
@ -6941,7 +6983,7 @@ def SetType(ea, newtype):
|
||||
@return: 1-ok, 0-failed.
|
||||
"""
|
||||
if newtype is not '':
|
||||
pt = ParseType(newtype, 0)
|
||||
pt = ParseType(newtype, 1) # silent
|
||||
if pt is None:
|
||||
# parsing failed
|
||||
return None
|
||||
|
@ -28,9 +28,8 @@ class IDAPythonStdOut:
|
||||
Dummy file-like class that receives stout and stderr
|
||||
"""
|
||||
def write(self, text):
|
||||
# Swap out the unprintable characters
|
||||
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
|
||||
# Print to IDA message window
|
||||
# NB: in case 'text' is Unicode, msg() will decode it
|
||||
# and call umsg() to print it
|
||||
_idaapi.msg(text)
|
||||
|
||||
def flush(self):
|
||||
|
54
pywraps.hpp
54
pywraps.hpp
@ -93,6 +93,18 @@ public:
|
||||
} 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
|
||||
insn_t *insn_t_get_clink(PyObject *self);
|
||||
@ -125,25 +137,38 @@ struct ref_t
|
||||
~ref_t() { decref(); }
|
||||
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;
|
||||
incref();
|
||||
if ( was != NULL )
|
||||
Py_DECREF(was);
|
||||
return *this;
|
||||
}
|
||||
|
||||
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 ! ((*this) == other); }
|
||||
|
||||
bool operator==(const ref_t &other) const { return o == other.o; }
|
||||
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
|
||||
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()
|
||||
|
@ -1,2 +1,2 @@
|
||||
@echo off
|
||||
c:\python27\python.exe deploy_all.py
|
||||
deploy_all.py
|
||||
|
@ -143,6 +143,12 @@ deploys = {
|
||||
"tgt" : "../swig/lines.i"
|
||||
},
|
||||
|
||||
"registry" : {
|
||||
"tag" : "py_registry",
|
||||
"src" : ["py_registry.hpp"],
|
||||
"tgt" : "../swig/registry.i"
|
||||
},
|
||||
|
||||
"pc_win32_appcall" : {
|
||||
"tag" : "appcalltest",
|
||||
"src" : ["py_appcall.py"],
|
||||
@ -155,6 +161,12 @@ deploys = {
|
||||
"tgt" : "../../../tests/input/pc_win32_custdata1.pe.hints"
|
||||
},
|
||||
|
||||
"ex_choose2" : {
|
||||
"tag" : "py_choose2ex1",
|
||||
"src" : ["py_choose2.py"],
|
||||
"tgt" : "../examples/ex_choose2.py"
|
||||
},
|
||||
|
||||
"ex_formchooser" : {
|
||||
"tag" : "ex_formchooser",
|
||||
"src" : ["py_askusingform.py"],
|
||||
|
@ -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;
|
||||
fa->close(close_normally);
|
||||
@ -362,6 +362,12 @@ static size_t py_get_AskUsingForm()
|
||||
return (size_t)AskUsingForm_c;
|
||||
}
|
||||
|
||||
static size_t py_get_OpenForm()
|
||||
{
|
||||
// See comments above.
|
||||
return (size_t)OpenForm_c;
|
||||
}
|
||||
|
||||
//</inline(py_kernwin)>
|
||||
|
||||
#endif // __PY_ASKUSINGFORM__
|
@ -29,6 +29,7 @@ try:
|
||||
_idaapi.CHOOSER_POPUP_MENU = 1
|
||||
pywraps = object_t()
|
||||
pywraps.py_get_AskUsingForm = lambda: 0
|
||||
pywraps.py_get_OpenForm = lambda: 0
|
||||
|
||||
class Choose2(object):
|
||||
CH_MULTI = 1
|
||||
@ -891,7 +892,7 @@ class Form(object):
|
||||
def __init__(self, form, controls):
|
||||
"""
|
||||
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
|
||||
defined and instantiated via various form controls (subclasses of Form).
|
||||
|
||||
@ -908,6 +909,15 @@ class Form(object):
|
||||
self.title = None
|
||||
"""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):
|
||||
"""
|
||||
@ -1039,6 +1049,11 @@ class Form(object):
|
||||
"""
|
||||
# First argument is the form string
|
||||
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
|
||||
|
||||
# Reset all group control internal flags
|
||||
@ -1121,6 +1136,22 @@ class Form(object):
|
||||
|
||||
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
|
||||
args[0] = form
|
||||
|
||||
@ -1157,18 +1188,34 @@ class Form(object):
|
||||
return self.__args is not None
|
||||
|
||||
|
||||
def Execute(self):
|
||||
"""
|
||||
Displays a compiled form.
|
||||
@return: 1 - ok ; 0 - cancel
|
||||
"""
|
||||
def _ChkCompiled(self):
|
||||
if not self.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)
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
Enable or disable an input field
|
||||
@ -1311,15 +1358,18 @@ try:
|
||||
# Setup the numeric argument size
|
||||
Form.NumericArgument.DefI64 = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
|
||||
AskUsingForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_AskUsingForm())
|
||||
OpenForm__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_OpenForm())
|
||||
except:
|
||||
def AskUsingForm__(*args):
|
||||
warning("AskUsingForm() needs ctypes library in order to work")
|
||||
return 0
|
||||
def OpenForm__(*args):
|
||||
warning("OpenForm() needs ctypes library in order to work")
|
||||
|
||||
|
||||
def AskUsingForm(*args):
|
||||
"""
|
||||
Calls the AskUsingForm()
|
||||
Calls AskUsingForm()
|
||||
@param: Compiled Arguments obtain through the Form.Compile() function
|
||||
@return: 1 = ok, 0 = cancel
|
||||
"""
|
||||
@ -1328,6 +1378,15 @@ def AskUsingForm(*args):
|
||||
set_script_timeout(old)
|
||||
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)>
|
||||
|
||||
@ -1671,7 +1730,7 @@ Dropdown list test
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def test_dropdown(execute=True):
|
||||
"""Test the combobox controls"""
|
||||
"""Test the combobox controls, in a modal dialog"""
|
||||
f = MyForm3()
|
||||
f, args = f.Compile()
|
||||
if execute:
|
||||
@ -1687,6 +1746,18 @@ def test_dropdown(execute=True):
|
||||
|
||||
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)>
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
@ -153,15 +153,21 @@ ACFOPT_ESCAPE = 0x00000010 # for ACFOPT_ASCII, convert non-printable
|
||||
|
||||
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
|
||||
"""
|
||||
Get contents of ascii string
|
||||
This function returns the displayed part of the string
|
||||
Get bytes contents at location, possibly converted.
|
||||
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 len: length of the string in bytes (including terminating 0)
|
||||
@param type: type of the string
|
||||
@param flags: combination of ACFOPT_...
|
||||
@return: string contents (not including terminating 0) or None
|
||||
@param type: type of the string. Represents both the character encoding,
|
||||
<u>and</u> the 'type' of string at the given location.
|
||||
@param flags: combination of ACFOPT_..., to perform output conversion.
|
||||
@return: a bytes-filled str object.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
@ -177,7 +183,7 @@ static PyObject *py_get_ascii_contents2(
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
Py_RETURN_NONE;
|
||||
|
@ -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 methods
|
||||
@ -420,7 +470,7 @@ public:
|
||||
}
|
||||
|
||||
int add_command(
|
||||
const char *caption,
|
||||
const char *_caption,
|
||||
int flags=0,
|
||||
int menu_index=-1,
|
||||
int icon=-1)
|
||||
@ -428,60 +478,16 @@ public:
|
||||
if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS )
|
||||
return -1;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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,
|
||||
qstring title, caption;
|
||||
if ( !split_chooser_caption(&title, &caption, _caption)
|
||||
|| !add_chooser_command(
|
||||
title.c_str(),
|
||||
caption.c_str(),
|
||||
menu_cbs[menu_cb_idx],
|
||||
menu_index,
|
||||
icon,
|
||||
flags))
|
||||
{
|
||||
flags) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
return menu_cb_idx++;
|
||||
}
|
||||
@ -869,10 +875,7 @@ int choose2_add_command(
|
||||
int icon=-1)
|
||||
{
|
||||
py_choose2_t *c2 = choose2_find_instance(self);
|
||||
if ( c2 != NULL )
|
||||
return c2->add_command(caption, flags, menu_index, icon);
|
||||
else
|
||||
return -2;
|
||||
return c2 == NULL ? -2 : c2->add_command(caption, flags, menu_index, icon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -54,6 +54,8 @@ class Choose2(object):
|
||||
CH_ATTRS = 0x10
|
||||
CH_NOIDB = 0x20
|
||||
"""use the chooser even without an open database, same as x0=-2"""
|
||||
CH_UTF8 = 0x40
|
||||
"""string encoding is utf-8"""
|
||||
|
||||
CH_BUILTIN_MASK = 0xF80000
|
||||
|
||||
@ -162,12 +164,11 @@ class Choose2(object):
|
||||
icon = -1,
|
||||
emb=None):
|
||||
"""
|
||||
Adds a new chooser command
|
||||
Save the returned value and later use it in the OnCommand handler
|
||||
|
||||
@return: Returns a negative value on failure or the command index
|
||||
Deprecated: Use
|
||||
- register_action()
|
||||
- attach_action_to_menu()
|
||||
- attach_action_to_popup()
|
||||
"""
|
||||
|
||||
# Use the 'emb' as a sentinel. It will be passed the correct value from the EmbeddedChooserControl
|
||||
if self.embedded and ((emb is None) or (emb != 2002)):
|
||||
raise RuntimeError("Please add a command through EmbeddedChooserControl.AddCommand()")
|
||||
@ -275,6 +276,24 @@ class Choose2(object):
|
||||
#</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):
|
||||
|
||||
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)
|
||||
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):
|
||||
r = self.items[n]
|
||||
t = self.icon + r[1].count("*")
|
||||
@ -344,14 +354,7 @@ class MyChoose2(Choose2):
|
||||
return t
|
||||
|
||||
def show(self):
|
||||
t = self.Show(self.modal)
|
||||
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
|
||||
return self.Show(self.modal) >= 0
|
||||
|
||||
def make_item(self):
|
||||
r = [str(self.n), "func_%04d" % self.n]
|
||||
@ -369,6 +372,9 @@ def test_choose2(modal=False):
|
||||
global c
|
||||
c = MyChoose2("Choose2 - sample 1", nb=10, modal=modal)
|
||||
r = c.show()
|
||||
form = idaapi.get_current_tform()
|
||||
for thing in ["A", "B"]:
|
||||
idaapi.attach_action_to_popup(form, None, "choose2:act%s" % thing)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def test_choose2_embedded():
|
||||
@ -386,5 +392,17 @@ def test_choose2_embedded():
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
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)>
|
||||
|
@ -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
|
||||
{
|
||||
protected:
|
||||
@ -166,13 +169,6 @@ private:
|
||||
qstring _curline;
|
||||
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)
|
||||
{
|
||||
size_t mid = (size_t)ud;
|
||||
@ -271,6 +267,10 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
inline TForm *get_tform() { return _form; }
|
||||
inline TCustomControl *get_tcustom_control() { return _cv; }
|
||||
|
||||
//
|
||||
// All the overridable callbacks
|
||||
//
|
||||
@ -1111,6 +1111,22 @@ bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl)
|
||||
DECL_THIS;
|
||||
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
|
||||
//</inline(py_custviewer)>
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -204,6 +204,24 @@ class simplecustviewer_t(object):
|
||||
"""Returns True if the current view is the focused view"""
|
||||
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
|
||||
#<pydoc>
|
||||
# def OnClick(self, shift):
|
||||
@ -278,6 +296,18 @@ class simplecustviewer_t(object):
|
||||
|
||||
#<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):
|
||||
def Create(self, sn=None):
|
||||
@ -289,8 +319,6 @@ class mycv_t(simplecustviewer_t):
|
||||
# Create the customviewer
|
||||
if not simplecustviewer_t.Create(self, title):
|
||||
return False
|
||||
self.menu_hello = self.AddPopupMenu("Hello")
|
||||
self.menu_world = self.AddPopupMenu("World")
|
||||
|
||||
for i in xrange(0, 100):
|
||||
self.AddLine("Line %d" % i)
|
||||
@ -391,13 +419,6 @@ class mycv_t(simplecustviewer_t):
|
||||
return False
|
||||
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):
|
||||
"""
|
||||
Hint requested for the given line number.
|
||||
@ -408,22 +429,6 @@ class mycv_t(simplecustviewer_t):
|
||||
"""
|
||||
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:
|
||||
# created already?
|
||||
@ -440,7 +445,16 @@ def show_win():
|
||||
print "Failed to create!"
|
||||
return None
|
||||
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
|
||||
|
||||
mycv = show_win()
|
||||
if not mycv:
|
||||
del mycv
|
||||
|
@ -61,323 +61,6 @@ struct scfld_t
|
||||
#define FT_BAD_TYPE -2
|
||||
#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(
|
||||
const ref_t &py_list,
|
||||
@ -1052,9 +735,6 @@ bool pyw_convert_idc_args(
|
||||
{
|
||||
// PyTuple_SetItem() steals the reference.
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
@ -723,5 +723,63 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
|
||||
}
|
||||
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)>
|
||||
#endif
|
||||
|
@ -38,7 +38,10 @@ private:
|
||||
GRCODE_HAVE_GOTFOCUS = 0x00080000,
|
||||
GRCODE_HAVE_LOSTFOCUS = 0x00100000,
|
||||
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
|
||||
{
|
||||
@ -142,6 +145,7 @@ private:
|
||||
// Check return value to OnRefresh() call
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id));
|
||||
PyW_ShowCbErr(S_ON_COMMAND);
|
||||
}
|
||||
|
||||
// Refresh user-defined graph node number and edges
|
||||
@ -189,6 +193,7 @@ private:
|
||||
(char *)S_ON_CLICK,
|
||||
"i",
|
||||
item2->n));
|
||||
PyW_ShowCbErr(S_ON_CLICK);
|
||||
return result == NULL || !PyObject_IsTrue(result.o);
|
||||
}
|
||||
|
||||
@ -210,29 +215,38 @@ private:
|
||||
(char *)S_ON_DBL_CLICK,
|
||||
"i",
|
||||
item->node));
|
||||
PyW_ShowCbErr(S_ON_DBL_CLICK);
|
||||
return result == NULL || !PyObject_IsTrue(result.o);
|
||||
}
|
||||
|
||||
// a graph viewer got focus
|
||||
void on_gotfocus(graph_viewer_t * /*view*/)
|
||||
{
|
||||
if ( self.o == NULL )
|
||||
return;
|
||||
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_ACTIVATE,
|
||||
NULL));
|
||||
PyW_ShowCbErr(S_ON_ACTIVATE);
|
||||
}
|
||||
|
||||
// a graph viewer lost focus
|
||||
void on_lostfocus(graph_viewer_t * /*view*/)
|
||||
{
|
||||
if ( self.o == NULL )
|
||||
return;
|
||||
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_DEACTIVATE,
|
||||
NULL));
|
||||
PyW_ShowCbErr(S_ON_DEACTIVATE);
|
||||
}
|
||||
|
||||
// a new graph node became the current node
|
||||
@ -251,6 +265,7 @@ private:
|
||||
(char *)S_ON_SELECT,
|
||||
"i",
|
||||
curnode));
|
||||
PyW_ShowCbErr(S_ON_SELECT);
|
||||
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)
|
||||
{
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes);
|
||||
newref_t py_nodes(PyList_New(my_nodes->size()));
|
||||
int i;
|
||||
intvec_t::const_iterator p;
|
||||
@ -270,6 +284,7 @@ private:
|
||||
(char *)S_ON_CREATING_GROUP,
|
||||
"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);
|
||||
}
|
||||
|
||||
@ -299,6 +314,10 @@ private:
|
||||
|
||||
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);
|
||||
int x, y;
|
||||
|
||||
@ -342,6 +361,7 @@ private:
|
||||
if ( pview != NULL )
|
||||
viewer_fit_window(pview);
|
||||
bind(self, pview);
|
||||
install_custom_viewer_handlers();
|
||||
refresh();
|
||||
lookup_info.commit(e, form, view);
|
||||
}
|
||||
@ -379,13 +399,16 @@ public:
|
||||
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);
|
||||
if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) )
|
||||
return;
|
||||
|
||||
_this->jump_to_node(0);
|
||||
_this->jump_to_node(nid);
|
||||
}
|
||||
|
||||
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_ACTIVATE, GRCODE_HAVE_GOTFOCUS);
|
||||
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
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL));
|
||||
PyW_ShowCbErr(S_ON_REFRESH);
|
||||
if ( ret != NULL && PyObject_IsTrue(ret.o) )
|
||||
{
|
||||
// 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
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node));
|
||||
PyW_ShowCbErr(S_ON_GETTEXT);
|
||||
if ( result == NULL )
|
||||
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();
|
||||
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);
|
||||
if ( ok )
|
||||
*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);
|
||||
}
|
||||
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;
|
||||
//
|
||||
case grcode_gotfocus:
|
||||
@ -698,28 +730,43 @@ int py_graph_t::gr_callback(int code, va_list va)
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
intvec_t *nodes = va_arg(va, intvec_t*);
|
||||
ret = on_creating_group(g, nodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok to create
|
||||
}
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
int old_group = va_arg(va, int);
|
||||
ret = on_deleting_group(g, old_group);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok to delete
|
||||
}
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
int group = va_arg(va, int);
|
||||
bool expand = bool(va_arg(va, int));
|
||||
ret = on_group_visibility(g, group, expand);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok.
|
||||
}
|
||||
break;
|
||||
//
|
||||
default:
|
||||
|
@ -70,10 +70,9 @@ class GraphViewer(CustomIDAMemo):
|
||||
|
||||
def AddCommand(self, title, hotkey):
|
||||
"""
|
||||
Adds a menu command to the graph. Call this command after the graph is shown (with Show()).
|
||||
Once a command is added, a command id is returned. The commands are handled inside the OnCommand() handler
|
||||
|
||||
@return: 0 on failure or the command id
|
||||
Deprecated: Use
|
||||
- register_action()
|
||||
- attach_action_to_popup()
|
||||
"""
|
||||
return _idaapi.pyg_add_command(self, title, hotkey)
|
||||
|
||||
@ -155,9 +154,8 @@ class GraphViewer(CustomIDAMemo):
|
||||
#
|
||||
# def OnCommand(self, cmd_id):
|
||||
# """
|
||||
# Triggered when a menu command is selected through the menu or its hotkey
|
||||
# @return: None
|
||||
# Deprecated
|
||||
# """
|
||||
# print "command:", cmd_id
|
||||
# pass
|
||||
#</pydoc>
|
||||
#</pycode(py_graph)>
|
||||
|
@ -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_SWITCHED[] = "OnViewSwitched";
|
||||
static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver";
|
||||
static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved";
|
||||
|
||||
|
||||
#ifdef __PYWRAPS__
|
||||
@ -623,7 +624,6 @@ void *pyobj_get_clink(PyObject *pyobj)
|
||||
}
|
||||
|
||||
//</code(py_idaapi)>
|
||||
|
||||
//<inline(py_idaapi)>
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
@ -644,12 +644,7 @@ static PyObject *py_parse_command_line(const char *cmdline)
|
||||
qstrvec_t args;
|
||||
if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
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;
|
||||
return qstrvec2pylist(args);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -8,6 +8,7 @@ class py_idaview_t : public py_customidamemo_t
|
||||
|
||||
public:
|
||||
static bool Bind(PyObject *self);
|
||||
static bool Unbind(PyObject *self);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -53,24 +54,43 @@ bool py_idaview_t::Bind(PyObject *self)
|
||||
if ( ok )
|
||||
{
|
||||
ok = py_view->collect_pyobject_callbacks(self);
|
||||
if ( !ok )
|
||||
if ( ok )
|
||||
py_view->install_custom_viewer_handlers();
|
||||
else
|
||||
delete py_view;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool py_idaview_t::Unbind(PyObject *self)
|
||||
{
|
||||
py_idaview_t *_this = view_extract_this<py_idaview_t>(self);
|
||||
if ( _this == NULL )
|
||||
return false;
|
||||
_this->unbind();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool pyidag_bind(PyObject *self)
|
||||
{
|
||||
return py_idaview_t::Bind(self);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool pyidag_unbind(PyObject *self)
|
||||
{
|
||||
return py_idaview_t::Unbind(self);
|
||||
}
|
||||
|
||||
//</code(py_idaview)>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
//<inline(py_idaview)>
|
||||
bool pyidag_bind(PyObject *self);
|
||||
bool pyidag_unbind(PyObject *self);
|
||||
//</inline(py_idaview)>
|
||||
|
||||
#endif // __PY_IDA_VIEW__
|
||||
|
@ -13,4 +13,8 @@ class IDAViewWrapper(CustomIDAMemo):
|
||||
|
||||
def Bind(self):
|
||||
return _idaapi.pyidag_bind(self)
|
||||
|
||||
def Unbind(self):
|
||||
return _idaapi.pyidag_unbind(self)
|
||||
|
||||
#</pycode(py_idaview)>
|
||||
|
@ -748,6 +748,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void auto_empty_finally()
|
||||
{
|
||||
}
|
||||
|
||||
virtual int rename(ea_t ea, const char *new_name)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
@ -834,38 +847,38 @@ public:
|
||||
return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
|
||||
}
|
||||
// Hook functions to override in Python
|
||||
virtual int byte_patched(ea_t /*ea*/) { return 0; };
|
||||
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
|
||||
virtual int byte_patched(ea_t /*ea*/) { 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 ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
|
||||
virtual int enum_created(enum_t /*id*/) { return 0; };
|
||||
virtual int enum_deleted(enum_t /*id*/) { return 0; };
|
||||
virtual int enum_bf_changed(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_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 struc_created(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_expanded(struc_t * /*sptr*/) { 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_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_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { 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_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 func_noret_changed(func_t * /*pfn*/) { return 0; };
|
||||
virtual int segm_added(segment_t * /*s*/) { return 0; };
|
||||
virtual int segm_deleted(ea_t /*startEA*/) { 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_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; };
|
||||
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }
|
||||
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }
|
||||
virtual int enum_created(enum_t /*id*/) { return 0; }
|
||||
virtual int enum_deleted(enum_t /*id*/) { return 0; }
|
||||
virtual int enum_bf_changed(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_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 struc_created(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_expanded(struc_t * /*sptr*/) { 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_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_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { 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_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 func_noret_changed(func_t * /*pfn*/) { return 0; }
|
||||
virtual int segm_added(segment_t * /*s*/) { return 0; }
|
||||
virtual int segm_deleted(ea_t /*startEA*/) { 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_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }
|
||||
};
|
||||
|
||||
//</inline(py_idp)>
|
||||
@ -951,6 +964,12 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
|
||||
break;
|
||||
}
|
||||
|
||||
case processor_t::auto_empty_finally:
|
||||
{
|
||||
proxy->auto_empty_finally();
|
||||
break;
|
||||
}
|
||||
|
||||
case processor_t::rename:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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:
|
||||
{
|
||||
func_t *func = va_arg(va, func_t *);
|
||||
|
@ -218,6 +218,72 @@ def readsel2(view, p0, p1):
|
||||
#</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>
|
||||
@ -299,18 +365,17 @@ PyObject *py_str2user(const char *str)
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def process_ui_action(name, flags):
|
||||
def process_ui_action(name):
|
||||
"""
|
||||
Invokes an IDA UI action by name
|
||||
|
||||
@param name: action name
|
||||
@param flags: Reserved. Must be zero
|
||||
@return: Boolean
|
||||
"""
|
||||
pass
|
||||
#</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);
|
||||
}
|
||||
@ -319,12 +384,7 @@ static bool py_process_ui_action(const char *name, int flags)
|
||||
/*
|
||||
#<pydoc>
|
||||
def del_menu_item(menu_ctx):
|
||||
"""
|
||||
Deletes a menu item previously added with add_menu_item()
|
||||
|
||||
@param menu_ctx: value returned by add_menu_item()
|
||||
@return: Boolean
|
||||
"""
|
||||
"""Deprecated. Use detach_menu_item()/unregister_action() instead."""
|
||||
pass
|
||||
#</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);
|
||||
|
||||
bool ok = del_menu_item(ctx->menupath.c_str());
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
Py_DECREF(ctx->cb_data);
|
||||
@ -455,21 +514,7 @@ PyObject *py_add_hotkey(const char *hotkey, PyObject *pyfunc)
|
||||
/*
|
||||
#<pydoc>
|
||||
def add_menu_item(menupath, name, hotkey, flags, callback, args):
|
||||
"""
|
||||
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())
|
||||
"""
|
||||
"""Deprecated. Use register_action()/attach_menu_item() instead."""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
@ -816,6 +861,45 @@ class UI_Hooks(object):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
IDA is terminated and the database is already closed.
|
||||
@ -873,7 +957,242 @@ public:
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
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)>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -932,6 +1251,44 @@ int idaapi UI_Callback(void *ud, int notification_code, va_list va)
|
||||
}
|
||||
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)
|
||||
|
@ -32,7 +32,7 @@ DP_INSIDE = 0x0010
|
||||
# this flag alone cannot be used to determine orientation
|
||||
DP_BEFORE = 0x0020
|
||||
# used with combination of other flags
|
||||
DP_RAW = 0x0040
|
||||
DP_TAB = 0x0040
|
||||
DP_FLOATING = 0x0080
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@ -83,6 +83,17 @@ def askseg(defval, format):
|
||||
else:
|
||||
return None
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class action_handler_t:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def activate(self, ctx):
|
||||
return 0
|
||||
|
||||
def update(self, ctx):
|
||||
pass
|
||||
|
||||
#</pycode(py_kernwin)>
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
112
pywraps/py_registry.hpp
Normal file
112
pywraps/py_registry.hpp
Normal 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__
|
@ -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)
|
||||
"""
|
||||
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_fields: type fields
|
||||
@param py_fields: fields string (may be empty or None)
|
||||
@param ea: the address of the object
|
||||
@param flags: combination of TINFO_... constants or 0
|
||||
@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)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
return rc;
|
||||
}
|
||||
@ -138,7 +165,7 @@ PyObject *py_unpack_object_from_idb(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -150,7 +177,7 @@ PyObject *py_unpack_object_from_idb(
|
||||
|
||||
// Unpack
|
||||
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;
|
||||
error_t err;
|
||||
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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@param tp: type string
|
||||
@param fields: type fields
|
||||
@param fields: fields string (may be empty or None)
|
||||
@param bytes: the bytes to unpack
|
||||
@param pio_flags: flags used while unpacking
|
||||
@return:
|
||||
@ -206,7 +233,7 @@ PyObject *py_unpack_object_from_bv(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -218,7 +245,7 @@ PyObject *py_unpack_object_from_bv(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@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 pio_flags: flags used while unpacking
|
||||
"""
|
||||
@ -278,7 +305,7 @@ PyObject *py_pack_object_to_idb(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -296,7 +323,7 @@ PyObject *py_pack_object_to_idb(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
// 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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@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 pio_flags: flags used while unpacking
|
||||
@return:
|
||||
@ -335,7 +362,7 @@ PyObject *py_pack_object_to_bv(
|
||||
int pio_flags=0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -353,7 +380,7 @@ PyObject *py_pack_object_to_bv(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
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)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -509,7 +536,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam
|
||||
|
||||
qstring res;
|
||||
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;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
tinfo_t tif;
|
||||
@ -536,43 +563,78 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize)
|
||||
|
||||
//<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
|
||||
// associated, in the kernel, with the tinfo_t instances.
|
||||
//
|
||||
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
|
||||
// closed, but the "type details" must be cleared _before_ the IDB is closed.
|
||||
static qvector<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)
|
||||
{
|
||||
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that
|
||||
// were not done here, ~tinfo_t() calls happening as part of the python shutdown
|
||||
// process will try and clear() their details. ..but the kernel's til-related
|
||||
// functions will already have deleted those details at that point.
|
||||
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i )
|
||||
python_tinfos[i]->clear();
|
||||
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t
|
||||
// Pre-emptive strike: clear all the python-exposed tinfo_t
|
||||
// (& related types) instances: if that were not done here,
|
||||
// ~tinfo_t() calls happening as part of the python shutdown
|
||||
// process will try and clear() their details. ..but the kernel's
|
||||
// til-related functions will already have deleted those details
|
||||
// at that point.
|
||||
//
|
||||
// NOTE: Don't clear() the arrays of pointers. All the python-exposed
|
||||
// instances will be deleted through the python shutdown/ref-decrementing
|
||||
// process anyway (which will cause til_deregister_..() calls), and the
|
||||
// entries will be properly pulled out of the vector when that happens.
|
||||
#define BATCH_CLEAR(Type) \
|
||||
do \
|
||||
{ \
|
||||
for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \
|
||||
__clear(py_##Type##_vec[i]); \
|
||||
} while ( false )
|
||||
|
||||
BATCH_CLEAR(tinfo_t);
|
||||
BATCH_CLEAR(ptr_type_data_t);
|
||||
BATCH_CLEAR(array_type_data_t);
|
||||
BATCH_CLEAR(func_type_data_t);
|
||||
BATCH_CLEAR(udt_type_data_t);
|
||||
#undef BATCH_CLEAR
|
||||
}
|
||||
|
||||
void til_register_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
// Let's add_unique() it, because every reference to an object's
|
||||
// tinfo_t property will end up trying to register it.
|
||||
python_tinfos.add_unique(tif);
|
||||
}
|
||||
|
||||
void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif);
|
||||
if ( found != python_tinfos.end() )
|
||||
{
|
||||
tif->clear();
|
||||
python_tinfos.erase(found);
|
||||
#define DEF_REG_UNREG_REFCOUNTED(Type) \
|
||||
void til_register_python_##Type##_instance(Type *inst) \
|
||||
{ \
|
||||
/* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \
|
||||
/* to an object's tinfo_t property will end up trying to register it. */ \
|
||||
py_##Type##_vec.add_unique(inst); \
|
||||
} \
|
||||
\
|
||||
void til_deregister_python_##Type##_instance(Type *inst) \
|
||||
{ \
|
||||
qvector<Type*>::iterator found = py_##Type##_vec.find(inst); \
|
||||
if ( found != py_##Type##_vec.end() ) \
|
||||
{ \
|
||||
__clear(inst); \
|
||||
/* tif->clear();*/ \
|
||||
py_##Type##_vec.erase(found); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
|
||||
DEF_REG_UNREG_REFCOUNTED(tinfo_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(array_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(func_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(udt_type_data_t);
|
||||
|
||||
#undef DEF_REG_UNREG_REFCOUNTED
|
||||
|
||||
//</code(py_typeinf)>
|
||||
|
||||
|
@ -14,7 +14,6 @@ op_t *op_t_get_clink(PyObject *self)
|
||||
{
|
||||
return (op_t *)pyobj_get_clink(self);
|
||||
}
|
||||
|
||||
//</code(py_ua)>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -329,6 +328,49 @@ bool py_out_name_expr(
|
||||
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)
|
||||
{
|
||||
|
@ -412,13 +412,13 @@ o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
|
||||
o_imm = 5 # Immediate Value value
|
||||
o_far = 6 # Immediate Far Address (CODE) addr
|
||||
o_near = 7 # Immediate Near Address (CODE) addr
|
||||
o_idpspec0 = 8 # IDP specific type
|
||||
o_idpspec1 = 9 # IDP specific type
|
||||
o_idpspec2 = 10 # IDP specific type
|
||||
o_idpspec3 = 11 # IDP specific type
|
||||
o_idpspec4 = 12 # IDP specific type
|
||||
o_idpspec5 = 13 # IDP specific type
|
||||
o_last = 14 # first unused type
|
||||
o_idpspec0 = 8 # Processor specific type
|
||||
o_idpspec1 = 9 # Processor specific type
|
||||
o_idpspec2 = 10 # Processor specific type
|
||||
o_idpspec3 = 11 # Processor specific type
|
||||
o_idpspec4 = 12 # Processor specific type
|
||||
o_idpspec5 = 13 # Processor specific type
|
||||
# There can be more processor specific types
|
||||
|
||||
#
|
||||
# op_t.dtyp
|
||||
@ -485,7 +485,7 @@ class processor_t(pyidc_opaque_object_t):
|
||||
short processor names similar to the one in ph.psnames.
|
||||
This method can be overridden to return to the kernel a different IDP description.
|
||||
"""
|
||||
return self.plnames[0] + ':' + ':'.join(self.psnames)
|
||||
return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames)))
|
||||
|
||||
def get_uFlag(self):
|
||||
"""Use this utility function to retrieve the 'uFlag' global variable"""
|
||||
|
@ -138,12 +138,16 @@ class py_customidamemo_t
|
||||
GRBASE_HAVE_CLOSE = 0x080,
|
||||
GRBASE_HAVE_VIEW_SWITCHED = 0x100,
|
||||
GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200,
|
||||
GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400,
|
||||
};
|
||||
|
||||
static void ensure_view_callbacks_installed();
|
||||
int cb_flags;
|
||||
// number of arguments for OnViewClick implementation
|
||||
int ovc_num_args;
|
||||
// number of arguments for:
|
||||
int ovc_num_args; // OnViewClick implementation
|
||||
int ovdc_num_args; // OnViewDblclick implementation
|
||||
int ovmo_num_args; // OnViewMouseOver implementation
|
||||
int ovmm_num_args; // OnViewMouseMoved implementation
|
||||
|
||||
protected:
|
||||
ref_t self;
|
||||
@ -177,11 +181,15 @@ protected:
|
||||
bool collect_pyobject_callbacks(PyObject *self);
|
||||
virtual void collect_class_callbacks_ids(callbacks_ids_t *out);
|
||||
|
||||
void install_custom_viewer_handlers();
|
||||
|
||||
// Bi-directionally bind/unbind the Python object and this controller.
|
||||
bool bind(PyObject *_self, TCustomControl *view);
|
||||
void unbind();
|
||||
|
||||
static lookup_info_t lookup_info;
|
||||
friend TForm *pycim_get_tform(PyObject *self);
|
||||
friend TCustomControl *pycim_get_tcustom_control(PyObject *self);
|
||||
|
||||
public:
|
||||
py_customidamemo_t();
|
||||
@ -211,8 +219,16 @@ public:
|
||||
void on_view_close();
|
||||
void on_view_switched(tcc_renderer_type_t rt);
|
||||
void on_view_mouse_over(const view_mouse_event_t *event);
|
||||
void on_view_mouse_moved(const view_mouse_event_t *event);
|
||||
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
|
||||
int get_py_method_arg_count(char *method_name);
|
||||
|
||||
// View events that are bound with 'set_custom_viewer_handler()'.
|
||||
static void idaapi s_on_view_mouse_moved(
|
||||
TCustomControl *cv,
|
||||
int shift,
|
||||
view_mouse_event_t *e,
|
||||
void *ud);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -223,6 +239,9 @@ py_customidamemo_t::py_customidamemo_t()
|
||||
PYGLOG("%p: py_customidamemo_t()\n", this);
|
||||
ensure_view_callbacks_installed();
|
||||
ovc_num_args = -1;
|
||||
ovdc_num_args = -1;
|
||||
ovmo_num_args = -1;
|
||||
ovmm_num_args = -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -262,7 +281,7 @@ void py_customidamemo_t::ensure_view_callbacks_installed()
|
||||
py_view->on_view_keydown(key, state);
|
||||
}
|
||||
break;
|
||||
case view_popup:
|
||||
case obsolete_view_popup:
|
||||
py_view->on_view_popup();
|
||||
break;
|
||||
case view_click:
|
||||
@ -514,6 +533,18 @@ void py_customidamemo_t::unbind()
|
||||
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)
|
||||
{
|
||||
@ -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_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED);
|
||||
out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER);
|
||||
out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -567,9 +599,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
|
||||
if ( have > 0 && attr != NULL )
|
||||
cb_flags |= have;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::install_custom_viewer_handlers()
|
||||
{
|
||||
if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) )
|
||||
{
|
||||
// Set user-data
|
||||
set_custom_viewer_handler(view, CVH_USERDATA, (void *)this);
|
||||
|
||||
//
|
||||
set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#define CHK_EVT(flag_needed) \
|
||||
@ -577,10 +622,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
|
||||
return; \
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE()
|
||||
|
||||
|
||||
#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
|
||||
#define CHK_RES()
|
||||
#define CHK_RES() \
|
||||
do \
|
||||
{ \
|
||||
if (PyErr_Occurred()) \
|
||||
PyErr_Print(); \
|
||||
} while ( false )
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -632,13 +689,33 @@ void py_customidamemo_t::on_view_popup()
|
||||
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)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
|
||||
if ( ovc_num_args < 0 )
|
||||
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
|
||||
if ( ovc_num_args == 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(
|
||||
PyObject_CallMethod(
|
||||
@ -646,6 +723,7 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iiii",
|
||||
event->x, event->y, event->state, event->button));
|
||||
CHK_RES();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -655,14 +733,29 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
}
|
||||
CHK_RES();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK);
|
||||
if ( ovdc_num_args < 0 )
|
||||
ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK);
|
||||
if ( ovdc_num_args == 5 )
|
||||
{
|
||||
PyObject *rpos = build_renderer_pos_swig_proxy(event);
|
||||
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(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
@ -670,6 +763,7 @@ void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
CHK_RES();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -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;
|
||||
int icode;
|
||||
ref_t tuple;
|
||||
if ( item != NULL )
|
||||
if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY)
|
||||
&& item != NULL )
|
||||
{
|
||||
if ( item->is_node )
|
||||
{
|
||||
icode = 1;
|
||||
*out_icode = 1;
|
||||
tuple = newref_t(Py_BuildValue("(i)", item->node));
|
||||
}
|
||||
else
|
||||
{
|
||||
icode = 2;
|
||||
*out_icode = 2;
|
||||
tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
icode = 0;
|
||||
*out_icode = 0;
|
||||
tuple = newref_t(Py_BuildValue("()"));
|
||||
}
|
||||
return tuple;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
|
||||
if ( ovmo_num_args < 0 )
|
||||
ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER);
|
||||
if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY )
|
||||
return;
|
||||
|
||||
int icode;
|
||||
ref_t tuple = build_current_graph_item_tuple(&icode, event);
|
||||
if ( ovmo_num_args == 7 )
|
||||
{
|
||||
PyObject *rpos = build_renderer_pos_swig_proxy(event);
|
||||
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(
|
||||
self.o,
|
||||
(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_EVT
|
||||
@ -748,6 +886,10 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
return
|
||||
#define CHK_THIS_OR_NULL() \
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
return NULL;
|
||||
#define CHK_THIS_OR_NONE() \
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
@ -829,7 +971,28 @@ PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject
|
||||
return _this->set_groups_visibility(groups, expand, new_current);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
TForm *pycim_get_tform(PyObject *self)
|
||||
{
|
||||
CHK_THIS_OR_NULL();
|
||||
TForm *form = NULL;
|
||||
if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) )
|
||||
return NULL;
|
||||
return form;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
TCustomControl *pycim_get_tcustom_control(PyObject *self)
|
||||
{
|
||||
CHK_THIS_OR_NULL();
|
||||
TCustomControl *tcc = NULL;
|
||||
if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) )
|
||||
return NULL;
|
||||
return tcc;
|
||||
}
|
||||
|
||||
#undef CHK_THIS_OR_NONE
|
||||
#undef CHK_THIS_OR_NULL
|
||||
#undef CHK_THIS
|
||||
#undef GET_THIS
|
||||
|
||||
@ -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_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current);
|
||||
PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current);
|
||||
TForm *pycim_get_tform(PyObject *self);
|
||||
TCustomControl *pycim_get_tcustom_control(PyObject *self);
|
||||
//</inline(py_view_base)>
|
||||
|
||||
|
||||
|
@ -104,4 +104,21 @@ class CustomIDAMemo(object):
|
||||
"""
|
||||
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)>
|
||||
|
@ -985,7 +985,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\examples\ex_add_menu_item.py"
|
||||
RelativePath="..\examples\ex_actions.py"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -92,7 +92,6 @@ BADADDR = 0xFFFFFFFFFFFFFFFFL
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
UA_MAXOP = 6
|
||||
o_last = 14
|
||||
o_void = 0
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
@ -42,13 +42,13 @@ o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
|
||||
o_imm = 5 # Immediate Value value
|
||||
o_far = 6 # Immediate Far Address (CODE) addr
|
||||
o_near = 7 # Immediate Near Address (CODE) addr
|
||||
o_idpspec0 = 8 # IDP specific type
|
||||
o_idpspec1 = 9 # IDP specific type
|
||||
o_idpspec2 = 10 # IDP specific type
|
||||
o_idpspec3 = 11 # IDP specific type
|
||||
o_idpspec4 = 12 # IDP specific type
|
||||
o_idpspec5 = 13 # IDP specific type
|
||||
o_last = 14 # first unused type
|
||||
o_idpspec0 = 8 # Processor specific type
|
||||
o_idpspec1 = 9 # Processor specific type
|
||||
o_idpspec2 = 10 # Processor specific type
|
||||
o_idpspec3 = 11 # Processor specific type
|
||||
o_idpspec4 = 12 # Processor specific type
|
||||
o_idpspec5 = 13 # Processor specific type
|
||||
# There can be more processor specific types
|
||||
|
||||
#
|
||||
# op_t.dtyp
|
||||
|
18
swig/bytes.i
18
swig/bytes.i
@ -751,15 +751,21 @@ ACFOPT_ESCAPE = 0x00000010 # for ACFOPT_ASCII, convert non-printable
|
||||
|
||||
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
|
||||
"""
|
||||
Get contents of ascii string
|
||||
This function returns the displayed part of the string
|
||||
Get bytes contents at location, possibly converted.
|
||||
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 len: length of the string in bytes (including terminating 0)
|
||||
@param type: type of the string
|
||||
@param flags: combination of ACFOPT_...
|
||||
@return: string contents (not including terminating 0) or None
|
||||
@param type: type of the string. Represents both the character encoding,
|
||||
<u>and</u> the 'type' of string at the given location.
|
||||
@param flags: combination of ACFOPT_..., to perform output conversion.
|
||||
@return: a bytes-filled str object.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
@ -775,7 +781,7 @@ static PyObject *py_get_ascii_contents2(
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
Py_RETURN_NONE;
|
||||
|
72
swig/dbg.i
72
swig/dbg.i
@ -28,6 +28,20 @@ typedef struct
|
||||
%ignore set_manual_regions;
|
||||
%ignore inform_idc_about_debthread;
|
||||
%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
|
||||
// to release the GIL when calling into the IDA api: those
|
||||
// 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<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)>
|
||||
|
||||
%}
|
||||
|
@ -2,6 +2,7 @@
|
||||
%ignore enumerate_files;
|
||||
%rename (enumerate_files) py_enumerate_files;
|
||||
%ignore enumerate_system_files;
|
||||
%ignore enumerate_sorted_files;
|
||||
%ignore ioport_bit_t;
|
||||
%ignore ioport_bits_t;
|
||||
%ignore ioport_t;
|
||||
|
@ -38,6 +38,7 @@
|
||||
%ignore idc_stacksize;
|
||||
%ignore idc_calldepth;
|
||||
%ignore expr_printf;
|
||||
%ignore expr_uprintf;
|
||||
%ignore expr_sprintf;
|
||||
%ignore expr_printfer;
|
||||
%ignore init_idc;
|
||||
|
@ -29,4 +29,6 @@
|
||||
%ignore calc_frame_offset;
|
||||
%ignore add_stkvar;
|
||||
|
||||
%template(xreflist_t) qvector<xreflist_entry_t>;
|
||||
|
||||
%include "frame.hpp"
|
||||
|
69
swig/graph.i
69
swig/graph.i
@ -41,7 +41,10 @@ private:
|
||||
GRCODE_HAVE_GOTFOCUS = 0x00080000,
|
||||
GRCODE_HAVE_LOSTFOCUS = 0x00100000,
|
||||
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
|
||||
{
|
||||
@ -145,6 +148,7 @@ private:
|
||||
// Check return value to OnRefresh() call
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_COMMAND, "n", id));
|
||||
PyW_ShowCbErr(S_ON_COMMAND);
|
||||
}
|
||||
|
||||
// Refresh user-defined graph node number and edges
|
||||
@ -192,6 +196,7 @@ private:
|
||||
(char *)S_ON_CLICK,
|
||||
"i",
|
||||
item2->n));
|
||||
PyW_ShowCbErr(S_ON_CLICK);
|
||||
return result == NULL || !PyObject_IsTrue(result.o);
|
||||
}
|
||||
|
||||
@ -213,29 +218,38 @@ private:
|
||||
(char *)S_ON_DBL_CLICK,
|
||||
"i",
|
||||
item->node));
|
||||
PyW_ShowCbErr(S_ON_DBL_CLICK);
|
||||
return result == NULL || !PyObject_IsTrue(result.o);
|
||||
}
|
||||
|
||||
// a graph viewer got focus
|
||||
void on_gotfocus(graph_viewer_t * /*view*/)
|
||||
{
|
||||
if ( self.o == NULL )
|
||||
return;
|
||||
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_ACTIVATE,
|
||||
NULL));
|
||||
PyW_ShowCbErr(S_ON_ACTIVATE);
|
||||
}
|
||||
|
||||
// a graph viewer lost focus
|
||||
void on_lostfocus(graph_viewer_t * /*view*/)
|
||||
{
|
||||
if ( self.o == NULL )
|
||||
return;
|
||||
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_DEACTIVATE,
|
||||
NULL));
|
||||
PyW_ShowCbErr(S_ON_DEACTIVATE);
|
||||
}
|
||||
|
||||
// a new graph node became the current node
|
||||
@ -254,6 +268,7 @@ private:
|
||||
(char *)S_ON_SELECT,
|
||||
"i",
|
||||
curnode));
|
||||
PyW_ShowCbErr(S_ON_SELECT);
|
||||
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)
|
||||
{
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes);
|
||||
newref_t py_nodes(PyList_New(my_nodes->size()));
|
||||
int i;
|
||||
intvec_t::const_iterator p;
|
||||
@ -273,6 +287,7 @@ private:
|
||||
(char *)S_ON_CREATING_GROUP,
|
||||
"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);
|
||||
}
|
||||
|
||||
@ -302,6 +317,10 @@ private:
|
||||
|
||||
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);
|
||||
int x, y;
|
||||
|
||||
@ -345,6 +364,7 @@ private:
|
||||
if ( pview != NULL )
|
||||
viewer_fit_window(pview);
|
||||
bind(self, pview);
|
||||
install_custom_viewer_handlers();
|
||||
refresh();
|
||||
lookup_info.commit(e, form, view);
|
||||
}
|
||||
@ -382,13 +402,16 @@ public:
|
||||
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);
|
||||
if ( _this == NULL || !lookup_info.find_by_py_view(NULL, NULL, _this) )
|
||||
return;
|
||||
|
||||
_this->jump_to_node(0);
|
||||
_this->jump_to_node(nid);
|
||||
}
|
||||
|
||||
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_ACTIVATE, GRCODE_HAVE_GOTFOCUS);
|
||||
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
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t ret(PyObject_CallMethod(self.o, (char *)S_ON_REFRESH, NULL));
|
||||
PyW_ShowCbErr(S_ON_REFRESH);
|
||||
if ( ret != NULL && PyObject_IsTrue(ret.o) )
|
||||
{
|
||||
// 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
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_GETTEXT, "i", node));
|
||||
PyW_ShowCbErr(S_ON_GETTEXT);
|
||||
if ( result == NULL )
|
||||
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();
|
||||
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);
|
||||
if ( ok )
|
||||
*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);
|
||||
}
|
||||
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;
|
||||
//
|
||||
case grcode_gotfocus:
|
||||
@ -701,28 +733,43 @@ int py_graph_t::gr_callback(int code, va_list va)
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
intvec_t *nodes = va_arg(va, intvec_t*);
|
||||
ret = on_creating_group(g, nodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok to create
|
||||
}
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
int old_group = va_arg(va, int);
|
||||
ret = on_deleting_group(g, old_group);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok to delete
|
||||
}
|
||||
break;
|
||||
//
|
||||
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*);
|
||||
int group = va_arg(va, int);
|
||||
bool expand = bool(va_arg(va, int));
|
||||
ret = on_group_visibility(g, group, expand);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0; // Ok.
|
||||
}
|
||||
break;
|
||||
//
|
||||
default:
|
||||
@ -844,10 +891,9 @@ class GraphViewer(CustomIDAMemo):
|
||||
|
||||
def AddCommand(self, title, hotkey):
|
||||
"""
|
||||
Adds a menu command to the graph. Call this command after the graph is shown (with Show()).
|
||||
Once a command is added, a command id is returned. The commands are handled inside the OnCommand() handler
|
||||
|
||||
@return: 0 on failure or the command id
|
||||
Deprecated: Use
|
||||
- register_action()
|
||||
- attach_action_to_popup()
|
||||
"""
|
||||
return _idaapi.pyg_add_command(self, title, hotkey)
|
||||
|
||||
@ -929,10 +975,9 @@ class GraphViewer(CustomIDAMemo):
|
||||
#
|
||||
# def OnCommand(self, cmd_id):
|
||||
# """
|
||||
# Triggered when a menu command is selected through the menu or its hotkey
|
||||
# @return: None
|
||||
# Deprecated
|
||||
# """
|
||||
# print "command:", cmd_id
|
||||
# pass
|
||||
#</pydoc>
|
||||
#</pycode(py_graph)>
|
||||
%}
|
||||
|
142
swig/hexrays.i
142
swig/hexrays.i
@ -57,6 +57,7 @@
|
||||
%ignore cexpr_t::cexpr_t(mbl_array_t *mba, const lvar_t &v);
|
||||
%ignore lvar_t::is_promoted_arg;
|
||||
%ignore lvar_t::lvar_t;
|
||||
%ignore vdloc_t::is_fpu_mreg;
|
||||
%ignore strtype_info_t::find_strmem;
|
||||
%ignore file_printer_t::_print;
|
||||
%ignore file_printer_t;
|
||||
@ -120,51 +121,72 @@ public:
|
||||
cexpr_t *cexpr const { return (cexpr_t *)self; }
|
||||
};
|
||||
|
||||
#define CITEM_MEMBER_REF(name) \
|
||||
name##_t *name const { return self->##name; }
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// swig doesn't very much like the way the union is done in this class so we need to wrap all these up.
|
||||
%extend cinsn_t {
|
||||
CITEM_MEMBER_REF(cblock)
|
||||
CITEM_MEMBER_REF(cexpr)
|
||||
CITEM_MEMBER_REF(cif)
|
||||
CITEM_MEMBER_REF(cfor)
|
||||
CITEM_MEMBER_REF(cwhile)
|
||||
CITEM_MEMBER_REF(cdo)
|
||||
CITEM_MEMBER_REF(cswitch)
|
||||
CITEM_MEMBER_REF(creturn)
|
||||
CITEM_MEMBER_REF(cgoto)
|
||||
CITEM_MEMBER_REF(casm)
|
||||
};
|
||||
#define CITEM_MEMBER_REF(name) \
|
||||
c##name##_t *c##name const { if ( self->op == cit_##name ) { return self->c##name; } else { return NULL; } }
|
||||
|
||||
%extend cinsn_t {
|
||||
CITEM_MEMBER_REF(block);
|
||||
CITEM_MEMBER_REF(expr);
|
||||
CITEM_MEMBER_REF(if);
|
||||
CITEM_MEMBER_REF(for);
|
||||
CITEM_MEMBER_REF(while);
|
||||
CITEM_MEMBER_REF(do);
|
||||
CITEM_MEMBER_REF(switch);
|
||||
CITEM_MEMBER_REF(return);
|
||||
CITEM_MEMBER_REF(goto);
|
||||
CITEM_MEMBER_REF(asm);
|
||||
};
|
||||
#undef CITEM_MEMBER_REF
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#define CEXPR_MEMBER_REF(type, 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 {
|
||||
CEXPR_MEMBER_REF(cnumber_t*, n)
|
||||
CEXPR_MEMBER_REF(fnumber_t*, fpc)
|
||||
const var_ref_t& v { return self->v; }
|
||||
CEXPR_MEMBER_REF(ea_t, obj_ea)
|
||||
CEXPR_MEMBER_REF(int, refwidth)
|
||||
CEXPR_MEMBER_REF(cexpr_t*, x)
|
||||
CEXPR_MEMBER_REF(cexpr_t*, y)
|
||||
CEXPR_MEMBER_REF(carglist_t*, a)
|
||||
CEXPR_MEMBER_REF(int, m)
|
||||
CEXPR_MEMBER_REF(cexpr_t*, z)
|
||||
CEXPR_MEMBER_REF(int, ptrsize)
|
||||
CEXPR_MEMBER_REF(cinsn_t*, insn)
|
||||
CEXPR_MEMBER_REF(char*, helper)
|
||||
CEXPR_MEMBER_REF(char*, string)
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(cnumber_t*, n, self->op == cot_num, NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(fnumber_t*, fpc, self->op == cot_fnum, NULL);
|
||||
var_ref_t* v const { if ( self->op == cot_var ) { return &self->v; } else { return NULL; } }
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(ea_t, obj_ea, self->op == cot_obj, BADADDR);
|
||||
CEXPR_MEMBER_REF(int, refwidth);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, x, op_uses_x(self->op), NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, y, op_uses_y(self->op), NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(carglist_t*, a, self->op == cot_call, NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(int, m, self->op == cot_memptr || self->op == cot_memref, 0);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(cexpr_t*, z, op_uses_z(self->op), NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(int, ptrsize, self->op == cot_ptr || self->op == cot_memptr, 0);
|
||||
CEXPR_MEMBER_REF(cinsn_t*, insn);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(char*, helper, self->op == cot_helper, NULL);
|
||||
CEXPR_CONDITIONAL_MEMBER_REF(char*, string, self->op == cot_str, NULL);
|
||||
};
|
||||
|
||||
#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 {
|
||||
CEXPR_MEMBER_REF(citem_t *, it)
|
||||
CEXPR_MEMBER_REF(lvar_t*, l)
|
||||
CEXPR_MEMBER_REF(cfunc_t*, f)
|
||||
const treeloc_t& loc { return self->loc; }
|
||||
CTREE_ITEM_MEMBER_REF(citem_t *, it);
|
||||
CTREE_CONDITIONAL_ITEM_MEMBER_REF(cexpr_t*, e, VDI_EXPR);
|
||||
CTREE_CONDITIONAL_ITEM_MEMBER_REF(cinsn_t*, i, VDI_EXPR);
|
||||
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
|
||||
to fix the at() return type, otherwise swig mistakenly thinks it is "cinsn_t *&" and nonsense ensues. */
|
||||
%extend qvector< cinsn_t *> {
|
||||
@ -305,24 +327,16 @@ static int hexrays_python_call(ref_t fct, ref_t args)
|
||||
{
|
||||
PYW_GIL_GET;
|
||||
|
||||
int result;
|
||||
int ecode1 = 0 ;
|
||||
|
||||
newref_t resultobj(PyEval_CallObject(fct.o, args.o));
|
||||
if ( resultobj == NULL )
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
msg("IDAPython: Hex-rays python callback raised an exception.\n");
|
||||
|
||||
// we can't do much else than clear the exception since this was not called from Python.
|
||||
// XXX: print stack trace?
|
||||
PyErr_Clear();
|
||||
PyErr_Print();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecode1 = SWIG_AsVal_int(resultobj.o, &result);
|
||||
if (SWIG_IsOK(ecode1))
|
||||
int result;
|
||||
if ( SWIG_IsOK(SWIG_AsVal_int(resultobj.o, &result)) )
|
||||
return result;
|
||||
|
||||
msg("IDAPython: Hex-rays python callback returned non-integer; value ignored.\n");
|
||||
return 0;
|
||||
}
|
||||
@ -508,6 +522,22 @@ static int idaapi __hexrays_python_callback(void *ud, hexrays_event_t event, va_
|
||||
ret = hexrays_python_call(fct, args);
|
||||
}
|
||||
break;
|
||||
case hxe_populating_popup:
|
||||
///< Populating popup menu. We can add menu items now.
|
||||
///< TForm *form
|
||||
///< TPopupMenu *popup_handle
|
||||
///< vdui_t *vu
|
||||
{
|
||||
TForm *form = va_arg(va, TForm *);
|
||||
TPopupMenu *pp = va_arg(va, TPopupMenu*);
|
||||
vdui_t *vdui = va_arg(va, vdui_t *);
|
||||
newref_t py_form(SWIG_NewPointerObj(SWIG_as_voidptr(form), SWIGTYPE_p_Forms__TForm, 0));
|
||||
newref_t py_popup(SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_Menus__TPopupMenu, 0));
|
||||
newref_t py_vdui(SWIG_NewPointerObj(SWIG_as_voidptr(vdui), SWIGTYPE_p_vdui_t, 0 ));
|
||||
newref_t py_args(Py_BuildValue("(iOOO)", event, py_form.o, py_popup.o, py_vdui.o));
|
||||
ret = hexrays_python_call(fct, py_args);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//~ msg("IDAPython: Unknown event `%u' occured\n", event);
|
||||
ret = 0;
|
||||
@ -677,17 +707,37 @@ cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf);
|
||||
%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::find_ptr_or_array(bool) const;
|
||||
|
||||
#pragma SWIG nowarn=503
|
||||
%warnfilter(514) user_lvar_visitor_t; // Director base class 'x' has no virtual destructor.
|
||||
%warnfilter(514) ctree_visitor_t; // ditto
|
||||
%warnfilter(514) ctree_parentee_t; // ditto
|
||||
%warnfilter(514) cfunc_parentee_t; // ditto
|
||||
%warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended.
|
||||
|
||||
%feature("director") ctree_visitor_t;
|
||||
%feature("director") ctree_parentee_t;
|
||||
%feature("director") cfunc_parentee_t;
|
||||
%feature("director") user_lvar_visitor_t;
|
||||
|
||||
// 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"
|
||||
%exception; // Delete & restore handlers
|
||||
%exception_set_default_handlers();
|
||||
|
||||
%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_iflags_t, 'user_iflags', citem_locator_t, (int, long))
|
||||
_map_as_dict(user_unions_t, 'user_unions', (int, long), intvec_t)
|
||||
_map_as_dict(eamap_t, 'eamap', int, cinsnptrvec_t)
|
||||
_map_as_dict(eamap_t, 'eamap', long, cinsnptrvec_t)
|
||||
#_map_as_dict(boundaries_t, 'boundaries', cinsn_t, areaset_t)
|
||||
|
||||
%}
|
||||
|
410
swig/idaapi.i
410
swig/idaapi.i
@ -17,10 +17,73 @@
|
||||
#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory
|
||||
|
||||
%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
|
||||
%feature(autodoc,0);
|
||||
|
||||
%{
|
||||
/* strnlen() arrived on OSX at v10.7. Provide it ourselves if needed. */
|
||||
#ifdef __MAC__
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
#define MAC_OS_X_VERSION_10_7 1070
|
||||
#endif
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
|
||||
inline size_t strnlen(const char *s, size_t maxlen)
|
||||
{
|
||||
const char *found = (const char *) memchr(s, 0, maxlen);
|
||||
return found != NULL ? size_t(found - s) : maxlen;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
%}
|
||||
|
||||
%define SWIG_DECLARE_PY_CLINKED_OBJECT(type)
|
||||
%inline %{
|
||||
static PyObject *type##_create()
|
||||
@ -59,10 +122,6 @@ static PyObject *type##_get_clink_ptr(PyObject *self)
|
||||
%{
|
||||
#include <Python.h>
|
||||
|
||||
#ifndef USE_DANGEROUS_FUNCTIONS
|
||||
#define USE_DANGEROUS_FUNCTIONS 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSIZE_T
|
||||
#define _SSIZE_T_DEFINED 1
|
||||
#endif
|
||||
@ -102,6 +161,7 @@ static PyObject *type##_get_clink_ptr(PyObject *self)
|
||||
#include "strlist.hpp"
|
||||
#include "struct.hpp"
|
||||
#include "typeinf.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "ua.hpp"
|
||||
#include "xref.hpp"
|
||||
#include "ieee.h"
|
||||
@ -174,323 +234,6 @@ struct scfld_t
|
||||
#define FT_BAD_TYPE -2
|
||||
#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(
|
||||
const ref_t &py_list,
|
||||
@ -1165,9 +908,6 @@ bool pyw_convert_idc_args(
|
||||
{
|
||||
// PyTuple_SetItem() steals the reference.
|
||||
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);
|
||||
}
|
||||
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_SWITCHED[] = "OnViewSwitched";
|
||||
static const char S_ON_VIEW_MOUSE_OVER[] = "OnViewMouseOver";
|
||||
static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved";
|
||||
|
||||
|
||||
#ifdef __PYWRAPS__
|
||||
@ -2693,7 +2434,7 @@ class __IDAPython_Completion_Util(object):
|
||||
|
||||
return s
|
||||
|
||||
# Instantiate a completion object
|
||||
# Instantiate an IDAPython command completion object (for use with IDA's CLI bar)
|
||||
IDAPython_Completion = __IDAPython_Completion_Util()
|
||||
|
||||
def _listify_types(*classes):
|
||||
@ -2775,6 +2516,17 @@ NW_REMOVE = 0x0010
|
||||
|
||||
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(py_idaapi)>
|
||||
@ -2797,12 +2549,7 @@ static PyObject *py_parse_command_line(const char *cmdline)
|
||||
qstrvec_t args;
|
||||
if ( parse_command_line3(cmdline, &args, NULL, LP_PATH_WITH_ARGS) == 0 )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
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;
|
||||
return qstrvec2pylist(args);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -3035,3 +2782,4 @@ static bool notify_when(int when, PyObject *py_callable)
|
||||
%include "view.i"
|
||||
%include "graph.i"
|
||||
%include "fpro.i"
|
||||
%include "registry.i"
|
||||
|
96
swig/idp.i
96
swig/idp.i
@ -53,8 +53,6 @@
|
||||
t = AREACB_TYPE_SEGMENT;
|
||||
else if ( $self == &hidden_areas )
|
||||
t = AREACB_TYPE_HIDDEN_AREA;
|
||||
else if ( $self == &SRareas )
|
||||
t = AREACB_TYPE_SRAREA;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@ -807,6 +805,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void auto_empty_finally()
|
||||
{
|
||||
}
|
||||
|
||||
virtual int rename(ea_t ea, const char *new_name)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
@ -893,38 +904,38 @@ public:
|
||||
return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
|
||||
}
|
||||
// Hook functions to override in Python
|
||||
virtual int byte_patched(ea_t /*ea*/) { return 0; };
|
||||
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
|
||||
virtual int byte_patched(ea_t /*ea*/) { 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 ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
|
||||
virtual int enum_created(enum_t /*id*/) { return 0; };
|
||||
virtual int enum_deleted(enum_t /*id*/) { return 0; };
|
||||
virtual int enum_bf_changed(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_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 struc_created(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_expanded(struc_t * /*sptr*/) { 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_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_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { 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_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 func_noret_changed(func_t * /*pfn*/) { return 0; };
|
||||
virtual int segm_added(segment_t * /*s*/) { return 0; };
|
||||
virtual int segm_deleted(ea_t /*startEA*/) { 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_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; };
|
||||
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; }
|
||||
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; }
|
||||
virtual int enum_created(enum_t /*id*/) { return 0; }
|
||||
virtual int enum_deleted(enum_t /*id*/) { return 0; }
|
||||
virtual int enum_bf_changed(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_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 struc_created(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_expanded(struc_t * /*sptr*/) { 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_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_changed(struc_t * /*sptr*/, member_t * /*mptr*/) { 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_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 func_noret_changed(func_t * /*pfn*/) { return 0; }
|
||||
virtual int segm_added(segment_t * /*s*/) { return 0; }
|
||||
virtual int segm_deleted(ea_t /*startEA*/) { 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_moved(ea_t /*from*/, ea_t /*to*/, asize_t /*size*/) { return 0; }
|
||||
};
|
||||
|
||||
//</inline(py_idp)>
|
||||
@ -1011,6 +1022,12 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
|
||||
break;
|
||||
}
|
||||
|
||||
case processor_t::auto_empty_finally:
|
||||
{
|
||||
proxy->auto_empty_finally();
|
||||
break;
|
||||
}
|
||||
|
||||
case processor_t::rename:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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:
|
||||
{
|
||||
func_t *func = va_arg(va, func_t *);
|
||||
|
823
swig/kernwin.i
823
swig/kernwin.i
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,9 @@
|
||||
%ignore save_line_in_array;
|
||||
%ignore init_lines_array;
|
||||
%ignore finish_makeline;
|
||||
%ignore finish_makeline_ex;
|
||||
%ignore generate_many_lines_ex;
|
||||
%ignore MakeNull_ex;
|
||||
%ignore gen_labeled_line;
|
||||
%ignore gen_lname_line;
|
||||
%ignore makeline_producer_t;
|
||||
@ -43,6 +46,7 @@
|
||||
%ignore term_lines;
|
||||
%ignore gl_namedone;
|
||||
%ignore data_as_stack;
|
||||
%ignore unhide_hint_text;
|
||||
%ignore calc_stack_alignment;
|
||||
%ignore align_down_to_stack;
|
||||
%ignore align_up_to_stack;
|
||||
|
@ -111,6 +111,7 @@
|
||||
%ignore is_embedded_dbfile_ext;
|
||||
%ignore cpp_namespaces;
|
||||
%ignore max_trusted_idb_count;
|
||||
%ignore no_disk_space_handler;
|
||||
|
||||
%ignore mem2base;
|
||||
%rename (mem2base) py_mem2base;
|
||||
|
108
swig/nalt.i
108
swig/nalt.i
@ -6,12 +6,120 @@
|
||||
%ignore NALT_EA;
|
||||
%ignore 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_handlers_t;
|
||||
%ignore register_custom_refinfo;
|
||||
%ignore unregister_custom_refinfo;
|
||||
%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>;
|
||||
|
||||
%extend strpath_t {
|
||||
|
@ -4,6 +4,7 @@
|
||||
%ignore RootNode;
|
||||
%ignore for_all_supvals;
|
||||
%ignore netErrorHandler;
|
||||
%ignore netNoDiskSpaceHandler;
|
||||
%ignore netnode_key_count;
|
||||
|
||||
%ignore netnode_check;
|
||||
|
@ -2,7 +2,7 @@
|
||||
%ignore QueueGet;
|
||||
|
||||
// Kernel-only & unexported symbols
|
||||
%ignore QueueDel;
|
||||
%ignore QueueDel(ea_t);
|
||||
%ignore init_queue;
|
||||
%ignore save_queue;
|
||||
%ignore term_queue;
|
||||
|
145
swig/registry.i
Normal file
145
swig/registry.i
Normal 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"
|
@ -1,14 +1,44 @@
|
||||
// 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 init_srarea;
|
||||
%ignore term_srarea;
|
||||
%ignore reset_srarea;
|
||||
%ignore add_srarea_from_cache;
|
||||
%ignore srareas_got_loaded;
|
||||
%ignore save_srarea;
|
||||
%ignore create_segment_registers_area;
|
||||
%ignore set_segment_register_start;
|
||||
%ignore set_segment_register_end;
|
||||
%ignore kill_srareras;
|
||||
%ignore create_srarea;
|
||||
%ignore del_srareas;
|
||||
%ignore move_srareas;
|
||||
%ignore delete_v660_segreg_t;
|
||||
%ignore v660_segreg_t;
|
||||
|
||||
%ignore SRareas_get_area;
|
||||
%ignore SRareas_get_area_qty;
|
||||
%ignore SRareas_getn_area;
|
||||
%ignore SRareas_update;
|
||||
%ignore SRareas_get_area_num;
|
||||
%ignore SRareas_get_next_area;
|
||||
%ignore SRareas_get_prev_area;
|
||||
%ignore SRareas_next_area_ptr;
|
||||
%ignore SRareas_prev_area_ptr;
|
||||
%ignore SRareas_first_area_ptr;
|
||||
%ignore SRareas_choose_area2;
|
||||
%ignore SRareas_may_start_at;
|
||||
%ignore SRareas_may_end_at;
|
||||
%ignore SRareas_set_start;
|
||||
%ignore SRareas_set_end;
|
||||
%ignore SRareas_prepare_to_create;
|
||||
%ignore SRareas_create_area;
|
||||
%ignore SRareas_for_all_areas2;
|
||||
%ignore SRareas_del_area;
|
||||
|
||||
%ignore segreg_t::tag(int n);
|
||||
%ignore segreg_t::reg(int n);
|
||||
|
||||
#define R_es 29
|
||||
#define R_cs 30
|
||||
|
@ -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
|
||||
%typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) {
|
||||
@ -39,10 +66,6 @@
|
||||
$1 = ($1_ltype) qalloc(MAXSTR+1);
|
||||
}
|
||||
|
||||
%typemap(out) ssize_t {
|
||||
/* REMOVING ssize_t return value in $symname */
|
||||
}
|
||||
|
||||
%typemap(argout) (TYPEMAP,SIZE) {
|
||||
Py_XDECREF(resultobj);
|
||||
if (result > 0)
|
||||
@ -88,9 +111,6 @@
|
||||
%typemap(in,numinputs=0) (TYPEMAP, SIZE) {
|
||||
$1 = (char *) qalloc(MAXSPECSIZE+1);
|
||||
}
|
||||
%typemap(out) ssize_t {
|
||||
/* REMOVING ssize_t return value in $symname */
|
||||
}
|
||||
%typemap(argout) (TYPEMAP,SIZE) {
|
||||
Py_XDECREF(resultobj);
|
||||
if (result > 0)
|
||||
@ -115,9 +135,6 @@
|
||||
%typemap(in,numinputs=0) (TYPEMAP, SIZE) {
|
||||
$1 = (char *) qalloc(MAXSPECSIZE+1);
|
||||
}
|
||||
%typemap(out) ssize_t {
|
||||
/* REMOVING ssize_t return value in $symname */
|
||||
}
|
||||
%typemap(argout) (TYPEMAP,SIZE) {
|
||||
Py_XDECREF(resultobj);
|
||||
if (result)
|
||||
@ -166,8 +183,6 @@
|
||||
}
|
||||
$1 = $input;
|
||||
}
|
||||
|
||||
// Convert ea_t
|
||||
%typemap(in) ea_t
|
||||
{
|
||||
uint64 $1_temp;
|
||||
@ -178,6 +193,10 @@
|
||||
}
|
||||
$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
|
||||
@ -208,6 +227,15 @@
|
||||
%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__
|
||||
%apply longlong *INOUT { sval_t *value };
|
||||
@ -221,6 +249,14 @@
|
||||
%apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection()
|
||||
#endif
|
||||
|
||||
%apply qstring *result { qstring *label };
|
||||
%apply qstring *result { qstring *shortcut };
|
||||
%apply qstring *result { qstring *tooltip };
|
||||
%apply 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
|
||||
|
175
swig/typeinf.i
175
swig/typeinf.i
@ -71,7 +71,6 @@
|
||||
%ignore argloc_t::dstr;
|
||||
|
||||
%ignore extract_pstr;
|
||||
%ignore extract_name;
|
||||
%ignore skipName;
|
||||
%ignore extract_comment;
|
||||
%ignore skipComment;
|
||||
@ -180,43 +179,78 @@
|
||||
%{
|
||||
//<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
|
||||
// associated, in the kernel, with the tinfo_t instances.
|
||||
//
|
||||
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
|
||||
// closed, but the "type details" must be cleared _before_ the IDB is closed.
|
||||
static qvector<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)
|
||||
{
|
||||
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that
|
||||
// were not done here, ~tinfo_t() calls happening as part of the python shutdown
|
||||
// process will try and clear() their details. ..but the kernel's til-related
|
||||
// functions will already have deleted those details at that point.
|
||||
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i )
|
||||
python_tinfos[i]->clear();
|
||||
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t
|
||||
// Pre-emptive strike: clear all the python-exposed tinfo_t
|
||||
// (& related types) instances: if that were not done here,
|
||||
// ~tinfo_t() calls happening as part of the python shutdown
|
||||
// process will try and clear() their details. ..but the kernel's
|
||||
// til-related functions will already have deleted those details
|
||||
// at that point.
|
||||
//
|
||||
// NOTE: Don't clear() the arrays of pointers. All the python-exposed
|
||||
// instances will be deleted through the python shutdown/ref-decrementing
|
||||
// process anyway (which will cause til_deregister_..() calls), and the
|
||||
// entries will be properly pulled out of the vector when that happens.
|
||||
#define BATCH_CLEAR(Type) \
|
||||
do \
|
||||
{ \
|
||||
for ( size_t i = 0, n = py_##Type##_vec.size(); i < n; ++i ) \
|
||||
__clear(py_##Type##_vec[i]); \
|
||||
} while ( false )
|
||||
|
||||
BATCH_CLEAR(tinfo_t);
|
||||
BATCH_CLEAR(ptr_type_data_t);
|
||||
BATCH_CLEAR(array_type_data_t);
|
||||
BATCH_CLEAR(func_type_data_t);
|
||||
BATCH_CLEAR(udt_type_data_t);
|
||||
#undef BATCH_CLEAR
|
||||
}
|
||||
|
||||
void til_register_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
// Let's add_unique() it, because every reference to an object's
|
||||
// tinfo_t property will end up trying to register it.
|
||||
python_tinfos.add_unique(tif);
|
||||
}
|
||||
|
||||
void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif);
|
||||
if ( found != python_tinfos.end() )
|
||||
{
|
||||
tif->clear();
|
||||
python_tinfos.erase(found);
|
||||
#define DEF_REG_UNREG_REFCOUNTED(Type) \
|
||||
void til_register_python_##Type##_instance(Type *inst) \
|
||||
{ \
|
||||
/* Let's add_unique() it, because in the case of tinfo_t, every reference*/ \
|
||||
/* to an object's tinfo_t property will end up trying to register it. */ \
|
||||
py_##Type##_vec.add_unique(inst); \
|
||||
} \
|
||||
\
|
||||
void til_deregister_python_##Type##_instance(Type *inst) \
|
||||
{ \
|
||||
qvector<Type*>::iterator found = py_##Type##_vec.find(inst); \
|
||||
if ( found != py_##Type##_vec.end() ) \
|
||||
{ \
|
||||
__clear(inst); \
|
||||
/* tif->clear();*/ \
|
||||
py_##Type##_vec.erase(found); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
|
||||
DEF_REG_UNREG_REFCOUNTED(tinfo_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(ptr_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(array_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(func_type_data_t);
|
||||
DEF_REG_UNREG_REFCOUNTED(udt_type_data_t);
|
||||
|
||||
#undef DEF_REG_UNREG_REFCOUNTED
|
||||
|
||||
//</code(py_typeinf)>
|
||||
%}
|
||||
@ -245,6 +279,34 @@ void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
|
||||
}
|
||||
%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"
|
||||
|
||||
// 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)
|
||||
"""
|
||||
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_fields: type fields
|
||||
@param py_fields: fields string (may be empty or None)
|
||||
@param ea: the address of the object
|
||||
@param flags: combination of TINFO_... constants or 0
|
||||
@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)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
return rc;
|
||||
}
|
||||
@ -395,7 +484,7 @@ PyObject *py_unpack_object_from_idb(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -407,7 +496,7 @@ PyObject *py_unpack_object_from_idb(
|
||||
|
||||
// Unpack
|
||||
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;
|
||||
error_t err;
|
||||
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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@param tp: type string
|
||||
@param fields: type fields
|
||||
@param fields: fields string (may be empty or None)
|
||||
@param bytes: the bytes to unpack
|
||||
@param pio_flags: flags used while unpacking
|
||||
@return:
|
||||
@ -463,7 +552,7 @@ PyObject *py_unpack_object_from_bv(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -475,7 +564,7 @@ PyObject *py_unpack_object_from_bv(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@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 pio_flags: flags used while unpacking
|
||||
"""
|
||||
@ -535,7 +624,7 @@ PyObject *py_pack_object_to_idb(
|
||||
int pio_flags = 0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -553,7 +642,7 @@ PyObject *py_pack_object_to_idb(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
// 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
|
||||
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
|
||||
@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 pio_flags: flags used while unpacking
|
||||
@return:
|
||||
@ -592,7 +681,7 @@ PyObject *py_pack_object_to_bv(
|
||||
int pio_flags=0)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -610,7 +699,7 @@ PyObject *py_pack_object_to_bv(
|
||||
|
||||
// Get type strings
|
||||
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
|
||||
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)
|
||||
{
|
||||
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!");
|
||||
return NULL;
|
||||
@ -766,7 +855,7 @@ PyObject *idc_print_type(PyObject *py_type, PyObject *py_fields, const char *nam
|
||||
|
||||
qstring res;
|
||||
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;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
tinfo_t tif;
|
||||
|
64
swig/ua.i
64
swig/ua.i
@ -18,7 +18,6 @@
|
||||
%ignore out_insert;
|
||||
%ignore get_immval;
|
||||
%ignore get_spoiled_reg;
|
||||
%ignore construct_macro;
|
||||
%ignore decode_preceding_insn;
|
||||
%ignore init_ua;
|
||||
%ignore term_ua;
|
||||
@ -30,6 +29,9 @@
|
||||
%ignore get_immval;
|
||||
%ignore ua_stkvar;
|
||||
|
||||
%ignore construct_macro;
|
||||
%rename (construct_macro) py_construct_macro;
|
||||
|
||||
%include "ua.hpp"
|
||||
|
||||
%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);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<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)
|
||||
{
|
||||
@ -913,7 +958,6 @@ op_t *op_t_get_clink(PyObject *self)
|
||||
{
|
||||
return (op_t *)pyobj_get_clink(self);
|
||||
}
|
||||
|
||||
//</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_far = 6 # Immediate Far Address (CODE) addr
|
||||
o_near = 7 # Immediate Near Address (CODE) addr
|
||||
o_idpspec0 = 8 # IDP specific type
|
||||
o_idpspec1 = 9 # IDP specific type
|
||||
o_idpspec2 = 10 # IDP specific type
|
||||
o_idpspec3 = 11 # IDP specific type
|
||||
o_idpspec4 = 12 # IDP specific type
|
||||
o_idpspec5 = 13 # IDP specific type
|
||||
o_last = 14 # first unused type
|
||||
o_idpspec0 = 8 # Processor specific type
|
||||
o_idpspec1 = 9 # Processor specific type
|
||||
o_idpspec2 = 10 # Processor specific type
|
||||
o_idpspec3 = 11 # Processor specific type
|
||||
o_idpspec4 = 12 # Processor specific type
|
||||
o_idpspec5 = 13 # Processor specific type
|
||||
# There can be more processor specific types
|
||||
|
||||
#
|
||||
# op_t.dtyp
|
||||
@ -1405,7 +1449,7 @@ class processor_t(pyidc_opaque_object_t):
|
||||
short processor names similar to the one in ph.psnames.
|
||||
This method can be overridden to return to the kernel a different IDP description.
|
||||
"""
|
||||
return self.plnames[0] + ':' + ':'.join(self.psnames)
|
||||
return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames)))
|
||||
|
||||
def get_uFlag(self):
|
||||
"""Use this utility function to retrieve the 'uFlag' global variable"""
|
||||
|
240
swig/view.i
240
swig/view.i
@ -137,12 +137,16 @@ class py_customidamemo_t
|
||||
GRBASE_HAVE_CLOSE = 0x080,
|
||||
GRBASE_HAVE_VIEW_SWITCHED = 0x100,
|
||||
GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200,
|
||||
GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400,
|
||||
};
|
||||
|
||||
static void ensure_view_callbacks_installed();
|
||||
int cb_flags;
|
||||
// number of arguments for OnViewClick implementation
|
||||
int ovc_num_args;
|
||||
// number of arguments for:
|
||||
int ovc_num_args; // OnViewClick implementation
|
||||
int ovdc_num_args; // OnViewDblclick implementation
|
||||
int ovmo_num_args; // OnViewMouseOver implementation
|
||||
int ovmm_num_args; // OnViewMouseMoved implementation
|
||||
|
||||
protected:
|
||||
ref_t self;
|
||||
@ -176,11 +180,15 @@ protected:
|
||||
bool collect_pyobject_callbacks(PyObject *self);
|
||||
virtual void collect_class_callbacks_ids(callbacks_ids_t *out);
|
||||
|
||||
void install_custom_viewer_handlers();
|
||||
|
||||
// Bi-directionally bind/unbind the Python object and this controller.
|
||||
bool bind(PyObject *_self, TCustomControl *view);
|
||||
void unbind();
|
||||
|
||||
static lookup_info_t lookup_info;
|
||||
friend TForm *pycim_get_tform(PyObject *self);
|
||||
friend TCustomControl *pycim_get_tcustom_control(PyObject *self);
|
||||
|
||||
public:
|
||||
py_customidamemo_t();
|
||||
@ -210,8 +218,16 @@ public:
|
||||
void on_view_close();
|
||||
void on_view_switched(tcc_renderer_type_t rt);
|
||||
void on_view_mouse_over(const view_mouse_event_t *event);
|
||||
void on_view_mouse_moved(const view_mouse_event_t *event);
|
||||
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
|
||||
int get_py_method_arg_count(char *method_name);
|
||||
|
||||
// View events that are bound with 'set_custom_viewer_handler()'.
|
||||
static void idaapi s_on_view_mouse_moved(
|
||||
TCustomControl *cv,
|
||||
int shift,
|
||||
view_mouse_event_t *e,
|
||||
void *ud);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -222,6 +238,9 @@ py_customidamemo_t::py_customidamemo_t()
|
||||
PYGLOG("%p: py_customidamemo_t()\n", this);
|
||||
ensure_view_callbacks_installed();
|
||||
ovc_num_args = -1;
|
||||
ovdc_num_args = -1;
|
||||
ovmo_num_args = -1;
|
||||
ovmm_num_args = -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -261,7 +280,7 @@ void py_customidamemo_t::ensure_view_callbacks_installed()
|
||||
py_view->on_view_keydown(key, state);
|
||||
}
|
||||
break;
|
||||
case view_popup:
|
||||
case obsolete_view_popup:
|
||||
py_view->on_view_popup();
|
||||
break;
|
||||
case view_click:
|
||||
@ -513,6 +532,18 @@ void py_customidamemo_t::unbind()
|
||||
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)
|
||||
{
|
||||
@ -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_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED);
|
||||
out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER);
|
||||
out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -566,9 +598,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
|
||||
if ( have > 0 && attr != NULL )
|
||||
cb_flags |= have;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::install_custom_viewer_handlers()
|
||||
{
|
||||
if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) )
|
||||
{
|
||||
// Set user-data
|
||||
set_custom_viewer_handler(view, CVH_USERDATA, (void *)this);
|
||||
|
||||
//
|
||||
set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#define CHK_EVT(flag_needed) \
|
||||
@ -576,10 +621,22 @@ bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o)
|
||||
return; \
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE()
|
||||
|
||||
|
||||
#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
|
||||
#define CHK_RES()
|
||||
#define CHK_RES() \
|
||||
do \
|
||||
{ \
|
||||
if (PyErr_Occurred()) \
|
||||
PyErr_Print(); \
|
||||
} while ( false )
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -631,13 +688,33 @@ void py_customidamemo_t::on_view_popup()
|
||||
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)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
|
||||
if ( ovc_num_args < 0 )
|
||||
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
|
||||
if ( ovc_num_args == 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(
|
||||
PyObject_CallMethod(
|
||||
@ -645,6 +722,7 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iiii",
|
||||
event->x, event->y, event->state, event->button));
|
||||
CHK_RES();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -654,14 +732,29 @@ void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
}
|
||||
CHK_RES();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK);
|
||||
if ( ovdc_num_args < 0 )
|
||||
ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK);
|
||||
if ( ovdc_num_args == 5 )
|
||||
{
|
||||
PyObject *rpos = build_renderer_pos_swig_proxy(event);
|
||||
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(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
@ -669,6 +762,7 @@ void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event)
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
CHK_RES();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -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;
|
||||
int icode;
|
||||
ref_t tuple;
|
||||
if ( item != NULL )
|
||||
if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY)
|
||||
&& item != NULL )
|
||||
{
|
||||
if ( item->is_node )
|
||||
{
|
||||
icode = 1;
|
||||
*out_icode = 1;
|
||||
tuple = newref_t(Py_BuildValue("(i)", item->node));
|
||||
}
|
||||
else
|
||||
{
|
||||
icode = 2;
|
||||
*out_icode = 2;
|
||||
tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
icode = 0;
|
||||
*out_icode = 0;
|
||||
tuple = newref_t(Py_BuildValue("()"));
|
||||
}
|
||||
return tuple;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER);
|
||||
if ( ovmo_num_args < 0 )
|
||||
ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER);
|
||||
if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY )
|
||||
return;
|
||||
|
||||
int icode;
|
||||
ref_t tuple = build_current_graph_item_tuple(&icode, event);
|
||||
if ( ovmo_num_args == 7 )
|
||||
{
|
||||
PyObject *rpos = build_renderer_pos_swig_proxy(event);
|
||||
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(
|
||||
self.o,
|
||||
(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_EVT
|
||||
@ -747,6 +885,10 @@ void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event)
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
return
|
||||
#define CHK_THIS_OR_NULL() \
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
return NULL;
|
||||
#define CHK_THIS_OR_NONE() \
|
||||
GET_THIS(); \
|
||||
if ( _this == NULL ) \
|
||||
@ -828,7 +970,28 @@ PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject
|
||||
return _this->set_groups_visibility(groups, expand, new_current);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
TForm *pycim_get_tform(PyObject *self)
|
||||
{
|
||||
CHK_THIS_OR_NULL();
|
||||
TForm *form = NULL;
|
||||
if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) )
|
||||
return NULL;
|
||||
return form;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
TCustomControl *pycim_get_tcustom_control(PyObject *self)
|
||||
{
|
||||
CHK_THIS_OR_NULL();
|
||||
TCustomControl *tcc = NULL;
|
||||
if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) )
|
||||
return NULL;
|
||||
return tcc;
|
||||
}
|
||||
|
||||
#undef CHK_THIS_OR_NONE
|
||||
#undef CHK_THIS_OR_NULL
|
||||
#undef CHK_THIS
|
||||
#undef GET_THIS
|
||||
|
||||
@ -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_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current);
|
||||
PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current);
|
||||
TForm *pycim_get_tform(PyObject *self);
|
||||
TCustomControl *pycim_get_tcustom_control(PyObject *self);
|
||||
//</inline(py_view_base)>
|
||||
%}
|
||||
|
||||
@ -959,6 +1124,23 @@ class CustomIDAMemo(object):
|
||||
"""
|
||||
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)>
|
||||
%}
|
||||
|
||||
@ -970,6 +1152,7 @@ class py_idaview_t : public py_customidamemo_t
|
||||
|
||||
public:
|
||||
static bool Bind(PyObject *self);
|
||||
static bool Unbind(PyObject *self);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -1015,24 +1198,43 @@ bool py_idaview_t::Bind(PyObject *self)
|
||||
if ( ok )
|
||||
{
|
||||
ok = py_view->collect_pyobject_callbacks(self);
|
||||
if ( !ok )
|
||||
if ( ok )
|
||||
py_view->install_custom_viewer_handlers();
|
||||
else
|
||||
delete py_view;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool py_idaview_t::Unbind(PyObject *self)
|
||||
{
|
||||
py_idaview_t *_this = view_extract_this<py_idaview_t>(self);
|
||||
if ( _this == NULL )
|
||||
return false;
|
||||
_this->unbind();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool pyidag_bind(PyObject *self)
|
||||
{
|
||||
return py_idaview_t::Bind(self);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool pyidag_unbind(PyObject *self)
|
||||
{
|
||||
return py_idaview_t::Unbind(self);
|
||||
}
|
||||
|
||||
//</code(py_idaview)>
|
||||
%}
|
||||
|
||||
%inline %{
|
||||
//<inline(py_idaview)>
|
||||
bool pyidag_bind(PyObject *self);
|
||||
bool pyidag_unbind(PyObject *self);
|
||||
//</inline(py_idaview)>
|
||||
%}
|
||||
|
||||
@ -1051,5 +1253,9 @@ class IDAViewWrapper(CustomIDAMemo):
|
||||
|
||||
def Bind(self):
|
||||
return _idaapi.pyidag_bind(self)
|
||||
|
||||
def Unbind(self):
|
||||
return _idaapi.pyidag_unbind(self)
|
||||
|
||||
#</pycode(py_idaview)>
|
||||
%}
|
||||
|
Loading…
Reference in New Issue
Block a user