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_LOONGARCH:
124 return "loong64"
125 case elf.EM_PPC64:
126 if f.elf.ByteOrder == binary.LittleEndian {
127 return "ppc64le"
128 }
129 return "ppc64"
130 case elf.EM_RISCV:
131 if f.elf.Class == elf.ELFCLASS64 {
132 return "riscv64"
133 }
134 case elf.EM_S390:
135 return "s390x"
136 }
137 return ""
138 }
139
140 func (f *elfFile) loadAddress() (uint64, error) {
141 for _, p := range f.elf.Progs {
142 if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
143
144
145
146
147
148 return p.Vaddr - p.Vaddr%p.Align, nil
149 }
150 }
151 return 0, fmt.Errorf("unknown load address")
152 }
153
154 func (f *elfFile) dwarf() (*dwarf.Data, error) {
155 return f.elf.DWARF()
156 }
157
158 func (f *elfFile) symbolData(start, end string) []byte {
159 elfSyms, err := f.elf.Symbols()
160 if err != nil {
161 return nil
162 }
163 var addr, eaddr uint64
164 for _, s := range elfSyms {
165 if s.Name == start {
166 addr = s.Value
167 } else if s.Name == end {
168 eaddr = s.Value
169 }
170 if addr != 0 && eaddr != 0 {
171 break
172 }
173 }
174 if addr == 0 || eaddr < addr {
175 return nil
176 }
177 size := eaddr - addr
178 data := make([]byte, size)
179 for _, prog := range f.elf.Progs {
180 if prog.Vaddr <= addr && addr+size-1 <= prog.Vaddr+prog.Filesz-1 {
181 if _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)); err != nil {
182 return nil
183 }
184 return data
185 }
186 }
187 return nil
188 }
189
View as plain text