Skip to content

Commit 18ec9bf

Browse files
committed
swift-inspect: enable dump-arrays on Windows
Hoist `iterateHeaps` into the `RemoteProcess` protocol, requiring an implementation on all platforms. If the platform is unable to implement heap traversal, it would be possible to simply leave the callback uncalled. Be more careful about memory queries, we may receive invalid memory addresses.
1 parent 10f3828 commit 18ec9bf

File tree

6 files changed

+54
-12
lines changed

6 files changed

+54
-12
lines changed

tools/swift-inspect/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ The following inspection operations are available currently.
2222

2323
##### All Platforms
2424

25+
dump-arrays <name-or-pid>
26+
: Print information about array objects in the target
27+
2528
dump-cache-nodes <name-or-pid>
2629
: Print the metadata cache nodes.
2730

@@ -36,8 +39,5 @@ dump-raw-metadata <name-or-pid> [--backtrace] [--backtrace-long]
3639

3740
##### Darwin Only
3841

39-
dump-arrays <name-or-pid>
40-
: Print information about array objects in the target
41-
4242
dump-concurrency <name-or-pid>
43-
: Print information about tasks, actors, and threads under Concurrency.
43+
: Print information about tasks, actors, and threads under Concurrency.

tools/swift-inspect/Sources/swift-inspect/DarwinRemoteProcess.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,7 @@ internal final class DarwinRemoteProcess: RemoteProcess {
141141
let module = CSSymbolGetSymbolOwner(symbol)
142142
return (CSSymbolOwnerGetName(module), CSSymbolGetName(symbol))
143143
}
144-
}
145144

146-
extension DarwinRemoteProcess {
147145
internal func iterateHeap(_ body: (swift_addr_t, UInt64) -> Void) {
148146
withoutActuallyEscaping(body) {
149147
withUnsafePointer(to: $0) {
@@ -160,7 +158,9 @@ extension DarwinRemoteProcess {
160158
}
161159
}
162160
}
161+
}
163162

163+
extension DarwinRemoteProcess {
164164
internal var currentTasks: [(threadID: UInt64, currentTask: swift_addr_t)] {
165165
var threadList: UnsafeMutablePointer<thread_t>?
166166
var threadCount: mach_msg_type_number_t = 0

tools/swift-inspect/Sources/swift-inspect/Operations/DumpArray.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
1413
import ArgumentParser
1514
import SwiftRemoteMirror
1615

@@ -28,6 +27,7 @@ internal struct DumpArrays: ParsableCommand {
2827
let metadata: UInt =
2928
swift_reflection_metadataForObject(process.context, UInt(allocation))
3029
if metadata == 0 { return }
30+
3131
guard process.context.isContiguousArray(swift_reflection_ptr_t(metadata)) else {
3232
return
3333
}
@@ -44,5 +44,3 @@ internal struct DumpArrays: ParsableCommand {
4444
}
4545
}
4646
}
47-
48-
#endif

tools/swift-inspect/Sources/swift-inspect/RemoteProcess.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ internal protocol RemoteProcess: AnyObject {
4242
static var GetSymbolAddress: GetSymbolAddressFunction { get }
4343

4444
func symbolicate(_ address: swift_addr_t) -> (module: String?, symbol: String?)
45+
func iterateHeap(_ body: (swift_addr_t, UInt64) -> Void)
4546
}
4647

4748
extension RemoteProcess {

tools/swift-inspect/Sources/swift-inspect/WindowsRemoteProcess.swift

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ internal final class WindowsRemoteProcess: RemoteProcess {
7979

8080
var information: WIN32_MEMORY_REGION_INFORMATION =
8181
WIN32_MEMORY_REGION_INFORMATION()
82-
_ = QueryVirtualMemoryInformation(process.process,
82+
if !QueryVirtualMemoryInformation(process.process,
8383
LPVOID(bitPattern: UInt(address)),
8484
MemoryRegionInfo, &information,
8585
SIZE_T(MemoryLayout.size(ofValue: information)),
86-
nil)
86+
nil) {
87+
return 0
88+
}
8789

8890
// FIXME(compnerd) mapping in the memory region from the remote process
8991
// would be ideal to avoid a round-trip for each byte. This seems to work
@@ -123,7 +125,7 @@ internal final class WindowsRemoteProcess: RemoteProcess {
123125
}
124126

125127
init?(processId: ProcessIdentifier) {
126-
// Setup process handle.
128+
// Get process handle.
127129
self.process =
128130
OpenProcess(DWORD(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ), false,
129131
processId)
@@ -223,6 +225,46 @@ internal final class WindowsRemoteProcess: RemoteProcess {
223225

224226
return (context.1, symbol)
225227
}
228+
229+
internal func iterateHeap(_ body: (swift_addr_t, UInt64) -> Void) {
230+
let dwProcessId: DWORD = GetProcessId(self.process)
231+
if dwProcessId == 0 {
232+
// FIXME(compnerd) log error
233+
return
234+
}
235+
236+
let hSnapshot: HANDLE =
237+
CreateToolhelp32Snapshot(DWORD(TH32CS_SNAPHEAPLIST), dwProcessId)
238+
if hSnapshot == INVALID_HANDLE_VALUE {
239+
// FIXME(compnerd) log error
240+
return
241+
}
242+
defer { CloseHandle(hSnapshot) }
243+
244+
var heap: HEAPLIST32 = HEAPLIST32()
245+
heap.dwSize = SIZE_T(MemoryLayout<HEAPLIST32>.size)
246+
if !Heap32ListFirst(hSnapshot, &heap) {
247+
// FIXME(compnerd) log error
248+
return
249+
}
250+
251+
repeat {
252+
var entry: HEAPENTRY32 = HEAPENTRY32()
253+
entry.dwSize = SIZE_T(MemoryLayout<HEAPENTRY32>.size)
254+
255+
if !Heap32First(&entry, dwProcessId, heap.th32HeapID) {
256+
// FIXME(compnerd) log error
257+
continue
258+
}
259+
260+
repeat {
261+
if entry.dwFlags & DWORD(LF32_FREE) == DWORD(LF32_FREE) { continue }
262+
body(swift_addr_t(entry.dwAddress), UInt64(entry.dwBlockSize))
263+
} while Heap32Next(&entry)
264+
265+
heap.dwSize = SIZE_T(MemoryLayout<HEAPLIST32>.size)
266+
} while Heap32ListNext(hSnapshot, &heap)
267+
}
226268
}
227269

228270
#endif

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ internal struct SwiftInspect: ParsableCommand {
7777
DumpRawMetadata.self,
7878
DumpGenericMetadata.self,
7979
DumpCacheNodes.self,
80+
DumpArrays.self,
8081
]
8182
#endif
8283

0 commit comments

Comments
 (0)