mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
Merge branch 'master' of https://github.com/idapython/src
This commit is contained in:
+155
-16
@@ -13,6 +13,8 @@
|
||||
|
||||
import ida_idaapi
|
||||
import ida_hexrays
|
||||
import ida_lines
|
||||
import ida_typeinf
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
@@ -20,11 +22,12 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
|
||||
def activate(self, ctx):
|
||||
# get current item
|
||||
# get the current item
|
||||
vu = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
vu.get_current_item(idaapi.USE_KEYBOARD)
|
||||
vu.get_current_item(ida_hexrays.USE_KEYBOARD)
|
||||
|
||||
# check the current item is union field
|
||||
# REGION1, will be referenced latter
|
||||
# check that the current item is a union field
|
||||
if not vu.item.is_citem():
|
||||
return 0
|
||||
e = vu.item.e
|
||||
@@ -41,8 +44,10 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
break
|
||||
if not e.type.is_udt():
|
||||
return 0
|
||||
# END REGION1
|
||||
|
||||
# calculate member's offset
|
||||
# REGION2
|
||||
# calculate the member offset
|
||||
off = 0
|
||||
e = vu.item.e
|
||||
while True:
|
||||
@@ -55,7 +60,9 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
break
|
||||
if not e2.type.is_udt():
|
||||
break
|
||||
# END REGION2
|
||||
|
||||
# REGION3
|
||||
# go up and collect more member references (in order to calculate the final offset)
|
||||
p = vu.item.e
|
||||
while True:
|
||||
@@ -63,8 +70,8 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
if p2.op == ida_hexrays.cot_memptr:
|
||||
break
|
||||
if p2.op == ida_hexrays.cot_memref:
|
||||
e2 = p2
|
||||
tif = remove_pointer(e2.x.type)
|
||||
e2 = p2.cexpr
|
||||
tif = ida_typeinf.remove_pointer(e2.x.type)
|
||||
if not tif.is_union():
|
||||
off += e2.m
|
||||
p = p2
|
||||
@@ -81,45 +88,59 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
objsize = add.type.get_ptrarr_objsize()
|
||||
nbytes = delta * objsize
|
||||
off += nbytes
|
||||
# we can use the calling helpers like WORD/BYTE/...
|
||||
# to calculate the more precise offset
|
||||
# we could use helpers like WORD/BYTE/... to calculate a more precise offset
|
||||
# if ( p2->op == cot_call && (e2->exflags & EXFL_LVALUE) != 0 )
|
||||
break
|
||||
# END REGION3
|
||||
|
||||
# REGION4
|
||||
ea = vu.item.e.ea
|
||||
# the item itself may be unaddressable.
|
||||
# TODO: find its addressable parent
|
||||
if ea == idaapi.BADADDR:
|
||||
if ea == ida_idaapi.BADADDR:
|
||||
return 0
|
||||
# END REGION4
|
||||
|
||||
# REGION5
|
||||
# prepare the text representation for the item,
|
||||
# use the neighborhoods of cursor
|
||||
line = idaapi.tag_remove(ida_kernwin.get_custom_viewer_curline(vu.ct, False))
|
||||
line = ida_lines.tag_remove(ida_kernwin.get_custom_viewer_curline(vu.ct, False))
|
||||
line_len = len(line)
|
||||
x = max(0, vu.cpos.x - 10)
|
||||
l = min(10, line_len - vu.cpos.x) + 10
|
||||
line = line[x:x+l]
|
||||
# END REGION5
|
||||
|
||||
# REGION6
|
||||
ops = ida_hexrays.ui_stroff_ops_t()
|
||||
op = ops.push_back()
|
||||
op.offset = off
|
||||
op.text = line
|
||||
# END REGION6
|
||||
|
||||
# REGION7
|
||||
class set_union_sel_t(ida_hexrays.ui_stroff_applicator_t):
|
||||
def __init__(self, eas):
|
||||
def __init__(self, ea):
|
||||
ida_hexrays.ui_stroff_applicator_t.__init__(self)
|
||||
self.eas = eas
|
||||
self.ea = ea
|
||||
|
||||
def apply(self, opnum, path):
|
||||
vu.cfunc.set_user_union_selection(self.eas[opnum], path)
|
||||
def apply(self, opnum, path, top_tif, spath):
|
||||
typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, top_tif, '', '')
|
||||
idaapi.msg("User selected %s of type %s\n" % (spath, typename))
|
||||
if path.empty():
|
||||
return False
|
||||
vu.cfunc.set_user_union_selection(self.ea, path)
|
||||
vu.cfunc.save_user_unions()
|
||||
return True
|
||||
# END REGION7
|
||||
|
||||
su = set_union_sel_t([ea])
|
||||
# REGION8
|
||||
su = set_union_sel_t(ea)
|
||||
res = ida_hexrays.select_udt_by_offset(None, ops, su)
|
||||
if res != 0:
|
||||
# regenerate ctree
|
||||
vu.refresh_view(True)
|
||||
# END REGION8
|
||||
|
||||
return 1
|
||||
|
||||
@@ -131,7 +152,7 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
print("Hex-rays version %s has been detected, Structure offsets ready to use" % idaapi.get_hexrays_version())
|
||||
print("Hex-rays version %s has been detected, Structure offsets ready to use" % ida_hexrays.get_hexrays_version())
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
"vds17:strchoose",
|
||||
@@ -140,3 +161,121 @@ if ida_hexrays.init_hexrays_plugin():
|
||||
"Shift+T"))
|
||||
else:
|
||||
print('vds17: Hex-rays is not available.')
|
||||
|
||||
"""
|
||||
# A few notes about the VDS17 sample
|
||||
|
||||
You can find two VDS17 samples in the IDA Pro install directory:
|
||||
|
||||
python/examples/hexrays/vds17.py
|
||||
plugins/hexrays_sdk/plugins/vds17
|
||||
|
||||
The former is an IDAPython plugin and the latter is a C++ IDA Pro plugin.
|
||||
Actually they have the same functionality.
|
||||
Just to be more concrete the vds17.py plugin will be used below.
|
||||
|
||||
|
||||
## How the user interface works
|
||||
|
||||
Let us suppose that we have the following local types:
|
||||
|
||||
1 C struct {int c0;int c1;}
|
||||
2 U union {int u0;__int16 u1;}
|
||||
3 D struct {int d0;C d1;U d2;}
|
||||
4 E struct {int e0;D e1;}
|
||||
5 res_t struct {int r0;int r1;__int16 r2;}
|
||||
|
||||
and the decompiler generates the following pseudocode:
|
||||
|
||||
void __cdecl f(res_t *r)
|
||||
{
|
||||
r->r0 = e->e1.d1.c0;
|
||||
r->r1 = e->e1.d2.u0;
|
||||
r->r2 = e->e1.d2.u1;
|
||||
}
|
||||
|
||||
As we see, it looks good, the decompiler did a really good job.
|
||||
|
||||
But let us imagine that we need reference to the ```e1.d2.u0``` union member on the last line.
|
||||
|
||||
At first we need to load the VDS17 plugin. For that,
|
||||
place the cursor at the ```u1``` union member on the last line
|
||||
and use ```Shift-T```.
|
||||
|
||||
The "Structure offsets" dialog appears on the screen.
|
||||
The left pane of the dialog contains the available local types
|
||||
and the right pane has the following view:
|
||||
|
||||
[checked] e->e1.d2.u1; | 10h | |
|
||||
|
||||
Use the left pane to select ```E```, expand it, and select (Double-click) on the ```u0``` member.
|
||||
|
||||
The right pane will change to:
|
||||
|
||||
[checked] e->e1.d2.u1; | 10h | [checke] E.e1.d2.u0 |
|
||||
|
||||
Since this is what we want, press the ```OK``` button and the pseudocode gets changed:
|
||||
|
||||
void __cdecl f(res_t *r)
|
||||
{
|
||||
r->r0 = e->e1.d1.c0;
|
||||
r->r1 = e->e1.d2.u0;
|
||||
r->r2 = e->e1.d2.u0;
|
||||
}
|
||||
|
||||
|
||||
### What do we need this plugin for?
|
||||
|
||||
All union members have the same offset in the parent structure.
|
||||
The decompiler selects the first suitable union member.
|
||||
Sometimes we need to change this selection and use another union member.
|
||||
|
||||
|
||||
## API details
|
||||
|
||||
Let us look into ```python/examples/hexrays/vds17.py```.
|
||||
|
||||
* REGION1: check that the cursor points to the union member
|
||||
* REGION2: calculate the member offset
|
||||
* REGION3: sometimes there is a need to adjust the offset
|
||||
* REGION4: the pointed item must be addressable
|
||||
|
||||
Then the magic begins:
|
||||
|
||||
* REGION5: we need something to show in the ```Operand``` column of the right pane.
|
||||
The text around the cursor looks like a good compromise.
|
||||
* REGION6: we are ready to fill the right pane: we have calculated the offset and
|
||||
have prepared the descriptive text for the operand.
|
||||
* REGION7: it is a callback that informs us about the user selection (will be described later)
|
||||
* REGION8: activate the "Structure offsets" dialog, let the user select,
|
||||
the callback specified above will update the union member, refresh pseudocode
|
||||
|
||||
|
||||
### The devil is in the details
|
||||
|
||||
The main part of callback is the ```apply``` method (REGION7).
|
||||
It receives two arguments:
|
||||
|
||||
1. ```opnum``` is the number of the selected operand (line) in the right pane of the dialog.
|
||||
We need something to map the line number to our operand.
|
||||
In the case of VDS17 ```ea``` performs this role.
|
||||
2. ```path``` the path that describes the union selection.
|
||||
3. ```top_tif``` typeinfo of the top-level UDT which user selected
|
||||
4. ```spath``` the field names path to the selected member
|
||||
|
||||
The union selection path is denotes a concrete member inside a UDT.
|
||||
|
||||
For structure types there is no need in the union selection path because the member
|
||||
offset uniquely denotes the desired member.
|
||||
|
||||
For unions, on the other hand, the member offset is not enough because all union
|
||||
members start at the same offset zero. For them, we remember the ordinal number of the
|
||||
union member in the path. E.g., for the local types given above, the following holds:
|
||||
|
||||
* e1.d1.c0 is denoted by an empty path because it does not have any unions
|
||||
* e1.d2.u0 is denoted by path consisting of 0: we use the first member of U
|
||||
* e1.d2.u1 is denoted by path consisting of 1: we use the second member of U
|
||||
|
||||
You can retrieve the union selection path using API call ```get_user_union_selection```
|
||||
or apply it using ```set_user_union_selection```.
|
||||
"""
|
||||
|
||||
+18
-9
@@ -151,10 +151,10 @@ static bool find_libpython_dt_needed_info(
|
||||
//-------------------------------------------------------------------------
|
||||
static bool patch_dt_needed(
|
||||
const char *path,
|
||||
const qstring &replacement,
|
||||
const qstring &_replacement,
|
||||
qstring *errbuf)
|
||||
{
|
||||
out_verb("Setting relevant DT_NEEDED of \"%s\" to \"%s\"\n", path, replacement.c_str());
|
||||
out_verb("Setting relevant DT_NEEDED of \"%s\" to \"%s\"\n", path, _replacement.c_str());
|
||||
out_ident_inc_t iinc;
|
||||
linput_t *linput = open_linput(path, /*remote=*/ false);
|
||||
if ( linput == nullptr )
|
||||
@@ -214,13 +214,24 @@ static bool patch_dt_needed(
|
||||
room = qltell(reader.get_linput()) - dt_needed_off - 1;
|
||||
}
|
||||
|
||||
const size_t nbytes = replacement.length();
|
||||
bytevec_t replacement;
|
||||
replacement.append(_replacement.c_str(), _replacement.length() + 1);
|
||||
size_t nbytes = replacement.size();
|
||||
out_verb("We have room for %" FMT_Z " bytes, and need to write %" FMT_Z "\n",
|
||||
room, nbytes);
|
||||
|
||||
// and patch
|
||||
if ( room >= nbytes )
|
||||
{
|
||||
if ( room > nbytes )
|
||||
{
|
||||
out_verb("Expanding replacement with %" FMT_Z " '\\0' bytes, to "
|
||||
"override possible previous soname that could derail "
|
||||
"later computation of available room.\n", room - nbytes);
|
||||
replacement.resize(room, 0);
|
||||
nbytes = replacement.size();
|
||||
}
|
||||
|
||||
FILE *fp = openM(path);
|
||||
if ( fp != nullptr )
|
||||
{
|
||||
@@ -230,7 +241,7 @@ static bool patch_dt_needed(
|
||||
if ( !args.dry_run )
|
||||
{
|
||||
// we want to write the zero as well!
|
||||
if ( qfwrite(fp, replacement.c_str(), nbytes+1) == nbytes+1 )
|
||||
if ( qfwrite(fp, replacement.begin(), nbytes) == nbytes )
|
||||
{
|
||||
out_verb("File \"%s\" successfully patched\n", path);
|
||||
}
|
||||
@@ -243,7 +254,7 @@ static bool patch_dt_needed(
|
||||
else
|
||||
{
|
||||
out("Would write %" FMT_Z " bytes (\"%s\") to file\n",
|
||||
nbytes, replacement.c_str());
|
||||
nbytes, replacement.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -263,7 +274,7 @@ static bool patch_dt_needed(
|
||||
errbuf->sprnt("Replacement \"%s\" has a length of %" FMT_Z
|
||||
" bytes, but there is only room for %" FMT_Z ""
|
||||
" bytes in the file. Cannot proceed.\n",
|
||||
replacement.c_str(), nbytes, room);
|
||||
replacement.begin(), nbytes, room);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -460,9 +471,7 @@ static bool split_debug_expand_libpython3_dtneeded_room(
|
||||
out_verb("\"%s\" command successful. Restoring the "
|
||||
"original DT_NEEDED of \"%s\"\n",
|
||||
cmdline.c_str(), dt_needed);
|
||||
qstring padded_dt_needed(dt_needed);
|
||||
padded_dt_needed.resize(SLOT_SIZE, '\0');
|
||||
if ( !patch_dt_needed(path, padded_dt_needed, errbuf) )
|
||||
if ( !patch_dt_needed(path, dt_needed, errbuf) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
+8
-3
@@ -167,14 +167,19 @@ static bool has_appx_path(qstrvec_t paths)
|
||||
if ( appx_path.empty() )
|
||||
{
|
||||
HKEY hkey;
|
||||
bool ok = false;
|
||||
if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Appx", 0, KEY_READ, &hkey) == ERROR_SUCCESS )
|
||||
{
|
||||
if ( !read_string(&appx_path, hkey, L"PackageRoot") )
|
||||
appx_path = "<none>";
|
||||
ok = read_string(&appx_path, hkey, L"PackageRoot");
|
||||
RegCloseKey(hkey);
|
||||
}
|
||||
if ( !ok )
|
||||
{
|
||||
// no Appx support, set to dummy value which doesn't occur in paths
|
||||
appx_path = "<none>";
|
||||
}
|
||||
}
|
||||
for ( auto path : paths )
|
||||
for ( const qstring &path : paths )
|
||||
if ( path.find(appx_path) != qstring::npos )
|
||||
return true;
|
||||
|
||||
|
||||
+32
-7
@@ -254,6 +254,9 @@ void ida_export idapython_hide_wait_box()
|
||||
#define LEXEC(...)
|
||||
#endif
|
||||
|
||||
#define AVERAGE_STEPS_COUNT 10
|
||||
#define MAX_STEPS_COUNT ((AVERAGE_STEPS_COUNT * 2) + 1)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void execution_t::reset_steps()
|
||||
{
|
||||
@@ -268,7 +271,7 @@ void execution_t::reset_steps()
|
||||
// If we never hit the 'trace' callback while in the 'while True' loop
|
||||
// but always when performing the call to the processor module's 'out/outop'
|
||||
// then the loop will never stop. That was happening on windows (optimized.)
|
||||
steps_before_action = 1 + rand() % 20;
|
||||
steps_before_action = 1 + rand() % (AVERAGE_STEPS_COUNT*2);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -300,6 +303,7 @@ void execution_t::stop_tracking()
|
||||
void execution_t::sync_to_present_time()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
LEXEC("execution_t (%p)::sync_to_present_time() now=%d\n", this, int(now));
|
||||
for ( size_t i = 0, n = entries.size(); i < n; ++i )
|
||||
entries[i].etime = now;
|
||||
maybe_hide_wait_box();
|
||||
@@ -342,16 +346,38 @@ void execution_t::reset_current_start_time()
|
||||
//------------------------------------------------------------------------
|
||||
int execution_t::on_trace(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
|
||||
{
|
||||
LEXEC("on_trace() (steps=%d, nentries=%d)\n",
|
||||
#ifdef TESTABLE_BUILD
|
||||
// ensure there was no decrement overflow
|
||||
QASSERT(0, execution.steps_before_action <= MAX_STEPS_COUNT);
|
||||
#endif
|
||||
LEXEC("on_trace() (steps_before_action=%u, entries.size()=%d, timeout=%d)\n",
|
||||
int(execution.steps_before_action),
|
||||
int(execution.entries.size()));
|
||||
// we don't want to query for time at every trace event
|
||||
if ( execution.steps_before_action-- > 0 )
|
||||
int(execution.entries.size()),
|
||||
execution.timeout);
|
||||
if ( execution.timeout < 0 )
|
||||
{
|
||||
LEXEC("on_trace()::no timeout currently set (%d).\n", execution.timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we don't want to query for time at every trace event
|
||||
if ( execution.steps_before_action > 0 )
|
||||
{
|
||||
--execution.steps_before_action;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( get_active_modal_widget() != NULL )
|
||||
{
|
||||
LEXEC("on_trace()::a modal widget is active. Not showing our 'interrupt dialog'.\n");
|
||||
|
||||
// in addition, we want to sync the "start time" to now, so that
|
||||
// the timeout will be relative to that (otherwise, calling
|
||||
// ask_file() might end up showing the waitdialog for a fraction
|
||||
// of a second after `_ida_kernwin.ask_file()` returns, but before
|
||||
// the `ida_kernwin.ask_file()` one does.)
|
||||
execution.sync_to_present_time();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -377,8 +403,7 @@ int execution_t::on_trace(PyObject *obj, PyFrameObject *frame, int what, PyObjec
|
||||
{
|
||||
if ( PyErr_Occurred() == NULL )
|
||||
{
|
||||
LEXEC("on_trace()::INTERRUPTING (setting 'User interrupted' exception) at line %d\n",
|
||||
PyFrame_GetLineNumber(frame));
|
||||
LEXEC("on_trace()::INTERRUPTING (setting 'User interrupted' exception)\n");
|
||||
PyErr_SetString(PyExc_KeyboardInterrupt, "User interrupted");
|
||||
}
|
||||
return -1;
|
||||
|
||||
Binary file not shown.
+6
-18
@@ -444,8 +444,7 @@ def save_database(idbname, flags=0):
|
||||
if len(idbname) == 0:
|
||||
idbname = get_idb_path()
|
||||
mask = ida_loader.DBFL_KILL | ida_loader.DBFL_COMP | ida_loader.DBFL_BAK
|
||||
res = ida_loader.save_database_ex(idbname, flags & mask)
|
||||
return res
|
||||
return ida_loader.save_database(idbname, flags & mask)
|
||||
|
||||
DBFL_BAK = ida_loader.DBFL_BAK # for compatiblity with older versions, eventually delete this
|
||||
|
||||
@@ -509,14 +508,14 @@ def delete_all_segments():
|
||||
ida_name.del_global_name(ea)
|
||||
func = ida_funcs.get_func(ea)
|
||||
if func:
|
||||
ida_funcs.del_func_cmt(func, False)
|
||||
ida_funcs.del_func_cmt(func, True)
|
||||
ida_funcs.set_func_cmt(func, "", False)
|
||||
ida_funcs.set_func_cmt(func, "", True)
|
||||
ida_funcs.del_func(ea)
|
||||
ida_bytes.del_hidden_range(ea)
|
||||
seg = ida_segment.getseg(ea)
|
||||
if seg:
|
||||
ida_segment.del_segment_cmt(seg, False)
|
||||
ida_segment.del_segment_cmt(seg, True)
|
||||
ida_segment.set_segment_cmt(seg, "", False)
|
||||
ida_segment.set_segment_cmt(seg, "", True)
|
||||
ida_segment.del_segm(ea, ida_segment.SEGMOD_KEEP | ida_segment.SEGMOD_SILENT)
|
||||
|
||||
ea = ida_bytes.next_head(ea, ida_ida.cvar.inf.max_ea)
|
||||
@@ -1007,18 +1006,7 @@ def op_offset_high16(ea, n, target):
|
||||
|
||||
|
||||
def MakeVar(ea):
|
||||
"""
|
||||
Mark the location as "variable"
|
||||
|
||||
@param ea: address to mark
|
||||
|
||||
@return: None
|
||||
|
||||
@note: All that IDA does is to mark the location as "variable".
|
||||
Nothing else, no additional analysis is performed.
|
||||
This function may disappear in the future.
|
||||
"""
|
||||
ida_bytes.doVar(ea, 1)
|
||||
pass
|
||||
|
||||
# Every anterior/posterior line has its number.
|
||||
# Anterior lines have numbers from E_PREV
|
||||
|
||||
+18
-12
@@ -358,6 +358,12 @@ static int get_pyidc_cvt_type(PyObject *py_var)
|
||||
return int(IDAPyIntOrLong_AsLong(attr.o));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static inline bool is_pyidc_cvt_type_int64(PyObject *py_var)
|
||||
{
|
||||
return get_pyidc_cvt_type(py_var) == PY_ICID_INT64;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Utility function to convert a python object to an IDC object
|
||||
// and sets a python exception on failure.
|
||||
@@ -736,15 +742,9 @@ int ida_export pyvar_to_idcvar(
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline PyObject *cvt_to_pylong(int32 v)
|
||||
{
|
||||
return PyLong_FromLong(v);
|
||||
}
|
||||
|
||||
inline PyObject *cvt_to_pylong(int64 v)
|
||||
{
|
||||
return PyLong_FromLongLong(v);
|
||||
}
|
||||
// helpers to use with idc_value_t::num (which can be 32-, or 64-bit.)
|
||||
inline PyObject *cvt_to_pylong(int32 v) { return PyLong_FromLong(v); }
|
||||
inline PyObject *cvt_to_pylong(int64 v) { return PyLong_FromLongLong(v); }
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts an IDC variable to a Python variable
|
||||
@@ -786,8 +786,7 @@ int ida_export idcvar_to_pyvar(
|
||||
if ( *py_var != NULL )
|
||||
{
|
||||
// Recycling an int64 object?
|
||||
int t = get_pyidc_cvt_type(py_var->o);
|
||||
if ( t != PY_ICID_INT64 )
|
||||
if ( !is_pyidc_cvt_type_int64(py_var->o) )
|
||||
return CIP_IMMUTABLE; // Cannot recycle immutable object
|
||||
// Update the attribute
|
||||
PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64));
|
||||
@@ -818,7 +817,14 @@ int ida_export idcvar_to_pyvar(
|
||||
case VT_LONG:
|
||||
// Cannot recycle immutable objects
|
||||
if ( *py_var != NULL )
|
||||
return CIP_IMMUTABLE;
|
||||
{
|
||||
// Recycling an int64 object?
|
||||
if ( !is_pyidc_cvt_type_int64(py_var->o) )
|
||||
return CIP_IMMUTABLE;
|
||||
// Update the attribute
|
||||
PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, cvt_to_pylong(idc_var.num));
|
||||
return CIP_OK;
|
||||
}
|
||||
*py_var = newref_t(cvt_to_pylong(idc_var.num));
|
||||
break;
|
||||
case VT_FLOAT:
|
||||
|
||||
+3
-1
@@ -842,7 +842,9 @@ protected:
|
||||
{
|
||||
// identifier
|
||||
{
|
||||
ref_t py_id = newref_t(PyObject_GetAttrString(self, "id"));
|
||||
ref_t py_id;
|
||||
if ( PyObject_HasAttrString(self, "id") )
|
||||
py_id = newref_t(PyObject_GetAttrString(self, "id"));
|
||||
if ( py_id == NULL || !IDAPyStr_Check(py_id.o) )
|
||||
py_id = newref_t(PyObject_Repr(self));
|
||||
if ( py_id != NULL && IDAPyStr_Check(py_id.o) )
|
||||
|
||||
@@ -126,6 +126,15 @@ class quick_widget_commands_t:
|
||||
cmd.icon)
|
||||
attach_dynamic_action_to_popup(widget, popup, desc)
|
||||
|
||||
class disabled_script_timeout_t(object):
|
||||
def __enter__(self):
|
||||
import _ida_idaapi
|
||||
self.was_timeout = _ida_idaapi.set_script_timeout(0)
|
||||
|
||||
def __exit__(self, type, value, tb):
|
||||
import _ida_idaapi
|
||||
_ida_idaapi.set_script_timeout(self.was_timeout)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# bw-compat/deprecated. You shouldn't rely on this in new code
|
||||
from ida_pro import str2user
|
||||
|
||||
@@ -1384,15 +1384,12 @@ except:
|
||||
|
||||
def __call_form_callable(call, *args):
|
||||
assert(len(args))
|
||||
old = _ida_idaapi.set_script_timeout(0)
|
||||
try:
|
||||
with disabled_script_timeout_t():
|
||||
if sys.version_info.major >= 3 and isinstance(args[0], str):
|
||||
largs = list(args)
|
||||
largs[0] = largs[0].encode("UTF-8")
|
||||
args = tuple(largs)
|
||||
r = call(*args)
|
||||
finally:
|
||||
_ida_idaapi.set_script_timeout(old)
|
||||
return r
|
||||
|
||||
def ask_form(*args):
|
||||
|
||||
@@ -205,9 +205,8 @@ class Choose(object):
|
||||
self.flags |= Choose.CH_MODAL
|
||||
|
||||
# Disable the timeout
|
||||
old = _ida_idaapi.set_script_timeout(0)
|
||||
n = _ida_kernwin.choose_choose(self)
|
||||
_ida_idaapi.set_script_timeout(old)
|
||||
with disabled_script_timeout_t():
|
||||
n = _ida_kernwin.choose_choose(self)
|
||||
|
||||
# Delete the modal chooser instance
|
||||
self.Close()
|
||||
|
||||
@@ -31124,7 +31124,7 @@ class ui_stroff_applicator_t(__builtin__.object)
|
||||
| __repr__ = _swig_repr(self)
|
||||
|
|
||||
| apply(self, *args)
|
||||
| apply(self, opnum, path) -> bool
|
||||
| apply(self, opnum, path, top_tif, spath) -> bool
|
||||
|
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors defined here:
|
||||
@@ -46114,6 +46114,24 @@ detach_action_from_toolbar(*args)
|
||||
@param name: the action name (C++: const char *)
|
||||
@return: success
|
||||
|
||||
Help on class disabled_script_timeout_t in module ida_kernwin:
|
||||
|
||||
class disabled_script_timeout_t(__builtin__.object)
|
||||
| Methods defined here:
|
||||
|
|
||||
| __enter__(self)
|
||||
|
|
||||
| __exit__(self, type, value, tb)
|
||||
|
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors defined here:
|
||||
|
|
||||
| __dict__
|
||||
| dictionary for instance variables (if defined)
|
||||
|
|
||||
| __weakref__
|
||||
| list of weak references to the object (if defined)
|
||||
|
||||
Help on class disasm_line_t in module ida_kernwin:
|
||||
|
||||
class disasm_line_t(__builtin__.object)
|
||||
@@ -73313,15 +73331,6 @@ LoadFile(filepath, pos, ea, size)
|
||||
Help on function MakeVar in module idc:
|
||||
|
||||
MakeVar(ea)
|
||||
Mark the location as "variable"
|
||||
|
||||
@param ea: address to mark
|
||||
|
||||
@return: None
|
||||
|
||||
@note: All that IDA does is to mark the location as "variable".
|
||||
Nothing else, no additional analysis is performed.
|
||||
This function may disappear in the future.
|
||||
|
||||
Help on function SaveFile in module idc:
|
||||
|
||||
|
||||
@@ -31074,7 +31074,7 @@ class ui_stroff_applicator_t(builtins.object)
|
||||
| delete_ui_stroff_applicator_t(self)
|
||||
|
|
||||
| apply(self, *args) -> 'bool'
|
||||
| apply(self, opnum, path) -> bool
|
||||
| apply(self, opnum, path, top_tif, spath) -> bool
|
||||
|
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors defined here:
|
||||
@@ -46249,6 +46249,24 @@ detach_action_from_toolbar(*args) -> 'bool'
|
||||
@param name: the action name (C++: const char *)
|
||||
@return: success
|
||||
|
||||
Help on class disabled_script_timeout_t in module ida_kernwin:
|
||||
|
||||
class disabled_script_timeout_t(builtins.object)
|
||||
| Methods defined here:
|
||||
|
|
||||
| __enter__(self)
|
||||
|
|
||||
| __exit__(self, type, value, tb)
|
||||
|
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors defined here:
|
||||
|
|
||||
| __dict__
|
||||
| dictionary for instance variables (if defined)
|
||||
|
|
||||
| __weakref__
|
||||
| list of weak references to the object (if defined)
|
||||
|
||||
Help on class disasm_line_t in module ida_kernwin:
|
||||
|
||||
class disasm_line_t(builtins.object)
|
||||
@@ -73351,15 +73369,6 @@ LoadFile(filepath, pos, ea, size)
|
||||
Help on function MakeVar in module idc:
|
||||
|
||||
MakeVar(ea)
|
||||
Mark the location as "variable"
|
||||
|
||||
@param ea: address to mark
|
||||
|
||||
@return: None
|
||||
|
||||
@note: All that IDA does is to mark the location as "variable".
|
||||
Nothing else, no additional analysis is performed.
|
||||
This function may disappear in the future.
|
||||
|
||||
Help on function SaveFile in module idc:
|
||||
|
||||
|
||||
+6
-6
@@ -42,12 +42,12 @@ extern plugin_t PLUGIN;
|
||||
%ignore ask_text;
|
||||
%ignore vwarning;
|
||||
// Note: don't do that for ask_form(), since that calls back into Python.
|
||||
%thread ask_addr;
|
||||
%thread ask_seg;
|
||||
%thread ask_long;
|
||||
%thread ask_yn;
|
||||
%thread ask_buttons;
|
||||
%thread ask_file;
|
||||
%modal_dialog_triggering_function(ask_addr);
|
||||
%modal_dialog_triggering_function(ask_seg);
|
||||
%modal_dialog_triggering_function(ask_long);
|
||||
%modal_dialog_triggering_function(ask_yn);
|
||||
%modal_dialog_triggering_function(ask_buttons);
|
||||
%modal_dialog_triggering_function(ask_file);
|
||||
|
||||
%ignore simpleline_t::simpleline_t(const qstring &);
|
||||
|
||||
|
||||
@@ -1681,6 +1681,21 @@ SWIGINTERN bool __chkreqidb()
|
||||
|
||||
%}
|
||||
|
||||
%define %modal_dialog_triggering_function(NAME)
|
||||
%thread NAME;
|
||||
%pythonprepend NAME
|
||||
%{
|
||||
import ida_kernwin
|
||||
# kludge: we can't use %feature("shadow") for top-level
|
||||
# functions (see https://github.com/swig/swig/issues/980)
|
||||
# Thus we'll %pythonprepend some code, and return from it,
|
||||
# making the original code unreachable. Not pretty, but I
|
||||
# don't have anything better at the moment.
|
||||
with ida_kernwin.disabled_script_timeout_t():
|
||||
return _ida_kernwin.NAME(*args)
|
||||
%}
|
||||
%enddef
|
||||
|
||||
%include <constraints.i>
|
||||
|
||||
// If the module is 'pro', don't import pro.h, or the %include
|
||||
|
||||
Reference in New Issue
Block a user