Skip to content

Commit 03a6b85

Browse files
committed
[lldb/Target] Add Assert StackFrame Recognizer
When a thread stops, this checks depending on the platform if the top frame is an abort stack frame. If so, it looks for an assert stack frame in the upper frames and set it as the most relavant frame when found. To do so, the StackFrameRecognizer class holds a "Most Relevant Frame" and a "cooked" stop reason description. When the thread is about to stop, it checks if the current frame is recognized, and if so, it fetches the recognized frame's attributes and applies them. rdar://58528686 Differential Revision: https://reviews.llvm.org/D73303 Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
1 parent 7f93ff5 commit 03a6b85

File tree

17 files changed

+380
-21
lines changed

17 files changed

+380
-21
lines changed

lldb/docs/use/formatting.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ A complete list of currently supported format string variables is listed below:
134134
+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
135135
| ``thread.queue`` | The queue name of the thread if the target OS supports dispatch queues |
136136
+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
137-
| ``thread.stop-reason`` | A textual reason each thread stopped |
137+
| ``thread.stop-reason`` | A textual reason why the thread stopped. If the thread have a recognized frame, this displays its recognized stop reason. Otherwise, gets the stop info description. |
138+
+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
139+
| ``thread.stop-reason-raw`` | A textual reason why the thread stopped. Always returns stop info description. |
138140
+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
139141
| ``thread.return-value`` | The return value of the latest step operation (currently only for step-out.) |
140142
+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

lldb/include/lldb/Core/FormatEntity.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class FormatEntity {
6161
ThreadName,
6262
ThreadQueue,
6363
ThreadStopReason,
64+
ThreadStopReasonRaw,
6465
ThreadReturnValue,
6566
ThreadCompletedExpression,
6667
ScriptThread,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===-- AssertFrameRecognizer.cpp -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef liblldb_AssertFrameRecognizer_h_
10+
#define liblldb_AssertFrameRecognizer_h_
11+
12+
#include "lldb/Target/Process.h"
13+
#include "lldb/Target/StackFrameRecognizer.h"
14+
#include "lldb/Utility/ConstString.h"
15+
#include "lldb/Utility/FileSpec.h"
16+
17+
#include <tuple>
18+
19+
namespace lldb_private {
20+
21+
/// Registers the assert stack frame recognizer.
22+
///
23+
/// \param[in] process
24+
/// The process that is currently asserting. This will give us information on
25+
/// the target and the platform.
26+
void RegisterAssertFrameRecognizer(Process *process);
27+
28+
/// \class AssertRecognizedStackFrame
29+
///
30+
/// Holds the stack frame where the assert is called from.
31+
class AssertRecognizedStackFrame : public RecognizedStackFrame {
32+
public:
33+
AssertRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp);
34+
lldb::StackFrameSP GetMostRelevantFrame() override;
35+
llvm::StringRef GetStopDescription() override;
36+
37+
private:
38+
lldb::StackFrameSP m_most_relevant_frame;
39+
};
40+
41+
/// \class AssertFrameRecognizer
42+
///
43+
/// When a thread stops, it checks depending on the platform if the top frame is
44+
/// an abort stack frame. If so, it looks for an assert stack frame in the upper
45+
/// frames and set it as the most relavant frame when found.
46+
class AssertFrameRecognizer : public StackFrameRecognizer {
47+
public:
48+
std::string GetName() override { return "Assert StackFrame Recognizer"; }
49+
lldb::RecognizedStackFrameSP
50+
RecognizeFrame(lldb::StackFrameSP frame_sp) override;
51+
};
52+
53+
} // namespace lldb_private
54+
55+
#endif // liblldb_AssertFrameRecognizer_h_

lldb/include/lldb/Target/StackFrameRecognizer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "lldb/Core/ValueObject.h"
1313
#include "lldb/Core/ValueObjectList.h"
1414
#include "lldb/Symbol/VariableList.h"
15+
#include "lldb/Target/StopInfo.h"
1516
#include "lldb/Utility/StructuredData.h"
1617
#include "lldb/lldb-private-forward.h"
1718
#include "lldb/lldb-public.h"
@@ -33,6 +34,8 @@ class RecognizedStackFrame
3334
virtual lldb::ValueObjectSP GetExceptionObject() {
3435
return lldb::ValueObjectSP();
3536
}
37+
virtual lldb::StackFrameSP GetMostRelevantFrame() { return nullptr; };
38+
virtual llvm::StringRef GetStopDescription() { return ""; }
3639
virtual ~RecognizedStackFrame(){};
3740

3841
protected:

lldb/include/lldb/Target/Thread.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ class Thread : public std::enable_shared_from_this<Thread>,
216216

217217
virtual void RefreshStateAfterStop() = 0;
218218

219+
void SelectMostRelevantFrame();
220+
221+
llvm::StringRef GetStopDescription();
222+
223+
llvm::StringRef GetStopDescriptionRaw();
224+
219225
void WillStop();
220226

221227
bool ShouldStop(Event *event_ptr);

