Skip to content

Commit fb8fd7e

Browse files
committed
feat: GetSwiftTypeRefs with new record-length parser to handle symbolic protocol references #65
1 parent f104907 commit fb8fd7e

File tree

2 files changed

+358
-46
lines changed

2 files changed

+358
-46
lines changed

file_test.go

Lines changed: 168 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package macho
66

77
import (
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+
268428
func 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

Comments
 (0)