...

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 interface{}
	 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