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