Hi, On 8/7/19 9:14 AM, Balamuruhan S wrote: > Adds scripting interface with python library to call functions in > python modules from Qemu that can be used to feed input externally > and without recompiling Qemu that can be used for early development, > testing and can be extended to abstract some of Qemu code out to a > python script to ease maintenance. > > Signed-off-by: Balamuruhan S <bal...@linux.ibm.com> > --- > configure | 10 +++++ > include/sysemu/python_api.h | 30 +++++++++++++ > util/Makefile.objs | 1 + > util/python_api.c | 100 > ++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 141 insertions(+) > create mode 100644 include/sysemu/python_api.h > create mode 100644 util/python_api.c > > diff --git a/configure b/configure > index 714e7fb6a1..fddddcc879 100755 > --- a/configure > +++ b/configure > @@ -1866,6 +1866,11 @@ fi > # Preserve python version since some functionality is dependent on it > python_version=$($python -V 2>&1 | sed -e 's/Python\ //') > > +# Python config to be used for CFLAGS and LDFLAGS > +if ! [ -z "$python" ]; then > + python_config="$python-config" > +fi > + > # Suppress writing compiled files > python="$python -B" > > @@ -6304,6 +6309,11 @@ echo_version() { > fi > } > > +if ! [ -z "$python_config" ]; then > + QEMU_CFLAGS="$QEMU_CFLAGS $($python_config --includes)" > + QEMU_LDFLAGS="$QEMU_LDFLAGS $($python_config --ldflags)" > +fi > + > # prepend pixman and ftd flags after all config tests are done > QEMU_CFLAGS="$pixman_cflags $fdt_cflags $QEMU_CFLAGS" > QEMU_LDFLAGS="$fdt_ldflags $QEMU_LDFLAGS" > diff --git a/include/sysemu/python_api.h b/include/sysemu/python_api.h > new file mode 100644 > index 0000000000..ff02d58377 > --- /dev/null > +++ b/include/sysemu/python_api.h > @@ -0,0 +1,30 @@ > +#ifndef _PPC_PNV_PYTHON_H > +#define _PPC_PNV_PYTHON_H > + > +#include <stdbool.h> > +#include <Python.h> > + > +extern PyObject *python_callback(const char *abs_module_path, const char > *mod, > + const char *func, char *args[], > + const int nargs); > + > +extern uint64_t python_callback_int(const char *abs_module_path, > + const char *mod, > + const char *func, char *args[], > + const int nargs); > + > +extern char *python_callback_str(const char *abs_module_path, const char > *mod, > + const char *func, char *args[], > + const int nargs); > + > +extern bool python_callback_bool(const char *abs_module_path, const char > *mod, > + const char *func, char *args[], > + const int nargs); > + > +extern void python_args_init_cast_int(char *args[], int arg, int pos); > + > +extern void python_args_init_cast_long(char *args[], uint64_t arg, int pos); > + > +extern void python_args_clean(char *args[], int nargs); > + > +#endif > diff --git a/util/Makefile.objs b/util/Makefile.objs > index 41bf59d127..05851c94a7 100644 > --- a/util/Makefile.objs > +++ b/util/Makefile.objs > @@ -50,6 +50,7 @@ util-obj-y += range.o > util-obj-y += stats64.o > util-obj-y += systemd.o > util-obj-y += iova-tree.o > +util-obj-y += python_api.o
This is probably conditional to having python-dev (or whatever distribs call the package) installed. > util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o > util-obj-$(CONFIG_LINUX) += vfio-helpers.o > util-obj-$(CONFIG_POSIX) += drm.o > diff --git a/util/python_api.c b/util/python_api.c > new file mode 100644 > index 0000000000..854187e00f > --- /dev/null > +++ b/util/python_api.c > @@ -0,0 +1,100 @@ > +#include "sysemu/python_api.h" > +#include "qemu/osdep.h" > + > +PyObject *python_callback(const char *abs_module_path, const char *mod, > + const char *func, char *args[], const int nargs) > +{ > + PyObject *mod_name, *module, *mod_ref, *function, *arguments; > + PyObject *result = 0; > + PyObject *value = NULL; > + > + /* Set PYTHONPATH to absolute module path directory */ > + if (!abs_module_path) > + abs_module_path = "."; > + setenv("PYTHONPATH", abs_module_path, 1); > + > + /* Initialize the Python Interpreter */ > + Py_Initialize(); > + mod_name = PyUnicode_FromString(mod); > + /* Import module object */ > + module = PyImport_Import(mod_name); > + if (!module) { > + PyErr_Print(); > + fprintf(stderr, "Failed to load \"%s\"\n", mod); > + exit(EXIT_FAILURE); > + } > + mod_ref = PyModule_GetDict(module); > + function = PyDict_GetItemString(mod_ref, func); > + if (function && PyCallable_Check(function)) { > + arguments = PyTuple_New(nargs); > + for (int i = 0; i < nargs; i++) { > + value = PyUnicode_FromString(args[i]); > + if (!value) { > + Py_DECREF(arguments); > + Py_DECREF(module); > + fprintf(stderr, "Cannot convert argument\n"); > + exit(EXIT_FAILURE); > + } > + PyTuple_SetItem(arguments, i, value); > + } > + PyErr_Print(); > + result = PyObject_CallObject(function, arguments); > + PyErr_Print(); > + } > + else { > + if (PyErr_Occurred()) > + PyErr_Print(); > + fprintf(stderr, "Cannot find function \"%s\"\n", func); > + exit(EXIT_FAILURE); > + } > + /* Clean up */ > + Py_DECREF(value); > + Py_DECREF(module); > + Py_DECREF(mod_name); > + /* Finish the Python Interpreter */ > + Py_Finalize(); > + return result; > +} > + > +uint64_t python_callback_int(const char *abs_module_path, const char *mod, > + const char *func, char *args[], const int nargs) > +{ > + PyObject *result; > + result = python_callback(abs_module_path, mod, func, args, nargs); > + return PyLong_AsLong(result); > +} > + > +char *python_callback_str(const char *abs_module_path, const char *mod, > + const char *func, char *args[], const int nargs) > +{ > + PyObject *result; > + result = python_callback(abs_module_path, mod, func, args, nargs); > + return PyUnicode_AsUTF8(result); > +} > + > +bool python_callback_bool(const char *abs_module_path, const char *mod, > + const char *func, char *args[], const int nargs) > +{ > + PyObject *result; > + result = python_callback(abs_module_path, mod, func, args, nargs); > + return (result == Py_True); > +} > + > +void python_args_init_cast_int(char *args[], int arg, int pos) > +{ > + args[pos]= malloc(sizeof(int)); > + sprintf(args[pos], "%d", arg); > +} > + > +void python_args_init_cast_long(char *args[], uint64_t arg, int pos) > +{ > + args[pos]= g_malloc(sizeof(uint64_t) * 2); > + sprintf(args[pos], "%lx", arg); > +} > + > +void python_args_clean(char *args[], int nargs) > +{ > + for (int i = 0; i < nargs; i++) { > + g_free(args[i]); > + } > +} > Wondering about security, is this feature safe to enable in production environment? It seems to bypass all the hard effort to harden QEMU security.