IDA Pro 6.6 support

What's new:
- added the decompiler bindings
- Expose simpleline_t type to IDAPython. That lets the user to set the bgcolor & text for each line in the decompilation.
- Wrapped new functions from the IDA SDK

Various fixes:
for non-code locations, idc.GetOpnd() would create instructions instead of returning empty result
- idb_event::area_cmt_changed was never received in IDB_Hooks (and descendants)
- idb_event::ti_changed, and idb_event::op_ti_changed notifications were not accessible in IDAPython
- op_t.value was truncated to 32 bits under IDA64.
- print_tinfo() wouldn't return a valid string.
- readsel2() was not usable.
- read_selection() was buggy for 64-bit programs.
- StructMembers() considered holes in structures, and didn't properly iterate through the whole structure definition.
- There was no way to call calc_switch_cases() from IDAPython.
- when using multi-select/multi-edit choosers, erroneous event codes could be sent at beginning & end of batch deletion of lines.
- When, in a PluginForm#OnCreate, the layout of IDA was requested to change (for example by starting a debugging session), that PluginForm could be deleted and create an access violation.
- tinfo_t objects created from IDAPython could cause an assertion failure at exit time.
- Usage of IDAPython's DropdownListControl was broken.
This commit is contained in:
elias.bachaalany@gmail.com 2014-07-04 22:02:42 +00:00
parent 1c6752de40
commit fbb5bfabd6
44 changed files with 3195 additions and 2395 deletions

View File

@ -8,11 +8,11 @@ The IDAPython Team:
* Hex-Rays - http://www.hex-rays.com/ - <support@hex-rays.com>
Hex-Rays joined the IDAPython project in September 2009 and started contributing.
It is primarily maintained by Arnaud Diederen.
It is primarily maintained, updated and improved by Arnaud Diederen of Hex-Rays.
* Elias Bachaalany - http://0xeb.wordpress.com/
* Elias Bachaalany - elias.bachaalany@gmail.com
Maintains IDAPython online source code repository and coordinates patches/updates/contributions from Hex-Rays and 3rd party contributors
Current project owner and maintainer
* Ero Carrera - http://dkbza.org/

View File

@ -24,7 +24,7 @@ from distutils import sysconfig
VERBOSE = True
IDA_MAJOR_VERSION = 6
IDA_MINOR_VERSION = 5
IDA_MINOR_VERSION = 6
if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA']
@ -35,7 +35,7 @@ else:
# IDAPython version
VERSION_MAJOR = 1
VERSION_MINOR = 6
VERSION_MINOR = 7
VERSION_PATCH = 0
# Determine Python version
@ -339,13 +339,14 @@ def build_plugin(
idasdkdir,
plugin_name,
options):
""" Build the plugin from the SWIG wrapper and plugin main source """
global SWIG_OPTIONS
# Get the arguments
ea64 = options[S_EA64]
with_hexrays = options[S_WITH_HEXRAYS]
global SWIG_OPTIONS
""" Build the plugin from the SWIG wrapper and plugin main source """
# Path to the IDA SDK headers
ida_include_directory = os.path.join(idasdkdir, "include")

View File

@ -1,5 +1,6 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to use the graphing functionality in Python
# This is an example illustrating how to use the user graphing functionality
# in Python
# (c) Hex-Rays
#
from idaapi import GraphViewer

View File

@ -17,9 +17,8 @@ def main():
return True
sv = cfunc.get_pseudocode();
for i in xrange(0, sv.size()):
line = idaapi.tag_remove(str(sv[i]));
print line
for sline in sv:
print idaapi.tag_remove(sline.line);
return True

View File

@ -66,9 +66,9 @@ class XrefsForm(idaapi.PluginForm):
x = self.target.operands['x']
m = self.target.operands['m']
xtype = typestring(x.type.u_str())
xtype = x.type
xtype.remove_ptr_or_array()
typename = str(xtype)
typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '')
sid = idc.GetStrucIdByName(typename)
member = idc.GetMemberName(sid, m)
@ -137,11 +137,10 @@ class XrefsForm(idaapi.PluginForm):
lines = []
for stmt in insnvec:
qs = idaapi.qstring()
qp = idaapi.qstring_printer_t(cfunc.__deref__(), qs, False)
qp = idaapi.qstring_printer_t(cfunc.__deref__(), False)
stmt._print(0, qp)
s = str(qs).split('\n')[0]
s = qp.s.split('\n')[0]
#~ s = idaapi.tag_remove(s)
lines.append(s)
@ -156,7 +155,6 @@ class XrefsForm(idaapi.PluginForm):
for ea in frm:
try:
cfunc = idaapi.decompile(ea)
cfunc.refcnt += 1
self.functions.append(cfunc.entry_ea)
self.items.append((ea, idc.GetFunctionName(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea)))
@ -172,16 +170,15 @@ class XrefsForm(idaapi.PluginForm):
x = self.target.operands['x']
m = self.target.operands['m']
xtype = typestring(x.type.u_str())
xtype = x.type
xtype.remove_ptr_or_array()
typename = str(xtype)
typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '')
addresses = []
for ea in idautils.Functions():
try:
cfunc = idaapi.decompile(ea)
cfunc.refcnt += 1
except:
print 'Decompilation of %x failed' % (ea, )
continue
@ -195,9 +192,9 @@ class XrefsForm(idaapi.PluginForm):
_x = citem.operands['x']
_m = citem.operands['m']
_xtype = typestring(_x.type.u_str())
_xtype = _x.type
_xtype.remove_ptr_or_array()
_typename = str(_xtype)
_typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, _xtype, '', '')
#~ print 'in', hex(cfunc.entry_ea), _typename, _m

View File

@ -96,7 +96,7 @@
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.\pywraps;..\..\include;\python27\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\pywraps;..\..\include;c:\python27\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WITH_HEXRAYS;NO_OBSOLETE_FUNCS;_DEBUG;__NT__;__IDP__;MAXSTR=1024;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_STANDARD_FILE_FUNCTIONS;VER_MAJOR=1;VER_MINOR=5;VER_PATCH=3;PLUGINFIX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

View File

@ -69,7 +69,8 @@ enum script_run_when
//-------------------------------------------------------------------------
// Global variables
static bool g_initialized = false;
static bool g_instance_initialized = false; // This instance of the plugin is the one
// that initialized the python interpreter.
static int g_run_when = -1;
static char g_run_script[QMAXPATH];
static char g_idapython_dir[QMAXPATH];
@ -133,7 +134,8 @@ static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg)
if ( wasBreak() )
{
// User pressed Cancel in the waitbox; send KeyboardInterrupt exception
PyErr_SetInterrupt();
PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted");
return -1;
}
else if ( !box_displayed && ++ninsns > 10 )
{
@ -637,48 +639,6 @@ static bool parse_py_modname(
return p != NULL;
}
//-------------------------------------------------------------------------
// Compile callback for Python external language evaluator
bool idaapi IDAPython_extlang_compile(
const char *name,
ea_t /*current_ea*/,
const char *expr,
char *errbuf,
size_t errbufsize)
{
PYW_GIL_GET;
PyObject *globals = GetMainGlobals();
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
if ( code == NULL )
{
handle_python_error(errbuf, errbufsize);
return false;
}
// Set the desired function name
Py_XDECREF(code->co_name);
code->co_name = PyString_FromString(name);
// Create a function out of code
PyObject *func = PyFunction_New((PyObject *)code, globals);
if ( func == NULL )
{
ERR:
handle_python_error(errbuf, errbufsize);
Py_XDECREF(code);
return false;
}
int err = PyDict_SetItemString(globals, name, func);
Py_XDECREF(func);
if ( err )
goto ERR;
return true;
}
//-------------------------------------------------------------------------
// Run callback for Python external language evaluator
bool idaapi IDAPython_extlang_run(
@ -743,6 +703,68 @@ bool idaapi IDAPython_extlang_run(
return ok;
}
//-------------------------------------------------------------------------
// Compile callback for Python external language evaluator
bool idaapi IDAPython_extlang_compile(
const char *name,
ea_t /*current_ea*/,
const char *expr,
char *errbuf,
size_t errbufsize)
{
PYW_GIL_GET;
PyObject *globals = GetMainGlobals();
bool is_func = false;
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
if ( code == NULL )
{
// try compiling as a list of statements
// wrap them into a function
handle_python_error(errbuf, errbufsize);
qstring expr_copy = expr;
expr_copy.replace("\n", "\n ");
qstring qexpr;
qexpr.sprnt("def %s():\n %s", name, expr_copy.c_str());
code = (PyCodeObject *)Py_CompileString(qexpr.c_str(), "<string>", Py_file_input);
if ( code == NULL )
{
handle_python_error(errbuf, errbufsize);
return false;
}
is_func = true;
}
// Set the desired function name
Py_XDECREF(code->co_name);
code->co_name = PyString_FromString(name);
// Create a function out of code
PyObject *func = PyFunction_New((PyObject *)code, globals);
if ( func == NULL )
{
ERR:
handle_python_error(errbuf, errbufsize);
Py_XDECREF(code);
return false;
}
int err = PyDict_SetItemString(globals, name, func);
Py_XDECREF(func);
if ( err )
goto ERR;
if ( is_func )
{
const idc_value_t args;
idc_value_t result;
return IDAPython_extlang_run(name, 0, &args, &result, errbuf, errbufsize);
}
return true;
}
//-------------------------------------------------------------------------
// Compile callback for Python external language evaluator
bool idaapi IDAPython_extlang_compile_file(
@ -1273,8 +1295,11 @@ void convert_idc_args()
}
//------------------------------------------------------------------------
static int idaapi script_runner_cb(void *, int code, va_list)
static int idaapi on_ui_notification(void *, int code, va_list va)
{
#ifdef WITH_HEXRAYS
qnotused(va);
#endif
switch ( code )
{
case ui_ready_to_run:
@ -1296,12 +1321,66 @@ static int idaapi script_runner_cb(void *, int code, va_list)
RunScript(g_run_script);
}
break;
#ifdef WITH_HEXRAYS
// FIXME: HACK! THERE SHOULD BE A UI (or IDB?) NOTIFICATION
// WHEN A PLUGIN GETS [UN]LOADED!
// In the meantime, we're checking to see whether the Hex-Rays
// plugin gets loaded/pulled away.
case ui_add_menu_item:
if ( hexdsp == NULL )
{
const char *name = va_arg(va, char *);
name = va_arg(va, char *); // Drop 'menupath'. Look for 'name'.
if ( streq(name, "Jump to pseudocode") )
{
init_hexrays_plugin(0);
if ( hexdsp != NULL )
msg("IDAPython Hex-Rays bindings initialized.\n");
}
}
break;
case ui_del_menu_item:
{
if ( hexdsp != NULL )
{
// Hex-Rays will close. Make sure all the refcounted cfunc_t objects
// are cleared right away.
const char *menupath = va_arg(va, char *);
if ( streq(menupath, "Jump/Jump to pseudocode") )
{
hexrays_clear_python_cfuncptr_t_references();
hexdsp = NULL;
}
}
}
break;
#endif
default:
break;
}
return 0;
}
//-------------------------------------------------------------------------
//lint -esym(526,til_clear_python_tinfo_t_instances) not defined
extern void til_clear_python_tinfo_t_instances(void);
static int idaapi on_idp_notification(void *, int code, va_list)
{
switch ( code )
{
case processor_t::closebase:
// The til machinery is about to garbage-collect: We must go
// through all the tinfo_t objects that are embedded in SWIG wrappers,
// (i.e., that were created from Python) and clear those.
til_clear_python_tinfo_t_instances();
break;
}
return 0;
}
#ifdef _DEBUG
//------------------------------------------------------------------------
// extern int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag);
@ -1379,8 +1458,7 @@ static bool initsite(void)
// Initialize the Python environment
bool IDAPython_Init(void)
{
// Already initialized?
if ( g_initialized )
if ( Py_IsInitialized() != 0 )
return true;
// Form the absolute path to IDA\python folder
@ -1404,7 +1482,7 @@ bool IDAPython_Init(void)
#ifdef __MAC__
// We should set python home to the module's path, otherwise it can pick up stray modules from $PATH
NSModule pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
NSModule pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_InitializeEx"));
// Use dylib functions to find out where the framework was loaded from
const char *buf = (char *)NSLibraryNameForModule(pythonModule);
if ( buf != NULL )
@ -1443,11 +1521,11 @@ bool IDAPython_Init(void)
Py_NoSiteFlag = 1;
// Start the interpreter
Py_Initialize();
Py_InitializeEx(0 /* Don't catch SIGPIPE, SIGXFZ, SIGXFSZ & SIGINT signals */);
if ( !Py_IsInitialized() )
{
warning("IDAPython: Py_Initialize() failed");
warning("IDAPython: Py_InitializeEx() failed");
return false;
}
@ -1505,6 +1583,7 @@ bool IDAPython_Init(void)
"%s\n"
"\n"
"Refer to the message window to see the full error log.", tmp);
remove_extlang(&extlang_python);
return false;
}
@ -1512,6 +1591,7 @@ bool IDAPython_Init(void)
if ( !init_pywraps() || !pywraps_nw_init() )
{
warning("IDAPython: init_pywraps() failed!");
remove_extlang(&extlang_python);
return false;
}
@ -1536,16 +1616,17 @@ bool IDAPython_Init(void)
#ifdef _DEBUG
hook_to_notification_point(HT_UI, ui_debug_handler_cb, NULL);
#endif
hook_to_notification_point(HT_UI, script_runner_cb, NULL);
hook_to_notification_point(HT_UI, on_ui_notification, NULL);
hook_to_notification_point(HT_IDP, on_idp_notification, NULL);
// Enable the CLI by default
enable_python_cli(true);
g_initialized = true;
pywraps_nw_notify(NW_INITIDA_SLOT);
PyEval_ReleaseThread(PyThreadState_Get());
g_instance_initialized = true;
return true;
}
@ -1553,6 +1634,9 @@ bool IDAPython_Init(void)
// Cleaning up Python
void IDAPython_Term(void)
{
if ( !g_instance_initialized || Py_IsInitialized() == 0 )
return;
if ( PyGILState_GetThisThreadState() )
{
// Note: No 'PYW_GIL_GET' here, as it would try to release
@ -1563,7 +1647,8 @@ void IDAPython_Term(void)
PyGILState_Ensure();
}
unhook_from_notification_point(HT_UI, script_runner_cb, NULL);
unhook_from_notification_point(HT_IDP, on_idp_notification, NULL);
unhook_from_notification_point(HT_UI, on_ui_notification, NULL);
#ifdef _DEBUG
unhook_from_notification_point(HT_UI, ui_debug_handler_cb, NULL);
#endif
@ -1588,8 +1673,7 @@ void IDAPython_Term(void)
// Shut the interpreter down
Py_Finalize();
g_initialized = false;
g_instance_initialized = false;
}
//-------------------------------------------------------------------------

