/* 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(); if (!py_str.IsAllocated()) { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); return nullptr; } $1[i] = const_cast(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(); 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 { PythonObject obj = Retain($input); lldb::tid_t value = unwrapOrSetPythonException(As(obj)); if (PyErr_Occurred()) return nullptr; $1 = value; } %typemap(in) lldb::StateType { PythonObject obj = Retain($input); unsigned long long state_type_value = unwrapOrSetPythonException(As(obj)); if (PyErr_Occurred()) return nullptr; if (state_type_value > lldb::StateType::kLastStateType) { PyErr_SetString(PyExc_ValueError, "Not a valid StateType value"); return nullptr; } $1 = static_cast(state_type_value); } /* 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($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($1), result); $result = bytes.release(); } free($1); } %{ namespace { template T PyLongAsT(PyObject *obj) { static_assert(true, "unsupported type"); } template <> uint64_t PyLongAsT(PyObject *obj) { return static_cast(PyLong_AsUnsignedLongLong(obj)); } template <> uint32_t PyLongAsT(PyObject *obj) { return static_cast(PyLong_AsUnsignedLong(obj)); } template <> int64_t PyLongAsT(PyObject *obj) { return static_cast(PyLong_AsLongLong(obj)); } template <> int32_t PyLongAsT(PyObject *obj) { return static_cast(PyLong_AsLong(obj)); } template bool SetNumberFromPyObject(T &number, PyObject *obj) { if (PyInt_Check(obj)) number = static_cast(PyInt_AsLong(obj)); else if (PyLong_Check(obj)) number = PyLongAsT(obj); else return false; return true; } template <> bool SetNumberFromPyObject(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($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($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(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; } } %inline %{ struct Py_buffer_RAII { Py_buffer buffer = {}; Py_buffer_RAII() {}; Py_buffer &operator=(const Py_buffer_RAII &) = delete; Py_buffer_RAII(const Py_buffer_RAII &) = delete; ~Py_buffer_RAII() { if (buffer.obj) PyBuffer_Release(&buffer); } }; %} // 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 // // I've also moved the call to PyBuffer_Release to the end of the SWIG wrapper, // doing it right away is not legal according to the python buffer protocol. %define %pybuffer_mutable_binary(TYPEMAP, SIZE) %typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) { int res; Py_ssize_t size = 0; void *buf = 0; res = PyObject_GetBuffer($input, &view.buffer, PyBUF_WRITABLE); if (res < 0) { PyErr_Clear(); %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); } size = view.buffer.len; buf = view.buffer.buf; $1 = ($1_ltype) buf; $2 = ($2_ltype) (size/sizeof($*1_type)); } %enddef %define %pybuffer_binary(TYPEMAP, SIZE) %typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) { int res; Py_ssize_t size = 0; const void *buf = 0; res = PyObject_GetBuffer($input, &view.buffer, PyBUF_CONTIG_RO); if (res < 0) { PyErr_Clear(); %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); } size = view.buffer.len; buf = view.buffer.buf; $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);