Source file src/cmd/internal/objfile/goobj.go
1
2
3
4
5
6
7 package objfile
8
9 import (
10 "cmd/internal/goobj"
11 "cmd/internal/objabi"
12 "cmd/internal/sys"
13 "debug/dwarf"
14 "debug/gosym"
15 "errors"
16 "fmt"
17 "os"
18 )
19
20 type goobjFile struct {
21 goobj *goobj.Package
22 f *os.File
23 }
24
25 func openGoFile(r *os.File) (*File, error) {
26 f, err := goobj.Parse(r, `""`)
27 if err != nil {
28 return nil, err
29 }
30 rf := &goobjFile{goobj: f, f: r}
31 if len(f.Native) == 0 {
32 return &File{r, []*Entry{&Entry{raw: rf}}}, nil
33 }
34 entries := make([]*Entry, len(f.Native)+1)
35 entries[0] = &Entry{
36 raw: rf,
37 }
38 L:
39 for i, nr := range f.Native {
40 for _, try := range openers {
41 if raw, err := try(nr); err == nil {
42 entries[i+1] = &Entry{
43 name: nr.Name,
44 raw: raw,
45 }
46 continue L
47 }
48 }
49 return nil, fmt.Errorf("open %s: unrecognized archive member %s", r.Name(), nr.Name)
50 }
51 return &File{r, entries}, nil
52 }
53
54 func goobjName(id goobj.SymID) string {
55 if id.Version == 0 {
56 return id.Name
57 }
58 return fmt.Sprintf("%s<%d>", id.Name, id.Version)
59 }
60
61 func (f *goobjFile) symbols() ([]Sym, error) {
62 seen := make(map[goobj.SymID]bool)
63
64 var syms []Sym
65 for _, s := range f.goobj.Syms {
66 seen[s.SymID] = true
67 sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: s.Size, Type: s.Type.Name, Code: '?'}
68 switch s.Kind {
69 case objabi.STEXT:
70 sym.Code = 'T'
71 case objabi.SRODATA:
72 sym.Code = 'R'
73 case objabi.SDATA:
74 sym.Code = 'D'
75 case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
76 sym.Code = 'B'
77 }
78 if s.Version != 0 {
79 sym.Code += 'a' - 'A'
80 }
81 for i, r := range s.Reloc {
82 sym.Relocs = append(sym.Relocs, Reloc{Addr: uint64(s.Data.Offset) + uint64(r.Offset), Size: uint64(r.Size), Stringer: &s.Reloc[i]})
83 }
84 syms = append(syms, sym)
85 }
86
87 for _, s := range f.goobj.Syms {
88 for _, r := range s.Reloc {
89 if !seen[r.Sym] {
90 seen[r.Sym] = true
91 sym := Sym{Name: goobjName(r.Sym), Code: 'U'}
92 if s.Version != 0 {
93
94 sym.Code = 'u'
95 }
96 syms = append(syms, sym)
97 }
98 }
99 }
100
101 return syms, nil
102 }
103
104 func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
105
106
107 return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
108 }
109
110
111
112
113 func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
114
115 var arch *sys.Arch
116 for _, a := range sys.Archs {
117 if a.Name == f.goobj.Arch {
118 arch = a
119 break
120 }
121 }
122 if arch == nil {
123 return "", 0, nil
124 }
125 for _, s := range f.goobj.Syms {
126 if pc < uint64(s.Data.Offset) || pc >= uint64(s.Data.Offset+s.Data.Size) {
127 continue
128 }
129 if s.Func == nil {
130 return "", 0, nil
131 }
132 pcfile := make([]byte, s.Func.PCFile.Size)
133 _, err := f.f.ReadAt(pcfile, s.Func.PCFile.Offset)
134 if err != nil {
135 return "", 0, nil
136 }
137 fileID := int(pcValue(pcfile, pc-uint64(s.Data.Offset), arch))
138 fileName := s.Func.File[fileID]
139 pcline := make([]byte, s.Func.PCLine.Size)
140 _, err = f.f.ReadAt(pcline, s.Func.PCLine.Offset)
141 if err != nil {
142 return "", 0, nil
143 }
144 line := int(pcValue(pcline, pc-uint64(s.Data.Offset), arch))
145
146
147 return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: s.Name}}
148 }
149 return "", 0, nil
150 }
151
152
153
154 func pcValue(tab []byte, target uint64, arch *sys.Arch) int32 {
155 val := int32(-1)
156 var pc uint64
157 for step(&tab, &pc, &val, pc == 0, arch) {
158 if target < pc {
159 return val
160 }
161 }
162 return -1
163 }
164
165
166 func step(p *[]byte, pc *uint64, val *int32, first bool, arch *sys.Arch) bool {
167 uvdelta := readvarint(p)
168 if uvdelta == 0 && !first {
169 return false
170 }
171 if uvdelta&1 != 0 {
172 uvdelta = ^(uvdelta >> 1)
173 } else {
174 uvdelta >>= 1
175 }
176 vdelta := int32(uvdelta)
177 pcdelta := readvarint(p) * uint32(arch.MinLC)
178 *pc += uint64(pcdelta)
179 *val += vdelta
180 return true
181 }
182
183
184 func readvarint(p *[]byte) uint32 {
185 var v, shift uint32
186 s := *p
187 for shift = 0; ; shift += 7 {
188 b := s[0]
189 s = s[1:]
190 v |= (uint32(b) & 0x7F) << shift
191 if b&0x80 == 0 {
192 break
193 }
194 }
195 *p = s
196 return v
197 }
198
199
200 func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
201 var info os.FileInfo
202 info, err = f.f.Stat()
203 if err != nil {
204 return
205 }
206 text = make([]byte, info.Size())
207 _, err = f.f.ReadAt(text, 0)
208 return
209 }
210
211 func (f *goobjFile) goarch() string {
212 return f.goobj.Arch
213 }
214
215 func (f *goobjFile) loadAddress() (uint64, error) {
216 return 0, fmt.Errorf("unknown load address")
217 }
218
219 func (f *goobjFile) dwarf() (*dwarf.Data, error) {
220 return nil, errors.New("no DWARF data in go object file")
221 }
222
View as plain text