lldb/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,13 @@ def set_breakpoint(self, line):
104104
def check_stop_reason(self):
105105
matched = lldbplatformutil.match_android_device(
106106
self.getArchitecture(), valid_api_levels=list(range(1, 16 + 1)))
107-
if matched:
108-
# On android until API-16 the abort() call ended in a sigsegv
109-
# instead of in a sigabrt
110-
stop_reason = 'stop reason = signal SIGSEGV'
111-
else:
112-
stop_reason = 'stop reason = signal SIGABRT'
107+
108+
target = self.dbg.GetTargetAtIndex(0)
109+
process = target.GetProcess()
110+
111+
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
112+
113+
stop_reason = 'stop reason = ' + thread.GetStopDescription(256)
113114

114115
# The stop reason of the thread should be an abort signal or exception.
115116
self.expect("thread list", STOPPED_DUE_TO_ASSERT,
@@ -173,6 +174,22 @@ def inferior_asserting_registers(self):
173174
self.runCmd("run", RUN_SUCCEEDED)
174175
self.check_stop_reason()
175176

177+
# change current frame to frame 0, since recognizer might have selected
178+
# different frame.
179+
target = self.dbg.GetTargetAtIndex(0)
180+
self.assertTrue(target, VALID_TARGET)
181+
182+
process = target.GetProcess()
183+
self.assertTrue(process.IsValid(), "current process is valid")
184+
185+
thread = process.GetSelectedThread()
186+
self.assertTrue(thread.IsValid(), "current thread is valid")
187+
188+
thread.SetSelectedFrame(0)
189+
frame = thread.GetSelectedFrame()
190+
191+
self.assertTrue(thread.GetFrameAtIndex(0) == frame, "Frame #0 selected")
192+
176193
# lldb should be able to read from registers from the inferior after
177194
# asserting.
178195
lldbplatformutil.check_first_register_readable(self)

lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def test_objc_exceptions_at_throw(self):
2525
launch_info = lldb.SBLaunchInfo(["a.out", "0"])
2626
lldbutil.run_to_name_breakpoint(self, "objc_exception_throw", launch_info=launch_info)
2727

28-
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
29-
substrs=['stopped', 'stop reason = breakpoint'])
28+
self.expect("thread list",
29+
substrs=['stopped', 'stop reason = hit Objective-C exception'])
3030

3131
self.expect('thread exception', substrs=[
3232
'(NSException *) exception = ',

lldb/source/API/SBThread.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
325325

326326
StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
327327
if (stop_info_sp) {
328-
const char *stop_desc = stop_info_sp->GetDescription();
328+
const char *stop_desc =
329+
exe_ctx.GetThreadPtr()->GetStopDescription().data();
329330
if (stop_desc) {
330331
if (dst)
331332
return ::snprintf(dst, dst_len, "%s", stop_desc);

lldb/source/Core/FormatEntity.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ static FormatEntity::Entry::Definition g_thread_child_entries[] = {
166166
ENTRY("queue", ThreadQueue),
167167
ENTRY("name", ThreadName),
168168
ENTRY("stop-reason", ThreadStopReason),
169+
ENTRY("stop-reason-raw", ThreadStopReasonRaw),
169170
ENTRY("return-value", ThreadReturnValue),
170171
ENTRY("completed-expression", ThreadCompletedExpression),
171172
};
@@ -328,6 +329,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
328329
ENUM_TO_CSTR(ThreadName);
329330
ENUM_TO_CSTR(ThreadQueue);
330331
ENUM_TO_CSTR(ThreadStopReason);
332+
ENUM_TO_CSTR(ThreadStopReasonRaw);
331333
ENUM_TO_CSTR(ThreadReturnValue);
332334
ENUM_TO_CSTR(ThreadCompletedExpression);
333335
ENUM_TO_CSTR(ScriptThread);
@@ -1273,15 +1275,23 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
12731275

12741276
case Entry::Type::ThreadStopReason:
12751277
if (exe_ctx) {
1276-
Thread *thread = exe_ctx->GetThreadPtr();
1277-
if (thread) {
1278-
StopInfoSP stop_info_sp = thread->GetStopInfo();
1279-
if (stop_info_sp && stop_info_sp->IsValid()) {
1280-
const char *cstr = stop_info_sp->GetDescription();
1281-
if (cstr && cstr[0]) {
1282-
s.PutCString(cstr);
1283-
return true;
1284-
}
1278+
if (Thread *thread = exe_ctx->GetThreadPtr()) {
1279+
llvm::StringRef stop_description = thread->GetStopDescription();
1280+
if (!stop_description.empty()) {
1281+
s.PutCString(stop_description);
1282+
return true;
1283+
}
1284+
}
1285+
}
1286+
return false;
1287+
1288+
case Entry::Type::ThreadStopReasonRaw:
1289+
if (exe_ctx) {
1290+
if (Thread *thread = exe_ctx->GetThreadPtr()) {
1291+
llvm::StringRef stop_description = thread->GetStopDescriptionRaw();
1292+
if (!stop_description.empty()) {
1293+
s.PutCString(stop_description);
1294+
return true;
12851295
}
12861296
}
12871297
}

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,6 +2673,10 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
26732673
ValueObjectSP exception;
26742674

26752675
lldb::ValueObjectSP GetExceptionObject() override { return exception; }
2676+
2677+
llvm::StringRef GetStopDescription() override {
2678+
return "hit Objective-C exception";
2679+
}
26762680
};
26772681

26782682
class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {

0 commit comments

Comments
 (0)