diff options
Diffstat (limited to 'lldb/bindings/python/python-typemaps.swig')
| -rw-r--r-- | lldb/bindings/python/python-typemaps.swig | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig new file mode 100644 index 000000000000..bfd7ef9007d1 --- /dev/null +++ b/lldb/bindings/python/python-typemaps.swig @@ -0,0 +1,530 @@ +/* Typemap definitions, to allow SWIG to properly handle 'char**' data types. */ + +%typemap(in) char ** { + /* Check if is a list */ + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); + int i = 0; + $1 = (char**)malloc((size+1)*sizeof(char*)); + for (i = 0; i < size; i++) { + PythonString py_str = list.GetItemAtIndex(i).AsType<PythonString>(); + if (!py_str.IsAllocated()) { + PyErr_SetString(PyExc_TypeError,"list must contain strings"); + free($1); + return nullptr; + } + + $1[i] = const_cast<char*>(py_str.GetString().data()); + } + $1[i] = 0; + } else if ($input == Py_None) { + $1 = NULL; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } +} + +%typemap(typecheck) char ** { + /* Check if is a list */ + $1 = 1; + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); + int i = 0; + for (i = 0; i < size; i++) { + PythonString s = list.GetItemAtIndex(i).AsType<PythonString>(); + if (!s.IsAllocated()) { $1 = 0; } + } + } + else + { + $1 = ( ($input == Py_None) ? 1 : 0); + } +} + +%typemap(freearg) char** { + free((char *) $1); +} + +%typemap(out) char** { + int len; + int i; + len = 0; + while ($1[len]) len++; + PythonList list(len); + for (i = 0; i < len; i++) + list.SetItemAtIndex(i, PythonString($1[i])); + $result = list.release(); +} + + +%typemap(in) lldb::tid_t { + if (PythonInteger::Check($input)) + { + PythonInteger py_int(PyRefType::Borrowed, $input); + $1 = static_cast<lldb::tid_t>(py_int.GetInteger()); + } + else + { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return nullptr; + } +} + +%typemap(in) lldb::StateType { + if (PythonInteger::Check($input)) + { + PythonInteger py_int(PyRefType::Borrowed, $input); + int64_t state_type_value = py_int.GetInteger() ; + + if (state_type_value > lldb::StateType::kLastStateType) { + PyErr_SetString(PyExc_ValueError, "Not a valid StateType value"); + return nullptr; + } + $1 = static_cast<lldb::StateType>(state_type_value); + } + else + { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return nullptr; + } +} + +/* Typemap definitions to allow SWIG to properly handle char buffer. */ + +// typemap for a char buffer +%typemap(in) (char *dst, size_t dst_len) { + if (!PyInt_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return NULL; + } + $2 = PyInt_AsLong($input); + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + return NULL; + } + $1 = (char *) malloc($2); +} +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + +// Return the char buffer. Discarding any previous return result +%typemap(argout) (char *dst, size_t dst_len) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result == 0) { + PythonString string(""); + $result = string.release(); + Py_INCREF($result); + } else { + llvm::StringRef ref(static_cast<const char*>($1), result); + PythonString string(ref); + $result = string.release(); + } + free($1); +} +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(argout) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + + +// typemap for handling an snprintf-like API like SBThread::GetStopDescription. +%typemap(in) (char *dst_or_null, size_t dst_len) { + if (!PyInt_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return NULL; + } + $2 = PyInt_AsLong($input); + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + return NULL; + } + $1 = (char *) malloc($2); +} +%typemap(argout) (char *dst_or_null, size_t dst_len) { + Py_XDECREF($result); /* Blow away any previous result */ + llvm::StringRef ref($1); + PythonString string(ref); + $result = string.release(); + free($1); +} + + +// typemap for an outgoing buffer +// See also SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len). +// Ditto for SBProcess::PutSTDIN(const char *src, size_t src_len). +%typemap(in) (const char *cstr, uint32_t cstr_len), + (const char *src, size_t src_len) { + if (PythonString::Check($input)) { + PythonString str(PyRefType::Borrowed, $input); + $1 = (char*)str.GetString().data(); + $2 = str.GetSize(); + } + else if(PythonByteArray::Check($input)) { + PythonByteArray bytearray(PyRefType::Borrowed, $input); + $1 = (char*)bytearray.GetBytes().data(); + $2 = bytearray.GetSize(); + } + else if (PythonBytes::Check($input)) { + PythonBytes bytes(PyRefType::Borrowed, $input); + $1 = (char*)bytes.GetBytes().data(); + $2 = bytes.GetSize(); + } + else { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } +} +// For SBProcess::WriteMemory, SBTarget::GetInstructions and SBDebugger::DispatchInput. +%typemap(in) (const void *buf, size_t size), + (const void *data, size_t data_len) { + if (PythonString::Check($input)) { + PythonString str(PyRefType::Borrowed, $input); + $1 = (void*)str.GetString().data(); + $2 = str.GetSize(); + } + else if(PythonByteArray::Check($input)) { + PythonByteArray bytearray(PyRefType::Borrowed, $input); + $1 = (void*)bytearray.GetBytes().data(); + $2 = bytearray.GetSize(); + } + else if (PythonBytes::Check($input)) { + PythonBytes bytes(PyRefType::Borrowed, $input); + $1 = (void*)bytes.GetBytes().data(); + $2 = bytes.GetSize(); + } + else { + PyErr_SetString(PyExc_ValueError, "Expecting a buffer"); + return NULL; + } +} + +// typemap for an incoming buffer +// See also SBProcess::ReadMemory. +%typemap(in) (void *buf, size_t size) { + if (PyInt_Check($input)) { + $2 = PyInt_AsLong($input); + } else if (PyLong_Check($input)) { + $2 = PyLong_AsLong($input); + } else { + PyErr_SetString(PyExc_ValueError, "Expecting an integer or long object"); + return NULL; + } + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + return NULL; + } + $1 = (void *) malloc($2); +} + +// Return the buffer. Discarding any previous return result +// See also SBProcess::ReadMemory. +%typemap(argout) (void *buf, size_t size) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result == 0) { + $result = Py_None; + Py_INCREF($result); + } else { + PythonBytes bytes(static_cast<const uint8_t*>($1), result); + $result = bytes.release(); + } + free($1); +} + +%{ +namespace { +template <class T> +T PyLongAsT(PyObject *obj) { + static_assert(true, "unsupported type"); +} + +template <> uint64_t PyLongAsT<uint64_t>(PyObject *obj) { + return static_cast<uint64_t>(PyLong_AsUnsignedLongLong(obj)); +} + +template <> uint32_t PyLongAsT<uint32_t>(PyObject *obj) { + return static_cast<uint32_t>(PyLong_AsUnsignedLong(obj)); +} + +template <> int64_t PyLongAsT<int64_t>(PyObject *obj) { + return static_cast<int64_t>(PyLong_AsLongLong(obj)); +} + +template <> int32_t PyLongAsT<int32_t>(PyObject *obj) { + return static_cast<int32_t>(PyLong_AsLong(obj)); +} + +template <class T> +bool SetNumberFromPyObject(T &number, PyObject *obj) { + if (PyInt_Check(obj)) + number = static_cast<T>(PyInt_AsLong(obj)); + else if (PyLong_Check(obj)) + number = PyLongAsT<T>(obj); + else return false; + + return true; +} + +template <> +bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { + if (PyFloat_Check(obj)) { + number = PyFloat_AsDouble(obj); + return true; + } + + return false; +} + +} // namespace +%} + +// these typemaps allow Python users to pass list objects +// and have them turn into C++ arrays (this is useful, for instance +// when creating SBData objects from lists of numbers) +%typemap(in) (uint64_t* array, size_t array_len), + (uint32_t* array, size_t array_len), + (int64_t* array, size_t array_len), + (int32_t* array, size_t array_len), + (double* array, size_t array_len) { + /* Check if is a list */ + if (PyList_Check($input)) { + int size = PyList_Size($input); + int i = 0; + $2 = size; + $1 = ($1_type) malloc(size * sizeof($*1_type)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input,i); + if (!SetNumberFromPyObject($1[i], o)) { + PyErr_SetString(PyExc_TypeError,"list must contain numbers"); + free($1); + return NULL; + } + + if (PyErr_Occurred()) { + free($1); + return NULL; + } + } + } else if ($input == Py_None) { + $1 = NULL; + $2 = 0; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } +} + +%typemap(freearg) (uint64_t* array, size_t array_len), + (uint32_t* array, size_t array_len), + (int64_t* array, size_t array_len), + (int32_t* array, size_t array_len), + (double* array, size_t array_len) { + free($1); +} + +// these typemaps wrap SBModule::GetVersion() from requiring a memory buffer +// to the more Pythonic style where a list is returned and no previous allocation +// is necessary - this will break if more than 50 versions are ever returned +%typemap(typecheck) (uint32_t *versions, uint32_t num_versions) { + $1 = ($input == Py_None ? 1 : 0); +} + +%typemap(in, numinputs=0) (uint32_t *versions) { + $1 = (uint32_t*)malloc(sizeof(uint32_t) * 50); +} + +%typemap(in, numinputs=0) (uint32_t num_versions) { + $1 = 50; +} + +%typemap(argout) (uint32_t *versions, uint32_t num_versions) { + uint32_t count = result; + if (count >= $2) + count = $2; + PyObject* list = PyList_New(count); + for (uint32_t j = 0; j < count; j++) + { + PyObject* item = PyInt_FromLong($1[j]); + int ok = PyList_SetItem(list,j,item); + if (ok != 0) + { + $result = Py_None; + break; + } + } + $result = list; +} + +%typemap(freearg) (uint32_t *versions) { + free($1); +} + + +// For Log::LogOutputCallback +%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) { + if (!($input == Py_None || PyCallable_Check(reinterpret_cast<PyObject*>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + return NULL; + } + + // FIXME (filcab): We can't currently check if our callback is already + // LLDBSwigPythonCallPythonLogOutputCallback (to DECREF the previous + // baton) nor can we just remove all traces of a callback, if we want to + // revert to a file logging mechanism. + + // Don't lose the callback reference + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonLogOutputCallback; + $2 = $input; +} + +%typemap(typecheck) (lldb::LogOutputCallback log_callback, void *baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject*>($input)); +} + + +%typemap(in) lldb::FileSP { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + return nullptr; + } + auto sp = unwrapOrSetPythonException(py_file.ConvertToFile()); + if (!sp) + return nullptr; + $1 = sp; +} + +%typemap(in) lldb::FileSP FORCE_IO_METHODS { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + return nullptr; + } + auto sp = unwrapOrSetPythonException(py_file.ConvertToFileForcingUseOfScriptingIOMethods()); + if (!sp) + return nullptr; + $1 = sp; +} + +%typemap(in) lldb::FileSP BORROWED { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + return nullptr; + } + auto sp = unwrapOrSetPythonException(py_file.ConvertToFile(/*borrowed=*/true)); + if (!sp) + return nullptr; + $1 = sp; +} + +%typemap(in) lldb::FileSP BORROWED_FORCE_IO_METHODS { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + return nullptr; + } + auto sp = unwrapOrSetPythonException(py_file.ConvertToFileForcingUseOfScriptingIOMethods(/*borrowed=*/true)); + if (!sp) + return nullptr; + $1 = sp; +} + +%typecheck(SWIG_TYPECHECK_POINTER) lldb::FileSP { + if (PythonFile::Check($input)) { + $1 = 1; + } else { + PyErr_Clear(); + $1 = 0; + } +} + +%typemap(out) lldb::FileSP { + $result = nullptr; + lldb::FileSP &sp = $1; + if (sp) { + PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp)); + if (!pyfile.IsValid()) + return nullptr; + $result = pyfile.release(); + } + if (!$result) + { + $result = Py_None; + Py_INCREF(Py_None); + } +} + +%typemap(in) (const char* string, int len) { + if ($input == Py_None) + { + $1 = NULL; + $2 = 0; + } + else if (PythonString::Check($input)) + { + PythonString py_str(PyRefType::Borrowed, $input); + llvm::StringRef str = py_str.GetString(); + $1 = const_cast<char*>(str.data()); + $2 = str.size(); + // In Python 2, if $input is a PyUnicode object then this + // will trigger a Unicode -> String conversion, in which + // case the `PythonString` will now own the PyString. Thus + // if it goes out of scope, the data will be deleted. The + // only way to avoid this is to leak the Python object in + // that case. Note that if there was no conversion, then + // releasing the string will not leak anything, since we + // created this as a borrowed reference. + py_str.release(); + } + else + { + PyErr_SetString(PyExc_TypeError,"not a string-like object"); + return NULL; + } +} + +// These two pybuffer macros are copied out of swig/Lib/python/pybuffer.i, +// and fixed so they will not crash if PyObject_GetBuffer fails. +// https://github.com/swig/swig/issues/1640 + +%define %pybuffer_mutable_binary(TYPEMAP, SIZE) +%typemap(in) (TYPEMAP, SIZE) { + int res; Py_ssize_t size = 0; void *buf = 0; + Py_buffer view; + res = PyObject_GetBuffer($input, &view, PyBUF_WRITABLE); + if (res < 0) { + PyErr_Clear(); + %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); + } + size = view.len; + buf = view.buf; + PyBuffer_Release(&view); + $1 = ($1_ltype) buf; + $2 = ($2_ltype) (size/sizeof($*1_type)); +} +%enddef + +%define %pybuffer_binary(TYPEMAP, SIZE) +%typemap(in) (TYPEMAP, SIZE) { + int res; Py_ssize_t size = 0; const void *buf = 0; + Py_buffer view; + res = PyObject_GetBuffer($input, &view, PyBUF_CONTIG_RO); + if (res < 0) { + PyErr_Clear(); + %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); + } + size = view.len; + buf = view.buf; + PyBuffer_Release(&view); + $1 = ($1_ltype) buf; + $2 = ($2_ltype) (size / sizeof($*1_type)); +} +%enddef + +%pybuffer_binary(const uint8_t *buf, size_t num_bytes); +%pybuffer_mutable_binary(uint8_t *buf, size_t num_bytes); |
