Skip to content

Commit 771083a

Browse files
authored
Merge pull request #32795 from mikeash/swift-inspect-cache-node-dump
[swift-inspect] Add a command for dumping metadata cache nodes.
2 parents 8f7b1d7 + 5347179 commit 771083a

File tree

7 files changed

+151
-29
lines changed

7 files changed

+151
-29
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,36 @@ class ReflectionContext
850850
}
851851
}
852852

853+
llvm::Optional<MetadataCacheNode<Runtime>>
854+
metadataAllocationCacheNode(MetadataAllocation<Runtime> Allocation) {
855+
switch (Allocation.Tag) {
856+
case BoxesTag:
857+
case ObjCClassWrappersTag:
858+
case FunctionTypesTag:
859+
case MetatypeTypesTag:
860+
case ExistentialMetatypeValueWitnessTablesTag:
861+
case ExistentialMetatypesTag:
862+
case ExistentialTypesTag:
863+
case OpaqueExistentialValueWitnessTablesTag:
864+
case ClassExistentialValueWitnessTablesTag:
865+
case ForeignWitnessTablesTag:
866+
case TupleCacheTag:
867+
case GenericMetadataCacheTag:
868+
case ForeignMetadataCacheTag:
869+
case GenericWitnessTableCacheTag: {
870+
auto NodeBytes = getReader().readBytes(
871+
RemoteAddress(Allocation.Ptr), sizeof(MetadataCacheNode<Runtime>));
872+
auto Node =
873+
reinterpret_cast<const MetadataCacheNode<Runtime> *>(NodeBytes.get());
874+
if (!Node)
875+
return llvm::None;
876+
return *Node;
877+
}
878+
default:
879+
return llvm::None;
880+
}
881+
}
882+
853883
/// Iterate the metadata allocations in the target process, calling Call with
854884
/// each allocation found. Returns None on success, and a string describing
855885
/// the error on failure.

include/swift/Reflection/RuntimeInternals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ struct MetadataAllocation {
4141
unsigned Size;
4242
};
4343

44+
template <typename Runtime> struct MetadataCacheNode {
45+
typename Runtime::StoredPointer Left;
46+
typename Runtime::StoredPointer Right;
47+
};
48+
4449
} // end namespace reflection
4550
} // end namespace swift
4651

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ const char *
339339
swift_reflection_metadataAllocationTagName(SwiftReflectionContextRef ContextRef,
340340
swift_metadata_allocation_tag_t Tag);
341341

