Skip to content

Commit 4440bd4

Browse files
authored
Merge pull request #40055 from mikeash/swift-inspect-dump-arrays
[swift-inspect] Add a command to dump information about allocated arrays in the target process.
2 parents 299f9fa + 9fa76e2 commit 4440bd4

File tree

7 files changed

+94
-9
lines changed

7 files changed

+94
-9
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ class Node {
243243
return getChild(getNumChildren() - 1);
244244
}
245245
NodePointer getChild(size_t index) const {
246-
assert(getNumChildren() > index);
246+
if (index >= getNumChildren())
247+
return nullptr;
247248
return begin()[index];
248249
}
249250

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,11 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
11581158
return nullptr;
11591159
}
11601160

1161+
if (!Node) {
1162+
Printer << "<null node pointer>";
1163+
return nullptr;
1164+
}
1165+
11611166
switch (auto kind = Node->getKind()) {
11621167
case Node::Kind::Static:
11631168
Printer << "static ";

tools/swift-inspect/Sources/SymbolicationShims/SymbolicationShims.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct Range {
2121
uintptr_t location, length;
2222
};
2323

24-
uintptr_t GetPtrauthMask(void) {
24+
static inline uintptr_t GetPtrauthMask(void) {
2525
#if __has_feature(ptrauth_calls)
2626
return (uintptr_t)ptrauth_strip((void*)0x0007ffffffffffff, 0);
2727
#else

tools/swift-inspect/Sources/swift-inspect/Inspector.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@ class Inspector {
3535
}
3636

3737
func addReflectionInfoFromLoadedImages(context: SwiftReflectionContextRef) {
38-
var numSuccessfulImages = 0
39-
CSSymbolicatorForeachSymbolOwnerAtTime(symbolicator, kCSNow, { owner in
38+
_ = CSSymbolicatorForeachSymbolOwnerAtTime(symbolicator, kCSNow, { owner in
4039
let address = CSSymbolOwnerGetBaseAddress(owner);
41-
let name = CSSymbolOwnerGetName(owner)
4240
let _ = swift_reflection_addImage(context, address)
4341
})
4442
}
@@ -89,6 +87,25 @@ class Inspector {
8987
CSSymbolOwnerGetName(CSSymbolGetSymbolOwner(symbol)))
9088
}
9189

90+
func enumerateMallocs(callback: (swift_addr_t, UInt64) -> Void) {
91+
withoutActuallyEscaping(callback) {
92+
withUnsafePointer(to: $0) {
93+
task_enumerate_malloc_blocks(task, UnsafeMutableRawPointer(mutating: $0), CUnsignedInt(MALLOC_PTR_IN_USE_RANGE_TYPE), {
94+
(task, context, type, ranges, count) in
95+
let callback = context!.assumingMemoryBound(to: ((swift_addr_t, UInt64) -> Void).self).pointee
96+
for i in 0..<Int(count) {
97+
let range = ranges[i]
98+
callback(swift_addr_t(range.address), UInt64(range.size))
99+
}
100+
})
101+
}
102+
}
103+
}
104+
105+
func read(address: swift_addr_t, size: Int) -> UnsafeRawPointer? {
106+
return task_peek(task, address, mach_vm_size_t(size))
107+
}
108+
92109
enum Callbacks {
93110
static let QueryDataLayout: @convention(c)
94111
(UnsafeMutableRawPointer?,

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ extension SwiftReflectionContextRef {
3131
return String(cString: cstr)
3232
}
3333

34-
func isAContiguousArrayOfClassElementType(metadata: swift_reflection_ptr_t) ->
34+
func isAContiguousArray(metadata: swift_reflection_ptr_t) ->
3535
Bool {
3636
guard let name = name(metadata: metadata) else { return false }
37-
guard name.starts(with: "Swift._ContiguousArrayStorage") else {
38-
return false
39-
}
37+
return name.starts(with: "Swift._ContiguousArrayStorage")
38+
}
39+
40+
func isAContiguousArrayOfClassElementType(metadata: swift_reflection_ptr_t) ->
41+
Bool {
42+
guard isAContiguousArray(metadata: metadata) else { return false }
4043
let tr = swift_reflection_typeRefForMetadata(self, UInt(metadata));
4144
guard tr != 0 else {
4245
return false
@@ -54,6 +57,17 @@ extension SwiftReflectionContextRef {
5457
return typeInfo.Kind == SWIFT_STRONG_REFERENCE
5558
}
5659

60+
func arrayCount(
61+
array: swift_reflection_ptr_t,
62+
reader: (swift_addr_t, Int) -> UnsafeRawPointer?
63+
) -> UInt? {
64+
let size = MemoryLayout<UInt>.stride * 3
65+
guard let ptr = reader(array, size) else { return nil }
66+
let typedPtr = ptr.bindMemory(to: UInt.self, capacity: 3)
67+
// Array layout goes: metadata, refcount, count
68+
return typedPtr[2]
69+
}
70+
5771
func name(proto: swift_reflection_ptr_t) -> String? {
5872
guard let cstr = swift_reflection_copyDemangledNameForProtocolDescriptor(
5973
self, proto) else { return nil }

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ func dumpMetadataCacheNodes(
9090
}
9191
}
9292

93+
func dumpArrays(
94+
context: SwiftReflectionContextRef,
95+
inspector: Inspector
96+
) throws {
97+
print("Address","Size","Count","Is Class", separator: "\t")
98+
inspector.enumerateMallocs(callback: { (pointer, size) in
99+
let metadata = swift_reflection_ptr_t(swift_reflection_metadataForObject(context, UInt(pointer)))
100+
guard metadata != 0 else { return }
101+
guard context.isAContiguousArray(metadata: metadata) else { return }
102+
let isClass = context.isAContiguousArrayOfClassElementType(metadata: metadata)
103+
let count = context.arrayCount(array: pointer, reader: inspector.read)
104+
let countStr = count.map({ String($0) }) ?? "<unknown>"
105+
print("\(hex: pointer)\t\(size)\t\(countStr)\t\(isClass)")
106+
})
107+
}
108+
93109
func printBacktrace(
94110
style: Backtrace.Style?,
95111
for ptr: swift_reflection_ptr_t,
@@ -152,6 +168,7 @@ struct SwiftInspect: ParsableCommand {
152168
DumpRawMetadata.self,
153169
DumpGenericMetadata.self,
154170
DumpCacheNodes.self,
171+
DumpArrays.self,
155172
])
156173
}
157174

@@ -241,4 +258,18 @@ struct DumpCacheNodes: ParsableCommand {
241258
}
242259
}
243260

261+
struct DumpArrays: ParsableCommand {
262+
static let configuration = CommandConfiguration(
263+
abstract: "Print the target's metadata cache nodes.")
264+
265+
@OptionGroup()
266+
var options: UniversalOptions
267+
268+
func run() throws {
269+
try withReflectionContext(nameOrPid: options.nameOrPid) {
270+
try dumpArrays(context: $0, inspector: $1)
271+
}
272+
}
273+
}
274+
244275
SwiftInspect.main()

tools/swift-inspect/Sources/swift-inspect/symbolication.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ enum Sym {
7070
static let task_stop_peeking: @convention(c) (task_t) -> kern_return_t =
7171
symbol(symbolicationHandle, "task_stop_peeking")
7272

73+
typealias vm_range_recorder_t =
74+
@convention(c) (task_t, UnsafeMutableRawPointer?, CUnsignedInt,
75+
UnsafeMutablePointer<vm_range_t>, CUnsignedInt) -> Void
76+
static let task_enumerate_malloc_blocks:
77+
@convention(c) (task_t, UnsafeMutableRawPointer?, CUnsignedInt, vm_range_recorder_t)
78+
-> Void =
79+
symbol(symbolicationHandle, "task_enumerate_malloc_blocks")
80+
7381
static let CSSymbolicatorForeachSymbolOwnerAtTime:
7482
@convention(c) (CSSymbolicatorRef, CSMachineTime, @convention(block) (CSSymbolOwnerRef) -> Void) -> UInt =
7583
symbol(coreSymbolicationHandle, "CSSymbolicatorForeachSymbolOwnerAtTime")
@@ -196,3 +204,12 @@ func task_peek_string(
196204
func task_stop_peeking(_ task: task_t) {
197205
_ = Sym.task_stop_peeking(task)
198206
}
207+
208+
func task_enumerate_malloc_blocks(
209+
_ task: task_t,
210+
_ context: UnsafeMutableRawPointer?,
211+
_ type_mask: CUnsignedInt,
212+
_ recorder: Sym.vm_range_recorder_t
213+
) {
214+
Sym.task_enumerate_malloc_blocks(task, context, type_mask, recorder)
215+
}

0 commit comments

Comments
 (0)