Skip to content

Commit e7fa1b4

Browse files
committed
[lldb] Add Swift exception breakpoint frame recognizer
1 parent 30469c7 commit e7fa1b4

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

@@ -222,6 +225,66 @@ class SwiftHiddenFrameRecognizer : public StackFrameRecognizer {
222225
}
223226
};
224227

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

252325
} // 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)