View File

@ -481,6 +481,12 @@ def SaveBase(idbname, flags=0):
DBFL_BAK = idaapi.DBFL_BAK # for compatiblity with older versions, eventually delete this
def ValidateNames():
"""
check consistency of IDB name records
@return: number of inconsistent name records
"""
return idaapi.validate_idb_names()
def Exit(code):
"""
@ -2245,8 +2251,12 @@ def GetOpnd(ea, n):
0 - the first operand
1 - the second operand
@return: the current text representation of operand
@return: the current text representation of operand or ""
"""
if not isCode(idaapi.get_flags_novalue(ea)):
return ""
res = idaapi.ua_outop2(ea, n)
if not res:
@ -6931,7 +6941,10 @@ def SetType(ea, newtype):
@return: 1-ok, 0-failed.
"""
if newtype is not '':
pt = ParseType(newtype, 0)[1:]
pt = ParseType(newtype, 0)
if pt is None:
# parsing failed
return None
else:
pt = None
return ApplyType(ea, pt, TINFO_DEFINITE)
@ -8132,6 +8145,13 @@ def CheckTraceFile(filename):
"""
return idaapi.is_valid_trace_file(filename)
def DiffTraceFile(filename):
"""
Diff current trace buffer against given trace
@param filename: trace file
"""
return idaapi.diff_trace_file(filename)
def ClearTraceFile(filename):
"""
Clear the current trace buffer

View File

@ -58,40 +58,6 @@
#define CIP_OK 1 // Success
#define CIP_OK_OPAQUE 2 // Success, but the data pointed to by the PyObject* is an opaque object.
//---------------------------------------------------------------------------
// Helper macro to create C counterparts of Python py_clinked_object_t object
#ifdef __PYWRAPS__
#define DECLARE_PY_CLINKED_OBJECT(type) \
static PyObject *type##_create() \
{ \
PYW_GIL_CHECK_LOCKED_SCOPE(); \
return PyCObject_FromVoidPtr(new type(), NULL); \
} \
static bool type##_destroy(PyObject *py_obj) \
{ \
PYW_GIL_CHECK_LOCKED_SCOPE(); \
if ( !PyCObject_Check(py_obj) ) \
return false; \
delete (type *)PyCObject_AsVoidPtr(py_obj); \
return true; \
} \
static type *type##_get_clink(PyObject *self) \
{ \
PYW_GIL_CHECK_LOCKED_SCOPE(); \
return (type *)pyobj_get_clink(self); \
} \
static PyObject *type##_get_clink_ptr(PyObject *self) \
{ \
PYW_GIL_CHECK_LOCKED_SCOPE(); \
return PyLong_FromUnsignedLongLong( \
(unsigned PY_LONG_LONG)pyobj_get_clink(self)); \
}
#else
// SWIG does not expand macros and thus those definitions won't be wrapped
// Use DECLARE_PY_CLINKED_OBJECT(type) inside the .i file
#define DECLARE_PY_CLINKED_OBJECT(type)
#endif // __PYWRAPS__
//---------------------------------------------------------------------------
class gil_lock_t
{
@ -367,4 +333,6 @@ bool pywraps_check_autoscripts(char *buf, size_t bufsize);
bool init_pywraps();
void deinit_pywraps();
void hexrays_clear_python_cfuncptr_t_references(void);
#endif

View File

@ -9,8 +9,6 @@
#define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa;
//---------------------------------------------------------------------------
DECLARE_PY_CLINKED_OBJECT(textctrl_info_t);
static bool textctrl_info_t_assign(PyObject *self, PyObject *other)
{
textctrl_info_t *lhs = textctrl_info_t_get_clink(self);
@ -145,20 +143,21 @@ static PyObject *formchgcbfa_get_field_value(
PYW_GIL_CHECK_LOCKED_SCOPE();
switch ( ft )
{
// dropdown list
case 8:
{
// Readonly? Then return the selected index
if ( sz == 1 )
{
int sel_idx;
if ( fa->get_field_value(fid, &sel_idx) )
if ( fa->get_combobox_value(fid, &sel_idx) )
return PyLong_FromLong(sel_idx);
}
// Not readonly? Then return the qstring
else
{
qstring val;
if ( fa->get_field_value(fid, &val) )
if ( fa->get_combobox_value(fid, &val) )
return PyString_FromString(val.c_str());
}
break;
@ -167,15 +166,15 @@ static PyObject *formchgcbfa_get_field_value(
case 7:
{
textctrl_info_t ti;
if ( fa->get_field_value(fid, &ti) )
if ( fa->get_text_value(fid, &ti) )
return Py_BuildValue("(sII)", ti.text.c_str(), ti.flags, ti.tabsize);
break;
}
// button - uint32
case 4:
{
uint32 val;
if ( fa->get_field_value(fid, &val) )
uval_t val;
if ( fa->get_unsigned_value(fid, &val) )
return PyLong_FromUnsignedLong(val);
break;
}
@ -183,7 +182,7 @@ static PyObject *formchgcbfa_get_field_value(
case 2:
{
ushort val;
if ( fa->get_field_value(fid, &val) )
if ( fa->_get_field_value(fid, &val) )
return PyLong_FromUnsignedLong(val);
break;
}
@ -191,7 +190,7 @@ static PyObject *formchgcbfa_get_field_value(
case 1:
{
char val[MAXSTR];
if ( fa->get_field_value(fid, val) )
if ( fa->get_ascii_value(fid, val, sizeof(val)) )
return PyString_FromString(val);
break;
}
@ -200,7 +199,7 @@ static PyObject *formchgcbfa_get_field_value(
{
qstring val;
val.resize(sz + 1);
if ( fa->get_field_value(fid, val.begin()) )
if ( fa->get_ascii_value(fid, val.begin(), val.size()) )
return PyString_FromString(val.begin());
break;
}
@ -208,12 +207,11 @@ static PyObject *formchgcbfa_get_field_value(
{
intvec_t intvec;
// Returned as 1-base
if (fa->get_field_value(fid, &intvec))
if (fa->get_chooser_value(fid, &intvec))
{
// Make 0-based
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
(*it)--;
ref_t l(PyW_IntVecToPyList(intvec));
l.incref();
return l.o;
@ -234,33 +232,38 @@ static PyObject *formchgcbfa_get_field_value(
{
case 'S': // sel_t
{
if ( fa->get_field_value(fid, &u.sel) )
if ( fa->get_segment_value(fid, &u.sel) )
return Py_BuildValue(PY_FMT64, u.sel);
break;
}
// sval_t
case 'n':
case 'N':
case 'D':
case 'O':
case 'Y':
case 'H':
{
if ( fa->get_field_value(fid, &u.sval) )
if ( fa->get_signed_value(fid, &u.sval) )
return Py_BuildValue(PY_SFMT64, u.sval);
break;
}
case 'L': // uint64
case 'l': // int64
{
if ( fa->get_field_value(fid, &u.ull) )
return Py_BuildValue(sz == 'L' ? "K" : "L", u.ull);
if ( fa->_get_field_value(fid, &u.ull) )
return Py_BuildValue("K", u.ull);
break;
}
case 'N':
case 'M': // uval_t
{
if ( fa->get_unsigned_value(fid, &u.uval) )
return Py_BuildValue(PY_FMT64, u.uval);
break;
}
case '$': // ea_t
{
if ( fa->get_field_value(fid, &u.uval) )
if ( fa->get_ea_value(fid, &u.uval) )
return Py_BuildValue(PY_FMT64, u.uval);
break;
}
@ -290,13 +293,13 @@ static bool formchgcbfa_set_field_value(
if ( PyString_Check(py_val) )
{
qstring val(PyString_AsString(py_val));
return fa->set_field_value(fid, &val);
return fa->set_combobox_value(fid, &val);
}
// Readonly dropdown list
else
{
int sel_idx = PyLong_AsLong(py_val);
return fa->set_field_value(fid, &sel_idx);
return fa->set_combobox_value(fid, &sel_idx);
}
break;
}
@ -304,24 +307,24 @@ static bool formchgcbfa_set_field_value(
case 7:
{
textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(py_val);
return ti == NULL ? false : fa->set_field_value(fid, ti);
return ti == NULL ? false : fa->set_text_value(fid, ti);
}
// button - uint32
case 4:
{
uint32 val = PyLong_AsUnsignedLong(py_val);
return fa->set_field_value(fid, &val);
uval_t val = PyLong_AsUnsignedLong(py_val);
return fa->set_unsigned_value(fid, &val);
}
// ushort
case 2:
{
ushort val = PyLong_AsUnsignedLong(py_val) & 0xffff;
return fa->set_field_value(fid, &val);
return fa->_set_field_value(fid, &val);
}
// strings
case 3:
case 1:
return fa->set_field_value(fid, PyString_AsString(py_val));
return fa->set_ascii_value(fid, PyString_AsString(py_val));
// intvec_t
case 5:
{
@ -334,14 +337,14 @@ static bool formchgcbfa_set_field_value(
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
(*it)++;
return fa->set_field_value(fid, &intvec);
return fa->set_chooser_value(fid, &intvec);
}
// Numeric
case 6:
{
uint64 num;
if ( PyW_GetNumber(py_val, &num) )
return fa->set_field_value(fid, &num);
return fa->_set_field_value(fid, &num);
}
}
return false;
@ -351,6 +354,11 @@ static bool formchgcbfa_set_field_value(
static size_t py_get_AskUsingForm()
{
// Return a pointer to the function. Note that, although
// the C implementation of AskUsingForm_cv will do some
// Qt/txt widgets generation, the Python's ctypes
// implementation through which the call well go will first
// unblock other threads. No need to do it ourselves.
return (size_t)AskUsingForm_c;
}

View File

@ -8,7 +8,7 @@ try:
from _idaapi import set_script_timeout
import idaapi
from idaapi import py_clinked_object_t
from idaapi import qstrvec_t
from idaapi import _qstrvec_t
stdalone = False
except:
stdalone = True
@ -50,7 +50,7 @@ try:
from py_choose2 import *
py_clinked_object_t = idaapi.py_clinked_object_t
textctrl_info_t = idaapi.textctrl_info_t
qstrvec_t = idaapi.qstrvec_t
_qstrvec_t = idaapi._qstrvec_t
_idaapi.BADADDR = 0xFFFFFFFF
_idaapi.MAXSTR = 1024
@ -776,7 +776,7 @@ class Form(object):
Form.Control.free(self)
class DropdownListControl(InputControl, qstrvec_t):
class DropdownListControl(InputControl, _qstrvec_t):
"""
Dropdown control
This control allows manipulating a dropdown control
@ -803,7 +803,7 @@ class Form(object):
hlp)
# Init the associated qstrvec
qstrvec_t.__init__(self, items)
_qstrvec_t.__init__(self, items)
# Remember if readonly or not
self.readonly = readonly
@ -814,7 +814,7 @@ class Form(object):
val_addr = addressof(self.__selval)
else:
# Create an strvec with one qstring
self.__selval = qstrvec_t([selval])
self.__selval = _qstrvec_t([selval])
# Get address of the first element
val_addr = self.__selval.addressof(0)

View File

@ -289,8 +289,8 @@ private:
self,
(char *)S_ON_DELETE_LINE,
"i",
lineno - 1));
return pyres == NULL ? lineno : PyInt_AsLong(pyres.o) + 1;
IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1));
return pyres == NULL ? 1 : PyInt_AsLong(pyres.o);
}
int on_refresh(int lineno)

View File

