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