Source file src/cmd/internal/obj/pcln.go
1
2
3
4
5 package obj
6
7 import (
8 "cmd/internal/src"
9 "encoding/binary"
10 "log"
11 )
12
13 const (
14 PrologueEnd = 2 + iota
15 EpilogueBegin
16 )
17
18
19
20
21
22
23
24
25
26
27
28 func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
29 dbg := desc == ctxt.Debugpcln
30
31 dst.P = dst.P[:0]
32
33 if dbg {
34 ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
35 }
36
37 val := int32(-1)
38 oldval := val
39 if func_.Func.Text == nil {
40 return
41 }
42
43 pc := func_.Func.Text.Pc
44
45 if dbg {
46 ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
47 }
48
49 buf := make([]byte, binary.MaxVarintLen32)
50 started := false
51 for p := func_.Func.Text; p != nil; p = p.Link {
52
53 val = valfunc(ctxt, func_, val, p, 0, arg)
54
55 if val == oldval && started {
56 val = valfunc(ctxt, func_, val, p, 1, arg)
57 if dbg {
58 ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
59 }
60 continue
61 }
62
63
64
65
66
67 if p.Link != nil && p.Link.Pc == p.Pc {
68 val = valfunc(ctxt, func_, val, p, 1, arg)
69 if dbg {
70 ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
71 }
72 continue
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 if dbg {
90 ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
91 }
92
93 if started {
94 pcdelta := (p.Pc - pc) / int64(ctxt.Arch.MinLC)
95 n := binary.PutUvarint(buf, uint64(pcdelta))
96 dst.P = append(dst.P, buf[:n]...)
97 pc = p.Pc
98 }
99
100 delta := val - oldval
101 n := binary.PutVarint(buf, int64(delta))
102 dst.P = append(dst.P, buf[:n]...)
103 oldval = val
104 started = true
105 val = valfunc(ctxt, func_, val, p, 1, arg)
106 }
107
108 if started {
109 if dbg {
110 ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
111 }
112 v := (func_.Size - pc) / int64(ctxt.Arch.MinLC)
113 if v < 0 {
114 ctxt.Diag("negative pc offset: %v", v)
115 }
116 n := binary.PutUvarint(buf, uint64(v))
117 dst.P = append(dst.P, buf[:n]...)
118
119 dst.P = append(dst.P, 0)
120 }
121
122 if dbg {
123 ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
124 for _, p := range dst.P {
125 ctxt.Logf(" %02x", p)
126 }
127 ctxt.Logf("\n")
128 }
129 }
130
131
132
133
134
135 func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
136 if p.As == ATEXT || p.As == ANOP || p.Pos.Line() == 0 || phase == 1 {
137 return oldval
138 }
139 f, l := linkgetlineFromPos(ctxt, p.Pos)
140 if arg == nil {
141 return l
142 }
143 pcln := arg.(*Pcln)
144
145 if f == pcln.Lastfile {
146 return int32(pcln.Lastindex)
147 }
148
149 for i, file := range pcln.File {
150 if file == f {
151 pcln.Lastfile = f
152 pcln.Lastindex = i
153 return int32(i)
154 }
155 }
156 i := len(pcln.File)
157 pcln.File = append(pcln.File, f)
158 pcln.Lastfile = f
159 pcln.Lastindex = i
160 return int32(i)
161 }
162
163
164
165 type pcinlineState struct {
166 globalToLocal map[int]int
167 localTree InlTree
168 }
169
170
171
172 func (s *pcinlineState) addBranch(ctxt *Link, globalIndex int) int {
173 if globalIndex < 0 {
174 return -1
175 }
176
177 localIndex, ok := s.globalToLocal[globalIndex]
178 if ok {
179 return localIndex
180 }
181
182
183
184
185
186 call := ctxt.InlTree.nodes[globalIndex]
187 call.Parent = s.addBranch(ctxt, call.Parent)
188 localIndex = len(s.localTree.nodes)
189 s.localTree.nodes = append(s.localTree.nodes, call)
190 s.globalToLocal[globalIndex] = localIndex
191 return localIndex
192 }
193
194 func (s *pcinlineState) setParentPC(ctxt *Link, globalIndex int, pc int32) {
195 localIndex, ok := s.globalToLocal[globalIndex]
196 if !ok {
197
198
199
200
201
202 return
203 }
204 s.localTree.setParentPC(localIndex, pc)
205 }
206
207
208
209
210 func (s *pcinlineState) pctoinline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
211 if phase == 1 {
212 return oldval
213 }
214
215 posBase := ctxt.PosTable.Pos(p.Pos).Base()
216 if posBase == nil {
217 return -1
218 }
219
220 globalIndex := posBase.InliningIndex()
221 if globalIndex < 0 {
222 return -1
223 }
224
225 if s.globalToLocal == nil {
226 s.globalToLocal = make(map[int]int)
227 }
228
229 return int32(s.addBranch(ctxt, globalIndex))
230 }
231
232
233
234
235
236 func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
237 if oldval == -1 {
238 oldval = 0
239 }
240 if phase == 0 {
241 return oldval
242 }
243 if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
244 ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
245 ctxt.DiagFlush()
246 log.Fatalf("bad code")
247 }
248
249 return oldval + p.Spadj
250 }
251
252
253
254
255
256
257 func pctostmt(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
258 if phase == 1 {
259 return 0
260 }
261 s := p.Pos.IsStmt()
262 l := p.Pos.Xlogue()
263
264 var is_stmt int32
265
266
267 switch l {
268 case src.PosPrologueEnd:
269 is_stmt = PrologueEnd
270 case src.PosEpilogueBegin:
271 is_stmt = EpilogueBegin
272 }
273
274 if s != src.PosNotStmt {
275 is_stmt |= 1
276 }
277 return is_stmt
278 }
279
280
281
282
283
284
285 func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
286 if phase == 0 || p.As != APCDATA || p.From.Offset != int64(arg.(uint32)) {
287 return oldval
288 }
289 if int64(int32(p.To.Offset)) != p.To.Offset {
290 ctxt.Diag("overflow in PCDATA instruction: %v", p)
291 ctxt.DiagFlush()
292 log.Fatalf("bad code")
293 }
294
295 return int32(p.To.Offset)
296 }
297
298
299 func stmtData(ctxt *Link, cursym *LSym) {
300 var pctostmtData Pcdata
301 funcpctab(ctxt, &pctostmtData, cursym, "pctostmt", pctostmt, nil)
302 cursym.Func.dwarfIsStmtSym.P = pctostmtData.P
303 }
304
305 func linkpcln(ctxt *Link, cursym *LSym) {
306 pcln := &cursym.Func.Pcln
307
308 npcdata := 0
309 nfuncdata := 0
310 for p := cursym.Func.Text; p != nil; p = p.Link {
311
312
313
314
315 if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 {
316 npcdata = int(p.From.Offset + 1)
317 }
318
319
320 if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
321 nfuncdata = int(p.From.Offset + 1)
322 }
323 }
324
325 pcln.Pcdata = make([]Pcdata, npcdata)
326 pcln.Pcdata = pcln.Pcdata[:npcdata]
327 pcln.Funcdata = make([]*LSym, nfuncdata)
328 pcln.Funcdataoff = make([]int64, nfuncdata)
329 pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
330
331 funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
332 funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
333 funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
334
335 pcinlineState := new(pcinlineState)
336 funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
337 for _, inlMark := range cursym.Func.InlMarks {
338 pcinlineState.setParentPC(ctxt, int(inlMark.id), int32(inlMark.p.Pc))
339 }
340 pcln.InlTree = pcinlineState.localTree
341 if ctxt.Debugpcln == "pctoinline" && len(pcln.InlTree.nodes) > 0 {
342 ctxt.Logf("-- inlining tree for %s:\n", cursym)
343 dumpInlTree(ctxt, pcln.InlTree)
344 ctxt.Logf("--\n")
345 }
346
347
348 havepc := make([]uint32, (npcdata+31)/32)
349 havefunc := make([]uint32, (nfuncdata+31)/32)
350 for p := cursym.Func.Text; p != nil; p = p.Link {
351 if p.As == AFUNCDATA {
352 if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
353 ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
354 }
355 havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
356 }
357
358 if p.As == APCDATA && p.To.Offset != -1 {
359 havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
360 }
361 }
362
363
364 for i := 0; i < npcdata; i++ {
365 if (havepc[i/32]>>uint(i%32))&1 == 0 {
366 continue
367 }
368 funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
369 }
370
371
372 if nfuncdata > 0 {
373 for p := cursym.Func.Text; p != nil; p = p.Link {
374 if p.As != AFUNCDATA {
375 continue
376 }
377 i := int(p.From.Offset)
378 pcln.Funcdataoff[i] = p.To.Offset
379 if p.To.Type != TYPE_CONST {
380
381
382 pcln.Funcdata[i] = p.To.Sym
383 }
384 }
385 }
386 }
387
View as plain text