Skip to content

Commit b3ce1bc

Browse files
author
git apple-llvm automerger
committed
Merge commit '3f9b87500104' from swift/release/6.2 into stable/20240723
2 parents 28bf8e1 + 3f9b875 commit b3ce1bc

File tree

7 files changed

+194
-35
lines changed

7 files changed

+194
-35
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp

Lines changed: 100 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum class ThunkKind {
4545
AllocatingInit,
4646
PartialApply,
4747
ObjCAttribute,
48+
NonObjCAttributeOnCtor,
4849
Reabstraction,
4950
ProtocolConformance,
5051
};
@@ -55,6 +56,7 @@ enum class ThunkAction {
5556
StepIntoConformance,
5657
StepIntoAllocatingInit,
5758
StepThrough,
59+
RunToObjcCInteropCtor,
5860
};
5961

6062
} // namespace
@@ -313,6 +315,10 @@ static ThunkKind GetThunkKind(Symbol *symbol) {
313315
switch (main_node->getKind()) {
314316
case Node::Kind::ObjCAttribute:
315317
return ThunkKind::ObjCAttribute;
318+
case Node::Kind::NonObjCAttribute:
319+
if (hasChild(nodes, Node::Kind::Constructor))
320+
return ThunkKind::NonObjCAttributeOnCtor;
321+
break;
316322
case Node::Kind::ProtocolWitness:
317323
if (hasChild(main_node, Node::Kind::ProtocolConformance))
318324
return ThunkKind::ProtocolConformance;
@@ -342,6 +348,8 @@ static const char *GetThunkKindName(ThunkKind kind) {
342348
return "GetThunkTarget";
343349
case ThunkKind::ObjCAttribute:
344350
return "GetThunkTarget";
351+
case ThunkKind::NonObjCAttributeOnCtor:
352+
return "RunToObjcCInteropCtor";
345353
case ThunkKind::Reabstraction:
346354
return "GetThunkTarget";
347355
case ThunkKind::ProtocolConformance:
@@ -363,6 +371,8 @@ static ThunkAction GetThunkAction(ThunkKind kind) {
363371
return ThunkAction::StepThrough;
364372
case ThunkKind::ProtocolConformance:
365373
return ThunkAction::StepIntoConformance;
374+
case ThunkKind::NonObjCAttributeOnCtor:
375+
return ThunkAction::RunToObjcCInteropCtor;
366376
}
367377
}
368378

@@ -419,6 +429,66 @@ CreateRunThroughTaskSwitchingTrampolines(Thread &thread,
419429
return nullptr;
420430
}
421431

432+
/// Demangle `symbol_name` and extracts the text at the node described by
433+
/// `node_path`, if it exists; otherwise, returns an empty string.
434+
static std::string FindClassName(StringRef symbol_name,
435+
llvm::ArrayRef<Node::Kind> node_path) {
436+
swift::Demangle::Context ctx;
437+
NodePointer demangled_node =
438+
SwiftLanguageRuntime::DemangleSymbolAsNode(symbol_name, ctx);
439+
440+
if (!demangled_node) {
441+
std::string symbol_name_str = symbol_name.str();
442+
LLDB_LOGF(GetLog(LLDBLog::Step),
443+
"SwiftLanguageRuntime: failed to demangle %s.",
444+
symbol_name_str.c_str());
445+
return "";
446+
}
447+
NodePointer class_node = childAtPath(demangled_node, node_path);
448+
if (!class_node || !class_node->hasText()) {
449+
std::string node_str = getNodeTreeAsString(demangled_node);
450+
LLDB_LOGF(GetLog(LLDBLog::Step),
451+
"SwiftLanguageRuntime: failed to extract name from "
452+
"demangle node: %s",
453+
node_str.c_str());
454+
return "";
455+
}
456+
return class_node->getText().str();
457+
}
458+
459+
/// If sc_list is non-empty, returns a plan that runs to any of its addresses.
460+
/// Otherwise, returns nullptr.
461+
static ThreadPlanSP
462+
CreateThreadPlanRunToSCInList(Thread &thread, const SymbolContextList &sc_list,
463+
bool stop_others) {
464+
std::vector<addr_t> load_addresses;
465+
Target &target = thread.GetProcess()->GetTarget();
466+
for (const SymbolContext &sc : sc_list) {
467+
const Symbol *ctor_symbol = sc.symbol;
468+
if (ctor_symbol)
469+
load_addresses.push_back(ctor_symbol->GetLoadAddress(&target));
470+
}
471+
472+
if (load_addresses.empty()) {
473+
LLDB_LOG(GetLog(LLDBLog::Step),
474+
"SwiftLanguageRuntime: empty sc_list found.");
475+
return {};
476+
}
477+
return std::make_shared<ThreadPlanRunToAddress>(thread, load_addresses,
478+
stop_others);
479+
}
480+
481+
/// Search all modules for `target_func` and creates a RunToAddress plan
482+
/// targeting all symbols found.
483+
static ThreadPlanSP CreateRunToAddressPlan(StringRef target_func,
484+
Thread &thread, bool stop_others) {
485+
ModuleList modules = thread.GetProcess()->GetTarget().GetImages();
486+
SymbolContextList sc_list;
487+
modules.FindFunctionSymbols(ConstString(target_func), eFunctionNameTypeFull,
488+
sc_list);
489+
return CreateThreadPlanRunToSCInList(thread, sc_list, stop_others);
490+
}
491+
422492
static lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
423493
bool stop_others) {
424494
// Here are the trampolines we have at present.
@@ -475,19 +545,32 @@ static lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
475545
log->Printf(
476546
"Stepped to thunk \"%s\" (kind: %s) stepping to target: \"%s\".",
477547
symbol_name, GetThunkKindName(thunk_kind), thunk_target.c_str());
548+
return CreateRunToAddressPlan(thunk_target, thread, stop_others);
549+
}
550+
case ThunkAction::RunToObjcCInteropCtor: {
551+
static constexpr auto class_path = {
552+
Node::Kind::Constructor, Node::Kind::Class, Node::Kind::Identifier};
553+
std::string class_name = FindClassName(symbol_name, class_path);
554+
if (class_name.empty()) {
555+
LLDB_LOGF(log,
556+
"SwiftLanguageRuntime: could not derive class name from symbol "
557+
"\"%s\".",
558+
symbol_name);
559+
return nullptr;
560+
}
561+
std::string ctor_name = llvm::formatv("{0} init", class_name);
562+
LLDB_LOGF(log,
563+
"SwiftLanguageRuntime: running to objective C constructor \"%s\" "
564+
"from swift.",
565+
ctor_name.c_str());
478566

479-
ModuleList modules = thread.GetProcess()->GetTarget().GetImages();
480567
SymbolContextList sc_list;
481-
modules.FindFunctionSymbols(ConstString(thunk_target),
482-
eFunctionNameTypeFull, sc_list);
483-
if (sc_list.GetSize() == 1 && sc_list[0].symbol) {
484-
Symbol &thunk_symbol = *sc_list[0].symbol;
485-
Address target_address = thunk_symbol.GetAddress();
486-
if (target_address.IsValid())
487-
return std::make_shared<ThreadPlanRunToAddress>(thread, target_address,
488-
stop_others);
489-
}
490-
return nullptr;
568+
ModuleFunctionSearchOptions options{/*include_symbols*/ true,
569+
/*include_inlines*/ true};
570+
ModuleList modules = thread.GetProcess()->GetTarget().GetImages();
571+
modules.FindFunctions(RegularExpression(ctor_name), options, sc_list);
572+
573+
return CreateThreadPlanRunToSCInList(thread, sc_list, stop_others);
491574
}
492575
case ThunkAction::StepIntoConformance: {
493576
// The TTW symbols encode the protocol conformance requirements
@@ -582,37 +665,19 @@ static lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
582665
}
583666
case ThunkAction::StepIntoAllocatingInit: {
584667
LLDB_LOGF(log, "Stepping into allocating init: \"%s\"", symbol_name);
585-
swift::Demangle::Context ctx;
586-
NodePointer demangled_node =
587-
SwiftLanguageRuntime::DemangleSymbolAsNode(symbol_name, ctx);
588-
589668
using Kind = Node::Kind;
590-
NodePointer class_node = childAtPath(
591-
demangled_node, {Kind::Allocator, Kind::Class, Kind::Identifier});
592-
if (!class_node || !class_node->hasText()) {
593-
std::string node_str = getNodeTreeAsString(demangled_node);
594-
LLDB_LOGF(log,
595-
"Failed to extract constructor name from demangle node: %s",
596-
node_str.c_str());
669+
static constexpr auto class_path = {Kind::Allocator, Kind::Class,
670+
Kind::Identifier};
671+
std::string class_name = FindClassName(symbol_name, class_path);
672+
if (class_name.empty())
597673
return nullptr;
598-
}
599674

600675
ModuleFunctionSearchOptions options{/*include_symbols*/ true,
601676
/*include_inlines*/ true};
602-
std::string ctor_name = llvm::formatv("{0}.init", class_node->getText());
677+
std::string ctor_name = llvm::formatv("{0}.init", class_name);
603678
SymbolContextList sc_list;
604679
sc.module_sp->FindFunctions(RegularExpression(ctor_name), options, sc_list);
605-
std::vector<addr_t> load_addresses;
606-
Target &target = thread.GetProcess()->GetTarget();
607-
for (const SymbolContext &ctor_sc : sc_list) {
608-
const Symbol *ctor_symbol = ctor_sc.symbol;
609-
if (ctor_symbol)
610-
load_addresses.push_back(ctor_symbol->GetLoadAddress(&target));
611-
}
612-
if (load_addresses.empty())
613-
return nullptr;
614-
return std::make_shared<ThreadPlanRunToAddress>(thread, load_addresses,
615-
stop_others);
680+
return CreateThreadPlanRunToSCInList(thread, sc_list, stop_others);
616681
}
617682
case ThunkAction::StepThrough: {
618683
if (log)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface Foo : NSObject
4+
5+
@property (nonnull) NSArray<NSString *> *values;
6+
7+
- (nonnull id)init;
8+
- (nonnull id)initWithString:(nonnull NSString *)value;
9+
- (nonnull id)initWithString:(nonnull NSString *)value andOtherString:(nonnull NSString *) otherValue;
10+
11+
@end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#import "Foo.h"
2+
3+
@implementation Foo
4+
5+
- (id)init {
6+
}
7+
8+
- (id)initWithString:(nonnull NSString *)value {
9+
self->_values = @[value];
10+
return self;
11+
}
12+
13+
- (nonnull id)initWithString:(nonnull NSString *)value andOtherString:(nonnull NSString *) otherValue {
14+
self->_values = @[value, otherValue];
15+
return self;
16+
}
17+
18+
@end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFT_BRIDGING_HEADER := bridging-header.h
3+
OBJC_SOURCES := Foo.m
4+
SWIFT_OBJC_INTEROP := 1
5+
6+
include Makefile.rules
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestSwiftObjcProtocol(TestBase):
8+
def skip_debug_info_libraries(self):
9+
if platform.system() == "Darwin":
10+
lib_name = "libswiftCore.dylib"
11+
else:
12+
lib_name = "libswiftCore.so"
13+
14+
self.dbg.HandleCommand(
15+
"settings set "
16+
"target.process.thread.step-avoid-libraries {}".format(lib_name)
17+
)
18+
19+
@skipUnlessDarwin
20+
@swiftTest
21+
def test(self):
22+
self.build()
23+
(target, process, thread, breakpoint) = lldbutil.run_to_source_breakpoint(
24+
self, "break here", lldb.SBFileSpec("main.swift")
25+
)
26+
27+
self.skip_debug_info_libraries()
28+
# Go to the first constructor, assert we can step into it.
29+
thread.StepInto()
30+
self.assertEqual(thread.stop_reason, lldb.eStopReasonPlanComplete)
31+
self.assertIn("-[Foo init]", thread.frames[0].GetFunctionName())
32+
33+
# Go back to "work" function
34+
thread.StepOut()
35+
self.assertEqual(thread.stop_reason, lldb.eStopReasonPlanComplete)
36+
self.assertIn("work", thread.frames[0].GetFunctionName())
37+
38+
# Go to the next constructor call.
39+
thread.StepOver()
40+
self.assertEqual(thread.stop_reason, lldb.eStopReasonPlanComplete)
41+
self.assertIn("work", thread.frames[0].GetFunctionName())
42+
43+
# Assert we can step into it.
44+
thread.StepInto()
45+
self.assertEqual(thread.stop_reason, lldb.eStopReasonPlanComplete)
46+
self.assertIn("-[Foo initWithString:]", thread.frames[0].GetFunctionName())
47+
48+
# Go back to "work" function
49+
thread.StepOut()
50+
self.assertEqual(thread.stop_reason, lldb.eStopReasonPlanComplete)
51+
self.assertIn("work", thread.frames[0].GetFunctionName())
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import "Foo.h"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
func work() {
2+
let noParams = Foo() // break here
3+
let oneParam = Foo(string: "Bar")
4+
print("done")
5+
}
6+
7+
work()

0 commit comments

Comments
 (0)