aboutsummaryrefslogtreecommitdiff
path: root/lldb/bindings/python/python-typemaps.swig
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/bindings/python/python-typemaps.swig')
-rw-r--r--lldb/bindings/python/python-typemaps.swig530
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);