@ -112,7 +112,6 @@ private:
static cmdid_map_t cmdid_pyg;
// TForm *form;
bool refresh_needed;
nodetext_cache_map_t node_cache;
@ -122,6 +121,7 @@ private:
// static callback
static int idaapi s_callback(void *obj, int code, va_list va)
{
QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj));
PYW_GIL_GET;
return ((py_graph_t *)obj)->gr_callback(code, va);
}
@ -255,13 +255,13 @@ private:
}
// a group is being created
int on_creating_group(mutable_graph_t *my_g, intset_t *my_nodes)
int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes);
newref_t py_nodes(PyList_New(my_nodes->size()));
int i;
intset_t::const_iterator p;
intvec_t::const_iterator p;
for ( i = 0, p=my_nodes->begin(); p != my_nodes->end(); ++p, ++i )
PyList_SetItem(py_nodes.o, i, PyInt_FromLong(*p));
newref_t py_result(
@ -331,6 +331,7 @@ private:
TForm *form = create_tform(title, &hwnd);
if ( hwnd != NULL ) // Created new tform
{
lookup_info_t::entry_t &e = lookup_info.new_entry(this);
// get a unique graph id
netnode id;
char grnode[MAXSTR];
@ -342,8 +343,7 @@ private:
viewer_fit_window(pview);
bind(self, pview);
refresh();
// Link "form" and "py_graph"
lookup_info.add(form, view, this);
lookup_info.commit(e, form, view);
}
else
{
@ -700,7 +700,7 @@ int py_graph_t::gr_callback(int code, va_list va)
case grcode_creating_group: // a group is being created
{
mutable_graph_t *g = va_arg(va, mutable_graph_t*);
intset_t *nodes = va_arg(va, intset_t*);
intvec_t *nodes = va_arg(va, intvec_t*);
ret = on_creating_group(g, nodes);
}
break;

View File

@ -726,12 +726,9 @@ def RunPythonStatement(stmt):
#</pydoc>
*/
/*
//---------------------------------------------------------------------------
// qstrvec_t wrapper
// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py)
//---------------------------------------------------------------------------
DECLARE_PY_CLINKED_OBJECT(qstrvec_t);
static bool qstrvec_t_assign(PyObject *self, PyObject *other)
{
qstrvec_t *lhs = qstrvec_t_get_clink(self);
@ -833,7 +830,7 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx)
sv->erase(sv->begin()+idx);
return true;
}
*/
//---------------------------------------------------------------------------
//</inline(py_idaapi)>

View File

@ -171,6 +171,12 @@ class object_t(object):
"""Allow access to object attributes by index (like dictionaries)"""
return getattr(self, idx)
# -----------------------------------------------------------------------
def _bounded_getitem_iterator(self):
"""Helper function, to be set as __iter__ method for qvector-, or array-based classes."""
for i in range(len(self)):
yield self[i]
# -----------------------------------------------------------------------
class plugin_t(pyidc_opaque_object_t):
"""Base class for all scripted plugins."""
@ -237,72 +243,79 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__):
# -----------------------------------------------------------------------
# qstrvec_t clinked object
# class qstrvec_t(py_clinked_object_t):
# """Class representing an qstrvec_t"""
class _qstrvec_t(py_clinked_object_t):
"""
WARNING: It is very unlikely an IDAPython user should ever, ever
have to use this type. It should only be used for IDAPython internals.
# def __init__(self, items=None):
# py_clinked_object_t.__init__(self)
# # Populate the list if needed
# if items:
# self.from_list(items)
For example, in py_askusingform.py, we ctypes-expose to the IDA
kernel & UI a qstrvec instance, in case a DropdownListControl is
constructed.
That's because that's what AskUsingForm expects, and we have no
choice but to make a DropdownListControl hold a qstrvec_t.
This is, afaict, the only situation where a Python
_qstrvec_t is required.
"""
# def _create_clink(self):
# return _idaapi.qstrvec_t_create()
def __init__(self, items=None):
py_clinked_object_t.__init__(self)
# Populate the list if needed
if items:
self.from_list(items)
# def _del_clink(self, lnk):
# return _idaapi.qstrvec_t_destroy(lnk)
def _create_clink(self):
return _idaapi.qstrvec_t_create()
# def _get_clink_ptr(self):
# return _idaapi.qstrvec_t_get_clink_ptr(self)
def _del_clink(self, lnk):
return _idaapi.qstrvec_t_destroy(lnk)
# def assign(self, other):
# """Copies the contents of 'other' to 'self'"""
# return _idaapi.qstrvec_t_assign(self, other)
def _get_clink_ptr(self):
return _idaapi.qstrvec_t_get_clink_ptr(self)
# def __setitem__(self, idx, s):
# """Sets string at the given index"""
# return _idaapi.qstrvec_t_set(self, idx, s)
def assign(self, other):
"""Copies the contents of 'other' to 'self'"""
return _idaapi.qstrvec_t_assign(self, other)
# def __getitem__(self, idx):
# """Gets the string at the given index"""
# return _idaapi.qstrvec_t_get(self, idx)
def __setitem__(self, idx, s):
"""Sets string at the given index"""
return _idaapi.qstrvec_t_set(self, idx, s)
# def __get_size(self):
# return _idaapi.qstrvec_t_size(self)
def __getitem__(self, idx):
"""Gets the string at the given index"""
return _idaapi.qstrvec_t_get(self, idx)
# size = property(__get_size)
# """Returns the count of elements"""
def __get_size(self):
return _idaapi.qstrvec_t_size(self)
# def addressof(self, idx):
# """Returns the address (as number) of the qstring at the given index"""
# return _idaapi.qstrvec_t_addressof(self, idx)
size = property(__get_size)
"""Returns the count of elements"""
# def add(self, s):
# """Add a string to the vector"""
# return _idaapi.qstrvec_t_add(self, s)
def addressof(self, idx):
"""Returns the address (as number) of the qstring at the given index"""
return _idaapi.qstrvec_t_addressof(self, idx)
def add(self, s):
"""Add a string to the vector"""
return _idaapi.qstrvec_t_add(self, s)
# def from_list(self, lst):
# """Populates the vector from a Python string list"""
# return _idaapi.qstrvec_t_from_list(self, lst)
def from_list(self, lst):
"""Populates the vector from a Python string list"""
return _idaapi.qstrvec_t_from_list(self, lst)
def clear(self, qclear=False):
"""
Clears all strings from the vector.
@param qclear: Just reset the size but do not actually free the memory
"""
return _idaapi.qstrvec_t_clear(self, qclear)
# def clear(self, qclear=False):
# """
# Clears all strings from the vector.
# @param qclear: Just reset the size but do not actually free the memory
# """
# return _idaapi.qstrvec_t_clear(self, qclear)
def insert(self, idx, s):
"""Insert a string into the vector"""
return _idaapi.qstrvec_t_insert(self, idx, s)
# def insert(self, idx, s):
# """Insert a string into the vector"""
# return _idaapi.qstrvec_t_insert(self, idx, s)
# def remove(self, idx):
# """Removes a string from the vector"""
# return _idaapi.qstrvec_t_remove(self, idx)
def remove(self, idx):
"""Removes a string from the vector"""
return _idaapi.qstrvec_t_remove(self, idx)
# -----------------------------------------------------------------------
class PyIdc_cvt_refclass__(pyidc_cvt_helper__):
@ -580,7 +593,13 @@ class __IDAPython_Completion_Util(object):
return s
# Instantiate a completion object
# Instantiate an IDAPython command completion object (for use with IDA's CLI bar)
IDAPython_Completion = __IDAPython_Completion_Util()
def _listify_types(*classes):
for cls in classes:
cls.__getitem__ = cls.at
cls.__len__ = cls.size
cls.__iter__ = _bounded_getitem_iterator
#</pycode(py_idaapi)>

View File

@ -42,7 +42,8 @@ bool py_idaview_t::Bind(PyObject *self)
else
{
py_view = new py_idaview_t();
lookup_info.add(tform, v, py_view);
lookup_info_t::entry_t &e = lookup_info.new_entry(py_view);
lookup_info.commit(e, tform, v);
}
// Finally, bind:

View File

@ -807,6 +807,15 @@ public:
}
};
enum areacb_type_t
{
AREACB_TYPE_UNKNOWN,
AREACB_TYPE_FUNC,
AREACB_TYPE_SEGMENT,
AREACB_TYPE_HIDDEN_AREA,
AREACB_TYPE_SRAREA,
};
//---------------------------------------------------------------------------
// IDB hooks
//---------------------------------------------------------------------------
@ -827,8 +836,9 @@ public:
// Hook functions to override in Python
virtual int byte_patched(ea_t /*ea*/) { return 0; };
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("ti_changed hook not supported yet\n"); return 0; };
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("op_ti_changed hook not supported yet\n"); return 0; };
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; }
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
virtual int enum_created(enum_t /*id*/) { return 0; };
virtual int enum_deleted(enum_t /*id*/) { return 0; };
@ -1365,8 +1375,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
ea_t ea, ea2;
bool repeatable_cmt;
/*type_t *type;*/
/* p_list *fnames; */
type_t *type;
p_list *fnames;
int n;
enum_t id;
const_t cid;
@ -1390,20 +1400,29 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
ea = va_arg(va, ea_t);
repeatable_cmt = va_arg(va, int);
return proxy->cmt_changed(ea, repeatable_cmt);
#if 0
case idb_event::area_cmt_changed:
{
areacb_t *cb = va_arg(va, areacb_t*);
area_t *area = va_arg(va, area_t*);
const char *cmt = va_arg(va, char*);
repeatable_cmt = va_arg(va, int);
return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt);
}
case idb_event::ti_changed:
ea = va_arg(va, ea_t);
type = va_arg(va, type_t *);
fnames = va_arg(va, fnames);
fnames = va_arg(va, p_list *);
return proxy->ti_changed(ea, type, fnames);
case idb_event::op_ti_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);
type = va_arg(va, type_t *);
fnames = va_arg(va, fnames);
fnames = va_arg(va, p_list *);
return proxy->op_ti_changed(ea, n, type, fnames);
#endif
case idb_event::op_type_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);

View File

