Skip to content

Commit 0e70f06

Browse files
committed
Add a frame recognizer for Swift runtime error with instrumentation.
Certain errors are correctly detected by the Swift Runtime Instrumentation plugin, however, there is no frame recognizer to point the debugger to user code. This patch adds one. rdar://125125193
1 parent df6ce54 commit 0e70f06

File tree

5 files changed

+112
-7
lines changed

5 files changed

+112
-7
lines changed

lldb/source/Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.cpp

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include "lldb/Utility/LLDBLog.h"
1111
#include "lldb/Utility/Log.h"
1212

13+
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"
14+
#include "swift/Strings.h"
15+
1316
using namespace llvm;
1417
using namespace lldb;
1518
using namespace lldb_private;
@@ -21,12 +24,19 @@ SwiftRuntimeFailureRecognizedStackFrame::
2124
m_stop_desc = std::string(stop_desc);
2225
}
2326

27+
lldb::StackFrameSP
28+
SwiftRuntimeFailureRecognizedStackFrame::GetMostRelevantFrame() {
29+
return m_most_relevant_frame;
30+
}
31+
2432
lldb::RecognizedStackFrameSP SwiftRuntimeFailureFrameRecognizer::RecognizeFrame(
2533
lldb::StackFrameSP frame_sp) {
2634
if (frame_sp->GetFrameIndex())
2735
return {};
2836

2937
ThreadSP thread_sp = frame_sp->GetThread();
38+
if (!thread_sp)
39+
return {};
3040
ProcessSP process_sp = thread_sp->GetProcess();
3141

3242
StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1);
@@ -67,23 +77,72 @@ lldb::RecognizedStackFrameSP SwiftRuntimeFailureFrameRecognizer::RecognizeFrame(
6777
runtime_error));
6878
}
6979

70-
lldb::StackFrameSP
71-
SwiftRuntimeFailureRecognizedStackFrame::GetMostRelevantFrame() {
72-
return m_most_relevant_frame;
80+
lldb::RecognizedStackFrameSP
81+
SwiftRuntimeInstrumentedFrameRecognizer::RecognizeFrame(
82+
lldb::StackFrameSP frame_sp) {
83+
if (frame_sp->GetFrameIndex())
84+
return {};
85+
86+
ThreadSP thread_sp = frame_sp->GetThread();
87+
if (!thread_sp)
88+
return {};
89+
90+
StackFrameSP most_relevant_frame_sp;
91+
// Unwind until we leave the standard library.
92+
unsigned max_depth = 16;
93+
for (unsigned i = 1; i < max_depth; ++i) {
94+
most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(i);
95+
if (!most_relevant_frame_sp) {
96+
Log *log = GetLog(LLDBLog::Unwind);
97+
LLDB_LOG(log,
98+
"Swift Runtime Instrumentation Failure Recognizer: Hit "
99+
"unwinding bound ({0} frames)!",
100+
i);
101+
return {};
102+
}
103+
auto &sc =
104+
most_relevant_frame_sp->GetSymbolContext(lldb::eSymbolContextFunction);
105+
ConstString module_name = TypeSystemSwiftTypeRef::GetSwiftModuleFor(&sc);
106+
if (!module_name)
107+
continue;
108+
if (module_name == swift::STDLIB_NAME)
109+
continue;
110+
if (i + 1 == max_depth)
111+
return {};
112+
113+
break;
114+
}
115+
116+
std::string runtime_error = thread_sp->GetStopDescriptionRaw();
117+
return lldb::RecognizedStackFrameSP(
118+
new SwiftRuntimeFailureRecognizedStackFrame(most_relevant_frame_sp,
119+
runtime_error));
73120
}
74121

75122
namespace lldb_private {
76123

77124
void RegisterSwiftRuntimeFailureRecognizer(Process &process) {
78-
RegularExpressionSP module_regex_sp = nullptr;
79-
RegularExpressionSP symbol_regex_sp(
80-
new RegularExpression("Swift runtime failure"));
125+
RegularExpressionSP module_regex_sp = nullptr;
126+
{
127+
auto symbol_regex_sp =
128+
std::make_shared<RegularExpression>("Swift runtime failure");
81129

82130
StackFrameRecognizerSP srf_recognizer_sp =
83131
std::make_shared<SwiftRuntimeFailureFrameRecognizer>();
84132

85133
process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
86134
srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
135+
}
136+
{
137+
auto symbol_regex_sp =
138+
std::make_shared<RegularExpression>("_swift_runtime_on_report");
139+
140+
StackFrameRecognizerSP srf_recognizer_sp =
141+
std::make_shared<SwiftRuntimeInstrumentedFrameRecognizer>();
142+
143+
process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
144+
srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
145+
}
87146
}
88147

89148
} // namespace lldb_private

lldb/source/Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class SwiftRuntimeFailureRecognizedStackFrame : public RecognizedStackFrame {
3030
/// When a thread stops, it checks the current frame contains a swift runtime
3131
/// failure diagnostic. If so, it returns a \a
3232
/// SwiftRuntimeFailureRecognizedStackFrame holding the diagnostic a stop reason
33-
/// description with and the parent frame as the most relavant frame.
33+
/// description with and the parent frame as the most relevant frame.
3434
class SwiftRuntimeFailureFrameRecognizer : public StackFrameRecognizer {
3535
public:
3636
std::string GetName() override {
@@ -40,6 +40,17 @@ class SwiftRuntimeFailureFrameRecognizer : public StackFrameRecognizer {
4040
RecognizeFrame(lldb::StackFrameSP frame) override;
4141
};
4242

43+
/// Detect when a thread stops in _swift_runtime_on_report.
44+
class SwiftRuntimeInstrumentedFrameRecognizer : public StackFrameRecognizer {
45+
public:
46+
std::string GetName() override {
47+
return "Swift Runtime Instrumentation StackFrame Recognizer";
48+
}
49+
lldb::RecognizedStackFrameSP
50+
RecognizeFrame(lldb::StackFrameSP frame) override;
51+
};
52+
53+
4354
} // namespace lldb_private
4455

4556
#endif // liblldb_SwiftRuntimeFailureRegognizer_h_
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := RuntimeError.swift
2+
3+
include Makefile.rules
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
func testit(_ a: Int) -> Int {
2+
return 1 / a
3+
}
4+
5+
print(testit(0))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbtest as lldbtest
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import unittest2
6+
7+
8+
class TestSwiftRuntimeInstrumentationRecognizer(lldbtest.TestBase):
9+
@swiftTest
10+
def test(self):
11+
"""Test Swift Runtime Instrumentation Recognizer"""
12+
self.build()
13+
self.runCmd("file " + self.getBuildArtifact("a.out"))
14+
self.runCmd("process launch")
15+
16+
self.expect("frame recognizer list",
17+
substrs=['Swift Runtime Instrumentation StackFrame Recognizer, symbol _swift_runtime_on_report (regexp)'])
18+
19+
self.expect("frame recognizer info 0",
20+
substrs=['frame 0 is recognized by Swift Runtime Instrumentation StackFrame Recognizer'])
21+
22+
self.expect("thread info",
23+
substrs=['stop reason = Fatal error: Division by zero'])
24+
25+
self.expect('bt')
26+
self.expect("frame info",
27+
patterns=['frame #(.*)`testit(.*)at RuntimeError\.swift'])

0 commit comments

Comments
 (0)