@@ -89,6 +89,79 @@ private func _testContentSectionBounds() -> [SectionBounds] {
89
89
#elseif os(Linux) || os(FreeBSD) || os(Android)
90
90
// MARK: - ELF implementation
91
91
92
+ extension UnsafePointer < SWTElfWNhdr > {
93
+ /// The size of the implied `n_name` field, in bytes.
94
+ ///
95
+ /// This value is rounded up to ensure 32-bit alignment of the fields in the
96
+ /// test content header and record.
97
+ fileprivate var n_namesz : Int {
98
+ Int ( max ( 0 , pointee. n_namesz) ) . alignedUp ( for: UInt32 . self)
99
+ }
100
+
101
+ /// Get the implied `n_name` field.
102
+ ///
103
+ /// If this test content header has no name, or if the name is not
104
+ /// null-terminated, the value of this property is `nil`.
105
+ fileprivate var n_name : UnsafePointer < CChar > ? {
106
+ if n_namesz <= 0 {
107
+ return nil
108
+ }
109
+ return ( self + 1 ) . withMemoryRebound ( to: CChar . self, capacity: n_namesz) { name in
110
+ if strnlen ( name, n_namesz) >= n_namesz {
111
+ // There is no trailing null byte within the provided length.
112
+ return nil
113
+ }
114
+ return name
115
+ }
116
+ }
117
+
118
+ /// The size of the implied `n_name` field, in bytes.
119
+ ///
120
+ /// This value is rounded up to ensure 32-bit alignment of the fields in the
121
+ /// test content header and record.
122
+ fileprivate var n_descsz : Int {
123
+ Int ( max ( 0 , pointee. n_descsz) ) . alignedUp ( for: UInt32 . self)
124
+ }
125
+
126
+ /// The implied `n_desc` field.
127
+ ///
128
+ /// If this test content header has no description (payload), the value of
129
+ /// this property is `nil`.
130
+ fileprivate var n_desc : UnsafeRawPointer ? {
131
+ if n_descsz <= 0 {
132
+ return nil
133
+ }
134
+ return UnsafeRawPointer ( self + 1 ) + n_namesz
135
+ }
136
+
137
+ /// The number of bytes in this test content header, including all fields and
138
+ /// padding.
139
+ ///
140
+ /// The address at `UnsafeRawPointer(self) + self.byteCount` is the start of
141
+ /// the next test content header in the same section (if there is one.)
142
+ fileprivate var byteCount : Int {
143
+ MemoryLayout < Pointee > . stride + n_namesz + n_descsz
144
+ }
145
+ }
146
+
147
+ /// All test content headers found in this test content section.
148
+ func _noteHeaders( in buffer: UnsafeRawBufferPointer ) -> some Sequence < UnsafePointer < SWTElfWNhdr > > {
149
+ let start = buffer. baseAddress!
150
+ let end : UnsafeRawPointer = start + buffer. count
151
+ let firstHeader = start. assumingMemoryBound ( to: SWTElfWNhdr . self)
152
+
153
+ // Generate an infinite sequence of (possible) header addresses, then prefix
154
+ // it to those that are actually contained within the section. This way we can
155
+ // bounds-check even the first header while maintaining an opaque return type.
156
+ return sequence ( first: firstHeader) { header in
157
+ ( UnsafeRawPointer ( header) + header. byteCount) . assumingMemoryBound ( to: SWTElfWNhdr . self)
158
+ } . lazy. prefix { header in
159
+ header >= start && header < end
160
+ && ( header + 1 ) <= end
161
+ && UnsafeRawPointer ( header) + header. byteCount <= end
162
+ }
163
+ }
164
+
92
165
/// The ELF-specific implementation of ``SectionBounds/all``.
93
166
///
94
167
/// - Returns: An array of structures describing the bounds of all known test
@@ -97,20 +170,28 @@ private func _testContentSectionBounds() -> [SectionBounds] {
97
170
var result = [ SectionBounds] ( )
98
171
99
172
withUnsafeMutablePointer ( to: & result) { result in
100
- swift_enumerateAllMetadataSections ( { sections, context in
101
- let sections = sections. load ( as: MetadataSections . self)
102
- let result = context. assumingMemoryBound ( to: [ SectionBounds ] . self)
103
-
104
- let start = UnsafeRawPointer ( bitPattern: sections. swift5_tests. start)
105
- let size = Int ( clamping: sections. swift5_tests. length)
106
- if let start, size > 0 {
107
- let buffer = UnsafeRawBufferPointer ( start: start, count: size)
108
- let sb = SectionBounds ( imageAddress: sections. baseAddress, buffer: buffer)
109
- result. pointee. append ( sb)
110
- }
173
+ _ = swt_dl_iterate_phdr ( result) { dlpi_addr, dlpi_phdr, dlpi_phnum, context in
174
+ let result = context!. assumingMemoryBound ( to: [ SectionBounds ] . self)
111
175
112
- return true
113
- } , result)
176
+ let buffer = UnsafeBufferPointer ( start: dlpi_phdr, count: dlpi_phnum)
177
+ let sectionBoundsNotes : some Sequence < UnsafePointer < SWTElfWNhdr > > = buffer. lazy
178
+ . filter { $0. p_type == PT_NOTE }
179
+ . map { phdr in
180
+ UnsafeRawBufferPointer (
181
+ start: dlpi_addr + Int( clamping: UInt ( clamping: phdr. p_vaddr) ) ,
182
+ count: Int ( clamping: phdr. p_memsz)
183
+ )
184
+ } . flatMap ( _noteHeaders ( in: ) )
185
+ . filter { $0. pointee. n_type == 0 }
186
+ . filter { 0 == $0. n_name. map { strcmp ( $0, " swift5_tests " ) } }
187
+
188
+ result. pointee += sectionBoundsNotes. lazy
189
+ . compactMap { $0. n_desc? . assumingMemoryBound ( to: UnsafePointer< UnsafeRawPointer> . self ) }
190
+ . map { UnsafeRawBufferPointer ( start: $0 [ 0 ] , count: $0 [ 1 ] - $0[ 0 ] ) }
191
+ . map { SectionBounds ( imageAddress: dlpi_addr, buffer: $0) }
192
+
193
+ return 0
194
+ }
114
195
}
115
196
116
197
return result
0 commit comments