@ -5,30 +5,6 @@
//<inline(py_kernwin)>
//------------------------------------------------------------------------
//------------------------------------------------------------------------
/*
#<pydoc>
def read_selection():
"""
Returns selected area boundaries
@return: tuple(ok: bool, start_ea, end_ea)
"""
pass
#</pydoc>
*/
static PyObject *py_read_selection()
{
ea_t ea1, ea2;
bool b = read_selection(&ea1, &ea2);
PYW_GIL_CHECK_LOCKED_SCOPE();
return Py_BuildValue(
"(i" PY_FMT64 PY_FMT64 ")",
b ? 1 : 0,
pyul_t(ea1), pyul_t(ea2));
}
//------------------------------------------------------------------------
/*
#<pydoc>
@ -203,6 +179,45 @@ def free_custom_icon(icon_id):
#</pydoc>
*/
//-------------------------------------------------------------------------
/*
#<pydoc>
def readsel2(view, p0, p1):
"""
Read the user selection, and store its information in p0 (from) and p1 (to).
This can be used as follows:
>>> p0 = idaapi.twinpos_t()
p1 = idaapi.twinpos_t()
view = idaapi.get_current_viewer()
idaapi.readsel2(view, p0, p1)
At that point, p0 and p1 hold information for the selection.
But, the 'at' property of p0 and p1 is not properly typed.
To specialize it, call #place() on it, passing it the view
they were retrieved from. Like so:
>>> place0 = p0.place(view)
place1 = p1.place(view)
This will effectively "cast" the place into a specialized type,
holding proper information, depending on the view type (e.g.,
disassembly, structures, enums, ...)
@param view: The view to retrieve the selection for.
@param p0: Storage for the "from" part of the selection.
@param p1: Storage for the "to" part of the selection.
@return: a bool value indicating success.
"""
pass
#</pydoc>
*/
//------------------------------------------------------------------------
/*
#<pydoc>

View File

@ -135,6 +135,54 @@ idaman bool ida_export py_create_switch_xrefs(
return true;
}
//-------------------------------------------------------------------------
struct cases_and_targets_t
{
casevec_t cases;
eavec_t targets;
};
//-------------------------------------------------------------------------
/*
#<pydoc>
def calc_switch_cases(insn_ea, si):
"""
Get information about a switch's cases.
The returned information can be used as follows:
for idx in xrange(len(results.cases)):
cur_case = results.cases[idx]
for cidx in xrange(len(cur_case)):
print "case: %d" % cur_case[cidx]
print " goto 0x%x" % results.targets[idx]
@param insn_ea: address of the 'indirect jump' instruction
@param si: switch information
@return: a structure with 2 members: 'cases', and 'targets'.
"""
pass
#</pydoc>
*/
idaman cases_and_targets_t *ida_export py_calc_switch_cases(
ea_t insn_ea,
PyObject *py_swi)
{
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
if ( swi == NULL )
return NULL;
cases_and_targets_t *ct = new cases_and_targets_t;
if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) )
{
delete ct;
return NULL;
}
return ct;
}
//-------------------------------------------------------------------------
/*

View File

@ -532,7 +532,49 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize)
qstrncpy(buf, name, bufsize);
return true;
}
//</inline(py_typeinf)>
//<code(py_typeinf)>
//-------------------------------------------------------------------------
// A set of tinfo_t objects that were created from IDAPython.
// This is necessary in order to clear all the "type details" that are
// associated, in the kernel, with the tinfo_t instances.
//
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
// closed, but the "type details" must be cleared _before_ the IDB is closed.
static qvector<tinfo_t*> python_tinfos;
void til_clear_python_tinfo_t_instances(void)
{
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that
// were not done here, ~tinfo_t() calls happening as part of the python shutdown
// process will try and clear() their details. ..but the kernel's til-related
// functions will already have deleted those details at that point.
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i )
python_tinfos[i]->clear();
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t
// instances will be deleted through the python shutdown/ref-decrementing
// process anyway (which will cause til_deregister_..() calls), and the
// entries will be properly pulled out of the vector when that happens.
}
void til_register_python_tinfo_t_instance(tinfo_t *tif)
{
// Let's add_unique() it, because every reference to an object's
// tinfo_t property will end up trying to register it.
python_tinfos.add_unique(tif);
}
void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
{
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif);
if ( found != python_tinfos.end() )
{
tif->clear();
python_tinfos.erase(found);
}
}
//</code(py_typeinf)>
#endif

View File

@ -746,7 +746,7 @@ static PyObject *op_t_get_value(PyObject *self)
op_t *link = op_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("I", link->value);
return Py_BuildValue(PY_FMT64, (pyul_t)link->value);
}
static void op_t_set_value(PyObject *self, PyObject *value)
@ -755,7 +755,9 @@ static void op_t_set_value(PyObject *self, PyObject *value)
op_t *link = op_t_get_clink(self);
if ( link == NULL )
return;
link->value = PyInt_AsLong(value);
uint64 v(0);
PyW_GetNumber(value, &v);
link->value = uval_t(v);
}
static PyObject *op_t_get_addr(PyObject *self)

View File

@ -15,16 +15,33 @@ class py_customidamemo_t;
class lookup_info_t
{
public:
void add(TForm *form, TCustomControl *view, py_customidamemo_t *py_view)
struct entry_t
{
QASSERT(0, form != NULL && view != NULL && py_view != NULL
entry_t() : form(NULL), view(NULL), py_view(NULL) {}
private:
TForm *form;
TCustomControl *view;
py_customidamemo_t *py_view;
friend class lookup_info_t;
};
entry_t &new_entry(py_customidamemo_t *py_view)
{
QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view));
entry_t &e = entries.push_back();
e.py_view = py_view;
return e;
}
void commit(entry_t &e, TForm *form, TCustomControl *view)
{
QASSERT(30455, &e >= entries.begin() && &e < entries.end());
QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL
&& !find_by_form(NULL, NULL, form)
&& !find_by_view(NULL, NULL, view)
&& !find_by_py_view(NULL, NULL, py_view));
entry_t &e = entries.push_back();
&& find_by_py_view(NULL, NULL, e.py_view));
e.form = form;
e.view = view;
e.py_view = py_view;
}
#define FIND_BY__BODY(crit, res1, res2) \
@ -62,12 +79,6 @@ public:
}
private:
struct entry_t
{
TForm *form;
TCustomControl *view;
py_customidamemo_t *py_view;
};
typedef qvector<entry_t> entries_t;
entries_t entries;
};
@ -131,6 +142,8 @@ class py_customidamemo_t
static void ensure_view_callbacks_installed();
int cb_flags;
// number of arguments for OnViewClick implementation
int ovc_num_args;
protected:
ref_t self;
@ -199,6 +212,7 @@ public:
void on_view_switched(tcc_renderer_type_t rt);
void on_view_mouse_over(const view_mouse_event_t *event);
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
int get_py_method_arg_count(char *method_name);
};
//-------------------------------------------------------------------------
@ -208,6 +222,7 @@ py_customidamemo_t::py_customidamemo_t()
{
PYGLOG("%p: py_customidamemo_t()\n", this);
ensure_view_callbacks_installed();
ovc_num_args = -1;
}
//-------------------------------------------------------------------------
@ -402,7 +417,7 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
{
newref_t node(PySequence_GetItem(nodes.o, k));
if ( PyInt_Check(node.o) )
gi.nodes.insert(PyInt_AsLong(node.o));
gi.nodes.add_unique(PyInt_AsLong(node.o));
}
if ( !gi.nodes.empty() )
{
@ -410,18 +425,18 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
gis.push_back(gi);
}
}
intset_t groups;
intvec_t groups;
if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() )
Py_RETURN_NONE;
PyObject *py_groups = PyList_New(0);
for ( intset_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
PyList_Append(py_groups, PyInt_FromLong(long(*it)));
return py_groups;
}
//-------------------------------------------------------------------------
static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes)
{
Py_ssize_t sz = PySequence_Size(pynodes.o);
for ( Py_ssize_t i = 0; i < sz; ++i )
@ -429,7 +444,7 @@ static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
newref_t item(PySequence_GetItem(pynodes.o, i));
if ( !PyInt_Check(item.o) )
continue;
idanodes->insert(PyInt_AsLong(item.o));
idanodes->add_unique(PyInt_AsLong(item.o));
}
}
@ -440,7 +455,7 @@ PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_cu
Py_RETURN_NONE;
borref_t groups(_groups);
borref_t new_current(_new_current);
intset_t ida_groups;
intvec_t ida_groups;
pynodes_to_idanodes(&ida_groups, groups);
if ( ida_groups.empty() )
Py_RETURN_NONE;
@ -460,7 +475,7 @@ PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject
borref_t groups(_groups);
borref_t expand(_expand);
borref_t new_current(_new_current);
intset_t ida_groups;
intvec_t ida_groups;
pynodes_to_idanodes(&ida_groups, groups);
if ( ida_groups.empty() )
Py_RETURN_NONE;
@ -499,6 +514,23 @@ void py_customidamemo_t::unbind()
view = NULL;
}
//-------------------------------------------------------------------------
int py_customidamemo_t::get_py_method_arg_count(char *method_name)
{
newref_t method(PyObject_GetAttrString(self.o, method_name));
if ( method != NULL && PyCallable_Check(method.o) )
{
newref_t fc(PyObject_GetAttrString(method.o, "func_code"));
if ( fc != NULL )
{
newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount"));
if ( ac != NULL )
return PyInt_AsLong(ac.o);
}
}
return -1;
}
//-------------------------------------------------------------------------
void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out)
{
@ -604,12 +636,26 @@ void py_customidamemo_t::on_view_popup()
void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
if ( ovc_num_args < 0 )
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
if ( ovc_num_args == 5 )
{
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iiii",
event->x, event->y, event->state, event->button));
}
else
{
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iii",
event->x, event->y, event->state));
}
CHK_RES();
}

View File

@ -67,6 +67,7 @@
%ignore term_flags;
%ignore reset_flags;
%ignore flush_flags;
%ignore get_flags_linput;
%ignore data_type_t;
%ignore data_format_t;
%ignore get_custom_data_type;

View File

@ -22,6 +22,8 @@ typedef struct
%ignore bpt_t::write;
%ignore bpt_t::erase;
%ignore bpt_t::cndbody;
%ignore bpt_t::get_cnd_elang;
%ignore bpt_t::set_cnd_elang;
%rename (get_manual_regions) py_get_manual_regions;
%ignore set_manual_regions;
%ignore inform_idc_about_debthread;
@ -45,6 +47,7 @@ static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas);
%extend bpt_t
{
PyObject *condition;
PyObject *elang;
}
%{
PyObject *bpt_t_condition_get(bpt_t *bpt)
@ -56,6 +59,27 @@ void bpt_t_condition_set(bpt_t *bpt, PyObject *val)
{
if ( PyString_Check(val) )
bpt->cndbody = PyString_AsString(val);
else
PyErr_SetString(PyExc_ValueError, "expected a string");
}
PyObject *bpt_t_elang_get(bpt_t *bpt)
{
return PyString_FromString(bpt->get_cnd_elang());
}
void bpt_t_elang_set(bpt_t *bpt, PyObject *val)
{
if ( PyString_Check(val) )
{
char *cval = PyString_AsString(val);
if ( !bpt->set_cnd_elang(cval) )
PyErr_SetString(PyExc_ValueError, "too many extlangs");
}
else
{
PyErr_SetString(PyExc_ValueError, "expected a string");
}
}
%}
%inline %{

View File

@ -29,6 +29,7 @@
%ignore make_linput;
%ignore unmake_linput;
%ignore create_remote_linput;
%ignore make_filehandle_linput;
// FIXME: These should be wrapped for completeness
%ignore eread;

View File

@ -43,6 +43,7 @@
%ignore init_idc;
%ignore term_idc;
%ignore create_default_idc_classes;
%ignore notify_extlang_changed;
%ignore insn_to_idc;
%ignore find_builtin_idc_func;
%ignore idc_mutex;

View File

@ -115,7 +115,6 @@ private:
static cmdid_map_t cmdid_pyg;
// TForm *form;
bool refresh_needed;
nodetext_cache_map_t node_cache;
@ -125,6 +124,7 @@ private:
// static callback
static int idaapi s_callback(void *obj, int code, va_list va)
{
QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj));
PYW_GIL_GET;
return ((py_graph_t *)obj)->gr_callback(code, va);
}
@ -258,13 +258,13 @@ private:
}
// a group is being created
int on_creating_group(mutable_graph_t *my_g, intset_t *my_nodes)
int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes);
newref_t py_nodes(PyList_New(my_nodes->size()));
int i;
intset_t::const_iterator p;
intvec_t::const_iterator p;
for ( i = 0, p=my_nodes->begin(); p != my_nodes->end(); ++p, ++i )
PyList_SetItem(py_nodes.o, i, PyInt_FromLong(*p));
newref_t py_result(
@ -334,6 +334,7 @@ private:
TForm *form = create_tform(title, &hwnd);
if ( hwnd != NULL ) // Created new tform
{
lookup_info_t::entry_t &e = lookup_info.new_entry(this);
// get a unique graph id
netnode id;
char grnode[MAXSTR];
@ -345,8 +346,7 @@ private:
viewer_fit_window(pview);
bind(self, pview);
refresh();
// Link "form" and "py_graph"
lookup_info.add(form, view, this);
lookup_info.commit(e, form, view);
}
else
{
@ -703,7 +703,7 @@ int py_graph_t::gr_callback(int code, va_list va)
case grcode_creating_group: // a group is being created
{
mutable_graph_t *g = va_arg(va, mutable_graph_t*);
intset_t *nodes = va_arg(va, intset_t*);
intvec_t *nodes = va_arg(va, intvec_t*);
ret = on_creating_group(g, nodes);
}
break;

View File

@ -21,27 +21,25 @@
#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory
#define _STD_BEGIN
#define typename
%{
#include "hexrays.hpp"
%}
#ifdef __NT__
%include <windows.i>
#endif
//---------------------------------------------------------------------
// some defines to calm SWIG down.
#define DEFINE_MEMORY_ALLOCATION_FUNCS()
//#define DECLARE_UNCOPYABLE(f)
#define AS_PRINTF(format_idx, varg_idx)
#define idaapi
#define __fastcall
%ignore vd_printer_t::vprint;
%ignore string_printer_t::vprint;
%ignore typestring::dstr;
%ignore typestring::multiprint;
%ignore vdui_t::vdui_t;
%ignore cblock_t::find;
%ignore cfunc_t::cfunc_t;
%ignore cfunc_t::sv; // lazy member. Use get_pseudocode() instead
%ignore cfunc_t::boundaries; // lazy member. Use get_boundaries() instead
%ignore cfunc_t::eamap; // lazy member. Use get_eamap() instead
%ignore ctree_item_t::verify;
%ignore ccases_t::find_value;
%ignore ccases_t::print;
@ -60,27 +58,61 @@
%ignore lvar_t::is_promoted_arg;
%ignore lvar_t::lvar_t;
%ignore strtype_info_t::find_strmem;
%ignore typestring::resolve_func_type;
%ignore typestring::common_type;
%ignore typestring::noarray_size;
%ignore file_printer_t::_print;
%ignore file_printer_t;
%ignore qstring_printer_t::qstring_printer_t(const cfunc_t *, qstring &, bool);
%extend cfunc_t {
%immutable rgas;
%immutable stas;
%immutable argidx;
qstring __str__() {
qstring qs;
qstring_printer_t p($self, qs, 0);
$self->print_func(p);
return qs;
}
};
%ignore qstring_printer_t::qstring_printer_t(const cfunc_t *, qstring &, bool);
%ignore qstring_printer_t::~qstring_printer_t();
%extend qstring_printer_t {
qstring_printer_t(const cfunc_t *f, bool tags);
~qstring_printer_t();
qstring get_s() {
return $self->s;
}
%pythoncode {
s = property(lambda self: self.get_s())
}
};
%rename(dereference_uint16) operator uint16*;
%rename(dereference_const_uint16) operator const uint16*;
// this is a dummy class template to allow swig to do its thing.
#if !defined(__MAC__) || (MACSDKVER >= 1060)
#define HAS_MAP_AT
#endif
// Provide trivial std::map facade so basic operations are available.
template<class key_type, class mapped_type> class std::map {
public:
#ifdef HAS_MAP_AT
mapped_type& at(const key_type& _Keyval);
#endif
size_t size() const;
};
#ifndef HAS_MAP_AT
#warning "std::map doesn't provide at(). Augmenting it."
%extend std::map {
mapped_type& at(const key_type& _Keyval) { return $self->operator[](_Keyval); }
}
#endif
//---------------------------------------------------------------------
%extend citem_t {
// define these two struct members that can be used for casting.
@ -150,15 +182,21 @@ public:
%ignore qvector< citem_t *>::grow;
%ignore qvector< cinsn_t *>::grow;
//~ %template(qwstrvec_t) qvector<qwstring>; // vector of unicode strings
typedef intvec_t svalvec_t; // vector of signed values
typedef intvec_t eavec_t;// vector of addresses
// director classes make it possible to override virtual functions from python.
%feature("director") ctree_visitor_t;
%feature("director") ctree_parentee_t;
%feature("director") cfunc_parentee_t;
%feature("director") user_lvar_visitor_t;
// At this point, SWIG doesn't know about this
// type yet (kernwin.i is included later). Therefore,
// unless we do this, swig will consider 'strvec_t' to be
// just a regular type, and when retrieving structure
// members of type 'strvec_t', 2 issues:
// - an additional copy will be made, and
// - SWIG will use SWIGTYPE_p_strvec_t, which has a != Python type
// information than SWIGTYPE_p_qvectorT_simpleline_t_t, and no
// proper Python 'strvec_t' proxy instance will be created.
typedef qvector<simpleline_t> strvec_t;
// hexrays templates
%template(user_numforms_t) std::map<operand_locator_t, number_format_t>;
@ -172,6 +210,29 @@ typedef intvec_t eavec_t;// vector of addresses
%template(cinsnptrvec_t) qvector<cinsn_t *>;
%template(eamap_t) std::map<ea_t, cinsnptrvec_t>;
%template(boundaries_t) std::map<cinsn_t *, areaset_t>;
// WARNING: The order here is VERY important:
// 1) The '%extend' directive. Note that
// - the template name must be used, not the typedef (i.e., not 'cfuncptr_t')
// - to override the destructor, the destructor must have the template parameters.
// 2) The '%ignore' directive.
// - Again, using the template name, but this time
// - not qualifying the destructor with template parameters
// 3) The '%template' directive, that will indeed instantiate
// the template for swig.
%{ void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp); %}
%extend qrefcnt_t<cfunc_t> {
// The typemap above will take care of registering newly-constructed cfuncptr_t
// instances. However, there's no such thing as a destructor typemap.
// Therefore, we need to do the grunt work of de-registering ourselves.
// Note: The 'void' here is important: Without it, SWIG considers it to
// be a different destructor (which, of course, makes a ton of sense.)
~qrefcnt_t<cfunc_t>(void)
{
hexrays_deregister_python_cfuncptr_t_instance($self);
delete $self;
}
}
%ignore qrefcnt_t<cfunc_t>::~qrefcnt_t(void);
%template(cfuncptr_t) qrefcnt_t<cfunc_t>;
%template(qvector_history_t) qvector<history_item_t>;
%template(history_t) qstack<history_item_t>;
@ -215,25 +276,6 @@ class qlist_cinsn_t_iterator {};
const char *c_str() const { return self->c_str(); }
};
%{
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf)
{
try
{
cfuncptr_t cfunc = decompile(pfn, hf);
return cfunc;
}
catch(...)
{
error("Hex-Rays Python: decompiler threw an exception.\n");
}
return cfuncptr_t(0);
}
%}
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf);
%ignore decompile;
void qswap(cinsn_t &a, cinsn_t &b);
%include "typemaps.i"
@ -245,6 +287,19 @@ void qswap(cinsn_t &a, cinsn_t &b);
%{
//-------------------------------------------------------------------------
qstring_printer_t *new_qstring_printer_t(const cfunc_t *f, bool tags)
{
return new qstring_printer_t(f, * (new qstring()), tags);
}
//-------------------------------------------------------------------------
void delete_qstring_printer_t(qstring_printer_t *qs)
{
delete &(qs->s);
delete qs;
}
//---------------------------------------------------------------------
static int hexrays_python_call(ref_t fct, ref_t args)
{
@ -524,8 +579,89 @@ int __remove_hexrays_callback(PyObject *hx_cblist_callback)
return result;
}
%}
%{
//-------------------------------------------------------------------------
// A set of cfuncptr_t objects that were created from IDAPython.
// This is necessary in order to delete those objects before the hexrays
// plugin is unloaded. Otherwise, IDAPython will still delete them, but
// the plugin's 'hexdsp' dispatcher function will point to dlclose()'d
// code.
static qvector<cfuncptr_t*> python_cfuncptrs;
void hexrays_clear_python_cfuncptr_t_references(void)
{
for ( size_t i = 0, n = python_cfuncptrs.size(); i < n; ++i )
python_cfuncptrs[i]->reset();
// NOTE: Don't clear() the array of pointers. All the python-exposed
// cfuncptr_t instances will be deleted through the python
// shutdown/ref-decrementing process anyway, and the entries will be
// properly pulled out of the vector when that happens.
}
void hexrays_register_python_cfuncptr_t_instance(cfuncptr_t *fp)
{
QASSERT(30457, !python_cfuncptrs.has(fp));
python_cfuncptrs.push_back(fp);
}
void hexrays_deregister_python_cfuncptr_t_instance(cfuncptr_t *fp)
{
qvector<cfuncptr_t*>::iterator found = python_cfuncptrs.find(fp);
if ( found != python_cfuncptrs.end() )
{
fp->reset();
python_cfuncptrs.erase(found);
}
}
%}
//-------------------------------------------------------------------------
#if SWIG_VERSION == 0x20012
%typemap(out) cfuncptr_t {}
%typemap(ret) cfuncptr_t
{
// ret cfuncptr_t
cfuncptr_t *ni = new cfuncptr_t($1);
hexrays_register_python_cfuncptr_t_instance(ni);
$result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0);
}
%typemap(out) cfuncptr_t *{}
%typemap(ret) cfuncptr_t *
{
// ret cfuncptr_t*
cfuncptr_t *ni = new cfuncptr_t(*($1));
hexrays_register_python_cfuncptr_t_instance(ni);
$result = SWIG_NewPointerObj(ni, $1_descriptor, SWIG_POINTER_OWN | 0);
}
#else
#error Ensure cfuncptr_t wrapping is compatible with this version of SWIG
#endif
%{
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf)
{
try
{
cfuncptr_t cfunc = decompile(pfn, hf);
return cfunc;
}
catch(...)
{
error("Hex-Rays Python: decompiler threw an exception.\n");
}
return cfuncptr_t(0);
}
%}
cfuncptr_t _decompile(func_t *pfn, hexrays_failure_t *hf);
%ignore decompile;
//---------------------------------------------------------------------
%define %python_callback_in(CB)
%typemap(check) CB {
@ -540,6 +676,17 @@ int __remove_hexrays_callback(PyObject *hx_cblist_callback)
%python_callback_in(PyObject *hx_cblist_callback);
%python_callback_in(PyObject *custom_viewer_popup_item_callback);
%ignore cexpr_t::get_1num_op(const cexpr_t **, const cexpr_t **) const;
#pragma SWIG nowarn=503
%warnfilter(514) user_lvar_visitor_t; // Director base class 'x' has no virtual destructor.
%warnfilter(514) ctree_visitor_t; // ditto
%warnfilter(514) ctree_parentee_t; // ditto
%warnfilter(514) cfunc_parentee_t; // ditto
%warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended.
%feature("director") ctree_visitor_t;
%feature("director") ctree_parentee_t;
%feature("director") cfunc_parentee_t;
%feature("director") user_lvar_visitor_t;
%include "hexrays.hpp"
%pythoncode %{
@ -582,53 +729,19 @@ def decompile(ea, hf=None):
# ---------------------------------------------------------------------
# stringify all string types
qtype.__str__ = qtype.c_str
typestring.__str__ = typestring._print
qstring.__str__ = qstring.c_str
citem_cmt_t.__str__ = citem_cmt_t.c_str
typestring.size = property(typestring.size)
typestring.is_user_cc = property(typestring.is_user_cc)
typestring.is_vararg = property(typestring.is_vararg)
typestring.is_ptr_or_array = property(typestring.is_ptr_or_array)
typestring.is_paf = property(typestring.is_paf)
typestring.is_funcptr = property(typestring.is_funcptr)
typestring.is_ptr = property(typestring.is_ptr)
typestring.is_enum = property(typestring.is_enum)
typestring.is_func = property(typestring.is_func)
typestring.is_void = property(typestring.is_void)
typestring.is_array = property(typestring.is_array)
typestring.is_float = property(typestring.is_float)
typestring.is_union = property(typestring.is_union)
typestring.is_struct = property(typestring.is_struct)
typestring.is_struni = property(typestring.is_struni)
typestring.is_double = property(typestring.is_double)
typestring.is_ldouble = property(typestring.is_ldouble)
typestring.is_floating = property(typestring.is_floating)
typestring.is_const = property(typestring.is_const)
typestring.is_correct = property(typestring.is_correct)
typestring.is_scalar = property(typestring.is_scalar)
typestring.is_small_struni = property(typestring.is_small_struni)
typestring.is_like_scalar = property(typestring.is_like_scalar)
typestring.is_pvoid = property(typestring.is_pvoid)
typestring.is_partial_ptr = property(typestring.is_partial_ptr)
typestring.is_well_defined = property(typestring.is_well_defined)
typestring.requires_cot_ref = property(typestring.requires_cot_ref)
typestring.partial_type_num = property(typestring.partial_type_num)
#qtype.__str__ = qtype.c_str
#qstring.__str__ = qstring.c_str
#citem_cmt_t.__str__ = citem_cmt_t.c_str
# ---------------------------------------------------------------------
# listify all list types
def _vectors_iterator(self):
for i in range(len(self)):
yield self[i]
for cls in [cinsnptrvec_t, ctree_items_t, uvalvec_t, \
intvec_t, boolvec_t, hexwarns_t, \
history_t, strvec_t, qvector_lvar_t,
qvector_carg_t, qvector_ccase_t
]:
cls.__getitem__ = cls.at
cls.__len__ = cls.size
cls.__iter__ = _vectors_iterator
_listify_types(cinsnptrvec_t,
ctree_items_t,
qvector_lvar_t,
qvector_carg_t,
qvector_ccase_t,
hexwarns_t,
history_t)
def citem_to_specific_type(self):
""" cast the citem_t object to its more specific type, either cexpr_t or cinsn_t. """
@ -786,27 +899,17 @@ def cblock_insert(self, index, item):
return
cblock_t.insert = cblock_insert
def cfunc___str__(self):
qs = qstring()
p = qstring_printer_t(self, qs, 0)
self.print_func(p)
return qs.c_str()
cfunc_t.__str__ = cfunc___str__
cfuncptr_t.__str__ = lambda self: str(self.__deref__())
def cfunc_typestring(self):
""" Get the function's return type typestring object. The full prototype \
can be obtained via typestring._print() method. """
ts = typestring()
qt = qtype()
result = self.get_func_type(ts, qt)
if not result: return
return ts
cfunc_t.typestring = property(cfunc_typestring)
cfuncptr_t.typestring = property(lambda self: self.__deref__().typestring)
def cfunc_type(self):
""" Get the function's return type tinfo_t object. """
tif = tinfo_t()
result = self.get_func_type(tif)
if not result:
return
return tif
cfunc_t.type = property(cfunc_type)
cfuncptr_t.type = property(lambda self: self.__deref__().type)
cfunc_t.arguments = property(lambda self: [o for o in self.lvars if o.is_arg_var])
cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments)
@ -822,6 +925,8 @@ cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap())
cfunc_t.boundaries = property(cfunc_t.get_boundaries)
cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries())
#pragma SWIG nowarn=+503
lvar_t.used = property(lvar_t.used)
lvar_t.typed = property(lvar_t.typed)
lvar_t.mreg_done = property(lvar_t.mreg_done)
@ -989,7 +1094,7 @@ def _map_as_dict(maptype, name, keytype, valuetype):
maptype.popitem = _map_popitem
maptype.setdefault = _map_setdefault
_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring)
#_map_as_dict(user_labels_t, 'user_labels', (int, long), qstring)
_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t)
_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t)
_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, (int, long))

View File

@ -25,10 +25,12 @@
%inline %{
static PyObject *type##_create()
{
PYW_GIL_CHECK_LOCKED_SCOPE();
return PyCObject_FromVoidPtr(new type(), NULL);
}
static bool type##_destroy(PyObject *py_obj)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
if ( !PyCObject_Check(py_obj) )
return false;
delete (type *)PyCObject_AsVoidPtr(py_obj);
@ -36,11 +38,14 @@ static bool type##_destroy(PyObject *py_obj)
}
static type *type##_get_clink(PyObject *self)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
return (type *)pyobj_get_clink(self);
}
static PyObject *type##_get_clink_ptr(PyObject *self)
{
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)pyobj_get_clink(self));
PYW_GIL_CHECK_LOCKED_SCOPE();
return PyLong_FromUnsignedLongLong(
(unsigned PY_LONG_LONG)pyobj_get_clink(self));
}
%}
%enddef
@ -2266,6 +2271,12 @@ class object_t(object):
"""Allow access to object attributes by index (like dictionaries)"""
return getattr(self, idx)
# -----------------------------------------------------------------------
def _bounded_getitem_iterator(self):
"""Helper function, to be set as __iter__ method for qvector-, or array-based classes."""
for i in range(len(self)):
yield self[i]
# -----------------------------------------------------------------------
class plugin_t(pyidc_opaque_object_t):
"""Base class for all scripted plugins."""
@ -2332,72 +2343,79 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__):
# -----------------------------------------------------------------------
# qstrvec_t clinked object
# class qstrvec_t(py_clinked_object_t):
# """Class representing an qstrvec_t"""
class _qstrvec_t(py_clinked_object_t):
"""
WARNING: It is very unlikely an IDAPython user should ever, ever
have to use this type. It should only be used for IDAPython internals.
# def __init__(self, items=None):
# py_clinked_object_t.__init__(self)
# # Populate the list if needed
# if items:
# self.from_list(items)
For example, in py_askusingform.py, we ctypes-expose to the IDA
kernel & UI a qstrvec instance, in case a DropdownListControl is
constructed.
That's because that's what AskUsingForm expects, and we have no
choice but to make a DropdownListControl hold a qstrvec_t.
This is, afaict, the only situation where a Python
_qstrvec_t is required.
"""
# def _create_clink(self):
# return _idaapi.qstrvec_t_create()
def __init__(self, items=None):
py_clinked_object_t.__init__(self)
# Populate the list if needed
if items:
self.from_list(items)
# def _del_clink(self, lnk):
# return _idaapi.qstrvec_t_destroy(lnk)
def _create_clink(self):
return _idaapi.qstrvec_t_create()
# def _get_clink_ptr(self):
# return _idaapi.qstrvec_t_get_clink_ptr(self)
def _del_clink(self, lnk):
return _idaapi.qstrvec_t_destroy(lnk)
# def assign(self, other):
# """Copies the contents of 'other' to 'self'"""
# return _idaapi.qstrvec_t_assign(self, other)
def _get_clink_ptr(self):
return _idaapi.qstrvec_t_get_clink_ptr(self)
# def __setitem__(self, idx, s):
# """Sets string at the given index"""
# return _idaapi.qstrvec_t_set(self, idx, s)
def assign(self, other):
"""Copies the contents of 'other' to 'self'"""
return _idaapi.qstrvec_t_assign(self, other)
# def __getitem__(self, idx):
# """Gets the string at the given index"""
# return _idaapi.qstrvec_t_get(self, idx)
def __setitem__(self, idx, s):
"""Sets string at the given index"""
return _idaapi.qstrvec_t_set(self, idx, s)
# def __get_size(self):
# return _idaapi.qstrvec_t_size(self)
def __getitem__(self, idx):
"""Gets the string at the given index"""
return _idaapi.qstrvec_t_get(self, idx)
# size = property(__get_size)
# """Returns the count of elements"""
def __get_size(self):
return _idaapi.qstrvec_t_size(self)
# def addressof(self, idx):
# """Returns the address (as number) of the qstring at the given index"""
# return _idaapi.qstrvec_t_addressof(self, idx)
size = property(__get_size)
"""Returns the count of elements"""
# def add(self, s):
# """Add a string to the vector"""
# return _idaapi.qstrvec_t_add(self, s)
def addressof(self, idx):
"""Returns the address (as number) of the qstring at the given index"""
return _idaapi.qstrvec_t_addressof(self, idx)
def add(self, s):
"""Add a string to the vector"""
return _idaapi.qstrvec_t_add(self, s)
# def from_list(self, lst):
# """Populates the vector from a Python string list"""
# return _idaapi.qstrvec_t_from_list(self, lst)
def from_list(self, lst):
"""Populates the vector from a Python string list"""
return _idaapi.qstrvec_t_from_list(self, lst)
def clear(self, qclear=False):
"""
Clears all strings from the vector.
@param qclear: Just reset the size but do not actually free the memory
"""
return _idaapi.qstrvec_t_clear(self, qclear)
# def clear(self, qclear=False):
# """
# Clears all strings from the vector.
# @param qclear: Just reset the size but do not actually free the memory
# """
# return _idaapi.qstrvec_t_clear(self, qclear)
def insert(self, idx, s):
"""Insert a string into the vector"""
return _idaapi.qstrvec_t_insert(self, idx, s)
# def insert(self, idx, s):
# """Insert a string into the vector"""
# return _idaapi.qstrvec_t_insert(self, idx, s)
# def remove(self, idx):
# """Removes a string from the vector"""
# return _idaapi.qstrvec_t_remove(self, idx)
def remove(self, idx):
"""Removes a string from the vector"""
return _idaapi.qstrvec_t_remove(self, idx)
# -----------------------------------------------------------------------
class PyIdc_cvt_refclass__(pyidc_cvt_helper__):
@ -2678,6 +2696,12 @@ class __IDAPython_Completion_Util(object):
# Instantiate a completion object
IDAPython_Completion = __IDAPython_Completion_Util()
def _listify_types(*classes):
for cls in classes:
cls.__getitem__ = cls.at
cls.__len__ = cls.size
cls.__iter__ = _bounded_getitem_iterator
# The general callback format of notify_when() is:
@ -2744,10 +2768,13 @@ NW_REMOVE = 0x0010
%include "fixup.i"
%include "frame.i"
%include "funcs.i"
%include "typeinf.i"
#ifdef WITH_HEXRAYS
%include "hexrays.i"
#endif
SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t)
%inline %{
//<inline(py_idaapi)>
@ -2852,12 +2879,9 @@ def RunPythonStatement(stmt):
#</pydoc>
*/
/*
//---------------------------------------------------------------------------
// qstrvec_t wrapper
// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py)
//---------------------------------------------------------------------------
DECLARE_PY_CLINKED_OBJECT(qstrvec_t);
static bool qstrvec_t_assign(PyObject *self, PyObject *other)
{
qstrvec_t *lhs = qstrvec_t_get_clink(self);
@ -2959,7 +2983,7 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx)
sv->erase(sv->begin()+idx);
return true;
}
*/
//---------------------------------------------------------------------------
@ -3006,7 +3030,6 @@ static bool notify_when(int when, PyObject *py_callable)
%include "srarea.i"
%include "strlist.i"
%include "struct.i"
%include "typeinf.i"
%include "ua.i"
%include "xref.i"
%include "view.i"

