@@ -89,6 +89,79 @@ private func _testContentSectionBounds() -> [SectionBounds] {
8989#elseif os(Linux) || os(FreeBSD) || os(Android)
9090// MARK: - ELF implementation
9191
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+
92165/// The ELF-specific implementation of ``SectionBounds/all``.
93166///
94167/// - Returns: An array of structures describing the bounds of all known test
@@ -97,20 +170,28 @@ private func _testContentSectionBounds() -> [SectionBounds] {
97170 var result = [ SectionBounds] ( )
98171
99172 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)
111175
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+ }
114195 }
115196
116197 return result
0 commit comments