@@ -6,6 +6,7 @@ package macho
66
77import (
88 "bytes"
9+ "encoding/binary"
910 "encoding/json"
1011 "errors"
1112 "flag"
@@ -265,6 +266,165 @@ func openFatObscured(name string) (*FatFile, error) {
265266 return ff , nil
266267}
267268
269+ func newSyntheticDyldInfoOnlyFile (rawPointer uint64 , pointerAddr uint64 , resolvedPointer uint64 ) * File {
270+ data := make ([]byte , 0x40 )
271+ binary .LittleEndian .PutUint64 (data [0x10 :0x18 ], rawPointer )
272+
273+ f := & File {
274+ FileTOC : FileTOC {
275+ FileHeader : types.FileHeader {
276+ Magic : types .Magic64 ,
277+ Type : types .MH_EXECUTE ,
278+ },
279+ Loads : loads {
280+ & Segment {
281+ SegmentHeader : SegmentHeader {
282+ LoadCmd : types .LC_SEGMENT_64 ,
283+ Name : "__TEXT" ,
284+ Addr : 0x100000000 ,
285+ Memsz : 0x2000 ,
286+ Offset : 0 ,
287+ Filesz : uint64 (len (data )),
288+ },
289+ },
290+ & DyldInfoOnly {},
291+ },
292+ },
293+ }
294+ f .ByteOrder = binary .LittleEndian
295+
296+ f .vma = & types.VMAddrConverter {
297+ Converter : f .convertToVMAddr ,
298+ VMAddr2Offet : f .getOffset ,
299+ Offet2VMAddr : f .getVMAddress ,
300+ }
301+ reader := types .NewCustomSectionReader (bytes .NewReader (data ), f .vma , 0 , int64 (len (data )))
302+ f .sr = reader
303+ f .cr = reader
304+
305+ f .dyldInfoCacheBuilt = true
306+ f .dyldInfoRebaseValues = map [uint64 ]struct {}{
307+ rawPointer : {},
308+ }
309+ f .dyldInfoRebaseTargets = map [uint64 ]uint64 {
310+ pointerAddr : resolvedPointer ,
311+ }
312+
313+ return f
314+ }
315+
316+ func TestConvertToVMAddrDyldInfoOnlyRebaseValue (t * testing.T ) {
317+ const (
318+ raw = uint64 (0xfa0 )
319+ expected = uint64 (0x100000fa0 )
320+ )
321+
322+ mf := newSyntheticDyldInfoOnlyFile (raw , 0x100000010 , expected )
323+
324+ if ! mf .HasDyldInfoOnly () || mf .HasDyldChainedFixups () {
325+ t .Fatalf ("expected dyld-info-only binary without chained fixups" )
326+ }
327+
328+ if got := mf .convertToVMAddr (raw ); got != expected {
329+ t .Fatalf ("convertToVMAddr(%#x) = %#x, want %#x" , raw , got , expected )
330+ }
331+ if got := mf .SlidePointer (raw ); got != expected {
332+ t .Fatalf ("SlidePointer(%#x) = %#x, want %#x" , raw , got , expected )
333+ }
334+ }
335+
336+ func TestGetSlidPointerAtAddressDyldInfoOnlyRebase (t * testing.T ) {
337+ const (
338+ addr = uint64 (0x100000010 )
339+ raw = uint64 (0xfa0 )
340+ expected = uint64 (0x100000fa0 )
341+ )
342+
343+ mf := newSyntheticDyldInfoOnlyFile (raw , addr , expected )
344+
345+ got , err := mf .GetSlidPointerAtAddress (addr )
346+ if err != nil {
347+ t .Fatalf ("GetSlidPointerAtAddress(%#x) error = %v" , addr , err )
348+ }
349+ if got != expected {
350+ t .Fatalf ("GetSlidPointerAtAddress(%#x) = %#x, want %#x" , addr , got , expected )
351+ }
352+ }
353+
354+ func TestBuildDyldInfoFixupsCacheKeepsFirstBindForAddress (t * testing.T ) {
355+ const addr = uint64 (0x100000010 )
356+
357+ mf := newSyntheticDyldInfoOnlyFile (0 , addr , 0 )
358+ mf .dyldInfoCacheBuilt = false
359+ mf .rebasesDone = true
360+ mf .rebases = nil
361+ mf .binds = types.Binds {
362+ {
363+ Name : "_first_symbol" ,
364+ Dylib : "libSystem.B.dylib" ,
365+ Start : addr ,
366+ SegOffset : 0 ,
367+ },
368+ {
369+ Name : "_second_symbol" ,
370+ Dylib : "libSystem.B.dylib" ,
371+ Start : addr ,
372+ SegOffset : 0 ,
373+ },
374+ }
375+
376+ if err := mf .buildDyldInfoFixupsCache (); err != nil {
377+ t .Fatalf ("buildDyldInfoFixupsCache() error = %v" , err )
378+ }
379+
380+ got , ok := mf .dyldInfoBindsByAddr [addr ]
381+ if ! ok {
382+ t .Fatalf ("expected bind cache entry for %#x" , addr )
383+ }
384+ if got .Name != "_first_symbol" {
385+ t .Fatalf ("bind cache chose %q, want %q" , got .Name , "_first_symbol" )
386+ }
387+ }
388+
389+ func TestConvertToVMAddrDyldInfoOnlyDoesNotNormalizeUnknownValue (t * testing.T ) {
390+ const (
391+ rebaseRaw = uint64 (0xfa0 )
392+ addr = uint64 (0x100000010 )
393+ unknown = uint64 (0xfa1 )
394+ )
395+
396+ mf := newSyntheticDyldInfoOnlyFile (rebaseRaw , addr , 0x100000fa0 )
397+
398+ if got := mf .convertToVMAddr (unknown ); got != unknown {
399+ t .Fatalf ("convertToVMAddr(%#x) = %#x, want %#x" , unknown , got , unknown )
400+ }
401+ }
402+
403+ func TestGetSlidPointerAtAddressDyldInfoOnlyUnresolvedSelfBind (t * testing.T ) {
404+ const (
405+ addr = uint64 (0x100000010 )
406+ raw = uint64 (0xfeedface )
407+ )
408+
409+ mf := newSyntheticDyldInfoOnlyFile (raw , addr , raw )
410+ mf .dyldInfoRebaseTargets = map [uint64 ]uint64 {}
411+ mf .dyldInfoRebaseValues = map [uint64 ]struct {}{}
412+ mf .dyldInfoBindsByAddr = map [uint64 ]types.Bind {
413+ addr : {
414+ Name : "_missing_local_symbol" ,
415+ Dylib : mf .LibraryOrdinalName (types .BIND_SPECIAL_DYLIB_SELF ),
416+ },
417+ }
418+
419+ got , err := mf .GetSlidPointerAtAddress (addr )
420+ if err != nil {
421+ t .Fatalf ("GetSlidPointerAtAddress(%#x) error = %v" , addr , err )
422+ }
423+ if got != 0 {
424+ t .Fatalf ("GetSlidPointerAtAddress(%#x) = %#x, want %#x" , addr , got , uint64 (0 ))
425+ }
426+ }
427+
268428func TestOpen (t * testing.T ) {
269429 for i := range fileTests {
270430 tt := & fileTests [i ]
@@ -718,13 +878,14 @@ func TestNewFileWithSwift(t *testing.T) {
718878 }
719879 }
720880
721- // if refStrs, err := got.GetSwiftTypeRefs(); err != nil && !errors.Is(err, ErrSwiftSectionError) {
722- // t.Fatalf("GetSwiftTypeRefs() error = %v", err)
723- // } else {
724- // for addr, refstr := range refStrs {
725- // fmt.Printf("%#x: %s\n", addr, refstr)
726- // }
727- // }
881+ if refStrs , err := got .GetSwiftTypeRefs (); err != nil && ! errors .Is (err , ErrSwiftSectionError ) {
882+ t .Fatalf ("GetSwiftTypeRefs() error = %v" , err )
883+ } else {
884+ fmt .Println ("GetSwiftTypeRefs" + strings .Repeat ("-" , 80 ))
885+ for addr , refstr := range refStrs {
886+ fmt .Printf ("%#x: %s\n " , addr , refstr )
887+ }
888+ }
728889
729890 if typs , err := got .GetSwiftTypes (); err != nil && ! errors .Is (err , ErrSwiftSectionError ) {
730891 t .Fatalf ("GetSwiftTypes() error = %v" , err )
0 commit comments