@@ -40,9 +40,17 @@ type File struct {
4040 exp []trie.TrieExport
4141 exptrieData []byte
4242 binds types.Binds
43- objc map [uint64 ]any
44- swift map [uint64 ]any
45- ledata * bytes.Buffer // tmp storage of linkedit data
43+ rebases []types.Rebase
44+ rebasesDone bool
45+
46+ dyldInfoCacheBuilt bool
47+ dyldInfoRebaseTargets map [uint64 ]uint64
48+ dyldInfoRebaseValues map [uint64 ]struct {}
49+ dyldInfoBindsByAddr map [uint64 ]types.Bind
50+
51+ objc map [uint64 ]any
52+ swift map [uint64 ]any
53+ ledata * bytes.Buffer // tmp storage of linkedit data
4654
4755 sharedCacheRelativeSelectorBaseVMAddress uint64 // objc_opt version 16
4856 swiftAutoDemangle bool
@@ -1618,6 +1626,13 @@ func (f *File) GetPointerAtAddress(address uint64) (uint64, error) {
16181626// lookups will reparse the load command payload.
16191627func (f * File ) ResetFixupsCache () {
16201628 f .dcf = nil
1629+ f .binds = nil
1630+ f .rebases = nil
1631+ f .rebasesDone = false
1632+ f .dyldInfoCacheBuilt = false
1633+ f .dyldInfoRebaseTargets = nil
1634+ f .dyldInfoRebaseValues = nil
1635+ f .dyldInfoBindsByAddr = nil
16211636 if f .vma != nil {
16221637 f .vma .ChainedPointerFormat = 0
16231638 }
@@ -1632,7 +1647,7 @@ func (f *File) GetSlidPointerAtAddress(address uint64) (uint64, error) {
16321647 var raw uint64
16331648 var rawRead bool
16341649
1635- if offErr == nil && f .HasFixups () {
1650+ if offErr == nil && f .HasDyldChainedFixups () {
16361651 dcf , err := f .DyldChainedFixups ()
16371652 if err == nil && dcf != nil {
16381653 if format , fmtErr := dcf .PointerFormatForOffset (offset ); fmtErr == nil {
@@ -1664,11 +1679,15 @@ func (f *File) GetSlidPointerAtAddress(address uint64) (uint64, error) {
16641679 }
16651680 }
16661681
1682+ if resolved , ok := f .decodeDyldInfoPointerAtAddress (address , raw ); ok {
1683+ return resolved , nil
1684+ }
1685+
16671686 return f .SlidePointer (raw ), nil
16681687}
16691688
16701689func (f * File ) decodeChainedPointer (value uint64 ) (uint64 , bool ) {
1671- if value == 0 || ! f .HasFixups () {
1690+ if value == 0 || ! f .HasDyldChainedFixups () {
16721691 return 0 , false
16731692 }
16741693
@@ -1697,11 +1716,115 @@ func (f *File) decodeChainedPointer(value uint64) (uint64, bool) {
16971716 return value , true
16981717}
16991718
1719+ func (f * File ) buildDyldInfoFixupsCache () error {
1720+ if f .dyldInfoCacheBuilt {
1721+ return nil
1722+ }
1723+
1724+ f .dyldInfoRebaseTargets = make (map [uint64 ]uint64 )
1725+ f .dyldInfoRebaseValues = make (map [uint64 ]struct {})
1726+ f .dyldInfoBindsByAddr = make (map [uint64 ]types.Bind )
1727+
1728+ rebases , err := f .GetRebaseInfo ()
1729+ if err != nil && ! errors .Is (err , ErrMachODyldInfoNotFound ) {
1730+ return err
1731+ }
1732+ for _ , rebase := range rebases {
1733+ addr := rebase .Start + rebase .Offset
1734+ f .dyldInfoRebaseTargets [addr ] = f .normalizeDyldInfoPointer (rebase .Value )
1735+ f .dyldInfoRebaseValues [rebase .Value ] = struct {}{}
1736+ }
1737+
1738+ binds , err := f .GetBindInfo ()
1739+ if err != nil && ! errors .Is (err , ErrMachODyldInfoNotFound ) {
1740+ return err
1741+ }
1742+ for _ , bind := range binds {
1743+ addr := bind .Start + bind .SegOffset
1744+ if _ , exists := f .dyldInfoBindsByAddr [addr ]; exists {
1745+ continue
1746+ }
1747+ f .dyldInfoBindsByAddr [addr ] = bind
1748+ }
1749+
1750+ f .dyldInfoCacheBuilt = true
1751+ return nil
1752+ }
1753+
1754+ func (f * File ) normalizeDyldInfoPointer (value uint64 ) uint64 {
1755+ if value == 0 {
1756+ return 0
1757+ }
1758+ if f .FindSegmentForVMAddr (value ) != nil {
1759+ return value
1760+ }
1761+
1762+ base := f .GetBaseAddress ()
1763+ if value >= base {
1764+ return value
1765+ }
1766+
1767+ candidate := value + base
1768+ if f .FindSegmentForVMAddr (candidate ) != nil {
1769+ return candidate
1770+ }
1771+
1772+ return value
1773+ }
1774+
1775+ func (f * File ) usesDyldInfoOnlyFixups () bool {
1776+ return f .HasDyldInfoOnly () && ! f .HasDyldChainedFixups ()
1777+ }
1778+
1779+ func (f * File ) decodeDyldInfoPointer (value uint64 ) (uint64 , bool ) {
1780+ if value == 0 || ! f .usesDyldInfoOnlyFixups () {
1781+ return 0 , false
1782+ }
1783+
1784+ if err := f .buildDyldInfoFixupsCache (); err != nil {
1785+ return 0 , false
1786+ }
1787+ if _ , ok := f .dyldInfoRebaseValues [value ]; ! ok {
1788+ return 0 , false
1789+ }
1790+ return f .normalizeDyldInfoPointer (value ), true
1791+ }
1792+
1793+ func (f * File ) decodeDyldInfoPointerAtAddress (address , raw uint64 ) (uint64 , bool ) {
1794+ if ! f .usesDyldInfoOnlyFixups () {
1795+ return 0 , false
1796+ }
1797+
1798+ if err := f .buildDyldInfoFixupsCache (); err != nil {
1799+ return 0 , false
1800+ }
1801+
1802+ if resolved , ok := f .dyldInfoRebaseTargets [address ]; ok {
1803+ return resolved , true
1804+ }
1805+
1806+ if bind , ok := f .dyldInfoBindsByAddr [address ]; ok {
1807+ if bind .Dylib == f .LibraryOrdinalName (types .BIND_SPECIAL_DYLIB_SELF ) {
1808+ symAddr , err := f .FindSymbolAddress (bind .Name )
1809+ if err != nil {
1810+ return 0 , true
1811+ }
1812+ return uint64 (int64 (symAddr ) + bind .Addend ), true
1813+ }
1814+ return raw , true
1815+ }
1816+
1817+ return 0 , false
1818+ }
1819+
17001820// SlidePointer returns slid or un-chained pointer
17011821func (f * File ) SlidePointer (ptr uint64 ) uint64 {
17021822 if resolved , ok := f .decodeChainedPointer (ptr ); ok {
17031823 return resolved
17041824 }
1825+ if resolved , ok := f .decodeDyldInfoPointer (ptr ); ok {
1826+ return resolved
1827+ }
17051828 return f .vma .Convert (ptr )
17061829}
17071830
@@ -1711,6 +1834,9 @@ func (f *File) convertToVMAddr(value uint64) uint64 {
17111834 }
17121835 if resolved , ok := f .decodeChainedPointer (value ); ok {
17131836 return resolved
1837+ }
1838+ if resolved , ok := f .decodeDyldInfoPointer (value ); ok {
1839+ return resolved
17141840 } else if f .isArm64e () {
17151841 // TODO: fix this dumb hack for SUPPORT_OLD_ARM64E_FORMAT
17161842 dcf := fixupchains.DyldChainedFixups {
@@ -2984,26 +3110,45 @@ func (f *File) GetBindInfo() (types.Binds, error) {
29843110}
29853111
29863112func (f * File ) GetRebaseInfo () ([]types.Rebase , error ) {
2987- if dinfo := f .DyldInfo (); dinfo != nil {
2988- if dinfo .RebaseSize > 0 {
2989- dat := make ([]byte , dinfo .RebaseSize )
2990- if _ , err := f .cr .ReadAt (dat , int64 (dinfo .RebaseOff )); err != nil {
2991- return nil , fmt .Errorf ("failed to read rebase info: %v" , err )
2992- }
2993- return f .parseRebase (bytes .NewReader (dat ))
2994- }
2995- } else if dinfo := f .DyldInfoOnly (); dinfo != nil {
2996- if dinfo .RebaseSize > 0 {
2997- dat := make ([]byte , dinfo .RebaseSize )
2998- if _ , err := f .cr .ReadAt (dat , int64 (dinfo .RebaseOff )); err != nil {
2999- return nil , fmt .Errorf ("failed to read rebase info: %v" , err )
3000- }
3001- return f .parseRebase (bytes .NewReader (dat ))
3002- }
3003- } else {
3113+ if f .rebasesDone {
3114+ return f .rebases , nil
3115+ }
3116+ var (
3117+ rebaseOff uint32
3118+ rebaseSize uint32
3119+ )
3120+
3121+ switch {
3122+ case f .DyldInfo () != nil :
3123+ dinfo := f .DyldInfo ()
3124+ rebaseOff = dinfo .RebaseOff
3125+ rebaseSize = dinfo .RebaseSize
3126+ case f .DyldInfoOnly () != nil :
3127+ dinfo := f .DyldInfoOnly ()
3128+ rebaseOff = dinfo .RebaseOff
3129+ rebaseSize = dinfo .RebaseSize
3130+ default :
30043131 return nil , ErrMachODyldInfoNotFound
30053132 }
3006- return nil , nil
3133+
3134+ if rebaseSize == 0 {
3135+ f .rebasesDone = true
3136+ return nil , nil
3137+ }
3138+
3139+ dat := make ([]byte , rebaseSize )
3140+ if _ , err := f .cr .ReadAt (dat , int64 (rebaseOff )); err != nil {
3141+ return nil , fmt .Errorf ("failed to read rebase info: %v" , err )
3142+ }
3143+
3144+ rebases , err := f .parseRebase (bytes .NewReader (dat ))
3145+ if err != nil {
3146+ return nil , err
3147+ }
3148+
3149+ f .rebases = rebases
3150+ f .rebasesDone = true
3151+ return f .rebases , nil
30073152}
30083153
30093154func (f * File ) GetExports () ([]trie.TrieExport , error ) {
0 commit comments