diff --git a/Scripts/ImportExportViewer.py b/Scripts/ImportExportViewer.py
index 7c668ba..2a34871 100644
--- a/Scripts/ImportExportViewer.py
+++ b/Scripts/ImportExportViewer.py
@@ -3,14 +3,14 @@
# - enumerate imports
# - enumerate entrypoints
# - Use PluginForm class
-# - Use PySide with PluginForm to create a Python UI
+# - Use PyQt with PluginForm to create a Python UI
#
# (c) Hex-Rays
#
import idaapi
import idautils
from idaapi import PluginForm
-from PySide import QtGui, QtCore
+from PyQt5 import QtCore, QtWidgets
# --------------------------------------------------------------------------
class ImpExpForm_t(PluginForm):
@@ -51,24 +51,24 @@ class ImpExpForm_t(PluginForm):
self.tree.clear()
# Build imports
- root = QtGui.QTreeWidgetItem(self.tree)
+ root = QtWidgets.QTreeWidgetItem(self.tree)
root.setText(0, "Imports")
for dll_name, imp_entries in self.BuildImports().items():
- imp_dll = QtGui.QTreeWidgetItem(root)
+ imp_dll = QtWidgets.QTreeWidgetItem(root)
imp_dll.setText(0, dll_name)
for imp_ea, imp_name, imp_ord in imp_entries:
- item = QtGui.QTreeWidgetItem(imp_dll)
+ item = QtWidgets.QTreeWidgetItem(imp_dll)
item.setText(0, "%s [0x%08x]" %(imp_name, imp_ea))
# Build exports
- root = QtGui.QTreeWidgetItem(self.tree)
+ root = QtWidgets.QTreeWidgetItem(self.tree)
root.setText(0, "Exports")
for exp_i, exp_ord, exp_ea, exp_name in self.BuildExports():
- item = QtGui.QTreeWidgetItem(root)
+ item = QtWidgets.QTreeWidgetItem(root)
item.setText(0, "%s [#%d] [0x%08x]" % (exp_name, exp_ord, exp_ea))
@@ -78,15 +78,15 @@ class ImpExpForm_t(PluginForm):
"""
# Get parent widget
- self.parent = self.FormToPySideWidget(form)
+ self.parent = self.FormToPyQtWidget(form)
# Create tree control
- self.tree = QtGui.QTreeWidget()
+ self.tree = QtWidgets.QTreeWidget()
self.tree.setHeaderLabels(("Names",))
self.tree.setColumnWidth(0, 100)
# Create layout
- layout = QtGui.QVBoxLayout()
+ layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tree)
self.PopulateTree()
@@ -121,4 +121,4 @@ def main():
ImpExpForm.Show()
# --------------------------------------------------------------------------
-main()
\ No newline at end of file
+main()
diff --git a/api_contents.txt b/api_contents.txt
index 2f000b4..6593fb9 100644
--- a/api_contents.txt
+++ b/api_contents.txt
@@ -2051,6 +2051,7 @@
'delete_enumplace_t',
'delete_eval_ctx_t',
'delete_exception_info_t',
+ 'delete_excvec_t',
'delete_extra_cmts',
'delete_fixup_data_t',
'delete_fnumber_t',
@@ -2461,6 +2462,44 @@
'exception_info_t_handle',
'exception_info_t_name_get',
'exception_info_t_name_set',
+ 'excvec_t___getitem__',
+ 'excvec_t___len__',
+ 'excvec_t___setitem__',
+ 'excvec_t_at',
+ 'excvec_t_back',
+ 'excvec_t_back__SWIG_0',
+ 'excvec_t_back__SWIG_1',
+ 'excvec_t_begin',
+ 'excvec_t_begin__SWIG_0',
+ 'excvec_t_begin__SWIG_1',
+ 'excvec_t_capacity',
+ 'excvec_t_clear',
+ 'excvec_t_empty',
+ 'excvec_t_end',
+ 'excvec_t_end__SWIG_0',
+ 'excvec_t_end__SWIG_1',
+ 'excvec_t_erase',
+ 'excvec_t_erase__SWIG_0',
+ 'excvec_t_erase__SWIG_1',
+ 'excvec_t_extract',
+ 'excvec_t_front',
+ 'excvec_t_front__SWIG_0',
+ 'excvec_t_front__SWIG_1',
+ 'excvec_t_grow',
+ 'excvec_t_inject',
+ 'excvec_t_insert',
+ 'excvec_t_pop_back',
+ 'excvec_t_push_back',
+ 'excvec_t_push_back__SWIG_0',
+ 'excvec_t_push_back__SWIG_1',
+ 'excvec_t_qclear',
+ 'excvec_t_reserve',
+ 'excvec_t_resize',
+ 'excvec_t_resize__SWIG_0',
+ 'excvec_t_resize__SWIG_1',
+ 'excvec_t_size',
+ 'excvec_t_swap',
+ 'excvec_t_truncate',
'execute',
'execute_sync',
'execute_ui_requests',
@@ -3279,6 +3318,7 @@
'get_tev_info',
'get_tev_memory_info',
'get_tev_qty',
+ 'get_tev_reg_mem',
'get_tev_reg_mem_ea',
'get_tev_reg_mem_qty',
'get_tev_reg_val',
@@ -4711,6 +4751,9 @@
'new_exception_info_t',
'new_exception_info_t__SWIG_0',
'new_exception_info_t__SWIG_1',
+ 'new_excvec_t',
+ 'new_excvec_t__SWIG_0',
+ 'new_excvec_t__SWIG_1',
'new_fixup_data_t',
'new_fnumber_t',
'new_func_item_iterator_t',
diff --git a/examples/ex_askusingform.py b/examples/ex_askusingform.py
index 04f7b78..977e364 100644
--- a/examples/ex_askusingform.py
+++ b/examples/ex_askusingform.py
@@ -4,7 +4,6 @@
#
from idaapi import Form
-#
# --------------------------------------------------------------------------
class TestEmbeddedChooserClass(Choose2):
"""
@@ -372,8 +371,6 @@ def test_dropdown_nomodal():
tdn_form, _ = tdn_form.Compile()
tdn_form.Open()
-#
-
# --------------------------------------------------------------------------
ida_main()
diff --git a/examples/ex_choose2.py b/examples/ex_choose2.py
index e91eef1..d7915eb 100644
--- a/examples/ex_choose2.py
+++ b/examples/ex_choose2.py
@@ -1,9 +1,6 @@
import idaapi
from idaapi import Choose2
-#
-
-
class chooser_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
@@ -129,5 +126,3 @@ if __name__ == '__main__':
#test_choose2_embedded()
test_choose2(False)
-
-#
diff --git a/examples/ex_cli.py b/examples/ex_cli.py
index b68d58c..183ac34 100644
--- a/examples/ex_cli.py
+++ b/examples/ex_cli.py
@@ -4,7 +4,6 @@
#
from idaapi import NW_OPENIDB, NW_CLOSEIDB, NW_TERMIDA, NW_REMOVE, COLSTR, cli_t
-#
class mycli_t(cli_t):
flags = 0
sname = "pycli"
@@ -59,7 +58,6 @@ class mycli_t(cli_t):
"""
print "OnCompleteLine: prefix=%s n=%d line=%s prefix_start=%d" % (prefix, n, line, prefix_start)
return None
-#
# -----------------------------------------------------------------------
diff --git a/examples/ex_custview.py b/examples/ex_custview.py
index 36455fb..c38b03b 100644
--- a/examples/ex_custview.py
+++ b/examples/ex_custview.py
@@ -5,8 +5,8 @@
import idaapi
import idc
from idaapi import simplecustviewer_t
-#
+# -----------------------------------------------------------------------
class say_something_handler_t(idaapi.action_handler_t):
def __init__(self, thing):
idaapi.action_handler_t.__init__(self)
@@ -179,5 +179,3 @@ def make_many(n):
v.Show()
L.append(v)
return L
-
-#
diff --git a/examples/ex_expr.py b/examples/ex_expr.py
index 765d746..a40e449 100644
--- a/examples/ex_expr.py
+++ b/examples/ex_expr.py
@@ -4,7 +4,6 @@
#
from idaapi import set_idc_func_ex
-#
def py_power(n, e):
return n ** e
@@ -13,4 +12,3 @@ if ok:
print("Now the pow() will be present IDC!")
else:
print("Failed to register pow() IDC function")
-#
diff --git a/examples/ex_graph.py b/examples/ex_graph.py
index 62f67a1..dafeb6b 100644
--- a/examples/ex_graph.py
+++ b/examples/ex_graph.py
@@ -17,30 +17,51 @@ class GraphCloser(action_handler_t):
return AST_ENABLE_ALWAYS
+class ColorChanger(action_handler_t):
+ def __init__(self, graph):
+ action_handler_t.__init__(self)
+ self.graph = graph
+
+ def activate(self, ctx):
+ self.graph.color = self.graph.color ^ 0xffffff
+ self.graph.Refresh()
+ return 1
+
+ def update(self, ctx):
+ return AST_ENABLE_ALWAYS
+
+
class MyGraph(GraphViewer):
def __init__(self, funcname, result):
self.title = "call graph of " + funcname
GraphViewer.__init__(self, self.title)
self.funcname = funcname
self.result = result
+ self.color = 0xff00ff
def OnRefresh(self):
self.Clear()
- id = self.AddNode(self.funcname)
+ id = self.AddNode((self.funcname, self.color))
for x in self.result.keys():
- callee = self.AddNode(x)
+ callee = self.AddNode((x, self.color))
self.AddEdge(id, callee)
return True
def OnGetText(self, node_id):
- return str(self[node_id])
+ return self[node_id]
def Show(self):
if not GraphViewer.Show(self):
return False
+ # graph closer
actname = "graph_closer:%s" % self.title
- register_action(action_desc_t(actname, "Close %s" % self.title, GraphCloser(self)))
+ register_action(action_desc_t(actname, "Close: %s" % self.title, GraphCloser(self)))
+ attach_action_to_popup(self.GetTCustomControl(), None, actname)
+
+ # color changer
+ actname = "color_changer:%s" % self.title
+ register_action(action_desc_t(actname, "Change colors: %s" % self.title, ColorChanger(self)))
attach_action_to_popup(self.GetTCustomControl(), None, actname)
return True
diff --git a/examples/vds4.py b/examples/vds4.py
index 5c8e02d..0cb666c 100644
--- a/examples/vds4.py
+++ b/examples/vds4.py
@@ -68,51 +68,22 @@ def run():
idaapi.user_numforms_free(numforms)
# Display user-defined local variable information
- # First defined the visitor class
- class dump_lvar_info_t(idaapi.user_lvar_visitor_t):
+ lvinf = idaapi.lvar_uservec_t()
+ if idaapi.restore_user_lvar_settings(lvinf, entry_ea):
+ print "------- User defined local variable information\n"
+ for lv in lvinf.lvvec:
+ print "Lvar defined at %x" % (lv.ll.defea, )
- def __init__(self):
- idaapi.user_lvar_visitor_t.__init__(self)
- self.displayed_header = False
- return
+ if len(str(lv.name)):
+ print " Name: %s" % (str(lv.name), )
- def get_info_qty_for_saving(self):
- return 0
+ if len(str(lv.type)):
+ #~ print_type_to_one_line(buf, sizeof(buf), idati, .c_str());
+ print " Type: %s" % (str(lv.type), )
- def get_info_for_saving(self, lv):
- return False
+ if len(str(lv.cmt)):
+ print " Comment: %s" % (str(lv.cmt), )
- def handle_retrieved_info(self, lv):
-
- try:
- if not self.displayed_header:
- self.displayed_header = True;
- print "------- User defined local variable information"
-
- print "Lvar defined at %x" % (lv.ll.defea, )
-
- if len(str(lv.name)):
- print " Name: %s" % (str(lv.name), )
-
- if len(str(lv.type)):
- #~ print_type_to_one_line(buf, sizeof(buf), idati, .c_str());
- print " Type: %s" % (str(lv.type), )
-
- if len(str(lv.cmt)):
- print " Comment: %s" % (str(lv.cmt), )
- except:
- traceback.print_exc()
- return 0
-
- def handle_retrieved_mapping(self, lm):
- return 0
-
- def get_info_mapping_for_saving(self):
- return None
-
- # Now iterate over all user definitions
- dli = dump_lvar_info_t();
- idaapi.restore_user_lvar_settings(entry_ea, dli)
return
diff --git a/examples/vds_xrefs.py b/examples/vds_xrefs.py
index b78eb26..b949b27 100644
--- a/examples/vds_xrefs.py
+++ b/examples/vds_xrefs.py
@@ -15,17 +15,7 @@ import idc
import traceback
-try:
- from PyQt4 import QtCore, QtGui
- print 'Using PyQt'
-except:
- print 'PyQt not available'
-
- try:
- from PySide import QtGui, QtCore
- print 'Using PySide'
- except:
- print 'PySide not available'
+from PyQt5 import QtCore, QtWidgets
XREF_EA = 0
XREF_STRUC_MEMBER = 1
@@ -78,10 +68,7 @@ class XrefsForm(idaapi.PluginForm):
def OnCreate(self, form):
# Get parent widget
- try:
- self.parent = self.FormToPySideWidget(form)
- except:
- self.parent = self.FormToPyQtWidget(form)
+ self.parent = self.FormToPyQtWidget(form)
self.populate_form()
@@ -93,16 +80,16 @@ class XrefsForm(idaapi.PluginForm):
def populate_form(self):
# Create layout
- layout = QtGui.QVBoxLayout()
+ layout = QtWidgets.QVBoxLayout()
- layout.addWidget(QtGui.QLabel(self.__name))
- self.table = QtGui.QTableWidget()
+ layout.addWidget(QtWidgets.QLabel(self.__name))
+ self.table = QtWidgets.QTableWidget()
layout.addWidget(self.table)
self.table.setColumnCount(3)
- self.table.setHorizontalHeaderItem(0, QtGui.QTableWidgetItem("Address"))
- self.table.setHorizontalHeaderItem(1, QtGui.QTableWidgetItem("Function"))
- self.table.setHorizontalHeaderItem(2, QtGui.QTableWidgetItem("Line"))
+ self.table.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem("Address"))
+ self.table.setHorizontalHeaderItem(1, QtWidgets.QTableWidgetItem("Function"))
+ self.table.setHorizontalHeaderItem(2, QtWidgets.QTableWidgetItem("Line"))
self.table.setColumnWidth(0, 80)
self.table.setColumnWidth(1, 150)
@@ -110,8 +97,8 @@ class XrefsForm(idaapi.PluginForm):
self.table.cellDoubleClicked.connect(self.double_clicked)
- #~ self.table.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
- self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows )
+ #~ self.table.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
+ self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows )
self.parent.setLayout(layout)
self.populate_table()
@@ -244,13 +231,13 @@ class XrefsForm(idaapi.PluginForm):
i = 0
for item in self.items:
address, func, line = item
- item = QtGui.QTableWidgetItem('0x%x' % (address, ))
+ item = QtWidgets.QTableWidgetItem('0x%x' % (address, ))
item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
self.table.setItem(i, 0, item)
- item = QtGui.QTableWidgetItem(func)
+ item = QtWidgets.QTableWidgetItem(func)
item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
self.table.setItem(i, 1, item)
- item = QtGui.QTableWidgetItem(line)
+ item = QtWidgets.QTableWidgetItem(line)
item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
self.table.setItem(i, 2, item)
diff --git a/makefile b/makefile
index 1bc2ff3..8443621 100644
--- a/makefile
+++ b/makefile
@@ -94,6 +94,7 @@ ifeq ($(OUT_OF_TREE_BUILD),)
DEPLOY_INIT_PY=$(SCRIPTDIR)/init.py
DEPLOY_IDC_PY=$(SCRIPTDIR)/idc.py
DEPLOY_IDAUTILS_PY=$(SCRIPTDIR)/idautils.py
+ DEPLOY_PYTHON_CFG=$(C)python.cfg
TEST_IDC=test_idc
else
SCRIPTDIR=python
diff --git a/python/idc.py b/python/idc.py
index b34277c..e2be3d1 100644
--- a/python/idc.py
+++ b/python/idc.py
@@ -1715,11 +1715,7 @@ def GetInputMD5():
@return: MD5 string or None on error
"""
- ua = idaapi.uchar_array(16)
- if idaapi.retrieve_input_file_md5(ua.cast()):
- return "".join(["%02X" % ua[i] for i in xrange(16)])
- else:
- return None
+ return idaapi.retrieve_input_file_md5()
def GetFlags(ea):
@@ -2032,7 +2028,7 @@ def GetReg(ea, reg):
@return: the value of the segment register or -1 on error
@note: The segment registers in 32bit program usually contain selectors,
- so to get paragraph pointed by the segment register you need to
+ so to get paragraph pointed to by the segment register you need to
call AskSelector() function.
"""
reg = idaapi.str2reg(reg);
@@ -2598,6 +2594,8 @@ LFLG_64BIT = 0x04 # 64-bit program?
LFLG_DBG_NOPATH = 0x08 # do not store input full path
LFLG_SNAPSHOT = 0x10 # is memory snapshot?
# in debugger process options
+LFLG_8ALIGN4 = 0x40 # 4 byte alignment for 8byte scalars
+ # (__int64/double) inside structures
INF_DEMNAMES = 14 # char; display demangled names as:
DEMNAM_CMNT = 0 # comments
DEMNAM_NAME = 1 # regular names
@@ -2822,6 +2820,9 @@ INF_SIZEOF_LONG = 190
INF_SIZEOF_LLONG = 191
INF_CHANGE_COUNTER = 192 # database change counter; keeps track of byte and segment modifications
INF_SIZEOF_LDBL = 196 # uchar; sizeof(long double)
+INF_REFCMTS = 221 # uchar; number of comment lines to generate for refs
+ # to ASCII string or demangled name
+ # 0 - such comments won't be generated at all
# Redefine these offsets for 64-bit version
if __EA64__:
@@ -2895,7 +2896,8 @@ if __EA64__:
INF_SIZEOF_LONG = 274
INF_SIZEOF_LLONG = 275
INF_CHANGE_COUNTER = 276
- INF_SIZEOF_LBDL = 280
+ INF_SIZEOF_LDBL = 280
+ INF_REFCMTS = 305
_INFMAP = {
INF_VERSION : (False, 'version'), # short; Version of database
@@ -7050,6 +7052,38 @@ PT_HIGH = 0x0080 # assume high level prototypes
PT_LOWER = 0x0100 # lower the function prototypes
+def PrintLocalTypes(ordinals, flags):
+ """
+ Print types in a format suitable for use in a header file
+
+ @param ordinals: comma-separated list of type ordinals
+ @param flags: combination of PDF_... constants or 0
+
+ @return: string containing the type definitions
+ """
+ class def_sink(idaapi.text_sink_t):
+
+ def __init__(self):
+ idaapi.text_sink_t.__init__(self)
+ self.text = ""
+
+ def _print(self, defstr):
+ self.text += defstr
+ return 0
+
+ sink = def_sink()
+ py_ordinals = map(lambda l : int(l), ordinals.split(","))
+ idaapi.print_decls(sink, idaapi.cvar.idati, py_ordinals, flags)
+
+ return sink.text
+
+
+PDF_INCL_DEPS = 0x1 # include dependencies
+PDF_DEF_FWD = 0x2 # allow forward declarations
+PDF_DEF_BASE = 0x4 # include base types: __int8, __int16, etc..
+PDF_HEADER_CMT = 0x8 # prepend output with a descriptive comment
+
+
def GetMaxLocalType():
"""
Get number of local types + 1
@@ -8038,8 +8072,7 @@ def SetBptAttr(address, bptattr, value):
if bptattr == BPTATTR_FLAGS:
bpt.flags = value
- idaapi.update_bpt(bpt)
- return True
+ return idaapi.update_bpt(bpt)
def SetBptCndEx(ea, cnd, is_lowcnd):
"""
@@ -8281,14 +8314,20 @@ def GetTevRegVal(tev, reg):
def GetTevRegMemQty(tev):
"""
- Return the number of memory addresses recorded for the specified event
+ Return the number of blobs of memory recorded, for the specified event
+
+ Note: this requires that the tracing options have been set to record pieces of memory for instruction events
+
@param tev: event number
"""
return idaapi.get_tev_reg_mem_qty(tev)
def GetTevRegMem(tev, idx):
"""
- Return the memory pointed by 'index' for the specified event
+ Return the blob of memory pointed to by 'index', for the specified event
+
+ Note: this requires that the tracing options have been set to record pieces of memory for instruction events
+
@param tev: event number
@param idx: memory address index
"""
@@ -8296,7 +8335,10 @@ def GetTevRegMem(tev, idx):
def GetTevRegMemEa(tev, idx):
"""
- Return the address pointed by 'index' for the specified event
+ Return the address of the blob of memory pointed to by 'index' for the specified event
+
+ Note: this requires that the tracing options have been set to record pieces of memory for instruction events
+
@param tev: event number
@param idx: memory address index
"""
diff --git a/pywraps/py_choose.hpp b/pywraps/py_choose.hpp
index 8e4995f..369d77e 100644
--- a/pywraps/py_choose.hpp
+++ b/pywraps/py_choose.hpp
@@ -39,7 +39,7 @@ void idaapi choose_enter(void *self, uint32 n)
//---------------------------------------------------------------------------
uint32 choose_choose(
- void *self,
+ PyObject *self,
int flags,
int x0,int y0,
int x1,int y1,
@@ -48,14 +48,14 @@ uint32 choose_choose(
int icon)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
- newref_t pytitle(PyObject_GetAttrString((PyObject *)self, "title"));
+ newref_t pytitle(PyObject_GetAttrString(self, "title"));
const char *title = pytitle != NULL ? PyString_AsString(pytitle.o) : "Choose";
int r = choose(
flags,
x0, y0,
x1, y1,
- self,
+ (void*) self,
width,
choose_sizer,
choose_getl,
diff --git a/pywraps/py_dbg.hpp b/pywraps/py_dbg.hpp
index b0592c5..750a8ea 100644
--- a/pywraps/py_dbg.hpp
+++ b/pywraps/py_dbg.hpp
@@ -338,5 +338,26 @@ static ea_t py_internal_get_sreg_base(thid_t tid, int sreg_value)
: answer;
}
+//-------------------------------------------------------------------------
+static PyObject *py_get_tev_reg_mem(int tev, int reg)
+{
+ tev_info_t ti;
+ memreg_infos_t mis;
+ bool ok = get_tev_info(tev, &ti)
+ && get_insn_tev_reg_mem(tev, &mis)
+ && reg >= 0 && reg < mis.size();
+ if ( ok )
+ {
+ PyObject *py_str = PyString_FromStringAndSize(
+ (const char *) mis[reg].bytes.begin(),
+ mis[reg].bytes.size());
+ return py_str;
+ }
+ else
+ {
+ Py_RETURN_NONE;
+ }
+}
+
//
#endif
diff --git a/pywraps/py_idaapi.hpp b/pywraps/py_idaapi.hpp
index 633e283..f3cf3fa 100644
--- a/pywraps/py_idaapi.hpp
+++ b/pywraps/py_idaapi.hpp
@@ -1757,7 +1757,7 @@ static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx)
if ( sv == NULL || idx >= sv->size() )
Py_RETURN_NONE;
else
- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)&sv->at(idx));
+ return PyLong_FromUnsignedLongLong(size_t(&sv->at(idx)));
}
diff --git a/pywraps/py_idp.hpp b/pywraps/py_idp.hpp
index 3cd639b..e2cb0c2 100644
--- a/pywraps/py_idp.hpp
+++ b/pywraps/py_idp.hpp
@@ -695,35 +695,29 @@ struct libfunc_t;
int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
class IDP_Hooks
{
-public:
- virtual ~IDP_Hooks()
- {
- unhook();
- }
-
- bool hook()
- {
- return hook_to_notification_point(HT_IDP, IDP_Callback, this);
- }
-
- bool unhook()
- {
- return unhook_from_notification_point(HT_IDP, IDP_Callback, this);
- }
-
+ friend int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
static int bool_to_cmdsize(bool in) { return in ? (1 + cmd.size) : 0; }
static int bool_to_2or0(bool in) { return in ? 2 : 0; }
static int cm_t_to_int(cm_t cm) { return int(cm); }
+ static bool _handle_string_output(PyObject *o, char *buf, size_t bufsize)
+ {
+ bool is_str = o != NULL && PyString_Check(o);
+ if ( is_str && buf != NULL )
+ qstrncpy(buf, PyString_AS_STRING(o), bufsize);
+ Py_XDECREF(o);
+ return is_str;
+ }
+ static bool _handle_qstring_output(PyObject *o, qstring *buf)
+ {
+ bool is_str = o != NULL && PyString_Check(o);
+ if ( is_str && buf != NULL )
+ buf->append(PyString_AS_STRING(o));
+ Py_XDECREF(o);
+ return is_str;
+ }
static int handle_custom_mnem_output(PyObject *o, char *buf, size_t bufsize)
{
- int rc = 0;
- if ( o != NULL && PyString_Check(o) )
- {
- qstrncpy(buf, PyString_AS_STRING(o), bufsize);
- rc = 2;
- }
- Py_XDECREF(o);
- return rc;
+ return _handle_string_output(o, buf, bufsize) ? 2 : 0;
}
static int handle_assemble_output(PyObject *o, ea_t /*ea*/, ea_t /*cs*/, ea_t /*ip*/, bool /*use32*/, const char */*line*/, uchar *bin)
{
@@ -743,7 +737,33 @@ public:
Py_XDECREF(o);
return rc;
}
+ static int handle_get_reg_name_output(PyObject *o, int /*reg*/, size_t /*width*/, char *buf, size_t bufsize, int /*reghi*/)
+ {
+ int rc = 0;
+ if ( _handle_string_output(o, buf, bufsize) )
+ rc = qstrlen(buf) + 2;
+ return rc;
+ }
+ static int handle_decorate_name3_output(PyObject *o, qstring *outbuf, const char * /*name*/, bool /*mangle*/, int /*cc*/)
+ {
+ return _handle_qstring_output(o, outbuf) ? 2 : 0;
+ }
+public:
+ virtual ~IDP_Hooks()
+ {
+ unhook();
+ }
+
+ bool hook()
+ {
+ return hook_to_notification_point(HT_IDP, IDP_Callback, this);
+ }
+
+ bool unhook()
+ {
+ return unhook_from_notification_point(HT_IDP, IDP_Callback, this);
+ }
// hookgenIDP:methods
virtual int init(const char * idp_modname) {qnotused(idp_modname); return 0;}
virtual int term() {return 0;}
@@ -792,7 +812,7 @@ virtual void kernel_config_loaded() {}
virtual int might_change_sp(ea_t ea) {qnotused(ea); return 0;}
virtual int is_alloca_probe(ea_t ea) {qnotused(ea); return 0;}
virtual int out_3byte(ea_t dataea, uint32 value, bool analyze_only) {qnotused(dataea); qnotused(value); qnotused(analyze_only); return 0;}
-virtual int get_reg_name(int reg, size_t width, char * buf, size_t bufsize, int reghi) {qnotused(reg); qnotused(width); qnotused(buf); qnotused(bufsize); qnotused(reghi); return 0;}
+virtual PyObject * get_reg_name(int reg, size_t width, int reghi) {qnotused(reg); qnotused(width); qnotused(reghi); Py_RETURN_NONE;}
virtual void savebase() {}
virtual void gen_asm_or_lst(bool starting, FILE * fp, bool is_asm, int flags, gen_outline_t ** outline) {qnotused(starting); qnotused(fp); qnotused(is_asm); qnotused(flags); qnotused(outline); }
virtual int out_src_file_lnnum() {return 0;}
@@ -847,7 +867,7 @@ virtual int calc_cdecl_purged_bytes2() {return 0;}
virtual int get_stkarg_offset2() {return 0;}
virtual int til_for_file() {return 0;}
virtual int equal_reglocs(argloc_t * a1, argloc_t * a2) {qnotused(a1); qnotused(a2); return 0;}
-virtual int decorate_name3(qstring * outbuf, const char * name, bool mangle, int cc) {qnotused(outbuf); qnotused(name); qnotused(mangle); qnotused(cc); return 0;}
+virtual PyObject * decorate_name3(const char * name, bool mangle, int cc) {qnotused(name); qnotused(mangle); qnotused(cc); Py_RETURN_NONE;}
virtual int calc_retloc3(const tinfo_t * rettype, cm_t cc, argloc_t * retloc) {qnotused(rettype); qnotused(cc); qnotused(retloc); return 0;}
virtual int calc_varglocs3(const func_type_data_t * ftd, regobjs_t * regs, relobj_t * stkargs, int nfixed) {qnotused(ftd); qnotused(regs); qnotused(stkargs); qnotused(nfixed); return 0;}
virtual int calc_arglocs3(func_type_data_t * fti) {qnotused(fti); return 0;}
@@ -1260,7 +1280,8 @@ case processor_t::get_reg_name:
char * buf = va_arg(va, char *);
size_t bufsize = va_arg(va, size_t);
int reghi = va_arg(va, int);
- ret = proxy->get_reg_name(reg, width, buf, bufsize, reghi);
+ PyObject * _tmp = proxy->get_reg_name(reg, width, reghi);
+ ret = IDP_Hooks::handle_get_reg_name_output(_tmp, reg, width, buf, bufsize, reghi);
}
break;
@@ -1707,7 +1728,8 @@ case processor_t::decorate_name3:
const char * name = va_arg(va, const char *);
bool mangle = bool(va_arg(va, int));
cm_t cc = cm_t(va_arg(va, int));
- ret = proxy->decorate_name3(outbuf, name, mangle, IDP_Hooks::cm_t_to_int(cc));
+ PyObject * _tmp = proxy->decorate_name3(name, mangle, IDP_Hooks::cm_t_to_int(cc));
+ ret = IDP_Hooks::handle_decorate_name3_output(_tmp, outbuf, name, mangle, cc);
}
break;
diff --git a/pywraps/py_kernwin.hpp b/pywraps/py_kernwin.hpp
index a17d282..7b6db62 100644
--- a/pywraps/py_kernwin.hpp
+++ b/pywraps/py_kernwin.hpp
@@ -427,11 +427,16 @@ bool py_del_hotkey(PyObject *pyctx)
return false;
py_idchotkey_ctx_t *ctx = (py_idchotkey_ctx_t *) PyCObject_AsVoidPtr(pyctx);
- if ( !del_idc_hotkey(ctx->hotkey.c_str()) )
+ if ( ctx == NULL || !del_idc_hotkey(ctx->hotkey.c_str()) )
return false;
Py_DECREF(ctx->pyfunc);
delete ctx;
+ // Here we must ensure that the python object is invalidated.
+ // This is to avoid the possibility of this function being called again
+ // with the same ctx, which would contain a pointer to a deleted object.
+ PyCObject_SetVoidPtr(pyctx, NULL);
+
return true;
}
@@ -826,6 +831,7 @@ static bool py_execute_ui_requests(PyObject *py_list)
virtual idaapi ~py_ui_request_t()
{
+ PYW_GIL_GET;
py_callables.clear();
}
};
diff --git a/swig/dbg.i b/swig/dbg.i
index ae7db6e..2929e96 100644
--- a/swig/dbg.i
+++ b/swig/dbg.i
@@ -44,6 +44,8 @@ typedef struct
%ignore internal_get_sreg_base;
%rename (internal_get_sreg_base) py_internal_get_sreg_base;
+%rename (get_tev_reg_mem) py_get_tev_reg_mem;
+
// We want ALL wrappers around what is declared in dbg.hpp
// to release the GIL when calling into the IDA api: those
// might be very long operations, that even require some
diff --git a/swig/idd.i b/swig/idd.i
index 50b1720..9436f10 100644
--- a/swig/idd.i
+++ b/swig/idd.i
@@ -10,6 +10,14 @@
%ignore gdecode_t;
%apply unsigned char { char dtyp };
+%ignore qvector::operator==;
+%ignore qvector::operator!=;
+%ignore qvector::find;
+%ignore qvector::has;
+%ignore qvector::del;
+%ignore qvector::add_unique;
+%template(excvec_t) qvector;
+
%include "idd.hpp"
%clear(char dtyp);
diff --git a/swig/typeinf.i b/swig/typeinf.i
index 9fabf8b..779cc69 100644
--- a/swig/typeinf.i
+++ b/swig/typeinf.i
@@ -90,6 +90,8 @@
%rename (get_named_type64) py_get_named_type64;
%rename ("%s") tinfo_t::get_named_type;
+%ignore udt_type_data_t::is_last_baseclass;
+
%rename (print_decls) py_print_decls;
%ignore print_decls;
diff --git a/tools/deploy.py b/tools/deploy.py
index 624d01e..2acd26b 100644
--- a/tools/deploy.py
+++ b/tools/deploy.py
@@ -9,13 +9,10 @@ import re
import os
major, minor, micro, _, _ = sys.version_info
+if major < 2 or minor < 7:
+ raise Exception("Expected Python version 2.7.x, but got %s.%s.%s (from %s)" % (major, minor, micro, sys.executable))
-try:
- from argparse import ArgumentParser
-except:
- print "Failed to import module 'argparse'. Upgrade to Python 2.7, copy argparse.py to this directory or try 'apt-get install python-argparse'"
- raise
-
+from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("-t", "--template", required=True)
parser.add_argument("-o", "--output", required=True)
diff --git a/tools/genhooks/recipe_idphooks.py b/tools/genhooks/recipe_idphooks.py
index a221ab0..c7bf03d 100644
--- a/tools/genhooks/recipe_idphooks.py
+++ b/tools/genhooks/recipe_idphooks.py
@@ -82,7 +82,26 @@ recipe = {
"cc" : {
"type" : "int",
"convertor" : "IDP_Hooks::cm_t_to_int",
- }
+ },
+ "outbuf" : { "suppress_for_call" : True, },
+ },
+ "return" : {
+ "type" : "PyObject *",
+ "retexpr" : "Py_RETURN_NONE",
+ "convertor" : "IDP_Hooks::handle_decorate_name3_output",
+ "convertor_pass_args" : True,
}
- }
+ },
+ "get_reg_name" : {
+ "params" : {
+ "buf" : { "suppress_for_call" : True, },
+ "bufsize" : { "suppress_for_call" : True, },
+ },
+ "return" : {
+ "type" : "PyObject *",
+ "retexpr" : "Py_RETURN_NONE",
+ "convertor" : "IDP_Hooks::handle_get_reg_name_output",
+ "convertor_pass_args" : True,
+ }
+ },
}