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
72 sect := f.elf.Section(".gosymtab")
73 if sect == nil {
74
75 sect = f.elf.Section(".data.rel.ro.gosymtab")
76 }
77 if sect != nil {
78 if symtab, err = sect.Data(); err != nil {
79 return 0, nil, nil, err
80 }
81 } else {
82
83 symtab = f.symbolData("runtime.symtab", "runtime.esymtab")
84 }
85
86 sect = f.elf.Section(".gopclntab")
87 if sect == nil {
88
89 sect = f.elf.Section(".data.rel.ro.gopclntab")
90 }
91 if sect != nil {
92 if pclntab, err = sect.Data(); err != nil {
93 return 0, nil, nil, err
94 }
95 } else {
96
97 pclntab = f.symbolData("runtime.pclntab", "runtime.epclntab")
98 }
99
100 return textStart, symtab, pclntab, nil
101 }
102
103 func (f *elfFile) text() (textStart uint64, text []byte, err error) {
104 sect := f.elf.Section(".text")
105 if sect == nil {
106 return 0, nil, fmt.Errorf("text section not found")
107 }
108 textStart = sect.Addr
109 text, err = sect.Data()
110 return
111 }
112
113 func (f *elfFile) goarch() string {
114 switch f.elf.Machine {
115 case elf.EM_386:
116 return "386"
117 case elf.EM_X86_64:
118 return "amd64"
119 case elf.EM_ARM:
120 return "arm"
121 case elf.EM_AARCH64:
122 return "arm64"
123 case elf.EM_PPC64:
124 if f.elf.ByteOrder == binary.LittleEndian {
125 return "ppc64le"
126 }
127 return "ppc64"
128 case elf.EM_S390:
129 return "s390x"
130 }
131 return ""
132 }
133
134 func (f *elfFile) loadAddress() (uint64, error) {
135 for _, p := range f.elf.Progs {
136 if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
137
138
139
140
141
142 return p.Vaddr - p.Vaddr%p.Align, nil
143 }
144 }
145 return 0, fmt.Errorf("unknown load address")
146 }
147
148 func (f *elfFile) dwarf() (*dwarf.Data, error) {
149 return f.elf.DWARF()
150 }
151
152 func (f *elfFile) symbolData(start, end string) []byte {
153 elfSyms, err := f.elf.Symbols()
154 if err != nil {
155 return nil
156 }
157 var addr, eaddr uint64
158 for _, s := range elfSyms {
159 if s.Name == start {
160 addr = s.Value
161 } else if s.Name == end {
162 eaddr = s.Value
163 }
164 if addr != 0 && eaddr != 0 {
165 break
166 }
167 }
168 if addr == 0 || eaddr < addr {
169 return nil
170 }
171 size := eaddr - addr
172 data := make([]byte, size)
173 for _, prog := range f.elf.Progs {
174 if prog.Vaddr <= addr && addr+size-1 <= prog.Vaddr+prog.Filesz-1 {
175 if _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)); err != nil {
176 return nil
177 }
178 return data
179 }
180 }
181 return nil
182 }
183
View as plain text