diff --git a/lldb/bindings/interface/SBThread.i b/lldb/bindings/interface/SBThread.i --- a/lldb/bindings/interface/SBThread.i +++ b/lldb/bindings/interface/SBThread.i @@ -127,7 +127,7 @@ Pass only an (int)length and expect to get a Python string describing the stop reason.") GetStopDescription; size_t - GetStopDescription (char *dst, size_t dst_len); + GetStopDescription (char *dst_or_null, size_t dst_len); SBValue GetStopReturnValue (); diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig --- a/lldb/bindings/python/python-typemaps.swig +++ b/lldb/bindings/python/python-typemaps.swig @@ -95,7 +95,6 @@ /* Typemap definitions to allow SWIG to properly handle char buffer. */ // typemap for a char buffer -// See also SBThread::GetStopDescription. %typemap(in) (char *dst, size_t dst_len) { if (!PyInt_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expecting an integer"); @@ -113,7 +112,6 @@ %typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len); // Return the char buffer. Discarding any previous return result -// See also SBThread::GetStopDescription. %typemap(argout) (char *dst, size_t dst_len) { Py_XDECREF($result); /* Blow away any previous result */ if (result == 0) { @@ -132,6 +130,28 @@ %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). diff --git a/lldb/packages/Python/lldbsuite/test/python_api/thread/TestThreadAPI.py b/lldb/packages/Python/lldbsuite/test/python_api/thread/TestThreadAPI.py --- a/lldb/packages/Python/lldbsuite/test/python_api/thread/TestThreadAPI.py +++ b/lldb/packages/Python/lldbsuite/test/python_api/thread/TestThreadAPI.py @@ -122,14 +122,20 @@ self.assertTrue( thread.IsValid(), "There should be a thread stopped due to breakpoint") - #self.runCmd("process status") - - # Due to the typemap magic (see lldb.swig), we pass in an (int)length to GetStopDescription - # and expect to get a Python string as the return object! - # The 100 is just an arbitrary number specifying the buffer size. - stop_description = thread.GetStopDescription(100) - self.expect(stop_description, exe=False, - startstr='breakpoint') + + # Get the stop reason. GetStopDescription expects that we pass in the size of the description + # we expect plus an additional byte for the null terminator. + + # Test with a buffer that is exactly as large as the expected stop reason. + self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 1)) + + # Test some smaller buffer sizes. + self.assertEqual("breakpoint", thread.GetStopDescription(len('breakpoint') + 1)) + self.assertEqual("break", thread.GetStopDescription(len('break') + 1)) + self.assertEqual("b", thread.GetStopDescription(len('b') + 1)) + + # Test that we can pass in a much larger size and still get the right output. + self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 100)) def step_out_of_malloc_into_function_b(self, exe_name): """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""