View File

@ -42,6 +42,23 @@
%include "idp.hpp"
%feature("director") IDB_Hooks;
%feature("director") IDP_Hooks;
%extend areacb_t {
areacb_type_t get_type()
{
areacb_type_t t = AREACB_TYPE_UNKNOWN;
if ( $self == &funcs )
t = AREACB_TYPE_FUNC;
else if ( $self == &segs )
t = AREACB_TYPE_SEGMENT;
else if ( $self == &hidden_areas )
t = AREACB_TYPE_HIDDEN_AREA;
else if ( $self == &SRareas )
t = AREACB_TYPE_SRAREA;
return t;
}
}
%inline %{
//<inline(py_idp)>
@ -849,6 +866,15 @@ public:
}
};
enum areacb_type_t
{
AREACB_TYPE_UNKNOWN,
AREACB_TYPE_FUNC,
AREACB_TYPE_SEGMENT,
AREACB_TYPE_HIDDEN_AREA,
AREACB_TYPE_SRAREA,
};
//---------------------------------------------------------------------------
// IDB hooks
//---------------------------------------------------------------------------
@ -869,8 +895,9 @@ public:
// Hook functions to override in Python
virtual int byte_patched(ea_t /*ea*/) { return 0; };
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("ti_changed hook not supported yet\n"); return 0; };
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("op_ti_changed hook not supported yet\n"); return 0; };
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; }
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
virtual int enum_created(enum_t /*id*/) { return 0; };
virtual int enum_deleted(enum_t /*id*/) { return 0; };
@ -1408,8 +1435,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
ea_t ea, ea2;
bool repeatable_cmt;
/*type_t *type;*/
/* p_list *fnames; */
type_t *type;
p_list *fnames;
int n;
enum_t id;
const_t cid;
@ -1433,20 +1460,29 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
ea = va_arg(va, ea_t);
repeatable_cmt = va_arg(va, int);
return proxy->cmt_changed(ea, repeatable_cmt);
#if 0
case idb_event::area_cmt_changed:
{
areacb_t *cb = va_arg(va, areacb_t*);
area_t *area = va_arg(va, area_t*);
const char *cmt = va_arg(va, char*);
repeatable_cmt = va_arg(va, int);
return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt);
}
case idb_event::ti_changed:
ea = va_arg(va, ea_t);
type = va_arg(va, type_t *);
fnames = va_arg(va, fnames);
fnames = va_arg(va, p_list *);
return proxy->ti_changed(ea, type, fnames);
case idb_event::op_ti_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);
type = va_arg(va, type_t *);
fnames = va_arg(va, fnames);
fnames = va_arg(va, p_list *);
return proxy->op_ti_changed(ea, n, type, fnames);
#endif
case idb_event::op_type_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);

