github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/cmd/internal/objfile/elf.go (about)

     1  // Copyright 2013 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  // Parsing of ELF executables (Linux, FreeBSD, and so on).
     6  
     7  package objfile
     8  
     9  import (
    10  	"debug/dwarf"
    11  	"debug/elf"
    12  	"fmt"
    13  	"os"
    14  )
    15  
    16  type elfFile struct {
    17  	elf *elf.File
    18  }
    19  
    20  func openElf(r *os.File) (rawFile, error) {
    21  	f, err := elf.NewFile(r)
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  	return &elfFile{f}, nil
    26  }
    27  
    28  func (f *elfFile) symbols() ([]Sym, error) {
    29  	elfSyms, err := f.elf.Symbols()
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  
    34  	var syms []Sym
    35  	for _, s := range elfSyms {
    36  		sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
    37  		switch s.Section {
    38  		case elf.SHN_UNDEF:
    39  			sym.Code = 'U'
    40  		case elf.SHN_COMMON:
    41  			sym.Code = 'B'
    42  		default:
    43  			i := int(s.Section)
    44  			if i < 0 || i >= len(f.elf.Sections) {
    45  				break
    46  			}
    47  			sect := f.elf.Sections[i]
    48  			switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
    49  			case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
    50  				sym.Code = 'T'
    51  			case elf.SHF_ALLOC:
    52  				sym.Code = 'R'
    53  			case elf.SHF_ALLOC | elf.SHF_WRITE:
    54  				sym.Code = 'D'
    55  			}
    56  		}
    57  		if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
    58  			sym.Code += 'a' - 'A'
    59  		}
    60  		syms = append(syms, sym)
    61  	}
    62  
    63  	return syms, nil
    64  }
    65  
    66  func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
    67  	if sect := f.elf.Section(".text"); sect != nil {
    68  		textStart = sect.Addr
    69  	}
    70  	if sect := f.elf.Section(".gosymtab"); sect != nil {
    71  		if symtab, err = sect.Data(); err != nil {
    72  			return 0, nil, nil, err
    73  		}
    74  	}
    75  	if sect := f.elf.Section(".gopclntab"); sect != nil {
    76  		if pclntab, err = sect.Data(); err != nil {
    77  			return 0, nil, nil, err
    78  		}
    79  	}
    80  	return textStart, symtab, pclntab, nil
    81  }
    82  
    83  func (f *elfFile) text() (textStart uint64, text []byte, err error) {
    84  	sect := f.elf.Section(".text")
    85  	if sect == nil {
    86  		return 0, nil, fmt.Errorf("text section not found")
    87  	}
    88  	textStart = sect.Addr
    89  	text, err = sect.Data()
    90  	return
    91  }
    92  
    93  func (f *elfFile) goarch() string {
    94  	switch f.elf.Machine {
    95  	case elf.EM_386:
    96  		return "386"
    97  	case elf.EM_X86_64:
    98  		return "amd64"
    99  	case elf.EM_ARM:
   100  		return "arm"
   101  	case elf.EM_PPC64:
   102  		return "ppc64"
   103  	case elf.EM_S390:
   104  		return "s390x"
   105  	}
   106  	return ""
   107  }
   108  
   109  func (f *elfFile) loadAddress() (uint64, error) {
   110  	for _, p := range f.elf.Progs {
   111  		if p.Type == elf.PT_LOAD {
   112  			return p.Vaddr, nil
   113  		}
   114  	}
   115  	return 0, fmt.Errorf("unknown load address")
   116  }
   117  
   118  func (f *elfFile) dwarf() (*dwarf.Data, error) {
   119  	return f.elf.DWARF()
   120  }