@@ -218,36 +218,46 @@ extension MachOFile {
218
218
public var indirectSymbols : IndirectSymbols ? {
219
219
guard let dysymtab = loadCommands. dysymtab else { return nil }
220
220
221
- let offset : UInt64 = numericCast ( headerStartOffset ) + numericCast ( dysymtab. indirectsymoff)
221
+ let offset : UInt64 = numericCast ( dysymtab. indirectsymoff)
222
222
let numberOfElements : Int = numericCast ( dysymtab. nindirectsyms)
223
223
224
- return fileHandle . readDataSequence (
225
- offset: offset,
226
- numberOfElements : numberOfElements,
227
- swapHandler : { data in
228
- guard self . isSwapped else { return }
229
- data . withUnsafeMutableBytes {
230
- let buffer = $0 . assumingMemoryBound ( to : UInt32 . self )
231
- for i in 0 ..< numberOfElements {
232
- buffer [ i ] = buffer [ i ] . byteSwapped
233
- }
224
+ guard var data = _readLinkEditData (
225
+ offset: numericCast ( offset) ,
226
+ length : MemoryLayout < UInt32 > . size * numberOfElements
227
+ ) else { return nil }
228
+
229
+ if isSwapped {
230
+ data . withUnsafeMutableBytes {
231
+ let buffer = $0 . assumingMemoryBound ( to : UInt32 . self )
232
+ for i in 0 ..< numberOfElements {
233
+ buffer [ i ] = buffer [ i ] . byteSwapped
234
234
}
235
235
}
236
+ }
237
+
238
+ return . init(
239
+ data: data,
240
+ numberOfElements: numberOfElements
236
241
)
237
242
}
238
243
}
239
244
240
245
extension MachOFile {
241
246
public var symbolStrings : Strings ? {
242
- if let symtab = loadCommands. symtab {
243
- return Strings (
244
- machO: self ,
245
- offset: headerStartOffset + Int( symtab. stroff) ,
246
- size: Int ( symtab. strsize) ,
247
- isSwapped: isSwapped
248
- )
247
+ guard let symtab = loadCommands. symtab else {
248
+ return nil
249
249
}
250
- return nil
250
+ guard let fileSlice = _fileSliceForLinkEditData (
251
+ offset: numericCast ( symtab. stroff) ,
252
+ length: numericCast ( symtab. strsize)
253
+ ) else { return nil }
254
+
255
+ return . init(
256
+ fileSlice: fileSlice,
257
+ offset: numericCast ( symtab. stroff) ,
258
+ size: numericCast ( symtab. strsize) ,
259
+ isSwapped: isSwapped
260
+ )
251
261
}
252
262
}
253
263
@@ -421,8 +431,13 @@ extension MachOFile {
421
431
return nil
422
432
}
423
433
424
- let entries : DataSequence < DataInCodeEntry > = fileHandle. readDataSequence (
425
- offset: numericCast ( headerStartOffset) + numericCast( dataInCode. dataoff) ,
434
+ guard let data = _readLinkEditData (
435
+ offset: numericCast ( dataInCode. dataoff) ,
436
+ length: numericCast ( dataInCode. datasize)
437
+ ) else { return nil }
438
+
439
+ let entries : DataSequence < DataInCodeEntry > = . init(
440
+ data: data,
426
441
numberOfElements: numericCast ( dataInCode. datasize) / DataInCodeEntry. layoutSize
427
442
)
428
443
@@ -449,12 +464,13 @@ extension MachOFile {
449
464
guard let info = loadCommands. dyldChainedFixups else {
450
465
return nil
451
466
}
467
+ guard let fileSlice = _fileSliceForLinkEditData (
468
+ offset: numericCast ( info. dataoff) ,
469
+ length: numericCast ( info. datasize)
470
+ ) else { return nil }
452
471
453
472
return . init(
454
- fileSice: try ! fileHandle. fileSlice (
455
- offset: headerStartOffset + numericCast( info. dataoff) ,
456
- length: numericCast ( info. datasize)
457
- ) ,
473
+ fileSice: fileSlice,
458
474
isSwapped: isSwapped
459
475
)
460
476
}
@@ -465,18 +481,27 @@ extension MachOFile {
465
481
guard let dysymtab = loadCommands. dysymtab else {
466
482
return nil
467
483
}
468
- return fileHandle. readDataSequence (
469
- offset: numericCast ( dysymtab. extreloff) ,
470
- numberOfElements: numericCast ( dysymtab. nextrel) ,
471
- swapHandler: { data in
472
- guard self . isSwapped else { return }
473
- data. withUnsafeMutableBytes {
474
- guard let baseAddress = $0. baseAddress else { return }
475
- let ptr = baseAddress
476
- . assumingMemoryBound ( to: relocation_info. self)
477
- swap_relocation_info ( ptr, dysymtab. nextrel, NXHostByteOrder ( ) )
478
- }
484
+
485
+ let offset : UInt64 = numericCast ( dysymtab. extreloff)
486
+ let numberOfElements : Int = numericCast ( dysymtab. nextrel)
487
+
488
+ guard var data = _readLinkEditData (
489
+ offset: numericCast ( offset) ,
490
+ length: MemoryLayout < UInt64 > . size * numberOfElements
491
+ ) else { return nil }
492
+
493
+ if isSwapped {
494
+ data. withUnsafeMutableBytes {
495
+ guard let baseAddress = $0. baseAddress else { return }
496
+ let ptr = baseAddress
497
+ . assumingMemoryBound ( to: relocation_info. self)
498
+ swap_relocation_info ( ptr, dysymtab. nextrel, NXHostByteOrder ( ) )
479
499
}
500
+ }
501
+
502
+ return . init(
503
+ data: data,
504
+ numberOfElements: numberOfElements
480
505
)
481
506
}
482
507
@@ -508,11 +533,13 @@ extension MachOFile {
508
533
guard let info = loadCommands. codeSignature else {
509
534
return nil
510
535
}
536
+ guard let fileSlice = _fileSliceForLinkEditData (
537
+ offset: numericCast ( info. dataoff) ,
538
+ length: numericCast ( info. datasize)
539
+ ) else { return nil }
540
+
511
541
return . init(
512
- fileSice: try ! fileHandle. fileSlice (
513
- offset: headerStartOffset + numericCast( info. dataoff) ,
514
- length: numericCast ( info. datasize)
515
- )
542
+ fileSice: fileSlice
516
543
)
517
544
}
518
545
}
@@ -522,6 +549,18 @@ extension MachOFile {
522
549
public var isLoadedFromDyldCache : Bool {
523
550
headerStartOffsetInCache > 0
524
551
}
552
+
553
+ internal var cache : DyldCache ? {
554
+ try ? . init( url: url)
555
+ }
556
+
557
+ internal var fullCache : FullDyldCache ? {
558
+ try ? . init(
559
+ url: url
560
+ . deletingPathExtension ( )
561
+ . deletingPathExtension ( )
562
+ )
563
+ }
525
564
}
526
565
527
566
extension MachOFile {
@@ -587,11 +626,67 @@ extension MachOFile {
587
626
}
588
627
}
589
628
629
+ extension MachOFile {
630
+ internal func _fileSliceForLinkEditData(
631
+ offset: Int , // linkedit_data_command->dataoff (linkedit.fileoff + x)
632
+ length: Int
633
+ ) -> File . FileSlice ? {
634
+ let linkedit : ( any SegmentCommandProtocol ) ? = loadCommands. linkedit64 ?? loadCommands. linkedit
635
+ guard let linkedit else { return nil }
636
+ guard linkedit. fileOffset + linkedit. fileSize >= offset + length else { return nil }
637
+
638
+ // The linkeditdata in iOS is stored together in a separate, independent cache.
639
+ // (.0x.linkeditdata)
640
+ if isLoadedFromDyldCache {
641
+ let offset = offset - numericCast( linkedit. fileOffset)
642
+ guard let fullCache = self . fullCache,
643
+ let fileOffset = fullCache. fileOffset (
644
+ of: numericCast ( linkedit. virtualMemoryAddress + offset)
645
+ ) ,
646
+ let ( _, segment) = fullCache. urlAndFileSegment (
647
+ forOffset: fileOffset
648
+ ) else {
649
+ return nil
650
+ }
651
+ return try ? segment. _file. fileSlice (
652
+ offset: numericCast ( fileOffset) - segment. offset,
653
+ length: length
654
+ )
655
+ } else {
656
+ return try ? fileHandle. fileSlice (
657
+ offset: headerStartOffset + offset,
658
+ length: length
659
+ )
660
+ }
661
+ }
662
+
663
+ /// Reads the data in the linkedit segment appropriately.
664
+ ///
665
+ /// The linkedit data in the machO file obtained from the dyld cache may be separated in a separate sub cache file.
666
+ /// (e.g. dyld cache in iOS except Simulator)
667
+ ///
668
+ /// The data related to the following load command exists in linkedit.
669
+ /// - symtab
670
+ /// - dysymtab
671
+ /// - linkedit_data_command
672
+ /// - exports trie
673
+ public func _readLinkEditData(
674
+ offset: Int , // linkedit_data_command->dataoff (linkedit.fileoff + x)
675
+ length: Int
676
+ ) -> Data ? {
677
+ guard let fileSlice = _fileSliceForLinkEditData (
678
+ offset: offset,
679
+ length: length
680
+ ) else { return nil }
681
+ return try ? fileSlice. readAllData ( )
682
+ }
683
+ }
684
+
590
685
extension MachOFile {
591
686
// https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/common/MetadataVisitor.cpp#L262
592
687
public func resolveRebase( at offset: UInt64 ) -> UInt64 ? {
593
688
if isLoadedFromDyldCache,
594
- let cache = try ? DyldCache ( url : url ) {
689
+ let cache = self . cache {
595
690
return cache. resolveRebase ( at: offset)
596
691
}
597
692
@@ -609,7 +704,7 @@ extension MachOFile {
609
704
610
705
public func resolveOptionalRebase( at offset: UInt64 ) -> UInt64 ? {
611
706
if isLoadedFromDyldCache,
612
- let cache = try ? DyldCache ( url : url ) {
707
+ let cache = self . cache {
613
708
return cache. resolveOptionalRebase ( at: offset)
614
709
}
615
710
@@ -759,7 +854,7 @@ extension MachOFile {
759
854
}
760
855
761
856
if header. isInDyldCache,
762
- let cache = try ? DyldCache ( url : url ) {
857
+ let cache = self . cache {
763
858
return cache. header. platform == . macOS
764
859
}
765
860
0 commit comments