Skip to content

Commit e0bc3cb

Browse files
committed
[lldb] Add Swift exception breakpoint frame recognizer
1 parent 92e60fa commit e0bc3cb

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
#include "lldb/Core/Module.h"
44
#include "lldb/Symbol/Function.h"
55
#include "lldb/Symbol/SymbolContext.h"
6+
#include "lldb/Target/Platform.h"
67
#include "lldb/Target/Process.h"
78
#include "lldb/Target/StackFrameRecognizer.h"
89
#include "lldb/Target/Target.h"
910
#include "lldb/Target/Thread.h"
1011

12+
#include "lldb/Utility/ConstString.h"
13+
#include "lldb/Utility/FileSpec.h"
1114
#include "lldb/Utility/LLDBLog.h"
1215
#include "lldb/Utility/Log.h"
1316

@@ -220,6 +223,66 @@ class SwiftHiddenFrameRecognizer : public StackFrameRecognizer {
220223
}
221224
};
222225

226+
/// A frame recognizer for Swift exception breakpoints.
227+
class SwiftExceptionBreakpointFrameRecognizer : public StackFrameRecognizer {
228+
public:
229+
class SwiftExceptionFrame : public RecognizedStackFrame {
230+
public:
231+
SwiftExceptionFrame(StackFrameSP frame) : m_frame_sp(frame) {
232+
m_stop_desc = "Swift exception breakpoint";
233+
}
234+
235+
StackFrameSP GetMostRelevantFrame() override {
236+
if (!m_frame_sp)
237+
return {};
238+
239+
auto thread_sp = m_frame_sp->GetThread();
240+
if (!thread_sp)
241+
return {};
242+
243+
StringRef symbol_name;
244+
{
245+
const SymbolContext &sc =
246+
m_frame_sp->GetSymbolContext(eSymbolContextSymbol);
247+
if (!sc.symbol)
248+
return {};
249+
symbol_name = sc.symbol->GetName();
250+
}
251+
252+
StackFrameSP relevant_frame_sp;
253+
if (symbol_name == "swift_willThrow")
254+
relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1);
255+
else if (symbol_name == "swift_willThrowTypedImpl")
256+
relevant_frame_sp = thread_sp->GetStackFrameAtIndex(2);
257+
else {
258+
assert(false && "unexpected frame name");
259+
return {};
260+
}
261+
262+
if (relevant_frame_sp) {
263+
// Select the relevant frame only if source is available.
264+
const SymbolContext &sc =
265+
relevant_frame_sp->GetSymbolContext(eSymbolContextCompUnit);
266+
if (sc.comp_unit)
267+
return relevant_frame_sp;
268+
}
269+
270+
return {};
271+
}
272+
273+
private:
274+
StackFrameSP m_frame_sp;
275+
};
276+
277+
RecognizedStackFrameSP RecognizeFrame(StackFrameSP frame) override {
278+
return std::make_shared<SwiftExceptionFrame>(frame);
279+
};
280+
281+
std::string GetName() override {
282+
return "Swift exception breakpoint frame recognizer";
283+
}
284+
};
285+
223286
void RegisterSwiftFrameRecognizers(Process &process) {
224287
RegularExpressionSP module_regex_sp = nullptr;
225288
auto &manager = process.GetTarget().GetFrameRecognizerManager();
@@ -245,6 +308,16 @@ void RegisterSwiftFrameRecognizers(Process &process) {
245308
manager.AddRecognizer(srf_sp, module_regex_sp, symbol_regex_sp,
246309
Mangled::NamePreference::ePreferMangled, false);
247310
}
311+
{
312+
auto srf_sp = std::make_shared<SwiftExceptionBreakpointFrameRecognizer>();
313+
ConstString module_name = ConstString("swiftCore");
314+
if (auto platform_sp = process.GetTarget().GetPlatform())
315+
module_name = platform_sp->GetFullNameForDylib(module_name);
316+
manager.AddRecognizer(srf_sp, module_name,
317+
{ConstString("swift_willThrow"),
318+
ConstString("swift_willThrowTypedImpl")},
319+
Mangled::NamePreference::ePreferMangled, false);
320+
}
248321
}
249322

250323
} // namespace lldb_private
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -parse-as-library
3+
include Makefile.rules
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class TestCase(TestBase):
8+
9+
@swiftTest
10+
def test(self):
11+
self.build()
12+
13+
target = lldbutil.run_to_breakpoint_make_target(self)
14+
bp = target.BreakpointCreateForException(lldb.eLanguageTypeSwift, False, True)
15+
16+
# First breakpoint in an untyped throws function.
17+
_, process, _, _ = lldbutil.run_to_breakpoint_do_run(self, target, bp)
18+
thread = process.selected_thread
19+
stop_desc = thread.GetStopDescription(128)
20+
self.assertEqual(stop_desc, "Swift exception breakpoint")
21+
self.assertEqual(thread.frame[0].symbol.name, "swift_willThrow")
22+
self.assertEqual(thread.selected_frame.idx, 1)
23+
24+
# Second breakpoint in an typed throws function.
25+
process.Continue()
26+
thread = process.selected_thread
27+
stop_desc = thread.GetStopDescription(128)
28+
self.assertEqual(stop_desc, "Swift exception breakpoint")
29+
self.assertEqual(thread.frame[0].symbol.name, "swift_willThrowTypedImpl")
30+
self.assertEqual(thread.selected_frame.idx, 2)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
struct OpaqueError: Error {}
2+
3+
func untyped() throws {
4+
throw OpaqueError()
5+
}
6+
7+
func typed() throws(OpaqueError) {
8+
throw OpaqueError()
9+
}
10+
11+
@main struct Entry {
12+
static func main() {
13+
do {
14+
try untyped()
15+
} catch {}
16+
do {
17+
try typed()
18+
} catch {}
19+
}
20+
}

0 commit comments

Comments
 (0)