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