342+
SWIFT_REMOTE_MIRROR_LINKAGE
343+
int swift_reflection_metadataAllocationCacheNode(
344+
SwiftReflectionContextRef ContextRef,
345+
swift_metadata_allocation_t Allocation,
346+
swift_metadata_cache_node_t *OutNode);
347+
342348
/// Backtrace iterator callback passed to
343349
/// swift_reflection_iterateMetadataAllocationBacktraces
344350
typedef void (*swift_metadataAllocationBacktraceIterator)(

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ typedef struct swift_metadata_allocation {
162162
unsigned Size;
163163
} swift_metadata_allocation_t;
164164

165+
typedef struct swift_metadata_cache_node {
166+
swift_reflection_ptr_t Left;
167+
swift_reflection_ptr_t Right;
168+
} swift_metadata_cache_node_t;
169+
165170
/// An opaque pointer to a context which maintains state and
166171
/// caching of reflection structure for heap instances.
167172
typedef struct SwiftReflectionContext *SwiftReflectionContextRef;

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,25 @@ const char *swift_reflection_metadataAllocationTagName(
645645
return returnableCString(ContextRef, Result);
646646
}
647647

648+
int swift_reflection_metadataAllocationCacheNode(
649+
SwiftReflectionContextRef ContextRef,
650+
swift_metadata_allocation_t Allocation,
651+
swift_metadata_cache_node_t *OutNode) {
652+
auto Context = ContextRef->nativeContext;
653+
MetadataAllocation<Runtime> ConvertedAllocation;
654+
ConvertedAllocation.Tag = Allocation.Tag;
655+
ConvertedAllocation.Ptr = Allocation.Ptr;
656+
ConvertedAllocation.Size = Allocation.Size;
657+
658+
auto Result = Context->metadataAllocationCacheNode(ConvertedAllocation);
659+
if (!Result)
660+
return 0;
661+
662+
OutNode->Left = Result->Left;
663+
OutNode->Right = Result->Right;
664+
return 1;
665+
}
666+
648667
const char *swift_reflection_iterateMetadataAllocationBacktraces(
649668
SwiftReflectionContextRef ContextRef,
650669
swift_metadataAllocationBacktraceIterator Call, void *ContextPtr) {

tools/swift-inspect/Sources/swift-inspect/RemoteMirrorExtensions.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ extension SwiftReflectionContextRef {
8383
swift_reflection_allocationMetadataPointer(self, allocation)
8484
}
8585

86+
func metadataTagName(_ tag: swift_metadata_allocation_tag_t) -> String? {
87+
swift_reflection_metadataAllocationTagName(self, tag)
88+
.map(String.init)
89+
}
90+
91+
func metadataAllocationCacheNode(
92+
_ allocation: swift_metadata_allocation_t
93+
) -> swift_metadata_cache_node_t? {
94+
var node = swift_metadata_cache_node_t();
95+
let success = swift_reflection_metadataAllocationCacheNode(
96+
self, allocation, &node)
97+
if success == 0 {
98+
return nil
99+
}
100+
return node
101+
}
102+
86103
private func throwError(str: UnsafePointer<CChar>?) throws {
87104
if let str = str {
88105
throw Error(cString: str)

tools/swift-inspect/Sources/swift-inspect/main.swift

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ func dumpRawMetadata(
4040
) throws {
4141
let backtraces = backtraceStyle != nil ? context.allocationBacktraces : [:]
4242
for allocation in context.allocations {
43-
let tagNameC = swift_reflection_metadataAllocationTagName(context, allocation.tag)
44-
let tagName = tagNameC.map(String.init) ?? "<unknown>"
43+
let tagName = context.metadataTagName(allocation.tag) ?? "<unknown>"
4544
print("Metadata allocation at: \(hex: allocation.ptr) " +
4645
"size: \(allocation.size) tag: \(allocation.tag) (\(tagName))")
4746
printBacktrace(style: backtraceStyle, for: allocation.ptr, in: backtraces, inspector: inspector)
@@ -74,6 +73,22 @@ func dumpGenericMetadata(
7473
}
7574
}
7675

76+
func dumpMetadataCacheNodes(
77+
context: SwiftReflectionContextRef,
78+
inspector: Inspector
79+
) throws {
80+
print("Address","Tag","Tag Name","Size","Left","Right", separator: "\t")
81+
for allocation in context.allocations {
82+
guard let node = context.metadataAllocationCacheNode(allocation.allocation_t) else {
83+
continue
84+
}
85+
86+
let tagName = context.metadataTagName(allocation.tag) ?? "<unknown>"
87+
print("\(hex: allocation.ptr)\t\(allocation.tag)\t\(tagName)\t" +
88+
"\(allocation.size)\t\(hex: node.Left)\t\(hex: node.Right)")
89+
}
90+
}
91+
7792
func printBacktrace(
7893
style: Backtrace.Style?,
7994
for ptr: swift_reflection_ptr_t,
@@ -133,18 +148,38 @@ struct SwiftInspect: ParsableCommand {
133148
DumpConformanceCache.self,
134149
DumpRawMetadata.self,
135150
DumpGenericMetadata.self,
151+
DumpCacheNodes.self,
136152
])
137153
}
138154

155+
struct UniversalOptions: ParsableArguments {
156+
@Argument(help: "The pid or partial name of the target process")
157+
var nameOrPid: String
158+
}
159+
160+
struct BacktraceOptions: ParsableArguments {
161+
@Flag(help: "Show the backtrace for each allocation")
162+
var backtrace: Bool
163+
164+
@Flag(help: "Show a long-form backtrace for each allocation")
165+
var backtraceLong: Bool
166+
167+
var style: Backtrace.Style? {
168+
backtrace ? .oneLine :
169+
backtraceLong ? .long :
170+
nil
171+
}
172+
}
173+
139174
struct DumpConformanceCache: ParsableCommand {
140175
static let configuration = CommandConfiguration(
141176
abstract: "Print the contents of the target's protocol conformance cache.")
142177

143-
@Argument(help: "The pid or partial name of the target process")
144-
var nameOrPid: String
178+
@OptionGroup()
179+
var options: UniversalOptions
145180

146181
func run() throws {
147-
try withReflectionContext(nameOrPid: nameOrPid) { context, _ in
182+
try withReflectionContext(nameOrPid: options.nameOrPid) { context, _ in
148183
try dumpConformanceCache(context: context)
149184
}
150185
}
@@ -153,22 +188,18 @@ struct DumpConformanceCache: ParsableCommand {
153188
struct DumpRawMetadata: ParsableCommand {
154189
static let configuration = CommandConfiguration(
155190
abstract: "Print the target's metadata allocations.")
156-
@Argument(help: "The pid or partial name of the target process")
157-
158-
var nameOrPid: String
159191

160-
@Flag(help: "Show the backtrace for each allocation")
161-
var backtrace: Bool
192+
@OptionGroup()
193+
var universalOptions: UniversalOptions
162194

163-
@Flag(help: "Show a long-form backtrace for each allocation")
164-
var backtraceLong: Bool
195+
@OptionGroup()
196+
var backtraceOptions: BacktraceOptions
165197

166198
func run() throws {
167-
let style = backtrace ? Backtrace.Style.oneLine :
168-
backtraceLong ? Backtrace.Style.long :
169-
nil
170-
try withReflectionContext(nameOrPid: nameOrPid) {
171-
try dumpRawMetadata(context: $0, inspector: $1, backtraceStyle: style)
199+
try withReflectionContext(nameOrPid: universalOptions.nameOrPid) {
200+
try dumpRawMetadata(context: $0,
201+
inspector: $1,
202+
backtraceStyle: backtraceOptions.style)
172203
}
173204
}
174205
}
@@ -177,23 +208,32 @@ struct DumpGenericMetadata: ParsableCommand {
177208
static let configuration = CommandConfiguration(
178209
abstract: "Print the target's generic metadata allocations.")
179210

180-
@Argument(help: "The pid or partial name of the target process")
181-
var nameOrPid: String
211+
@OptionGroup()
212+
var universalOptions: UniversalOptions
182213

183-
@Flag(help: "Show the backtrace for each allocation")
184-
var backtrace: Bool
185-
186-
@Flag(help: "Show a long-form backtrace for each allocation")
187-
var backtraceLong: Bool
214+
@OptionGroup()
215+
var backtraceOptions: BacktraceOptions
188216

189217
func run() throws {
190-
let style = backtrace ? Backtrace.Style.oneLine :
191-
backtraceLong ? Backtrace.Style.long :
192-
nil
193-
try withReflectionContext(nameOrPid: nameOrPid) {
218+
try withReflectionContext(nameOrPid: universalOptions.nameOrPid) {
194219
try dumpGenericMetadata(context: $0,
195220
inspector: $1,
196-
backtraceStyle: style)
221+
backtraceStyle: backtraceOptions.style)
222+
}
223+
}
224+
}
225+
226+
struct DumpCacheNodes: ParsableCommand {
227+
static let configuration = CommandConfiguration(
228+
abstract: "Print the target's metadata cache nodes.")
229+
230+
@OptionGroup()
231+
var options: UniversalOptions
232+
233+
func run() throws {
234+
try withReflectionContext(nameOrPid: options.nameOrPid) {
235+
try dumpMetadataCacheNodes(context: $0,
236+
inspector: $1)
197237
}
198238
}
199239
}

0 commit comments

Comments
 (0)