1
2
3
4
5
6 package macho
7
8
9
10 import (
11 "bytes"
12 "compress/zlib"
13 "debug/dwarf"
14 "encoding/binary"
15 "fmt"
16 "io"
17 "os"
18 "strings"
19 "unsafe"
20 )
21
22
23 type File struct {
24 FileTOC
25
26 Symtab *Symtab
27 Dysymtab *Dysymtab
28
29 closer io.Closer
30 }
31
32 type FileTOC struct {
33 FileHeader
34 ByteOrder binary.ByteOrder
35 Loads []Load
36 Sections []*Section
37 }
38
39 func (t *FileTOC) AddLoad(l Load) {
40 t.Loads = append(t.Loads, l)
41 t.NCommands++
42 t.SizeCommands += l.LoadSize(t)
43 }
44
45
46
47
48 func (t *FileTOC) AddSegment(s *Segment) {
49 t.AddLoad(s)
50 s.Nsect = 0
51 s.Firstsect = 0
52 }
53
54
55 func (t *FileTOC) AddSection(s *Section) {
56 g := t.Loads[len(t.Loads)-1].(*Segment)
57 if g.Nsect == 0 {
58 g.Firstsect = uint32(len(t.Sections))
59 }
60 g.Nsect++
61 t.Sections = append(t.Sections, s)
62 sectionsize := uint32(unsafe.Sizeof(Section32{}))
63 if g.Command() == LcSegment64 {
64 sectionsize = uint32(unsafe.Sizeof(Section64{}))
65 }
66 t.SizeCommands += sectionsize
67 g.Len += sectionsize
68 }
69
70
71 type Load interface {
72 String() string
73 Command() LoadCmd
74 LoadSize(*FileTOC) uint32
75 Put([]byte, binary.ByteOrder) int
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 }
106
107
108 type LoadBytes []byte
109
110
111 type SegmentHeader struct {
112 LoadCmd
113 Len uint32
114 Name string
115 Addr uint64
116 Memsz uint64
117 Offset uint64
118 Filesz uint64
119 Maxprot uint32
120 Prot uint32
121 Nsect uint32
122 Flag SegFlags
123 Firstsect uint32
124 }
125
126
127 type Segment struct {
128 SegmentHeader
129
130
131
132
133
134
135
136 io.ReaderAt
137 sr *io.SectionReader
138 }
139
140 func (s *Segment) Put32(b []byte, o binary.ByteOrder) int {
141 o.PutUint32(b[0*4:], uint32(s.LoadCmd))
142 o.PutUint32(b[1*4:], s.Len)
143 putAtMost16Bytes(b[2*4:], s.Name)
144 o.PutUint32(b[6*4:], uint32(s.Addr))
145 o.PutUint32(b[7*4:], uint32(s.Memsz))
146 o.PutUint32(b[8*4:], uint32(s.Offset))
147 o.PutUint32(b[9*4:], uint32(s.Filesz))
148 o.PutUint32(b[10*4:], s.Maxprot)
149 o.PutUint32(b[11*4:], s.Prot)
150 o.PutUint32(b[12*4:], s.Nsect)
151 o.PutUint32(b[13*4:], uint32(s.Flag))
152 return 14 * 4
153 }
154
155 func (s *Segment) Put64(b []byte, o binary.ByteOrder) int {
156 o.PutUint32(b[0*4:], uint32(s.LoadCmd))
157 o.PutUint32(b[1*4:], s.Len)
158 putAtMost16Bytes(b[2*4:], s.Name)
159 o.PutUint64(b[6*4+0*8:], s.Addr)
160 o.PutUint64(b[6*4+1*8:], s.Memsz)
161 o.PutUint64(b[6*4+2*8:], s.Offset)
162 o.PutUint64(b[6*4+3*8:], s.Filesz)
163 o.PutUint32(b[6*4+4*8:], s.Maxprot)
164 o.PutUint32(b[7*4+4*8:], s.Prot)
165 o.PutUint32(b[8*4+4*8:], s.Nsect)
166 o.PutUint32(b[9*4+4*8:], uint32(s.Flag))
167 return 10*4 + 4*8
168 }
169
170
171
172
173
174 type LoadCmdBytes struct {
175 LoadCmd
176 LoadBytes
177 }
178
179 type SectionHeader struct {
180 Name string
181 Seg string
182 Addr uint64
183 Size uint64
184 Offset uint32
185 Align uint32
186 Reloff uint32
187 Nreloc uint32
188 Flags SecFlags
189 Reserved1 uint32
190 Reserved2 uint32
191 Reserved3 uint32
192 }
193
194
195 type Reloc struct {
196 Addr uint32
197 Value uint32
198
199
200
201 Type uint8
202 Len uint8
203 Pcrel bool
204 Extern bool
205 Scattered bool
206 }
207
208 type Section struct {
209 SectionHeader
210 Relocs []Reloc
211
212
213
214
215
216
217
218 io.ReaderAt
219 sr *io.SectionReader
220 }
221
222 func (s *Section) Put32(b []byte, o binary.ByteOrder) int {
223 putAtMost16Bytes(b[0:], s.Name)
224 putAtMost16Bytes(b[16:], s.Seg)
225 o.PutUint32(b[8*4:], uint32(s.Addr))
226 o.PutUint32(b[9*4:], uint32(s.Size))
227 o.PutUint32(b[10*4:], s.Offset)
228 o.PutUint32(b[11*4:], s.Align)
229 o.PutUint32(b[12*4:], s.Reloff)
230 o.PutUint32(b[13*4:], s.Nreloc)
231 o.PutUint32(b[14*4:], uint32(s.Flags))
232 o.PutUint32(b[15*4:], s.Reserved1)
233 o.PutUint32(b[16*4:], s.Reserved2)
234 a := 17 * 4
235 return a + s.PutRelocs(b[a:], o)
236 }
237
238 func (s *Section) Put64(b []byte, o binary.ByteOrder) int {
239 putAtMost16Bytes(b[0:], s.Name)
240 putAtMost16Bytes(b[16:], s.Seg)
241 o.PutUint64(b[8*4+0*8:], s.Addr)
242 o.PutUint64(b[8*4+1*8:], s.Size)
243 o.PutUint32(b[8*4+2*8:], s.Offset)
244 o.PutUint32(b[9*4+2*8:], s.Align)
245 o.PutUint32(b[10*4+2*8:], s.Reloff)
246 o.PutUint32(b[11*4+2*8:], s.Nreloc)
247 o.PutUint32(b[12*4+2*8:], uint32(s.Flags))
248 o.PutUint32(b[13*4+2*8:], s.Reserved1)
249 o.PutUint32(b[14*4+2*8:], s.Reserved2)
250 o.PutUint32(b[15*4+2*8:], s.Reserved3)
251 a := 16*4 + 2*8
252 return a + s.PutRelocs(b[a:], o)
253 }
254
255 func (s *Section) PutRelocs(b []byte, o binary.ByteOrder) int {
256 a := 0
257 for _, r := range s.Relocs {
258 var ri relocInfo
259 typ := uint32(r.Type) & (1<<4 - 1)
260 len := uint32(r.Len) & (1<<2 - 1)
261 pcrel := uint32(0)
262 if r.Pcrel {
263 pcrel = 1
264 }
265 ext := uint32(0)
266 if r.Extern {
267 ext = 1
268 }
269 switch {
270 case r.Scattered:
271 ri.Addr = r.Addr&(1<<24-1) | typ<<24 | len<<28 | 1<<31 | pcrel<<30
272 ri.Symnum = r.Value
273 case o == binary.LittleEndian:
274 ri.Addr = r.Addr
275 ri.Symnum = r.Value&(1<<24-1) | pcrel<<24 | len<<25 | ext<<27 | typ<<28
276 case o == binary.BigEndian:
277 ri.Addr = r.Addr
278 ri.Symnum = r.Value<<8 | pcrel<<7 | len<<5 | ext<<4 | typ
279 }
280 o.PutUint32(b, ri.Addr)
281 o.PutUint32(b[4:], ri.Symnum)
282 a += 8
283 b = b[8:]
284 }
285 return a
286 }
287
288 func putAtMost16Bytes(b []byte, n string) {
289 for i := range n {
290 if i == 16 {
291 break
292 }
293 b[i] = n[i]
294 }
295 }
296
297
298 type Symbol struct {
299 Name string
300 Type uint8
301 Sect uint8
302 Desc uint16
303 Value uint64
304 }
305
306
309
310
311
312 type FormatError struct {
313 off int64
314 msg string
315 }
316
317 func formatError(off int64, format string, data ...interface{}) *FormatError {
318 return &FormatError{off, fmt.Sprintf(format, data...)}
319 }
320
321 func (e *FormatError) Error() string {
322 return e.msg + fmt.Sprintf(" in record at byte %#x", e.off)
323 }
324
325 func (e *FormatError) String() string {
326 return e.Error()
327 }
328
329
330
331 func (t *FileTOC) DerivedCopy(Type HdrType, Flags HdrFlags) *FileTOC {
332 h := t.FileHeader
333 h.NCommands, h.SizeCommands, h.Type, h.Flags = 0, 0, Type, Flags
334
335 return &FileTOC{FileHeader: h, ByteOrder: t.ByteOrder}
336 }
337
338
339
340
341
342 func (t *FileTOC) TOCSize() uint32 {
343 return t.HdrSize() + t.LoadSize()
344 }
345
346
347
348 func (t *FileTOC) LoadAlign() uint64 {
349 if t.Magic == Magic64 {
350 return 8
351 }
352 return 4
353 }
354
355
356 func (t *FileTOC) SymbolSize() uint32 {
357 if t.Magic == Magic64 {
358 return uint32(unsafe.Sizeof(Nlist64{}))
359 }
360 return uint32(unsafe.Sizeof(Nlist32{}))
361 }
362
363
364
365 func (t *FileTOC) HdrSize() uint32 {
366 switch t.Magic {
367 case Magic32:
368 return fileHeaderSize32
369 case Magic64:
370 return fileHeaderSize64
371 case MagicFat:
372 panic("MagicFat not handled yet")
373 default:
374 panic(fmt.Sprintf("Unexpected magic number 0x%x, expected Mach-O object file", t.Magic))
375 }
376 }
377
378
379
380 func (t *FileTOC) LoadSize() uint32 {
381 cmdsz := uint32(0)
382 for _, l := range t.Loads {
383 s := l.LoadSize(t)
384 cmdsz += s
385 }
386 return cmdsz
387 }
388
389
390
391
392 func (t *FileTOC) FileSize() uint64 {
393 sz := uint64(t.LoadSize())
394 for _, l := range t.Loads {
395 if s, ok := l.(*Segment); ok {
396 if m := s.Offset + s.Filesz; m > sz {
397 sz = m
398 }
399 }
400 }
401 return sz
402 }
403
404
405
406
407
408 func (t *FileTOC) Put(buffer []byte) int {
409 next := t.FileHeader.Put(buffer, t.ByteOrder)
410 for _, l := range t.Loads {
411 if s, ok := l.(*Segment); ok {
412 switch t.Magic {
413 case Magic64:
414 next += s.Put64(buffer[next:], t.ByteOrder)
415 for i := uint32(0); i < s.Nsect; i++ {
416 c := t.Sections[i+s.Firstsect]
417 next += c.Put64(buffer[next:], t.ByteOrder)
418 }
419 case Magic32:
420 next += s.Put32(buffer[next:], t.ByteOrder)
421 for i := uint32(0); i < s.Nsect; i++ {
422 c := t.Sections[i+s.Firstsect]
423 next += c.Put32(buffer[next:], t.ByteOrder)
424 }
425 default:
426 panic(fmt.Sprintf("Unexpected magic number 0x%x", t.Magic))
427 }
428
429 } else {
430 next += l.Put(buffer[next:], t.ByteOrder)
431 }
432 }
433 return next
434 }
435
436
437
438 func (s *Segment) UncompressedSize(t *FileTOC, align uint64) uint64 {
439 sz := uint64(0)
440 for j := uint32(0); j < s.Nsect; j++ {
441 c := t.Sections[j+s.Firstsect]
442 sz += c.UncompressedSize()
443 }
444 return (sz + align - 1) & uint64(-int64(align))
445 }
446
447 func (s *Section) UncompressedSize() uint64 {
448 if !strings.HasPrefix(s.Name, "__z") {
449 return s.Size
450 }
451 b := make([]byte, 12)
452 n, err := s.sr.ReadAt(b, 0)
453 if err != nil {
454 panic("Malformed object file")
455 }
456 if n != len(b) {
457 return s.Size
458 }
459 if string(b[:4]) == "ZLIB" {
460 return binary.BigEndian.Uint64(b[4:12])
461 }
462 return s.Size
463 }
464
465 func (s *Section) PutData(b []byte) {
466 bb := b[0:s.Size]
467 n, err := s.sr.ReadAt(bb, 0)
468 if err != nil || uint64(n) != s.Size {
469 panic("Malformed object file (ReadAt error)")
470 }
471 }
472
473 func (s *Section) PutUncompressedData(b []byte) {
474 if strings.HasPrefix(s.Name, "__z") {
475 bb := make([]byte, 12)
476 n, err := s.sr.ReadAt(bb, 0)
477 if err != nil {
478 panic("Malformed object file")
479 }
480 if n == len(bb) && string(bb[:4]) == "ZLIB" {
481 size := binary.BigEndian.Uint64(bb[4:12])
482
483 r, err := zlib.NewReader(io.NewSectionReader(s, 12, int64(size)-12))
484 if err != nil {
485 panic("Malformed object file (zlib.NewReader error)")
486 }
487 n, err := io.ReadFull(r, b[0:size])
488 if err != nil {
489 panic("Malformed object file (ReadFull error)")
490 }
491 if uint64(n) != size {
492 panic(fmt.Sprintf("PutUncompressedData, expected to read %d bytes, instead read %d", size, n))
493 }
494 if err := r.Close(); err != nil {
495 panic("Malformed object file (Close error)")
496 }
497 return
498 }
499 }
500
501 s.PutData(b)
502 }
503
504 func (b LoadBytes) String() string {
505 s := "["
506 for i, a := range b {
507 if i > 0 {
508 s += " "
509 if len(b) > 48 && i >= 16 {
510 s += fmt.Sprintf("... (%d bytes)", len(b))
511 break
512 }
513 }
514 s += fmt.Sprintf("%x", a)
515 }
516 s += "]"
517 return s
518 }
519
520 func (b LoadBytes) Raw() []byte { return b }
521 func (b LoadBytes) Copy() LoadBytes { return LoadBytes(append([]byte{}, b...)) }
522 func (b LoadBytes) LoadSize(t *FileTOC) uint32 { return uint32(len(b)) }
523
524 func (lc LoadCmd) Put(b []byte, o binary.ByteOrder) int {
525 panic(fmt.Sprintf("Put not implemented for %s", lc.String()))
526 }
527
528 func (s LoadCmdBytes) String() string {
529 return s.LoadCmd.String() + ": " + s.LoadBytes.String()
530 }
531 func (s LoadCmdBytes) Copy() LoadCmdBytes {
532 return LoadCmdBytes{LoadCmd: s.LoadCmd, LoadBytes: s.LoadBytes.Copy()}
533 }
534
535 func (s *SegmentHeader) String() string {
536 return fmt.Sprintf(
537 "Seg %s, len=0x%x, addr=0x%x, memsz=0x%x, offset=0x%x, filesz=0x%x, maxprot=0x%x, prot=0x%x, nsect=%d, flag=0x%x, firstsect=%d",
538 s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect)
539 }
540
541 func (s *Segment) String() string {
542 return fmt.Sprintf(
543 "Seg %s, len=0x%x, addr=0x%x, memsz=0x%x, offset=0x%x, filesz=0x%x, maxprot=0x%x, prot=0x%x, nsect=%d, flag=0x%x, firstsect=%d",
544 s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect)
545 }
546
547
548 func (s *Segment) Data() ([]byte, error) {
549 dat := make([]byte, s.sr.Size())
550 n, err := s.sr.ReadAt(dat, 0)
551 if n == len(dat) {
552 err = nil
553 }
554 return dat[0:n], err
555 }
556
557 func (s *Segment) Copy() *Segment {
558 r := &Segment{SegmentHeader: s.SegmentHeader}
559 return r
560 }
561 func (s *Segment) CopyZeroed() *Segment {
562 r := s.Copy()
563 r.Filesz = 0
564 r.Offset = 0
565 r.Nsect = 0
566 r.Firstsect = 0
567 if s.Command() == LcSegment64 {
568 r.Len = uint32(unsafe.Sizeof(Segment64{}))
569 } else {
570 r.Len = uint32(unsafe.Sizeof(Segment32{}))
571 }
572 return r
573 }
574
575 func (s *Segment) LoadSize(t *FileTOC) uint32 {
576 if s.Command() == LcSegment64 {
577 return uint32(unsafe.Sizeof(Segment64{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section64{}))
578 }
579 return uint32(unsafe.Sizeof(Segment32{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section32{}))
580 }
581
582
583 func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
584
585
586 func (s *Section) Data() ([]byte, error) {
587 dat := make([]byte, s.sr.Size())
588 n, err := s.sr.ReadAt(dat, 0)
589 if n == len(dat) {
590 err = nil
591 }
592 return dat[0:n], err
593 }
594
595 func (s *Section) Copy() *Section {
596 return &Section{SectionHeader: s.SectionHeader}
597 }
598
599
600 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
601
602
603 type Dylib struct {
604 DylibCmd
605 Name string
606 Time uint32
607 CurrentVersion uint32
608 CompatVersion uint32
609 }
610
611 func (s *Dylib) String() string { return "Dylib " + s.Name }
612 func (s *Dylib) Copy() *Dylib {
613 r := *s
614 return &r
615 }
616 func (s *Dylib) LoadSize(t *FileTOC) uint32 {
617 return uint32(RoundUp(uint64(unsafe.Sizeof(DylibCmd{}))+uint64(len(s.Name)), t.LoadAlign()))
618 }
619
620 type Dylinker struct {
621 DylinkerCmd
622 Name string
623 }
624
625 func (s *Dylinker) String() string { return s.DylinkerCmd.LoadCmd.String() + " " + s.Name }
626 func (s *Dylinker) Copy() *Dylinker {
627 return &Dylinker{DylinkerCmd: s.DylinkerCmd, Name: s.Name}
628 }
629 func (s *Dylinker) LoadSize(t *FileTOC) uint32 {
630 return uint32(RoundUp(uint64(unsafe.Sizeof(DylinkerCmd{}))+uint64(len(s.Name)), t.LoadAlign()))
631 }
632
633
634 type Symtab struct {
635 SymtabCmd
636 Syms []Symbol
637 }
638
639 func (s *Symtab) Put(b []byte, o binary.ByteOrder) int {
640 o.PutUint32(b[0*4:], uint32(s.LoadCmd))
641 o.PutUint32(b[1*4:], s.Len)
642 o.PutUint32(b[2*4:], s.Symoff)
643 o.PutUint32(b[3*4:], s.Nsyms)
644 o.PutUint32(b[4*4:], s.Stroff)
645 o.PutUint32(b[5*4:], s.Strsize)
646 return 6 * 4
647 }
648
649 func (s *Symtab) String() string { return fmt.Sprintf("Symtab %#v", s.SymtabCmd) }
650 func (s *Symtab) Copy() *Symtab {
651 return &Symtab{SymtabCmd: s.SymtabCmd, Syms: append([]Symbol{}, s.Syms...)}
652 }
653 func (s *Symtab) LoadSize(t *FileTOC) uint32 {
654 return uint32(unsafe.Sizeof(SymtabCmd{}))
655 }
656
657 type LinkEditData struct {
658 LinkEditDataCmd
659 }
660
661 func (s *LinkEditData) String() string { return "LinkEditData " + s.LoadCmd.String() }
662 func (s *LinkEditData) Copy() *LinkEditData {
663 return &LinkEditData{LinkEditDataCmd: s.LinkEditDataCmd}
664 }
665 func (s *LinkEditData) LoadSize(t *FileTOC) uint32 {
666 return uint32(unsafe.Sizeof(LinkEditDataCmd{}))
667 }
668
669 type Uuid struct {
670 UuidCmd
671 }
672
673 func (s *Uuid) String() string {
674 return fmt.Sprintf("Uuid %X-%X-%X-%X-%X",
675 s.Id[0:4], s.Id[4:6], s.Id[6:8], s.Id[8:10], s.Id[10:16])
676 }
677 func (s *Uuid) Copy() *Uuid {
678 return &Uuid{UuidCmd: s.UuidCmd}
679 }
680 func (s *Uuid) LoadSize(t *FileTOC) uint32 {
681 return uint32(unsafe.Sizeof(UuidCmd{}))
682 }
683 func (s *Uuid) Put(b []byte, o binary.ByteOrder) int {
684 o.PutUint32(b[0*4:], uint32(s.LoadCmd))
685 o.PutUint32(b[1*4:], s.Len)
686 copy(b[2*4:], s.Id[0:])
687 return int(s.Len)
688 }
689
690 type DyldInfo struct {
691 DyldInfoCmd
692 }
693
694 func (s *DyldInfo) String() string { return "DyldInfo " + s.LoadCmd.String() }
695 func (s *DyldInfo) Copy() *DyldInfo {
696 return &DyldInfo{DyldInfoCmd: s.DyldInfoCmd}
697 }
698 func (s *DyldInfo) LoadSize(t *FileTOC) uint32 {
699 return uint32(unsafe.Sizeof(DyldInfoCmd{}))
700 }
701
702 type EncryptionInfo struct {
703 EncryptionInfoCmd
704 }
705
706 func (s *EncryptionInfo) String() string { return "EncryptionInfo " + s.LoadCmd.String() }
707 func (s *EncryptionInfo) Copy() *EncryptionInfo {
708 return &EncryptionInfo{EncryptionInfoCmd: s.EncryptionInfoCmd}
709 }
710 func (s *EncryptionInfo) LoadSize(t *FileTOC) uint32 {
711 return uint32(unsafe.Sizeof(EncryptionInfoCmd{}))
712 }
713
714
715 type Dysymtab struct {
716 DysymtabCmd
717 IndirectSyms []uint32
718 }
719
720 func (s *Dysymtab) String() string { return fmt.Sprintf("Dysymtab %#v", s.DysymtabCmd) }
721 func (s *Dysymtab) Copy() *Dysymtab {
722 return &Dysymtab{DysymtabCmd: s.DysymtabCmd, IndirectSyms: append([]uint32{}, s.IndirectSyms...)}
723 }
724 func (s *Dysymtab) LoadSize(t *FileTOC) uint32 {
725 return uint32(unsafe.Sizeof(DysymtabCmd{}))
726 }
727
728
729 type Rpath struct {
730 LoadCmd
731 Path string
732 }
733
734 func (s *Rpath) String() string { return "Rpath " + s.Path }
735 func (s *Rpath) Command() LoadCmd { return LcRpath }
736 func (s *Rpath) Copy() *Rpath {
737 return &Rpath{Path: s.Path}
738 }
739 func (s *Rpath) LoadSize(t *FileTOC) uint32 {
740 return uint32(RoundUp(uint64(unsafe.Sizeof(RpathCmd{}))+uint64(len(s.Path)), t.LoadAlign()))
741 }
742
743
744 func Open(name string) (*File, error) {
745 f, err := os.Open(name)
746 if err != nil {
747 return nil, err
748 }
749 ff, err := NewFile(f)
750 if err != nil {
751 f.Close()
752 return nil, err
753 }
754 ff.closer = f
755 return ff, nil
756 }
757
758
759
760
761 func (f *File) Close() error {
762 var err error
763 if f.closer != nil {
764 err = f.closer.Close()
765 f.closer = nil
766 }
767 return err
768 }
769
770
771
772 func NewFile(r io.ReaderAt) (*File, error) {
773 f := new(File)
774 sr := io.NewSectionReader(r, 0, 1<<63-1)
775
776
777
778 var ident [4]byte
779 if _, err := r.ReadAt(ident[0:], 0); err != nil {
780 return nil, err
781 }
782 be := binary.BigEndian.Uint32(ident[0:])
783 le := binary.LittleEndian.Uint32(ident[0:])
784 switch Magic32 &^ 1 {
785 case be &^ 1:
786 f.ByteOrder = binary.BigEndian
787 f.Magic = be
788 case le &^ 1:
789 f.ByteOrder = binary.LittleEndian
790 f.Magic = le
791 default:
792 return nil, formatError(0, "invalid magic number be=0x%x, le=0x%x", be, le)
793 }
794
795
796 if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
797 return nil, err
798 }
799
800
801 offset := int64(fileHeaderSize32)
802 if f.Magic == Magic64 {
803 offset = fileHeaderSize64
804 }
805 dat := make([]byte, f.SizeCommands)
806 if _, err := r.ReadAt(dat, offset); err != nil {
807 return nil, err
808 }
809 f.Loads = make([]Load, f.NCommands)
810 bo := f.ByteOrder
811 for i := range f.Loads {
812
813 if len(dat) < 8 {
814 return nil, formatError(offset, "command block too small, len(dat) = %d", len(dat))
815 }
816 cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
817 if siz < 8 || siz > uint32(len(dat)) {
818 return nil, formatError(offset, "invalid command block size, len(dat)=%d, size=%d", len(dat), siz)
819 }
820 var cmddat []byte
821 cmddat, dat = dat[0:siz], dat[siz:]
822 offset += int64(siz)
823 var s *Segment
824 switch cmd {
825 default:
826 f.Loads[i] = LoadCmdBytes{LoadCmd(cmd), LoadBytes(cmddat)}
827
828 case LcUuid:
829 var hdr UuidCmd
830 b := bytes.NewReader(cmddat)
831 if err := binary.Read(b, bo, &hdr); err != nil {
832 return nil, err
833 }
834 l := &Uuid{UuidCmd: hdr}
835
836 f.Loads[i] = l
837
838 case LcRpath:
839 var hdr RpathCmd
840 b := bytes.NewReader(cmddat)
841 if err := binary.Read(b, bo, &hdr); err != nil {
842 return nil, err
843 }
844 l := &Rpath{LoadCmd: hdr.LoadCmd}
845 if hdr.Path >= uint32(len(cmddat)) {
846 return nil, formatError(offset, "invalid path in rpath command, len(cmddat)=%d, hdr.Path=%d", len(cmddat), hdr.Path)
847 }
848 l.Path = cstring(cmddat[hdr.Path:])
849 f.Loads[i] = l
850
851 case LcLoadDylinker, LcIdDylinker, LcDyldEnvironment:
852 var hdr DylinkerCmd
853 b := bytes.NewReader(cmddat)
854 if err := binary.Read(b, bo, &hdr); err != nil {
855 return nil, err
856 }
857 l := new(Dylinker)
858 if hdr.Name >= uint32(len(cmddat)) {
859 return nil, formatError(offset, "invalid name in dynamic linker command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat))
860 }
861 l.Name = cstring(cmddat[hdr.Name:])
862 l.DylinkerCmd = hdr
863 f.Loads[i] = l
864
865 case LcDylib:
866 var hdr DylibCmd
867 b := bytes.NewReader(cmddat)
868 if err := binary.Read(b, bo, &hdr); err != nil {
869 return nil, err
870 }
871 l := new(Dylib)
872 if hdr.Name >= uint32(len(cmddat)) {
873 return nil, formatError(offset, "invalid name in dynamic library command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat))
874 }
875 l.Name = cstring(cmddat[hdr.Name:])
876 l.Time = hdr.Time
877 l.CurrentVersion = hdr.CurrentVersion
878 l.CompatVersion = hdr.CompatVersion
879 f.Loads[i] = l
880
881 case LcSymtab:
882 var hdr SymtabCmd
883 b := bytes.NewReader(cmddat)
884 if err := binary.Read(b, bo, &hdr); err != nil {
885 return nil, err
886 }
887 strtab := make([]byte, hdr.Strsize)
888 if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
889 return nil, err
890 }
891 var symsz int
892 if f.Magic == Magic64 {
893 symsz = 16
894 } else {
895 symsz = 12
896 }
897 symdat := make([]byte, int(hdr.Nsyms)*symsz)
898 if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
899 return nil, err
900 }
901 st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
902 st.SymtabCmd = hdr
903 if err != nil {
904 return nil, err
905 }
906 f.Loads[i] = st
907 f.Symtab = st
908
909 case LcDysymtab:
910 var hdr DysymtabCmd
911 b := bytes.NewReader(cmddat)
912 if err := binary.Read(b, bo, &hdr); err != nil {
913 return nil, err
914 }
915 dat := make([]byte, hdr.Nindirectsyms*4)
916 if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
917 return nil, err
918 }
919 x := make([]uint32, hdr.Nindirectsyms)
920 if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
921 return nil, err
922 }
923 st := new(Dysymtab)
924 st.DysymtabCmd = hdr
925 st.IndirectSyms = x
926 f.Loads[i] = st
927 f.Dysymtab = st
928
929 case LcSegment:
930 var seg32 Segment32
931 b := bytes.NewReader(cmddat)
932 if err := binary.Read(b, bo, &seg32); err != nil {
933 return nil, err
934 }
935 s = new(Segment)
936 s.LoadCmd = cmd
937 s.Len = siz
938 s.Name = cstring(seg32.Name[0:])
939 s.Addr = uint64(seg32.Addr)
940 s.Memsz = uint64(seg32.Memsz)
941 s.Offset = uint64(seg32.Offset)
942 s.Filesz = uint64(seg32.Filesz)
943 s.Maxprot = seg32.Maxprot
944 s.Prot = seg32.Prot
945 s.Nsect = seg32.Nsect
946 s.Flag = seg32.Flag
947 s.Firstsect = uint32(len(f.Sections))
948 f.Loads[i] = s
949 for i := 0; i < int(s.Nsect); i++ {
950 var sh32 Section32
951 if err := binary.Read(b, bo, &sh32); err != nil {
952 return nil, err
953 }
954 sh := new(Section)
955 sh.Name = cstring(sh32.Name[0:])
956 sh.Seg = cstring(sh32.Seg[0:])
957 sh.Addr = uint64(sh32.Addr)
958 sh.Size = uint64(sh32.Size)
959 sh.Offset = sh32.Offset
960 sh.Align = sh32.Align
961 sh.Reloff = sh32.Reloff
962 sh.Nreloc = sh32.Nreloc
963 sh.Flags = sh32.Flags
964 sh.Reserved1 = sh32.Reserve1
965 sh.Reserved2 = sh32.Reserve2
966 if err := f.pushSection(sh, r); err != nil {
967 return nil, err
968 }
969 }
970
971 case LcSegment64:
972 var seg64 Segment64
973 b := bytes.NewReader(cmddat)
974 if err := binary.Read(b, bo, &seg64); err != nil {
975 return nil, err
976 }
977 s = new(Segment)
978 s.LoadCmd = cmd
979 s.Len = siz
980 s.Name = cstring(seg64.Name[0:])
981 s.Addr = seg64.Addr
982 s.Memsz = seg64.Memsz
983 s.Offset = seg64.Offset
984 s.Filesz = seg64.Filesz
985 s.Maxprot = seg64.Maxprot
986 s.Prot = seg64.Prot
987 s.Nsect = seg64.Nsect
988 s.Flag = seg64.Flag
989 s.Firstsect = uint32(len(f.Sections))
990 f.Loads[i] = s
991 for i := 0; i < int(s.Nsect); i++ {
992 var sh64 Section64
993 if err := binary.Read(b, bo, &sh64); err != nil {
994 return nil, err
995 }
996 sh := new(Section)
997 sh.Name = cstring(sh64.Name[0:])
998 sh.Seg = cstring(sh64.Seg[0:])
999 sh.Addr = sh64.Addr
1000 sh.Size = sh64.Size
1001 sh.Offset = sh64.Offset
1002 sh.Align = sh64.Align
1003 sh.Reloff = sh64.Reloff
1004 sh.Nreloc = sh64.Nreloc
1005 sh.Flags = sh64.Flags
1006 sh.Reserved1 = sh64.Reserve1
1007 sh.Reserved2 = sh64.Reserve2
1008 sh.Reserved3 = sh64.Reserve3
1009 if err := f.pushSection(sh, r); err != nil {
1010 return nil, err
1011 }
1012 }
1013
1014 case LcCodeSignature, LcSegmentSplitInfo, LcFunctionStarts,
1015 LcDataInCode, LcDylibCodeSignDrs:
1016 var hdr LinkEditDataCmd
1017 b := bytes.NewReader(cmddat)
1018
1019 if err := binary.Read(b, bo, &hdr); err != nil {
1020 return nil, err
1021 }
1022 l := new(LinkEditData)
1023
1024 l.LinkEditDataCmd = hdr
1025 f.Loads[i] = l
1026
1027 case LcEncryptionInfo, LcEncryptionInfo64:
1028 var hdr EncryptionInfoCmd
1029 b := bytes.NewReader(cmddat)
1030
1031 if err := binary.Read(b, bo, &hdr); err != nil {
1032 return nil, err
1033 }
1034 l := new(EncryptionInfo)
1035
1036 l.EncryptionInfoCmd = hdr
1037 f.Loads[i] = l
1038
1039 case LcDyldInfo, LcDyldInfoOnly:
1040 var hdr DyldInfoCmd
1041 b := bytes.NewReader(cmddat)
1042
1043 if err := binary.Read(b, bo, &hdr); err != nil {
1044 return nil, err
1045 }
1046 l := new(DyldInfo)
1047
1048 l.DyldInfoCmd = hdr
1049 f.Loads[i] = l
1050 }
1051 if s != nil {
1052 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
1053 s.ReaderAt = s.sr
1054 }
1055 if f.Loads[i].LoadSize(&f.FileTOC) != siz {
1056 fmt.Printf("Oops, actual size was %d, calculated was %d, load was %s\n", siz, f.Loads[i].LoadSize(&f.FileTOC), f.Loads[i].String())
1057 panic("oops")
1058 }
1059 }
1060 return f, nil
1061 }
1062
1063 func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
1064 bo := f.ByteOrder
1065 symtab := make([]Symbol, hdr.Nsyms)
1066 b := bytes.NewReader(symdat)
1067 for i := range symtab {
1068 var n Nlist64
1069 if f.Magic == Magic64 {
1070 if err := binary.Read(b, bo, &n); err != nil {
1071 return nil, err
1072 }
1073 } else {
1074 var n32 Nlist32
1075 if err := binary.Read(b, bo, &n32); err != nil {
1076 return nil, err
1077 }
1078 n.Name = n32.Name
1079 n.Type = n32.Type
1080 n.Sect = n32.Sect
1081 n.Desc = n32.Desc
1082 n.Value = uint64(n32.Value)
1083 }
1084 sym := &symtab[i]
1085 if n.Name >= uint32(len(strtab)) {
1086 return nil, formatError(offset, "invalid name in symbol table, n.Name=%d, len(strtab)=%d", n.Name, len(strtab))
1087 }
1088 sym.Name = cstring(strtab[n.Name:])
1089 sym.Type = n.Type
1090 sym.Sect = n.Sect
1091 sym.Desc = n.Desc
1092 sym.Value = n.Value
1093 }
1094 st := new(Symtab)
1095 st.Syms = symtab
1096 return st, nil
1097 }
1098
1099 type relocInfo struct {
1100 Addr uint32
1101 Symnum uint32
1102 }
1103
1104 func (f *File) pushSection(sh *Section, r io.ReaderAt) error {
1105 f.Sections = append(f.Sections, sh)
1106 sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
1107 sh.ReaderAt = sh.sr
1108
1109 if sh.Nreloc > 0 {
1110 reldat := make([]byte, int(sh.Nreloc)*8)
1111 if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil {
1112 return err
1113 }
1114 b := bytes.NewReader(reldat)
1115
1116 bo := f.ByteOrder
1117
1118 sh.Relocs = make([]Reloc, sh.Nreloc)
1119 for i := range sh.Relocs {
1120 rel := &sh.Relocs[i]
1121
1122 var ri relocInfo
1123 if err := binary.Read(b, bo, &ri); err != nil {
1124 return err
1125 }
1126
1127 if ri.Addr&(1<<31) != 0 {
1128 rel.Addr = ri.Addr & (1<<24 - 1)
1129 rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1))
1130 rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1))
1131 rel.Pcrel = ri.Addr&(1<<30) != 0
1132 rel.Value = ri.Symnum
1133 rel.Scattered = true
1134 } else {
1135 switch bo {
1136 case binary.LittleEndian:
1137 rel.Addr = ri.Addr
1138 rel.Value = ri.Symnum & (1<<24 - 1)
1139 rel.Pcrel = ri.Symnum&(1<<24) != 0
1140 rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1))
1141 rel.Extern = ri.Symnum&(1<<27) != 0
1142 rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1))
1143 case binary.BigEndian:
1144 rel.Addr = ri.Addr
1145 rel.Value = ri.Symnum >> 8
1146 rel.Pcrel = ri.Symnum&(1<<7) != 0
1147 rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1))
1148 rel.Extern = ri.Symnum&(1<<4) != 0
1149 rel.Type = uint8(ri.Symnum & (1<<4 - 1))
1150 default:
1151 panic("unreachable")
1152 }
1153 }
1154 }
1155 }
1156
1157 return nil
1158 }
1159
1160 func cstring(b []byte) string {
1161 i := bytes.IndexByte(b, 0)
1162 if i == -1 {
1163 i = len(b)
1164 }
1165 return string(b[0:i])
1166 }
1167
1168
1169 func (f *File) Segment(name string) *Segment {
1170 for _, l := range f.Loads {
1171 if s, ok := l.(*Segment); ok && s.Name == name {
1172 return s
1173 }
1174 }
1175 return nil
1176 }
1177
1178
1179
1180 func (f *File) Section(name string) *Section {
1181 for _, s := range f.Sections {
1182 if s.Name == name {
1183 return s
1184 }
1185 }
1186 return nil
1187 }
1188
1189
1190 func (f *File) DWARF() (*dwarf.Data, error) {
1191 dwarfSuffix := func(s *Section) string {
1192 switch {
1193 case strings.HasPrefix(s.Name, "__debug_"):
1194 return s.Name[8:]
1195 case strings.HasPrefix(s.Name, "__zdebug_"):
1196 return s.Name[9:]
1197 default:
1198 return ""
1199 }
1200
1201 }
1202 sectionData := func(s *Section) ([]byte, error) {
1203 b, err := s.Data()
1204 if err != nil && uint64(len(b)) < s.Size {
1205 return nil, err
1206 }
1207
1208 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1209 dlen := binary.BigEndian.Uint64(b[4:12])
1210 dbuf := make([]byte, dlen)
1211 r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1212 if err != nil {
1213 return nil, err
1214 }
1215 if _, err := io.ReadFull(r, dbuf); err != nil {
1216 return nil, err
1217 }
1218 if err := r.Close(); err != nil {
1219 return nil, err
1220 }
1221 b = dbuf
1222 }
1223 return b, nil
1224 }
1225
1226
1227
1228
1229 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1230 for _, s := range f.Sections {
1231 suffix := dwarfSuffix(s)
1232 if suffix == "" {
1233 continue
1234 }
1235 if _, ok := dat[suffix]; !ok {
1236 continue
1237 }
1238 b, err := sectionData(s)
1239 if err != nil {
1240 return nil, err
1241 }
1242 dat[suffix] = b
1243 }
1244
1245 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1246 if err != nil {
1247 return nil, err
1248 }
1249
1250
1251 for i, s := range f.Sections {
1252 suffix := dwarfSuffix(s)
1253 if suffix != "types" {
1254 continue
1255 }
1256
1257 b, err := sectionData(s)
1258 if err != nil {
1259 return nil, err
1260 }
1261
1262 err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
1263 if err != nil {
1264 return nil, err
1265 }
1266 }
1267
1268 return d, nil
1269 }
1270
1271
1272
1273
1274 func (f *File) ImportedSymbols() ([]string, error) {
1275 if f.Dysymtab == nil || f.Symtab == nil {
1276 return nil, formatError(0, "missing symbol table, f.Dsymtab=%v, f.Symtab=%v", f.Dysymtab, f.Symtab)
1277 }
1278
1279 st := f.Symtab
1280 dt := f.Dysymtab
1281 var all []string
1282 for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
1283 all = append(all, s.Name)
1284 }
1285 return all, nil
1286 }
1287
1288
1289
1290
1291 func (f *File) ImportedLibraries() ([]string, error) {
1292 var all []string
1293 for _, l := range f.Loads {
1294 if lib, ok := l.(*Dylib); ok {
1295 all = append(all, lib.Name)
1296 }
1297 }
1298 return all, nil
1299 }
1300
1301 func RoundUp(x, align uint64) uint64 {
1302 return uint64((x + align - 1) & -align)
1303 }
1304
View as plain text