Skip to content

Commit 4f3a47c

Browse files
committed
[lldb] Add alternative SBThread::GetStopDescription
the function signature for `GetStopDescription` is `lldb::SBThread::GetStopDescription(char *dst_or_null, size_t len)` to get a description you need to call the function first time to get the buffer size. and again to get the description. This is little worse from the python size as the signature is `lldb.SBThread.GetStopDescription(int: len) -> list[str]` the user has to pass the max size as possible with no way of checking if it is enough. This patch adds a new api `lldb.SBThread.GetStopDescription(desc: lldb.SBStream()) -> bool` `bool lldb::SBThread::GetStopDescription(lldb::SBStream &description)` which handles this case.
1 parent 5142707 commit 4f3a47c

File tree

8 files changed

+84
-7
lines changed

8 files changed

+84
-7
lines changed

lldb/bindings/lua/lua-typemaps.swig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,16 @@ LLDB_NUMBER_TYPEMAP(enum SWIGTYPE);
121121
$1 = (char *)malloc($2);
122122
}
123123

124+
// Remove the default type check for this match.
125+
// because if the match function has an overload and a typemap,
126+
// it will typecheck against the original function instead of the
127+
// typemap.
128+
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) (char *dst_or_null, size_t dst_len) ""
129+
124130
%typemap(argout) (char *dst_or_null, size_t dst_len) {
125131
lua_pop(L, 1); // Blow away the previous result
126-
lua_pushlstring(L, (const char *)$1, $result);
132+
llvm::StringRef ref($1);
133+
lua_pushlstring(L, (const char *)$1, ref.size());
127134
free($1);
128135
// SWIG_arg was already incremented
129136
}

lldb/bindings/python/python-typemaps.swig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ AND call SWIG_fail at the same time, because it will result in a double free.
224224
}
225225
$1 = (char *)malloc($2);
226226
}
227+
228+
// Remove the default type check for this match.
229+
// because if the match function has an overload and a typemap,
230+
// it will typecheck against the original function instead of the
231+
// typemap.
232+
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) (char *dst_or_null, size_t dst_len) ""
233+
227234
%typemap(argout) (char *dst_or_null, size_t dst_len) {
228235
Py_XDECREF($result); /* Blow away any previous result */
229236
llvm::StringRef ref($1);

lldb/include/lldb/API/SBThread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ class LLDB_API SBThread {
8181
SBThreadCollection
8282
GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type);
8383

84+
/// Gets a human-readable description of why the thread stopped.
85+
///
86+
/// \param stream Output stream to receive the stop description text
87+
/// \return
88+
/// true if obtained and written to the stream,
89+
// false if there was an error retrieving the description.
90+
bool GetStopDescription(lldb::SBStream &stream) const;
91+
8492
size_t GetStopDescription(char *dst_or_null, size_t dst_len);
8593

8694
SBValue GetStopReturnValue();

lldb/source/API/SBThread.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,34 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
239239
return threads;
240240
}
241241

242-
size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
243-
LLDB_INSTRUMENT_VA(this, dst, dst_len);
242+
bool SBThread::GetStopDescription(lldb::SBStream &stream) const {
243+
LLDB_INSTRUMENT_VA(this, stream);
244+
245+
if (!m_opaque_sp)
246+
return false;
247+
248+
llvm::Expected<StoppedExecutionContext> exe_ctx =
249+
GetStoppedExecutionContext(m_opaque_sp);
250+
if (!exe_ctx) {
251+
LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
252+
return false;
253+
}
254+
255+
if (!exe_ctx->HasThreadScope())
256+
return false;
257+
258+
Stream &strm = stream.ref();
259+
const std::string stop_desc = exe_ctx->GetThreadPtr()->GetStopDescription();
260+
strm.PutCString(stop_desc);
261+
262+
return true;
263+
}
264+
265+
size_t SBThread::GetStopDescription(char *dst_or_null, size_t dst_len) {
266+
LLDB_INSTRUMENT_VA(this, dst_or_null, dst_len);
244267

245-
if (dst)
246-
*dst = 0;
268+
if (dst_or_null)
269+
*dst_or_null = 0;
247270

248271
llvm::Expected<StoppedExecutionContext> exe_ctx =
249272
GetStoppedExecutionContext(m_opaque_sp);
@@ -259,8 +282,8 @@ size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
259282
if (thread_stop_desc.empty())
260283
return 0;
261284

262-
if (dst)
263-
return ::snprintf(dst, dst_len, "%s", thread_stop_desc.c_str()) + 1;
285+
if (dst_or_null)
286+
return ::snprintf(dst_or_null, dst_len, "%s", thread_stop_desc.c_str()) + 1;
264287

265288
// NULL dst passed in, return the length needed to contain the
266289
// description.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
_T = require('lua_lldb_test').create_test('TestThreadAPI')
2+
3+
function _T:TestGetStopDescription()
4+
local target = self:create_target()
5+
local breakpoint = target:BreakpointCreateByName("main", "a.out")
6+
assertTrue(breakpoint:IsValid() and breakpoint:GetNumLocations() == 1)
7+
8+
local process = target:LaunchSimple({ 'arg1', 'arg2' }, nil, nil)
9+
local thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
10+
assertNotNil(thread)
11+
assertTrue(thread:IsValid())
12+
13+
assertEqual("breakpoint", thread:GetStopDescription(string.len("breakpoint") + 1))
14+
assertEqual("break", thread:GetStopDescription(string.len("break") + 1))
15+
assertEqual("b", thread:GetStopDescription(string.len("b") + 1))
16+
assertEqual("breakpoint 1.1", thread:GetStopDescription(string.len("breakpoint 1.1") + 100))
17+
18+
-- Test stream variation
19+
local stream = lldb.SBStream()
20+
assertTrue(thread:GetStopDescription(stream))
21+
assertNotNil(stream)
22+
assertEqual("breakpoint 1.1", stream:GetData())
23+
end
24+
25+
os.exit(_T:run())

lldb/test/API/python_api/default-constructor/sb_thread.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def fuzz_obj(obj):
1010
obj.GetStopReasonDataCount()
1111
obj.GetStopReasonDataAtIndex(100)
1212
obj.GetStopDescription(256)
13+
obj.GetStopDescription(lldb.SBStream())
1314
obj.GetThreadID()
1415
obj.GetIndexID()
1516
obj.GetName()

lldb/test/API/python_api/thread/TestThreadAPI.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ def get_stop_description(self):
138138
"breakpoint 1.1", thread.GetStopDescription(len("breakpoint 1.1") + 100)
139139
)
140140

141+
# Test the stream variation
142+
stream = lldb.SBStream()
143+
self.assertTrue(thread.GetStopDescription(stream))
144+
self.assertEqual("breakpoint 1.1", stream.GetData())
145+
141146
def step_out_of_malloc_into_function_b(self, exe_name):
142147
"""Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
143148
exe = self.getBuildArtifact(exe_name)

lldb/tools/lldb-rpc-gen/RPCCommon.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = {
118118
"_ZN4lldb8SBTarget15GetInstructionsEyPKvm",
119119
"_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm",
120120
"_ZN4lldb8SBThread18GetStopDescriptionEPcm",
121+
"_ZNK4lldb8SBThread18GetStopDescriptionERNS_8SBStreamE",
121122
// The below mangled names are used for dummy methods in shell tests
122123
// that test the emitters' output. If you're adding any new mangled names
123124
// from the actual SB API to this list please add them above.

0 commit comments

Comments
 (0)