...

Source file src/debug/macho/file.go

Documentation: debug/macho

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package macho implements access to Mach-O object files.
     6  package macho
     7  
     8  // High level access to low level data structures.
     9  
    10  import (
    11  	"bytes"
    12  	"compress/zlib"
    13  	"debug/dwarf"
    14  	"encoding/binary"
    15  	"fmt"
    16  	"io"
    17  	"os"
    18  	"strings"
    19  )
    20  
    21  // A File represents an open Mach-O file.
    22  type File struct {
    23  	FileHeader
    24  	ByteOrder binary.ByteOrder
    25  	Loads     []Load
    26  	Sections  []*Section
    27  
    28  	Symtab   *Symtab
    29  	Dysymtab *Dysymtab
    30  
    31  	closer io.Closer
    32  }
    33  
    34  // A Load represents any Mach-O load command.
    35  type Load interface {
    36  	Raw() []byte
    37  }
    38  
    39  // A LoadBytes is the uninterpreted bytes of a Mach-O load command.
    40  type LoadBytes []byte
    41  
    42  func (b LoadBytes) Raw() []byte { return b }
    43  
    44  // A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
    45  type SegmentHeader struct {
    46  	Cmd     LoadCmd
    47  	Len     uint32
    48  	Name    string
    49  	Addr    uint64
    50  	Memsz   uint64
    51  	Offset  uint64
    52  	Filesz  uint64
    53  	Maxprot uint32
    54  	Prot    uint32
    55  	Nsect   uint32
    56  	Flag    uint32
    57  }
    58  
    59  // A Segment represents a Mach-O 32-bit or 64-bit load segment command.
    60  type Segment struct {
    61  	LoadBytes
    62  	SegmentHeader
    63  
    64  	// Embed ReaderAt for ReadAt method.
    65  	// Do not embed SectionReader directly
    66  	// to avoid having Read and Seek.
    67  	// If a client wants Read and Seek it must use
    68  	// Open() to avoid fighting over the seek offset
    69  	// with other clients.
    70  	io.ReaderAt
    71  	sr *io.SectionReader
    72  }
    73  
    74  // Data reads and returns the contents of the segment.
    75  func (s *Segment) Data() ([]byte, error) {
    76  	dat := make([]byte, s.sr.Size())
    77  	n, err := s.sr.ReadAt(dat, 0)
    78  	if n == len(dat) {
    79  		err = nil
    80  	}
    81  	return dat[0:n], err
    82  }
    83  
    84  // Open returns a new ReadSeeker reading the segment.
    85  func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
    86  
    87  type SectionHeader struct {
    88  	Name   string
    89  	Seg    string
    90  	Addr   uint64
    91  	Size   uint64
    92  	Offset uint32
    93  	Align  uint32
    94  	Reloff uint32
    95  	Nreloc uint32
    96  	Flags  uint32
    97  }
    98  
    99  // A Reloc represents a Mach-O relocation.
   100  type Reloc struct {
   101  	Addr  uint32
   102  	Value uint32
   103  	// when Scattered == false && Extern == true, Value is the symbol number.
   104  	// when Scattered == false && Extern == false, Value is the section number.
   105  	// when Scattered == true, Value is the value that this reloc refers to.
   106  	Type      uint8
   107  	Len       uint8 // 0=byte, 1=word, 2=long, 3=quad
   108  	Pcrel     bool
   109  	Extern    bool // valid if Scattered == false
   110  	Scattered bool
   111  }
   112  
   113  type Section struct {
   114  	SectionHeader
   115  	Relocs []Reloc
   116  
   117  	// Embed ReaderAt for ReadAt method.
   118  	// Do not embed SectionReader directly
   119  	// to avoid having Read and Seek.
   120  	// If a client wants Read and Seek it must use
   121  	// Open() to avoid fighting over the seek offset
   122  	// with other clients.
   123  	io.ReaderAt
   124  	sr *io.SectionReader
   125  }
   126  
   127  // Data reads and returns the contents of the Mach-O section.
   128  func (s *Section) Data() ([]byte, error) {
   129  	dat := make([]byte, s.sr.Size())
   130  	n, err := s.sr.ReadAt(dat, 0)
   131  	if n == len(dat) {
   132  		err = nil
   133  	}
   134  	return dat[0:n], err
   135  }
   136  
   137  // Open returns a new ReadSeeker reading the Mach-O section.
   138  func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
   139  
   140  // A Dylib represents a Mach-O load dynamic library command.
   141  type Dylib struct {
   142  	LoadBytes
   143  	Name           string
   144  	Time           uint32
   145  	CurrentVersion uint32
   146  	CompatVersion  uint32
   147  }
   148  
   149  // A Symtab represents a Mach-O symbol table command.
   150  type Symtab struct {
   151  	LoadBytes
   152  	SymtabCmd
   153  	Syms []Symbol
   154  }
   155  
   156  // A Dysymtab represents a Mach-O dynamic symbol table command.
   157  type Dysymtab struct {
   158  	LoadBytes
   159  	DysymtabCmd
   160  	IndirectSyms []uint32 // indices into Symtab.Syms
   161  }
   162  
   163  // A Rpath represents a Mach-O rpath command.
   164  type Rpath struct {
   165  	LoadBytes
   166  	Path string
   167  }
   168  
   169  // A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
   170  type Symbol struct {
   171  	Name  string
   172  	Type  uint8
   173  	Sect  uint8
   174  	Desc  uint16
   175  	Value uint64
   176  }
   177  
   178  /*
   179   * Mach-O reader
   180   */
   181  
   182  // FormatError is returned by some operations if the data does
   183  // not have the correct format for an object file.
   184  type FormatError struct {
   185  	off int64
   186  	msg string
   187  	val any
   188  }
   189  
   190  func (e *FormatError) Error() string {
   191  	msg := e.msg
   192  	if e.val != nil {
   193  		msg += fmt.Sprintf(" '%v'", e.val)
   194  	}
   195  	msg += fmt.Sprintf(" in record at byte %#x", e.off)
   196  	return msg
   197  }
   198  
   199  // Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
   200  func Open(name string) (*File, error) {
   201  	f, err := os.Open(name)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	ff, err := NewFile(f)
   206  	if err != nil {
   207  		f.Close()
   208  		return nil, err
   209  	}
   210  	ff.closer = f
   211  	return ff, nil
   212  }
   213  
   214  // Close closes the File.
   215  // If the File was created using NewFile directly instead of Open,
   216  // Close has no effect.
   217  func (f *File) Close() error {
   218  	var err error
   219  	if f.closer != nil {
   220  		err = f.closer.Close()
   221  		f.closer = nil
   222  	}
   223  	return err
   224  }
   225  
   226  // NewFile creates a new File for accessing a Mach-O binary in an underlying reader.
   227  // The Mach-O binary is expected to start at position 0 in the ReaderAt.
   228  func NewFile(r io.ReaderAt) (*File, error) {
   229  	f := new(File)
   230  	sr := io.NewSectionReader(r, 0, 1<<63-1)
   231  
   232  	// Read and decode Mach magic to determine byte order, size.
   233  	// Magic32 and Magic64 differ only in the bottom bit.
   234  	var ident [4]byte
   235  	if _, err := r.ReadAt(ident[0:], 0); err != nil {
   236  		return nil, err
   237  	}
   238  	be := binary.BigEndian.Uint32(ident[0:])
   239  	le := binary.LittleEndian.Uint32(ident[0:])
   240  	switch Magic32 &^ 1 {
   241  	case be &^ 1:
   242  		f.ByteOrder = binary.BigEndian
   243  		f.Magic = be
   244  	case le &^ 1:
   245  		f.ByteOrder = binary.LittleEndian
   246  		f.Magic = le
   247  	default:
   248  		return nil, &FormatError{0, "invalid magic number", nil}
   249  	}
   250  
   251  	// Read entire file header.
   252  	if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	// Then load commands.
   257  	offset := int64(fileHeaderSize32)
   258  	if f.Magic == Magic64 {
   259  		offset = fileHeaderSize64
   260  	}
   261  	dat := make([]byte, f.Cmdsz)
   262  	if _, err := r.ReadAt(dat, offset); err != nil {
   263  		return nil, err
   264  	}
   265  	f.Loads = make([]Load, f.Ncmd)
   266  	bo := f.ByteOrder
   267  	for i := range f.Loads {
   268  		// Each load command begins with uint32 command and length.
   269  		if len(dat) < 8 {
   270  			return nil, &FormatError{offset, "command block too small", nil}
   271  		}
   272  		cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
   273  		if siz < 8 || siz > uint32(len(dat)) {
   274  			return nil, &FormatError{offset, "invalid command block size", nil}
   275  		}
   276  		var cmddat []byte
   277  		cmddat, dat = dat[0:siz], dat[siz:]
   278  		offset += int64(siz)
   279  		var s *Segment
   280  		switch cmd {
   281  		default:
   282  			f.Loads[i] = LoadBytes(cmddat)
   283  
   284  		case LoadCmdRpath:
   285  			var hdr RpathCmd
   286  			b := bytes.NewReader(cmddat)
   287  			if err := binary.Read(b, bo, &hdr); err != nil {
   288  				return nil, err
   289  			}
   290  			l := new(Rpath)
   291  			if hdr.Path >= uint32(len(cmddat)) {
   292  				return nil, &FormatError{offset, "invalid path in rpath command", hdr.Path}
   293  			}
   294  			l.Path = cstring(cmddat[hdr.Path:])
   295  			l.LoadBytes = LoadBytes(cmddat)
   296  			f.Loads[i] = l
   297  
   298  		case LoadCmdDylib:
   299  			var hdr DylibCmd
   300  			b := bytes.NewReader(cmddat)
   301  			if err := binary.Read(b, bo, &hdr); err != nil {
   302  				return nil, err
   303  			}
   304  			l := new(Dylib)
   305  			if hdr.Name >= uint32(len(cmddat)) {
   306  				return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
   307  			}
   308  			l.Name = cstring(cmddat[hdr.Name:])
   309  			l.Time = hdr.Time
   310  			l.CurrentVersion = hdr.CurrentVersion
   311  			l.CompatVersion = hdr.CompatVersion
   312  			l.LoadBytes = LoadBytes(cmddat)
   313  			f.Loads[i] = l
   314  
   315  		case LoadCmdSymtab:
   316  			var hdr SymtabCmd
   317  			b := bytes.NewReader(cmddat)
   318  			if err := binary.Read(b, bo, &hdr); err != nil {
   319  				return nil, err
   320  			}
   321  			strtab := make([]byte, hdr.Strsize)
   322  			if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
   323  				return nil, err
   324  			}
   325  			var symsz int
   326  			if f.Magic == Magic64 {
   327  				symsz = 16
   328  			} else {
   329  				symsz = 12
   330  			}
   331  			symdat := make([]byte, int(hdr.Nsyms)*symsz)
   332  			if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
   333  				return nil, err
   334  			}
   335  			st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
   336  			if err != nil {
   337  				return nil, err
   338  			}
   339  			f.Loads[i] = st
   340  			f.Symtab = st
   341  
   342  		case LoadCmdDysymtab:
   343  			var hdr DysymtabCmd
   344  			b := bytes.NewReader(cmddat)
   345  			if err := binary.Read(b, bo, &hdr); err != nil {
   346  				return nil, err
   347  			}
   348  			if hdr.Iundefsym > uint32(len(f.Symtab.Syms)) {
   349  				return nil, &FormatError{offset, fmt.Sprintf(
   350  					"undefined symbols index in dynamic symbol table command is greater than symbol table length (%d > %d)",
   351  					hdr.Iundefsym, len(f.Symtab.Syms)), nil}
   352  			} else if hdr.Iundefsym+hdr.Nundefsym > uint32(len(f.Symtab.Syms)) {
   353  				return nil, &FormatError{offset, fmt.Sprintf(
   354  					"number of undefined symbols after index in dynamic symbol table command is greater than symbol table length (%d > %d)",
   355  					hdr.Iundefsym+hdr.Nundefsym, len(f.Symtab.Syms)), nil}
   356  			}
   357  			dat := make([]byte, hdr.Nindirectsyms*4)
   358  			if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
   359  				return nil, err
   360  			}
   361  			x := make([]uint32, hdr.Nindirectsyms)
   362  			if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
   363  				return nil, err
   364  			}
   365  			st := new(Dysymtab)
   366  			st.LoadBytes = LoadBytes(cmddat)
   367  			st.DysymtabCmd = hdr
   368  			st.IndirectSyms = x
   369  			f.Loads[i] = st
   370  			f.Dysymtab = st
   371  
   372  		case LoadCmdSegment:
   373  			var seg32 Segment32
   374  			b := bytes.NewReader(cmddat)
   375  			if err := binary.Read(b, bo, &seg32); err != nil {
   376  				return nil, err
   377  			}
   378  			s = new(Segment)
   379  			s.LoadBytes = cmddat
   380  			s.Cmd = cmd
   381  			s.Len = siz
   382  			s.Name = cstring(seg32.Name[0:])
   383  			s.Addr = uint64(seg32.Addr)
   384  			s.Memsz = uint64(seg32.Memsz)
   385  			s.Offset = uint64(seg32.Offset)
   386  			s.Filesz = uint64(seg32.Filesz)
   387  			s.Maxprot = seg32.Maxprot
   388  			s.Prot = seg32.Prot
   389  			s.Nsect = seg32.Nsect
   390  			s.Flag = seg32.Flag
   391  			f.Loads[i] = s
   392  			for i := 0; i < int(s.Nsect); i++ {
   393  				var sh32 Section32
   394  				if err := binary.Read(b, bo, &sh32); err != nil {
   395  					return nil, err
   396  				}
   397  				sh := new(Section)
   398  				sh.Name = cstring(sh32.Name[0:])
   399  				sh.Seg = cstring(sh32.Seg[0:])
   400  				sh.Addr = uint64(sh32.Addr)
   401  				sh.Size = uint64(sh32.Size)
   402  				sh.Offset = sh32.Offset
   403  				sh.Align = sh32.Align
   404  				sh.Reloff = sh32.Reloff
   405  				sh.Nreloc = sh32.Nreloc
   406  				sh.Flags = sh32.Flags
   407  				if err := f.pushSection(sh, r); err != nil {
   408  					return nil, err
   409  				}
   410  			}
   411  
   412  		case LoadCmdSegment64:
   413  			var seg64 Segment64
   414  			b := bytes.NewReader(cmddat)
   415  			if err := binary.Read(b, bo, &seg64); err != nil {
   416  				return nil, err
   417  			}
   418  			s = new(Segment)
   419  			s.LoadBytes = cmddat
   420  			s.Cmd = cmd
   421  			s.Len = siz
   422  			s.Name = cstring(seg64.Name[0:])
   423  			s.Addr = seg64.Addr
   424  			s.Memsz = seg64.Memsz
   425  			s.Offset = seg64.Offset
   426  			s.Filesz = seg64.Filesz
   427  			s.Maxprot = seg64.Maxprot
   428  			s.Prot = seg64.Prot
   429  			s.Nsect = seg64.Nsect
   430  			s.Flag = seg64.Flag
   431  			f.Loads[i] = s
   432  			for i := 0; i < int(s.Nsect); i++ {
   433  				var sh64 Section64
   434  				if err := binary.Read(b, bo, &sh64); err != nil {
   435  					return nil, err
   436  				}
   437  				sh := new(Section)
   438  				sh.Name = cstring(sh64.Name[0:])
   439  				sh.Seg = cstring(sh64.Seg[0:])
   440  				sh.Addr = sh64.Addr
   441  				sh.Size = sh64.Size
   442  				sh.Offset = sh64.Offset
   443  				sh.Align = sh64.Align
   444  				sh.Reloff = sh64.Reloff
   445  				sh.Nreloc = sh64.Nreloc
   446  				sh.Flags = sh64.Flags
   447  				if err := f.pushSection(sh, r); err != nil {
   448  					return nil, err
   449  				}
   450  			}
   451  		}
   452  		if s != nil {
   453  			s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
   454  			s.ReaderAt = s.sr
   455  		}
   456  	}
   457  	return f, nil
   458  }
   459  
   460  func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
   461  	bo := f.ByteOrder
   462  	symtab := make([]Symbol, hdr.Nsyms)
   463  	b := bytes.NewReader(symdat)
   464  	for i := range symtab {
   465  		var n Nlist64
   466  		if f.Magic == Magic64 {
   467  			if err := binary.Read(b, bo, &n); err != nil {
   468  				return nil, err
   469  			}
   470  		} else {
   471  			var n32 Nlist32
   472  			if err := binary.Read(b, bo, &n32); err != nil {
   473  				return nil, err
   474  			}
   475  			n.Name = n32.Name
   476  			n.Type = n32.Type
   477  			n.Sect = n32.Sect
   478  			n.Desc = n32.Desc
   479  			n.Value = uint64(n32.Value)
   480  		}
   481  		sym := &symtab[i]
   482  		if n.Name >= uint32(len(strtab)) {
   483  			return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
   484  		}
   485  		// We add "_" to Go symbols. Strip it here. See issue 33808.
   486  		name := cstring(strtab[n.Name:])
   487  		if strings.Contains(name, ".") && name[0] == '_' {
   488  			name = name[1:]
   489  		}
   490  		sym.Name = name
   491  		sym.Type = n.Type
   492  		sym.Sect = n.Sect
   493  		sym.Desc = n.Desc
   494  		sym.Value = n.Value
   495  	}
   496  	st := new(Symtab)
   497  	st.LoadBytes = LoadBytes(cmddat)
   498  	st.Syms = symtab
   499  	return st, nil
   500  }
   501  
   502  type relocInfo struct {
   503  	Addr   uint32
   504  	Symnum uint32
   505  }
   506  
   507  func (f *File) pushSection(sh *Section, r io.ReaderAt) error {
   508  	f.Sections = append(f.Sections, sh)
   509  	sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
   510  	sh.ReaderAt = sh.sr
   511  
   512  	if sh.Nreloc > 0 {
   513  		reldat := make([]byte, int(sh.Nreloc)*8)
   514  		if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil {
   515  			return err
   516  		}
   517  		b := bytes.NewReader(reldat)
   518  
   519  		bo := f.ByteOrder
   520  
   521  		sh.Relocs = make([]Reloc, sh.Nreloc)
   522  		for i := range sh.Relocs {
   523  			rel := &sh.Relocs[i]
   524  
   525  			var ri relocInfo
   526  			if err := binary.Read(b, bo, &ri); err != nil {
   527  				return err
   528  			}
   529  
   530  			if ri.Addr&(1<<31) != 0 { // scattered
   531  				rel.Addr = ri.Addr & (1<<24 - 1)
   532  				rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1))
   533  				rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1))
   534  				rel.Pcrel = ri.Addr&(1<<30) != 0
   535  				rel.Value = ri.Symnum
   536  				rel.Scattered = true
   537  			} else {
   538  				switch bo {
   539  				case binary.LittleEndian:
   540  					rel.Addr = ri.Addr
   541  					rel.Value = ri.Symnum & (1<<24 - 1)
   542  					rel.Pcrel = ri.Symnum&(1<<24) != 0
   543  					rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1))
   544  					rel.Extern = ri.Symnum&(1<<27) != 0
   545  					rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1))
   546  				case binary.BigEndian:
   547  					rel.Addr = ri.Addr
   548  					rel.Value = ri.Symnum >> 8
   549  					rel.Pcrel = ri.Symnum&(1<<7) != 0
   550  					rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1))
   551  					rel.Extern = ri.Symnum&(1<<4) != 0
   552  					rel.Type = uint8(ri.Symnum & (1<<4 - 1))
   553  				default:
   554  					panic("unreachable")
   555  				}
   556  			}
   557  		}
   558  	}
   559  
   560  	return nil
   561  }
   562  
   563  func cstring(b []byte) string {
   564  	i := bytes.IndexByte(b, 0)
   565  	if i == -1 {
   566  		i = len(b)
   567  	}
   568  	return string(b[0:i])
   569  }
   570  
   571  // Segment returns the first Segment with the given name, or nil if no such segment exists.
   572  func (f *File) Segment(name string) *Segment {
   573  	for _, l := range f.Loads {
   574  		if s, ok := l.(*Segment); ok && s.Name == name {
   575  			return s
   576  		}
   577  	}
   578  	return nil
   579  }
   580  
   581  // Section returns the first section with the given name, or nil if no such
   582  // section exists.
   583  func (f *File) Section(name string) *Section {
   584  	for _, s := range f.Sections {
   585  		if s.Name == name {
   586  			return s
   587  		}
   588  	}
   589  	return nil
   590  }
   591  
   592  // DWARF returns the DWARF debug information for the Mach-O file.
   593  func (f *File) DWARF() (*dwarf.Data, error) {
   594  	dwarfSuffix := func(s *Section) string {
   595  		switch {
   596  		case strings.HasPrefix(s.Name, "__debug_"):
   597  			return s.Name[8:]
   598  		case strings.HasPrefix(s.Name, "__zdebug_"):
   599  			return s.Name[9:]
   600  		default:
   601  			return ""
   602  		}
   603  
   604  	}
   605  	sectionData := func(s *Section) ([]byte, error) {
   606  		b, err := s.Data()
   607  		if err != nil && uint64(len(b)) < s.Size {
   608  			return nil, err
   609  		}
   610  
   611  		if len(b) >= 12 && string(b[:4]) == "ZLIB" {
   612  			dlen := binary.BigEndian.Uint64(b[4:12])
   613  			dbuf := make([]byte, dlen)
   614  			r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
   615  			if err != nil {
   616  				return nil, err
   617  			}
   618  			if _, err := io.ReadFull(r, dbuf); err != nil {
   619  				return nil, err
   620  			}
   621  			if err := r.Close(); err != nil {
   622  				return nil, err
   623  			}
   624  			b = dbuf
   625  		}
   626  		return b, nil
   627  	}
   628  
   629  	// There are many other DWARF sections, but these
   630  	// are the ones the debug/dwarf package uses.
   631  	// Don't bother loading others.
   632  	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
   633  	for _, s := range f.Sections {
   634  		suffix := dwarfSuffix(s)
   635  		if suffix == "" {
   636  			continue
   637  		}
   638  		if _, ok := dat[suffix]; !ok {
   639  			continue
   640  		}
   641  		b, err := sectionData(s)
   642  		if err != nil {
   643  			return nil, err
   644  		}
   645  		dat[suffix] = b
   646  	}
   647  
   648  	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
   649  	if err != nil {
   650  		return nil, err
   651  	}
   652  
   653  	// Look for DWARF4 .debug_types sections and DWARF5 sections.
   654  	for i, s := range f.Sections {
   655  		suffix := dwarfSuffix(s)
   656  		if suffix == "" {
   657  			continue
   658  		}
   659  		if _, ok := dat[suffix]; ok {
   660  			// Already handled.
   661  			continue
   662  		}
   663  
   664  		b, err := sectionData(s)
   665  		if err != nil {
   666  			return nil, err
   667  		}
   668  
   669  		if suffix == "types" {
   670  			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
   671  		} else {
   672  			err = d.AddSection(".debug_"+suffix, b)
   673  		}
   674  		if err != nil {
   675  			return nil, err
   676  		}
   677  	}
   678  
   679  	return d, nil
   680  }
   681  
   682  // ImportedSymbols returns the names of all symbols
   683  // referred to by the binary f that are expected to be
   684  // satisfied by other libraries at dynamic load time.
   685  func (f *File) ImportedSymbols() ([]string, error) {
   686  	if f.Dysymtab == nil || f.Symtab == nil {
   687  		return nil, &FormatError{0, "missing symbol table", nil}
   688  	}
   689  
   690  	st := f.Symtab
   691  	dt := f.Dysymtab
   692  	var all []string
   693  	for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
   694  		all = append(all, s.Name)
   695  	}
   696  	return all, nil
   697  }
   698  
   699  // ImportedLibraries returns the paths of all libraries
   700  // referred to by the binary f that are expected to be
   701  // linked with the binary at dynamic link time.
   702  func (f *File) ImportedLibraries() ([]string, error) {
   703  	var all []string
   704  	for _, l := range f.Loads {
   705  		if lib, ok := l.(*Dylib); ok {
   706  			all = append(all, lib.Name)
   707  		}
   708  	}
   709  	return all, nil
   710  }
   711  

View as plain text