View File

@ -43,7 +43,6 @@
%ignore restore_database_snapshot;
%ignore destroy_custom_viewer;
%ignore destroy_custom_viewerdestroy_custom_viewer;
%ignore get_custom_viewer_place;
%ignore set_custom_viewer_popup_menu;
%ignore set_custom_viewer_handler;
%ignore set_custom_viewer_range;
@ -72,18 +71,12 @@
%rename (asktext) py_asktext;
%rename (str2ea) py_str2ea;
%rename (str2user) py_str2user;
%ignore process_ui_action;
%rename (process_ui_action) py_process_ui_action;
%ignore exec_request_t;
%ignore execute_sync;
%ignore exec_request_t;
%rename (execute_sync) py_execute_sync;
%ignore read_selection;
%rename (read_selection) py_read_selection;
%ignore ui_request_t;
%ignore execute_ui_requests;
%rename (execute_ui_requests) py_execute_ui_requests;
@ -136,39 +129,12 @@ void refresh_lists(void)
# This is for get_cursor()
%apply int *OUTPUT {int *x, int *y};
# This is for read_selection()
%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 };
SWIG_DECLARE_PY_CLINKED_OBJECT(textctrl_info_t)
%inline %{
//<inline(py_kernwin)>
//------------------------------------------------------------------------
//------------------------------------------------------------------------
/*
#<pydoc>
def read_selection():
"""
Returns selected area boundaries
@return: tuple(ok: bool, start_ea, end_ea)
"""
pass
#</pydoc>
*/
static PyObject *py_read_selection()
{
ea_t ea1, ea2;
bool b = read_selection(&ea1, &ea2);
PYW_GIL_CHECK_LOCKED_SCOPE();
return Py_BuildValue(
"(i" PY_FMT64 PY_FMT64 ")",
b ? 1 : 0,
pyul_t(ea1), pyul_t(ea2));
}
//------------------------------------------------------------------------
/*
#<pydoc>
@ -343,6 +309,45 @@ def free_custom_icon(icon_id):
#</pydoc>
*/
//-------------------------------------------------------------------------
/*
#<pydoc>
def readsel2(view, p0, p1):
"""
Read the user selection, and store its information in p0 (from) and p1 (to).
This can be used as follows:
>>> p0 = idaapi.twinpos_t()
p1 = idaapi.twinpos_t()
view = idaapi.get_current_viewer()
idaapi.readsel2(view, p0, p1)
At that point, p0 and p1 hold information for the selection.
But, the 'at' property of p0 and p1 is not properly typed.
To specialize it, call #place() on it, passing it the view
they were retrieved from. Like so:
>>> place0 = p0.place(view)
place1 = p1.place(view)
This will effectively "cast" the place into a specialized type,
holding proper information, depending on the view type (e.g.,
disassembly, structures, enums, ...)
@param view: The view to retrieve the selection for.
@param p0: Storage for the "from" part of the selection.
@param p1: Storage for the "to" part of the selection.
@return: a bool value indicating success.
"""
pass
#</pydoc>
*/
//------------------------------------------------------------------------
/*
#<pydoc>
@ -1086,8 +1091,6 @@ PyObject *choose2_get_embedded_selection(PyObject *self);
#define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa;
//---------------------------------------------------------------------------
DECLARE_PY_CLINKED_OBJECT(textctrl_info_t);
static bool textctrl_info_t_assign(PyObject *self, PyObject *other)
{
textctrl_info_t *lhs = textctrl_info_t_get_clink(self);
@ -1222,20 +1225,21 @@ static PyObject *formchgcbfa_get_field_value(
PYW_GIL_CHECK_LOCKED_SCOPE();
switch ( ft )
{
// dropdown list
case 8:
{
// Readonly? Then return the selected index
if ( sz == 1 )
{
int sel_idx;
if ( fa->get_field_value(fid, &sel_idx) )
if ( fa->get_combobox_value(fid, &sel_idx) )
return PyLong_FromLong(sel_idx);
}
// Not readonly? Then return the qstring
else
{
qstring val;
if ( fa->get_field_value(fid, &val) )
if ( fa->get_combobox_value(fid, &val) )
return PyString_FromString(val.c_str());
}
break;
@ -1244,15 +1248,15 @@ static PyObject *formchgcbfa_get_field_value(
case 7:
{
textctrl_info_t ti;
if ( fa->get_field_value(fid, &ti) )
if ( fa->get_text_value(fid, &ti) )
return Py_BuildValue("(sII)", ti.text.c_str(), ti.flags, ti.tabsize);
break;
}
// button - uint32
case 4:
{
uint32 val;
if ( fa->get_field_value(fid, &val) )
uval_t val;
if ( fa->get_unsigned_value(fid, &val) )
return PyLong_FromUnsignedLong(val);
break;
}
@ -1260,7 +1264,7 @@ static PyObject *formchgcbfa_get_field_value(
case 2:
{
ushort val;
if ( fa->get_field_value(fid, &val) )
if ( fa->_get_field_value(fid, &val) )
return PyLong_FromUnsignedLong(val);
break;
}
@ -1268,7 +1272,7 @@ static PyObject *formchgcbfa_get_field_value(
case 1:
{
char val[MAXSTR];
if ( fa->get_field_value(fid, val) )
if ( fa->get_ascii_value(fid, val, sizeof(val)) )
return PyString_FromString(val);
break;
}
@ -1277,7 +1281,7 @@ static PyObject *formchgcbfa_get_field_value(
{
qstring val;
val.resize(sz + 1);
if ( fa->get_field_value(fid, val.begin()) )
if ( fa->get_ascii_value(fid, val.begin(), val.size()) )
return PyString_FromString(val.begin());
break;
}
@ -1285,12 +1289,11 @@ static PyObject *formchgcbfa_get_field_value(
{
intvec_t intvec;
// Returned as 1-base
if (fa->get_field_value(fid, &intvec))
if (fa->get_chooser_value(fid, &intvec))
{
// Make 0-based
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
(*it)--;
ref_t l(PyW_IntVecToPyList(intvec));
l.incref();
return l.o;
@ -1311,33 +1314,38 @@ static PyObject *formchgcbfa_get_field_value(
{
case 'S': // sel_t
{
if ( fa->get_field_value(fid, &u.sel) )
if ( fa->get_segment_value(fid, &u.sel) )
return Py_BuildValue(PY_FMT64, u.sel);
break;
}
// sval_t
case 'n':
case 'N':
case 'D':
case 'O':
case 'Y':
case 'H':
{
if ( fa->get_field_value(fid, &u.sval) )
if ( fa->get_signed_value(fid, &u.sval) )
return Py_BuildValue(PY_SFMT64, u.sval);
break;
}
case 'L': // uint64
case 'l': // int64
{
if ( fa->get_field_value(fid, &u.ull) )
return Py_BuildValue(sz == 'L' ? "K" : "L", u.ull);
if ( fa->_get_field_value(fid, &u.ull) )
return Py_BuildValue("K", u.ull);
break;
}
case 'N':
case 'M': // uval_t
{
if ( fa->get_unsigned_value(fid, &u.uval) )
return Py_BuildValue(PY_FMT64, u.uval);
break;
}
case '$': // ea_t
{
if ( fa->get_field_value(fid, &u.uval) )
if ( fa->get_ea_value(fid, &u.uval) )
return Py_BuildValue(PY_FMT64, u.uval);
break;
}
@ -1367,13 +1375,13 @@ static bool formchgcbfa_set_field_value(
if ( PyString_Check(py_val) )
{
qstring val(PyString_AsString(py_val));
return fa->set_field_value(fid, &val);
return fa->set_combobox_value(fid, &val);
}
// Readonly dropdown list
else
{
int sel_idx = PyLong_AsLong(py_val);
return fa->set_field_value(fid, &sel_idx);
return fa->set_combobox_value(fid, &sel_idx);
}
break;
}
@ -1381,24 +1389,24 @@ static bool formchgcbfa_set_field_value(
case 7:
{
textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(py_val);
return ti == NULL ? false : fa->set_field_value(fid, ti);
return ti == NULL ? false : fa->set_text_value(fid, ti);
}
// button - uint32
case 4:
{
uint32 val = PyLong_AsUnsignedLong(py_val);
return fa->set_field_value(fid, &val);
uval_t val = PyLong_AsUnsignedLong(py_val);
return fa->set_unsigned_value(fid, &val);
}
// ushort
case 2:
{
ushort val = PyLong_AsUnsignedLong(py_val) & 0xffff;
return fa->set_field_value(fid, &val);
return fa->_set_field_value(fid, &val);
}
// strings
case 3:
case 1:
return fa->set_field_value(fid, PyString_AsString(py_val));
return fa->set_ascii_value(fid, PyString_AsString(py_val));
// intvec_t
case 5:
{
@ -1411,14 +1419,14 @@ static bool formchgcbfa_set_field_value(
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
(*it)++;
return fa->set_field_value(fid, &intvec);
return fa->set_chooser_value(fid, &intvec);
}
// Numeric
case 6:
{
uint64 num;
if ( PyW_GetNumber(py_val, &num) )
return fa->set_field_value(fid, &num);
return fa->_set_field_value(fid, &num);
}
}
return false;
@ -1428,6 +1436,11 @@ static bool formchgcbfa_set_field_value(
static size_t py_get_AskUsingForm()
{
// Return a pointer to the function. Note that, although
// the C implementation of AskUsingForm_cv will do some
// Qt/txt widgets generation, the Python's ctypes
// implementation through which the call well go will first
// unblock other threads. No need to do it ourselves.
return (size_t)AskUsingForm_c;
}
@ -1813,8 +1826,8 @@ private:
self,
(char *)S_ON_DELETE_LINE,
"i",
lineno - 1));
return pyres == NULL ? lineno : PyInt_AsLong(pyres.o) + 1;
IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1));
return pyres == NULL ? 1 : PyInt_AsLong(pyres.o);
}
int on_refresh(int lineno)
@ -3980,8 +3993,39 @@ uint32 choose_choose(PyObject *self,
int deflt,
int icon);
%extend place_t {
static idaplace_t *as_idaplace_t(place_t *p) { return (idaplace_t *) p; }
static enumplace_t *as_enumplace_t(place_t *p) { return (enumplace_t *) p; }
static structplace_t *as_structplace_t(place_t *p) { return (structplace_t *) p; }
static simpleline_place_t *as_simpleline_place_t(place_t *p) { return (simpleline_place_t *) p; }
}
%extend twinpos_t {
%pythoncode {
def place_as_idaplace_t(self):
return place_t.as_idaplace_t(self.at)
def place_as_enumplace_t(self):
return place_t.as_enumplace_t(self.at)
def place_as_structplace_t(self):
return place_t.as_structplace_t(self.at)
def place_as_simpleline_place_t(self):
return place_t.as_simpleline_place_t(self.at)
def place(self, view):
ptype = get_viewer_place_type(view)
if ptype == TCCPT_IDAPLACE:
return self.place_as_idaplace_t()
elif ptype == TCCPT_ENUMPLACE:
return self.place_as_enumplace_t()
elif ptype == TCCPT_STRUCTPLACE:
return self.place_as_structplace_t()
elif ptype == TCCPT_SIMPLELINE_PLACE:
return self.place_as_simpleline_place_t()
else:
return self.at
}
}
%pythoncode %{
@ -4995,7 +5039,7 @@ class Form(object):
Form.Control.free(self)
class DropdownListControl(InputControl, qstrvec_t):
class DropdownListControl(InputControl, _qstrvec_t):
"""
Dropdown control
This control allows manipulating a dropdown control
@ -5022,7 +5066,7 @@ class Form(object):
hlp)
# Init the associated qstrvec
qstrvec_t.__init__(self, items)
_qstrvec_t.__init__(self, items)
# Remember if readonly or not
self.readonly = readonly
@ -5033,7 +5077,7 @@ class Form(object):
val_addr = addressof(self.__selval)
else:
# Create an strvec with one qstring
self.__selval = qstrvec_t([selval])
self.__selval = _qstrvec_t([selval])
# Get address of the first element
val_addr = self.__selval.addressof(0)
@ -6094,5 +6138,3 @@ class simplecustviewer_t(object):
#</pydoc>
#</pycode(py_custviewer)>
%}

View File

@ -4,6 +4,8 @@
%ignore term_marks;
%ignore change_jumps_stack_format;
%ignore move_marks;
%ignore curloc_after_segments_moved;
%ignore curloc::rebase_stack;
%ignore loc_gtag;
%ignore DEFINE_CURLOC_HELPERS;
%ignore DEFINE_LOCATION_HELPERS;

View File

@ -12,11 +12,11 @@
%ignore unregister_custom_refinfo;
%ignore get_custom_refinfos;
%template (ids_array) wrapped_array<tid_t,32>;
%template (ids_array) wrapped_array_t<tid_t,32>;
%extend strpath_t {
wrapped_array<tid_t,32> __getIds() {
return wrapped_array<tid_t,32>($self->ids);
wrapped_array_t<tid_t,32> __getIds() {
return wrapped_array_t<tid_t,32>($self->ids);
}
%pythoncode {
@ -85,6 +85,7 @@ switch_info_ex_t *switch_info_ex_t_get_clink(PyObject *self)
%rename (del_switch_info_ex) py_del_switch_info_ex;
%rename (create_switch_xrefs) py_create_switch_xrefs;
%rename (create_switch_table) py_create_switch_table;
%rename (calc_switch_cases) py_calc_switch_cases;
%inline %{
//<inline(py_nalt)>
@ -169,6 +170,54 @@ idaman bool ida_export py_create_switch_xrefs(
return true;
}
//-------------------------------------------------------------------------
struct cases_and_targets_t
{
casevec_t cases;
eavec_t targets;
};
//-------------------------------------------------------------------------
/*
#<pydoc>
def calc_switch_cases(insn_ea, si):
"""
Get information about a switch's cases.
The returned information can be used as follows:
for idx in xrange(len(results.cases)):
cur_case = results.cases[idx]
for cidx in xrange(len(cur_case)):
print "case: %d" % cur_case[cidx]
print " goto 0x%x" % results.targets[idx]
@param insn_ea: address of the 'indirect jump' instruction
@param si: switch information
@return: a structure with 2 members: 'cases', and 'targets'.
"""
pass
#</pydoc>
*/
idaman cases_and_targets_t *ida_export py_calc_switch_cases(
ea_t insn_ea,
PyObject *py_swi)
{
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
if ( swi == NULL )
return NULL;
cases_and_targets_t *ct = new cases_and_targets_t;
if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) )
{
delete ct;
return NULL;
}
return ct;
}
//-------------------------------------------------------------------------
/*

View File

@ -87,6 +87,7 @@
%ignore netnode::altadjust;
%ignore netnode::getblob(void *buf, size_t *bufsize, nodeidx_t start, char tag);
%ignore netnode::operator nodeidx_t;
%ignore netnode::validate_names;
// Renaming one version of hashset() otherwise SWIG will not be able to activate the other one
%rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag);
@ -136,4 +137,3 @@
return self->hashset(idx, buf, sz, tag);
}
}

View File

@ -16,6 +16,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1);
}
//---------------------------------------------------------------------
%ignore wchar2char;
%ignore hit_counter_t;
%ignore reg_hit_counter;
@ -55,6 +56,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1);
%ignore qstrchr;
%ignore qstrrchr;
%ignore bytevec_t;
%ignore qstrvec_t;
%ignore reloc_info_t;
%ignore relobj_t;
%ignore wchar2char;
@ -63,6 +65,7 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1);
%ignore base64_encode;
%ignore base64_decode;
%ignore utf8_unicode;
%ignore unicode_utf8;
%ignore win_utf2idb;
%ignore char2oem;
%ignore oem2char;
@ -112,22 +115,59 @@ $result = PyLong_FromUnsignedLongLong((unsigned long long) $1);
void qvector<uval_t>::grow(const unsigned int &x=0);
%ignore qvector<uval_t>::grow;
%ignore qvector::at(size_t);
// simpleline_t doesn't implement '=='. Therefore, all these cannot be present in the instantiated template.
%ignore qvector<simpleline_t>::operator==;
%ignore qvector<simpleline_t>::operator!=;
%ignore qvector<simpleline_t>::find;
%ignore qvector<simpleline_t>::has;
%ignore qvector<simpleline_t>::del;
%ignore qvector<simpleline_t>::add_unique;
%include "pro.h"
//---------------------------------------------------------------------
%template(uvalvec_t) qvector<uval_t>; // vector of unsigned values
%template(intvec_t) qvector<int>; // vector of integers
%template(qstrvec_t) qvector<qstring>; // vector of strings
%template(boolvec_t) qvector<bool>; // vector of bools
%extend qvector {
inline size_t __len__() const { return $self->size(); }
// The fact that we are returning a const version of a reference to the
// type is what allows SWIG to generate a wrapper for this method, that
// will build an proper object (int, unsigned int, ...) instead
// of a pointer. Remove the 'const', and you'll see that, in
// SWIGINTERN PyObject *_wrap_uvalvec_t___getitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
// it will produce this:
// resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 );
// instead of that:
// resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result));
inline const T& __getitem__(size_t i) const throw(std::out_of_range) {
if (i >= $self->size() || i < 0)
throw std::out_of_range("out of bounds access");
return $self->at(i);
}
inline void __setitem__(size_t i, const T& v) throw(std::out_of_range) {
if (i >= $self->size() || i < 0)
throw std::out_of_range("out of bounds access");
$self->at(i) = v;
}
%pythoncode {
__iter__ = _bounded_getitem_iterator
}
}
//---------------------------------------------------------------------
class qstring {
public:
const char *c_str() const { return self->c_str(); }
};
%template(uvalvec_t) qvector<uval_t>; // unsigned values
%template(intvec_t) qvector<int>;
%template(boolvec_t) qvector<bool>;
%template(casevec_t) qvector<qvector<sval_t> >; // signed values
%template(strvec_t) qvector<simpleline_t>;
class qtype {
public:
const uchar *c_str() const { return self->c_str(); }
};
%pythoncode %{
_listify_types(uvalvec_t,
intvec_t,
boolvec_t,
casevec_t,
strvec_t)
%}

View File

@ -31,10 +31,12 @@ void segment_t_startEA_set(segment_t *segm, ea_t newea)
segm->startEA = newea;
}
}
ea_t segment_t_startEA_get(segment_t *segm)
{
return segm->startEA;
}
void segment_t_endEA_set(segment_t *segm, ea_t newea)
{
if ( getseg(segm->startEA) == segm )
@ -46,6 +48,7 @@ void segment_t_endEA_set(segment_t *segm, ea_t newea)
segm->endEA = newea;
}
}
ea_t segment_t_endEA_get(segment_t *segm)
{
return segm->endEA;
@ -56,6 +59,7 @@ ea_t segment_t_endEA_get(segment_t *segm)
ea_t startEA;
ea_t endEA;
}
%include "segment.hpp"
%inline %{

View File

@ -133,8 +133,32 @@
}
%enddef
//---------------------------------------------------------------------
// IN/OUT qstring
//---------------------------------------------------------------------
%typemap(in,numinputs=0) qstring *result (qstring temp) {
$1 = &temp;
}
%typemap(argout) qstring *result {
Py_XDECREF(resultobj);
if (result)
{
resultobj = PyString_FromStringAndSize($1->begin(), $1->length());
}
else
{
Py_INCREF(Py_None);
resultobj = Py_None;
}
}
%typemap(freearg) qstring* result
{
// Nothing. We certainly don't want 'temp' to be deleted.
}
//---------------------------------------------------------------------
// Check that the argument is a callable Python object
//---------------------------------------------------------------------
%typemap(in) PyObject *pyfunc {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Expected a callable object");
@ -155,8 +179,10 @@
$1 = ea_t($1_temp);
}
//-------------------------------------------------------------------------
// Convert qstring
//---------------------------------------------------------------------
// IN qstring
//---------------------------------------------------------------------
// This is used to set/retrieve qstring that are structure members.
%typemap(in) qstring*
{
char *buf;
@ -167,25 +193,32 @@
$1 = new qstring(buf, length);
}
}
%typemap(freearg) qstring*
{
delete $1;
}
%typemap(out) qstring*
{
$result = PyString_FromStringAndSize($1->c_str(), $1->length());
}
%typemap(out) qstring
{
$result = PyString_FromStringAndSize($1.c_str(), $1.length());
}
%apply qstring { _qstring<char> }
%apply qstring* { _qstring<char>* }
#ifdef __EA64__
%apply longlong *INOUT { sval_t *value };
%apply ulonglong *INOUT { ea_t *addr };
%apply ulonglong *INOUT { sel_t *sel };
%apply ulonglong *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection()
#else
%apply int *INOUT { sval_t *value };
%apply unsigned int *INOUT { ea_t *addr };
%apply unsigned int *INOUT { sel_t *sel };
%apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_selection()
#endif
@ -200,14 +233,14 @@
%immutable;
%inline %{
template <typename Type, size_t N>
struct wrapped_array {
struct wrapped_array_t {
Type (&data)[N];
wrapped_array(Type (&data)[N]) : data(data) { }
wrapped_array_t(Type (&data)[N]) : data(data) { }
};
%}
%mutable;
%extend wrapped_array {
%extend wrapped_array_t {
inline size_t __len__() const { return N; }
inline const Type& __getitem__(size_t i) const throw(std::out_of_range) {
@ -221,5 +254,49 @@ struct wrapped_array {
throw std::out_of_range("out of bounds access");
$self->data[i] = v;
}
%pythoncode {
__iter__ = _bounded_getitem_iterator
}
}
//-------------------------------------------------------------------------
#if SWIG_VERSION == 0x20012
%typemap(out) tinfo_t {}
%typemap(ret) tinfo_t
{
// ret tinfo_t
tinfo_t *ni = new tinfo_t($1);
til_register_python_tinfo_t_instance(ni);
$result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0);
}
// KLUDGE: We'll let the compiler (or at worse the runtime)
// decide of the flags to use, depending on the method we are currently
// wrapping: at new-time, a SWIG_POINTER_NEW is required.
%typemap(out) tinfo_t* {}
%typemap(ret) tinfo_t*
{
// ret tinfo_t*
tinfo_t *ni = new tinfo_t(*($1));
til_register_python_tinfo_t_instance(ni);
if ( strcmp("new_tinfo_t", "$symname") == 0 )
{
$result = SWIG_NewPointerObj(SWIG_as_voidptr(ni), $1_descriptor, SWIG_POINTER_NEW | 0);
delete $1;
}
else
{
$result = SWIG_NewPointerObj(SWIG_as_voidptr(ni), $1_descriptor, SWIG_POINTER_OWN | 0);
}
}
%typemap(check) tinfo_t*
{
if ( $1 == NULL )
SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'");
}
#else
#error Ensure tinfo_t wrapping is compatible with this version of SWIG
#endif

View File

@ -68,6 +68,7 @@
%ignore skip_function_arg_names;
%ignore perform_funcarg_conversion;
%ignore get_argloc_info;
%ignore argloc_t::dstr;
%ignore extract_pstr;
%ignore extract_name;
@ -148,7 +149,10 @@
%ignore format_data_info_t;
%ignore valinfo_t;
%ignore print_c_data;
%ignore print_cdata;
%ignore format_c_data;
%ignore format_cdata;
%ignore format_cdata2;
%ignore format_c_number;
%ignore get_enum_member_expr;
%ignore extend_sign;
@ -165,6 +169,81 @@
%ignore enum_type_data_t::deserialize_enum;
%ignore valstr_deprecated_t;
%ignore valinfo_deprecated_t;
%ignore valstr_deprecated2_t;
%ignore valinfo_deprecated2_t;
%ignore custloc_desc_t;
%ignore install_custom_argloc;
%ignore remove_custom_argloc;
%ignore retrieve_custom_argloc;
%{
//<code(py_typeinf)>
//-------------------------------------------------------------------------
// A set of tinfo_t objects that were created from IDAPython.
// This is necessary in order to clear all the "type details" that are
// associated, in the kernel, with the tinfo_t instances.
//
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
// closed, but the "type details" must be cleared _before_ the IDB is closed.
static qvector<tinfo_t*> python_tinfos;
void til_clear_python_tinfo_t_instances(void)
{
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that
// were not done here, ~tinfo_t() calls happening as part of the python shutdown
// process will try and clear() their details. ..but the kernel's til-related
// functions will already have deleted those details at that point.
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i )
python_tinfos[i]->clear();
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t
// instances will be deleted through the python shutdown/ref-decrementing
// process anyway (which will cause til_deregister_..() calls), and the
// entries will be properly pulled out of the vector when that happens.
}
void til_register_python_tinfo_t_instance(tinfo_t *tif)
{
// Let's add_unique() it, because every reference to an object's
// tinfo_t property will end up trying to register it.
python_tinfos.add_unique(tif);
}
void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
{
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif);
if ( found != python_tinfos.end() )
{
tif->clear();
python_tinfos.erase(found);
}
}
//</code(py_typeinf)>
%}
%extend tinfo_t {
bool deserialize(
const til_t *til,
const type_t *type,
const p_list *fields,
const p_list *cmts = NULL)
{
return $self->deserialize(til, &type, &fields, cmts == NULL ? NULL : &cmts);
}
// The typemap in typeconv.i will take care of registering newly-constructed
// tinfo_t instances. However, there's no such thing as a destructor typemap.
// Therefore, we need to do the grunt work of de-registering ourselves.
// Note: The 'void' here is important: Without it, SWIG considers it to
// be a different destructor (which, of course, makes a ton of sense.)
~tinfo_t(void)
{
til_deregister_python_tinfo_t_instance($self);
delete $self;
}
}
%ignore tinfo_t::~tinfo_t(void);
%include "typeinf.hpp"
@ -710,7 +789,6 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize)
qstrncpy(buf, name, bufsize);
return true;
}
//</inline(py_typeinf)>
til_t *load_til(const char *tildir, const char *name)
{

View File

@ -771,7 +771,7 @@ static PyObject *op_t_get_value(PyObject *self)
op_t *link = op_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("I", link->value);
return Py_BuildValue(PY_FMT64, (pyul_t)link->value);
}
static void op_t_set_value(PyObject *self, PyObject *value)
@ -780,7 +780,9 @@ static void op_t_set_value(PyObject *self, PyObject *value)
op_t *link = op_t_get_clink(self);
if ( link == NULL )
return;
link->value = PyInt_AsLong(value);
uint64 v(0);
PyW_GetNumber(value, &v);
link->value = uval_t(v);
}
static PyObject *op_t_get_addr(PyObject *self)

View File

@ -14,16 +14,33 @@ class py_customidamemo_t;
class lookup_info_t
{
public:
void add(TForm *form, TCustomControl *view, py_customidamemo_t *py_view)
struct entry_t
{
QASSERT(0, form != NULL && view != NULL && py_view != NULL
entry_t() : form(NULL), view(NULL), py_view(NULL) {}
private:
TForm *form;
TCustomControl *view;
py_customidamemo_t *py_view;
friend class lookup_info_t;
};
entry_t &new_entry(py_customidamemo_t *py_view)
{
QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view));
entry_t &e = entries.push_back();
e.py_view = py_view;
return e;
}
void commit(entry_t &e, TForm *form, TCustomControl *view)
{
QASSERT(30455, &e >= entries.begin() && &e < entries.end());
QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL
&& !find_by_form(NULL, NULL, form)
&& !find_by_view(NULL, NULL, view)
&& !find_by_py_view(NULL, NULL, py_view));
entry_t &e = entries.push_back();
&& find_by_py_view(NULL, NULL, e.py_view));
e.form = form;
e.view = view;
e.py_view = py_view;
}
#define FIND_BY__BODY(crit, res1, res2) \
@ -61,12 +78,6 @@ public:
}
private:
struct entry_t
{
TForm *form;
TCustomControl *view;
py_customidamemo_t *py_view;
};
typedef qvector<entry_t> entries_t;
entries_t entries;
};
@ -130,6 +141,8 @@ class py_customidamemo_t
static void ensure_view_callbacks_installed();
int cb_flags;
// number of arguments for OnViewClick implementation
int ovc_num_args;
protected:
ref_t self;
@ -198,6 +211,7 @@ public:
void on_view_switched(tcc_renderer_type_t rt);
void on_view_mouse_over(const view_mouse_event_t *event);
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
int get_py_method_arg_count(char *method_name);
};
//-------------------------------------------------------------------------
@ -207,6 +221,7 @@ py_customidamemo_t::py_customidamemo_t()
{
PYGLOG("%p: py_customidamemo_t()\n", this);
ensure_view_callbacks_installed();
ovc_num_args = -1;
}
//-------------------------------------------------------------------------
@ -401,7 +416,7 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
{
newref_t node(PySequence_GetItem(nodes.o, k));
if ( PyInt_Check(node.o) )
gi.nodes.insert(PyInt_AsLong(node.o));
gi.nodes.add_unique(PyInt_AsLong(node.o));
}
if ( !gi.nodes.empty() )
{
@ -409,18 +424,18 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
gis.push_back(gi);
}
}
intset_t groups;
intvec_t groups;
if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() )
Py_RETURN_NONE;
PyObject *py_groups = PyList_New(0);
for ( intset_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
PyList_Append(py_groups, PyInt_FromLong(long(*it)));
return py_groups;
}
//-------------------------------------------------------------------------
static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes)
{
Py_ssize_t sz = PySequence_Size(pynodes.o);
for ( Py_ssize_t i = 0; i < sz; ++i )
@ -428,7 +443,7 @@ static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
newref_t item(PySequence_GetItem(pynodes.o, i));
if ( !PyInt_Check(item.o) )
continue;
idanodes->insert(PyInt_AsLong(item.o));
idanodes->add_unique(PyInt_AsLong(item.o));
}
}
@ -439,7 +454,7 @@ PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_cu
Py_RETURN_NONE;
borref_t groups(_groups);
borref_t new_current(_new_current);
intset_t ida_groups;
intvec_t ida_groups;
pynodes_to_idanodes(&ida_groups, groups);
if ( ida_groups.empty() )
Py_RETURN_NONE;
@ -459,7 +474,7 @@ PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject
borref_t groups(_groups);
borref_t expand(_expand);
borref_t new_current(_new_current);
intset_t ida_groups;
intvec_t ida_groups;
pynodes_to_idanodes(&ida_groups, groups);
if ( ida_groups.empty() )
Py_RETURN_NONE;
@ -498,6 +513,23 @@ void py_customidamemo_t::unbind()
view = NULL;
}
//-------------------------------------------------------------------------
int py_customidamemo_t::get_py_method_arg_count(char *method_name)
{
newref_t method(PyObject_GetAttrString(self.o, method_name));
if ( method != NULL && PyCallable_Check(method.o) )
{
newref_t fc(PyObject_GetAttrString(method.o, "func_code"));
if ( fc != NULL )
{
newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount"));
if ( ac != NULL )
return PyInt_AsLong(ac.o);
}
}
return -1;
}
//-------------------------------------------------------------------------
void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out)
{
@ -603,12 +635,26 @@ void py_customidamemo_t::on_view_popup()
void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
{
CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
if ( ovc_num_args < 0 )
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
if ( ovc_num_args == 5 )
{
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iiii",
event->x, event->y, event->state, event->button));
}
else
{
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iii",
event->x, event->y, event->state));
}
CHK_RES();
}
@ -958,7 +1004,8 @@ bool py_idaview_t::Bind(PyObject *self)
else
{
py_view = new py_idaview_t();
lookup_info.add(tform, v, py_view);
lookup_info_t::entry_t &e = lookup_info.new_entry(py_view);
lookup_info.commit(e, tform, v);
}
// Finally, bind:

View File

@ -11,6 +11,7 @@
%ignore destroy_switch_info;
%ignore create_switch_xrefs;
%ignore create_switch_table;
%rename (calc_switch_cases) py_calc_switch_cases;
// These functions should not be called directly (according to docs)
%ignore xrefblk_t_first_from;