mirror of
https://github.com/cemu-project/idapython.git
synced 2024-12-28 02:31:53 +01:00
IDAPython 1.3.0 / IDA Pro 5.6
(For older versions please use the 1.2.90 branch)
This commit is contained in:
parent
ab7a03431e
commit
277facf240
28
BUILDING.txt
28
BUILDING.txt
@ -9,8 +9,8 @@ REQUIREMENTS
|
||||
|
||||
[Tested versions are in brackets]
|
||||
|
||||
- IDA and IDA SDK [5.4]
|
||||
http://www.datarescue.com/idabase/
|
||||
- IDA and IDA SDK [5.6]
|
||||
http://www.hex-rays.com/idapro/
|
||||
|
||||
- Python [2.5.1, 2.6.1]
|
||||
http://www.python.org/
|
||||
@ -38,26 +38,26 @@ Make sure all the needed tools (compiler, swig) are on the PATH.
|
||||
1, Unpack the IDAPython source and IDA Pro SDK into the following
|
||||
directory structure:
|
||||
|
||||
swigsdk-versions/5.4/ - version 5.4 of the IDA Pro SDK
|
||||
swigsdk-versions/5.6/ - version 5.4 of the IDA Pro SDK
|
||||
idapython/ - IDAPython source code
|
||||
|
||||
2, Patch the SDK using GNU Patch with one of patches from patches/ directory.
|
||||
You will have to use the -P option depending on which directory you
|
||||
patch from. This step is not required if there is no SDK patch.
|
||||
|
||||
3, On Mac OS X copy libida.dylib from the IDA install directory to
|
||||
swigsdk-versions/5.4/libgcc32.mac/
|
||||
2, On Mac OS X copy libida.dylib from the IDA install directory to
|
||||
swigsdk-versions/5.6/lib/gcc32.mac/
|
||||
and libida64.dylib to
|
||||
swigsdk-versions/5.4/libgcc64.mac/
|
||||
swigsdk-versions/5.6/lib/gcc64.mac/
|
||||
|
||||
4, Build the plugin
|
||||
3, Build the plugin
|
||||
|
||||
python build.py
|
||||
|
||||
It is possible to build the plugin for different Python versions by
|
||||
running build.py with the corresponding Python binary. The option
|
||||
--ea64 builds the 64-bit version as well.
|
||||
running build.py with the corresponding Python binary.
|
||||
|
||||
Some build options:
|
||||
--ea64: builds the 64-bit version
|
||||
--no-early-load: builds the IDAPython plugin w/o PLUGIN_FIX plugin flag
|
||||
(This flag disables the ability to write file loaders in IDAPython)
|
||||
|
||||
5, Install the components as described in README.txt
|
||||
4, Install the components as described in README.txt
|
||||
|
||||
See build.py for build details and possible tweaks.
|
||||
|
11
README.txt
11
README.txt
@ -61,6 +61,15 @@ Start IDA with the following command line options:
|
||||
If you want fully unattended execution mode, make sure your script
|
||||
exits with a qexit() call.
|
||||
|
||||
By default scripts run after the database is opened. Extended option
|
||||
format is:
|
||||
|
||||
-OIDAPython:[N;]script.py
|
||||
|
||||
Where N can be:
|
||||
0: run script after opening database (default)
|
||||
1: run script when UI is ready
|
||||
2: run script immediately on plugin load (shortly after IDA starts and before processor modules and loaders)
|
||||
|
||||
User init file:
|
||||
|
||||
@ -71,7 +80,7 @@ ${HOME}/.idapro/
|
||||
|
||||
or
|
||||
|
||||
C:\Documents and Settings\%USER%\Application Data\Hex-Rays\IDA Pro
|
||||
%AppData%\Hex-Rays\IDA Pro
|
||||
|
||||
The user init file is read and executed at the end of the init process.
|
||||
|
||||
|
16
build.py
16
build.py
@ -22,7 +22,7 @@ from distutils import sysconfig
|
||||
# Start of user configurable options
|
||||
VERBOSE = True
|
||||
IDA_MAJOR_VERSION = 5
|
||||
IDA_MINOR_VERSION = 5
|
||||
IDA_MINOR_VERSION = 6
|
||||
if 'IDA' in os.environ:
|
||||
IDA_SDK = os.environ['IDA']
|
||||
else:
|
||||
@ -32,8 +32,8 @@ else:
|
||||
|
||||
# IDAPython version
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 2
|
||||
VERSION_PATCH = 90
|
||||
VERSION_MINOR = 3
|
||||
VERSION_PATCH = 0
|
||||
|
||||
# Determine Python version
|
||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||
@ -296,7 +296,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
platform_macros = [ "__LINUX__" ]
|
||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
||||
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.lnx" or "libgcc32.lnx")
|
||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.lnx" or "gcc32.lnx")
|
||||
ida_lib = ""
|
||||
extra_link_parameters = ""
|
||||
# Platform-specific settings for the Windows build
|
||||
@ -305,7 +305,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
platform_macros = [ "__NT__" ]
|
||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
||||
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libvc.w64" or "libvc.w32")
|
||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "vc.w64" or "vc.w32")
|
||||
ida_lib = "ida.lib"
|
||||
SWIG_OPTIONS += " -D__NT__ "
|
||||
extra_link_parameters = ""
|
||||
@ -316,7 +316,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
platform_macros = [ "__MAC__" ]
|
||||
python_libpath = "."
|
||||
python_library = "-framework Python"
|
||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.mac" or "libgcc32.mac")
|
||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.mac64" or "gcc32.mac")
|
||||
ida_lib = ea64 and "-lida64" or "-lida"
|
||||
extra_link_parameters = ""
|
||||
|
||||
@ -326,7 +326,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
||||
if ea64:
|
||||
platform_macros.append("__EA64__")
|
||||
|
||||
if '--early-load' in sys.argv:
|
||||
if not '--no-early-load' in sys.argv:
|
||||
platform_macros.append("PLUGINFIX")
|
||||
|
||||
# Build the wrapper from the interface files
|
||||
@ -394,7 +394,7 @@ def build_binary_package(ea64, nukeold):
|
||||
binmanifest = []
|
||||
if nukeold:
|
||||
binmanifest.extend(BINDIST_MANIFEST)
|
||||
binmanifest.extend([(x, ea64 and "python64" or "python") for x in "python/init.py", "python/idc.py", "python/idautils.py", "idaapi.py"])
|
||||
binmanifest.extend([(x, "python") for x in "python/init.py", "python/idc.py", "python/idautils.py", "idaapi.py"])
|
||||
binmanifest.append((plugin_name, "plugins"))
|
||||
build_distribution(binmanifest, BINDISTDIR, ea64, nukeold)
|
||||
|
||||
|
595
python.cpp
595
python.cpp
@ -48,15 +48,20 @@ extern "C"
|
||||
|
||||
#define IDAPYTHON_DATA_STATEMENT 0
|
||||
|
||||
#ifdef __EA64__
|
||||
#define PYTHON_DIR_NAME "python64"
|
||||
#else
|
||||
#define PYTHON_DIR_NAME "python"
|
||||
#endif
|
||||
|
||||
void init_idaapi(void);
|
||||
void idaapi run(int arg);
|
||||
static int initialized = 0;
|
||||
//--------------------------------------------------------------------------
|
||||
// Some utility functions from pywraps / idaapi
|
||||
int idcvar_to_pyvar(const idc_value_t &idc_var, PyObject **py_var);
|
||||
int pyvar_to_idcvar(PyObject *py_var, idc_value_t *idc_var, int *gvar_sn = NULL);
|
||||
PyObject *PyObject_TryGetAttrString(PyObject *py_var, const char *attr);
|
||||
bool PyGetError(qstring *out = NULL);
|
||||
bool init_pywraps();
|
||||
void deinit_pywraps();
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/* This is a simple tracing code for debugging purposes. */
|
||||
/* It might evolve into a tracing facility for user scripts. */
|
||||
@ -141,34 +146,99 @@ void end_execution()
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return a formatted error or just print it to the console */
|
||||
static void handle_python_error(char *errbuf, size_t errbufsize)
|
||||
{
|
||||
PyObject *result;
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
|
||||
if ( errbufsize > 0 )
|
||||
errbuf[0] = '\0';
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||||
result = PyObject_Repr(pvalue);
|
||||
if (result)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
|
||||
PyErr_Clear();
|
||||
Py_XDECREF(ptype);
|
||||
Py_XDECREF(pvalue);
|
||||
Py_XDECREF(ptraceback);
|
||||
}
|
||||
else
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
|
||||
/* helper function to get globals for the __main__ module */
|
||||
PyObject *GetMainGlobals()
|
||||
{
|
||||
PyObject *module = PyImport_AddModule("__main__");
|
||||
if (module == NULL)
|
||||
return NULL;
|
||||
|
||||
return PyModule_GetDict(module);
|
||||
}
|
||||
|
||||
/* Simple Python statement runner function for IDC */
|
||||
static const char idc_runpythonstatement_args[] = { VT_STR, 0 };
|
||||
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
|
||||
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
|
||||
{
|
||||
begin_execution();
|
||||
res->num = PyRun_SimpleString(argv[0].str);
|
||||
end_execution();
|
||||
PyObject *globals = GetMainGlobals();
|
||||
if (globals == NULL)
|
||||
{
|
||||
res->set_string("internal error");
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear();
|
||||
begin_execution();
|
||||
PyObject *result = PyRun_String(argv[0].c_str(), Py_file_input, globals, globals );
|
||||
end_execution();
|
||||
Py_XDECREF(result);
|
||||
if ( result == NULL || PyErr_Occurred() )
|
||||
{
|
||||
char errbuf[MAXSTR];
|
||||
handle_python_error(errbuf, sizeof(errbuf));
|
||||
*res = idc_value_t(errbuf);
|
||||
if ( errbuf[0] == '\0' )
|
||||
res->set_string("internal error");
|
||||
else
|
||||
res->set_string(errbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// success
|
||||
res->set_long(0);
|
||||
}
|
||||
}
|
||||
return eOk;
|
||||
}
|
||||
|
||||
/* QuickFix for the FILE* incompatibility problem */
|
||||
int ExecFile(const char *FileName)
|
||||
{
|
||||
PyObject* PyFileObject = PyFile_FromString((char*)FileName, "r");
|
||||
PyObject *PyFileObject = PyFile_FromString((char*)FileName, "r");
|
||||
|
||||
if (!PyFileObject)
|
||||
PyObject *globals = GetMainGlobals();
|
||||
if (globals == NULL)
|
||||
return 0;
|
||||
|
||||
if (PyRun_SimpleFile(PyFile_AsFile(PyFileObject), FileName) == 0)
|
||||
PyErr_Clear();
|
||||
PyObject *result = PyRun_File(PyFile_AsFile(PyFileObject), FileName, Py_file_input, globals, globals);
|
||||
|
||||
Py_XDECREF(PyFileObject);
|
||||
Py_XDECREF(result);
|
||||
if ( result == NULL || PyErr_Occurred() )
|
||||
{
|
||||
Py_DECREF(PyFileObject);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_DECREF(PyFileObject);
|
||||
return 0;
|
||||
if ( !PyErr_Occurred() )
|
||||
PyErr_Print();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for the presence of a file in IDADIR/python */
|
||||
@ -188,11 +258,11 @@ bool CheckFile(char *filename)
|
||||
|
||||
/* Execute the Python script from the plugin */
|
||||
/* Default hotkey: Alt-9 */
|
||||
void IDAPython_RunScript(char *script)
|
||||
void IDAPython_RunScript(const char *script)
|
||||
{
|
||||
char statement[MAXSTR+32];
|
||||
char slashpath[MAXSTR+1];
|
||||
char *scriptpath;
|
||||
const char *scriptpath;
|
||||
|
||||
int i;
|
||||
|
||||
@ -255,15 +325,13 @@ void IDAPython_RunStatement(void)
|
||||
/* Default hotkey: Alt-7 */
|
||||
void IDAPython_ScriptBox(void)
|
||||
{
|
||||
PyObject *module;
|
||||
PyObject *dict;
|
||||
PyObject *scriptbox;
|
||||
PyObject *pystr;
|
||||
|
||||
/* Get globals() */
|
||||
/* These two should never fail */
|
||||
module = PyImport_AddModule("__main__");
|
||||
dict = PyModule_GetDict(module);
|
||||
/* This should never fail */
|
||||
dict = GetMainGlobals();
|
||||
|
||||
scriptbox = PyDict_GetItemString(dict, "scriptbox");
|
||||
|
||||
@ -296,37 +364,52 @@ void IDAPython_ScriptBox(void)
|
||||
|
||||
bool idaapi IDAPython_Menu_Callback(void *ud)
|
||||
{
|
||||
run((int)ud);
|
||||
run((size_t)ud);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return a formatted error or just print it to the console */
|
||||
static void handle_python_error(char *errbuf, size_t errbufsize)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This function parses a name into two different components (if it applies).
|
||||
// The first mode of operation:
|
||||
// split_mod_attr_name("modname.attrname", mod_buf, attr_buf)
|
||||
// It splits the full name into two parts.
|
||||
//
|
||||
// The second mode of operation:
|
||||
// split_mod_attr_name("c:\libs\x.py", file_name_buf, NULL)
|
||||
//
|
||||
static bool parse_py_modname(
|
||||
const char *full_name,
|
||||
char *modname,
|
||||
char *attrname, size_t sz)
|
||||
{
|
||||
PyObject *result;
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
|
||||
if ( errbufsize > 0 )
|
||||
errbuf[0] = '\0';
|
||||
|
||||
if (PyErr_Occurred())
|
||||
if (attrname == NULL)
|
||||
{
|
||||
// take the filename.ext part
|
||||
qstrncpy(modname, qbasename(full_name), sz);
|
||||
// take the filename part only
|
||||
qsplitfile(modname, NULL, NULL);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *p = strchr(full_name, '.');
|
||||
if (p == NULL)
|
||||
{
|
||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||||
result = PyObject_Repr(pvalue);
|
||||
if (result)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
|
||||
PyErr_Clear();
|
||||
Py_XDECREF(ptype);
|
||||
Py_XDECREF(pvalue);
|
||||
Py_XDECREF(ptraceback);
|
||||
}
|
||||
else
|
||||
PyErr_Print();
|
||||
qstrncpy(modname, "idaapi", sz);
|
||||
qstrncpy(attrname, full_name, sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
qstrncpy(modname, full_name, p - full_name + 1);
|
||||
qstrncpy(attrname, p + 1, sz);
|
||||
}
|
||||
return p != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert return value from Python to IDC or report about an error */
|
||||
/* Convert return value from Python to IDC or report about an error. */
|
||||
/* This function also decrements the reference "result" (python variable) */
|
||||
static bool return_python_result(idc_value_t *rv,
|
||||
PyObject *result,
|
||||
char *errbuf,
|
||||
@ -340,48 +423,24 @@ static bool return_python_result(idc_value_t *rv,
|
||||
handle_python_error(errbuf, errbufsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PyInt_Check(result))
|
||||
bool ok = true;
|
||||
if (pyvar_to_idcvar(result, rv) <= 0)
|
||||
{
|
||||
rv->num = PyInt_AsLong(result);
|
||||
rv->vtype = VT_LONG;
|
||||
Py_XDECREF(result);
|
||||
return true;
|
||||
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (PyString_Check(result))
|
||||
{
|
||||
rv->str = (char *)qalloc(PyString_Size(result)+1);
|
||||
if (!rv->str)
|
||||
return false;
|
||||
qstrncpy(rv->str, PyString_AsString(result), MAXSTR);
|
||||
rv->vtype = VT_STR;
|
||||
Py_XDECREF(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PyFloat_Check(result))
|
||||
{
|
||||
double dresult = PyFloat_AsDouble(result);
|
||||
ieee_realcvt((void *)&dresult, rv->e, 3);
|
||||
rv->vtype = VT_FLOAT;
|
||||
Py_XDECREF(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
|
||||
return false;
|
||||
Py_XDECREF(result);
|
||||
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)
|
||||
ea_t /*current_ea*/,
|
||||
const char *expr,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
||||
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
|
||||
|
||||
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
||||
if (code == NULL)
|
||||
@ -413,77 +472,211 @@ bool idaapi IDAPython_extlang_compile(const char *name,
|
||||
|
||||
/* Run callback for Python external language evaluator */
|
||||
bool idaapi IDAPython_extlang_run(const char *name,
|
||||
int nargs,
|
||||
const idc_value_t args[],
|
||||
idc_value_t *result,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
int nargs,
|
||||
const idc_value_t args[],
|
||||
idc_value_t *result,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
// convert arguments to python
|
||||
qvector<PyObject *> pargs;
|
||||
qvector<bool> do_decref;
|
||||
|
||||
for (int i=0; i<nargs; i++)
|
||||
bool ok = true;
|
||||
|
||||
PyObject *module(NULL);
|
||||
char modname[MAXSTR] = {0};
|
||||
char funcname[MAXSTR] = {0};
|
||||
bool imported_module = parse_py_modname(name, modname, funcname, MAXSTR);
|
||||
do
|
||||
{
|
||||
double dresult;
|
||||
PyObject *pa;
|
||||
switch (args[i].vtype)
|
||||
for (int i=0; i<nargs; i++)
|
||||
{
|
||||
case VT_LONG:
|
||||
pa = PyInt_FromLong(args[i].num);
|
||||
break;
|
||||
case VT_STR:
|
||||
pa = PyString_FromString(args[i].str);
|
||||
break;
|
||||
case VT_FLOAT:
|
||||
ieee_realcvt(&dresult, (ushort *)args[i].e, 013);
|
||||
pa = PyFloat_FromDouble(dresult);
|
||||
break;
|
||||
default:
|
||||
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
||||
return false;
|
||||
PyObject *py_obj(NULL);
|
||||
int cvt = idcvar_to_pyvar(args[i], &py_obj);
|
||||
if (cvt <= 0)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
pargs.push_back(py_obj);
|
||||
// do not decrement reference of opaque objects
|
||||
do_decref.push_back(cvt == 1);
|
||||
}
|
||||
pargs.push_back(pa);
|
||||
}
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
||||
PyObject *func = PyDict_GetItemString(globals, name);
|
||||
if (imported_module)
|
||||
{
|
||||
module = PyImport_ImportModule(modname);
|
||||
}
|
||||
else
|
||||
{
|
||||
module = PyImport_AddModule("__main__"); QASSERT(module != NULL);
|
||||
}
|
||||
PyObject *globals = PyModule_GetDict(module); QASSERT(globals != NULL);
|
||||
PyObject *func = PyDict_GetItemString(globals, funcname);
|
||||
|
||||
if (func == NULL)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
|
||||
return false;
|
||||
}
|
||||
if (func == NULL)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
||||
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
|
||||
NULL, 0, NULL, 0, NULL);
|
||||
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
||||
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
|
||||
NULL, 0, NULL, 0, NULL);
|
||||
|
||||
ok = return_python_result(result, pres, errbuf, errbufsize);
|
||||
} while (false);
|
||||
|
||||
// free argument objects
|
||||
for (int i=0; i<nargs; i++)
|
||||
Py_XDECREF(pargs[i]);
|
||||
for (int i=0; i<nargs; i++)
|
||||
{
|
||||
if (do_decref[i])
|
||||
Py_DECREF(pargs[i]);
|
||||
}
|
||||
|
||||
return return_python_result(result, pres, errbuf, errbufsize);
|
||||
if (imported_module)
|
||||
Py_XDECREF(module);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
/* Compile callback for Python external language evaluator */
|
||||
bool idaapi IDAPython_extlang_compile_file(const char *name,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
bool idaapi IDAPython_extlang_compile_file(const char *script_path,
|
||||
char *errbuf,
|
||||
size_t errbufsize)
|
||||
{
|
||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
||||
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
|
||||
|
||||
if (!ExecFile(name))
|
||||
if (!ExecFile(script_path))
|
||||
{
|
||||
handle_python_error(errbuf, errbufsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
char modname[MAXSTR] = {0};
|
||||
parse_py_modname(script_path, modname, NULL, sizeof(modname));
|
||||
// import the module using its absolute path
|
||||
qstring s;
|
||||
s.sprnt(
|
||||
"import imp\n"
|
||||
"imp.load_source('%s', r'%s')", modname, script_path);
|
||||
PyRun_SimpleString(s.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Create an object instance */
|
||||
bool idaapi IDAPython_extlang_create_object(
|
||||
const char *name, // in: object class name
|
||||
int nargs, // in: number of input arguments
|
||||
const idc_value_t args[], // in: input arguments
|
||||
idc_value_t *result, // out: created object or exception
|
||||
char *errbuf, // out: error message if evaluation fails
|
||||
size_t errbufsize) // in: size of the error buffer
|
||||
{
|
||||
PyObject *py_mod(NULL), *py_cls(NULL), *py_args(NULL);
|
||||
bool ok = false;
|
||||
do
|
||||
{
|
||||
// Parse the object name (to get the module and class name)
|
||||
char modname[MAXSTR] = {0};
|
||||
char clsname[MAXSTR] = {0};
|
||||
parse_py_modname(name, modname, clsname, MAXSTR);
|
||||
|
||||
// Get a reference to the module
|
||||
py_mod = PyImport_ImportModule(modname);
|
||||
if (py_mod == NULL)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "Could not import module %s!", modname);
|
||||
break;
|
||||
}
|
||||
// Get the class reference
|
||||
py_cls = PyObject_GetAttrString(py_mod, clsname);
|
||||
if (py_cls == NULL)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "Could not find class %s!", clsname);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a tupple
|
||||
py_args = PyTuple_New(nargs);
|
||||
if (py_args == NULL)
|
||||
break;
|
||||
|
||||
// Store all the converted arguments in the tupple
|
||||
ok = true;
|
||||
for (int i=0;i<nargs;i++)
|
||||
{
|
||||
PyObject *arg(NULL);
|
||||
// Convert the argument
|
||||
int cvt = idcvar_to_pyvar(args[i], &arg);
|
||||
if (cvt <= 0)
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "Failed while converting argument #%d", i);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
// Opaque object?
|
||||
if (cvt == 2)
|
||||
{
|
||||
// Increment reference for opaque objects.
|
||||
// A tupple will steal references of its set items,
|
||||
// and for an opaque object we want it to still exist
|
||||
// even if the tuple is gone.
|
||||
Py_INCREF(arg);
|
||||
}
|
||||
// Save it
|
||||
// Steals the reference and that means we are no longer responsible
|
||||
// for reference management of the items.
|
||||
PyTuple_SetItem(py_args, i, arg);
|
||||
}
|
||||
|
||||
// Error during conversion?
|
||||
if (!ok)
|
||||
break;
|
||||
ok = false;
|
||||
|
||||
// Call the constructor
|
||||
PyObject *py_res = PyObject_Call(py_cls, py_args, NULL);
|
||||
|
||||
// Call failed?
|
||||
if (py_res == NULL)
|
||||
{
|
||||
// Try to get a meaningful error string
|
||||
qstring s;
|
||||
if (!PyGetError(&s))
|
||||
{
|
||||
qsnprintf(errbuf, errbufsize, "Calling the constructor failed!");
|
||||
}
|
||||
else
|
||||
{
|
||||
qstrncpy(errbuf, s.c_str(), errbufsize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
int r = pyvar_to_idcvar(py_res, result);
|
||||
ok = r > 0;
|
||||
// decrement reference only if not an opaque object
|
||||
if (r == 1)
|
||||
Py_DECREF(py_res);
|
||||
} while (false);
|
||||
|
||||
Py_XDECREF(py_mod);
|
||||
Py_XDECREF(py_cls);
|
||||
|
||||
// Free the arguments tuple
|
||||
if (py_args != NULL)
|
||||
Py_DECREF(py_args);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Returns: success
|
||||
|
||||
/* Calculator callback for Python external language evaluator */
|
||||
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
||||
const char *expr,
|
||||
@ -492,18 +685,16 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
||||
size_t errbufsize)
|
||||
{
|
||||
PyObject *result;
|
||||
PyObject *module = PyImport_AddModule("__main__");
|
||||
|
||||
if (module == NULL)
|
||||
PyObject *globals = GetMainGlobals();
|
||||
if (globals == NULL)
|
||||
return false;
|
||||
|
||||
PyObject *globals = PyModule_GetDict(module);
|
||||
|
||||
begin_execution();
|
||||
begin_execution();
|
||||
result = PyRun_String(expr, Py_eval_input, globals, globals);
|
||||
end_execution();
|
||||
end_execution();
|
||||
|
||||
VarFree(rv);
|
||||
rv->clear();
|
||||
|
||||
return return_python_result(rv, result, errbuf, errbufsize);
|
||||
}
|
||||
@ -517,25 +708,52 @@ extlang_t extlang_python =
|
||||
IDAPython_extlang_run,
|
||||
IDAPython_extlang_calcexpr,
|
||||
IDAPython_extlang_compile_file,
|
||||
"py"
|
||||
"py",
|
||||
IDAPython_extlang_create_object
|
||||
};
|
||||
|
||||
void enable_extlang_python(bool enable)
|
||||
{
|
||||
#if IDA_SDK_VERSION < 560
|
||||
#define SELECT_EXTLANG register_extlang
|
||||
#else
|
||||
#define SELECT_EXTLANG select_extlang
|
||||
#endif
|
||||
if (enable)
|
||||
register_extlang(&extlang_python);
|
||||
SELECT_EXTLANG(&extlang_python);
|
||||
else
|
||||
register_extlang(NULL);
|
||||
SELECT_EXTLANG(NULL);
|
||||
#undef SELECT_EXTLANG
|
||||
}
|
||||
|
||||
#if IDA_SDK_VERSION >= 540
|
||||
/* Execute a line in the Python CLI */
|
||||
bool idaapi IDAPython_cli_execute_line(const char *line)
|
||||
{
|
||||
begin_execution();
|
||||
PyRun_SimpleString(line);
|
||||
end_execution();
|
||||
return true;
|
||||
const char *first_line = strrchr(line, '\n');
|
||||
if (first_line == NULL)
|
||||
first_line = line;
|
||||
else
|
||||
first_line += 1;
|
||||
|
||||
// skip empty lines
|
||||
if (first_line[0] != '\0')
|
||||
{
|
||||
// take a copy of the line so we r-trim it
|
||||
char *tline = qstrdup(first_line);
|
||||
trim(tline);
|
||||
// line ends with ":" or begins with a space character?
|
||||
bool more = tline[qstrlen(tline)-1] == ':' || isspace(first_line[0]);
|
||||
qfree(tline);
|
||||
|
||||
if ( more )
|
||||
return false;
|
||||
}
|
||||
begin_execution();
|
||||
PyRun_SimpleString(line);
|
||||
end_execution();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cli_t cli_python =
|
||||
@ -560,6 +778,12 @@ void enable_python_cli(bool enable)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Prints the IDAPython copyright banner */
|
||||
void print_banner()
|
||||
{
|
||||
PyRun_SimpleString("print_banner()");
|
||||
}
|
||||
|
||||
/* Install python menu items */
|
||||
static void install_python_menus()
|
||||
{
|
||||
@ -593,22 +817,65 @@ static void install_python_menus()
|
||||
(void *)IDAPYTHON_SCRIPTBOX);
|
||||
}
|
||||
|
||||
enum script_run_when {
|
||||
run_on_db_open = 0, // run script after opening database (default)
|
||||
run_on_ui_ready = 1, // run script when UI is ready
|
||||
run_on_init = 2, // run script immediately on plugin load (shortly after IDA starts)
|
||||
};
|
||||
|
||||
static int g_run_when = -1;
|
||||
static char g_run_script[QMAXPATH];
|
||||
|
||||
/* Parse plugin options */
|
||||
void parse_options()
|
||||
{
|
||||
const char *options = get_plugin_options("IDAPython");
|
||||
if ( options == NULL )
|
||||
return;
|
||||
const char *p = strchr(options, ';');
|
||||
if ( p == NULL )
|
||||
{
|
||||
g_run_when = run_on_db_open;
|
||||
qstrncpy(g_run_script, options, sizeof(g_run_script));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_run_when = atoi(options);
|
||||
qstrncpy(g_run_script, p+1, sizeof(g_run_script));
|
||||
}
|
||||
}
|
||||
|
||||
/* we install the menu later because the text version crashes if
|
||||
add_menu_item is called too early */
|
||||
static int idaapi menu_installer_cb(void *, int code, va_list)
|
||||
{
|
||||
if ( code != ui_ready_to_run )
|
||||
return 0;
|
||||
const char *script;
|
||||
int when;
|
||||
|
||||
install_python_menus();
|
||||
unhook_from_notification_point(HT_UI, menu_installer_cb, NULL);
|
||||
switch ( code )
|
||||
{
|
||||
case ui_ready_to_run:
|
||||
print_banner();
|
||||
install_python_menus();
|
||||
|
||||
if ( g_run_when == run_on_ui_ready )
|
||||
IDAPython_RunScript(g_run_script);
|
||||
break;
|
||||
|
||||
case ui_database_inited:
|
||||
if ( g_run_when == run_on_db_open )
|
||||
IDAPython_RunScript(g_run_script);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize the Python environment */
|
||||
bool IDAPython_Init(void)
|
||||
{
|
||||
char *options;
|
||||
char tmp[MAXSTR+64];
|
||||
bool result = true;
|
||||
|
||||
@ -631,9 +898,9 @@ bool IDAPython_Init(void)
|
||||
qsnprintf(tmp, sizeof(tmp), "libpython%d.%d.so",
|
||||
PY_MAJOR_VERSION,
|
||||
PY_MINOR_VERSION);
|
||||
if (!dlopen(tmp, RTLD_NOLOAD | RTLD_GLOBAL))
|
||||
if (!dlopen(tmp, RTLD_NOLOAD | RTLD_GLOBAL | RTLD_LAZY))
|
||||
{
|
||||
warning("IDAPython: dlopen(%s) failed", tmp);
|
||||
warning("IDAPython: %s", dlerror());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@ -648,7 +915,6 @@ bool IDAPython_Init(void)
|
||||
|
||||
/* Init the SWIG wrapper */
|
||||
init_idaapi();
|
||||
|
||||
/* Set IDAPYTHON_VERSION in Python */
|
||||
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
||||
VER_MAJOR,
|
||||
@ -656,32 +922,41 @@ bool IDAPython_Init(void)
|
||||
VER_PATCH,
|
||||
VER_STATUS,
|
||||
VER_SERIAL);
|
||||
begin_execution();
|
||||
begin_execution();
|
||||
PyRun_SimpleString(tmp);
|
||||
end_execution();
|
||||
end_execution();
|
||||
|
||||
/* Pull in the Python side of init */
|
||||
qmakepath(tmp, MAXSTR, idadir(PYTHON_DIR_NAME), "init.py", NULL);
|
||||
if (!ExecFile(tmp))
|
||||
{
|
||||
warning("IDAPython: error executing init.py");
|
||||
handle_python_error(tmp, sizeof(tmp));
|
||||
warning("IDAPython: error executing init.py:\n%s", tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Init pywraps (hand made/custom wrapper) */
|
||||
if (!init_pywraps())
|
||||
{
|
||||
warning("IDAPython: init_pywraps() failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PYTHON_PROFILING
|
||||
PyEval_SetTrace(tracefunc, NULL);
|
||||
#endif
|
||||
|
||||
/* Batch-mode operation: */
|
||||
/* A script specified on the command line is run */
|
||||
options = (char *)get_plugin_options("IDAPython");
|
||||
if (options)
|
||||
IDAPython_RunScript(options);
|
||||
parse_options();
|
||||
if ( g_run_when == run_on_init )
|
||||
IDAPython_RunScript(g_run_script);
|
||||
|
||||
#ifdef PLUGINFIX
|
||||
hook_to_notification_point(HT_UI, menu_installer_cb, NULL);
|
||||
#else
|
||||
install_python_menus();
|
||||
print_banner();
|
||||
#endif
|
||||
/* Register a RunPythonStatement() function for IDC */
|
||||
set_idc_func("RunPythonStatement", idc_runpythonstatement, idc_runpythonstatement_args);
|
||||
@ -691,6 +966,10 @@ bool IDAPython_Init(void)
|
||||
enable_python_cli(true);
|
||||
#endif
|
||||
|
||||
#if IDA_SDK_VERSION >= 560
|
||||
install_extlang(&extlang_python);
|
||||
#endif
|
||||
|
||||
initialized = 1;
|
||||
|
||||
return true;
|
||||
@ -714,8 +993,14 @@ void IDAPython_Term(void)
|
||||
#endif
|
||||
|
||||
/* Remove the extlang */
|
||||
#if IDA_SDK_VERSION >= 560
|
||||
remove_extlang(&extlang_python);
|
||||
#else
|
||||
register_extlang(NULL);
|
||||
#endif
|
||||
|
||||
/* De-init pywraps */
|
||||
deinit_pywraps();
|
||||
/* Shut the interpreter down */
|
||||
Py_Finalize();
|
||||
|
||||
|
@ -438,10 +438,12 @@ def Eval(expr):
|
||||
if err:
|
||||
return "IDC_FAILURE: "+err
|
||||
else:
|
||||
if rv.vtype == '\x01': # string
|
||||
if rv.vtype == '\x01': # VT_STR
|
||||
return rv.str
|
||||
elif rv.vtype == '\x02': # long
|
||||
return rv.num
|
||||
elif rv.vtype == '\x07': # VT_STR2
|
||||
return rv.c_str()
|
||||
else:
|
||||
raise NotImplementedError, "Eval() supports only expressions returning strings or longs"
|
||||
|
||||
@ -6165,6 +6167,13 @@ def GetType(ea):
|
||||
"""
|
||||
return idaapi.idc_get_type(ea)
|
||||
|
||||
def SizeOf(typestr):
|
||||
"""
|
||||
Returns the size of the type. It is equivalent to IDC's sizeof().
|
||||
Use name, tp, fld = idc.ParseType() ; Sizeof(fld) to retrieve the size
|
||||
@return: -1 if typestring is not valid otherwise the size of the type
|
||||
"""
|
||||
return idaapi.get_type_size0(idaapi.cvar.idati, typestr)
|
||||
|
||||
def GuessType(ea):
|
||||
"""
|
||||
@ -6191,6 +6200,16 @@ def SetType(ea, newtype):
|
||||
"""
|
||||
return idaapi.apply_cdecl(ea, newtype)
|
||||
|
||||
def ParseType(inputtype, flags):
|
||||
"""
|
||||
Parse type declaration
|
||||
|
||||
@param inputtype: file name or C declarations (depending on the flags)
|
||||
@param flags: combination of PT_... constants or 0
|
||||
|
||||
@return: None on failure or (name, type, fields) tuple
|
||||
"""
|
||||
return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags)
|
||||
|
||||
def ParseTypes(inputtype, flags):
|
||||
"""
|
||||
|
@ -113,18 +113,12 @@ sys.stdout = sys.stderr = MyStdOut()
|
||||
sys.argv = [ "" ]
|
||||
|
||||
# Have to make sure Python finds our modules
|
||||
if _idaapi.idainfo_is_64bit(_idaapi.cvar.inf):
|
||||
pythonDir = "python64"
|
||||
else:
|
||||
pythonDir = "python"
|
||||
sys.path.append(_idaapi.idadir(pythonDir))
|
||||
|
||||
print_banner()
|
||||
sys.path.append(_idaapi.idadir("python"))
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Import all the required modules
|
||||
#-----------------------------------------------------------
|
||||
from idaapi import Choose, get_user_idadir, cvar, Choose2
|
||||
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall
|
||||
from idc import *
|
||||
from idautils import *
|
||||
import idaapi
|
||||
|
@ -22,8 +22,8 @@
|
||||
%ignore clrFlbits;
|
||||
%ignore get_8bit;
|
||||
%ignore get_ascii_char;
|
||||
%ignore del_typeinfo;
|
||||
%ignore del_operand_typeinfo;
|
||||
%ignore del_opinfo;
|
||||
%ignore del_one_opinfo;
|
||||
%ignore doCode;
|
||||
%ignore get_repeatable_cmt;
|
||||
%ignore get_any_indented_cmt;
|
||||
@ -72,11 +72,11 @@
|
||||
|
||||
%clear(const void *buf, size_t size);
|
||||
%clear(void *buf, ssize_t size);
|
||||
%clear(typeinfo_t *);
|
||||
%clear(opinfo_t *);
|
||||
|
||||
%rename (nextthat) py_nextthat;
|
||||
%rename (prevthat) py_prevthat;
|
||||
|
||||
|
||||
%{
|
||||
//<code(py_bytes)>
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -10,7 +10,7 @@ typedef struct
|
||||
%rename (get_manual_regions) py_get_manual_regions;
|
||||
%ignore set_manual_regions;
|
||||
%include "dbg.hpp"
|
||||
|
||||
%ignore DBG_Callback;
|
||||
%feature("director") DBG_Hooks;
|
||||
|
||||
%{
|
||||
@ -250,7 +250,7 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Swig::DirectorException &e)
|
||||
catch (Swig::DirectorException &)
|
||||
{
|
||||
msg("Exception in IDP Hook function:\n");
|
||||
if (PyErr_Occurred())
|
||||
|
@ -27,6 +27,7 @@
|
||||
%ignore qlfile;
|
||||
%ignore make_linput;
|
||||
%ignore unmake_linput;
|
||||
%ignore create_remote_linput;
|
||||
|
||||
// FIXME: These should be wrapped for completeness
|
||||
%ignore eread;
|
||||
@ -44,6 +45,7 @@
|
||||
|
||||
%{
|
||||
//<code(py_diskio)>
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi py_enumerate_files_cb(const char *file, void *ud)
|
||||
{
|
||||
PyObject *py_file = PyString_FromString(file);
|
||||
@ -72,6 +74,12 @@ private:
|
||||
OWN_FROM_FP = 3, // We got an li instance from an fp instance, we have to unmake_linput() on Close
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void _from_cobject(PyObject *pycobject)
|
||||
{
|
||||
this->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void assign(const loader_input_t &rhs)
|
||||
{
|
||||
@ -79,19 +87,30 @@ private:
|
||||
li = rhs.li;
|
||||
own = OWN_FROM_LI;
|
||||
}
|
||||
public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
loader_input_t(const loader_input_t &rhs)
|
||||
{
|
||||
assign(rhs);
|
||||
}
|
||||
|
||||
public:
|
||||
// Special attribute that tells the pyvar_to_idcvar how to convert this
|
||||
// class from and to IDC. The value of this variable must be set to two
|
||||
int __idc_cvt_id__;
|
||||
//--------------------------------------------------------------------------
|
||||
loader_input_t()
|
||||
loader_input_t(PyObject *pycobject = NULL)
|
||||
{
|
||||
li = NULL;
|
||||
own = OWN_NONE;
|
||||
fn.qclear();
|
||||
__idc_cvt_id__ = 2; // Opaque object
|
||||
if (pycobject != NULL && PyCObject_Check(pycobject))
|
||||
{
|
||||
_from_cobject(pycobject);
|
||||
}
|
||||
else
|
||||
{
|
||||
li = NULL;
|
||||
own = OWN_NONE;
|
||||
fn.qclear();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -152,7 +171,7 @@ public:
|
||||
if (!PyCObject_Check(pycobject))
|
||||
return NULL;
|
||||
loader_input_t *l = new loader_input_t();
|
||||
l->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
|
||||
l->_from_cobject(pycobject);
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -285,6 +304,12 @@ public:
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int file2base(int32 pos, ea_t ea1, ea_t ea2, int patchable)
|
||||
{
|
||||
return ::file2base(li, pos, ea1, ea2, patchable);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int32 size()
|
||||
{
|
||||
@ -308,6 +333,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback)
|
||||
{
|
||||
do
|
||||
|
@ -2,6 +2,8 @@
|
||||
%ignore funcset_t;
|
||||
%ignore extlang_t;
|
||||
%ignore extlang;
|
||||
%ignore extlangs_t;
|
||||
%ignore extlangs;
|
||||
%ignore register_extlang;
|
||||
%ignore IDCFuncs;
|
||||
%ignore set_idc_func;
|
||||
@ -28,6 +30,8 @@
|
||||
%ignore find_builtin_idc_func;
|
||||
%ignore idc_lx;
|
||||
%ignore idc_vars;
|
||||
%ignore idc_resolve_label;
|
||||
%ignore idc_resolver_ea;
|
||||
|
||||
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
||||
|
||||
@ -65,7 +69,7 @@ bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errb
|
||||
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
|
||||
}
|
||||
%}
|
||||
|
||||
|
||||
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
||||
|
||||
%rename (CompileLine) CompileLine_wrap;
|
||||
|
21
swig/fpro.i
21
swig/fpro.i
@ -7,13 +7,29 @@ private:
|
||||
bool own;
|
||||
qstring fn;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void assign(const qfile_t &rhs)
|
||||
{
|
||||
fn = rhs.fn;
|
||||
fp = rhs.fp;
|
||||
own = false;
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
bool _from_fp(FILE *fp)
|
||||
{
|
||||
if (fp == NULL)
|
||||
return false;
|
||||
own = false;
|
||||
fn.sprnt("<FILE * %p>", fp);
|
||||
fp = fp;
|
||||
return true;
|
||||
}
|
||||
inline void _from_cobject(PyObject *pycobject)
|
||||
{
|
||||
_from_fp((FILE *)PyCObject_AsVoidPtr(pycobject));
|
||||
}
|
||||
public:
|
||||
int __idc_cvt_id__;
|
||||
//--------------------------------------------------------------------------
|
||||
qfile_t(const qfile_t &rhs)
|
||||
{
|
||||
@ -21,11 +37,14 @@ public:
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
qfile_t()
|
||||
qfile_t(PyObject *pycobject = NULL)
|
||||
{
|
||||
fp = NULL;
|
||||
own = true;
|
||||
fn.qclear();
|
||||
__idc_cvt_id__ = 2; // Opaque object
|
||||
if (pycobject != NULL && PyCObject_Check(pycobject))
|
||||
_from_cobject(pycobject);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
@ -35,6 +35,7 @@
|
||||
}
|
||||
|
||||
%pythoncode %{
|
||||
#<pycode(py_gdl)>
|
||||
# -----------------------------------------------------------------------
|
||||
class BasicBlock:
|
||||
def __init__(self, id, bb, f):
|
||||
@ -96,5 +97,5 @@ class FlowChart:
|
||||
if index >= self.size:
|
||||
raise StopIteration
|
||||
return BasicBlock(index, self._q[index], self)
|
||||
|
||||
#</pycode(py_gdl)>
|
||||
%}
|
||||
|
19
swig/graph.i
19
swig/graph.i
@ -481,12 +481,6 @@ private:
|
||||
//grcode_user_draw, // render node of a user-defined graph
|
||||
return ret;
|
||||
}
|
||||
static PyObject *PyObject_TryGetAttrString(PyObject *object, const char *attr)
|
||||
{
|
||||
if (!PyObject_HasAttrString(object, attr))
|
||||
return NULL;
|
||||
return PyObject_GetAttrString(object, attr);
|
||||
}
|
||||
|
||||
void unbind()
|
||||
{
|
||||
@ -494,7 +488,9 @@ private:
|
||||
return;
|
||||
|
||||
// Unbind this object from the python object
|
||||
PyObject_SetAttrString(self, S_M_THIS, PyCObject_FromVoidPtr(NULL, NULL));
|
||||
PyObject *py_cobj = PyCObject_FromVoidPtr(NULL, NULL);
|
||||
PyObject_SetAttrString(self, S_M_THIS, py_cobj);
|
||||
Py_DECREF(py_cobj);
|
||||
Py_XDECREF(self);
|
||||
self = NULL;
|
||||
}
|
||||
@ -600,10 +596,15 @@ private:
|
||||
Py_XDECREF(attr);
|
||||
}
|
||||
|
||||
// Bind py_graph_t to python object
|
||||
|
||||
// Keep a reference
|
||||
this->self = self;
|
||||
Py_INCREF(self);
|
||||
PyObject_SetAttrString(self, S_M_THIS, PyCObject_FromVoidPtr(this, NULL));
|
||||
|
||||
// Bind py_graph_t to python object
|
||||
PyObject *py_cobj = PyCObject_FromVoidPtr(this, NULL);
|
||||
PyObject_SetAttrString(self, S_M_THIS, py_cobj);
|
||||
Py_DECREF(py_cobj);
|
||||
|
||||
// Create form
|
||||
HWND hwnd = NULL;
|
||||
|
@ -4,6 +4,9 @@
|
||||
%ignore idainfo::retrieve;
|
||||
%ignore idainfo::read;
|
||||
%ignore idainfo::write;
|
||||
%ignore idainfo::align_short_demnames;
|
||||
%ignore idainfo::align_strtype;
|
||||
%ignore idainfo::align_long_demnames;
|
||||
|
||||
%ignore setflag(uchar &where,uchar bit,int value);
|
||||
%ignore setflag(ushort &where,ushort bit,int value);
|
||||
|
806
swig/idaapi.i
806
swig/idaapi.i
@ -45,24 +45,697 @@
|
||||
#include "typeinf.hpp"
|
||||
#include "ua.hpp"
|
||||
#include "xref.hpp"
|
||||
#include "ieee.h"
|
||||
#include "err.h"
|
||||
#include "fpro.h"
|
||||
#include <map>
|
||||
#ifdef __NT__
|
||||
#include "graph.hpp"
|
||||
#endif
|
||||
|
||||
//<code(py_idaapi)>
|
||||
|
||||
#ifndef PYUL_DEFINED
|
||||
#define PYUL_DEFINED
|
||||
typedef unsigned PY_LONG_LONG pyul_t;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static const char PY_IDC_CLASS_NAME[] = "py_idc_object_class";
|
||||
static const char PY_IDC_GLOBAL_VAR_FMT[] = "__py_cvt_gvar_%d";
|
||||
static const char PY_IDCCVT_ID_ATTR[] = "__idc_cvt_id__";
|
||||
static const char PY_IDCCVT_VALUE_ATTR[] = "__idc_cvt_value__";
|
||||
static const char S_PY_IDC_OPAQUE_T[] = "py_idc_cvt_helper_t";
|
||||
|
||||
#ifndef __PYWRAPS__
|
||||
static const char S_PY_IDAAPI_MODNAME[] = "idaapi";
|
||||
#else
|
||||
static const char S_PY_IDAAPI_MODNAME[] = "__main__";
|
||||
#endif
|
||||
|
||||
#define PY_CLSID_CVT_INT64 0
|
||||
#define PY_CLSID_APPCALL_SKEL_OBJ 1
|
||||
#define PY_CLSID_CVT_BYREF 2
|
||||
#define PY_CLSID_LAST 3
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// PyIdc conversion object ids
|
||||
#define PY_ICID_INT64 0
|
||||
#define PY_ICID_BYREF 1
|
||||
#define PY_ICID_OPAQUE 2
|
||||
|
||||
static PyObject *py_cvt_helper_module = NULL;
|
||||
static bool pywraps_initialized = false;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
idc_class_t *py_idc_cvt_opaque_t = NULL;
|
||||
static const char py_idc_cvt_helper_dtor_args[] = { VT_OBJ, 0 };
|
||||
static error_t idaapi py_idc_opaque_dtor(
|
||||
idc_value_t *argv,
|
||||
idc_value_t *res)
|
||||
{
|
||||
// Get the value from the object
|
||||
idc_value_t idc_val;
|
||||
VarGetAttr(&argv[0], PY_IDCCVT_VALUE_ATTR, &idc_val);
|
||||
|
||||
// Extract the Python object reference
|
||||
PyObject *py_obj = (PyObject *)idc_val.pvoid;
|
||||
// Decrease its reference (and eventually destroy it)
|
||||
Py_DECREF(py_obj);
|
||||
return eOk;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// This function must be called on initialization
|
||||
bool init_pywraps()
|
||||
{
|
||||
if (pywraps_initialized)
|
||||
return true;
|
||||
|
||||
// Take a reference to the idaapi python module
|
||||
// (We need it to create instances of certain classes)
|
||||
if (py_cvt_helper_module == NULL)
|
||||
{
|
||||
// Take a reference to the module so we can create the needed class instances
|
||||
py_cvt_helper_module = PyImport_ImportModule(S_PY_IDAAPI_MODNAME);
|
||||
if (py_cvt_helper_module == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (py_idc_cvt_opaque_t == NULL)
|
||||
{
|
||||
// Add the class
|
||||
py_idc_cvt_opaque_t = add_idc_class(S_PY_IDC_OPAQUE_T);
|
||||
if (py_idc_cvt_opaque_t == NULL)
|
||||
return false;
|
||||
|
||||
// Form the dtor name
|
||||
char dtor_name[MAXSTR];
|
||||
qstrncpy(dtor_name, S_PY_IDC_OPAQUE_T, sizeof(dtor_name));
|
||||
qstrncat(dtor_name, ".dtor", sizeof(dtor_name));
|
||||
|
||||
// register the dtor function
|
||||
if (!set_idc_func(dtor_name, py_idc_opaque_dtor, py_idc_cvt_helper_dtor_args))
|
||||
return false;
|
||||
|
||||
// Link the dtor function to the class
|
||||
set_idc_dtor(py_idc_cvt_opaque_t, dtor_name);
|
||||
}
|
||||
pywraps_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// This function must be called on de-initialization
|
||||
void deinit_pywraps()
|
||||
{
|
||||
if (!pywraps_initialized)
|
||||
return;
|
||||
pywraps_initialized = false;
|
||||
Py_XDECREF(py_cvt_helper_module);
|
||||
py_cvt_helper_module = NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Gets a class type reference in idaapi
|
||||
// With the class type reference we can create a new instance of that type
|
||||
// This function takes a reference to the idaapi module and keeps the reference
|
||||
static PyObject *get_idaapi_class_reference(const int class_id)
|
||||
{
|
||||
if (class_id >= PY_CLSID_LAST)
|
||||
return NULL;
|
||||
|
||||
// Some class names. The array is parallel with the PY_CLSID_xxx consts
|
||||
static const char *class_names[]=
|
||||
{
|
||||
"PyIdc_cvt_int64__",
|
||||
"Appcall_object__",
|
||||
"PyIdc_cvt_refclass__"
|
||||
};
|
||||
|
||||
return PyObject_GetAttrString(py_cvt_helper_module, class_names[class_id]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Returns an attribute or NULL
|
||||
// No errors will be set if the attribute did not exist
|
||||
PyObject *PyObject_TryGetAttrString(PyObject *py_var, const char *attr)
|
||||
{
|
||||
if (!PyObject_HasAttrString(py_var, attr))
|
||||
return NULL;
|
||||
return PyObject_GetAttrString(py_var, attr);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts a Python number into an IDC value (32 or 64bits)
|
||||
// The function will first try to convert the number into a 32bit value
|
||||
// If the number does not fit then VT_INT64 will be used
|
||||
// NB: This function cannot properly detect if the Python value should be
|
||||
// converted to a VT_INT64 or not. For example: 2**32-1 = 0xffffffff which
|
||||
// can fit in a C long but Python creates a PyLong object for it.
|
||||
// And because of that we are confused as to whether to convert to 32 or 64
|
||||
bool PyGetNumber(PyObject *py_var, idc_value_t *idc_var)
|
||||
{
|
||||
if (!(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)))
|
||||
return false;
|
||||
|
||||
// Can we convert to C long?
|
||||
long l = PyInt_AsLong(py_var);
|
||||
if (!PyErr_Occurred())
|
||||
{
|
||||
idc_var->set_long(l);
|
||||
return true;
|
||||
}
|
||||
// Clear last error
|
||||
PyErr_Clear();
|
||||
// Can be fit into a C unsigned long?
|
||||
l = (long) PyLong_AsUnsignedLong(py_var);
|
||||
if (!PyErr_Occurred())
|
||||
{
|
||||
idc_var->set_long(l);
|
||||
return true;
|
||||
}
|
||||
PyErr_Clear();
|
||||
idc_var->set_int64(PyLong_AsLongLong(py_var));
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Checks if a given object is of sequence type
|
||||
bool PyIsSequenceType(PyObject *obj)
|
||||
{
|
||||
if (!PySequence_Check(obj))
|
||||
return false;
|
||||
Py_ssize_t sz = PySequence_Size(obj);
|
||||
if (sz == -1 || PyErr_Occurred() != NULL)
|
||||
{
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns the string representation of an object
|
||||
bool PyObjectToString(PyObject *obj, qstring *out)
|
||||
{
|
||||
PyObject *py_str = PyObject_Str(obj);
|
||||
if (py_str != NULL)
|
||||
{
|
||||
*out = PyString_AsString(py_str);
|
||||
Py_DECREF(py_str);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->qclear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Checks if a Python error occured and fills the out parameter with the
|
||||
// exception string
|
||||
bool PyGetError(qstring *out = NULL)
|
||||
{
|
||||
PyObject *py_err;
|
||||
if ( (py_err = PyErr_Occurred()) == NULL)
|
||||
return false;
|
||||
|
||||
PyObject *err_type, *err_value, *err_traceback;
|
||||
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||
if ( out != NULL )
|
||||
PyObjectToString(err_value, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Checks if the given py_var is a special PyIdc_cvt_helper object.
|
||||
// It does that by examining the magic attribute and returns its numeric value.
|
||||
// It returns -1 if the object is not a recognized helper object.
|
||||
// Any Python object can be treated as an cvt object if this attribute is created.
|
||||
static int get_pyidc_cvt_type(PyObject *py_var)
|
||||
{
|
||||
// Check if this our special by reference object
|
||||
PyObject *attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_ID_ATTR);
|
||||
if (attr == NULL)
|
||||
return -1;
|
||||
if (!(PyInt_Check(attr) || PyLong_Check(attr)))
|
||||
{
|
||||
Py_DECREF(attr);
|
||||
return -1;
|
||||
}
|
||||
int r = (int)PyInt_AsLong(attr);
|
||||
Py_DECREF(attr);
|
||||
return r;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Utility function to create opaque / convertible Python <-> IDC variables
|
||||
// The referred Python variable will have its reference increased
|
||||
static bool create_py_idc_opaque_obj(PyObject *py_var, idc_value_t *idc_var)
|
||||
{
|
||||
// Create an IDC object of this special helper class
|
||||
if (VarObject(idc_var, py_idc_cvt_opaque_t) != eOk)
|
||||
return false;
|
||||
|
||||
// Store the CVT id
|
||||
idc_value_t idc_val;
|
||||
idc_val.set_long(PY_ICID_OPAQUE);
|
||||
VarSetAttr(idc_var, PY_IDCCVT_ID_ATTR, &idc_val);
|
||||
|
||||
// Store the value as a PVOID referencing the given Python object
|
||||
idc_val.set_pvoid(py_var);
|
||||
VarSetAttr(idc_var, PY_IDCCVT_VALUE_ATTR, &idc_val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts a Python variable into an IDC variable
|
||||
// This function returns:
|
||||
// 0 - failure
|
||||
// 1 - success
|
||||
// 2 - success but do not decrement the reference of the py_var (used by opaque values)
|
||||
int pyvar_to_idcvar(
|
||||
PyObject *py_var,
|
||||
idc_value_t *idc_var,
|
||||
int *gvar_sn = NULL)
|
||||
{
|
||||
PyObject *attr;
|
||||
// None / NULL
|
||||
if (py_var == NULL || py_var == Py_None)
|
||||
idc_var->set_long(0);
|
||||
// Numbers?
|
||||
else if (PyGetNumber(py_var, idc_var))
|
||||
return 1;
|
||||
// String
|
||||
else if (PyString_Check(py_var))
|
||||
idc_var->_set_string(PyString_AsString(py_var), PyString_Size(py_var)+1);
|
||||
// Float
|
||||
else if (PyBool_Check(py_var))
|
||||
idc_var->set_long(py_var == Py_True ? 1 : 0);
|
||||
// Boolean
|
||||
else if (PyFloat_Check(py_var))
|
||||
{
|
||||
double dresult = PyFloat_AsDouble(py_var);
|
||||
ieee_realcvt((void *)&dresult, idc_var->e, 3);
|
||||
idc_var->vtype = VT_FLOAT;
|
||||
}
|
||||
// void*
|
||||
else if (PyCObject_Check(py_var))
|
||||
idc_var->set_pvoid(PyCObject_AsVoidPtr(py_var));
|
||||
else if (PyList_CheckExact(py_var) || PyIsSequenceType(py_var))
|
||||
{
|
||||
// Create the object
|
||||
VarObject(idc_var);
|
||||
|
||||
// Determine list size and type
|
||||
bool is_seq = !PyList_CheckExact(py_var);
|
||||
Py_ssize_t size = is_seq ? PySequence_Size(py_var) : PyList_Size(py_var);
|
||||
bool ok = true;
|
||||
qstring attr_name;
|
||||
|
||||
// Convert each item
|
||||
for (Py_ssize_t i=0;i<size;i++)
|
||||
{
|
||||
// Get the item
|
||||
PyObject *py_item = is_seq ? PySequence_GetItem(py_var, i) : PyList_GetItem(py_var, i);
|
||||
|
||||
// Convert the item into an IDC variable
|
||||
idc_value_t v;
|
||||
ok = pyvar_to_idcvar(py_item, &v, gvar_sn) > 0;
|
||||
if (ok)
|
||||
{
|
||||
// Form the attribute name
|
||||
PyObject *py_int = PyInt_FromSsize_t(i);
|
||||
ok = PyObjectToString(py_int, &attr_name);
|
||||
if (!ok)
|
||||
break;
|
||||
Py_DECREF(py_int);
|
||||
// Store the attribute
|
||||
VarSetAttr(idc_var, attr_name.c_str(), &v);
|
||||
}
|
||||
// Sequences return a new reference for GetItem()
|
||||
if (is_seq)
|
||||
Py_DECREF(py_var);
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
return ok ? 1 : 0;
|
||||
}
|
||||
// Dictionary: we convert to an IDC object
|
||||
else if (PyDict_Check(py_var))
|
||||
{
|
||||
// Create an empty IDC object
|
||||
VarObject(idc_var);
|
||||
|
||||
// Get the dict.items() list
|
||||
PyObject *py_items = PyDict_Items(py_var);
|
||||
|
||||
// Get the size of the list
|
||||
qstring key_name;
|
||||
bool ok = true;
|
||||
Py_ssize_t size = PySequence_Size(py_items);
|
||||
for (Py_ssize_t i=0;i<size;i++)
|
||||
{
|
||||
// Get item[i] -> (key, value)
|
||||
PyObject *py_item = PyList_GetItem(py_items, i);
|
||||
|
||||
// Extract key/value
|
||||
PyObject *key = PySequence_GetItem(py_item, 0);
|
||||
PyObject *val = PySequence_GetItem(py_item, 1);
|
||||
|
||||
// Get key's string representation
|
||||
PyObjectToString(key, &key_name);
|
||||
|
||||
// Convert the attribute into an IDC value
|
||||
idc_value_t v;
|
||||
ok = pyvar_to_idcvar(val, &v, gvar_sn) > 0;
|
||||
if (ok)
|
||||
{
|
||||
// Store the attribute
|
||||
VarSetAttr(idc_var, key_name.c_str(), &v);
|
||||
}
|
||||
Py_XDECREF(key);
|
||||
Py_XDECREF(val);
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
// Decrement attribute reference
|
||||
Py_DECREF(py_items);
|
||||
return ok ? 1 : 0;
|
||||
}
|
||||
// Objects:
|
||||
// - pyidc_cvt objects: int64, byref, opaque
|
||||
// - other python objects
|
||||
else
|
||||
{
|
||||
// Get the type
|
||||
int cvt_id = get_pyidc_cvt_type(py_var);
|
||||
switch (cvt_id)
|
||||
{
|
||||
//
|
||||
// INT64
|
||||
//
|
||||
case PY_ICID_INT64:
|
||||
// Get the value attribute
|
||||
attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_VALUE_ATTR);
|
||||
if (attr == NULL)
|
||||
return false;
|
||||
idc_var->set_int64(PyLong_AsLongLong(attr));
|
||||
Py_DECREF(attr);
|
||||
return 1;
|
||||
//
|
||||
// BYREF
|
||||
//
|
||||
case PY_ICID_BYREF:
|
||||
{
|
||||
// BYREF always require this parameter
|
||||
if (gvar_sn == NULL)
|
||||
return 0;
|
||||
|
||||
// Get the value attribute
|
||||
attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_VALUE_ATTR);
|
||||
if (attr == NULL)
|
||||
return 0;
|
||||
|
||||
// Create a global variable
|
||||
char buf[MAXSTR];
|
||||
qsnprintf(buf, sizeof(buf), PY_IDC_GLOBAL_VAR_FMT, *gvar_sn);
|
||||
idc_value_t *gvar = add_idc_gvar(buf);
|
||||
// Convert the python value into the IDC global variable
|
||||
bool ok = pyvar_to_idcvar(attr, gvar, gvar_sn) > 0;
|
||||
if (ok)
|
||||
{
|
||||
(*gvar_sn)++;
|
||||
// Create a reference to this global variable
|
||||
VarRef(idc_var, gvar);
|
||||
}
|
||||
Py_DECREF(attr);
|
||||
return ok ? 1 : 0;
|
||||
}
|
||||
//
|
||||
// OPAQUE
|
||||
//
|
||||
case PY_ICID_OPAQUE:
|
||||
{
|
||||
if (!create_py_idc_opaque_obj(py_var, idc_var))
|
||||
return 0;
|
||||
return 2; // do not decrement the reference
|
||||
}
|
||||
//
|
||||
// Other objects
|
||||
//
|
||||
default:
|
||||
// A normal object?
|
||||
PyObject *py_dir = PyObject_Dir(py_var);
|
||||
Py_ssize_t size = PyList_Size(py_dir);
|
||||
if (py_dir == NULL || !PyList_Check(py_dir) || size == 0)
|
||||
{
|
||||
Py_XDECREF(py_dir);
|
||||
return 0;
|
||||
}
|
||||
// Create the IDC object
|
||||
VarObject(idc_var);
|
||||
for (Py_ssize_t i=0;i<size;i++)
|
||||
{
|
||||
PyObject *item = PyList_GetItem(py_dir, i);
|
||||
const char *field_name = PyString_AsString(item);
|
||||
if (field_name == NULL)
|
||||
continue;
|
||||
size_t len = strlen(field_name);
|
||||
// skip private attributes
|
||||
if ( (len > 2 )
|
||||
&& (strncmp(field_name, "__", 2) == 0 )
|
||||
&& (strncmp(field_name+len-2, "__", 2) == 0) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
idc_value_t v;
|
||||
// Get the non-private attribute from the object
|
||||
attr = PyObject_GetAttrString(py_var, field_name);
|
||||
if (attr == NULL
|
||||
// Convert the attribute into an IDC value
|
||||
|| pyvar_to_idcvar(attr, &v, gvar_sn) <= 0)
|
||||
{
|
||||
Py_XDECREF(attr);
|
||||
return 0;
|
||||
}
|
||||
// Store the attribute
|
||||
VarSetAttr(idc_var, field_name, &v);
|
||||
// Decrement attribute reference
|
||||
Py_DECREF(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Converts an IDC variable to a Python variable
|
||||
// If py_var points to an existing object then the object will be updated
|
||||
// If py_var points to an existing immutable object then ZERO is returned
|
||||
// Return codes:
|
||||
#define CIP_FAILED -1 // Conversion error
|
||||
#define CIP_IMMUTABLE 0 // Immutable object passed. Will not update the object but no error occured
|
||||
#define CIP_OK 1 // Success
|
||||
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
|
||||
int idcvar_to_pyvar(
|
||||
const idc_value_t &idc_var,
|
||||
PyObject **py_var)
|
||||
{
|
||||
switch (idc_var.vtype)
|
||||
{
|
||||
case VT_PVOID:
|
||||
if (*py_var == NULL)
|
||||
*py_var = PyCObject_FromVoidPtr(idc_var.pvoid, NULL);
|
||||
else
|
||||
return CIP_IMMUTABLE;
|
||||
break;
|
||||
case VT_INT64:
|
||||
{
|
||||
// Recycle?
|
||||
if (*py_var != NULL)
|
||||
{
|
||||
// Recycling an int64 object?
|
||||
int t = get_pyidc_cvt_type(*py_var);
|
||||
if (t != PY_ICID_INT64)
|
||||
return CIP_IMMUTABLE; // Cannot recycle immutable object
|
||||
// Update the attribute
|
||||
PyObject_SetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64));
|
||||
return CIP_OK;
|
||||
}
|
||||
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_CVT_INT64);
|
||||
if (py_cls == NULL)
|
||||
return CIP_FAILED;
|
||||
*py_var = PyObject_CallFunctionObjArgs(py_cls, PyLong_FromLongLong(idc_var.i64), NULL);
|
||||
Py_DECREF(py_cls);
|
||||
break;
|
||||
}
|
||||
case VT_STR:
|
||||
*py_var = PyString_FromString(idc_var.str);
|
||||
break;
|
||||
case VT_STR2:
|
||||
if (*py_var == NULL)
|
||||
{
|
||||
const qstring &s = idc_var.qstr();
|
||||
*py_var = PyString_FromStringAndSize(s.begin(), s.length());
|
||||
break;
|
||||
}
|
||||
else
|
||||
return CIP_IMMUTABLE; // Cannot recycle immutable object
|
||||
case VT_LONG:
|
||||
// Cannot recycle immutable objects
|
||||
if (*py_var != NULL)
|
||||
return CIP_IMMUTABLE;
|
||||
#ifdef __EA64__
|
||||
*py_var = PyLong_FromLongLong(idc_var.num);
|
||||
#else
|
||||
*py_var = PyLong_FromLong(idc_var.num);
|
||||
#endif
|
||||
break;
|
||||
case VT_FLOAT:
|
||||
if (*py_var == NULL)
|
||||
{
|
||||
double x;
|
||||
if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 )
|
||||
INTERR();
|
||||
*py_var = PyFloat_FromDouble(x);
|
||||
break;
|
||||
}
|
||||
else
|
||||
return CIP_IMMUTABLE;
|
||||
case VT_REF:
|
||||
{
|
||||
if (*py_var == NULL)
|
||||
{
|
||||
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_CVT_BYREF);
|
||||
if (py_cls == NULL)
|
||||
return CIP_FAILED;
|
||||
// Create a byref object with None value. We populate it later
|
||||
*py_var = PyObject_CallFunctionObjArgs(py_cls, Py_None, NULL);
|
||||
Py_DECREF(py_cls);
|
||||
}
|
||||
int t = *py_var == NULL ? -1 : get_pyidc_cvt_type(*py_var);
|
||||
if (t != PY_ICID_BYREF)
|
||||
return CIP_FAILED;
|
||||
|
||||
// Dereference
|
||||
// (Since we are not using VREF_COPY flag, we can safely const_cast)
|
||||
idc_value_t *dref_v = VarDeref(const_cast<idc_value_t *>(&idc_var), VREF_LOOP);
|
||||
if (dref_v == NULL)
|
||||
return CIP_FAILED;
|
||||
|
||||
// Can we recycle the object?
|
||||
PyObject *new_py_val = PyObject_TryGetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR);
|
||||
if (new_py_val != NULL)
|
||||
{
|
||||
// Recycle
|
||||
t = idcvar_to_pyvar(*dref_v, &new_py_val);
|
||||
Py_XDECREF(new_py_val); // DECREF because of GetAttrStr
|
||||
// Success? Nothing more to be done
|
||||
if (t == CIP_OK)
|
||||
return CIP_OK;
|
||||
// Clear it so we don't recycle it
|
||||
new_py_val = NULL;
|
||||
}
|
||||
// Try to convert (not recycle)
|
||||
if (idcvar_to_pyvar(*dref_v, &new_py_val) != CIP_OK)
|
||||
return CIP_FAILED;
|
||||
// Update the attribute
|
||||
PyObject_SetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR, new_py_val);
|
||||
Py_DECREF(new_py_val);
|
||||
break;
|
||||
}
|
||||
// Can convert back into a Python object or Python dictionary
|
||||
// (Depending if py_var will be recycled and it was a dictionary)
|
||||
case VT_OBJ:
|
||||
{
|
||||
// Check if this IDC object has __cvt_id__ and the __idc_cvt_value__ fields
|
||||
idc_value_t idc_val;
|
||||
if ( VarGetAttr(&idc_var, PY_IDCCVT_ID_ATTR, &idc_val) == eOk
|
||||
&& VarGetAttr(&idc_var, PY_IDCCVT_VALUE_ATTR, &idc_val) == eOk )
|
||||
{
|
||||
// Extract the object
|
||||
*py_var = (PyObject *) idc_val.pvoid;
|
||||
return CIP_OK_NODECREF;
|
||||
}
|
||||
PyObject *obj;
|
||||
bool is_dict = false;
|
||||
// Need to create a new object?
|
||||
if (*py_var == NULL)
|
||||
{
|
||||
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_APPCALL_SKEL_OBJ);
|
||||
if (py_cls == NULL)
|
||||
return CIP_FAILED;
|
||||
obj = PyObject_CallFunctionObjArgs(py_cls, NULL);
|
||||
Py_DECREF(py_cls);
|
||||
if (obj == NULL)
|
||||
return CIP_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recycle existing variable
|
||||
obj = *py_var;
|
||||
if (PyDict_Check(obj))
|
||||
is_dict = true;
|
||||
}
|
||||
// Walk the IDC attributes and store into python
|
||||
for (const char *attr_name = VarFirstAttr(&idc_var);
|
||||
attr_name != NULL;
|
||||
attr_name=VarNextAttr(&idc_var, attr_name))
|
||||
{
|
||||
// Get the attribute
|
||||
idc_value_t v;
|
||||
VarGetAttr(&idc_var, attr_name, &v, true);
|
||||
// Convert attribute to a python value
|
||||
PyObject *py_attr(NULL);
|
||||
int cvt = idcvar_to_pyvar(v, &py_attr);
|
||||
if (cvt <= CIP_IMMUTABLE)
|
||||
{
|
||||
// Delete the object (if we created it)
|
||||
if (*py_var == NULL)
|
||||
Py_DECREF(obj);
|
||||
return CIP_FAILED;
|
||||
}
|
||||
if (is_dict)
|
||||
PyDict_SetItemString(obj, attr_name, py_attr);
|
||||
else
|
||||
PyObject_SetAttrString(obj, attr_name, py_attr);
|
||||
if (cvt == CIP_OK)
|
||||
Py_DECREF(py_attr);
|
||||
}
|
||||
*py_var = obj;
|
||||
break;
|
||||
}
|
||||
// Unhandled type
|
||||
default:
|
||||
*py_var = NULL;
|
||||
return CIP_FAILED;
|
||||
}
|
||||
return CIP_OK;
|
||||
}
|
||||
|
||||
//</code(py_idaapi)>
|
||||
%}
|
||||
|
||||
// Do not create separate wrappers for default arguments
|
||||
%feature("compactdefaultargs");
|
||||
|
||||
#ifdef __EA64__
|
||||
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFF;
|
||||
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFF;
|
||||
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFF;
|
||||
#else
|
||||
%constant ea_t BADADDR = 0xFFFFFFFF;
|
||||
%constant sel_t BADSEL = 0xFFFFFFFF;
|
||||
%constant nodeidx_t BADNODE = 0xFFFFFFFF;
|
||||
#ifdef __GNUC__
|
||||
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFll;
|
||||
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFFll;
|
||||
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFFll;
|
||||
#else // __GNUC__
|
||||
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFui64;
|
||||
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFFui64;
|
||||
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFFui64;
|
||||
#endif // __GNUC__
|
||||
#else //__EA64__
|
||||
%constant ea_t BADADDR = 0xFFFFFFFFL;
|
||||
%constant sel_t BADSEL = 0xFFFFFFFFL;
|
||||
%constant nodeidx_t BADNODE = 0xFFFFFFFFL;
|
||||
#endif
|
||||
|
||||
// Help SWIG to figure out the ulonglong type
|
||||
@ -166,3 +839,122 @@ idainfo *get_inf_structure(void)
|
||||
void enable_extlang_python(bool enable);
|
||||
void enable_python_cli(bool enable);
|
||||
}
|
||||
|
||||
%pythoncode %{
|
||||
#<pycode(py_idaapi)>
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Seek constants
|
||||
SEEK_SET = 0 # from the file start
|
||||
SEEK_CUR = 1 # from the current position
|
||||
SEEK_END = 2 # from the file end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This is a special helper object that helps detect which kind
|
||||
# of object is this python object wrapping and how to convert it
|
||||
# back and from IDC.
|
||||
# This object is characterized by its special attribute and its value
|
||||
class PyIdc_cvt_helper__(object):
|
||||
def __init__(self, cvt_id, value):
|
||||
# 0 = int64 object
|
||||
# 1 = byref object
|
||||
# 2 = opaque object
|
||||
self.__idc_cvt_id__ = cvt_id
|
||||
self.value = value
|
||||
|
||||
def __set_value(self, v):
|
||||
self.__idc_cvt_value__ = v
|
||||
def __get_value(self):
|
||||
return self.__idc_cvt_value__
|
||||
value = property(__get_value, __set_value)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class PyIdc_cvt_int64__(PyIdc_cvt_helper__):
|
||||
"""Helper class for explicitly representing VT_INT64 values"""
|
||||
def __init__(self, v):
|
||||
# id = 0 = int64 object
|
||||
super(self.__class__, self).__init__(0, v)
|
||||
|
||||
# operation table
|
||||
op_table = \
|
||||
{
|
||||
0: lambda a, b: a + b,
|
||||
1: lambda a, b: a - b,
|
||||
2: lambda a, b: a * b,
|
||||
3: lambda a, b: a / b
|
||||
}
|
||||
# carries the operation given its number
|
||||
def op(self, op_n, other, rev=False):
|
||||
a = self.value
|
||||
# other operand of same type? then take its value field
|
||||
if type(other) == type(self):
|
||||
b = other.value
|
||||
else:
|
||||
b = other
|
||||
if rev:
|
||||
t = a
|
||||
a = b
|
||||
b = t
|
||||
# construct a new object and return as the result
|
||||
return self.__class__(self.op_table[op_n](a, b))
|
||||
|
||||
# overloaded operators
|
||||
def __add__(self, other): return self.op(0, other)
|
||||
def __sub__(self, other): return self.op(1, other)
|
||||
def __mul__(self, other): return self.op(2, other)
|
||||
def __div__(self, other): return self.op(3, other)
|
||||
def __radd__(self, other): return self.op(0, other, True)
|
||||
def __rsub__(self, other): return self.op(1, other, True)
|
||||
def __rmul__(self, other): return self.op(2, other, True)
|
||||
def __rdiv__(self, other): return self.op(3, other, True)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class PyIdc_cvt_refclass__(PyIdc_cvt_helper__):
|
||||
"""Helper class for representing references to immutable objects"""
|
||||
def __init__(self, v):
|
||||
# id = one = byref object
|
||||
super(self.__class__, self).__init__(1, v)
|
||||
|
||||
def cstr(self):
|
||||
return as_cstr(self.value)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This object can be passed to IDC and back to Python transparently
|
||||
# The attribute "__idc_cvt_value__" is used
|
||||
class PyIdc_cvt_opaque__(PyIdc_cvt_helper__):
|
||||
def __init__(self, v):
|
||||
# id = two = opaque object
|
||||
super(self.__class__, self).__init__(2, v)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def as_cstr(val):
|
||||
"""
|
||||
Returns a C str from the passed value. The passed value can be of type refclass (returned by a call to buffer() or byref())
|
||||
It scans for the first \x00 and returns the string value up to that point.
|
||||
"""
|
||||
if isinstance(val, PyIdc_cvt_refclass__):
|
||||
val = val.value
|
||||
n = 0
|
||||
for x in val:
|
||||
if ord(x) == 0:
|
||||
break
|
||||
n = n + 1
|
||||
return val[:n]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def as_unicode(s):
|
||||
"""Convenience function to convert a string into appropriate unicode format"""
|
||||
# use UTF16 big/little endian, depending on the environment?
|
||||
return unicode(s).encode("UTF-16" + ("BE" if _idaapi.cvar.inf.mf else "LE"))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def as_uint32(v):
|
||||
return v & 0xffffffff
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def as_int32(v):
|
||||
return -((~v & 0xffffffff)+1)
|
||||
|
||||
#</pycode(py_idaapi)>
|
||||
|
||||
%}
|
523
swig/idd.i
523
swig/idd.i
@ -1,7 +1,7 @@
|
||||
%ignore debugger_t;
|
||||
%ignore memory_info_t;
|
||||
%ignore register_info_t;
|
||||
|
||||
%ignore appcall;
|
||||
%apply unsigned char { char dtyp };
|
||||
|
||||
%include "idd.hpp"
|
||||
@ -11,11 +11,7 @@
|
||||
%{
|
||||
//<code(py_idd)>
|
||||
|
||||
#ifndef PYUL_DEFINED
|
||||
#define PYUL_DEFINED
|
||||
typedef unsigned PY_LONG_LONG pyul_t;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool dbg_can_query()
|
||||
{
|
||||
// Reject the request only if no debugger is set
|
||||
@ -23,6 +19,7 @@ bool dbg_can_query()
|
||||
return !(dbg == NULL || (!dbg->may_disturb() && get_process_state() != DSTATE_SUSP));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
|
||||
{
|
||||
PyObject *py_list = PyList_New(areas.size());
|
||||
@ -32,19 +29,20 @@ PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
|
||||
{
|
||||
const memory_info_t &mi = *it;
|
||||
// startEA endEA name sclass sbase bitness perm
|
||||
PyList_SetItem(py_list, i,
|
||||
Py_BuildValue("(KKssKii)",
|
||||
PyList_SetItem(py_list, i,
|
||||
Py_BuildValue("(KKssKii)",
|
||||
pyul_t(mi.startEA),
|
||||
pyul_t(mi.endEA),
|
||||
mi.name.c_str(),
|
||||
mi.sclass.c_str(),
|
||||
pyul_t(mi.sbase),
|
||||
(unsigned int)(mi.bitness),
|
||||
(unsigned int)(mi.bitness),
|
||||
(unsigned int)mi.perm));
|
||||
}
|
||||
return py_list;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *dbg_get_memory_info()
|
||||
{
|
||||
if (!dbg_can_query())
|
||||
@ -59,11 +57,12 @@ PyObject *dbg_get_memory_info()
|
||||
return meminfo_vec_t_to_py(areas);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *dbg_get_registers()
|
||||
{
|
||||
if (dbg == NULL)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
|
||||
PyObject *py_list = PyList_New(dbg->registers_size);
|
||||
|
||||
for (int i=0;i<dbg->registers_size;i++)
|
||||
@ -89,11 +88,11 @@ PyObject *dbg_get_registers()
|
||||
}
|
||||
|
||||
// name flags class dtyp bit_strings bit_strings_default_mask
|
||||
PyList_SetItem(py_list, i,
|
||||
Py_BuildValue("(sIIINI)",
|
||||
ri.name,
|
||||
ri.flags,
|
||||
(unsigned int)ri.register_class,
|
||||
PyList_SetItem(py_list, i,
|
||||
Py_BuildValue("(sIIINI)",
|
||||
ri.name,
|
||||
ri.flags,
|
||||
(unsigned int)ri.register_class,
|
||||
(unsigned int)ri.dtyp,
|
||||
py_bits,
|
||||
(unsigned int)ri.bit_strings_default));
|
||||
@ -101,6 +100,7 @@ PyObject *dbg_get_registers()
|
||||
return py_list;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
|
||||
{
|
||||
if (!dbg_can_query() || !PyInt_Check(py_tid) || !PyInt_Check(py_sreg_value))
|
||||
@ -113,6 +113,7 @@ PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
|
||||
return Py_BuildValue("K", pyul_t(answer));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
||||
{
|
||||
if (!dbg_can_query() || !PyNumber_Check(py_ea) || !PyNumber_Check(py_sz))
|
||||
@ -139,6 +140,7 @@ PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
||||
{
|
||||
if (!dbg_can_query() || !PyString_Check(py_buf) || !PyNumber_Check(py_ea))
|
||||
@ -151,9 +153,145 @@ PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
||||
Py_RETURN_FALSE;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *py_appcall(
|
||||
ea_t func_ea,
|
||||
thid_t tid,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
PyObject *arg_list)
|
||||
{
|
||||
if (!PyList_Check(arg_list))
|
||||
return NULL;
|
||||
|
||||
const char *type = py_type == Py_None ? NULL : PyString_AS_STRING(py_type);
|
||||
const char *fields = py_fields == Py_None ? NULL : PyString_AS_STRING(py_fields);
|
||||
|
||||
// Convert Python arguments into IDC values
|
||||
qvector<idc_value_t> idc_args;
|
||||
int sn = 0;
|
||||
Py_ssize_t nargs = PyList_Size(arg_list);
|
||||
idc_args.resize(nargs);
|
||||
bool ok = true;
|
||||
for (Py_ssize_t i=0;i<nargs;i++)
|
||||
{
|
||||
// Get argument
|
||||
PyObject *py_item = PyList_GetItem(arg_list, i);
|
||||
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||
{
|
||||
qstring s;
|
||||
PyObjectToString(py_item, &s);
|
||||
msg("obj[%d]->%s\n", int(i), s.c_str());
|
||||
}
|
||||
// Convert it
|
||||
if (pyvar_to_idcvar(py_item, &idc_args[i], &sn) <= 0)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set exception message
|
||||
if (!ok)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed to convert Python values to IDC values");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||
{
|
||||
msg("input variables:\n"
|
||||
"----------------\n");
|
||||
qstring s;
|
||||
for (Py_ssize_t i=0;i<nargs;i++)
|
||||
{
|
||||
VarPrint(&s, &idc_args[i]);
|
||||
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
|
||||
s.qclear();
|
||||
}
|
||||
}
|
||||
// Do Appcall
|
||||
idc_value_t idc_result;
|
||||
error_t ret = appcall(
|
||||
func_ea,
|
||||
tid,
|
||||
(type_t *)type,
|
||||
(p_list *)fields,
|
||||
idc_args.size(),
|
||||
idc_args.begin(),
|
||||
&idc_result);
|
||||
|
||||
if (ret != eOk)
|
||||
{
|
||||
// An exception was thrown?
|
||||
if (ret == eExecThrow)
|
||||
{
|
||||
// Convert the result (which is a debug_event) into a Python object
|
||||
PyObject *py_appcall_exc(NULL);
|
||||
idcvar_to_pyvar(idc_result, &py_appcall_exc);
|
||||
PyErr_SetObject(PyExc_OSError, py_appcall_exc);
|
||||
Py_DECREF(py_appcall_exc);
|
||||
return NULL;
|
||||
}
|
||||
// An error in the Appcall? (or an exception but AppCallOptions/DEBEV is not set)
|
||||
else
|
||||
{
|
||||
char err_str[MAXSTR];
|
||||
qstrerror(ret, err_str, sizeof(err_str));
|
||||
PyErr_SetString(PyExc_Exception, err_str);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||
{
|
||||
msg("return variables:\n"
|
||||
"-----------------\n");
|
||||
qstring s;
|
||||
for (Py_ssize_t i=0;i<nargs;i++)
|
||||
{
|
||||
VarPrint(&s, &idc_args[i]);
|
||||
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
|
||||
s.qclear();
|
||||
}
|
||||
}
|
||||
// Convert IDC values back to Python values
|
||||
for (Py_ssize_t i=0;i<nargs;i++)
|
||||
{
|
||||
// Get argument
|
||||
PyObject *py_item = PyList_GetItem(arg_list, i);
|
||||
// We convert arguments but fail only on fatal errors
|
||||
// (we ignore failure because of immutable objects)
|
||||
if (idcvar_to_pyvar(idc_args[i], &py_item) == CIP_FAILED)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC values to Python values");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// Convert the result from IDC back to Python
|
||||
PyObject *py_result(NULL);
|
||||
if (idcvar_to_pyvar(idc_result, &py_result) <= CIP_IMMUTABLE)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC return value to Python return value");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||
{
|
||||
msg("return var:\n"
|
||||
"-----------\n");
|
||||
qstring s;
|
||||
VarPrint(&s, &idc_result);
|
||||
msg("%s\n-----------\n", s.c_str());
|
||||
}
|
||||
return py_result;
|
||||
}
|
||||
//</code(py_idd)>
|
||||
%}
|
||||
|
||||
%rename (appcall) py_appcall;
|
||||
|
||||
%inline %{
|
||||
|
||||
//<inline(py_idd)>
|
||||
@ -163,6 +301,12 @@ PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value);
|
||||
PyObject *dbg_get_registers();
|
||||
PyObject *dbg_get_memory_info();
|
||||
bool dbg_can_query();
|
||||
PyObject *py_appcall(
|
||||
ea_t func_ea,
|
||||
thid_t tid,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
PyObject *arg_list);
|
||||
//</inline(py_idd)>
|
||||
|
||||
char get_event_module_name(const debug_event_t* ev, char *buf, size_t bufsize)
|
||||
@ -213,3 +357,352 @@ bool can_exc_continue(const debug_event_t* ev)
|
||||
return ev->exc.can_cont;
|
||||
}
|
||||
%}
|
||||
|
||||
%pythoncode %{
|
||||
#<pycode(py_idd)>
|
||||
import types
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This class is used with |Appcall.array() method
|
||||
class Appcall_array__(object):
|
||||
def __init__(self, tp):
|
||||
self.__type = tp
|
||||
|
||||
def pack(self, L):
|
||||
t = type(L)
|
||||
if not (t == types.ListType or t == types.TupleType):
|
||||
raise ValueError, "Either a list or a type must be passed"
|
||||
self.__size = len(L)
|
||||
if self.__size == 1:
|
||||
self.__typedobj = Appcall__.typedobj(self.__type + ";")
|
||||
else:
|
||||
self.__typedobj = Appcall__.typedobj("%s x[%d];" % (self.__type, self.__size))
|
||||
# Now store the object in a string buffer
|
||||
ok, buf = self.__typedobj.store(L)
|
||||
if ok:
|
||||
return Appcall__.byref(buf)
|
||||
else:
|
||||
return None
|
||||
|
||||
def try_to_convert_to_list(self, obj):
|
||||
if not (hasattr(obj, "0") and hasattr(obj, str(self.__size-1))):
|
||||
return obj
|
||||
# at this point, we are sure we have an "idc list"
|
||||
# let us convert to a Python list
|
||||
return [getattr(obj, str(x)) for x in xrange(0, self.__size)]
|
||||
|
||||
def unpack(self, buf, as_list=True):
|
||||
# take the value from the special ref object
|
||||
if isinstance(buf, PyIdc_cvt_refclass__):
|
||||
buf = buf.value
|
||||
|
||||
# we can only unpack from strings
|
||||
if type(buf) != types.StringType:
|
||||
raise ValueError, "Cannot unpack this type!"
|
||||
# now unpack
|
||||
ok, obj = self.__typedobj.retrieve(buf)
|
||||
if not ok:
|
||||
raise ValueError, "Failed while unpacking!"
|
||||
if not as_list:
|
||||
return obj
|
||||
return self.try_to_convert_to_list(obj)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This class is used with the obj() method
|
||||
class Appcall_object__(object):
|
||||
"""Helper class used to initialize empty objects"""
|
||||
def __init__(self, **kwds):
|
||||
self.__dict__ = kwds
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return getattr(self, idx)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Wrapper class for the appcall()
|
||||
class Appcall_callable__(object):
|
||||
"""
|
||||
Helper class to issue appcalls using a natural syntax:
|
||||
appcall.FunctionNameInTheDatabase(arguments, ....)
|
||||
or
|
||||
appcall["Function@8"](arguments, ...)
|
||||
or
|
||||
f8 = appcall["Function@8"]
|
||||
f8(arg1, arg2, ...)
|
||||
or
|
||||
o = appcall.obj()
|
||||
i = byref(5)
|
||||
appcall.funcname(arg1, i, "hello", o)
|
||||
"""
|
||||
def __init__(self, ea, tp = None, fld = None):
|
||||
"""Initializes an appcall with a given function ea"""
|
||||
self.__ea = ea
|
||||
self.__type = tp
|
||||
self.__fields = fld
|
||||
self.__options = None # Appcall options
|
||||
|
||||
def __get_options(self):
|
||||
return self.__options if self.__options != None else Appcall__.get_appcall_options()
|
||||
def __set_options(self, v):
|
||||
self.__options = v
|
||||
"""Sets the Appcall options locally to this Appcall instance"""
|
||||
options = property(__get_options, __set_options)
|
||||
|
||||
def __call__(self, *args):
|
||||
"""Make object callable. We redirect execution to idaapi.appcall()"""
|
||||
if self.ea == None:
|
||||
raise ValueError, "Object not callable!"
|
||||
|
||||
# unpack arguments and convert to a list
|
||||
arg_list = [x for x in args]
|
||||
|
||||
# Save appcall options and set new global options
|
||||
old_opt = Appcall__.get_appcall_options()
|
||||
Appcall__.set_appcall_options(self.options)
|
||||
|
||||
# Do the Appcall (use the wrapped version)
|
||||
e_obj = None
|
||||
try:
|
||||
r = _idaapi.appcall(
|
||||
self.ea,
|
||||
_idaapi.get_current_thread(),
|
||||
self.type,
|
||||
self.fields,
|
||||
arg_list)
|
||||
except Exception, e:
|
||||
e_obj = e
|
||||
|
||||
# Restore appcall options
|
||||
Appcall__.set_appcall_options(old_opt)
|
||||
|
||||
# Return or re-raise exception
|
||||
if e_obj:
|
||||
raise Exception, e_obj
|
||||
return r
|
||||
|
||||
def __get_ea(self):
|
||||
return self.__ea
|
||||
def __set_ea(self, val):
|
||||
self.__ea = val
|
||||
"""Returns or sets the EA associated with this object"""
|
||||
ea = property(__get_ea, __set_ea)
|
||||
|
||||
def __get_size(self):
|
||||
if self.__type == None:
|
||||
return -1
|
||||
r = _idaapi.get_type_size0(_idaapi.cvar.idati, self.__type)
|
||||
if not r:
|
||||
return -1
|
||||
return r
|
||||
"""Returns the size of the type"""
|
||||
size = property(__get_size)
|
||||
|
||||
def __get_type(self):
|
||||
return self.__type
|
||||
"""Returns the typestring"""
|
||||
type = property(__get_type)
|
||||
|
||||
def __get_fields(self):
|
||||
return self.__fields
|
||||
"""Returns the typestring"""
|
||||
fields = property(__get_fields)
|
||||
|
||||
def retrieve(self, src=None, flags=0):
|
||||
"""
|
||||
Unpacks a typed object from the database if an ea is given or from a string if a string was passed
|
||||
@param src: the address of the object or a string
|
||||
@return: Returns a tuple of boolean and object or error number (Bool, Error | Object).
|
||||
"""
|
||||
|
||||
# Nothing passed? Take the address and unpack from the database
|
||||
if not src:
|
||||
src = self.ea
|
||||
|
||||
if type(src) == types.StringType:
|
||||
return _idaapi.unpack_object_from_bv(_idaapi.cvar.idati, self.type, self.fields, src, flags)
|
||||
else:
|
||||
return _idaapi.unpack_object_from_idb(_idaapi.cvar.idati, self.type, self.fields, src, flags)
|
||||
|
||||
def store(self, obj, dest_ea=None, base_ea=0, flags=0):
|
||||
"""
|
||||
Packs an object into a given ea if provided or into a string if no address was passed.
|
||||
|
||||
@return: - If packing to a string then a Tuple(Boolean, packed_string or error code)
|
||||
- If packing to the database then a return code is returned (0 is success)
|
||||
"""
|
||||
|
||||
# no ea passed? thus pack to a string
|
||||
if not dest_ea:
|
||||
return _idaapi.pack_object_to_bv(obj, _idaapi.cvar.idati, self.type, self.fields, base_ea, flags)
|
||||
else:
|
||||
return _idaapi.pack_object_to_idb(obj, _idaapi.cvar.idati, self.type, self.fields, dest_ea, flags)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class Appcall_consts__(object):
|
||||
def __init__(self, default=0):
|
||||
self.__default = default
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return Appcall__.valueof(attr, self.__default)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class Appcall__(object):
|
||||
"""
|
||||
Only set up the appcall, do not run it.
|
||||
you should call CleanupAppcall() when finished
|
||||
"""
|
||||
APPCALL_MANUAL = 0x1
|
||||
"""
|
||||
Return debug event information
|
||||
If this bit is set, exceptions during appcall
|
||||
will generate idc exceptions with full
|
||||
information about the exception
|
||||
"""
|
||||
APPCALL_DEBEV = 0x2
|
||||
|
||||
def __init__(self):
|
||||
self.__consts = Appcall_consts__()
|
||||
|
||||
def __get_consts(self):
|
||||
return self.__consts
|
||||
"""Use Appcall.Consts.CONST_NAME to access constants"""
|
||||
Consts = property(__get_consts)
|
||||
|
||||
@staticmethod
|
||||
def __name_or_ea(name_or_ea):
|
||||
"""Function that accepts a name or an ea and checks if the address is enabled.
|
||||
If a name is passed then idaapi.get_name_ea() is applied to retrieve the name
|
||||
@return: Returns the resolved EA or raises an exception if the address is not enabled
|
||||
"""
|
||||
|
||||
# a string? try to resolve it
|
||||
if type(name_or_ea) == types.StringType:
|
||||
ea = _idaapi.get_name_ea(_idaapi.BADADDR, name_or_ea)
|
||||
else:
|
||||
ea = name_or_ea
|
||||
# could not resolve name or invalid address?
|
||||
if ea == _idaapi.BADADDR or not _idaapi.isEnabled(ea):
|
||||
raise ValueError, "Undefined function " + name_or_ea
|
||||
return ea
|
||||
|
||||
@staticmethod
|
||||
def proto(name_or_ea, prototype, flags = None):
|
||||
"""Allows you to instantiate an appcall with the desired prototype"""
|
||||
|
||||
# resolve and raise exception on error
|
||||
ea = Appcall__.__name_or_ea(name_or_ea)
|
||||
# parse the type
|
||||
if not flags:
|
||||
flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP
|
||||
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags)
|
||||
if not result:
|
||||
raise ValueError, "Could not parse type: " + prototype
|
||||
# Return the callable method with type info
|
||||
return Appcall_callable__(ea, result[1], result[2])
|
||||
|
||||
def __getattr__(self, name_or_ea):
|
||||
"""Allows you to call functions as if they were member functions"""
|
||||
# resolve and raise exception on error
|
||||
ea = self.__name_or_ea(name_or_ea)
|
||||
if ea == _idaapi.BADADDR:
|
||||
raise ValueError, "Undefined function " + name
|
||||
# Return the callable method
|
||||
return Appcall_callable__(ea)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""
|
||||
Use self[func_name] syntax if the function name contains invalid characters for an attribute name
|
||||
See __getattr___
|
||||
"""
|
||||
return self.__getattr__(idx)
|
||||
|
||||
@staticmethod
|
||||
def valueof(name, default=0):
|
||||
"""
|
||||
Returns the numeric value of a given name string.
|
||||
If the name could not be resolved then the default value will be returned
|
||||
"""
|
||||
t, v = _idaapi.get_name_value(_idaapi.BADADDR, name)
|
||||
if t == 0: # NT_NONE
|
||||
v = default
|
||||
return v
|
||||
|
||||
@staticmethod
|
||||
def int64(v):
|
||||
"""Whenever a 64bit number is needed use this method to construct an object"""
|
||||
return PyIdc_cvt_int64__(v)
|
||||
|
||||
@staticmethod
|
||||
def byref(val):
|
||||
"""
|
||||
Method to create references to immutable objects
|
||||
Currently we support references to int/strings
|
||||
Objects need not be passed by reference (this will be done automatically)
|
||||
"""
|
||||
return PyIdc_cvt_refclass__(val)
|
||||
|
||||
@staticmethod
|
||||
def buffer(str = None, size = 0, fill="\x00"):
|
||||
"""
|
||||
Creates a string buffer. The returned value (r) will be a byref object.
|
||||
Use r.value to get the contents and r.size to get the buffer's size
|
||||
"""
|
||||
if not str:
|
||||
str = ""
|
||||
left = size - len(str)
|
||||
if left > 0:
|
||||
str = str + (fill * left)
|
||||
r = Appcall__.byref(str)
|
||||
r.size = size
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def obj(**kwds):
|
||||
"""Returns an empty object or objects with attributes as passed via its keywords arguments"""
|
||||
return Appcall_object__(**kwds)
|
||||
|
||||
@staticmethod
|
||||
def cstr(val):
|
||||
return as_cstr(val)
|
||||
|
||||
@staticmethod
|
||||
def unicode(s):
|
||||
return as_unicode(s)
|
||||
|
||||
@staticmethod
|
||||
def array(type_name):
|
||||
"""Defines an array type. Later you need to pack() / unpack()"""
|
||||
return Appcall_array__(type_name)
|
||||
|
||||
@staticmethod
|
||||
def typedobj(typestr, ea=None):
|
||||
"""
|
||||
Parses a type string and returns an appcall object.
|
||||
One can then use retrieve() member method
|
||||
@param ea: Optional parameter that later can be used to retrieve the type
|
||||
@return: Appcall object
|
||||
"""
|
||||
# parse the type
|
||||
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP
|
||||
if not result:
|
||||
raise ValueError, "Could not parse type: " + typestr
|
||||
# Return the callable method with type info
|
||||
return Appcall_callable__(ea, result[1], result[2])
|
||||
|
||||
@staticmethod
|
||||
def set_appcall_options(opt):
|
||||
old_opt = Appcall__.get_appcall_options()
|
||||
_idaapi.cvar.inf.appcall_options = opt
|
||||
return old_opt
|
||||
|
||||
@staticmethod
|
||||
def get_appcall_options():
|
||||
return _idaapi.cvar.inf.appcall_options
|
||||
|
||||
@staticmethod
|
||||
def cleanup_appcall(tid = 0):
|
||||
"""Equivalent to IDC's CleanupAppcall()"""
|
||||
return _idaapi.cleanup_appcall(tid)
|
||||
|
||||
Appcall = Appcall__()
|
||||
#</pycode(py_idd)>
|
||||
%}
|
@ -50,7 +50,7 @@
|
||||
%ignore processor_t::gen_stkvar_def;
|
||||
%ignore processor_t::u_outspec;
|
||||
%ignore processor_t::is_align_insn;
|
||||
|
||||
%ignore IDB_Callback;
|
||||
%ignore processor_t::idp_notify;
|
||||
%ignore processor_t::notify;
|
||||
%ignore processor_t::set_idp_options;
|
||||
@ -113,7 +113,7 @@ 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;
|
||||
/*type_t *type;*/
|
||||
/* p_list *fnames; */
|
||||
int n;
|
||||
enum_t id;
|
||||
@ -269,7 +269,7 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
||||
return proxy->segm_moved(ea, ea2, size);
|
||||
}
|
||||
}
|
||||
catch (Swig::DirectorException &e)
|
||||
catch (Swig::DirectorException &)
|
||||
{
|
||||
msg("Exception in IDP Hook function:\n");
|
||||
if (PyErr_Occurred())
|
||||
|
@ -156,14 +156,6 @@ uint32 choose_choose(PyObject *self,
|
||||
|
||||
//<code(py_choose2)>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static PyObject *PyObject_TryGetAttrString(PyObject *object, const char *attr)
|
||||
{
|
||||
if (!PyObject_HasAttrString(object, attr))
|
||||
return NULL;
|
||||
return PyObject_GetAttrString(object, attr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Some defines
|
||||
#define POPUP_NAMES_COUNT 4
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
// TODO: These could be wrapped if needed
|
||||
%ignore load_info_t;
|
||||
%ignore add_plugin_option;
|
||||
%ignore build_loaders_list;
|
||||
%ignore free_loaders_list;
|
||||
%ignore get_loader_name_from_dll;
|
||||
|
228
swig/typeinf.i
228
swig/typeinf.i
@ -10,6 +10,10 @@
|
||||
%ignore get_de;
|
||||
%ignore skip_ptr_type_header;
|
||||
%ignore skip_array_type_header;
|
||||
%ignore unpack_object_from_idb;
|
||||
%ignore unpack_object_from_bv;
|
||||
%ignore pack_object_to_idb;
|
||||
%ignore pack_object_to_bv;
|
||||
%ignore typend;
|
||||
%ignore typlen;
|
||||
%ignore typncpy;
|
||||
@ -133,22 +137,230 @@
|
||||
%ignore build_anon_type_name;
|
||||
%ignore type_names;
|
||||
%ignore get_compiler_id;
|
||||
|
||||
%ignore reloc_info_t;
|
||||
%ignore relobj_t;
|
||||
%ignore regobj_t;
|
||||
%ignore build_func_type;
|
||||
|
||||
%include "typeinf.hpp"
|
||||
|
||||
%{
|
||||
//<code(py_typeinf)>
|
||||
//-------------------------------------------------------------------------
|
||||
// Utility function to convert a python object to an IDC object
|
||||
// and sets a python exception on failure.
|
||||
static bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj)
|
||||
{
|
||||
int sn = 0;
|
||||
if (pyvar_to_idcvar(py_obj, idc_obj, &sn) <= 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Could not convert Python object to IDC object!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//</code(py_typeinf)>
|
||||
%}
|
||||
// Custom wrappers
|
||||
|
||||
%rename (load_til) load_til_wrap;
|
||||
%rename (get_type_size0) py_get_type_size0;
|
||||
%rename (unpack_object_from_idb) py_unpack_object_from_idb;
|
||||
%rename (unpack_object_from_bv) py_unpack_object_from_bv;
|
||||
%rename (pack_object_to_idb) py_pack_object_to_idb;
|
||||
%rename (pack_object_to_bv) py_pack_object_to_bv;
|
||||
%inline %{
|
||||
//<inline(py_typeinf)>
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
|
||||
{
|
||||
qtype fields, type;
|
||||
qstring name;
|
||||
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
|
||||
if (!ok)
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("(sss)",
|
||||
name.c_str(),
|
||||
(char *)type.c_str(),
|
||||
(char *)fields.c_str());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
PyObject *py_get_type_size0(const til_t *ti, PyObject *tp)
|
||||
{
|
||||
if (!PyString_Check(tp))
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "String expected!");
|
||||
return NULL;
|
||||
}
|
||||
size_t sz = get_type_size0(ti, (type_t *)PyString_AsString(tp));
|
||||
if (sz == BADSIZE)
|
||||
Py_RETURN_NONE;
|
||||
return PyInt_FromLong(sz);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Read a typed idc object from the database
|
||||
PyObject *py_unpack_object_from_idb(
|
||||
til_t *ti,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
ea_t ea,
|
||||
int pio_flags)
|
||||
{
|
||||
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Unpack
|
||||
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||
idc_value_t idc_obj;
|
||||
error_t err = unpack_object_from_idb(&idc_obj, ti, type, fields, ea, NULL, pio_flags);
|
||||
|
||||
// Unpacking failed?
|
||||
if (err != eOk)
|
||||
return Py_BuildValue("(ii)", 0, err);
|
||||
|
||||
// Convert
|
||||
PyObject *py_ret(NULL);
|
||||
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||
// Conversion failed?
|
||||
if (err != CIP_OK)
|
||||
return Py_BuildValue("(ii)", 0, err);
|
||||
return Py_BuildValue("(iO)", 1, py_ret);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Read a typed idc object from the byte vector
|
||||
PyObject *py_unpack_object_from_bv(
|
||||
til_t *ti,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
PyObject *py_bytes,
|
||||
int pio_flags)
|
||||
{
|
||||
if (!PyString_Check(py_type) && !PyString_Check(py_fields) && !PyString_Check(py_bytes))
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Incorrect argument type!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get type strings
|
||||
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||
|
||||
// Make a byte vector
|
||||
bytevec_t bytes;
|
||||
bytes.resize(PyString_Size(py_bytes));
|
||||
memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size());
|
||||
|
||||
idc_value_t idc_obj;
|
||||
error_t err = unpack_object_from_bv(&idc_obj, ti, type, fields, bytes, pio_flags);
|
||||
|
||||
// Unpacking failed?
|
||||
if (err != eOk)
|
||||
return Py_BuildValue("(ii)", 0, err);
|
||||
|
||||
// Convert
|
||||
PyObject *py_ret(NULL);
|
||||
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||
// Conversion failed?
|
||||
if (err != CIP_OK)
|
||||
return Py_BuildValue("(ii)", 0, err);
|
||||
return Py_BuildValue("(iO)", 1, py_ret);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Write a typed idc object to the database
|
||||
// Raises an exception if wrong parameters were passed or conversion fails
|
||||
// Returns the error_t returned by idasdk.pack_object_to_idb
|
||||
PyObject *py_pack_object_to_idb(
|
||||
PyObject *py_obj,
|
||||
til_t *ti,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
ea_t ea,
|
||||
int pio_flags)
|
||||
{
|
||||
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert Python object to IDC object
|
||||
idc_value_t idc_obj;
|
||||
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
|
||||
return NULL;
|
||||
|
||||
// Get type strings
|
||||
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||
|
||||
// Pack
|
||||
error_t err = pack_object_to_idb(&idc_obj, ti, type, fields, ea, pio_flags);
|
||||
return PyInt_FromLong(err);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns a tuple(Boolean, PackedBuffer or Error Code)
|
||||
PyObject *py_pack_object_to_bv(
|
||||
PyObject *py_obj,
|
||||
til_t *ti,
|
||||
PyObject *py_type,
|
||||
PyObject *py_fields,
|
||||
ea_t base_ea,
|
||||
int pio_flags=0)
|
||||
{
|
||||
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert Python object to IDC object
|
||||
idc_value_t idc_obj;
|
||||
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
|
||||
return NULL;
|
||||
|
||||
// Get type strings
|
||||
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||
|
||||
// Pack
|
||||
relobj_t bytes;
|
||||
error_t err = pack_object_to_bv(
|
||||
&idc_obj,
|
||||
ti,
|
||||
type,
|
||||
fields,
|
||||
&bytes,
|
||||
NULL,
|
||||
pio_flags);
|
||||
do
|
||||
{
|
||||
if (err != eOk)
|
||||
break;
|
||||
if (!bytes.relocate(base_ea, inf.mf))
|
||||
{
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
return Py_BuildValue("(is#)", 1, bytes.begin(), bytes.size());
|
||||
} while (false);
|
||||
return Py_BuildValue("(ii)", 0, err);
|
||||
}
|
||||
//</inline(py_typeinf)>
|
||||
til_t * load_til(const char *tildir, const char *name)
|
||||
{
|
||||
char errbuf[4096];
|
||||
til_t *res;
|
||||
|
||||
|
||||
res = load_til(tildir, name, errbuf, sizeof(errbuf));
|
||||
|
||||
|
||||
if (!res)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
||||
@ -165,9 +377,9 @@ til_t * load_til_header_wrap(const char *tildir, const char *name)
|
||||
{
|
||||
char errbuf[4096];
|
||||
til_t *res;
|
||||
|
||||
|
||||
res = load_til_header(tildir, name, errbuf, sizeof(errbuf));;
|
||||
|
||||
|
||||
if (!res)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
||||
@ -196,7 +408,7 @@ char *idc_get_type(ea_t ea, char *buf, size_t bufsize)
|
||||
{
|
||||
type_t type[MAXSTR];
|
||||
p_list fnames[MAXSTR];
|
||||
|
||||
|
||||
if (get_ti(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
||||
{
|
||||
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
||||
@ -211,7 +423,7 @@ char *idc_guess_type(ea_t ea, char *buf, size_t bufsize)
|
||||
{
|
||||
type_t type[MAXSTR];
|
||||
p_list fnames[MAXSTR];
|
||||
|
||||
|
||||
if (guess_type(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
||||
{
|
||||
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
||||
@ -234,7 +446,7 @@ int idc_set_local_type(int ordinal, const char *dcl, int flags)
|
||||
qstring name;
|
||||
qtype type;
|
||||
qtype fields;
|
||||
|
||||
|
||||
if (!parse_decl(idati, dcl, &name, &type, &fields, flags))
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user