python.cpp: Proper extlang implementation from Ilfak

python.cpp: Cleanups and fixes from Ilfak
This commit is contained in:
gergely.erdelyi 2009-01-25 16:30:05 +00:00
parent 1a45b5952a
commit 43af79132f

View File

@ -36,7 +36,7 @@ extern "C"
/* Python-style version tuple comes from the makefile */ /* Python-style version tuple comes from the makefile */
/* Only the serial and status is set here */ /* Only the serial and status is set here */
#define VER_SERIAL 0 #define VER_SERIAL 0
#define VER_STATUS "alpha" #define VER_STATUS "final"
#define IDAPYTHON_RUNFILE 0 #define IDAPYTHON_RUNFILE 0
#define IDAPYTHON_RUNSTATEMENT 1 #define IDAPYTHON_RUNSTATEMENT 1
@ -80,7 +80,7 @@ int tracefunc(PyObject *obj, _frame *frame, int what, PyObject *arg)
/* Simple Python statement runner function for IDC */ /* Simple Python statement runner function for IDC */
static const char idc_runpythonstatement_args[] = { VT_STR, 0 }; static const char idc_runpythonstatement_args[] = { VT_STR, 0 };
static error_t idaapi idc_runpythonstatement(value_t *argv, value_t *res) static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
{ {
res->num = PyRun_SimpleString(argv[0].str); res->num = PyRun_SimpleString(argv[0].str);
return eOk; return eOk;
@ -88,9 +88,9 @@ static error_t idaapi idc_runpythonstatement(value_t *argv, value_t *res)
/* QuickFix for the FILE* incompatibility problem */ /* QuickFix for the FILE* incompatibility problem */
int ExecFile(char *FileName) int ExecFile(const char *FileName)
{ {
PyObject* PyFileObject = PyFile_FromString(FileName, "r"); PyObject* PyFileObject = PyFile_FromString((char*)FileName, "r");
if (!PyFileObject) if (!PyFileObject)
{ {
@ -171,7 +171,7 @@ void IDAPython_RunScript(char *script)
slashpath[i] = '\0'; slashpath[i] = '\0';
/* Add the script't path to sys.path */ /* Add the script't path to sys.path */
snprintf(statement, sizeof(statement), "runscript(\"%s\")", slashpath); qsnprintf(statement, sizeof(statement), "runscript(\"%s\")", slashpath);
PyRun_SimpleString(statement); PyRun_SimpleString(statement);
/* Error handling */ /* Error handling */
@ -256,74 +256,46 @@ bool idaapi IDAPython_Menu_Callback(void *ud)
return true; return true;
} }
/* Compile callback for Python external language evaluator */ /* Return a formatted error or just print it to the console */
bool idaapi IDAPython_extlang_compile(const char *name, static void handle_python_error(char *errbuf, size_t errbufsize)
ea_t current_ea,
const char *expr,
char *errbuf,
size_t errbufsize)
{
qstrncpy(errbuf, "evaluation error", errbufsize);
return false;
}
/* 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)
{
qstrncpy(errbuf, "evaluation error", errbufsize);
return false;
}
/* Calculator callback for Python external language evaluator */
bool idaapi IDAPython_extlang_calcexpr(ea_t current_ea,
const char *expr,
idc_value_t *rv,
char *errbuf,
size_t errbufsize)
{ {
PyObject *result; PyObject *result;
PyObject *ptype, *pvalue, *ptraceback; PyObject *ptype, *pvalue, *ptraceback;
PyObject *module = PyImport_AddModule("__main__");
double dresult;
if (module == NULL) if ( errbufsize > 0 )
return false; errbuf[0] = '\0';
PyObject *globals = PyModule_GetDict(module); if (PyErr_Occurred())
{
result = PyRun_String(expr, Py_eval_input, globals, globals); 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();
}
}
}
/* Convert return value from Python to IDC or report about an error */
static bool return_python_result(idc_value_t *rv,
PyObject *result,
char *errbuf,
size_t errbufsize)
{
if (result == NULL) if (result == NULL)
{ {
/* Return a formatted error or just print it to the console */ handle_python_error(errbuf, errbufsize);
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();
}
}
return false; return false;
} }
VarFree(rv);
if (PyInt_Check(result)) if (PyInt_Check(result))
{ {
rv->num = PyInt_AsLong(result); rv->num = PyInt_AsLong(result);
@ -339,7 +311,7 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t current_ea,
{ {
return false; return false;
} }
strcpy(rv->str, PyString_AsString(result)); qstrncpy(rv->str, PyString_AsString(result), MAXSTR);
rv->vtype = VT_STR; rv->vtype = VT_STR;
Py_XDECREF(result); Py_XDECREF(result);
return true; return true;
@ -347,7 +319,7 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t current_ea,
if (PyFloat_Check(result)) if (PyFloat_Check(result))
{ {
dresult = PyFloat_AsDouble(result); double dresult = PyFloat_AsDouble(result);
ieee_realcvt((void *)&dresult, rv->e, 3); ieee_realcvt((void *)&dresult, rv->e, 3);
rv->vtype = VT_FLOAT; rv->vtype = VT_FLOAT;
Py_XDECREF(result); Py_XDECREF(result);
@ -357,6 +329,142 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t current_ea,
return false; return false;
} }
/* 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)
{
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
if (code == NULL)
{
handle_python_error(errbuf, errbufsize);
return false;
}
// set the desired function name
Py_XDECREF(code->co_name);
code->co_name = PyString_FromString(name);
// create a function out of code
PyObject *func = PyFunction_New((PyObject *)code, globals);
if (func == NULL)
{
ERR:
handle_python_error(errbuf, errbufsize);
Py_XDECREF(code);
return false;
}
int err = PyDict_SetItemString(globals, name, func);
if (err)
goto ERR;
return true;
}
/* 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)
{
// convert arguments to python
qvector<PyObject *> pargs;
for (int i=0; i<nargs; i++)
{
double dresult;
PyObject *pa;
switch (args[i].vtype)
{
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;
}
pargs.push_back(pa);
}
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
PyObject *func = PyDict_GetItemString(globals, name);
if (func == NULL)
{
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
return false;
}
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
NULL, 0, NULL, 0, NULL);
// free argument objects
for (int i=0; i<nargs; i++)
Py_XDECREF(pargs[i]);
return return_python_result(result, pres, errbuf, errbufsize);
}
/* Compile callback for Python external language evaluator */
bool idaapi IDAPython_extlang_compile_file(const char *name,
char *errbuf,
size_t errbufsize)
{
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
if (!ExecFile(name))
{
handle_python_error(errbuf, errbufsize);
return false;
}
return true;
}
/* Calculator callback for Python external language evaluator */
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
const char *expr,
idc_value_t *rv,
char *errbuf,
size_t errbufsize)
{
PyObject *result;
PyObject *module = PyImport_AddModule("__main__");
if (module == NULL)
return false;
PyObject *globals = PyModule_GetDict(module);
result = PyRun_String(expr, Py_eval_input, globals, globals);
VarFree(rv);
return return_python_result(rv, result, errbuf, errbufsize);
}
extlang_t extlang_python = extlang_t extlang_python =
{ {
sizeof(extlang_t), sizeof(extlang_t),
@ -364,7 +472,9 @@ extlang_t extlang_python =
"Python", "Python",
IDAPython_extlang_compile, IDAPython_extlang_compile,
IDAPython_extlang_run, IDAPython_extlang_run,
IDAPython_extlang_calcexpr IDAPython_extlang_calcexpr,
IDAPython_extlang_compile_file,
"py"
}; };
void enable_extlang_python(bool enable) void enable_extlang_python(bool enable)
@ -452,7 +562,7 @@ bool IDAPython_Init(void)
/* Init the SWIG wrapper */ /* Init the SWIG wrapper */
init_idaapi(); init_idaapi();
sprintf(tmp, "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \ qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
VER_MAJOR, VER_MAJOR,
VER_MINOR, VER_MINOR,
VER_PATCH, VER_PATCH,
@ -491,7 +601,7 @@ bool IDAPython_Init(void)
/* Add menu items for all the functions */ /* Add menu items for all the functions */
/* Different paths are used for the GUI version */ /* Different paths are used for the GUI version */
result = add_menu_item("File/IDC command...", "P~y~thon command...", add_menu_item("File/IDC command...", "P~y~thon command...",
"Alt-8", SETMENU_APP, "Alt-8", SETMENU_APP,
(menu_item_callback_t *)IDAPython_Menu_Callback, (menu_item_callback_t *)IDAPython_Menu_Callback,
(void *)IDAPYTHON_RUNSTATEMENT); (void *)IDAPYTHON_RUNSTATEMENT);