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
+35 -27
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;
}
+5 -5
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)
+2 -2
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)
+6 -6
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;
+2 -5
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)>
+70 -51
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)>
+2 -1
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:
+136 -117
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;
@@ -1382,152 +1392,161 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
try {
switch (notification_code)
{
case idb_event::byte_patched:
ea = va_arg(va, ea_t);
return proxy->byte_patched(ea);
case idb_event::byte_patched:
ea = va_arg(va, ea_t);
return proxy->byte_patched(ea);
case idb_event::cmt_changed:
ea = va_arg(va, ea_t);
repeatable_cmt = va_arg(va, int);
return proxy->cmt_changed(ea, repeatable_cmt);
#if 0
case idb_event::ti_changed:
ea = va_arg(va, ea_t);
type = va_arg(va, type_t *);
fnames = va_arg(va, fnames);
return proxy->ti_changed(ea, type, fnames);
case idb_event::cmt_changed:
ea = va_arg(va, ea_t);
repeatable_cmt = va_arg(va, int);
return proxy->cmt_changed(ea, repeatable_cmt);
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);
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);
return proxy->op_type_changed(ea, n);
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::enum_created:
id = va_arg(va, enum_t);
return proxy->enum_created(id);
case idb_event::ti_changed:
ea = va_arg(va, ea_t);
type = va_arg(va, type_t *);
fnames = va_arg(va, p_list *);
return proxy->ti_changed(ea, type, fnames);
case idb_event::enum_deleted:
id = va_arg(va, enum_t);
return proxy->enum_deleted(id);
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, p_list *);
return proxy->op_ti_changed(ea, n, type, fnames);
case idb_event::enum_bf_changed:
id = va_arg(va, enum_t);
return proxy->enum_bf_changed(id);
case idb_event::op_type_changed:
ea = va_arg(va, ea_t);
n = va_arg(va, int);
return proxy->op_type_changed(ea, n);
case idb_event::enum_cmt_changed:
id = va_arg(va, enum_t);
return proxy->enum_cmt_changed(id);
case idb_event::enum_created:
id = va_arg(va, enum_t);
return proxy->enum_created(id);
case idb_event::enum_deleted:
id = va_arg(va, enum_t);
return proxy->enum_deleted(id);
case idb_event::enum_bf_changed:
id = va_arg(va, enum_t);
return proxy->enum_bf_changed(id);
case idb_event::enum_cmt_changed:
id = va_arg(va, enum_t);
return proxy->enum_cmt_changed(id);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_created:
case idb_event::enum_member_created:
#else
case idb_event::enum_const_created:
case idb_event::enum_const_created:
#endif
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_created(id, cid);
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_created(id, cid);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_deleted:
case idb_event::enum_member_deleted:
#else
case idb_event::enum_const_deleted:
case idb_event::enum_const_deleted:
#endif
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_deleted(id, cid);
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_member_deleted(id, cid);
case idb_event::struc_created:
struc_id = va_arg(va, tid_t);
return proxy->struc_created(struc_id);
case idb_event::struc_created:
struc_id = va_arg(va, tid_t);
return proxy->struc_created(struc_id);
case idb_event::struc_deleted:
struc_id = va_arg(va, tid_t);
return proxy->struc_deleted(struc_id);
case idb_event::struc_deleted:
struc_id = va_arg(va, tid_t);
return proxy->struc_deleted(struc_id);
case idb_event::struc_renamed:
sptr = va_arg(va, struc_t *);
return proxy->struc_renamed(sptr);
case idb_event::struc_renamed:
sptr = va_arg(va, struc_t *);
return proxy->struc_renamed(sptr);
case idb_event::struc_expanded:
sptr = va_arg(va, struc_t *);
return proxy->struc_expanded(sptr);
case idb_event::struc_expanded:
sptr = va_arg(va, struc_t *);
return proxy->struc_expanded(sptr);
case idb_event::struc_cmt_changed:
struc_id = va_arg(va, tid_t);
return proxy->struc_cmt_changed(struc_id);
case idb_event::struc_cmt_changed:
struc_id = va_arg(va, tid_t);
return proxy->struc_cmt_changed(struc_id);
case idb_event::struc_member_created:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_created(sptr, mptr);
case idb_event::struc_member_created:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_created(sptr, mptr);
case idb_event::struc_member_deleted:
sptr = va_arg(va, struc_t *);
member_id = va_arg(va, tid_t);
ea = va_arg(va, ea_t);
return proxy->struc_member_deleted(sptr, member_id, ea);
case idb_event::struc_member_deleted:
sptr = va_arg(va, struc_t *);
member_id = va_arg(va, tid_t);
ea = va_arg(va, ea_t);
return proxy->struc_member_deleted(sptr, member_id, ea);
case idb_event::struc_member_renamed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_renamed(sptr, mptr);
case idb_event::struc_member_renamed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_renamed(sptr, mptr);
case idb_event::struc_member_changed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_changed(sptr, mptr);
case idb_event::struc_member_changed:
sptr = va_arg(va, struc_t *);
mptr = va_arg(va, member_t *);
return proxy->struc_member_changed(sptr, mptr);
case idb_event::thunk_func_created:
pfn = va_arg(va, func_t *);
return proxy->thunk_func_created(pfn);
case idb_event::thunk_func_created:
pfn = va_arg(va, func_t *);
return proxy->thunk_func_created(pfn);
case idb_event::func_tail_appended:
pfn = va_arg(va, func_t *);
tail = va_arg(va, func_t *);
return proxy->func_tail_appended(pfn, tail);
case idb_event::func_tail_appended:
pfn = va_arg(va, func_t *);
tail = va_arg(va, func_t *);
return proxy->func_tail_appended(pfn, tail);
case idb_event::func_tail_removed:
pfn = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->func_tail_removed(pfn, ea);
case idb_event::func_tail_removed:
pfn = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->func_tail_removed(pfn, ea);
case idb_event::tail_owner_changed:
tail = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->tail_owner_changed(tail, ea);
case idb_event::tail_owner_changed:
tail = va_arg(va, func_t *);
ea = va_arg(va, ea_t);
return proxy->tail_owner_changed(tail, ea);
case idb_event::func_noret_changed:
pfn = va_arg(va, func_t *);
return proxy->func_noret_changed(pfn);
case idb_event::func_noret_changed:
pfn = va_arg(va, func_t *);
return proxy->func_noret_changed(pfn);
case idb_event::segm_added:
seg = va_arg(va, segment_t *);
return proxy->segm_added(seg);
case idb_event::segm_added:
seg = va_arg(va, segment_t *);
return proxy->segm_added(seg);
case idb_event::segm_deleted:
ea = va_arg(va, ea_t);
return proxy->segm_deleted(ea);
case idb_event::segm_deleted:
ea = va_arg(va, ea_t);
return proxy->segm_deleted(ea);
case idb_event::segm_start_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_start_changed(seg);
case idb_event::segm_start_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_start_changed(seg);
case idb_event::segm_end_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_end_changed(seg);
case idb_event::segm_end_changed:
seg = va_arg(va, segment_t *);
return proxy->segm_end_changed(seg);
case idb_event::segm_moved:
ea = va_arg(va, ea_t);
ea2 = va_arg(va, ea_t);
size = va_arg(va, asize_t);
return proxy->segm_moved(ea, ea2, size);
case idb_event::segm_moved:
ea = va_arg(va, ea_t);
ea2 = va_arg(va, ea_t);
size = va_arg(va, asize_t);
return proxy->segm_moved(ea, ea2, size);
}
}
catch (Swig::DirectorException &e)
+39 -24
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>
+48
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;
}
//-------------------------------------------------------------------------
/*
+43 -1
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
+4 -2
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)
+71 -25
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
&& !find_by_form(NULL, NULL, form)
&& !find_by_view(NULL, NULL, view)
&& !find_by_py_view(NULL, NULL, py_view));
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, 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);
newref_t result(
PyObject_CallMethod(
self.o,
(char *)S_ON_VIEW_CLICK,
"iii",
event->x, event->y, event->state));
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();
}