-
Notifications
You must be signed in to change notification settings - Fork 339
[lldb] Fix stepping into Objective-C interop ctors #10697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: swift/release/6.2
Are you sure you want to change the base?
[lldb] Fix stepping into Objective-C interop ctors #10697
Conversation
These will be useful to reuse code in upcoming commits.
When constructing an Objective C object of type `Foo` from Swift, this sequence of function calls is used: ``` * frame #0: 0x000000010000147c test.out`-[Foo initWithString:](self=0x00006000023ec000, _cmd="initWithString:", value=@"Bar") -[Foo initWithString:] at Foo.m:9:21 frame swiftlang#1: 0x00000001000012bc test.out`@nonobjc Foo.init(string:) $sSo3FooC6stringABSS_tcfcTO at <compiler-generated>:0 frame swiftlang#2: 0x0000000100001170 test.out`Foo.__allocating_init(string:) $sSo3FooC6stringABSS_tcfC at Foo.h:0 frame swiftlang#3: 0x0000000100000ed8 test.out`work() $s4test4workyyF at main.swift:5:18 ``` Frames 1 and 2 are common with pure Swift classes, and LLDB has a Thread Plan to go from `Foo.allocating_init` -> `Foo.init`. In the case of Objcetive C interop, `Foo.init` has no user code, and is annotated with `@nonobjc`. The debugger needs a plan to go from that code to the Objective C implementation. This is what this patch attempts to fix by creating a plan that runs to any symbol matching `Foo init` (this will match all the :withBlah suffixes). This seems to be the only possible fix for this. While Objective C constructors are not necessarily called init, the interop layer seems to assume this. The only other alternative has some obstacles that could not be easily overcome. Here's the main idea for that. The assembly for `@nonobjc Foo.init` looks like (deleted all non branches): ``` test.out`@nonobjc Foo.init(string:): ... 0x1000012a0 <+20>: bl 0x100001618 ; symbol stub for: Swift.String._bridgeToObjectiveC() -> __C.NSString ... 0x1000012b8 <+44>: bl 0x100001630 ; symbol stub for: objc_msgSend ... 0x1000012e8 <+92>: ret ``` If we had more String arguments, there would be more calls to `_bridgeToObjectiveC`. The call to `objc_msgSend` is the important one, and LLDB knows how to go from that to the target of the message, LLDB has ThreadPlans for that. However, setting a breakpoint on `objc_msgSend` would fail: the calls to `_bridgeToObjectiveC` may also call `objc_msgSend`, so LLDB would end up in the wrong `objc_msgSend`. This is not entirely bad, LLDB would step back to `Foo.init`. Here's the catch: the language runtime refuses to create other plans if PC is not at the start of the function, which makes sense, as it would not be able to distinguish if its job was already done previously or not, unless it had a stateful plan (which it doesn't today).
75bd162
to
6d84e65
Compare
@swift-ci test |
modules.FindFunctionSymbols(ConstString(target_func), eFunctionNameTypeFull, | ||
sc_list); | ||
if (sc_list.GetSize() != 1 || sc_list[0].symbol == nullptr) | ||
return nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return nullptr; | |
return {}; |
|
||
/// Demangle `symbol_name` and extracts the text at the node described by | ||
/// `node_path`, if it exists. | ||
static std::optional<std::string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any value in the optional or can you just use the empty string as null value?
From the test failure:
Standard library with debug info strikes again. |
The first commit is just hoisting helper functions for re-use. The second commit actually solves the problem.
Please read each commit in isolation, especially the message on the second commit.
rdar://146886271