@@ -17,53 +17,37 @@ import LinuxSystemHeaders
1717// currently private to swift/stdlib/public/Backtrace.
1818class ElfFile {
1919 public enum ELFError : Error {
20- case readFailure( _ filePath: String , offset: UInt64 , size: UInt64 )
2120 case notELF64( _ filePath: String , _ description: String = " " )
2221 case malformedFile( _ filePath: String , _ description: String = " " )
2322 }
2423
2524 public typealias SymbolMap = [ String : ( start: UInt64 , end: UInt64 ) ]
2625
2726 let filePath : String
28- let file : FileHandle
27+ let fileData : Data
2928 let ehdr : Elf64_Ehdr
3029
3130 public init ( filePath: String ) throws {
3231 self . filePath = filePath
3332
34- let file = try FileHandle ( forReadingFrom : URL ( fileURLWithPath: filePath) )
35- self . file = file
33+ let fileData = try Data ( contentsOf : URL ( fileURLWithPath: filePath) , options : . alwaysMapped )
34+ self . fileData = fileData
3635
3736 let identLen = Int ( EI_NIDENT)
38- file. seek ( toFileOffset: 0 )
39- guard let identData = try file. read ( upToCount: identLen) , identData. count == identLen else {
40- file. closeFile ( )
41- throw ELFError . readFailure ( filePath, offset: 0 , size: UInt64 ( identLen) )
42- }
43-
44- let identMagic = String ( bytes: identData. prefix ( Int ( SELFMAG) ) , encoding: . utf8)
37+ let identMagic = String ( bytes: fileData [ 0 ..< identLen] . prefix ( Int ( SELFMAG) ) , encoding: . utf8)
4538 guard identMagic == ELFMAG else {
46- file. closeFile ( )
4739 throw ELFError . notELF64 ( filePath)
4840 }
4941
50- let identClass = identData [ Int ( EI_CLASS) ]
42+ let identClass = fileData [ Int ( EI_CLASS) ]
5143 guard identClass == ELFCLASS64 else {
5244 throw ELFError . notELF64 ( filePath, " \( identClass) != ELFCLASS64 " )
5345 }
5446
5547 let ehdrSize = MemoryLayout< Elf64_Ehdr> . size
56- file. seek ( toFileOffset: 0 )
57- guard let ehdrData = try file. read ( upToCount: ehdrSize) , ehdrData. count == ehdrSize else {
58- file. closeFile ( )
59- throw ELFError . readFailure ( filePath, offset: 0 , size: UInt64 ( ehdrSize) )
60- }
61-
62- self . ehdr = ehdrData. withUnsafeBytes { $0. load ( as: Elf64_Ehdr . self) }
48+ self . ehdr = fileData [ 0 ..< ehdrSize] . withUnsafeBytes { $0. load ( as: Elf64_Ehdr . self) }
6349 }
6450
65- deinit { self . file. closeFile ( ) }
66-
6751 // returns a map of symbol names to their offset range in file (+ baseAddress)
6852 public func loadSymbols( baseAddress: UInt64 = 0 ) throws -> SymbolMap {
6953 guard let sectionCount = UInt ( exactly: self . ehdr. e_shnum) else {
@@ -73,11 +57,11 @@ class ElfFile {
7357
7458 var symbols : SymbolMap = [ : ]
7559 for sectionIndex in 0 ..< sectionCount {
76- let shdr : Elf64_Shdr = try self . readShdr ( index: sectionIndex)
60+ let shdr : Elf64_Shdr = try self . loadShdr ( index: sectionIndex)
7761 guard shdr. sh_type == SHT_SYMTAB || shdr. sh_type == SHT_DYNSYM else { continue }
7862
79- let sectionData : Data = try self . readSection ( shdr)
80- let symTable : [ Elf64_Sym ] = sectionData . withUnsafeBytes {
63+ let symTableData : Data = try self . loadSection ( shdr)
64+ let symTable : [ Elf64_Sym ] = symTableData . withUnsafeBytes {
8165 Array ( $0. bindMemory ( to: Elf64_Sym . self) )
8266 }
8367
@@ -91,13 +75,16 @@ class ElfFile {
9175 throw ELFError . malformedFile ( self . filePath, " invalid Elf64_Shdr.sh_link: \( shdr. sh_link) " )
9276 }
9377
94- let shdrLink : Elf64_Shdr = try self . readShdr ( index: UInt ( linkIndex) )
78+ let shdrLink : Elf64_Shdr = try self . loadShdr ( index: UInt ( linkIndex) )
9579 guard shdrLink. sh_type == SHT_STRTAB else {
9680 throw ELFError . malformedFile ( self . filePath, " linked section not SHT_STRTAB " )
9781 }
9882
9983 // load the entire contents of the string table into memory
100- let strTable : Data = try self . readSection ( shdrLink)
84+ let strTableData : Data = try self . loadSection ( shdrLink)
85+ let strTable : [ UInt8 ] = strTableData. withUnsafeBytes {
86+ Array ( $0. bindMemory ( to: UInt8 . self) )
87+ }
10188
10289 let symCount = Int ( shdr. sh_size / shdr. sh_entsize)
10390 for symIndex in 0 ..< symCount {
@@ -110,7 +97,7 @@ class ElfFile {
11097 }
11198
11299 guard let strEnd = strTable [ strStart... ] . firstIndex ( of: 0 ) ,
113- let symName = String ( data : strTable [ strStart..< strEnd] , encoding: . utf8)
100+ let symName = String ( bytes : strTable [ strStart..< strEnd] , encoding: . utf8)
114101 else {
115102 throw ELFError . malformedFile ( self . filePath, " invalid string @ offset \( strStart) " )
116103 }
@@ -124,8 +111,8 @@ class ElfFile {
124111 return symbols
125112 }
126113
127- // reads and returns the Elf64_Shdr at the specified index
128- internal func readShdr ( index: UInt ) throws -> Elf64_Shdr {
114+ // returns the Elf64_Shdr at the specified index
115+ internal func loadShdr ( index: UInt ) throws -> Elf64_Shdr {
129116 guard index < self . ehdr. e_shnum else {
130117 throw ELFError . malformedFile (
131118 self . filePath, " section index \( index) >= Elf64_Ehdr.e_shnum \( self . ehdr. e_shnum) ) " )
@@ -136,27 +123,22 @@ class ElfFile {
136123 throw ELFError . malformedFile ( self . filePath, " Elf64_Ehdr.e_shentsize != \( shdrSize) " )
137124 }
138125
139- let shdrOffset : UInt64 = self . ehdr. e_shoff + UInt64( index) * UInt64( shdrSize)
140- self . file. seek ( toFileOffset: shdrOffset)
141- guard let shdrData = try self . file. read ( upToCount: shdrSize) , shdrData. count == shdrSize else {
142- throw ELFError . readFailure ( self . filePath, offset: shdrOffset, size: UInt64 ( shdrSize) )
143- }
144-
126+ let shdrOffset = Int ( self . ehdr. e_shoff) + Int( index) * shdrSize
127+ let shdrData = self . fileData [ shdrOffset..< ( shdrOffset + shdrSize) ]
145128 return shdrData. withUnsafeBytes { $0. load ( as: Elf64_Shdr . self) }
146129 }
147130
148- // reads and returns all data in the specified section
149- internal func readSection ( _ shdr: Elf64_Shdr ) throws -> Data {
131+ // returns all data in the specified section
132+ internal func loadSection ( _ shdr: Elf64_Shdr ) throws -> Data {
150133 guard let sectionSize = Int ( exactly: shdr. sh_size) else {
151134 throw ELFError . malformedFile ( self . filePath, " Elf64_Shdr.sh_size too large \( shdr. sh_size) " )
152135 }
153136
154- let fileOffset = shdr. sh_offset
155- self . file. seek ( toFileOffset: fileOffset)
156- guard let data = try self . file. read ( upToCount: sectionSize) , data. count == sectionSize else {
157- throw ELFError . readFailure ( self . filePath, offset: fileOffset, size: UInt64 ( sectionSize) )
137+ guard let fileOffset = Int ( exactly: shdr. sh_offset) else {
138+ throw ELFError . malformedFile (
139+ self . filePath, " Elf64_Shdr.sh_offset too large \( shdr. sh_offset) " )
158140 }
159141
160- return data
142+ return self . fileData [ fileOffset ..< ( fileOffset + sectionSize ) ]
161143 }
162144}
0 commit comments