1
2
3
4
5
6
7 package objfile
8
9 import (
10 "debug/dwarf"
11 "debug/elf"
12 "encoding/binary"
13 "fmt"
14 "io"
15 )
16
17 type elfFile struct {
18 elf *elf.File
19 }
20
21 func openElf(r io.ReaderAt) (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_AARCH64:
103 return "arm64"
104 case elf.EM_PPC64:
105 if f.elf.ByteOrder == binary.LittleEndian {
106 return "ppc64le"
107 }
108 return "ppc64"
109 case elf.EM_S390:
110 return "s390x"
111 }
112 return ""
113 }
114
115 func (f *elfFile) loadAddress() (uint64, error) {
116 for _, p := range f.elf.Progs {
117 if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
118 return p.Vaddr, nil
119 }
120 }
121 return 0, fmt.Errorf("unknown load address")
122 }
123
124 func (f *elfFile) dwarf() (*dwarf.Data, error) {
125 return f.elf.DWARF()
126 }
127
View as plain text