URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [debug/] [macho/] [file.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package macho implements access to Mach-O object files, as defined by// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.package macho// High level access to low level data structures.import ("bytes""debug/dwarf""encoding/binary""errors""fmt""io""os")// A File represents an open Mach-O file.type File struct {FileHeaderByteOrder binary.ByteOrderLoads []LoadSections []*SectionSymtab *SymtabDysymtab *Dysymtabcloser io.Closer}// A Load represents any Mach-O load command.type Load interface {Raw() []byte}// A LoadBytes is the uninterpreted bytes of a Mach-O load command.type LoadBytes []bytefunc (b LoadBytes) Raw() []byte { return b }// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.type SegmentHeader struct {Cmd LoadCmdLen uint32Name stringAddr uint64Memsz uint64Offset uint64Filesz uint64Maxprot uint32Prot uint32Nsect uint32Flag uint32}// A Segment represents a Mach-O 32-bit or 64-bit load segment command.type Segment struct {LoadBytesSegmentHeader// Embed ReaderAt for ReadAt method.// Do not embed SectionReader directly// to avoid having Read and Seek.// If a client wants Read and Seek it must use// Open() to avoid fighting over the seek offset// with other clients.io.ReaderAtsr *io.SectionReader}// Data reads and returns the contents of the segment.func (s *Segment) Data() ([]byte, error) {dat := make([]byte, s.sr.Size())n, err := s.sr.ReadAt(dat, 0)return dat[0:n], err}// Open returns a new ReadSeeker reading the segment.func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }type SectionHeader struct {Name stringSeg stringAddr uint64Size uint64Offset uint32Align uint32Reloff uint32Nreloc uint32Flags uint32}type Section struct {SectionHeader// Embed ReaderAt for ReadAt method.// Do not embed SectionReader directly// to avoid having Read and Seek.// If a client wants Read and Seek it must use// Open() to avoid fighting over the seek offset// with other clients.io.ReaderAtsr *io.SectionReader}// Data reads and returns the contents of the Mach-O section.func (s *Section) Data() ([]byte, error) {dat := make([]byte, s.sr.Size())n, err := s.sr.ReadAt(dat, 0)return dat[0:n], err}// Open returns a new ReadSeeker reading the Mach-O section.func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }// A Dylib represents a Mach-O load dynamic library command.type Dylib struct {LoadBytesName stringTime uint32CurrentVersion uint32CompatVersion uint32}// A Symtab represents a Mach-O symbol table command.type Symtab struct {LoadBytesSymtabCmdSyms []Symbol}// A Dysymtab represents a Mach-O dynamic symbol table command.type Dysymtab struct {LoadBytesDysymtabCmdIndirectSyms []uint32 // indices into Symtab.Syms}/** Mach-O reader*/type FormatError struct {off int64msg stringval interface{}}func (e *FormatError) Error() string {msg := e.msgif e.val != nil {msg += fmt.Sprintf(" '%v'", e.val)}msg += fmt.Sprintf(" in record at byte %#x", e.off)return msg}// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.func Open(name string) (*File, error) {f, err := os.Open(name)if err != nil {return nil, err}ff, err := NewFile(f)if err != nil {f.Close()return nil, err}ff.closer = freturn ff, nil}// Close closes the File.// If the File was created using NewFile directly instead of Open,// Close has no effect.func (f *File) Close() error {var err errorif f.closer != nil {err = f.closer.Close()f.closer = nil}return err}// NewFile creates a new File for accessing a Mach-O binary in an underlying reader.// The Mach-O binary is expected to start at position 0 in the ReaderAt.func NewFile(r io.ReaderAt) (*File, error) {f := new(File)sr := io.NewSectionReader(r, 0, 1<<63-1)// Read and decode Mach magic to determine byte order, size.// Magic32 and Magic64 differ only in the bottom bit.var ident [4]byteif _, err := r.ReadAt(ident[0:], 0); err != nil {return nil, err}be := binary.BigEndian.Uint32(ident[0:])le := binary.LittleEndian.Uint32(ident[0:])switch Magic32 &^ 1 {case be &^ 1:f.ByteOrder = binary.BigEndianf.Magic = becase le &^ 1:f.ByteOrder = binary.LittleEndianf.Magic = ledefault:return nil, &FormatError{0, "invalid magic number", nil}}// Read entire file header.if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {return nil, err}// Then load commands.offset := int64(fileHeaderSize32)if f.Magic == Magic64 {offset = fileHeaderSize64}dat := make([]byte, f.Cmdsz)if _, err := r.ReadAt(dat, offset); err != nil {return nil, err}f.Loads = make([]Load, f.Ncmd)bo := f.ByteOrderfor i := range f.Loads {// Each load command begins with uint32 command and length.if len(dat) < 8 {return nil, &FormatError{offset, "command block too small", nil}}cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])if siz < 8 || siz > uint32(len(dat)) {return nil, &FormatError{offset, "invalid command block size", nil}}var cmddat []bytecmddat, dat = dat[0:siz], dat[siz:]offset += int64(siz)var s *Segmentswitch cmd {default:f.Loads[i] = LoadBytes(cmddat)case LoadCmdDylib:var hdr DylibCmdb := bytes.NewBuffer(cmddat)if err := binary.Read(b, bo, &hdr); err != nil {return nil, err}l := new(Dylib)if hdr.Name >= uint32(len(cmddat)) {return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}}l.Name = cstring(cmddat[hdr.Name:])l.Time = hdr.Timel.CurrentVersion = hdr.CurrentVersionl.CompatVersion = hdr.CompatVersionl.LoadBytes = LoadBytes(cmddat)f.Loads[i] = lcase LoadCmdSymtab:var hdr SymtabCmdb := bytes.NewBuffer(cmddat)if err := binary.Read(b, bo, &hdr); err != nil {return nil, err}strtab := make([]byte, hdr.Strsize)if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {return nil, err}var symsz intif f.Magic == Magic64 {symsz = 16} else {symsz = 12}symdat := make([]byte, int(hdr.Nsyms)*symsz)if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {return nil, err}st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)if err != nil {return nil, err}f.Loads[i] = stf.Symtab = stcase LoadCmdDysymtab:var hdr DysymtabCmdb := bytes.NewBuffer(cmddat)if err := binary.Read(b, bo, &hdr); err != nil {return nil, err}dat := make([]byte, hdr.Nindirectsyms*4)if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {return nil, err}x := make([]uint32, hdr.Nindirectsyms)if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {return nil, err}st := new(Dysymtab)st.LoadBytes = LoadBytes(cmddat)st.DysymtabCmd = hdrst.IndirectSyms = xf.Loads[i] = stf.Dysymtab = stcase LoadCmdSegment:var seg32 Segment32b := bytes.NewBuffer(cmddat)if err := binary.Read(b, bo, &seg32); err != nil {return nil, err}s = new(Segment)s.LoadBytes = cmddats.Cmd = cmds.Len = sizs.Name = cstring(seg32.Name[0:])s.Addr = uint64(seg32.Addr)s.Memsz = uint64(seg32.Memsz)s.Offset = uint64(seg32.Offset)s.Filesz = uint64(seg32.Filesz)s.Maxprot = seg32.Maxprots.Prot = seg32.Prots.Nsect = seg32.Nsects.Flag = seg32.Flagf.Loads[i] = sfor i := 0; i < int(s.Nsect); i++ {var sh32 Section32if err := binary.Read(b, bo, &sh32); err != nil {return nil, err}sh := new(Section)sh.Name = cstring(sh32.Name[0:])sh.Seg = cstring(sh32.Seg[0:])sh.Addr = uint64(sh32.Addr)sh.Size = uint64(sh32.Size)sh.Offset = sh32.Offsetsh.Align = sh32.Alignsh.Reloff = sh32.Reloffsh.Nreloc = sh32.Nrelocsh.Flags = sh32.Flagsf.pushSection(sh, r)}case LoadCmdSegment64:var seg64 Segment64b := bytes.NewBuffer(cmddat)if err := binary.Read(b, bo, &seg64); err != nil {return nil, err}s = new(Segment)s.LoadBytes = cmddats.Cmd = cmds.Len = sizs.Name = cstring(seg64.Name[0:])s.Addr = seg64.Addrs.Memsz = seg64.Memszs.Offset = seg64.Offsets.Filesz = seg64.Fileszs.Maxprot = seg64.Maxprots.Prot = seg64.Prots.Nsect = seg64.Nsects.Flag = seg64.Flagf.Loads[i] = sfor i := 0; i < int(s.Nsect); i++ {var sh64 Section64if err := binary.Read(b, bo, &sh64); err != nil {return nil, err}sh := new(Section)sh.Name = cstring(sh64.Name[0:])sh.Seg = cstring(sh64.Seg[0:])sh.Addr = sh64.Addrsh.Size = sh64.Sizesh.Offset = sh64.Offsetsh.Align = sh64.Alignsh.Reloff = sh64.Reloffsh.Nreloc = sh64.Nrelocsh.Flags = sh64.Flagsf.pushSection(sh, r)}}if s != nil {s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))s.ReaderAt = s.sr}}return f, nil}func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {bo := f.ByteOrdersymtab := make([]Symbol, hdr.Nsyms)b := bytes.NewBuffer(symdat)for i := range symtab {var n Nlist64if f.Magic == Magic64 {if err := binary.Read(b, bo, &n); err != nil {return nil, err}} else {var n32 Nlist32if err := binary.Read(b, bo, &n32); err != nil {return nil, err}n.Name = n32.Namen.Type = n32.Typen.Sect = n32.Sectn.Desc = n32.Descn.Value = uint64(n32.Value)}sym := &symtab[i]if n.Name >= uint32(len(strtab)) {return nil, &FormatError{offset, "invalid name in symbol table", n.Name}}sym.Name = cstring(strtab[n.Name:])sym.Type = n.Typesym.Sect = n.Sectsym.Desc = n.Descsym.Value = n.Value}st := new(Symtab)st.LoadBytes = LoadBytes(cmddat)st.Syms = symtabreturn st, nil}func (f *File) pushSection(sh *Section, r io.ReaderAt) {f.Sections = append(f.Sections, sh)sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))sh.ReaderAt = sh.sr}func cstring(b []byte) string {var i intfor i = 0; i < len(b) && b[i] != 0; i++ {}return string(b[0:i])}// Segment returns the first Segment with the given name, or nil if no such segment exists.func (f *File) Segment(name string) *Segment {for _, l := range f.Loads {if s, ok := l.(*Segment); ok && s.Name == name {return s}}return nil}// Section returns the first section with the given name, or nil if no such// section exists.func (f *File) Section(name string) *Section {for _, s := range f.Sections {if s.Name == name {return s}}return nil}// DWARF returns the DWARF debug information for the Mach-O file.func (f *File) DWARF() (*dwarf.Data, error) {// There are many other DWARF sections, but these// are the required ones, and the debug/dwarf package// does not use the others, so don't bother loading them.var names = [...]string{"abbrev", "info", "str"}var dat [len(names)][]bytefor i, name := range names {name = "__debug_" + names := f.Section(name)if s == nil {return nil, errors.New("missing Mach-O section " + name)}b, err := s.Data()if err != nil && uint64(len(b)) < s.Size {return nil, err}dat[i] = b}abbrev, info, str := dat[0], dat[1], dat[2]return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)}// ImportedSymbols returns the names of all symbols// referred to by the binary f that are expected to be// satisfied by other libraries at dynamic load time.func (f *File) ImportedSymbols() ([]string, error) {if f.Dysymtab == nil || f.Symtab == nil {return nil, &FormatError{0, "missing symbol table", nil}}st := f.Symtabdt := f.Dysymtabvar all []stringfor _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {all = append(all, s.Name)}return all, nil}// ImportedLibraries returns the paths of all libraries// referred to by the binary f that are expected to be// linked with the binary at dynamic link time.func (f *File) ImportedLibraries() ([]string, error) {var all []stringfor _, l := range f.Loads {if lib, ok := l.(*Dylib); ok {all = append(all, lib.Name)}}return all, nil}
