@@ -55,6 +55,29 @@ private struct Metadata: Encodable {
55
55
}
56
56
}
57
57
58
+ internal struct Output : TextOutputStream {
59
+ let fileHandle : FileHandle
60
+ init ( _ outputFile: String ? = nil ) throws {
61
+ if let outputFile {
62
+ if FileManager ( ) . createFile ( atPath: outputFile, contents: nil ) {
63
+ self . fileHandle = try FileHandle ( forWritingAtPath: outputFile) !
64
+ } else {
65
+ print ( " Unable to create file \( outputFile) " )
66
+ exit ( 1 )
67
+ }
68
+ } else {
69
+ self . fileHandle = FileHandle . standardOutput
70
+ }
71
+ }
72
+
73
+ mutating func write( _ string: String ) {
74
+ if let encodedString = string. data ( using: . utf8) {
75
+ fileHandle. write ( encodedString)
76
+ }
77
+ }
78
+
79
+ }
80
+
58
81
internal struct DumpGenericMetadata : ParsableCommand {
59
82
static let configuration = CommandConfiguration (
60
83
abstract: " Print the target's generic metadata allocations. " )
@@ -96,56 +119,58 @@ internal struct DumpGenericMetadata: ParsableCommand {
96
119
backtrace: currentBacktrace)
97
120
}
98
121
99
- if let outputFile = genericMetadataOptions. outputJson {
100
- try dumpToJson ( process: process, generics: generics,
101
- outputPath: outputFile)
122
+ if genericMetadataOptions. json {
123
+ try dumpJson ( process: process, generics: generics)
102
124
} else {
103
- try dumpToStdout ( process: process, generics: generics)
125
+ try dumpText ( process: process, generics: generics)
104
126
}
105
127
}
106
128
}
107
129
108
- private func dumpToStdout ( process: any RemoteProcess , generics: [ Metadata ] ) throws {
130
+ private func dumpText ( process: any RemoteProcess , generics: [ Metadata ] ) throws {
109
131
var errorneousMetadata : [ ( ptr: swift_reflection_ptr_t , name: String ) ] = [ ]
110
-
111
- print ( " Address " , " Allocation " , " Size " , " Offset " , " isArrayOfClass " , " Name " , separator: " \t " )
132
+ var output = try Output ( genericMetadataOptions . outputFile )
133
+ print ( " Address " , " Allocation " , " Size " , " Offset " , " isArrayOfClass " , " Name " , separator: " \t " , to : & output )
112
134
generics. forEach {
113
- print ( " \( hex: $0. ptr) " , terminator: " \t " )
135
+ print ( " \( hex: $0. ptr) " , terminator: " \t " , to : & output )
114
136
if let allocation = $0. allocation, let offset = $0. offset {
115
- print ( " \( hex: allocation. ptr) \t \( allocation. size) \t \( offset) " , terminator: " \t " )
137
+ print ( " \( hex: allocation. ptr) \t \( allocation. size) \t \( offset) " , terminator: " \t " , to : & output )
116
138
} else {
117
139
if $0. garbage {
118
140
errorneousMetadata. append ( ( ptr: $0. ptr, name: $0. name) )
119
141
}
120
- print ( " ??? \t ?? \t ??? " , terminator: " \t " )
142
+ print ( " ??? \t ?? \t ??? " , terminator: " \t " , to : & output )
121
143
}
122
- print ( $0. isArrayOfClass, terminator: " \t " )
123
- print ( $0. name)
144
+ print ( $0. isArrayOfClass, terminator: " \t " , to : & output )
145
+ print ( $0. name, to : & output )
124
146
if let _ = backtraceOptions. style, let _ = $0. allocation {
125
- print ( $0. backtrace ?? " No stacktrace available " )
147
+ print ( $0. backtrace ?? " No stacktrace available " , to : & output )
126
148
}
127
149
}
128
150
129
151
if errorneousMetadata. count > 0 {
130
- print ( " Error: The following metadata was not found in any DATA or AUTH segments, may be garbage. " )
152
+ print ( " Error: The following metadata was not found in any DATA or AUTH segments, may be garbage. " , to : & output )
131
153
errorneousMetadata. forEach {
132
- print ( " \( hex: $0. ptr) \t \( $0. name) " )
154
+ print ( " \( hex: $0. ptr) \t \( $0. name) " , to : & output )
133
155
}
134
156
}
135
157
}
136
158
137
- private func dumpToJson( process: any RemoteProcess ,
138
- generics: [ Metadata ] ,
139
- outputPath: String ) throws {
159
+ private func dumpJson( process: any RemoteProcess ,
160
+ generics: [ Metadata ] ) throws {
140
161
struct AllMetadataEntries : Encodable {
141
162
var metadata : [ Metadata ]
142
163
}
143
164
let allMetadataEntries = AllMetadataEntries ( metadata: generics)
144
165
let encoder = JSONEncoder ( )
145
166
encoder. outputFormatting = . prettyPrinted
146
167
let data = try encoder. encode ( allMetadataEntries)
147
- try String ( data: data, encoding: . utf8) !
148
- . write ( toFile: outputPath, atomically: true , encoding: . utf8)
168
+ let jsonOutput = String ( data: data, encoding: . utf8) !
169
+ if let outputFile = genericMetadataOptions. outputFile {
170
+ try jsonOutput. write ( toFile: outputFile, atomically: true , encoding: . utf8)
171
+ } else {
172
+ print ( jsonOutput)
173
+ }
149
174
}
150
175
151
176
}
0 commit comments