mirror of
https://github.com/cemu-project/idapython.git
synced 2024-12-28 18:51:53 +01:00
IDAPython 1.5.3
- IDA Pro 6.2 support - added set_idc_func_ex(): it is now possible to add new IDC functions using Python - added visit_patched_bytes() (see ex_patch.py) - added support for the multiline text input control in the Form class - added support for the editable/readonly dropdown list control in the Form class - added execute_sync() to register a function call into the UI message queue - added execute_ui_requests() / check ex_uirequests.py - added add_hotkey() / del_hotkey() to bind Python methods to hotkeys - added register_timer()/unregister_timer(). Check ex_timer.py - added the IDC (Arrays) netnode manipulation layer into idc.py - added idautils.Structs() and StructMembers() generator functions - removed the "Run Python Statement" menu item. IDA now has a unified dialog. Use RunPlugin("python", 0) to invoke it manually. - better error messages for script plugins, loaders and processor modules - bugfix: Dbg_Hooks.dbg_run_to() was receiving wrong input - bugfix: A few Enum related functions were not properly working in idc.py - bugfix: GetIdaDirectory() and GetProcessName() were broken in idc.py - bugfix: idaapi.get_item_head() / idc.ItemHead() were not working
This commit is contained in:
parent
96cd02db6c
commit
1258fab948
@ -7,7 +7,7 @@ The IDAPython Team:
|
||||
|
||||
* Hex-Rays - http://www.hex-rays.com/ - <support@hex-rays.com>
|
||||
|
||||
Hex-Rays joined the project in September 2009 and started contributing.
|
||||
Hex-Rays joined the IDAPython project in September 2009 and started contributing.
|
||||
It is primarily maintained by Elias Bachaalany.
|
||||
|
||||
|
||||
@ -21,3 +21,4 @@ The IDAPython Team:
|
||||
Igor Skochinsky
|
||||
Sebastian Muniz
|
||||
cbwhiz
|
||||
Arnaud Diederen
|
||||
|
10
BUILDING.txt
10
BUILDING.txt
@ -1,6 +1,6 @@
|
||||
----------------------------------------------------------
|
||||
IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
----------------------------------------------------------
|
||||
------------------------------------------------------
|
||||
IDAPython - Python plugin for Interactive Disassembler
|
||||
------------------------------------------------------
|
||||
Building From Source
|
||||
--------------------
|
||||
|
||||
@ -36,10 +36,10 @@ BUILDING
|
||||
|
||||
Make sure all the needed tools (compiler, swig) are on the PATH.
|
||||
|
||||
1. Unpack the IDAPython source and IDA Pro SDK into the following
|
||||
1. Unpack the IDAPython source and IDA SDK into the following
|
||||
directory structure:
|
||||
|
||||
swigsdk-versions/x.y/ - A supported version of the IDA Pro SDK
|
||||
swigsdk-versions/x.y/ - A supported version of the IDA SDK
|
||||
idapython/ - IDAPython source code
|
||||
|
||||
2. On Mac OS X copy libida.dylib from the IDA install directory to
|
||||
|
22
CHANGES.txt
22
CHANGES.txt
@ -1,12 +1,32 @@
|
||||
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
|
||||
|
||||
|
||||
Changes from version 1.5.2 to 1.5.3
|
||||
------------------------------------
|
||||
- added set_idc_func_ex(): it is now possible to add new IDC functions using Python
|
||||
- added visit_patched_bytes() (see ex_patch.py)
|
||||
- added support for the multiline text input control in the Form class
|
||||
- added support for the editable/readonly dropdown list control in the Form class
|
||||
- added execute_sync() to register a function call into the UI message queue
|
||||
- added execute_ui_requests() / check ex_uirequests.py
|
||||
- added add_hotkey() / del_hotkey() to bind Python methods to hotkeys
|
||||
- added register_timer()/unregister_timer(). Check ex_timer.py
|
||||
- added the IDC (Arrays) netnode manipulation layer into idc.py
|
||||
- added idautils.Structs() and StructMembers() generator functions
|
||||
- removed the "Run Python Statment" menu item. IDA now has a unified dialog.
|
||||
Use RunPlugin("python", 0) to invoke it manually.
|
||||
- better error messages for script plugins, loaders and processor modules
|
||||
- bugfix: Dbg_Hooks.dbg_run_to() was receiving wrong input
|
||||
- bugfix: A few Enum related functions were not properly working in idc.py
|
||||
- bugfix: GetIdaDirectory() and GetProcessName() were broken in idc.py
|
||||
- bugfix: idaapi.get_item_head() / idc.ItemHead() were not working
|
||||
|
||||
Changes from version 1.5.1 to 1.5.2
|
||||
------------------------------------
|
||||
- added ui_term/ui_save/ui_saved/ui_get_ea_hint UI notifications
|
||||
- added ph_get_operand_info() to retrieve operand information while debugging
|
||||
- added PteDump.py script
|
||||
- some code refactoring
|
||||
- bugfix: read/write_dbg_memory() and dbg_get_thread_sreg_base() were not working with all debugger modules
|
||||
- bugfix: idaapi.netnode.getblob() was limited to MAXSPECSIZE
|
||||
- bugfix: idc.GetString()/idaapi.get_ascii_contents()/idautils.Strings() were limited to MAXSTR string length
|
||||
- bugfix: idaapi.del_menu_item() was failing to delete some menu items
|
||||
|
47
README.txt
47
README.txt
@ -1,8 +1,8 @@
|
||||
----------------------------------------------------------
|
||||
IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
----------------------------------------------------------
|
||||
------------------------------------------------------
|
||||
IDAPython - Python plugin for Interactive Disassembler
|
||||
------------------------------------------------------
|
||||
|
||||
WHAT IS IDAPTYHON?
|
||||
What is IDAPython?
|
||||
------------------
|
||||
|
||||
IDAPython is an IDA plugin which makes it possible to write scripts
|
||||
@ -12,7 +12,7 @@ access to both the IDA API and any installed Python module.
|
||||
Check the scripts in the examples directory to get an quick glimpse.
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
Availability
|
||||
------------
|
||||
|
||||
Latest stable versions of IDAPython are available from
|
||||
@ -22,7 +22,7 @@ Development builds are available from
|
||||
http://code.google.com/p/idapython/
|
||||
|
||||
|
||||
RESOURCES
|
||||
Resources
|
||||
---------
|
||||
|
||||
The full function cross-reference is readable online at
|
||||
@ -35,22 +35,23 @@ Mailing list for the project is hosted by Google Groups at
|
||||
http://groups.google.com/group/idapython
|
||||
|
||||
|
||||
INSTALLATION FROM BINARIES
|
||||
Installation from binaries
|
||||
--------------------------
|
||||
|
||||
1. Install 2.6 or 2.7 from http://www.python.org/
|
||||
2. Copy "python" directory to %IDADIR%
|
||||
3. Copy "plugins" directory to the %IDADIR%\plugins\
|
||||
2. Copy the whole "python" directory to %IDADIR%
|
||||
3. Copy the contents of the "plugins" directory to the %IDADIR%\plugins\
|
||||
4. Copy "python.cfg" to %IDADIR%\cfg
|
||||
|
||||
USAGE
|
||||
Usage
|
||||
-----
|
||||
|
||||
- Run script: File / Script file (Alt-F7)
|
||||
- Execute Python statement(s) (Ctrl-F3)
|
||||
- Run previously executed script again: View / Recent Scripts (Alt+F9)
|
||||
|
||||
Batch mode execution:
|
||||
|
||||
* Batch mode execution:
|
||||
|
||||
Start IDA with the following command line options:
|
||||
|
||||
@ -75,7 +76,7 @@ Where N can be:
|
||||
1: run script when UI is ready
|
||||
2: run script immediately on plugin load (shortly after IDA starts and before processor modules and loaders)
|
||||
|
||||
User init file:
|
||||
* User init file
|
||||
|
||||
You can place your custom settings to a file called 'idapythonrc.py'
|
||||
that should be placed to
|
||||
@ -89,3 +90,25 @@ or
|
||||
The user init file is read and executed at the end of the init process.
|
||||
|
||||
Please note that IDAPython can be configured with "python.cfg" file.
|
||||
|
||||
* Invoking Python from IDC
|
||||
|
||||
The IDAPython plugin exposes a new IDC function "RunPythonStatement(string idc_code)" that allows execution
|
||||
of Python code from IDC
|
||||
|
||||
* Invoking IDC from Python
|
||||
|
||||
It is possible to use the idc.Eval() to evaluate IDC expressions from Python
|
||||
|
||||
* Making Python the default language
|
||||
|
||||
By default, IDA will use IDC to evaluate expressions. It is possible to change the default language to use
|
||||
Python instead of IDC.
|
||||
|
||||
In order to do that, please use the following IDC code:
|
||||
|
||||
RunPlugin("python", 3)
|
||||
|
||||
To disable Python language and revert back to IDC:
|
||||
RunPlugin("python", 4)
|
||||
|
||||
|
@ -20,7 +20,7 @@ PLUGIN_TEST = 0
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Configuration file
|
||||
VT_CFGFILE = idaapi.get_user_idadir() + os.sep + "virustotal.cfg"
|
||||
VT_CFGFILE = os.path.join(idaapi.get_user_idadir(), "virustotal.cfg")
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# VirusTotal Icon in PNG format
|
||||
|
33
build.py
33
build.py
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#---------------------------------------------------------------------
|
||||
# IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
# IDAPython - Python plugin for Interactive Disassembler
|
||||
#
|
||||
# Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
# (c) The IDAPython Team <idapython@googlegroups.com>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
@ -24,19 +24,19 @@ from distutils import sysconfig
|
||||
VERBOSE = True
|
||||
|
||||
IDA_MAJOR_VERSION = 6
|
||||
IDA_MINOR_VERSION = 1
|
||||
IDA_MINOR_VERSION = 2
|
||||
|
||||
if 'IDA' in os.environ:
|
||||
IDA_SDK = os.environ['IDA']
|
||||
else:
|
||||
IDA_SDK = ".." + os.sep + "swigsdk-versions" + os.sep + "%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION)
|
||||
IDA_SDK = os.path.join("..", "swigsdk-versions", ("%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION)))
|
||||
|
||||
# End of user configurable options
|
||||
|
||||
# IDAPython version
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 5
|
||||
VERSION_PATCH = 2
|
||||
VERSION_PATCH = 3
|
||||
|
||||
# Determine Python version
|
||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||
@ -72,6 +72,8 @@ BINDIST_MANIFEST = [
|
||||
"docs/notes.txt",
|
||||
"examples/chooser.py",
|
||||
"examples/colours.py",
|
||||
"examples/ex_idphook_asm.py",
|
||||
"examples/ex_uirequests.py",
|
||||
"examples/debughook.py",
|
||||
"examples/ex_cli.py",
|
||||
"examples/ex1.idc",
|
||||
@ -87,6 +89,10 @@ BINDIST_MANIFEST = [
|
||||
"examples/ex_choose2.py",
|
||||
"examples/ex_debug_names.py",
|
||||
"examples/ex_graph.py",
|
||||
"examples/ex_hotkey.py",
|
||||
"examples/ex_patch.py",
|
||||
"examples/ex_expr.py",
|
||||
"examples/ex_timer.py",
|
||||
"examples/ex_dbg.py",
|
||||
"examples/ex_custview.py",
|
||||
"examples/ex_prefix_plugin.py",
|
||||
@ -94,6 +100,7 @@ BINDIST_MANIFEST = [
|
||||
"examples/ex_pyqt.py",
|
||||
"examples/ex_askusingform.py",
|
||||
"examples/ex_uihook.py",
|
||||
"examples/ex_idphook_asm.py",
|
||||
"examples/ex_imports.py"
|
||||
]
|
||||
|
||||
@ -216,7 +223,7 @@ class GCCBuilder(BuilderBase):
|
||||
self.include_delimiter = "-I"
|
||||
self.macro_delimiter = "-D"
|
||||
self.libpath_delimiter = "-L"
|
||||
self.compiler_parameters = "-fpermissive"
|
||||
self.compiler_parameters = "-fpermissive -Wno-write-strings"
|
||||
self.linker_parameters = "-shared"
|
||||
self.basemacros = [ ]
|
||||
self.compiler = "g++ -m32"
|
||||
@ -279,8 +286,8 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
|
||||
if type(f) == types.TupleType:
|
||||
srcfilepath = f[0]
|
||||
srcfilename = os.path.basename(srcfilepath)
|
||||
dstdir = distrootdir + os.sep + f[1]
|
||||
dstfilepath = dstdir + os.sep + srcfilename
|
||||
dstdir = os.path.join(distrootdir, f[1])
|
||||
dstfilepath = os.path.join(dstdir, srcfilename)
|
||||
else:
|
||||
srcfilepath = f
|
||||
srcfilename = os.path.basename(f)
|
||||
@ -288,12 +295,12 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
|
||||
if srcdir == "":
|
||||
dstdir = distrootdir
|
||||
else:
|
||||
dstdir = distrootdir + os.sep + srcdir
|
||||
dstdir = os.path.join(distrootdir, srcdir)
|
||||
|
||||
if not os.path.exists(dstdir):
|
||||
os.makedirs(dstdir)
|
||||
|
||||
dstfilepath = dstdir + os.sep + srcfilename
|
||||
dstfilepath = os.path.join(dstdir, srcfilename)
|
||||
shutil.copyfile(srcfilepath, dstfilepath)
|
||||
zip.write(dstfilepath)
|
||||
|
||||
@ -304,14 +311,14 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
global SWIG_OPTIONS
|
||||
""" Build the plugin from the SWIG wrapper and plugin main source """
|
||||
# Path to the IDA SDK headers
|
||||
ida_include_directory = idasdkdir + os.sep + "include"
|
||||
ida_include_directory = os.path.join(idasdkdir, "include")
|
||||
|
||||
builder = None
|
||||
# Platform-specific settings for the Linux build
|
||||
if platform == "linux":
|
||||
builder = GCCBuilder()
|
||||
platform_macros = [ "__LINUX__" ]
|
||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
||||
python_libpath = os.path.join(sysconfig.EXEC_PREFIX, "lib")
|
||||
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_linux_gcc_64" or "x86_linux_gcc_32")
|
||||
ida_lib = ""
|
||||
@ -320,7 +327,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
elif platform == "win32":
|
||||
builder = MSVCBuilder()
|
||||
platform_macros = [ "__NT__" ]
|
||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
||||
python_libpath = os.path.join(sysconfig.EXEC_PREFIX, "libs")
|
||||
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_win_vc_64" or "x86_win_vc_32")
|
||||
ida_lib = "ida.lib"
|
||||
|
@ -9,7 +9,7 @@ from idaapi import Choose
|
||||
|
||||
#
|
||||
# Modal chooser
|
||||
#
|
||||
#
|
||||
|
||||
# Get a modal Choose instance
|
||||
chooser = Choose([], "MyChooser", 1)
|
||||
@ -21,28 +21,30 @@ chooser.width = 50
|
||||
ch = chooser.choose()
|
||||
# Print the results
|
||||
if ch > 0:
|
||||
print "You chose %d which is %s" % (ch, chooser.list[ch-1])
|
||||
print "You chose %d which is %s" % (ch, chooser.list[ch-1])
|
||||
else:
|
||||
print "Escape from chooser"
|
||||
print "Escape from chooser"
|
||||
|
||||
#
|
||||
# Normal chooser
|
||||
#
|
||||
class MyChoose(Choose):
|
||||
"""
|
||||
You have to subclass Chooser to override the enter() method
|
||||
"""
|
||||
def __init__(self, list=[], name="Choose"):
|
||||
Choose.__init__(self, list, name)
|
||||
# Set the width
|
||||
self.width = 50
|
||||
"""
|
||||
You have to subclass Chooser to override the enter() method
|
||||
"""
|
||||
def __init__(self, list=[], name="Choose"):
|
||||
Choose.__init__(self, list, name)
|
||||
# Set the width
|
||||
self.width = 50
|
||||
self.deflt = 1
|
||||
|
||||
def enter(self, n):
|
||||
print "Enter called. Do some stuff here."
|
||||
print "The chosen item is %d = %s" % (n, self.list[n-1])
|
||||
print "Now press ESC to leave."
|
||||
def enter(self, n):
|
||||
print "Enter called. Do some stuff here."
|
||||
print "The chosen item is %d = %s" % (n, self.list[n-1])
|
||||
print "Now press ESC to leave."
|
||||
|
||||
# Get a Choose instance
|
||||
chooser = MyChoose([ "First", "Second", "Third" ], "MyChoose")
|
||||
|
||||
# Run the chooser
|
||||
ch = chooser.choose()
|
||||
|
@ -16,16 +16,17 @@ class MyDbgHook(DBG_Hooks):
|
||||
|
||||
def dbg_process_start(self, pid, tid, ea, name, base, size):
|
||||
print("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
|
||||
return 0
|
||||
|
||||
def dbg_process_exit(self, pid, tid, ea, code):
|
||||
print("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
|
||||
return 0
|
||||
|
||||
def dbg_library_unload(self, pid, tid, ea, info):
|
||||
print("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
|
||||
return 0
|
||||
|
||||
def dbg_process_attach(self, pid, tid, ea, name, base, size):
|
||||
print("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
|
||||
|
||||
def dbg_process_detach(self, pid, tid, ea):
|
||||
print("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
|
||||
return 0
|
||||
@ -57,15 +58,19 @@ class MyDbgHook(DBG_Hooks):
|
||||
|
||||
def dbg_trace(self, tid, ea):
|
||||
print("Trace tid=%d ea=0x%x" % (tid, ea))
|
||||
# return values:
|
||||
# 1 - do not log this trace event;
|
||||
# 0 - log it
|
||||
return 0
|
||||
|
||||
def dbg_step_into(self):
|
||||
print("Step into")
|
||||
return self.dbg_step_over()
|
||||
self.dbg_step_over()
|
||||
|
||||
def dbg_run_to(self, pid, tid=0, ea=0):
|
||||
print "Runto: tid=%d" % tid
|
||||
idaapi.continue_process()
|
||||
|
||||
# def dbg_run_to(self, tid):
|
||||
# print "Runto: tid=%d" % tid
|
||||
# idaapi.continue_process()
|
||||
|
||||
def dbg_step_over(self):
|
||||
eip = GetRegValue("EIP")
|
||||
@ -76,7 +81,7 @@ class MyDbgHook(DBG_Hooks):
|
||||
request_exit_process()
|
||||
else:
|
||||
request_step_over()
|
||||
return 0
|
||||
|
||||
|
||||
# Remove an existing debug hook
|
||||
try:
|
||||
|
@ -218,6 +218,148 @@ using address %$
|
||||
if ok == 1:
|
||||
print("You entered: %x" % num.value)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def test_multilinetext_legacy():
|
||||
# Here we text the multi line text control in legacy mode
|
||||
|
||||
# Sample form from kernwin.hpp
|
||||
s = """Sample dialog box
|
||||
|
||||
This is sample dialog box
|
||||
<Enter multi line text:t40:80:50::>
|
||||
"""
|
||||
# Use either StringArgument or NumericArgument to pass values to the function
|
||||
ti = textctrl_info_t("Some initial value")
|
||||
ok = idaapi.AskUsingForm(s, pointer(c_void_p.from_address(ti.clink_ptr)))
|
||||
if ok == 1:
|
||||
print("You entered: %s" % ti.text)
|
||||
|
||||
del ti
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class MyForm2(Form):
|
||||
"""Simple Form to test multilinetext and combo box controls"""
|
||||
def __init__(self):
|
||||
Form.__init__(self, r"""STARTITEM 0
|
||||
BUTTON YES* Yeah
|
||||
BUTTON NO Nope
|
||||
BUTTON CANCEL NONE
|
||||
Form Test
|
||||
|
||||
{FormChangeCb}
|
||||
<Multilinetext:{txtMultiLineText}>
|
||||
""", {
|
||||
'txtMultiLineText': Form.MultiLineTextControl(text="Hello"),
|
||||
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
|
||||
})
|
||||
|
||||
|
||||
def OnFormChange(self, fid):
|
||||
if fid == self.txtMultiLineText.id:
|
||||
pass
|
||||
elif fid == -2:
|
||||
ti = self.GetControlValue(self.txtMultiLineText)
|
||||
print "ti.text = %s" % ti.text
|
||||
else:
|
||||
print(">>fid:%d" % fid)
|
||||
return 1
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def test_multilinetext(execute=True):
|
||||
"""Test the multilinetext and combobox controls"""
|
||||
f = MyForm2()
|
||||
f, args = f.Compile()
|
||||
if execute:
|
||||
ok = f.Execute()
|
||||
else:
|
||||
print args[0]
|
||||
print args[1:]
|
||||
ok = 0
|
||||
|
||||
if ok == 1:
|
||||
assert f.txtMultiLineText.text == f.txtMultiLineText.value
|
||||
print f.txtMultiLineText.text
|
||||
|
||||
f.Free()
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class MyForm3(Form):
|
||||
"""Simple Form to test multilinetext and combo box controls"""
|
||||
def __init__(self):
|
||||
self.__n = 0
|
||||
Form.__init__(self,
|
||||
r"""BUTTON YES* Yeah
|
||||
BUTTON NO Nope
|
||||
BUTTON CANCEL NONE
|
||||
Dropdown list test
|
||||
|
||||
{FormChangeCb}
|
||||
<Dropdown list (readonly):{cbReadonly}> <Add element:{iButtonAddelement}> <Set index:{iButtonSetIndex}>
|
||||
<Dropdown list (editable):{cbEditable}> <Set string:{iButtonSetString}>
|
||||
""", {
|
||||
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
|
||||
'cbReadonly': Form.DropdownListControl(
|
||||
items=["red", "green", "blue"],
|
||||
readonly=True,
|
||||
selval=1),
|
||||
'cbEditable': Form.DropdownListControl(
|
||||
items=["1MB", "2MB", "3MB", "4MB"],
|
||||
readonly=False,
|
||||
selval="4MB"),
|
||||
'iButtonAddelement': Form.ButtonInput(self.OnButtonNop),
|
||||
'iButtonSetIndex': Form.ButtonInput(self.OnButtonNop),
|
||||
'iButtonSetString': Form.ButtonInput(self.OnButtonNop),
|
||||
})
|
||||
|
||||
|
||||
def OnButtonNop(self, code=0):
|
||||
"""Do nothing, we will handle events in the form callback"""
|
||||
pass
|
||||
|
||||
def OnFormChange(self, fid):
|
||||
if fid == self.iButtonSetString.id:
|
||||
s = idc.AskStr("none", "Enter value")
|
||||
if s:
|
||||
self.SetControlValue(self.cbEditable, s)
|
||||
elif fid == self.iButtonSetIndex.id:
|
||||
s = idc.AskStr("1", "Enter index value:")
|
||||
if s:
|
||||
try:
|
||||
i = int(s)
|
||||
except:
|
||||
i = 0
|
||||
self.SetControlValue(self.cbReadonly, i)
|
||||
elif fid == self.iButtonAddelement.id:
|
||||
# add a value to the string list
|
||||
self.__n += 1
|
||||
self.cbReadonly.add("some text #%d" % self.__n)
|
||||
# Refresh the control
|
||||
self.RefreshField(self.cbReadonly)
|
||||
elif fid == -2:
|
||||
s = self.GetControlValue(self.cbEditable)
|
||||
print "user entered: %s" % s
|
||||
sel_idx = self.GetControlValue(self.cbReadonly)
|
||||
|
||||
return 1
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def test_dropdown(execute=True):
|
||||
"""Test the combobox controls"""
|
||||
f = MyForm3()
|
||||
f, args = f.Compile()
|
||||
if execute:
|
||||
ok = f.Execute()
|
||||
else:
|
||||
print args[0]
|
||||
print args[1:]
|
||||
ok = 0
|
||||
|
||||
if ok == 1:
|
||||
print "Editable: %s" % f.cbEditable.value
|
||||
print "Readonly: %s" % f.cbReadonly.value
|
||||
|
||||
f.Free()
|
||||
|
||||
#</pycode(ex_askusingform)>
|
||||
|
||||
|
||||
|
@ -3,12 +3,13 @@ from idaapi import Choose2
|
||||
|
||||
class MyChoose2(Choose2):
|
||||
|
||||
def __init__(self, title, nb = 5):
|
||||
def __init__(self, title, nb = 5, deflt=1):
|
||||
Choose2.__init__(self, title, [ ["Address", 10], ["Name", 30] ])
|
||||
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.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
|
||||
print("created %s" % str(self))
|
||||
|
||||
@ -79,6 +80,6 @@ class MyChoose2(Choose2):
|
||||
return [0xFF0000, 0]
|
||||
|
||||
for i in xrange(1, 5+1):
|
||||
c = MyChoose2("choose2 - sample %d" % i, i*2)
|
||||
c = MyChoose2("choose2 - sample %d" % i, i*2, deflt=i)
|
||||
r = c.show()
|
||||
print r
|
||||
|
16
examples/ex_expr.py
Normal file
16
examples/ex_expr.py
Normal file
@ -0,0 +1,16 @@
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to extend IDC from Python
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import set_idc_func_ex
|
||||
|
||||
#<pycode(ex_expr)>
|
||||
def py_power(n, e):
|
||||
return n ** e
|
||||
|
||||
ok = set_idc_func_ex("pow", py_power, (idaapi.VT_LONG, idaapi.VT_LONG), 0)
|
||||
if ok:
|
||||
print("Now the pow() will be present IDC!")
|
||||
else:
|
||||
print("Failed to register pow() IDC function")
|
||||
#</pycode(ex_expr)>
|
25
examples/ex_hotkey.py
Normal file
25
examples/ex_hotkey.py
Normal file
@ -0,0 +1,25 @@
|
||||
#---------------------------------------------------------------------
|
||||
# This script demonstrates the usage of hotkeys.
|
||||
#
|
||||
#
|
||||
# Author: IDAPython team
|
||||
#---------------------------------------------------------------------
|
||||
import idaapi
|
||||
|
||||
def hotkey_pressed():
|
||||
print("hotkey pressed!")
|
||||
|
||||
try:
|
||||
hotkey_ctx
|
||||
if idaapi.del_hotkey(hotkey_ctx):
|
||||
print("Hotkey unregistered!")
|
||||
del hotkey_ctx
|
||||
else:
|
||||
print("Failed to delete hotkey!")
|
||||
except:
|
||||
hotkey_ctx = idaapi.add_hotkey("Shift-A", hotkey_pressed)
|
||||
if hotkey_ctx is None:
|
||||
print("Failed to register hotkey!")
|
||||
del hotkey_ctx
|
||||
else:
|
||||
print("Hotkey registered!")
|
48
examples/ex_idphook_asm.py
Normal file
48
examples/ex_idphook_asm.py
Normal file
@ -0,0 +1,48 @@
|
||||
import idaapi
|
||||
import idautils
|
||||
|
||||
"""
|
||||
This is a sample plugin for extending the assemble().
|
||||
|
||||
We add support for assembling the following pseudo instructions:
|
||||
- "zero eax" -> xor eax, eax
|
||||
- "nothing" -> nop
|
||||
|
||||
|
||||
(c) Hex-Rays
|
||||
"""
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
class assemble_idp_hook_t(idaapi.IDP_Hooks):
|
||||
def __init__(self):
|
||||
idaapi.IDP_Hooks.__init__(self)
|
||||
|
||||
def assemble(self, ea, cs, ip, use32, line):
|
||||
line = line.strip()
|
||||
if line == "xor eax, eax":
|
||||
return "\x33\xC0"
|
||||
elif line == "nop":
|
||||
# Decode current instruction to figure out its size
|
||||
cmd = idautils.DecodeInstruction(ea)
|
||||
if cmd:
|
||||
# NOP all the instruction bytes
|
||||
return "\x90" * cmd.size
|
||||
return None
|
||||
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Remove an existing hook on second run
|
||||
try:
|
||||
idp_hook_stat = "un"
|
||||
print("IDP hook: checking for hook...")
|
||||
idphook
|
||||
print("IDP hook: unhooking....")
|
||||
idphook.unhook()
|
||||
del idphook
|
||||
except:
|
||||
print("IDP hook: not installed, installing now....")
|
||||
idp_hook_stat = ""
|
||||
idphook = assemble_idp_hook_t()
|
||||
idphook.hook()
|
||||
|
||||
print("IDP hook %sinstalled. Run the script again to %sinstall" % (idp_hook_stat, idp_hook_stat))
|
36
examples/ex_patch.py
Normal file
36
examples/ex_patch.py
Normal file
@ -0,0 +1,36 @@
|
||||
# -------------------------------------------------------------------------
|
||||
# This is an example illustrating how to visit all patched bytes in Python
|
||||
# (c) Hex-Rays
|
||||
|
||||
import idaapi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
class patched_bytes_visitor(object):
|
||||
def __init__(self):
|
||||
self.skip = 0
|
||||
self.patch = 0
|
||||
|
||||
def __call__(self, ea, fpos, o, v, cnt=()):
|
||||
if fpos == -1:
|
||||
self.skip += 1
|
||||
print(" ea: %x o: %x v: %x...skipped" % (ea, fpos, o, v))
|
||||
else:
|
||||
self.patch += 1
|
||||
print(" ea: %x fpos: %x o: %x v: %x" % (ea, fpos, o, v))
|
||||
return 0
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
def main():
|
||||
print("Visiting all patched bytes:")
|
||||
v = patched_bytes_visitor()
|
||||
r = idaapi.visit_patched_bytes(0, idaapi.BADADDR, v)
|
||||
if r != 0:
|
||||
print("visit_patched_bytes() returned %d" % r)
|
||||
else:
|
||||
print("Patched: %d Skipped: %d" % (v.patch, v.skip))
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
38
examples/ex_timer.py
Normal file
38
examples/ex_timer.py
Normal file
@ -0,0 +1,38 @@
|
||||
# -------------------------------------------------------------------------
|
||||
# This is an example illustrating how to use timers
|
||||
# (c) Hex-Rays
|
||||
|
||||
import idaapi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
class timercallback_t(object):
|
||||
def __init__(self):
|
||||
self.interval = 1000
|
||||
self.obj = idaapi.register_timer(self.interval, self)
|
||||
if self.obj is None:
|
||||
raise RuntimeError, "Failed to register timer"
|
||||
self.times = 5
|
||||
|
||||
def __call__(self):
|
||||
print("Timer invoked. %d time(s) left" % self.times)
|
||||
self.times -= 1
|
||||
# Unregister the timer when the counter reaches zero
|
||||
return -1 if self.times == 0 else self.interval
|
||||
|
||||
def __del__(self):
|
||||
print("Timer object disposed %s" % id(self))
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
def main():
|
||||
try:
|
||||
t = timercallback_t()
|
||||
# No need to unregister the timer.
|
||||
# It will unregister itself in the callback when it returns -1
|
||||
except Exception as e:
|
||||
print "Error: %s" % e
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
75
examples/ex_uirequests.py
Normal file
75
examples/ex_uirequests.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to use the execute_ui_requests()
|
||||
# and the idautils.ProcessUiActions()
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
import idaapi
|
||||
import idautils
|
||||
import idc
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class __process_ui_actions_helper(object):
|
||||
def __init__(self, actions, flags = 0):
|
||||
"""Expect a list or a string with a list of actions"""
|
||||
if isinstance(actions, str):
|
||||
lst = actions.split(";")
|
||||
elif isinstance(actions, (list, tuple)):
|
||||
lst = actions
|
||||
else:
|
||||
raise ValueError, "Must pass a string, list or a tuple"
|
||||
|
||||
# Remember the action list and the flags
|
||||
self.__action_list = lst
|
||||
self.__flags = flags
|
||||
|
||||
# Reset action index
|
||||
self.__idx = 0
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__action_list)
|
||||
|
||||
def __call__(self):
|
||||
if self.__idx >= len(self.__action_list):
|
||||
return False
|
||||
|
||||
# Execute one action
|
||||
idaapi.process_ui_action(
|
||||
self.__action_list[self.__idx],
|
||||
self.__flags)
|
||||
|
||||
# Move to next action
|
||||
self.__idx += 1
|
||||
print "index=%d" % self.__idx
|
||||
|
||||
# Reschedule
|
||||
return True
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def ProcessUiActions(actions, flags=0):
|
||||
"""
|
||||
@param actions: A string containing a list of actions separated by semicolon, a list or a tuple
|
||||
@param flags: flags to be passed to process_ui_action()
|
||||
@return: Boolean. Returns False if the action list was empty or execute_ui_requests() failed.
|
||||
"""
|
||||
|
||||
# Instantiate a helper
|
||||
helper = __process_ui_actions_helper(actions, flags)
|
||||
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class print_req_t(object):
|
||||
def __init__(self, s):
|
||||
self.s = s
|
||||
def __call__(self):
|
||||
idaapi.msg("%s" % self.s)
|
||||
return False # Don't reschedule
|
||||
|
||||
|
||||
|
||||
if idc.AskYN(1,("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n"
|
||||
"Press NO to execute ProcessUiActions() example\n")):
|
||||
idaapi.execute_ui_requests(
|
||||
(print_req_t("Hello"), print_req_t(" world\n")) )
|
||||
else:
|
||||
ProcessUiActions("JumpQ;JumpName")
|
@ -5,9 +5,6 @@ ALERT_AUTO_SCRIPTS = 1
|
||||
// Remove current directory from import search path
|
||||
REMOVE_CWD_SYS_PATH = 0
|
||||
|
||||
// Execute statement hotkey
|
||||
EXEC_STATEMENT_HOTKEY = "Ctrl-F7";
|
||||
|
||||
// Script timeout (in seconds)
|
||||
// (A value of 0 disables the timeout)
|
||||
SCRIPT_TIMEOUT = 3
|
||||
|
274
python.cpp
274
python.cpp
@ -1,5 +1,5 @@
|
||||
//---------------------------------------------------------------------
|
||||
// IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
// IDAPython - Python plugin for Interactive Disassembler
|
||||
//
|
||||
// Copyright (c) The IDAPython Team <idapython@googlegroups.com>
|
||||
//
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
// Python-style version tuple comes from the makefile
|
||||
// Only the serial and status is set here
|
||||
#define VER_SERIAL 3
|
||||
#define VER_SERIAL 0
|
||||
#define VER_STATUS "final"
|
||||
#define IDAPYTHON_RUNSTATEMENT 0
|
||||
#define IDAPYTHON_ENABLE_EXTLANG 3
|
||||
@ -75,11 +75,9 @@ enum script_run_when
|
||||
//-------------------------------------------------------------------------
|
||||
// Global variables
|
||||
static bool g_initialized = false;
|
||||
static bool g_menu_installed = false;
|
||||
static int g_run_when = -1;
|
||||
static char g_run_script[QMAXPATH];
|
||||
static char g_idapython_dir[QMAXPATH];
|
||||
static char g_runstmt_hotkey[30] = "Ctrl-F3";
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Prototypes and forward declarations
|
||||
@ -223,123 +221,23 @@ int set_script_timeout(int timeout)
|
||||
return timeout;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts IDC arguments to Python argument list or just one tuple
|
||||
// If 'decref' is NULL then 'pargs' will contain one element which is the tuple
|
||||
static bool convert_args(
|
||||
const idc_value_t args[],
|
||||
int nargs,
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
bool as_tupple = decref == NULL;
|
||||
PyObject *py_tuple(NULL);
|
||||
|
||||
pargs.qclear();
|
||||
|
||||
if ( as_tupple )
|
||||
{
|
||||
py_tuple = PyTuple_New(nargs);
|
||||
if ( py_tuple == NULL )
|
||||
{
|
||||
qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize);
|
||||
return false;
|
||||
}
|
||||
// Add the tuple
|
||||
pargs.push_back(py_tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
decref->qclear();
|
||||
}
|
||||
|
||||
for ( int i=0; i<nargs; i++ )
|
||||
{
|
||||
PyObject *py_obj(NULL);
|
||||
int cvt = idcvar_to_pyvar(args[i], &py_obj);
|
||||
if ( cvt < CIP_OK )
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( as_tupple )
|
||||
{
|
||||
// Opaque object?
|
||||
if ( cvt == CIP_OK_NODECREF )
|
||||
{
|
||||
// Increment reference for opaque objects.
|
||||
// (A tupple will steal references of its set items,
|
||||
// and for an opaque object we want it to still exist
|
||||
// even if the tuple is gone)
|
||||
Py_INCREF(py_obj);
|
||||
}
|
||||
// Save argument
|
||||
PyTuple_SetItem(py_tuple, i, py_obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
pargs.push_back(py_obj);
|
||||
// do not decrement reference of opaque objects
|
||||
decref->push_back(cvt == CIP_OK);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Frees arguments returned by convert_args()
|
||||
static void free_args(
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref = NULL)
|
||||
{
|
||||
if ( decref == NULL )
|
||||
{
|
||||
if ( !pargs.empty() )
|
||||
Py_XDECREF(pargs[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// free argument objects
|
||||
for ( int i=(int)pargs.size()-1; i>=0; i-- )
|
||||
{
|
||||
if ( decref->at(i) )
|
||||
Py_DECREF(pargs[i]);
|
||||
}
|
||||
decref->clear();
|
||||
}
|
||||
pargs.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Return a formatted error or just print it to the console
|
||||
static void handle_python_error(char *errbuf, size_t errbufsize)
|
||||
static void handle_python_error(
|
||||
char *errbuf,
|
||||
size_t errbufsize,
|
||||
bool clear_error = true)
|
||||
{
|
||||
if ( errbufsize > 0 )
|
||||
errbuf[0] = '\0';
|
||||
|
||||
// No exception?
|
||||
if ( !PyErr_Occurred() )
|
||||
return;
|
||||
|
||||
PyObject *result;
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||||
result = PyObject_Str(pvalue);
|
||||
if ( result != NULL )
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
|
||||
PyErr_Clear();
|
||||
Py_XDECREF(ptype);
|
||||
Py_XDECREF(pvalue);
|
||||
Py_XDECREF(ptraceback);
|
||||
Py_DECREF(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Print();
|
||||
}
|
||||
qstring s;
|
||||
if ( PyW_GetError(&s, clear_error) )
|
||||
qstrncpy(errbuf, s.c_str(), errbufsize);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -391,23 +289,26 @@ static void PythonEvalOrExec(
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Simple Python statement runner function for IDC
|
||||
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
|
||||
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
|
||||
// Executes a simple string
|
||||
static bool idaapi IDAPython_extlang_run_statements(
|
||||
const char *str,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
PyObject *globals = GetMainGlobals();
|
||||
bool ok;
|
||||
if ( globals == NULL )
|
||||
{
|
||||
res->set_string("internal error");
|
||||
ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
errbuf[0] = '\0';
|
||||
PyErr_Clear();
|
||||
|
||||
begin_execution();
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyRun_String(
|
||||
argv[0].c_str(),
|
||||
str,
|
||||
Py_file_input,
|
||||
globals,
|
||||
globals);
|
||||
@ -415,21 +316,31 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
|
||||
Py_XDECREF(result);
|
||||
end_execution();
|
||||
|
||||
if ( result == NULL || PyErr_Occurred() )
|
||||
{
|
||||
char errbuf[MAXSTR];
|
||||
handle_python_error(errbuf, sizeof(errbuf));
|
||||
if ( errbuf[0] == '\0' )
|
||||
res->set_string("internal error");
|
||||
else
|
||||
res->set_string(errbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// success
|
||||
res->set_long(0);
|
||||
}
|
||||
ok = result != NULL && !PyErr_Occurred();
|
||||
|
||||
if ( !ok )
|
||||
handle_python_error(errbuf, errbufsize);
|
||||
}
|
||||
if ( !ok && errbuf[0] == '\0' )
|
||||
qstrncpy(errbuf, "internal error", errbufsize);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Simple Python statement runner function for IDC
|
||||
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
|
||||
static error_t idaapi idc_runpythonstatement(
|
||||
idc_value_t *argv,
|
||||
idc_value_t *res)
|
||||
{
|
||||
char errbuf[MAXSTR];
|
||||
bool ok = IDAPython_extlang_run_statements(argv[0].c_str(), errbuf, sizeof(errbuf));
|
||||
|
||||
if ( ok )
|
||||
res->set_long(0);
|
||||
else
|
||||
res->set_string(errbuf);
|
||||
|
||||
return eOk;
|
||||
}
|
||||
|
||||
@ -441,15 +352,7 @@ const char *idaapi set_python_options(
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( value_type == IDPOPT_STR )
|
||||
{
|
||||
if ( qstrcmp(keyword, "EXEC_STATEMENT_HOTKEY" ) == 0 )
|
||||
{
|
||||
qstrncpy(g_runstmt_hotkey, (const char *)value, sizeof(g_runstmt_hotkey));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( value_type == IDPOPT_NUM )
|
||||
if ( value_type == IDPOPT_NUM )
|
||||
{
|
||||
if ( qstrcmp(keyword, "SCRIPT_TIMEOUT") == 0 )
|
||||
{
|
||||
@ -567,7 +470,7 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
|
||||
|
||||
char script[MAXSTR];
|
||||
qstrncpy(script, FileName, sizeof(script));
|
||||
strrpl(script, '\\', '//');
|
||||
strrpl(script, '\\', '/');
|
||||
|
||||
PyObject *py_script = PyString_FromString(script);
|
||||
PYW_GIL_ENSURE;
|
||||
@ -754,7 +657,7 @@ bool idaapi IDAPython_extlang_run(
|
||||
do
|
||||
{
|
||||
// Convert arguments to python
|
||||
ok = convert_args(args, nargs, pargs, &decref, errbuf, errbufsize);
|
||||
ok = pyw_convert_idc_args(args, nargs, pargs, &decref, errbuf, errbufsize);
|
||||
if ( !ok )
|
||||
break;
|
||||
|
||||
@ -792,7 +695,7 @@ bool idaapi IDAPython_extlang_run(
|
||||
ok = return_python_result(result, pres, errbuf, errbufsize);
|
||||
} while ( false );
|
||||
|
||||
free_args(pargs, &decref);
|
||||
pyw_free_idc_args(pargs, &decref);
|
||||
|
||||
if ( imported_module )
|
||||
Py_XDECREF(module);
|
||||
@ -851,7 +754,7 @@ bool idaapi IDAPython_extlang_create_object(
|
||||
}
|
||||
|
||||
// Error during conversion?
|
||||
ok = convert_args(args, nargs, pargs, NULL, errbuf, errbufsize);
|
||||
ok = pyw_convert_idc_args(args, nargs, pargs, NULL, errbuf, errbufsize);
|
||||
if ( !ok )
|
||||
break;
|
||||
ok = false;
|
||||
@ -867,7 +770,7 @@ bool idaapi IDAPython_extlang_create_object(
|
||||
Py_XDECREF(py_cls);
|
||||
|
||||
// Free the arguments tuple
|
||||
free_args(pargs);
|
||||
pyw_free_idc_args(pargs);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -918,9 +821,41 @@ bool idaapi IDAPython_extlang_get_attr(
|
||||
// No object specified:
|
||||
else
|
||||
{
|
||||
// then work with main module
|
||||
// ...then work with main module
|
||||
py_obj = py_mod;
|
||||
}
|
||||
// Special case: if attribute not passed then retrieve the class
|
||||
// name associated associated with the passed object
|
||||
if ( attr == NULL || attr[0] == '\0' )
|
||||
{
|
||||
cvt = CIP_FAILED;
|
||||
// Get the class
|
||||
PyObject *cls = PyObject_GetAttrString(py_obj, "__class__");
|
||||
if ( cls == NULL )
|
||||
break;
|
||||
|
||||
// Get its name
|
||||
PyObject *name = PyObject_GetAttrString(cls, "__name__");
|
||||
Py_DECREF(cls);
|
||||
if ( name == NULL )
|
||||
break;
|
||||
|
||||
// Convert name object to string object
|
||||
PyObject *string = PyObject_Str(name);
|
||||
Py_DECREF(name);
|
||||
if ( string == NULL )
|
||||
break;
|
||||
|
||||
// Convert name python string to a C string
|
||||
const char *clsname = PyString_AsString(name);
|
||||
if ( clsname == NULL )
|
||||
break;
|
||||
|
||||
result->set_string(clsname);
|
||||
cvt = CIP_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
PyObject *py_attr = PyW_TryGetAttrString(py_obj, attr);
|
||||
// No attribute?
|
||||
if ( py_attr == NULL )
|
||||
@ -1089,7 +1024,7 @@ bool idaapi IDAPython_extlang_call_method(
|
||||
}
|
||||
|
||||
// Convert arguments to python objects
|
||||
ok = convert_args(args, nargs, pargs, NULL, errbuf, errbufsize);
|
||||
ok = pyw_convert_idc_args(args, nargs, pargs, NULL, errbuf, errbufsize);
|
||||
if ( !ok )
|
||||
break;
|
||||
|
||||
@ -1100,7 +1035,7 @@ bool idaapi IDAPython_extlang_call_method(
|
||||
} while ( false );
|
||||
|
||||
// Free converted args
|
||||
free_args(pargs);
|
||||
pyw_free_idc_args(pargs);
|
||||
|
||||
// Release reference of object if needed
|
||||
if ( obj_cvt != CIP_OK_NODECREF )
|
||||
@ -1124,7 +1059,8 @@ extlang_t extlang_python =
|
||||
IDAPython_extlang_create_object,
|
||||
IDAPython_extlang_get_attr,
|
||||
IDAPython_extlang_set_attr,
|
||||
IDAPython_extlang_call_method
|
||||
IDAPython_extlang_call_method,
|
||||
IDAPython_extlang_run_statements,
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -1247,26 +1183,6 @@ void py_print_banner()
|
||||
PYW_GIL_RELEASE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Install python menu items
|
||||
static void install_python_menus()
|
||||
{
|
||||
if ( g_menu_installed )
|
||||
return;
|
||||
|
||||
// Add menu items for all the functions
|
||||
// Note: Different paths are used for the GUI version
|
||||
add_menu_item(
|
||||
"File/IDC command...",
|
||||
"P~y~thon command...",
|
||||
g_runstmt_hotkey,
|
||||
SETMENU_APP,
|
||||
IDAPython_Menu_Callback,
|
||||
(void *)IDAPYTHON_RUNSTATEMENT);
|
||||
|
||||
g_menu_installed = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Parse plugin options
|
||||
void parse_plugin_options()
|
||||
@ -1331,7 +1247,6 @@ static int idaapi menu_installer_cb(void *, int code, va_list)
|
||||
case ui_ready_to_run:
|
||||
g_ui_ready = true;
|
||||
py_print_banner();
|
||||
install_python_menus();
|
||||
|
||||
if ( g_run_when == run_on_ui_ready )
|
||||
RunScript(g_run_script);
|
||||
@ -1429,7 +1344,8 @@ bool IDAPython_Init(void)
|
||||
init_idaapi();
|
||||
|
||||
// Set IDAPYTHON_VERSION in Python
|
||||
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
|
||||
qsnprintf(tmp, sizeof(tmp),
|
||||
"IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
|
||||
"IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n",
|
||||
VER_MAJOR,
|
||||
VER_MINOR,
|
||||
@ -1447,8 +1363,17 @@ bool IDAPython_Init(void)
|
||||
qmakepath(tmp, MAXSTR, g_idapython_dir, S_INIT_PY, NULL);
|
||||
if ( !PyRunFile(tmp) )
|
||||
{
|
||||
handle_python_error(tmp, sizeof(tmp));
|
||||
warning("IDAPython: error executing " S_INIT_PY ":\n%s", tmp);
|
||||
// Try to fetch a one line error string. We must do it before printing
|
||||
// the traceback information. Make sure that the exception is not cleared
|
||||
handle_python_error(tmp, sizeof(tmp), false);
|
||||
|
||||
// Print the exception traceback
|
||||
PyRun_SimpleString("import traceback;traceback.print_exc();");
|
||||
|
||||
warning("IDAPython: error executing " S_INIT_PY ":\n"
|
||||
"%s\n"
|
||||
"\n"
|
||||
"Refer to the message window to see the full error log.", tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1497,7 +1422,6 @@ void IDAPython_Term(void)
|
||||
#endif
|
||||
/* Remove the menu items before termination */
|
||||
del_menu_item("File/Python command...");
|
||||
g_menu_installed = false;
|
||||
|
||||
// Notify about IDA closing
|
||||
pywraps_nw_notify(NW_TERMIDA_SLOT);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#---------------------------------------------------------------------
|
||||
# IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
# IDAPython - Python plugin for Interactive Disassembler
|
||||
#
|
||||
# Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
#
|
||||
@ -310,6 +310,38 @@ def FuncItems(start):
|
||||
ok = fii.next_code()
|
||||
|
||||
|
||||
def Structs():
|
||||
"""
|
||||
Get a list of structures
|
||||
|
||||
@return: List of tuples (idx, sid, name)
|
||||
"""
|
||||
idx = idc.GetFirstStrucIdx()
|
||||
while idx != idaapi.BADADDR:
|
||||
sid = idc.GetStrucId(idx)
|
||||
yield (idx, sid, idc.GetStrucName(sid))
|
||||
idx = idc.GetNextStrucIdx(idx)
|
||||
|
||||
|
||||
def StructMembers(sid):
|
||||
"""
|
||||
Get a list of structure members information.
|
||||
|
||||
@param sid: ID of the structure.
|
||||
|
||||
@return: List of tuples (offset, name, size)
|
||||
|
||||
@note: If 'sid' does not refer to a valid structure,
|
||||
an exception will be raised.
|
||||
"""
|
||||
off = idc.GetFirstMember(sid)
|
||||
if off == idaapi.BADNODE:
|
||||
raise Exception("No structure with ID: 0x%x" % sid)
|
||||
members = idc.GetMemberQty(sid)
|
||||
for idx in range(0, members):
|
||||
yield (off, idc.GetMemberName(sid, off), idc.GetMemberSize(sid, off))
|
||||
off = idc.GetStrucNextOff(sid, off)
|
||||
|
||||
|
||||
def DecodePrecedingInstruction(ea):
|
||||
"""
|
||||
@ -648,17 +680,69 @@ class _procregs(object):
|
||||
def __setattr__(self, attr, value):
|
||||
raise AttributeError(attr)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class _cpu(object):
|
||||
"Simple wrapper around GetRegValue/SetRegValue"
|
||||
def __getattr__(self, name):
|
||||
#print "cpu.get(%s)"%name
|
||||
#print "cpu.get(%s)" % name
|
||||
return idc.GetRegValue(name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
#print "cpu.set(%s)"%name
|
||||
#print "cpu.set(%s)" % name
|
||||
return idc.SetRegValue(value, name)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class __process_ui_actions_helper(object):
|
||||
def __init__(self, actions, flags = 0):
|
||||
"""Expect a list or a string with a list of actions"""
|
||||
if isinstance(actions, str):
|
||||
lst = actions.split(";")
|
||||
elif isinstance(actions, (list, tuple)):
|
||||
lst = actions
|
||||
else:
|
||||
raise ValueError, "Must pass a string, list or a tuple"
|
||||
|
||||
# Remember the action list and the flags
|
||||
self.__action_list = lst
|
||||
self.__flags = flags
|
||||
|
||||
# Reset action index
|
||||
self.__idx = 0
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__action_list)
|
||||
|
||||
def __call__(self):
|
||||
if self.__idx >= len(self.__action_list):
|
||||
return False
|
||||
|
||||
# Execute one action
|
||||
idaapi.process_ui_action(
|
||||
self.__action_list[self.__idx],
|
||||
self.__flags)
|
||||
|
||||
# Move to next action
|
||||
self.__idx += 1
|
||||
|
||||
# Reschedule
|
||||
return True
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def ProcessUiActions(actions, flags=0):
|
||||
"""
|
||||
@param actions: A string containing a list of actions separated by semicolon, a list or a tuple
|
||||
@param flags: flags to be passed to process_ui_action()
|
||||
@return: Boolean. Returns False if the action list was empty or execute_ui_requests() failed.
|
||||
"""
|
||||
|
||||
# Instantiate a helper
|
||||
helper = __process_ui_actions_helper(actions, flags)
|
||||
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class peutils_t(object):
|
||||
"""
|
||||
|
507
python/idc.py
507
python/idc.py
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
#---------------------------------------------------------------------
|
||||
# IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
# IDAPython - Python plugin for Interactive Disassembler
|
||||
#
|
||||
# Original IDC.IDC:
|
||||
# Copyright (c) 1990-2010 Ilfak Guilfanov
|
||||
@ -39,8 +39,7 @@ import time
|
||||
import types
|
||||
|
||||
__EA64__ = idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
|
||||
WORDMASK = __EA64__ and 0xFFFFFFFFFFFFFFFF or 0xFFFFFFFF
|
||||
|
||||
WORDMASK = 0xFFFFFFFFFFFFFFFF if __EA64__ else 0xFFFFFFFF
|
||||
class DeprecatedIDCError(Exception):
|
||||
"""
|
||||
Exception for deprecated function calls
|
||||
@ -78,7 +77,7 @@ def _IDC_SetAttr(obj, attrmap, attroffs, value):
|
||||
BADADDR = idaapi.BADADDR # Not allowed address value
|
||||
BADSEL = idaapi.BADSEL # Not allowed selector value/number
|
||||
MAXADDR = idaapi.MAXADDR & WORDMASK
|
||||
|
||||
SIZE_MAX = idaapi.SIZE_MAX
|
||||
#
|
||||
# Flag bit definitions (for GetFlags())
|
||||
#
|
||||
@ -838,6 +837,21 @@ def MakeStructEx(ea, size, strname):
|
||||
return idaapi.doStruct(ea, size, strid)
|
||||
|
||||
|
||||
def MakeCustomDataEx(ea, size, dtid, fid):
|
||||
"""
|
||||
Convert the item at address to custom data.
|
||||
|
||||
@param ea: linear address.
|
||||
@param size: custom data size in bytes.
|
||||
@param dtid: data type ID.
|
||||
@param fid: data format ID.
|
||||
|
||||
@return: 1-ok, 0-failure
|
||||
"""
|
||||
return idaapi.doCustomData(ea, size, dtid, fid)
|
||||
|
||||
|
||||
|
||||
def MakeAlign(ea, count, align):
|
||||
"""
|
||||
Convert the current item to an alignment directive
|
||||
@ -2021,9 +2035,7 @@ def ItemHead(ea):
|
||||
@return: the starting address of the item
|
||||
if the current address is unexplored, returns 'ea'
|
||||
"""
|
||||
if idaapi.isTail(idaapi.get_flags_novalue(ea)):
|
||||
ea = idaapi.prev_not_tail(ea)
|
||||
return ea
|
||||
return idaapi.get_item_head(ea)
|
||||
|
||||
|
||||
def ItemEnd(ea):
|
||||
@ -2328,9 +2340,9 @@ def GetString(ea, length = -1, strtype = ASCSTR_C):
|
||||
@return: string contents or empty string
|
||||
"""
|
||||
if length == -1:
|
||||
length = idaapi.get_max_ascii_length(ea, strtype)
|
||||
length = idaapi.get_max_ascii_length(ea, strtype, idaapi.ALOPT_IGNHEADS)
|
||||
|
||||
return idaapi.get_ascii_contents(ea, length, strtype, length + 1)
|
||||
return idaapi.get_ascii_contents2(ea, length, strtype)
|
||||
|
||||
|
||||
def GetStringType(ea):
|
||||
@ -2935,7 +2947,7 @@ def AskLong(defval, prompt):
|
||||
|
||||
def ProcessUiAction(name, flags=0):
|
||||
"""
|
||||
Invokes an IDA Pro UI action by name
|
||||
Invokes an IDA UI action by name
|
||||
|
||||
@param name: Command name
|
||||
@param flags: Reserved. Must be zero
|
||||
@ -4771,8 +4783,8 @@ def GetMemberQty(sid):
|
||||
@return: -1 if bad structure type ID is passed otherwise
|
||||
returns number of members.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -4797,8 +4809,8 @@ def GetStrucPrevOff(sid, offset):
|
||||
It will return size of the structure if input
|
||||
'offset' is bigger than the structure size.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -4826,8 +4838,8 @@ def GetStrucNextOff(sid, offset):
|
||||
It will return size of the structure if input
|
||||
'offset' belongs to the last member of the structure.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -4848,8 +4860,8 @@ def GetFirstMember(sid):
|
||||
structure. It treats these 'holes'
|
||||
as unnamed arrays of bytes.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -4873,8 +4885,8 @@ def GetLastMember(sid):
|
||||
structure. It treats these 'holes'
|
||||
as unnamed arrays of bytes.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -4895,8 +4907,8 @@ def GetMemberOffset(sid, member_name):
|
||||
or no such member in the structure
|
||||
otherwise returns offset of the specified member.
|
||||
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
@note: Union members are, in IDA's internals, located
|
||||
at subsequent byte offsets: member 0 -> offset 0x0,
|
||||
member 1 -> offset 0x1, etc...
|
||||
"""
|
||||
s = idaapi.get_struc(sid)
|
||||
@ -5891,6 +5903,8 @@ def AddEnum(idx, name, flag):
|
||||
|
||||
@return: id of new enum or BADADDR
|
||||
"""
|
||||
if idx < 0:
|
||||
idx = idx & SIZE_MAX
|
||||
return idaapi.add_enum(idx, name, flag)
|
||||
|
||||
|
||||
@ -6077,68 +6091,414 @@ def SetConstCmt(const_id, cmt, repeatable):
|
||||
# A R R A Y S I N I D C
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
_IDC_ARRAY_PREFIX = "$ idc_array "
|
||||
def __l2m1(v):
|
||||
"""
|
||||
Long to minus 1: If the 'v' appears to be the
|
||||
'signed long' version of -1, then return -1.
|
||||
Otherwise, return 'v'.
|
||||
"""
|
||||
if v == idaapi.BADNODE:
|
||||
return -1
|
||||
else:
|
||||
return v
|
||||
|
||||
|
||||
|
||||
AR_LONG = idaapi.atag
|
||||
"""Array of longs"""
|
||||
|
||||
AR_STR = idaapi.stag
|
||||
"""Array of strings"""
|
||||
|
||||
|
||||
class __dummy_netnode(object):
|
||||
"""
|
||||
Implements, in an "always failing" fashion, the
|
||||
netnode functions that are necessary for the
|
||||
array-related functions.
|
||||
|
||||
The sole purpose of this singleton class is to
|
||||
serve as a placeholder for netnode-manipulating
|
||||
functions, that don't want to each have to perform
|
||||
checks on the existence of the netnode.
|
||||
(..in other words: it avoids a bunch of if/else's).
|
||||
|
||||
See __GetArrayById() for more info.
|
||||
"""
|
||||
def rename(self, *args): return 0
|
||||
def kill(self, *args): pass
|
||||
def index(self, *args): return -1
|
||||
def altset(self, *args): return 0
|
||||
def supset(self, *args): return 0
|
||||
def altval(self, *args): return 0
|
||||
def supval(self, *args): return 0
|
||||
def altdel(self, *args): return 0
|
||||
def supdel(self, *args): return 0
|
||||
def alt1st(self, *args): return -1
|
||||
def sup1st(self, *args): return -1
|
||||
def altlast(self, *args): return -1
|
||||
def suplast(self, *args): return -1
|
||||
def altnxt(self, *args): return -1
|
||||
def supnxt(self, *args): return -1
|
||||
def altprev(self, *args): return -1
|
||||
def supprev(self, *args): return -1
|
||||
def hashset(self, *args): return 0
|
||||
def hashval(self, *args): return 0
|
||||
def hashstr(self, *args): return 0
|
||||
def hashstr_buf(self, *args): return 0
|
||||
def hashset_idx(self, *args): return 0
|
||||
def hashset_buf(self, *args): return 0
|
||||
def hashval_long(self, *args): return 0
|
||||
def hashdel(self, *args): return 0
|
||||
def hash1st(self, *args): return 0
|
||||
def hashnxt(self, *args): return 0
|
||||
def hashprev(self, *args): return 0
|
||||
def hashlast(self, *args): return 0
|
||||
__dummy_netnode.instance = __dummy_netnode()
|
||||
|
||||
|
||||
|
||||
def __GetArrayById(array_id):
|
||||
"""
|
||||
Get an array, by its ID.
|
||||
|
||||
This (internal) wrapper around 'idaaip.netnode(array_id)'
|
||||
will ensure a certain safety around the retrieval of
|
||||
arrays (by catching quite unexpect[ed|able] exceptions,
|
||||
and making sure we don't create & use `transient' netnodes).
|
||||
|
||||
@param array_id: A positive, valid array ID.
|
||||
"""
|
||||
try:
|
||||
node = idaapi.netnode(array_id)
|
||||
nodename = node.name()
|
||||
if nodename is None or not nodename.startswith(_IDC_ARRAY_PREFIX):
|
||||
return __dummy_netnode.instance
|
||||
else:
|
||||
return node
|
||||
except NotImplementedError:
|
||||
return __dummy_netnode.instance
|
||||
|
||||
|
||||
def CreateArray(name):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
"""
|
||||
Create array.
|
||||
|
||||
@param name: The array name.
|
||||
|
||||
@return: -1 in case of failure, a valid array_id otherwise.
|
||||
"""
|
||||
node = idaapi.netnode()
|
||||
res = node.create(_IDC_ARRAY_PREFIX + name)
|
||||
if res == False:
|
||||
return -1
|
||||
else:
|
||||
return node.index()
|
||||
|
||||
|
||||
def GetArrayId(name):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
"""
|
||||
Get array array_id, by name.
|
||||
|
||||
def RenameArray(hashid, newname):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@param name: The array name.
|
||||
|
||||
def DeleteArray(hashid):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@return: -1 in case of failure (i.e., no array with that
|
||||
name exists), a valid array_id otherwise.
|
||||
"""
|
||||
return __l2m1(idaapi.netnode(_IDC_ARRAY_PREFIX + name, 0, False).index())
|
||||
|
||||
def SetArrayLong(hashid, idx, value):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
def SetArrayString(hashid, idx, s):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
def RenameArray(array_id, newname):
|
||||
"""
|
||||
Rename array, by its ID.
|
||||
|
||||
def GetArrayElement(tag, hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@param id: The ID of the array to rename.
|
||||
@param newname: The new name of the array.
|
||||
|
||||
def DelArrayElement(tag, hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@return: 1 in case of success, 0 otherwise
|
||||
"""
|
||||
return __GetArrayById(array_id).rename(_IDC_ARRAY_PREFIX + newname) == 1
|
||||
|
||||
def GetFirstIndex(tag, hashid):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
def GetLastIndex(tag, hashid):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
def DeleteArray(array_id):
|
||||
"""
|
||||
Delete array, by its ID.
|
||||
|
||||
def GetNextIndex(tag, hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@param array_id: The ID of the array to delete.
|
||||
"""
|
||||
__GetArrayById(array_id).kill()
|
||||
|
||||
def GetPrevIndex(tag, hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
def SetHashLong(hashid, idx, value):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
def SetArrayLong(array_id, idx, value):
|
||||
"""
|
||||
Sets the long value of an array element.
|
||||
|
||||
def SetHashString(hashid, idx, value):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of an element.
|
||||
@param value: 32bit or 64bit value to store in the array
|
||||
|
||||
def GetHashLong(hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@return: 1 in case of success, 0 otherwise
|
||||
"""
|
||||
return __GetArrayById(array_id).altset(idx, value)
|
||||
|
||||
def GetHashString(hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
def DelHashElement(hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
def SetArrayString(array_id, idx, value):
|
||||
"""
|
||||
Sets the string value of an array element.
|
||||
|
||||
def GetFirstHashKey(hashid):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of an element.
|
||||
@param value: String value to store in the array
|
||||
|
||||
def GetNextHashKey(hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
@return: 1 in case of success, 0 otherwise
|
||||
"""
|
||||
return __GetArrayById(array_id).supset(idx, value)
|
||||
|
||||
|
||||
def GetArrayElement(tag, array_id, idx):
|
||||
"""
|
||||
Get value of array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of an element.
|
||||
|
||||
@return: Value of the specified array element. Note that
|
||||
this function may return char or long result. Unexistent
|
||||
array elements give zero as a result.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
if tag == AR_LONG:
|
||||
return node.altval(idx, tag)
|
||||
elif tag == AR_STR:
|
||||
res = node.supval(idx, tag)
|
||||
return 0 if res is None else res
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def DelArrayElement(tag, array_id, idx):
|
||||
"""
|
||||
Delete an array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of an element.
|
||||
|
||||
@return: 1 in case of success, 0 otherwise.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
if tag == AR_LONG:
|
||||
return node.altdel(idx, tag)
|
||||
elif tag == AR_STR:
|
||||
return node.supdel(idx, tag)
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def GetFirstIndex(tag, array_id):
|
||||
"""
|
||||
Get index of the first existing array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
|
||||
@return: -1 if the array is empty, otherwise index of first array
|
||||
element of given type.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
if tag == AR_LONG:
|
||||
return __l2m1(node.alt1st(tag))
|
||||
elif tag == AR_STR:
|
||||
return __l2m1(node.sup1st(tag))
|
||||
else:
|
||||
return -1
|
||||
|
||||
|
||||
def GetLastIndex(tag, array_id):
|
||||
"""
|
||||
Get index of last existing array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
|
||||
@return: -1 if the array is empty, otherwise index of first array
|
||||
element of given type.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
if tag == AR_LONG:
|
||||
return __l2m1(node.altlast(tag))
|
||||
elif tag == AR_STR:
|
||||
return __l2m1(node.suplast(tag))
|
||||
else:
|
||||
return -1
|
||||
|
||||
|
||||
def GetNextIndex(tag, array_id, idx):
|
||||
"""
|
||||
Get index of the next existing array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of the current element.
|
||||
|
||||
@return: -1 if no more elements, otherwise returns index of the
|
||||
next array element of given type.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
try:
|
||||
if tag == AR_LONG:
|
||||
return __l2m1(node.altnxt(idx, tag))
|
||||
elif tag == AR_STR:
|
||||
return __l2m1(node.supnxt(idx, tag))
|
||||
else:
|
||||
return -1
|
||||
except OverflowError:
|
||||
# typically: An index of -1 was passed.
|
||||
return -1
|
||||
|
||||
|
||||
def GetPrevIndex(tag, array_id, idx):
|
||||
"""
|
||||
Get index of the previous existing array element.
|
||||
|
||||
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
|
||||
@param array_id: The array ID.
|
||||
@param idx: Index of the current element.
|
||||
|
||||
@return: -1 if no more elements, otherwise returns index of the
|
||||
previous array element of given type.
|
||||
"""
|
||||
node = __GetArrayById(array_id)
|
||||
try:
|
||||
if tag == AR_LONG:
|
||||
return __l2m1(node.altprev(idx, tag))
|
||||
elif tag == AR_STR:
|
||||
return __l2m1(node.supprev(idx, tag))
|
||||
else:
|
||||
return -1
|
||||
except OverflowError:
|
||||
# typically: An index of -1 was passed.
|
||||
return -1
|
||||
|
||||
|
||||
# -------------------- hashes -----------------------
|
||||
|
||||
def SetHashLong(hash_id, key, value):
|
||||
"""
|
||||
Sets the long value of a hash element.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: Key of an element.
|
||||
@param value: 32bit or 64bit value to store in the hash
|
||||
|
||||
@return: 1 in case of success, 0 otherwise
|
||||
"""
|
||||
return __GetArrayById(hash_id).hashset_idx(key, value)
|
||||
|
||||
|
||||
def GetHashLong(hash_id, key):
|
||||
"""
|
||||
Gets the long value of a hash element.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: Key of an element.
|
||||
|
||||
@return: the 32bit or 64bit value of the element, or 0 if no such
|
||||
element.
|
||||
"""
|
||||
return __GetArrayById(hash_id).hashval_long(key);
|
||||
|
||||
|
||||
def SetHashString(hash_id, key, value):
|
||||
"""
|
||||
Sets the string value of a hash element.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: Key of an element.
|
||||
@param value: string value to store in the hash
|
||||
|
||||
@return: 1 in case of success, 0 otherwise
|
||||
"""
|
||||
return __GetArrayById(hash_id).hashset_buf(key, value)
|
||||
|
||||
|
||||
def GetHashString(hash_id, key):
|
||||
"""
|
||||
Gets the string value of a hash element.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: Key of an element.
|
||||
|
||||
@return: the string value of the element, or None if no such
|
||||
element.
|
||||
"""
|
||||
return __GetArrayById(hash_id).hashstr_buf(key);
|
||||
|
||||
|
||||
def DelHashElement(hash_id, key):
|
||||
"""
|
||||
Delete a hash element.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: Key of an element
|
||||
|
||||
@return: 1 upon success, 0 otherwise.
|
||||
"""
|
||||
return __GetArrayById(hash_id).hashdel(key)
|
||||
|
||||
|
||||
def GetFirstHashKey(hash_id):
|
||||
"""
|
||||
Get the first key in the hash.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
|
||||
@return: the key, 0 otherwise.
|
||||
"""
|
||||
r = __GetArrayById(hash_id).hash1st()
|
||||
return 0 if r is None else r
|
||||
|
||||
|
||||
def GetLastHashKey(hash_id):
|
||||
"""
|
||||
Get the last key in the hash.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
|
||||
@return: the key, 0 otherwise.
|
||||
"""
|
||||
r = __GetArrayById(hash_id).hashlast()
|
||||
return 0 if r is None else r
|
||||
|
||||
|
||||
def GetNextHashKey(hash_id, key):
|
||||
"""
|
||||
Get the next key in the hash.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: The current key.
|
||||
|
||||
@return: the next key, 0 otherwise
|
||||
"""
|
||||
r = __GetArrayById(hash_id).hashnxt(key)
|
||||
return 0 if r is None else r
|
||||
|
||||
|
||||
def GetPrevHashKey(hash_id, key):
|
||||
"""
|
||||
Get the previous key in the hash.
|
||||
|
||||
@param hash_id: The hash ID.
|
||||
@param key: The current key.
|
||||
|
||||
@return: the previous key, 0 otherwise
|
||||
"""
|
||||
r = __GetArrayById(hash_id).hashprev(key)
|
||||
return 0 if r is None else r
|
||||
|
||||
def GetLastHashKey(hashid):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
def GetPrevHashKey(hashid, idx):
|
||||
raise DeprecatedIDCError, "Use python pickles instead."
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
@ -7053,6 +7413,20 @@ EXCDLG_ALWAYS = 0x00006000 # always display
|
||||
DOPT_LOAD_DINFO = 0x00008000 # automatically load debug files (pdb)
|
||||
|
||||
|
||||
def GetDebuggerEventCondition():
|
||||
"""
|
||||
Return the debugger event condition
|
||||
"""
|
||||
return idaapi.get_debugger_event_cond()
|
||||
|
||||
|
||||
def SetDebuggerEventCondition(cond):
|
||||
"""
|
||||
Set the debugger event condition
|
||||
"""
|
||||
return idaapi.set_debugger_event_cond(cond)
|
||||
|
||||
|
||||
def SetRemoteDebugger(hostname, password, portnum):
|
||||
"""
|
||||
Set remote debugging options
|
||||
@ -7628,10 +8002,11 @@ def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
|
||||
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
|
||||
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
|
||||
|
||||
def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
|
||||
def Name(ea): return NameEx(BADADDR, ea)
|
||||
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
|
||||
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
|
||||
def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
|
||||
def MakeCustomData(ea, size, dtid, fid): return MakeCustomDataEx(ea, size, dtid, fid)
|
||||
def Name(ea): return NameEx(BADADDR, ea)
|
||||
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
|
||||
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
|
||||
|
||||
#def GetFrame(ea): return GetFunctionAttr(ea, FUNCATTR_FRAME)
|
||||
#def GetFrameLvarSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRSIZE)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# -----------------------------------------------------------------------
|
||||
# IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
# IDAPython - Python plugin for Interactive Disassembler
|
||||
#
|
||||
# Copyright (c) The IDAPython Team <idapython@googlegroups.com>
|
||||
#
|
||||
@ -94,7 +94,7 @@ from idautils import *
|
||||
import idaapi
|
||||
|
||||
# Load the users personal init file
|
||||
userrc = get_user_idadir() + os.sep + "idapythonrc.py"
|
||||
userrc = os.path.join(get_user_idadir(), "idapythonrc.py")
|
||||
if os.path.exists(userrc):
|
||||
idaapi.IDAPython_ExecScript(userrc, globals())
|
||||
|
||||
|
80
pywraps.hpp
80
pywraps.hpp
@ -23,11 +23,14 @@
|
||||
#define PY_SFMT64 "l"
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
#define S_IDAAPI_MODNAME "idaapi"
|
||||
#define S_IDC_MODNAME "idc"
|
||||
#define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript"
|
||||
#define S_IDAAPI_COMPLETION "IDAPython_Completion"
|
||||
#define S_IDAAPI_FORMATEXC "IDAPython_FormatExc"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Vector of PyObject*
|
||||
typedef qvector<PyObject *> ppyobject_vec_t;
|
||||
|
||||
@ -57,6 +60,36 @@ typedef qvector<PyObject *> ppyobject_vec_t;
|
||||
#define CIP_OK 1 // Success
|
||||
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Helper macro to create C counterparts of Python py_clinked_object_t object
|
||||
#ifdef __PYWRAPS__
|
||||
#define DECLARE_PY_CLINKED_OBJECT(type) \
|
||||
static PyObject *type##_create() \
|
||||
{ \
|
||||
return PyCObject_FromVoidPtr(new type(), NULL); \
|
||||
} \
|
||||
static bool type##_destroy(PyObject *py_obj) \
|
||||
{ \
|
||||
if ( !PyCObject_Check(py_obj) ) \
|
||||
return false; \
|
||||
delete (type *)PyCObject_AsVoidPtr(py_obj); \
|
||||
return true; \
|
||||
} \
|
||||
static type *type##_get_clink(PyObject *self) \
|
||||
{ \
|
||||
return (type *)pyobj_get_clink(self); \
|
||||
} \
|
||||
static PyObject *type##_get_clink_ptr(PyObject *self) \
|
||||
{ \
|
||||
return PyLong_FromUnsignedLongLong( \
|
||||
(unsigned PY_LONG_LONG)pyobj_get_clink(self)); \
|
||||
}
|
||||
#else
|
||||
// SWIG does not expand macros and thus those definitions won't be wrapped
|
||||
// Use DECLARE_PY_CLINKED_OBJECT(type) inside the .i file
|
||||
#define DECLARE_PY_CLINKED_OBJECT(type)
|
||||
#endif // __PYWRAPS__
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class CGilStateAuto
|
||||
{
|
||||
@ -82,11 +115,18 @@ public:
|
||||
|
||||
#define PYW_GIL_ENSURE PYW_GIL_ENSURE_N(_)
|
||||
#define PYW_GIL_RELEASE PYW_GIL_RELEASE_N(_)
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// All the exported functions from PyWraps are forward declared here
|
||||
insn_t *insn_t_get_clink(PyObject *self);
|
||||
op_t *op_t_get_clink(PyObject *self);
|
||||
|
||||
// Returns a reference to a class
|
||||
PyObject *get_idaapi_attr(const char *attr);
|
||||
|
||||
// Returns a reference to a class by its ID
|
||||
PyObject *get_idaapi_attr_by_id(const int class_id);
|
||||
|
||||
// Tries to import a module and swallows the exception if it fails and returns NULL
|
||||
PyObject *PyW_TryImportModule(const char *name);
|
||||
|
||||
@ -112,7 +152,8 @@ bool PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL);
|
||||
bool PyW_IsSequenceType(PyObject *obj);
|
||||
|
||||
// Returns an error string from the last exception (and clears it)
|
||||
bool PyW_GetError(qstring *out = NULL);
|
||||
bool PyW_GetError(qstring *out = NULL, bool clear_err = true);
|
||||
bool PyW_GetError(char *buf, size_t bufsz, bool clear_err = true);
|
||||
|
||||
// If an error occured (it calls PyGetError) it displays it and return TRUE
|
||||
// This function is used when calling callbacks
|
||||
@ -124,10 +165,6 @@ PyObject *create_idaapi_class_instance0(const char *clsname);
|
||||
// Utility function to create linked class instances
|
||||
PyObject *create_idaapi_linked_class_instance(const char *clsname, void *lnk);
|
||||
|
||||
// [De]Initializes PyWraps
|
||||
bool init_pywraps();
|
||||
void deinit_pywraps();
|
||||
|
||||
// Returns the string representation of a PyObject
|
||||
bool PyW_ObjectToString(PyObject *obj, qstring *out);
|
||||
|
||||
@ -135,6 +172,24 @@ bool PyW_ObjectToString(PyObject *obj, qstring *out);
|
||||
// and sets a python exception on failure.
|
||||
bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj);
|
||||
|
||||
// Creates and initializes an IDC exception
|
||||
error_t PyW_CreateIdcException(idc_value_t *res, const char *msg);
|
||||
|
||||
//
|
||||
// Conversion functions
|
||||
//
|
||||
bool pyw_convert_idc_args(
|
||||
const idc_value_t args[],
|
||||
int nargs,
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref,
|
||||
char *errbuf = NULL,
|
||||
size_t errbufsize = 0);
|
||||
|
||||
void pyw_free_idc_args(
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref = NULL);
|
||||
|
||||
// Converts Python variable to IDC variable
|
||||
// gvar_sn is used in case the Python object was a created from a call to idcvar_to_pyvar and the IDC object was a VT_REF
|
||||
int pyvar_to_idcvar(
|
||||
@ -160,17 +215,22 @@ PyObject *PyW_IntVecToPyList(const intvec_t &intvec);
|
||||
// Converts an Python list to an intvec
|
||||
bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec);
|
||||
|
||||
// Returns a reference to a class
|
||||
PyObject *get_idaapi_attr(const char *attr);
|
||||
|
||||
// Returns a reference to a class by its ID
|
||||
PyObject *get_idaapi_attr_by_id(const int class_id);
|
||||
// Converts a Python list to a qstrvec
|
||||
bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// notify_when()
|
||||
//
|
||||
bool pywraps_nw_term();
|
||||
bool pywraps_nw_notify(int slot, ...);
|
||||
bool pywraps_nw_init();
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *pywraps_check_autoscripts();
|
||||
|
||||
// [De]Initializes PyWraps
|
||||
bool init_pywraps();
|
||||
void deinit_pywraps();
|
||||
|
||||
#endif
|
94
swig/bytes.i
94
swig/bytes.i
@ -13,6 +13,7 @@
|
||||
%ignore adjust_visea;
|
||||
%ignore prev_visea;
|
||||
%ignore next_visea;
|
||||
%ignore visit_patched_bytes;
|
||||
%ignore is_first_visea;
|
||||
%ignore is_last_visea;
|
||||
%ignore is_visible_finally;
|
||||
@ -36,7 +37,6 @@
|
||||
%ignore noExtra;
|
||||
%ignore coagulate;
|
||||
%ignore coagulate_dref;
|
||||
%ignore get_item_head;
|
||||
%ignore init_hidden_areas;
|
||||
%ignore save_hidden_areas;
|
||||
%ignore term_hidden_areas;
|
||||
@ -74,6 +74,7 @@
|
||||
%ignore register_custom_data_type;
|
||||
%ignore get_many_bytes;
|
||||
%ignore get_ascii_contents;
|
||||
%ignore get_ascii_contents2;
|
||||
|
||||
// TODO: This could be fixed (if needed)
|
||||
%ignore set_dbgmem_source;
|
||||
@ -86,6 +87,7 @@
|
||||
%clear(void *buf, ssize_t size);
|
||||
%clear(opinfo_t *);
|
||||
|
||||
%rename (visit_patched_bytes) py_visit_patched_bytes;
|
||||
%rename (nextthat) py_nextthat;
|
||||
%rename (prevthat) py_prevthat;
|
||||
%rename (get_custom_data_type) py_get_custom_data_type;
|
||||
@ -95,7 +97,7 @@
|
||||
%rename (unregister_custom_data_type) py_unregister_custom_data_type;
|
||||
%rename (register_custom_data_type) py_register_custom_data_type;
|
||||
%rename (get_many_bytes) py_get_many_bytes;
|
||||
%rename (get_ascii_contents) py_get_ascii_contents;
|
||||
%rename (get_ascii_contents2) py_get_ascii_contents2;
|
||||
%{
|
||||
//<code(py_bytes)>
|
||||
//------------------------------------------------------------------------
|
||||
@ -121,6 +123,30 @@ static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next)
|
||||
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static int idaapi py_visit_patched_bytes_cb(
|
||||
ea_t ea,
|
||||
int32 fpos,
|
||||
uint32 o,
|
||||
uint32 v,
|
||||
void *ud)
|
||||
{
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *py_result = PyObject_CallFunction(
|
||||
(PyObject *)ud,
|
||||
PY_FMT64 "iII",
|
||||
pyul_t(ea),
|
||||
fpos,
|
||||
o,
|
||||
v);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
PyW_ShowCbErr("visit_patched_bytes");
|
||||
int ret = (py_result != NULL && PyInt_Check(py_result)) ? PyInt_AsLong(py_result) : 0;
|
||||
Py_XDECREF(py_result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -639,11 +665,54 @@ static PyObject *py_data_format_to_py_dict(const data_format_t *df)
|
||||
//<inline(py_bytes)>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def visit_patched_bytes(ea1, ea2, callable):
|
||||
"""
|
||||
Enumerates patched bytes in the given range and invokes a callable
|
||||
@param ea1: start address
|
||||
@param ea2: end address
|
||||
@param callable: a Python callable with the following prototype:
|
||||
callable(ea, fpos, org_val, patch_val).
|
||||
If the callable returns non-zero then that value will be
|
||||
returned to the caller and the enumeration will be
|
||||
interrupted.
|
||||
@return: Zero if the enumeration was successful or the return
|
||||
value of the callback if enumeration was interrupted.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static int py_visit_patched_bytes(ea_t ea1, ea_t ea2, PyObject *py_callable)
|
||||
{
|
||||
if ( !PyCallable_Check(py_callable) )
|
||||
return 0;
|
||||
else
|
||||
return visit_patched_bytes(ea1, ea2, py_visit_patched_bytes_cb, py_callable);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def nextthat(ea, maxea, callable):
|
||||
"""
|
||||
Find next address with a flag satisfying the function 'testf'.
|
||||
Start searching from address 'ea'+1 and inspect bytes up to 'maxea'.
|
||||
maxea is not included in the search range.
|
||||
|
||||
@param callable: a Python callable with the following prototype:
|
||||
callable(flags). Return True to stop enumeration.
|
||||
@return: the found address or BADADDR.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static ea_t py_nextthat(ea_t ea, ea_t maxea, PyObject *callable)
|
||||
{
|
||||
return py_npthat(ea, maxea, callable, true);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static ea_t py_prevthat(ea_t ea, ea_t minea, PyObject *callable)
|
||||
{
|
||||
return py_npthat(ea, minea, callable, false);
|
||||
@ -694,37 +763,40 @@ static PyObject *py_get_many_bytes(ea_t ea, unsigned int size)
|
||||
//---------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def get_ascii_contents(ea, len, type, bufsize):
|
||||
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
|
||||
"""
|
||||
Get contents of ascii string
|
||||
This function returns the displayed part of the string
|
||||
It works even if the string has not been created in the database yet.
|
||||
|
||||
@param ea: linear address of the string
|
||||
@param len: length of the string in bytes
|
||||
@param len: length of the string in bytes (including terminating 0)
|
||||
@param type: type of the string
|
||||
@param bufsize: size of output buffer
|
||||
@return: 1-ok, 0-ascii string is too long and was truncated
|
||||
@param flags: combination of ACFOPT_...
|
||||
@return: string contents (not including terminating 0) or None
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static PyObject *py_get_ascii_contents(
|
||||
static PyObject *py_get_ascii_contents2(
|
||||
ea_t ea,
|
||||
size_t len,
|
||||
int32 type,
|
||||
size_t bufsize = MAXSTR)
|
||||
int flags = ACFOPT_ASCII)
|
||||
{
|
||||
char *buf = (char *)qalloc(bufsize);
|
||||
char *buf = (char *)qalloc(len+1);
|
||||
if ( buf == NULL )
|
||||
return NULL;
|
||||
|
||||
if ( !get_ascii_contents(ea, len, type, buf, bufsize) )
|
||||
size_t used_size;
|
||||
if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size) )
|
||||
{
|
||||
qfree(buf);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
PyObject *py_buf = PyString_FromStringAndSize((const char *)buf, bufsize);
|
||||
if ( type == ASCSTR_C && used_size > 0 && buf[used_size-1] == '\0' )
|
||||
used_size--;
|
||||
PyObject *py_buf = PyString_FromStringAndSize((const char *)buf, used_size);
|
||||
qfree(buf);
|
||||
return py_buf;
|
||||
}
|
||||
|
231
swig/dbg.i
231
swig/dbg.i
@ -114,86 +114,81 @@ static PyObject *refresh_debugger_memory()
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
//</inline(py_dbg)>
|
||||
|
||||
int idaapi DBG_Callback(void *ud, int notification_code, va_list va);
|
||||
class DBG_Hooks
|
||||
{
|
||||
public:
|
||||
virtual ~DBG_Hooks() {};
|
||||
virtual ~DBG_Hooks() {};
|
||||
|
||||
bool hook() { return hook_to_notification_point(HT_DBG, DBG_Callback, this); };
|
||||
bool unhook() { return unhook_from_notification_point(HT_DBG, DBG_Callback, this); };
|
||||
/* Hook functions to be overridden in Python */
|
||||
virtual void dbg_process_start(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_process_exit(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int exit_code) { };
|
||||
virtual void dbg_process_attach(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_process_detach(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea) { };
|
||||
virtual void dbg_thread_start(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea) { };
|
||||
virtual void dbg_thread_exit(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int exit_code) { };
|
||||
virtual void dbg_library_load(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_library_unload(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *libname) { };
|
||||
virtual void dbg_information(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *info) { };
|
||||
virtual int dbg_exception(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int code,
|
||||
bool can_cont,
|
||||
ea_t exc_ea,
|
||||
char *info) { return 0; };
|
||||
virtual void dbg_suspend_process(void) { };
|
||||
virtual int dbg_bpt(thid_t tid, ea_t breakpoint_ea) { return 0; };
|
||||
virtual int dbg_trace(thid_t tid, ea_t ip) { return 0; };
|
||||
virtual void dbg_request_error(int failed_command,
|
||||
int failed_dbg_notification) { };
|
||||
virtual void dbg_step_into(void) { };
|
||||
virtual void dbg_step_over(void) { };
|
||||
virtual void dbg_run_to(thid_t tid) { };
|
||||
virtual void dbg_step_until_ret(void) { };
|
||||
bool hook() { return hook_to_notification_point(HT_DBG, DBG_Callback, this); };
|
||||
bool unhook() { return unhook_from_notification_point(HT_DBG, DBG_Callback, this); };
|
||||
/* Hook functions to be overridden in Python */
|
||||
virtual void dbg_process_start(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_process_exit(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int exit_code) { };
|
||||
virtual void dbg_process_attach(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_process_detach(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea) { };
|
||||
virtual void dbg_thread_start(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea) { };
|
||||
virtual void dbg_thread_exit(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int exit_code) { };
|
||||
virtual void dbg_library_load(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *name,
|
||||
ea_t base,
|
||||
asize_t size) { };
|
||||
virtual void dbg_library_unload(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *libname) { };
|
||||
virtual void dbg_information(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
char *info) { };
|
||||
virtual int dbg_exception(pid_t pid,
|
||||
thid_t tid,
|
||||
ea_t ea,
|
||||
int code,
|
||||
bool can_cont,
|
||||
ea_t exc_ea,
|
||||
char *info) { return 0; };
|
||||
virtual void dbg_suspend_process(void) { };
|
||||
virtual int dbg_bpt(thid_t tid, ea_t breakpoint_ea) { return 0; };
|
||||
virtual int dbg_trace(thid_t tid, ea_t ip) { return 0; };
|
||||
virtual void dbg_request_error(int failed_command,
|
||||
int failed_dbg_notification) { };
|
||||
virtual void dbg_step_into(void) { };
|
||||
virtual void dbg_step_over(void) { };
|
||||
virtual void dbg_run_to(pid_t pid, thid_t tid, ea_t ea) { };
|
||||
virtual void dbg_step_until_ret(void) { };
|
||||
};
|
||||
|
||||
int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
|
||||
{
|
||||
class DBG_Hooks *proxy = (class DBG_Hooks *)ud;
|
||||
|
||||
debug_event_t *event;
|
||||
thid_t tid;
|
||||
int *warn;
|
||||
ea_t ip;
|
||||
ea_t breakpoint_ea;
|
||||
|
||||
try {
|
||||
int code = 0;
|
||||
try
|
||||
{
|
||||
switch (notification_code)
|
||||
{
|
||||
case dbg_process_start:
|
||||
@ -204,135 +199,155 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
|
||||
event->modinfo.name,
|
||||
event->modinfo.base,
|
||||
event->modinfo.size);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_process_exit:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_process_exit(event->pid,
|
||||
proxy->dbg_process_exit(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->exit_code);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_process_attach:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_process_attach(event->pid,
|
||||
proxy->dbg_process_attach(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->modinfo.name,
|
||||
event->modinfo.base,
|
||||
event->modinfo.size);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_process_detach:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_process_detach(event->pid,
|
||||
proxy->dbg_process_detach(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_thread_start:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_thread_start(event->pid,
|
||||
proxy->dbg_thread_start(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_thread_exit:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_thread_exit(event->pid,
|
||||
proxy->dbg_thread_exit(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->exit_code);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_library_load:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_library_load(event->pid,
|
||||
proxy->dbg_library_load(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->modinfo.name,
|
||||
event->modinfo.base,
|
||||
event->modinfo.size);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_library_unload:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_library_unload(event->pid,
|
||||
proxy->dbg_library_unload(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->info);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_information:
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_information(event->pid,
|
||||
proxy->dbg_information(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->info);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_exception:
|
||||
{
|
||||
event = va_arg(va, debug_event_t *);
|
||||
warn = va_arg(va, int *);
|
||||
*warn = proxy->dbg_exception(event->pid,
|
||||
int *warn = va_arg(va, int *);
|
||||
*warn = proxy->dbg_exception(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea,
|
||||
event->exc.code,
|
||||
event->exc.can_cont,
|
||||
event->exc.ea,
|
||||
event->exc.info);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dbg_suspend_process:
|
||||
proxy->dbg_suspend_process();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_bpt:
|
||||
tid = va_arg(va, thid_t);
|
||||
breakpoint_ea = va_arg(va, ea_t);
|
||||
warn = va_arg(va, int *);
|
||||
{
|
||||
thid_t tid = va_arg(va, thid_t);
|
||||
ea_t breakpoint_ea = va_arg(va, ea_t);
|
||||
int *warn = va_arg(va, int *);
|
||||
*warn = proxy->dbg_bpt(tid, breakpoint_ea);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dbg_trace:
|
||||
tid = va_arg(va, thid_t);
|
||||
ip = va_arg(va, ea_t);
|
||||
return proxy->dbg_trace(tid, ip);
|
||||
{
|
||||
thid_t tid = va_arg(va, thid_t);
|
||||
ea_t ip = va_arg(va, ea_t);
|
||||
code = proxy->dbg_trace(tid, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
case dbg_request_error:
|
||||
{
|
||||
int failed_command = (int)va_argi(va, ui_notification_t);
|
||||
int failed_dbg_notification = (int)va_argi(va, dbg_notification_t);
|
||||
proxy->dbg_request_error(failed_command, failed_dbg_notification);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dbg_step_into:
|
||||
proxy->dbg_step_into();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_step_over:
|
||||
proxy->dbg_step_over();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case dbg_run_to:
|
||||
tid = va_arg(va, thid_t);
|
||||
proxy->dbg_run_to(tid);
|
||||
return 0;
|
||||
event = va_arg(va, debug_event_t *);
|
||||
proxy->dbg_run_to(
|
||||
event->pid,
|
||||
event->tid,
|
||||
event->ea);
|
||||
break;
|
||||
|
||||
case dbg_step_until_ret:
|
||||
proxy->dbg_step_until_ret();
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Swig::DirectorException &)
|
||||
catch (Swig::DirectorException &e)
|
||||
{
|
||||
msg("Exception in DBG Hook function:\n");
|
||||
msg("Exception in DBG Hook function: %s\n", e.getMessage());
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return code;
|
||||
}
|
||||
//</inline(py_dbg)>
|
||||
|
||||
%}
|
||||
|
@ -12,6 +12,7 @@
|
||||
%ignore free_ioports;
|
||||
%ignore lread;
|
||||
%ignore qlread;
|
||||
%ignore efilelength;
|
||||
%ignore qlgets;
|
||||
%ignore qlgetc;
|
||||
%ignore lreadbytes;
|
||||
|
310
swig/expr.i
310
swig/expr.i
@ -7,7 +7,12 @@
|
||||
%ignore register_extlang;
|
||||
%ignore IDCFuncs;
|
||||
%ignore set_idc_func;
|
||||
%ignore set_idc_dtor;
|
||||
%ignore set_idc_method;
|
||||
%ignore set_idc_getattr;
|
||||
%ignore set_idc_setattr;
|
||||
%ignore set_idc_func_ex;
|
||||
%ignore run_statements_idc;
|
||||
%ignore VarLong;
|
||||
%ignore VarNum;
|
||||
%ignore extlang_get_attr_exists;
|
||||
@ -46,54 +51,291 @@
|
||||
%ignore idc_resolve_label;
|
||||
%ignore idc_resolver_ea;
|
||||
%ignore setup_lowcnd_regfuncs;
|
||||
|
||||
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
||||
|
||||
/* Compile* functions return false when error so the return */
|
||||
/* value must be negated for the error string to be returned */
|
||||
%ignore CompileEx;
|
||||
%rename (CompileEx) CompileEx_wrap;
|
||||
%inline %{
|
||||
bool CompileEx_wrap(const char *file, bool del_macros,
|
||||
char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !CompileEx(file, del_macros, errbuf, errbufsize);
|
||||
}
|
||||
%}
|
||||
|
||||
%ignore Compile;
|
||||
%rename (Compile) Compile_wrap;
|
||||
%inline %{
|
||||
bool Compile_wrap(const char *file, char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !Compile(file, errbuf, errbufsize);
|
||||
}
|
||||
%}
|
||||
|
||||
%ignore calcexpr;
|
||||
%rename (calcexpr) calcexpr_wrap;
|
||||
%inline %{
|
||||
bool calcexpr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !calcexpr(where, line, rv, errbuf, errbufsize);
|
||||
}
|
||||
%}
|
||||
|
||||
%ignore calc_idc_expr;
|
||||
%rename (calc_idc_expr) calc_idc_expr_wrap;
|
||||
%inline %{
|
||||
bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
|
||||
}
|
||||
%}
|
||||
|
||||
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
||||
%ignore CompileLineEx;
|
||||
|
||||
%ignore CompileLine;
|
||||
%rename (CompileLine) CompileLine_wrap;
|
||||
%{
|
||||
//<code(py_expr)>
|
||||
struct py_idcfunc_ctx_t
|
||||
{
|
||||
PyObject *py_func;
|
||||
qstring name;
|
||||
int nargs;
|
||||
py_idcfunc_ctx_t(PyObject *py_func, const char *name, int nargs): py_func(py_func), name(name), nargs(nargs)
|
||||
{
|
||||
Py_INCREF(py_func);
|
||||
}
|
||||
~py_idcfunc_ctx_t()
|
||||
{
|
||||
Py_DECREF(py_func);
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static error_t py_call_idc_func(
|
||||
void *_ctx,
|
||||
idc_value_t *argv,
|
||||
idc_value_t *r)
|
||||
{
|
||||
// Convert IDC arguments to Python list
|
||||
py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)_ctx;
|
||||
int cvt;
|
||||
ppyobject_vec_t pargs;
|
||||
char errbuf[MAXSTR];
|
||||
if ( !pyw_convert_idc_args(argv, ctx->nargs, pargs, NULL, errbuf, sizeof(errbuf)) )
|
||||
{
|
||||
// Error during conversion? Create an IDC exception
|
||||
return PyW_CreateIdcException(r, errbuf);
|
||||
}
|
||||
|
||||
// Call the Python function
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *py_result = PyObject_CallObject(
|
||||
ctx->py_func,
|
||||
pargs.empty() ? NULL : pargs[0]);
|
||||
|
||||
error_t err;
|
||||
if ( PyW_GetError(errbuf, sizeof(errbuf)) )
|
||||
{
|
||||
err = PyW_CreateIdcException(r, errbuf);
|
||||
Py_XDECREF(py_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the result to IDC
|
||||
r->clear();
|
||||
cvt = pyvar_to_idcvar(py_result, r);
|
||||
if ( cvt < CIP_OK )
|
||||
err = PyW_CreateIdcException(r, "ERROR: bad return value");
|
||||
else
|
||||
err = eOk;
|
||||
if ( cvt != CIP_OK_NODECREF )
|
||||
Py_XDECREF(py_result);
|
||||
}
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
// Free the converted args
|
||||
pyw_free_idc_args(pargs);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
//</code(py_expr)>
|
||||
%}
|
||||
|
||||
%inline %{
|
||||
//<inline(py_expr)>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static size_t py_get_call_idc_func()
|
||||
{
|
||||
return (size_t)py_call_idc_func;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internal function:
|
||||
// - capture the python callable
|
||||
// - return a C context as a numeric value
|
||||
static size_t pyw_register_idc_func(
|
||||
const char *name,
|
||||
const char *args,
|
||||
PyObject *py_fp)
|
||||
{
|
||||
return (size_t)new py_idcfunc_ctx_t(py_fp, name, strlen(args));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internal function:
|
||||
// - free the C context
|
||||
static bool pyw_unregister_idc_func(size_t ctxptr)
|
||||
{
|
||||
// Unregister the function
|
||||
py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)ctxptr;
|
||||
bool ok = set_idc_func_ex(ctx->name.c_str(), NULL, NULL, 0);
|
||||
|
||||
// Delete the context
|
||||
delete ctx;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static bool py_set_idc_func_ex(
|
||||
const char *name,
|
||||
size_t fp_ptr,
|
||||
const char *args,
|
||||
int flags)
|
||||
{
|
||||
return set_idc_func_ex(name, (idc_func_t *)fp_ptr, args, flags);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Compile* functions return false when error so the return
|
||||
// value must be negated for the error string to be returned
|
||||
bool CompileEx_wrap(
|
||||
const char *file,
|
||||
bool del_macros,
|
||||
char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !CompileEx(file, del_macros, errbuf, errbufsize);
|
||||
}
|
||||
|
||||
bool Compile_wrap(const char *file, char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !Compile(file, errbuf, errbufsize);
|
||||
}
|
||||
|
||||
bool calcexpr_wrap(
|
||||
ea_t where,
|
||||
const char *line,
|
||||
idc_value_t *rv,
|
||||
char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !calcexpr(where, line, rv, errbuf, errbufsize);
|
||||
}
|
||||
|
||||
bool calc_idc_expr_wrap(
|
||||
ea_t where,
|
||||
const char *line,
|
||||
idc_value_t *rv,
|
||||
char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
|
||||
}
|
||||
|
||||
bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize)
|
||||
{
|
||||
return !CompileLineEx(line, errbuf, errbufsize);
|
||||
return !CompileLineEx(line, errbuf, errbufsize);
|
||||
}
|
||||
|
||||
//</inline(py_expr)>
|
||||
%}
|
||||
|
||||
%include "expr.hpp"
|
||||
|
||||
%pythoncode %{
|
||||
|
||||
#<pycode(py_expr)>
|
||||
try:
|
||||
import types
|
||||
import ctypes
|
||||
# Callback for IDC func callback (On Windows, we use stdcall)
|
||||
# typedef error_t idaapi idc_func_t(idc_value_t *argv,idc_value_t *r);
|
||||
_IDCFUNC_CB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p)
|
||||
|
||||
# A trampoline function that is called from idcfunc_t that will
|
||||
# call the Python callback with the argv and r properly serialized to python
|
||||
call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_call_idc_func())
|
||||
except:
|
||||
def call_idc_func__(*args):
|
||||
warning("IDC extensions need ctypes library in order to work")
|
||||
return 0
|
||||
try:
|
||||
_IDCFUNC_CB_T = CFUNCTYPE(c_int, c_void_p, c_void_p)
|
||||
except:
|
||||
_IDCFUNC_CB_T = None
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
EXTFUN_BASE = 0x0001
|
||||
"""requires open database"""
|
||||
EXTFUN_NORET = 0x0002
|
||||
"""does not return. the interpreter may clean up its state before calling it."""
|
||||
EXTFUN_SAFE = 0x0004
|
||||
"""thread safe function. may be called"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class _IdcFunction(object):
|
||||
"""
|
||||
Internal class that calls pyw_call_idc_func() with a context
|
||||
"""
|
||||
def __init__(self, ctxptr):
|
||||
self.ctxptr = ctxptr
|
||||
# Take a reference to the ctypes callback
|
||||
# (note: this will create a circular reference)
|
||||
self.cb = _IDCFUNC_CB_T(self)
|
||||
|
||||
fp_ptr = property(lambda self: ctypes.cast(self.cb, ctypes.c_void_p).value)
|
||||
|
||||
def __call__(self, args, res):
|
||||
return call_idc_func__(self.ctxptr, args, res)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Dictionary to remember IDC function names along with the context pointer
|
||||
# retrieved by using the internal pyw_register_idc_func()
|
||||
__IDC_FUNC_CTXS = {}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
def set_idc_func_ex(name, fp=None, args=(), flags=0):
|
||||
"""
|
||||
Extends the IDC language by exposing a new IDC function that is backed up by a Python function
|
||||
This function also unregisters the IDC function if 'fp' was passed as None
|
||||
|
||||
@param name: IDC function name to expose
|
||||
@param fp: Python callable that will receive the arguments and return a tuple.
|
||||
If this argument is None then the IDC function is unregistered
|
||||
@param args: Arguments. A tuple of idaapi.VT_XXX constants
|
||||
@param flags: IDC function flags. A combination of EXTFUN_XXX constants
|
||||
|
||||
@return: Boolean.
|
||||
"""
|
||||
global __IDC_FUNC_CTXS
|
||||
|
||||
# Get the context
|
||||
f = __IDC_FUNC_CTXS.get(name, None)
|
||||
|
||||
# Unregistering?
|
||||
if fp is None:
|
||||
# Not registered?
|
||||
if f is None:
|
||||
return False
|
||||
|
||||
# Break circular reference
|
||||
del f.cb
|
||||
|
||||
# Delete the name from the dictionary
|
||||
del __IDC_FUNC_CTXS[name]
|
||||
|
||||
# Delete the context and unregister the function
|
||||
return _idaapi.pyw_unregister_idc_func(f.ctxptr)
|
||||
|
||||
# Registering a function that is already registered?
|
||||
if f is not None:
|
||||
# Unregister it first
|
||||
set_idc_func_ex(name, None)
|
||||
|
||||
# Convert the tupple argument info to a string
|
||||
args = "".join([chr(x) for x in args])
|
||||
|
||||
# Create a context
|
||||
ctxptr = _idaapi.pyw_register_idc_func(name, args, fp)
|
||||
if ctxptr == 0:
|
||||
return False
|
||||
|
||||
# Bind the context with the IdcFunc object
|
||||
f = _IdcFunction(ctxptr)
|
||||
|
||||
# Remember the Python context
|
||||
__IDC_FUNC_CTXS[name] = f
|
||||
|
||||
# Register IDC function with a callback
|
||||
return _idaapi.py_set_idc_func_ex(
|
||||
name,
|
||||
f.fp_ptr,
|
||||
args,
|
||||
flags)
|
||||
|
||||
#</pycode(py_expr)>
|
||||
%}
|
82
swig/graph.i
82
swig/graph.i
@ -26,7 +26,7 @@ private:
|
||||
nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { }
|
||||
nodetext_cache_t() { }
|
||||
};
|
||||
|
||||
|
||||
class nodetext_cache_map_t: public std::map<int, nodetext_cache_t>
|
||||
{
|
||||
public:
|
||||
@ -62,24 +62,24 @@ private:
|
||||
private:
|
||||
Py_ssize_t uid;
|
||||
public:
|
||||
|
||||
|
||||
cmdid_map_t()
|
||||
{
|
||||
// We start by one and keep zero for error id
|
||||
uid = 1;
|
||||
uid = 1;
|
||||
}
|
||||
|
||||
|
||||
void add(py_graph_t *pyg)
|
||||
{
|
||||
(*this)[uid] = pyg;
|
||||
++uid;
|
||||
}
|
||||
|
||||
const Py_ssize_t id() const
|
||||
{
|
||||
|
||||
const Py_ssize_t id() const
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
void clear(py_graph_t *pyg)
|
||||
{
|
||||
iterator e = end();
|
||||
@ -94,7 +94,7 @@ private:
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
py_graph_t *get(Py_ssize_t id)
|
||||
{
|
||||
iterator it = find(id);
|
||||
@ -123,7 +123,7 @@ private:
|
||||
py_graph_t *_this = cmdid_pyg.get(id);
|
||||
if ( _this != NULL )
|
||||
_this->on_command(id);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -208,11 +208,11 @@ private:
|
||||
|
||||
edge_ids[j] = v;
|
||||
}
|
||||
|
||||
|
||||
// Incomplete?
|
||||
if ( j != qnumber(edge_ids) )
|
||||
break;
|
||||
|
||||
|
||||
// Add the edge
|
||||
g->add_edge(edge_ids[0], edge_ids[1], NULL);
|
||||
}
|
||||
@ -312,27 +312,27 @@ private:
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
unbind();
|
||||
}
|
||||
|
||||
|
||||
// Remove the TForm from list
|
||||
if ( form != NULL )
|
||||
tform_pyg.erase(form);
|
||||
|
||||
|
||||
// Remove all associated commands from the list
|
||||
cmdid_pyg.clear(this);
|
||||
|
||||
|
||||
// Delete this instance
|
||||
delete this;
|
||||
}
|
||||
|
||||
// graph is being clicked
|
||||
int on_clicked(
|
||||
graph_viewer_t * /*gv*/,
|
||||
selection_item_t * /*item1*/,
|
||||
graph_viewer_t * /*gv*/,
|
||||
selection_item_t * /*item1*/,
|
||||
graph_item_t *item2)
|
||||
{
|
||||
// in: graph_viewer_t *gv
|
||||
@ -349,12 +349,12 @@ private:
|
||||
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_CLICK,
|
||||
"i",
|
||||
self,
|
||||
(char *)S_ON_CLICK,
|
||||
"i",
|
||||
item2->n);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
|
||||
if ( result == NULL || !PyObject_IsTrue(result) )
|
||||
{
|
||||
Py_XDECREF(result);
|
||||
@ -376,15 +376,15 @@ private:
|
||||
//selection_item_t *s = va_arg(va, selection_item_t *);
|
||||
if ( item == NULL || !item->is_node )
|
||||
return 1;
|
||||
|
||||
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_DBL_CLICK,
|
||||
"i",
|
||||
self,
|
||||
(char *)S_ON_DBL_CLICK,
|
||||
"i",
|
||||
item->node);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
|
||||
if ( result == NULL || !PyObject_IsTrue(result) )
|
||||
{
|
||||
Py_XDECREF(result);
|
||||
@ -399,8 +399,8 @@ private:
|
||||
{
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_ACTIVATE,
|
||||
self,
|
||||
(char *)S_ON_ACTIVATE,
|
||||
NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
Py_XDECREF(result);
|
||||
@ -411,8 +411,8 @@ private:
|
||||
{
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_DEACTIVATE,
|
||||
self,
|
||||
(char *)S_ON_DEACTIVATE,
|
||||
NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
@ -430,9 +430,9 @@ private:
|
||||
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_SELECT,
|
||||
"i",
|
||||
self,
|
||||
(char *)S_ON_SELECT,
|
||||
"i",
|
||||
curnode);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
@ -473,7 +473,7 @@ private:
|
||||
else
|
||||
{
|
||||
// Ignore the click
|
||||
ret = 1;
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
//
|
||||
@ -491,20 +491,20 @@ private:
|
||||
case grcode_gotfocus:
|
||||
if ( cb_flags & GR_HAVE_GOTFOCUS )
|
||||
on_gotfocus(va_arg(va, graph_viewer_t *));
|
||||
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
//
|
||||
case grcode_lostfocus:
|
||||
if ( cb_flags & GR_HAVE_LOSTFOCUS )
|
||||
on_lostfocus(va_arg(va, graph_viewer_t *));
|
||||
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
//
|
||||
case grcode_user_refresh:
|
||||
on_user_refresh(va_arg(va, mutable_graph_t *));
|
||||
|
||||
|
||||
ret = 1;
|
||||
break;
|
||||
//
|
||||
@ -664,7 +664,9 @@ private:
|
||||
{
|
||||
// get a unique graph id
|
||||
netnode id;
|
||||
id.create();
|
||||
char grnode[MAXSTR];
|
||||
qsnprintf(grnode, sizeof(grnode), "$ pygraph %s", title);
|
||||
id.create(grnode);
|
||||
gv = create_graph_viewer(form, id, s_callback, this, 0);
|
||||
open_tform(form, FORM_MDI | FORM_TAB | FORM_MENU);
|
||||
if ( gv != NULL )
|
||||
@ -724,7 +726,7 @@ private:
|
||||
if ( _this == NULL || _this->form == NULL )
|
||||
return;
|
||||
|
||||
close_tform(_this->form, 0);
|
||||
close_tform(_this->form, FORM_CLOSE_LATER);
|
||||
}
|
||||
|
||||
static void Refresh(PyObject *self)
|
||||
|
555
swig/idaapi.i
555
swig/idaapi.i
@ -1,4 +1,4 @@
|
||||
%module(docstring="IDA Pro Plugin SDK API wrapper",directors="1") idaapi
|
||||
%module(docstring="IDA Plugin SDK API wrapper",directors="1") idaapi
|
||||
// Suppress 'previous definition of XX' warnings
|
||||
#pragma SWIG nowarn=302
|
||||
// and others...
|
||||
@ -12,14 +12,41 @@
|
||||
#pragma SWIG nowarn=451
|
||||
#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory
|
||||
|
||||
%constant size_t SIZE_MAX = size_t(-1);
|
||||
|
||||
// Enable automatic docstring generation
|
||||
%feature(autodoc);
|
||||
|
||||
%define SWIG_DECLARE_PY_CLINKED_OBJECT(type)
|
||||
%inline %{
|
||||
static PyObject *type##_create()
|
||||
{
|
||||
return PyCObject_FromVoidPtr(new type(), NULL);
|
||||
}
|
||||
static bool type##_destroy(PyObject *py_obj)
|
||||
{
|
||||
if ( !PyCObject_Check(py_obj) )
|
||||
return false;
|
||||
delete (type *)PyCObject_AsVoidPtr(py_obj);
|
||||
return true;
|
||||
}
|
||||
static type *type##_get_clink(PyObject *self)
|
||||
{
|
||||
return (type *)pyobj_get_clink(self);
|
||||
}
|
||||
static PyObject *type##_get_clink_ptr(PyObject *self)
|
||||
{
|
||||
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)pyobj_get_clink(self));
|
||||
}
|
||||
%}
|
||||
%enddef
|
||||
|
||||
// We use those special maps because SWIG wraps passed PyObject* with 'SwigPtr_PyObject' and 'SwigVar_PyObject'
|
||||
// They act like autoptr and decrement the reference of the object when the scope ends
|
||||
// We need to keep a reference outside SWIG and let the caller manage its references
|
||||
%typemap(directorin) PyObject * "/*%din%*/Py_XINCREF($1_name);$input = $1_name;"
|
||||
%typemap(directorout) PyObject * "/*%dout%*/$result = result;Py_XINCREF($result);"
|
||||
|
||||
%{
|
||||
#include <Python.h>
|
||||
|
||||
@ -29,7 +56,7 @@
|
||||
|
||||
#ifndef NO_OBSOLETE_FUNCS
|
||||
#define NO_OBSOLETE_FUNCS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSIZE_T
|
||||
#define _SSIZE_T_DEFINED 1
|
||||
@ -124,6 +151,7 @@ enum scfield_types_t
|
||||
FT_CHRARR_STATIC,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
struct scfld_t
|
||||
{
|
||||
const char *field_name;
|
||||
@ -524,6 +552,30 @@ bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec)
|
||||
return pyvar_walk_list(py_list, pylist_to_intvec_cb, &intvec) != CIP_FAILED;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static int idaapi pylist_to_strvec_cb(
|
||||
PyObject *py_item,
|
||||
Py_ssize_t /*index*/,
|
||||
void *ud)
|
||||
{
|
||||
qstrvec_t &strvec = *(qstrvec_t *)ud;
|
||||
const char *s;
|
||||
if ( !PyString_Check(py_item) )
|
||||
s = "";
|
||||
else
|
||||
s = PyString_AsString(py_item);
|
||||
|
||||
strvec.push_back(s);
|
||||
return CIP_OK;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec)
|
||||
{
|
||||
strvec.clear();
|
||||
return pyvar_walk_list(py_list, pylist_to_strvec_cb, &strvec) != CIP_FAILED;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Checks if the given py_var is a special PyIdc_cvt_helper object.
|
||||
// It does that by examining the magic attribute and returns its numeric value.
|
||||
@ -874,7 +926,9 @@ int idcvar_to_pyvar(
|
||||
PyObject *py_cls = get_idaapi_attr_by_id(PY_CLSID_CVT_INT64);
|
||||
if ( py_cls == NULL )
|
||||
return CIP_FAILED;
|
||||
PYW_GIL_ENSURE;
|
||||
*py_var = PyObject_CallFunctionObjArgs(py_cls, PyLong_FromLongLong(idc_var.i64), NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
Py_DECREF(py_cls);
|
||||
if ( PyW_GetError() || *py_var == NULL )
|
||||
return CIP_FAILED;
|
||||
@ -928,7 +982,9 @@ int idcvar_to_pyvar(
|
||||
return CIP_FAILED;
|
||||
|
||||
// Create a byref object with None value. We populate it later
|
||||
PYW_GIL_ENSURE;
|
||||
*py_var = PyObject_CallFunctionObjArgs(py_cls, Py_None, NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
Py_DECREF(py_cls);
|
||||
if ( PyW_GetError() || *py_var == NULL )
|
||||
return CIP_FAILED;
|
||||
@ -993,7 +1049,9 @@ int idcvar_to_pyvar(
|
||||
return CIP_FAILED;
|
||||
|
||||
// Call constructor
|
||||
PYW_GIL_ENSURE;
|
||||
obj = PyObject_CallFunctionObjArgs(py_cls, NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
Py_DECREF(py_cls);
|
||||
if ( PyW_GetError() || obj == NULL )
|
||||
return CIP_FAILED;
|
||||
@ -1045,11 +1103,104 @@ int idcvar_to_pyvar(
|
||||
return CIP_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts IDC arguments to Python argument list or just one tuple
|
||||
// If 'decref' is NULL then 'pargs' will contain one element which is the tuple
|
||||
bool pyw_convert_idc_args(
|
||||
const idc_value_t args[],
|
||||
int nargs,
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
bool as_tupple = decref == NULL;
|
||||
PyObject *py_tuple(NULL);
|
||||
|
||||
pargs.qclear();
|
||||
|
||||
if ( as_tupple )
|
||||
{
|
||||
py_tuple = PyTuple_New(nargs);
|
||||
if ( py_tuple == NULL )
|
||||
{
|
||||
if ( errbuf != 0 && errbufsize > 0 )
|
||||
qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize);
|
||||
return false;
|
||||
}
|
||||
// Add the tuple
|
||||
pargs.push_back(py_tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
decref->qclear();
|
||||
}
|
||||
|
||||
for ( int i=0; i<nargs; i++ )
|
||||
{
|
||||
PyObject *py_obj(NULL);
|
||||
int cvt = idcvar_to_pyvar(args[i], &py_obj);
|
||||
if ( cvt < CIP_OK )
|
||||
{
|
||||
if ( errbuf != 0 && errbufsize > 0 )
|
||||
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( as_tupple )
|
||||
{
|
||||
// Opaque object?
|
||||
if ( cvt == CIP_OK_NODECREF )
|
||||
{
|
||||
// Increment reference for opaque objects.
|
||||
// (A tupple will steal references of its set items,
|
||||
// and for an opaque object we want it to still exist
|
||||
// even if the tuple is gone)
|
||||
Py_INCREF(py_obj);
|
||||
}
|
||||
// Save argument
|
||||
PyTuple_SetItem(py_tuple, i, py_obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
pargs.push_back(py_obj);
|
||||
// Do not decrement reference of opaque objects
|
||||
decref->push_back(cvt == CIP_OK);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Frees arguments returned by pyw_convert_idc_args()
|
||||
void pyw_free_idc_args(
|
||||
ppyobject_vec_t &pargs,
|
||||
boolvec_t *decref)
|
||||
{
|
||||
if ( decref == NULL )
|
||||
{
|
||||
if ( !pargs.empty() )
|
||||
Py_XDECREF(pargs[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// free argument objects
|
||||
for ( int i=(int)pargs.size()-1; i>=0; i-- )
|
||||
{
|
||||
if ( decref->at(i) )
|
||||
Py_DECREF(pargs[i]);
|
||||
}
|
||||
decref->clear();
|
||||
}
|
||||
pargs.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// String constants used
|
||||
static const char S_PYINVOKE0[] = "_py_invoke0";
|
||||
static const char S_PY_SWIEX_CLSNAME[] = "switch_info_ex_t";
|
||||
static const char S_PY_OP_T_CLSNAME[] = "op_t";
|
||||
static const char S_PROPS[] = "props";
|
||||
@ -1121,6 +1272,22 @@ struct py_add_del_menu_item_ctx
|
||||
PyObject *cb_data;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Context structure used by add|del_idc_hotkey()
|
||||
struct py_idchotkey_ctx_t
|
||||
{
|
||||
qstring hotkey;
|
||||
PyObject *pyfunc;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Context structure used by register/unregister timer
|
||||
struct py_timer_ctx_t
|
||||
{
|
||||
qtimer_t timer_id;
|
||||
PyObject *pycallback;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const char *pywraps_check_autoscripts()
|
||||
{
|
||||
@ -1146,6 +1313,43 @@ const char *pywraps_check_autoscripts()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
error_t PyW_CreateIdcException(idc_value_t *res, const char *msg)
|
||||
{
|
||||
// Create exception object
|
||||
VarObject(res, find_idc_class("exception"));
|
||||
|
||||
// Set the message field
|
||||
idc_value_t v;
|
||||
v.set_string(msg);
|
||||
VarSetAttr(res, "message", &v);
|
||||
|
||||
// Throw exception
|
||||
return set_qerrno(eExecThrow);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Calls a Python callable encoded in IDC.pvoid member
|
||||
static const char idc_py_invoke0_args[] = { VT_PVOID, 0 };
|
||||
static error_t idaapi idc_py_invoke0(
|
||||
idc_value_t *argv,
|
||||
idc_value_t *res)
|
||||
{
|
||||
PyObject *pyfunc = (PyObject *) argv[0].pvoid;
|
||||
PYW_GIL_ENSURE;
|
||||
PyObject *py_result = PyObject_CallFunctionObjArgs(pyfunc, NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
Py_XDECREF(py_result);
|
||||
|
||||
// Report Python error as IDC exception
|
||||
qstring err;
|
||||
if ( PyW_GetError(&err) )
|
||||
return PyW_CreateIdcException(res, err.c_str());
|
||||
|
||||
return eOk;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// This function must be called on initialization
|
||||
bool init_pywraps()
|
||||
@ -1163,6 +1367,11 @@ bool init_pywraps()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register the IDC PyInvoke0 method (helper function for add_idc_hotkey())
|
||||
if ( !set_idc_func_ex(S_PYINVOKE0, idc_py_invoke0, idc_py_invoke0_args, 0) )
|
||||
return false;
|
||||
|
||||
// IDC opaque class not registered?
|
||||
if ( get_py_idc_cvt_opaque() == NULL )
|
||||
{
|
||||
// Add the class
|
||||
@ -1196,6 +1405,9 @@ void deinit_pywraps()
|
||||
pywraps_initialized = false;
|
||||
Py_XDECREF(py_cvt_helper_module);
|
||||
py_cvt_helper_module = NULL;
|
||||
|
||||
// Unregister the IDC PyInvoke0 method (helper function for add_idc_hotkey())
|
||||
set_idc_func_ex(S_PYINVOKE0, NULL, idc_py_invoke0_args, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -1250,7 +1462,7 @@ PyObject *create_idaapi_linked_class_instance(
|
||||
// This function takes a reference to the idaapi module and keeps the reference
|
||||
PyObject *get_idaapi_attr_by_id(const int class_id)
|
||||
{
|
||||
if ( class_id >= PY_CLSID_LAST )
|
||||
if ( class_id >= PY_CLSID_LAST || py_cvt_helper_module == NULL )
|
||||
return NULL;
|
||||
|
||||
// Some class names. The array is parallel with the PY_CLSID_xxx consts
|
||||
@ -1267,7 +1479,9 @@ PyObject *get_idaapi_attr_by_id(const int class_id)
|
||||
// Gets a class reference by name
|
||||
PyObject *get_idaapi_attr(const char *attrname)
|
||||
{
|
||||
return PyW_TryGetAttrString(py_cvt_helper_module, attrname);
|
||||
return py_cvt_helper_module == NULL
|
||||
? NULL
|
||||
: PyW_TryGetAttrString(py_cvt_helper_module, attrname);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -1467,7 +1681,7 @@ bool PyW_ObjectToString(PyObject *obj, qstring *out)
|
||||
//--------------------------------------------------------------------------
|
||||
// Checks if a Python error occured and fills the out parameter with the
|
||||
// exception string
|
||||
bool PyW_GetError(qstring *out)
|
||||
bool PyW_GetError(qstring *out, bool clear_err)
|
||||
{
|
||||
if ( PyErr_Occurred() == NULL )
|
||||
return false;
|
||||
@ -1476,14 +1690,77 @@ bool PyW_GetError(qstring *out)
|
||||
if ( out == NULL )
|
||||
{
|
||||
// Just clear the error
|
||||
if ( clear_err )
|
||||
PyErr_Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the exception info
|
||||
PyObject *err_type, *err_value, *err_traceback, *py_ret(NULL);
|
||||
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||
|
||||
if ( !clear_err )
|
||||
PyErr_Restore(err_type, err_value, err_traceback);
|
||||
|
||||
// Resolve FormatExc()
|
||||
PyObject *py_fmtexc = get_idaapi_attr(S_IDAAPI_FORMATEXC);
|
||||
|
||||
// Helper there?
|
||||
if ( py_fmtexc != NULL )
|
||||
{
|
||||
// Call helper
|
||||
PYW_GIL_ENSURE;
|
||||
py_ret = PyObject_CallFunctionObjArgs(
|
||||
py_fmtexc,
|
||||
err_type,
|
||||
err_value,
|
||||
err_traceback,
|
||||
NULL);
|
||||
PYW_GIL_RELEASE;
|
||||
|
||||
// Dispose helper reference
|
||||
Py_DECREF(py_fmtexc);
|
||||
}
|
||||
|
||||
// Clear the error
|
||||
if ( clear_err )
|
||||
PyErr_Clear();
|
||||
|
||||
// Helper failed?!
|
||||
if ( py_ret == NULL )
|
||||
{
|
||||
// Just convert the 'value' part of the original error
|
||||
py_ret = PyObject_Str(err_value);
|
||||
}
|
||||
|
||||
// No exception text?
|
||||
if ( py_ret == NULL )
|
||||
{
|
||||
*out = "IDAPython: unknown error!";
|
||||
}
|
||||
else
|
||||
{
|
||||
PyObject *err_type, *err_value, *err_traceback;
|
||||
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||
PyW_ObjectToString(err_value, out);
|
||||
*out = PyString_AsString(py_ret);
|
||||
Py_DECREF(py_ret);
|
||||
}
|
||||
|
||||
if ( clear_err )
|
||||
{
|
||||
Py_XDECREF(err_traceback);
|
||||
Py_XDECREF(err_value);
|
||||
Py_XDECREF(err_type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool PyW_GetError(char *buf, size_t bufsz, bool clear_err)
|
||||
{
|
||||
qstring s;
|
||||
if ( !PyW_GetError(&s, clear_err) )
|
||||
return false;
|
||||
|
||||
qstrncpy(buf, s.c_str(), bufsz);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1770,11 +2047,11 @@ bool pywraps_nw_term()
|
||||
{
|
||||
if ( g_nw == NULL )
|
||||
return true;
|
||||
|
||||
|
||||
// If could not deinitialize then return w/o stopping nw
|
||||
if ( !g_nw->deinit() )
|
||||
return false;
|
||||
|
||||
|
||||
// Cleanup
|
||||
delete g_nw;
|
||||
g_nw = NULL;
|
||||
@ -1874,7 +2151,9 @@ class pyidc_opaque_object_t(object):
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class py_clinked_object_t(pyidc_opaque_object_t):
|
||||
"""This is a utility and base class for C linked objects"""
|
||||
"""
|
||||
This is a utility and base class for C linked objects
|
||||
"""
|
||||
def __init__(self, lnk = None):
|
||||
# static link: if a link was provided
|
||||
self.__static_clink__ = True if lnk else False
|
||||
@ -1884,22 +2163,13 @@ class py_clinked_object_t(pyidc_opaque_object_t):
|
||||
|
||||
def __del__(self):
|
||||
"""Delete the link upon object destruction (only if not static)"""
|
||||
if not self.__static_clink__:
|
||||
self._free()
|
||||
|
||||
def _free(self):
|
||||
"""Explicitly delete the link (only if not static)"""
|
||||
if not self.__static_clink__ and self.__clink__ is not None:
|
||||
self._del_clink(self.__clink__)
|
||||
|
||||
def _create_clink(self):
|
||||
"""
|
||||
Overwrite me.
|
||||
Creates a new clink
|
||||
@return: PyCObject representing the C link
|
||||
"""
|
||||
pass
|
||||
|
||||
def _del_clink(self, lnk):
|
||||
"""Overwrite me.
|
||||
This method deletes the link
|
||||
"""
|
||||
pass
|
||||
self.__clink__ = None
|
||||
|
||||
def copy(self):
|
||||
"""Returns a new copy of this class"""
|
||||
@ -1912,6 +2182,31 @@ class py_clinked_object_t(pyidc_opaque_object_t):
|
||||
|
||||
return inst
|
||||
|
||||
#
|
||||
# Methods to be overwritten
|
||||
#
|
||||
def _create_clink(self):
|
||||
"""
|
||||
Overwrite me.
|
||||
Creates a new clink
|
||||
@return: PyCObject representing the C link
|
||||
"""
|
||||
pass
|
||||
|
||||
def _del_clink(self, lnk):
|
||||
"""
|
||||
Overwrite me.
|
||||
This method deletes the link
|
||||
"""
|
||||
pass
|
||||
|
||||
def _get_clink_ptr(self):
|
||||
"""
|
||||
Overwrite me.
|
||||
Returns the C link pointer as a 64bit number
|
||||
"""
|
||||
pass
|
||||
|
||||
def assign(self, other):
|
||||
"""
|
||||
Overwrite me.
|
||||
@ -1921,6 +2216,10 @@ class py_clinked_object_t(pyidc_opaque_object_t):
|
||||
pass
|
||||
|
||||
clink = property(lambda self: self.__clink__)
|
||||
"""Returns the C link as a PyObject"""
|
||||
|
||||
clink_ptr = property(lambda self: self._get_clink_ptr())
|
||||
"""Returns the C link pointer as a number"""
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class object_t(object):
|
||||
@ -1996,6 +2295,75 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__):
|
||||
def __rmul__(self, other): return self.__op(2, other, True)
|
||||
def __rdiv__(self, other): return self.__op(3, other, True)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# qstrvec_t clinked object
|
||||
class qstrvec_t(py_clinked_object_t):
|
||||
"""Class representing an qstrvec_t"""
|
||||
|
||||
def __init__(self, items=None):
|
||||
py_clinked_object_t.__init__(self)
|
||||
# Populate the list if needed
|
||||
if items:
|
||||
self.from_list(items)
|
||||
|
||||
def _create_clink(self):
|
||||
return _idaapi.qstrvec_t_create()
|
||||
|
||||
def _del_clink(self, lnk):
|
||||
return _idaapi.qstrvec_t_destroy(lnk)
|
||||
|
||||
def _get_clink_ptr(self):
|
||||
return _idaapi.qstrvec_t_get_clink_ptr(self)
|
||||
|
||||
def assign(self, other):
|
||||
"""Copies the contents of 'other' to 'self'"""
|
||||
return _idaapi.qstrvec_t_assign(self, other)
|
||||
|
||||
def __setitem__(self, idx, s):
|
||||
"""Sets string at the given index"""
|
||||
return _idaapi.qstrvec_t_set(self, idx, s)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""Gets the string at the given index"""
|
||||
return _idaapi.qstrvec_t_get(self, idx)
|
||||
|
||||
def __get_size(self):
|
||||
return _idaapi.qstrvec_t_size(self)
|
||||
|
||||
size = property(__get_size)
|
||||
"""Returns the count of elements"""
|
||||
|
||||
def addressof(self, idx):
|
||||
"""Returns the address (as number) of the qstring at the given index"""
|
||||
return _idaapi.qstrvec_t_addressof(self, idx)
|
||||
|
||||
def add(self, s):
|
||||
"""Add a string to the vector"""
|
||||
return _idaapi.qstrvec_t_add(self, s)
|
||||
|
||||
|
||||
def from_list(self, lst):
|
||||
"""Populates the vector from a Python string list"""
|
||||
return _idaapi.qstrvec_t_from_list(self, lst)
|
||||
|
||||
|
||||
def clear(self, qclear=False):
|
||||
"""
|
||||
Clears all strings from the vector.
|
||||
@param qclear: Just reset the size but do not actually free the memory
|
||||
"""
|
||||
return _idaapi.qstrvec_t_clear(self, qclear)
|
||||
|
||||
|
||||
def insert(self, idx, s):
|
||||
"""Insert a string into the vector"""
|
||||
return _idaapi.qstrvec_t_insert(self, idx, s)
|
||||
|
||||
|
||||
def remove(self, idx):
|
||||
"""Removes a string from the vector"""
|
||||
return _idaapi.qstrvec_t_remove(self, idx)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class PyIdc_cvt_refclass__(pyidc_cvt_helper__):
|
||||
"""Helper class for representing references to immutable objects"""
|
||||
@ -2098,8 +2466,19 @@ def IDAPython_ExecSystem(cmd):
|
||||
s = ''.join(f.readlines())
|
||||
f.close()
|
||||
return s
|
||||
except Exception, e:
|
||||
return str(e)
|
||||
except Exception as e:
|
||||
return "%s\n%s" % (str(e), traceback.format_exc())
|
||||
|
||||
# ------------------------------------------------------------
|
||||
def IDAPython_FormatExc(etype, value, tb, limit=None):
|
||||
"""
|
||||
This function is used to format an exception given the
|
||||
values returned by a PyErr_Fetch()
|
||||
"""
|
||||
try:
|
||||
return ''.join(traceback.format_exception(etype, value, tb, limit))
|
||||
except:
|
||||
return str(value)
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
@ -2125,12 +2504,12 @@ def IDAPython_ExecScript(script, g):
|
||||
old__file__ = g['__file__'] if '__file__' in g else ''
|
||||
g['__file__'] = script
|
||||
|
||||
PY_COMPILE_ERR = None
|
||||
try:
|
||||
execfile(script, g)
|
||||
except Exception, e:
|
||||
PY_COMPILE_ERR = str(e) + "\n" + traceback.format_exc()
|
||||
print PY_COMPILE_ERR
|
||||
PY_COMPILE_ERR = None
|
||||
except Exception as e:
|
||||
PY_COMPILE_ERR = "%s\n%s" % (str(e), traceback.format_exc())
|
||||
print(PY_COMPILE_ERR)
|
||||
finally:
|
||||
# Restore the globals to the state before the script was run
|
||||
g['__file__'] = old__file__
|
||||
@ -2156,7 +2535,9 @@ class __IDAPython_Completion_Util(object):
|
||||
|
||||
@staticmethod
|
||||
def parse_identifier(line, prefix, prefix_start):
|
||||
"""Parse a line and extracts"""
|
||||
"""
|
||||
Parse a line and extracts identifier
|
||||
"""
|
||||
id_start = prefix_start
|
||||
while id_start > 0:
|
||||
ch = line[id_start]
|
||||
@ -2181,7 +2562,7 @@ class __IDAPython_Completion_Util(object):
|
||||
|
||||
for i in xrange(0, c-1):
|
||||
m = getattr(m, parts[i])
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
return (None, None)
|
||||
else:
|
||||
# search in the module
|
||||
@ -2388,6 +2769,112 @@ def RunPythonStatement(stmt):
|
||||
#</pydoc>
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// qstrvec_t wrapper
|
||||
//---------------------------------------------------------------------------
|
||||
DECLARE_PY_CLINKED_OBJECT(qstrvec_t);
|
||||
|
||||
static bool qstrvec_t_assign(PyObject *self, PyObject *other)
|
||||
{
|
||||
qstrvec_t *lhs = qstrvec_t_get_clink(self);
|
||||
qstrvec_t *rhs = qstrvec_t_get_clink(other);
|
||||
if (lhs == NULL || rhs == NULL)
|
||||
return false;
|
||||
*lhs = *rhs;
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL || idx >= sv->size() )
|
||||
Py_RETURN_NONE;
|
||||
else
|
||||
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)&sv->at(idx));
|
||||
}
|
||||
|
||||
|
||||
static bool qstrvec_t_set(
|
||||
PyObject *self,
|
||||
size_t idx,
|
||||
const char *s)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL || idx >= sv->size() )
|
||||
return false;
|
||||
(*sv)[idx] = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qstrvec_t_from_list(
|
||||
PyObject *self,
|
||||
PyObject *py_list)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
return sv == NULL ? false : PyW_PyListToStrVec(py_list, *sv);
|
||||
}
|
||||
|
||||
static size_t qstrvec_t_size(PyObject *self)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
return sv == NULL ? 0 : sv->size();
|
||||
}
|
||||
|
||||
static PyObject *qstrvec_t_get(PyObject *self, size_t idx)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL || idx >= sv->size() )
|
||||
Py_RETURN_NONE;
|
||||
return PyString_FromString(sv->at(idx).c_str());
|
||||
}
|
||||
|
||||
static bool qstrvec_t_add(PyObject *self, const char *s)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL )
|
||||
return false;
|
||||
sv->push_back(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qstrvec_t_clear(PyObject *self, bool qclear)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL )
|
||||
return false;
|
||||
|
||||
if ( qclear )
|
||||
sv->qclear();
|
||||
else
|
||||
sv->clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qstrvec_t_insert(
|
||||
PyObject *self,
|
||||
size_t idx,
|
||||
const char *s)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL || idx >= sv->size() )
|
||||
return false;
|
||||
sv->insert(sv->begin() + idx, s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qstrvec_t_remove(PyObject *self, size_t idx)
|
||||
{
|
||||
qstrvec_t *sv = qstrvec_t_get_clink(self);
|
||||
if ( sv == NULL || idx >= sv->size() )
|
||||
return false;
|
||||
|
||||
sv->erase(sv->begin()+idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
14
swig/idd.i
14
swig/idd.i
@ -90,7 +90,7 @@ PyObject *py_appcall(
|
||||
if ( !ok )
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
PyExc_ValueError,
|
||||
"PyAppCall: Failed to convert Python values to IDC values");
|
||||
return NULL;
|
||||
}
|
||||
@ -275,9 +275,9 @@ static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_va
|
||||
ea_t answer;
|
||||
thid_t tid = PyInt_AsLong(py_tid);
|
||||
int sreg_value = PyInt_AsLong(py_sreg_value);
|
||||
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
|
||||
if ( internal_get_sreg_base(tid, sreg_value, &answer) != 1 )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
|
||||
return Py_BuildValue(PY_FMT64, pyul_t(answer));
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ static PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
||||
char *buf;
|
||||
PyString_AsStringAndSize(ret, &buf, &len);
|
||||
|
||||
if ( (size_t)dbg->read_memory(ea_t(ea), buf, size_t(sz)) != sz )
|
||||
if ( (size_t)read_dbg_memory(ea_t(ea), buf, size_t(sz)) != sz )
|
||||
{
|
||||
// Release the string on failure
|
||||
Py_DECREF(ret);
|
||||
@ -339,7 +339,7 @@ static PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
||||
|
||||
size_t sz = PyString_GET_SIZE(py_buf);
|
||||
void *buf = (void *)PyString_AS_STRING(py_buf);
|
||||
if ( dbg->write_memory(ea_t(ea), buf, sz) != sz )
|
||||
if ( write_dbg_memory(ea_t(ea), buf, sz) != sz )
|
||||
Py_RETURN_FALSE;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
@ -386,7 +386,7 @@ static PyObject *dbg_get_memory_info()
|
||||
invalidate_dbgmem_contents(BADADDR, BADADDR);
|
||||
|
||||
meminfo_vec_t areas;
|
||||
dbg->get_memory_info(areas);
|
||||
get_dbg_memory_info(&areas);
|
||||
return meminfo_vec_t_to_py(areas);
|
||||
}
|
||||
|
||||
@ -587,7 +587,7 @@ class Appcall_callable__(object):
|
||||
self.type,
|
||||
self.fields,
|
||||
arg_list)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
e_obj = e
|
||||
|
||||
# Restore appcall options
|
||||
|
308
swig/idp.i
308
swig/idp.i
@ -423,7 +423,7 @@ static PyObject *ph_get_operand_info(
|
||||
regvals_t regvalues;
|
||||
regvalues.resize(dbg->registers_size);
|
||||
// Read registers
|
||||
if ( dbg->read_registers(tid, -1, regvalues.begin()) != 1 )
|
||||
if ( get_reg_vals(tid, -1, regvalues.begin()) != 1 )
|
||||
break;
|
||||
|
||||
// Call the processor module
|
||||
@ -749,7 +749,7 @@ public:
|
||||
|
||||
virtual PyObject *custom_mnem()
|
||||
{
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
virtual int is_sane_insn(int no_crefs)
|
||||
@ -825,7 +825,7 @@ public:
|
||||
bool /*use32*/,
|
||||
const char * /*line*/)
|
||||
{
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
@ -865,7 +865,7 @@ public:
|
||||
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*/) { 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; };
|
||||
@ -1067,6 +1067,303 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
|
||||
Py_XDECREF(py_buffer);
|
||||
break;
|
||||
}
|
||||
// validate_flirt_func, // flirt has recognized a library function
|
||||
// // this callback can be used by a plugin or proc module
|
||||
// // to intercept it and validate such a function
|
||||
// // args: ea_t start_ea
|
||||
// // const char *funcname
|
||||
// // returns: -1-do not create a function,
|
||||
// // 1-function is validated
|
||||
// // the idp module is allowed to modify 'cmd'
|
||||
// set_func_start, // Function chunk start address will be changed
|
||||
// // args: func_t *pfn
|
||||
// // ea_t new_start
|
||||
// // Returns: 1-ok,<=0-do not change
|
||||
// set_func_end, // Function chunk end address will be changed
|
||||
// // args: func_t *pfn
|
||||
// // ea_t new_end
|
||||
// // Returns: 1-ok,<=0-do not change
|
||||
// outlabel, // The kernel is going to generate an instruction
|
||||
// // label line or a function header
|
||||
// // args:
|
||||
// // ea_t ea -
|
||||
// // const char *colored_name -
|
||||
// // If returns value <=0, then the kernel should
|
||||
// // not generate the label
|
||||
// may_show_sreg, // The kernel wants to display the segment registers
|
||||
// // in the messages window.
|
||||
// // arg - ea_t current_ea
|
||||
// // if this function returns 0
|
||||
// // then the kernel will not show
|
||||
// // the segment registers.
|
||||
// // (assuming that the module have done it)
|
||||
// coagulate, // Try to define some unexplored bytes
|
||||
// // This notification will be called if the
|
||||
// // kernel tried all possibilities and could
|
||||
// // not find anything more useful than to
|
||||
// // convert to array of bytes.
|
||||
// // The module can help the kernel and convert
|
||||
// // the bytes into something more useful.
|
||||
// // arg:
|
||||
// // ea_t start_ea
|
||||
// // returns: number of converted bytes + 1
|
||||
// auto_empty, // Info: all analysis queues are empty
|
||||
// // args: none
|
||||
// // returns: none
|
||||
// // This callback is called once when the
|
||||
// // initial analysis is finished. If the queue is
|
||||
// // not empty upon the return from this callback,
|
||||
// // it will be called later again.
|
||||
// // See also auto_empty_finally.
|
||||
// auto_queue_empty, // One analysis queue is empty
|
||||
// // args: atype_t type
|
||||
// // returns: 1-yes, keep the queue empty
|
||||
// // <=0-no, the queue is not empty anymore
|
||||
// // This callback can be called many times, so
|
||||
// // only the autoMark() functions can be used from it
|
||||
// // (other functions may work but it is not tested)
|
||||
// func_bounds, // find_func_bounds() finished its work
|
||||
// // The module may fine tune the function bounds
|
||||
// // args: int *possible_return_code
|
||||
// // func_t *pfn
|
||||
// // ea_t max_func_end_ea (from the kernel's point of view)
|
||||
// // returns: none
|
||||
// is_jump_func, // is the function a trivial "jump" function?
|
||||
// // args: func_t *pfn
|
||||
// // ea_t *jump_target
|
||||
// // ea_t *func_pointer
|
||||
// // returns: 0-no, 1-don't know, 2-yes, see jump_target
|
||||
// // and func_pointer
|
||||
// gen_regvar_def, // generate register variable definition line
|
||||
// // args: regvar_t *v
|
||||
// // returns: 0-ok
|
||||
// setsgr, // The kernel has changed a segment register value
|
||||
// // args: ea_t startEA
|
||||
// // ea_t endEA
|
||||
// // int regnum
|
||||
// // sel_t value
|
||||
// // sel_t old_value
|
||||
// // uchar tag (SR_... values)
|
||||
// // returns: 1-ok, 0-error
|
||||
// set_compiler, // The kernel has changed the compiler information
|
||||
// // (inf.cc structure)
|
||||
// is_basic_block_end, // Is the current instruction end of a basic block?
|
||||
// // This function should be defined for processors
|
||||
// // with delayed jump slots. The current instruction
|
||||
// // is stored in 'cmd'
|
||||
// // args: bool call_insn_stops_block
|
||||
// // returns: 1-unknown, 0-no, 2-yes
|
||||
// reglink, // IBM PC only, ignore it
|
||||
// get_vxd_name, // IBM PC only, ignore it
|
||||
// // Get Vxd function name
|
||||
// // args: int vxdnum
|
||||
// // int funcnum
|
||||
// // char *outbuf
|
||||
// // returns: nothing
|
||||
//
|
||||
//
|
||||
// moving_segm, // May the kernel move the segment?
|
||||
// // args: segment_t - segment to move
|
||||
// // ea_t to - new segment start address
|
||||
// // returns: 1-yes, <=0-the kernel should stop
|
||||
// move_segm, // A segment is moved
|
||||
// // Fix processor dependent address sensitive information
|
||||
// // args: ea_t from - old segment address
|
||||
// // segment_t* - moved segment
|
||||
// // returns: nothing
|
||||
//
|
||||
//
|
||||
// get_stkvar_scale_factor,// Should stack variable references be multiplied by
|
||||
// // a coefficient before being used in the stack frame?
|
||||
// // Currently used by TMS320C55 because the references into
|
||||
// // the stack should be multiplied by 2
|
||||
// // Returns: scaling factor
|
||||
// // Note: PR_SCALE_STKVARS should be set to use this callback
|
||||
//
|
||||
// create_flat_group, // Create special segment representing the flat group
|
||||
// // (to use for PC mainly)
|
||||
// // args - ea_t image_base, int bitness, sel_t dataseg_sel
|
||||
//
|
||||
// kernel_config_loaded, // This callback is called when ida.cfg is parsed
|
||||
// // args - none, returns - nothing
|
||||
//
|
||||
// might_change_sp, // Does the instruction at 'ea' modify the stack pointer?
|
||||
// // args: ea_t ea
|
||||
// // returns: 1-yes, 0-false
|
||||
// // (not used yet)
|
||||
//
|
||||
// is_alloca_probe, // Does the function at 'ea' behave as __alloca_probe?
|
||||
// // args: ea_t ea
|
||||
// // returns: 2-yes, 1-false
|
||||
//
|
||||
// out_3byte, // Generate text representation of 3byte data
|
||||
// // init_out_buffer() is called before this function
|
||||
// // and all Out... function can be used.
|
||||
// // uFlag contains the flags.
|
||||
// // This callback might be implemented by the processor
|
||||
// // module to generate custom representation of 3byte data.
|
||||
// // args:
|
||||
// // ea_t dataea - address of the data item
|
||||
// // uint32 value - value to output
|
||||
// // bool analyze_only - only create xrefs if necessary
|
||||
// // do not generate text representation
|
||||
// // returns: 2-yes, 1-false
|
||||
//
|
||||
// get_reg_name, // Generate text representation of a register
|
||||
// // int reg - internal register number as defined in the processor module
|
||||
// // size_t width - register width in bytes
|
||||
// // char *buf - output buffer
|
||||
// // size_t bufsize - size of output buffer
|
||||
// // int reghi - if not -1 then this function will return the register pair
|
||||
// // returns: -1 if error, strlen(buf)+2 otherwise
|
||||
// // Most processor modules do not need to implement this callback
|
||||
// // It is useful only if ph.regNames[reg] does not provide
|
||||
// // the correct register names
|
||||
// // save its local data
|
||||
// out_src_file_lnnum, // Callback: generate analog of
|
||||
// // #line "file.c" 123
|
||||
// // directive.
|
||||
// // const char *file - source file (may be NULL)
|
||||
// // size_t lnnum - line number
|
||||
// // returns: 2-directive has been generated
|
||||
// get_autocmt, // Callback: get dynamic auto comment
|
||||
// // Will be called if the autocomments are enabled
|
||||
// // and the comment retrieved from ida.int starts with
|
||||
// // '$!'. 'cmd' is contains valid info.
|
||||
// // char *buf - output buffer
|
||||
// // size_t bufsize - output buffer size
|
||||
// // returns: 2-new comment has been generated
|
||||
// // 1-callback has not been handled
|
||||
// // the buffer must not be changed in this case
|
||||
// is_insn_table_jump, // Callback: determine if instruction is a table jump or call
|
||||
// // If CF_JUMP bit can not describe all kinds of table
|
||||
// // jumps, please define this callback.
|
||||
// // It will be called for insns with CF_JUMP bit set.
|
||||
// // input: cmd structure contains the current instruction
|
||||
// // returns: 1-yes, 0-no
|
||||
// auto_empty_finally, // Info: all analysis queues are empty definitively
|
||||
// // args: none
|
||||
// // returns: none
|
||||
// // This callback is called only once.
|
||||
// // See also auto_empty.
|
||||
// loader_finished, // Event: external file loader finished its work
|
||||
// // linput_t *li
|
||||
// // uint16 neflags
|
||||
// // const char *filetypename
|
||||
// // Use this event to augment the existing loader functionality
|
||||
// loader_elf_machine, // Event: ELF loader machine type checkpoint
|
||||
// // linput_t *li
|
||||
// // int machine_type
|
||||
// // const char **p_procname
|
||||
// // proc_def **p_pd (see ldr\elf.h)
|
||||
// // set_elf_reloc_t *set_reloc
|
||||
// // A plugin check the machine_type. If it is the desired one,
|
||||
// // the the plugin fills p_procname with the processor name.
|
||||
// // p_pd is used to handle relocations, otherwise can be left untouched
|
||||
// // set_reloc can be later used by the plugin to specify relocations
|
||||
// // returns: e_machine value (if it is different from the
|
||||
// // original e_machine value, procname and p_pd will be ignored
|
||||
// // and the new value will be used)
|
||||
// // This event occurs for each loaded ELF file
|
||||
// is_indirect_jump, // Callback: determine if instruction is an indrect jump
|
||||
// // If CF_JUMP bit can not describe all jump types
|
||||
// // jumps, please define this callback.
|
||||
// // input: cmd structure contains the current instruction
|
||||
// // returns: 1-use CF_JUMP, 2-no, 3-yes
|
||||
// verify_noreturn, // The kernel wants to set 'noreturn' flags for a function
|
||||
// // func_t *pfn
|
||||
// // Returns: 1-ok, any other value-do not set 'noreturn' flag
|
||||
// verify_sp, // All function instructions have been analyzed
|
||||
// // Now the processor module can analyze the stack pointer
|
||||
// // for the whole function
|
||||
// // input: func_t *pfn
|
||||
// // Returns: 1-ok, 0-bad stack pointer
|
||||
// treat_hindering_item, // An item hinders creation of another item
|
||||
// // args: ea_t hindering_item_ea
|
||||
// // flags_t new_item_flags (0 for code)
|
||||
// // ea_t new_item_ea
|
||||
// // asize_t new_item_length
|
||||
// // Returns: 1-no reaction, <=0-the kernel may delete the hindering item
|
||||
// str2reg, // Convert a register name to a register number
|
||||
// // args: const char *regname
|
||||
// // Returns: register number + 2
|
||||
// // The register number is the register index in the regNames array
|
||||
// // Most processor modules do not need to implement this callback
|
||||
// // It is useful only if ph.regNames[reg] does not provide
|
||||
// // the correct register names
|
||||
// create_switch_xrefs, // Create xrefs for a custom jump table
|
||||
// // in: ea_t jumpea; - address of the jump insn
|
||||
// // switch_info_ex_t *; - switch information
|
||||
// // returns: must return 2
|
||||
// calc_switch_cases, // Calculate case values and targets for a custom jump table
|
||||
// // in: ea_t insn_ea - address of the 'indirect jump' instruction
|
||||
// // switch_info_ex_t *si - switch information
|
||||
// // casevec_t *casevec - vector of case values...
|
||||
// // evec_t *targets - ...and corresponding target addresses
|
||||
// // casevec and targets may be NULL
|
||||
// // returns: 2-ok, 1-failed
|
||||
// determined_main, // The main() function has been determined
|
||||
// // in: ea_t main - address of the main() function
|
||||
// // returns: none
|
||||
// preprocess_chart, // gui has retrieved a function flow chart
|
||||
// // in: qflow_chart_t *fc
|
||||
// // returns: none
|
||||
// // Plugins may modify the flow chart in this callback
|
||||
// get_bg_color, // Get item background color
|
||||
// // in: ea_t ea, bgcolor_t *color
|
||||
// // Returns: 1-not implemented, 2-color set
|
||||
// // Plugins can hook this callback to color disassembly lines
|
||||
// // dynamically
|
||||
// get_operand_string, // Request text string for operand (cli, java, ...)
|
||||
// // args: int opnum
|
||||
// // char *buf
|
||||
// // size_t buflen
|
||||
// // (cmd structure must contain info for the desired insn)
|
||||
// // opnum is the operand number; -1 means any string operand
|
||||
// // returns: 1 - no string (or empty string)
|
||||
// // >1 - original string length with terminating zero
|
||||
//
|
||||
// // the following 5 events are very low level
|
||||
// // take care of possible recursion
|
||||
// add_cref, // a code reference is being created
|
||||
// // args: ea_t from, ea_t to, cref_t type
|
||||
// // returns: <0 - cancel cref creation
|
||||
// add_dref, // a data reference is being created
|
||||
// // args: ea_t from, ea_t to, dref_t type
|
||||
// // returns: <0 - cancel dref creation
|
||||
// del_cref, // a code reference is being deleted
|
||||
// // args: ea_t from, ea_t to, bool expand
|
||||
// // returns: <0 - cancel cref deletion
|
||||
// del_dref, // a data reference is being deleted
|
||||
// // args: ea_t from, ea_t to
|
||||
// // returns: <0 - cancel dref deletion
|
||||
// coagulate_dref, // data reference is being analyzed
|
||||
// // args: ea_t from, ea_t to, bool may_define, ea_t *code_ea
|
||||
// // plugin may correct code_ea (e.g. for thumb mode refs, we clear the last bit)
|
||||
// // returns: <0 - cancel dref analysis
|
||||
// custom_fixup, // mutipurpose notification for FIXUP_CUSTOM
|
||||
// // args: cust_fix oper, ea_t ea, const fixup_data_t*, ... (see cust_fix)
|
||||
// // returns: 1 - no accepted (fixup ignored by ida)
|
||||
// // >1 - accepted (see cust_fix)
|
||||
// off_preproc, // called from get_offset_expr, when refinfo_t
|
||||
// // contain flag REFINFO_PREPROC. Normally this
|
||||
// // notification used in a combination with custom_fixup
|
||||
// // args: ea_t ea, int numop, ea_t* opval, const refinfo_t* ri,
|
||||
// // char* buf, size_t bufsize, ea_t* target,
|
||||
// // ea_t* fullvalue, ea_t from, int getn_flags
|
||||
// // returns: 2 - buf filled as simple expression
|
||||
// // 3 - buf filled as complex expression
|
||||
// // 4 - apply standard processing (with - possible - changed values)
|
||||
// // others - can't convert to offset expression
|
||||
//
|
||||
// set_proc_options, // called if the user specified an option string in the command line:
|
||||
// // -p<processor name>:<options>
|
||||
// // can be used for e.g. setting a processor subtype
|
||||
// // also called if option string is passed to set_processor_type()
|
||||
// // and IDC's SetProcessorType()
|
||||
// // args: const char * options
|
||||
// // returns: <0 - bad option string
|
||||
//
|
||||
}
|
||||
}
|
||||
catch (Swig::DirectorException &e)
|
||||
@ -1190,7 +1487,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
||||
case idb_event::struc_member_deleted:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
member_id = va_arg(va, tid_t);
|
||||
return proxy->struc_member_deleted(sptr, member_id);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->struc_member_deleted(sptr, member_id, ea);
|
||||
|
||||
case idb_event::struc_member_renamed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
|
901
swig/kernwin.i
901
swig/kernwin.i
File diff suppressed because it is too large
Load Diff
@ -115,6 +115,12 @@
|
||||
|
||||
%ignore mem2base;
|
||||
%rename (mem2base) py_mem2base;
|
||||
%ignore update_snapshot_attributes;
|
||||
%ignore build_snapshot_tree;
|
||||
%ignore visit_snapshot_tree;
|
||||
%ignore save_database_ex;
|
||||
%ignore snapshot_t;
|
||||
%ignore snapshots_t;
|
||||
%ignore load_plugin;
|
||||
%rename (load_plugin) py_load_plugin;
|
||||
%ignore run_plugin;
|
||||
@ -170,8 +176,8 @@ static PyObject *py_load_plugin(const char *name)
|
||||
plugin_t *r = load_plugin(name);
|
||||
if ( r == NULL )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
return PyCObject_FromVoidPtr(r, NULL);
|
||||
else
|
||||
return PyCObject_FromVoidPtr(r, NULL);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -190,8 +196,8 @@ static bool py_run_plugin(PyObject *plg, int arg)
|
||||
{
|
||||
if ( !PyCObject_Check(plg) )
|
||||
return false;
|
||||
|
||||
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
|
||||
else
|
||||
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
|
||||
}
|
||||
|
||||
//</inline(py_loader)>
|
||||
|
@ -566,10 +566,10 @@ class switch_info_ex_t(py_clinked_object_t):
|
||||
return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_SUBTRACT) != 0
|
||||
|
||||
def get_jtable_size(self):
|
||||
return self.jcases if self.is_indirect() else ncases
|
||||
return self.jcases if self.is_indirect() else self.ncases
|
||||
|
||||
def get_lowcase(self):
|
||||
return self.ind_lowcase if is_indirect() else self.lowcase
|
||||
return self.ind_lowcase if self.is_indirect() else self.lowcase
|
||||
|
||||
def set_expr(self, r, dt):
|
||||
self.regnum = r
|
||||
|
@ -90,7 +90,7 @@
|
||||
|
||||
%include "netnode.hpp"
|
||||
|
||||
%extend netnode
|
||||
%extend netnode
|
||||
{
|
||||
nodeidx_t index()
|
||||
{
|
||||
@ -111,5 +111,26 @@
|
||||
|
||||
return py_str;
|
||||
}
|
||||
|
||||
PyObject *hashstr_buf(const char *idx, char tag=htag)
|
||||
{
|
||||
char buf[MAXSPECSIZE];
|
||||
ssize_t sz = self->hashstr(idx, buf, sizeof(buf), tag);
|
||||
if ( sz < 0 )
|
||||
Py_RETURN_NONE;
|
||||
else
|
||||
return PyString_FromStringAndSize(buf, sz);
|
||||
}
|
||||
|
||||
bool hashset_buf(const char *idx, PyObject *py_str, char tag=htag)
|
||||
{
|
||||
char *buf;
|
||||
Py_ssize_t sz;
|
||||
|
||||
if ( PyString_AsStringAndSize(py_str, &buf, &sz) == -1 )
|
||||
return false;
|
||||
else
|
||||
return self->hashset(idx, buf, sz, tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
%ignore print_all_counters;
|
||||
%ignore incrementer_t;
|
||||
%ignore reloc_info_t; // swig under mac chokes on this
|
||||
|
||||
%ignore qstrvec_t;
|
||||
%ignore qmutex_create;
|
||||
%ignore qiterator;
|
||||
%ignore qrefcnt_t;
|
||||
@ -86,3 +86,4 @@
|
||||
%rename (parse_command_line) py_parse_command_line;
|
||||
%include "pro.h"
|
||||
|
||||
SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t)
|
||||
|
64
swig/ua.i
64
swig/ua.i
@ -331,6 +331,31 @@ bool py_out_name_expr(
|
||||
return op == NULL ? false : out_name_expr(*op, ea, off);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
|
||||
{
|
||||
if ( i < 0 || i >= UA_MAXOP || !PyCObject_Check(py_insn_lnk) )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
// Extract C link
|
||||
insn_t *insn = (insn_t *)PyCObject_AsVoidPtr(py_insn_lnk);
|
||||
|
||||
// Return a link to the operand
|
||||
return PyCObject_FromVoidPtr(&insn->Operands[i], NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *insn_t_create()
|
||||
{
|
||||
return PyCObject_FromVoidPtr(new insn_t(), NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *op_t_create()
|
||||
{
|
||||
return PyCObject_FromVoidPtr(new op_t(), NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static bool op_t_assign(PyObject *self, PyObject *other)
|
||||
{
|
||||
@ -355,40 +380,13 @@ static bool insn_t_assign(PyObject *self, PyObject *other)
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
|
||||
{
|
||||
if ( i < 0 || i >= UA_MAXOP || !PyCObject_Check(py_insn_lnk) )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
// Extract C link
|
||||
insn_t *insn = (insn_t *)PyCObject_AsVoidPtr(py_insn_lnk);
|
||||
|
||||
// Return a link to the operand
|
||||
return PyCObject_FromVoidPtr(&insn->Operands[i], NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *insn_t_create()
|
||||
{
|
||||
insn_t *insn = new insn_t();
|
||||
return PyCObject_FromVoidPtr(insn, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PyObject *op_t_create()
|
||||
{
|
||||
op_t *op = new op_t();
|
||||
return PyCObject_FromVoidPtr(op, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static bool op_t_destroy(PyObject *py_obj)
|
||||
{
|
||||
if ( !PyCObject_Check(py_obj) )
|
||||
return false;
|
||||
|
||||
op_t *op = (op_t *) PyCObject_AsVoidPtr(py_obj);
|
||||
op_t *op = (op_t *)PyCObject_AsVoidPtr(py_obj);
|
||||
delete op;
|
||||
|
||||
return true;
|
||||
@ -400,9 +398,7 @@ static bool insn_t_destroy(PyObject *py_obj)
|
||||
if ( !PyCObject_Check(py_obj) )
|
||||
return false;
|
||||
|
||||
insn_t *insn = (insn_t *) PyCObject_AsVoidPtr(py_obj);
|
||||
delete insn;
|
||||
|
||||
delete (insn_t *)PyCObject_AsVoidPtr(py_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -856,12 +852,6 @@ class op_t(py_clinked_object_t):
|
||||
"""Copies the contents of 'other' to 'self'"""
|
||||
return _idaapi.op_t_assign(self, other)
|
||||
|
||||
#<pydoc>
|
||||
# def copy(self):
|
||||
# """Returns a new copy of this class"""
|
||||
# pass
|
||||
#</pydoc>
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Checks if two register operands are equal by checking the register number and its dtype"""
|
||||
return (self.reg == other.reg) and (self.dtyp == other.dtyp)
|
||||
|
Loading…
Reference in New Issue
Block a user