Skip to content

Commit d0e243f

Browse files
authored
Merge pull request #740 from medismailben/apple/stable/20200108
[lldb/Target] Add Assert StackFrame Recognizer
2 parents 0505eae + a61f638 commit d0e243f

File tree

17 files changed

+403
-27
lines changed

17 files changed

+403
-27
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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
36+
private:
37+
lldb::StackFrameSP m_most_relevant_frame;
38+
};
39+
40+
/// \class AssertFrameRecognizer
41+
///
42+
/// When a thread stops, it checks depending on the platform if the top frame is
43+
/// an abort stack frame. If so, it looks for an assert stack frame in the upper
44+
/// frames and set it as the most relavant frame when found.
45+
class AssertFrameRecognizer : public StackFrameRecognizer {
46+
public:
47+
std::string GetName() override { return "Assert StackFrame Recognizer"; }
48+
lldb::RecognizedStackFrameSP
49+
RecognizeFrame(lldb::StackFrameSP frame_sp) override;
50+
};
51+
52+
} // namespace lldb_private
53+
54+
#endif // liblldb_AssertFrameRecognizer_h_

lldb/include/lldb/Target/StackFrameRecognizer.h

Lines changed: 5 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,10 +34,14 @@ class RecognizedStackFrame
3334
virtual lldb::ValueObjectSP GetExceptionObject() {
3435
return lldb::ValueObjectSP();
3536
}
37+
virtual lldb::StackFrameSP GetMostRelevantFrame() { return nullptr; };
3638
virtual ~RecognizedStackFrame(){};
3739

40+
std::string GetStopDescription() { return m_stop_desc; }
41+
3842
protected:
3943
lldb::ValueObjectListSP m_arguments;
44+
std::string m_stop_desc;
4045
};
4146

4247
/// \class StackFrameRecognizer

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+
std::string GetStopDescription();
222+
223+
std::string GetStopDescriptionRaw();
224+
219225
void WillStop();
220226

221227
bool ShouldStop(Event *event_ptr);

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

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,22 @@ def check_stop_reason(self):
107107
if matched:
108108
# On android until API-16 the abort() call ended in a sigsegv
109109
# instead of in a sigabrt
110-
stop_reason = 'stop reason = signal SIGSEGV'
110+
stop_reason = 'signal SIGSEGV'
111111
else:
112-
stop_reason = 'stop reason = signal SIGABRT'
112+
stop_reason = 'signal SIGABRT'
113+
114+
target = self.dbg.GetTargetAtIndex(0)
115+
process = target.GetProcess()
116+
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
117+
118+
pattern = "stop reason = (" + stop_reason + "|hit program assert)"
113119

114120
# The stop reason of the thread should be an abort signal or exception.
115121
self.expect("thread list", STOPPED_DUE_TO_ASSERT,
116-
substrs=['stopped',
117-
stop_reason])
122+
patterns=[pattern],
123+
substrs=['stopped'])
118124

119-
return stop_reason
125+
return pattern
120126

121127
def setUp(self):
122128
# Call super's setUp().
@@ -134,12 +140,13 @@ def inferior_asserting(self):
134140

135141
# And it should report a backtrace that includes the assert site.
136142
self.expect("thread backtrace all",
137-
substrs=[stop_reason, 'main', 'argc', 'argv'])
143+
patterns=[stop_reason],
144+
substrs=['main', 'argc', 'argv'])
138145

139146
# And it should report the correct line number.
140147
self.expect("thread backtrace all",
141-
substrs=[stop_reason,
142-
'main.c:%d' % self.line])
148+
patterns=[stop_reason],
149+
substrs=['main.c:%d' % self.line])
143150

144151
def inferior_asserting_python(self):
145152
"""Inferior asserts upon launching; lldb should catch the event and stop."""
@@ -173,6 +180,10 @@ def inferior_asserting_registers(self):
173180
self.runCmd("run", RUN_SUCCEEDED)
174181
self.check_stop_reason()
175182

183+
# change current frame to frame 0, since recognizer might have selected
184+
# different frame.
185+
self.runCmd("frame select 0", RUN_SUCCEEDED)
186+
176187
# lldb should be able to read from registers from the inferior after
177188
# asserting.
178189
lldbplatformutil.check_first_register_readable(self)
@@ -311,5 +322,5 @@ def inferior_asserting_step(self):
311322

312323
# And it should report the correct line number.
313324
self.expect("thread backtrace all",
314-
substrs=[stop_reason,
315-
'main.c:%d' % self.line])
325+
patterns=[stop_reason],
326+
substrs=['main.c:%d' % self.line])

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: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,11 @@ 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();
329-
if (stop_desc) {
328+
std::string thread_stop_desc =
329+
exe_ctx.GetThreadPtr()->GetStopDescription();
330+
const char *stop_desc = thread_stop_desc.c_str();
331+
332+
if (stop_desc[0] != '\0') {
330333
if (dst)
331334
return ::snprintf(dst, dst_len, "%s", stop_desc);
332335
else {

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+
std::string 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+
std::string 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,8 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
26982698

26992699
m_arguments = ValueObjectListSP(new ValueObjectList());
27002700
m_arguments->Append(exception);
2701+
2702+
m_stop_desc = "hit Objective-C exception";
27012703
}
27022704

27032705
ValueObjectSP exception;

0 commit comments

Comments
 (0)