github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/ssa/debug.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 package ssa 5 6 import ( 7 "cmd/internal/dwarf" 8 "cmd/internal/obj" 9 "encoding/hex" 10 "fmt" 11 "sort" 12 "strings" 13 ) 14 15 type SlotID int32 16 type VarID int32 17 18 // A FuncDebug contains all the debug information for the variables in a 19 // function. Variables are identified by their LocalSlot, which may be the 20 // result of decomposing a larger variable. 21 type FuncDebug struct { 22 // Slots is all the slots used in the debug info, indexed by their SlotID. 23 Slots []LocalSlot 24 // The user variables, indexed by VarID. 25 Vars []GCNode 26 // The slots that make up each variable, indexed by VarID. 27 VarSlots [][]SlotID 28 // The location list data, indexed by VarID. Must be processed by PutLocationList. 29 LocationLists [][]byte 30 31 // Filled in by the user. Translates Block and Value ID to PC. 32 GetPC func(ID, ID) int64 33 } 34 35 type BlockDebug struct { 36 // Whether the block had any changes to user variables at all. 37 relevant bool 38 // State at the end of the block if it's fully processed. Immutable once initialized. 39 endState []liveSlot 40 } 41 42 // A liveSlot is a slot that's live in loc at entry/exit of a block. 43 type liveSlot struct { 44 // An inlined VarLoc, so it packs into 16 bytes instead of 20. 45 Registers RegisterSet 46 StackOffset 47 48 slot SlotID 49 } 50 51 func (loc liveSlot) absent() bool { 52 return loc.Registers == 0 && !loc.onStack() 53 } 54 55 // StackOffset encodes whether a value is on the stack and if so, where. It is 56 // a 31-bit integer followed by a presence flag at the low-order bit. 57 type StackOffset int32 58 59 func (s StackOffset) onStack() bool { 60 return s != 0 61 } 62 63 func (s StackOffset) stackOffsetValue() int32 { 64 return int32(s) >> 1 65 } 66 67 // stateAtPC is the current state of all variables at some point. 68 type stateAtPC struct { 69 // The location of each known slot, indexed by SlotID. 70 slots []VarLoc 71 // The slots present in each register, indexed by register number. 72 registers [][]SlotID 73 } 74 75 // reset fills state with the live variables from live. 76 func (state *stateAtPC) reset(live []liveSlot) { 77 slots, registers := state.slots, state.registers 78 for i := range slots { 79 slots[i] = VarLoc{} 80 } 81 for i := range registers { 82 registers[i] = registers[i][:0] 83 } 84 for _, live := range live { 85 slots[live.slot] = VarLoc{live.Registers, live.StackOffset} 86 if live.Registers == 0 { 87 continue 88 } 89 90 mask := uint64(live.Registers) 91 for { 92 if mask == 0 { 93 break 94 } 95 reg := uint8(TrailingZeros64(mask)) 96 mask &^= 1 << reg 97 98 registers[reg] = append(registers[reg], SlotID(live.slot)) 99 } 100 } 101 state.slots, state.registers = slots, registers 102 } 103 104 func (s *debugState) LocString(loc VarLoc) string { 105 if loc.absent() { 106 return "<nil>" 107 } 108 109 var storage []string 110 if loc.onStack() { 111 storage = append(storage, "stack") 112 } 113 114 mask := uint64(loc.Registers) 115 for { 116 if mask == 0 { 117 break 118 } 119 reg := uint8(TrailingZeros64(mask)) 120 mask &^= 1 << reg 121 122 storage = append(storage, s.registers[reg].String()) 123 } 124 return strings.Join(storage, ",") 125 } 126 127 // A VarLoc describes the storage for part of a user variable. 128 type VarLoc struct { 129 // The registers this variable is available in. There can be more than 130 // one in various situations, e.g. it's being moved between registers. 131 Registers RegisterSet 132 133 StackOffset 134 } 135 136 func (loc VarLoc) absent() bool { 137 return loc.Registers == 0 && !loc.onStack() 138 } 139 140 var BlockStart = &Value{ 141 ID: -10000, 142 Op: OpInvalid, 143 Aux: "BlockStart", 144 } 145 146 var BlockEnd = &Value{ 147 ID: -20000, 148 Op: OpInvalid, 149 Aux: "BlockEnd", 150 } 151 152 // RegisterSet is a bitmap of registers, indexed by Register.num. 153 type RegisterSet uint64 154 155 // unexpected is used to indicate an inconsistency or bug in the debug info 156 // generation process. These are not fixable by users. At time of writing, 157 // changing this to a Fprintf(os.Stderr) and running make.bash generates 158 // thousands of warnings. 159 func (s *debugState) unexpected(v *Value, msg string, args ...interface{}) { 160 s.f.Logf("unexpected at "+fmt.Sprint(v.ID)+":"+msg, args...) 161 } 162 163 func (s *debugState) logf(msg string, args ...interface{}) { 164 s.f.Logf(msg, args...) 165 } 166 167 type debugState struct { 168 // See FuncDebug. 169 slots []LocalSlot 170 vars []GCNode 171 varSlots [][]SlotID 172 lists [][]byte 173 174 // The user variable that each slot rolls up to, indexed by SlotID. 175 slotVars []VarID 176 177 f *Func 178 loggingEnabled bool 179 registers []Register 180 stackOffset func(LocalSlot) int32 181 ctxt *obj.Link 182 183 // The names (slots) associated with each value, indexed by Value ID. 184 valueNames [][]SlotID 185 186 // The current state of whatever analysis is running. 187 currentState stateAtPC 188 liveCount []int 189 changedVars *sparseSet 190 191 // The pending location list entry for each user variable, indexed by VarID. 192 pendingEntries []pendingEntry 193 194 varParts map[GCNode][]SlotID 195 blockDebug []BlockDebug 196 pendingSlotLocs []VarLoc 197 liveSlots []liveSlot 198 liveSlotSliceBegin int 199 partsByVarOffset sort.Interface 200 } 201 202 func (state *debugState) initializeCache(f *Func, numVars, numSlots int) { 203 // One blockDebug per block. Initialized in allocBlock. 204 if cap(state.blockDebug) < f.NumBlocks() { 205 state.blockDebug = make([]BlockDebug, f.NumBlocks()) 206 } else { 207 // This local variable, and the ones like it below, enable compiler 208 // optimizations. Don't inline them. 209 b := state.blockDebug[:f.NumBlocks()] 210 for i := range b { 211 b[i] = BlockDebug{} 212 } 213 } 214 215 // A list of slots per Value. Reuse the previous child slices. 216 if cap(state.valueNames) < f.NumValues() { 217 old := state.valueNames 218 state.valueNames = make([][]SlotID, f.NumValues()) 219 copy(state.valueNames, old) 220 } 221 vn := state.valueNames[:f.NumValues()] 222 for i := range vn { 223 vn[i] = vn[i][:0] 224 } 225 226 // Slot and register contents for currentState. Cleared by reset(). 227 if cap(state.currentState.slots) < numSlots { 228 state.currentState.slots = make([]VarLoc, numSlots) 229 } else { 230 state.currentState.slots = state.currentState.slots[:numSlots] 231 } 232 if cap(state.currentState.registers) < len(state.registers) { 233 state.currentState.registers = make([][]SlotID, len(state.registers)) 234 } else { 235 state.currentState.registers = state.currentState.registers[:len(state.registers)] 236 } 237 238 // Used many times by mergePredecessors. 239 if cap(state.liveCount) < numSlots { 240 state.liveCount = make([]int, numSlots) 241 } else { 242 state.liveCount = state.liveCount[:numSlots] 243 } 244 245 // A relatively small slice, but used many times as the return from processValue. 246 state.changedVars = newSparseSet(numVars) 247 248 // A pending entry per user variable, with space to track each of its pieces. 249 numPieces := 0 250 for i := range state.varSlots { 251 numPieces += len(state.varSlots[i]) 252 } 253 if cap(state.pendingSlotLocs) < numPieces { 254 state.pendingSlotLocs = make([]VarLoc, numPieces) 255 } else { 256 psl := state.pendingSlotLocs[:numPieces] 257 for i := range psl { 258 psl[i] = VarLoc{} 259 } 260 } 261 if cap(state.pendingEntries) < numVars { 262 state.pendingEntries = make([]pendingEntry, numVars) 263 } 264 pe := state.pendingEntries[:numVars] 265 freePieceIdx := 0 266 for varID, slots := range state.varSlots { 267 pe[varID] = pendingEntry{ 268 pieces: state.pendingSlotLocs[freePieceIdx : freePieceIdx+len(slots)], 269 } 270 freePieceIdx += len(slots) 271 } 272 state.pendingEntries = pe 273 274 if cap(state.lists) < numVars { 275 state.lists = make([][]byte, numVars) 276 } else { 277 state.lists = state.lists[:numVars] 278 for i := range state.lists { 279 state.lists[i] = nil 280 } 281 } 282 283 state.liveSlots = state.liveSlots[:0] 284 state.liveSlotSliceBegin = 0 285 } 286 287 func (state *debugState) allocBlock(b *Block) *BlockDebug { 288 return &state.blockDebug[b.ID] 289 } 290 291 func (state *debugState) appendLiveSlot(ls liveSlot) { 292 state.liveSlots = append(state.liveSlots, ls) 293 } 294 295 func (state *debugState) getLiveSlotSlice() []liveSlot { 296 s := state.liveSlots[state.liveSlotSliceBegin:] 297 state.liveSlotSliceBegin = len(state.liveSlots) 298 return s 299 } 300 301 func (s *debugState) blockEndStateString(b *BlockDebug) string { 302 endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))} 303 endState.reset(b.endState) 304 return s.stateString(endState) 305 } 306 307 func (s *debugState) stateString(state stateAtPC) string { 308 var strs []string 309 for slotID, loc := range state.slots { 310 if !loc.absent() { 311 strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc))) 312 } 313 } 314 315 strs = append(strs, "\n") 316 for reg, slots := range state.registers { 317 if len(slots) != 0 { 318 var slotStrs []string 319 for _, slot := range slots { 320 slotStrs = append(slotStrs, s.slots[slot].String()) 321 } 322 strs = append(strs, fmt.Sprintf("\t%v = %v\n", &s.registers[reg], slotStrs)) 323 } 324 } 325 326 if len(strs) == 1 { 327 return "(no vars)\n" 328 } 329 return strings.Join(strs, "") 330 } 331 332 // BuildFuncDebug returns debug information for f. 333 // f must be fully processed, so that each Value is where it will be when 334 // machine code is emitted. 335 func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32) *FuncDebug { 336 if f.RegAlloc == nil { 337 f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f) 338 } 339 state := &f.Cache.debugState 340 state.loggingEnabled = loggingEnabled 341 state.f = f 342 state.registers = f.Config.registers 343 state.stackOffset = stackOffset 344 state.ctxt = ctxt 345 346 if state.varParts == nil { 347 state.varParts = make(map[GCNode][]SlotID) 348 } else { 349 for n := range state.varParts { 350 delete(state.varParts, n) 351 } 352 } 353 354 // Recompose any decomposed variables, and establish the canonical 355 // IDs for each var and slot by filling out state.vars and state.slots. 356 357 state.slots = state.slots[:0] 358 state.vars = state.vars[:0] 359 for i, slot := range f.Names { 360 state.slots = append(state.slots, slot) 361 if slot.N.IsSynthetic() { 362 continue 363 } 364 365 topSlot := &slot 366 for topSlot.SplitOf != nil { 367 topSlot = topSlot.SplitOf 368 } 369 if _, ok := state.varParts[topSlot.N]; !ok { 370 state.vars = append(state.vars, topSlot.N) 371 } 372 state.varParts[topSlot.N] = append(state.varParts[topSlot.N], SlotID(i)) 373 } 374 375 // Fill in the var<->slot mappings. 376 if cap(state.varSlots) < len(state.vars) { 377 state.varSlots = make([][]SlotID, len(state.vars)) 378 } else { 379 state.varSlots = state.varSlots[:len(state.vars)] 380 for i := range state.varSlots { 381 state.varSlots[i] = state.varSlots[i][:0] 382 } 383 } 384 if cap(state.slotVars) < len(state.slots) { 385 state.slotVars = make([]VarID, len(state.slots)) 386 } else { 387 state.slotVars = state.slotVars[:len(state.slots)] 388 } 389 390 if state.partsByVarOffset == nil { 391 state.partsByVarOffset = &partsByVarOffset{} 392 } 393 for varID, n := range state.vars { 394 parts := state.varParts[n] 395 state.varSlots[varID] = parts 396 for _, slotID := range parts { 397 state.slotVars[slotID] = VarID(varID) 398 } 399 *state.partsByVarOffset.(*partsByVarOffset) = partsByVarOffset{parts, state.slots} 400 sort.Sort(state.partsByVarOffset) 401 } 402 403 state.initializeCache(f, len(state.varParts), len(state.slots)) 404 405 for i, slot := range f.Names { 406 if slot.N.IsSynthetic() { 407 continue 408 } 409 for _, value := range f.NamedValues[slot] { 410 state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i)) 411 } 412 } 413 414 blockLocs := state.liveness() 415 state.buildLocationLists(blockLocs) 416 417 return &FuncDebug{ 418 Slots: state.slots, 419 VarSlots: state.varSlots, 420 Vars: state.vars, 421 LocationLists: state.lists, 422 } 423 } 424 425 // liveness walks the function in control flow order, calculating the start 426 // and end state of each block. 427 func (state *debugState) liveness() []*BlockDebug { 428 blockLocs := make([]*BlockDebug, state.f.NumBlocks()) 429 430 // Reverse postorder: visit a block after as many as possible of its 431 // predecessors have been visited. 432 po := state.f.Postorder() 433 for i := len(po) - 1; i >= 0; i-- { 434 b := po[i] 435 436 // Build the starting state for the block from the final 437 // state of its predecessors. 438 startState, startValid := state.mergePredecessors(b, blockLocs) 439 changed := false 440 if state.loggingEnabled { 441 state.logf("Processing %v, initial state:\n%v", b, state.stateString(state.currentState)) 442 } 443 444 // Update locs/registers with the effects of each Value. 445 for _, v := range b.Values { 446 slots := state.valueNames[v.ID] 447 448 // Loads and stores inherit the names of their sources. 449 var source *Value 450 switch v.Op { 451 case OpStoreReg: 452 source = v.Args[0] 453 case OpLoadReg: 454 switch a := v.Args[0]; a.Op { 455 case OpArg: 456 source = a 457 case OpStoreReg: 458 source = a.Args[0] 459 default: 460 state.unexpected(v, "load with unexpected source op %v", a) 461 } 462 } 463 // Update valueNames with the source so that later steps 464 // don't need special handling. 465 if source != nil { 466 slots = append(slots, state.valueNames[source.ID]...) 467 state.valueNames[v.ID] = slots 468 } 469 470 reg, _ := state.f.getHome(v.ID).(*Register) 471 c := state.processValue(v, slots, reg) 472 changed = changed || c 473 } 474 475 if state.loggingEnabled { 476 state.f.Logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState)) 477 } 478 479 locs := state.allocBlock(b) 480 locs.relevant = changed 481 if !changed && startValid { 482 locs.endState = startState 483 } else { 484 for slotID, slotLoc := range state.currentState.slots { 485 if slotLoc.absent() { 486 continue 487 } 488 state.appendLiveSlot(liveSlot{slot: SlotID(slotID), Registers: slotLoc.Registers, StackOffset: slotLoc.StackOffset}) 489 } 490 locs.endState = state.getLiveSlotSlice() 491 } 492 blockLocs[b.ID] = locs 493 } 494 return blockLocs 495 } 496 497 // mergePredecessors takes the end state of each of b's predecessors and 498 // intersects them to form the starting state for b. It returns that state in 499 // the BlockDebug, and fills state.currentState with it. 500 func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([]liveSlot, bool) { 501 // Filter out back branches. 502 var predsBuf [10]*Block 503 preds := predsBuf[:0] 504 for _, pred := range b.Preds { 505 if blockLocs[pred.b.ID] != nil { 506 preds = append(preds, pred.b) 507 } 508 } 509 510 if state.loggingEnabled { 511 // The logf below would cause preds to be heap-allocated if 512 // it were passed directly. 513 preds2 := make([]*Block, len(preds)) 514 copy(preds2, preds) 515 state.logf("Merging %v into %v\n", preds2, b) 516 } 517 518 if len(preds) == 0 { 519 if state.loggingEnabled { 520 } 521 state.currentState.reset(nil) 522 return nil, true 523 } 524 525 p0 := blockLocs[preds[0].ID].endState 526 if len(preds) == 1 { 527 state.currentState.reset(p0) 528 return p0, true 529 } 530 531 if state.loggingEnabled { 532 state.logf("Starting %v with state from %v:\n%v", b, preds[0], state.blockEndStateString(blockLocs[preds[0].ID])) 533 } 534 535 slotLocs := state.currentState.slots 536 for _, predSlot := range p0 { 537 slotLocs[predSlot.slot] = VarLoc{predSlot.Registers, predSlot.StackOffset} 538 state.liveCount[predSlot.slot] = 1 539 } 540 for i := 1; i < len(preds); i++ { 541 if state.loggingEnabled { 542 state.logf("Merging in state from %v:\n%v", preds[i], state.blockEndStateString(blockLocs[preds[i].ID])) 543 } 544 for _, predSlot := range blockLocs[preds[i].ID].endState { 545 state.liveCount[predSlot.slot]++ 546 liveLoc := slotLocs[predSlot.slot] 547 if !liveLoc.onStack() || !predSlot.onStack() || liveLoc.StackOffset != predSlot.StackOffset { 548 liveLoc.StackOffset = 0 549 } 550 liveLoc.Registers &= predSlot.Registers 551 slotLocs[predSlot.slot] = liveLoc 552 } 553 } 554 555 // Check if the final state is the same as the first predecessor's 556 // final state, and reuse it if so. In principle it could match any, 557 // but it's probably not worth checking more than the first. 558 unchanged := true 559 for _, predSlot := range p0 { 560 if state.liveCount[predSlot.slot] != len(preds) || 561 slotLocs[predSlot.slot].Registers != predSlot.Registers || 562 slotLocs[predSlot.slot].StackOffset != predSlot.StackOffset { 563 unchanged = false 564 break 565 } 566 } 567 if unchanged { 568 if state.loggingEnabled { 569 state.logf("After merge, %v matches %v exactly.\n", b, preds[0]) 570 } 571 state.currentState.reset(p0) 572 return p0, true 573 } 574 575 for reg := range state.currentState.registers { 576 state.currentState.registers[reg] = state.currentState.registers[reg][:0] 577 } 578 579 // A slot is live if it was seen in all predecessors, and they all had 580 // some storage in common. 581 for slotID := range p0 { 582 slotLoc := slotLocs[slotID] 583 584 if state.liveCount[slotID] != len(preds) { 585 // Seen in only some predecessors. Clear it out. 586 slotLocs[slotID] = VarLoc{} 587 continue 588 } 589 590 // Present in all predecessors. 591 mask := uint64(slotLoc.Registers) 592 for { 593 if mask == 0 { 594 break 595 } 596 reg := uint8(TrailingZeros64(mask)) 597 mask &^= 1 << reg 598 599 state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID)) 600 } 601 } 602 return nil, false 603 } 604 605 // processValue updates locs and state.registerContents to reflect v, a value with 606 // the names in vSlots and homed in vReg. "v" becomes visible after execution of 607 // the instructions evaluating it. It returns which VarIDs were modified by the 608 // Value's execution. 609 func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) bool { 610 locs := state.currentState 611 changed := false 612 setSlot := func(slot SlotID, loc VarLoc) { 613 changed = true 614 state.changedVars.add(ID(state.slotVars[slot])) 615 state.currentState.slots[slot] = loc 616 } 617 618 // Handle any register clobbering. Call operations, for example, 619 // clobber all registers even though they don't explicitly write to 620 // them. 621 clobbers := uint64(opcodeTable[v.Op].reg.clobbers) 622 for { 623 if clobbers == 0 { 624 break 625 } 626 reg := uint8(TrailingZeros64(clobbers)) 627 clobbers &^= 1 << reg 628 629 for _, slot := range locs.registers[reg] { 630 if state.loggingEnabled { 631 state.logf("at %v: %v clobbered out of %v\n", v.ID, state.slots[slot], &state.registers[reg]) 632 } 633 634 last := locs.slots[slot] 635 if last.absent() { 636 state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg]) 637 continue 638 } 639 regs := last.Registers &^ (1 << uint8(reg)) 640 setSlot(slot, VarLoc{regs, last.StackOffset}) 641 } 642 643 locs.registers[reg] = locs.registers[reg][:0] 644 } 645 646 switch { 647 case v.Op == OpArg: 648 home := state.f.getHome(v.ID).(LocalSlot) 649 stackOffset := state.stackOffset(home)<<1 | 1 650 for _, slot := range vSlots { 651 if state.loggingEnabled { 652 state.logf("at %v: arg %v now on stack in location %v\n", v.ID, state.slots[slot], home) 653 if last := locs.slots[slot]; !last.absent() { 654 state.unexpected(v, "Arg op on already-live slot %v", state.slots[slot]) 655 } 656 } 657 658 setSlot(slot, VarLoc{0, StackOffset(stackOffset)}) 659 } 660 661 case v.Op == OpStoreReg: 662 home := state.f.getHome(v.ID).(LocalSlot) 663 stackOffset := state.stackOffset(home)<<1 | 1 664 for _, slot := range vSlots { 665 last := locs.slots[slot] 666 if last.absent() { 667 state.unexpected(v, "spill of unnamed register %s\n", vReg) 668 break 669 } 670 671 setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)}) 672 if state.loggingEnabled { 673 state.logf("at %v: %v spilled to stack location %v\n", v.ID, state.slots[slot], home) 674 } 675 } 676 677 case vReg != nil: 678 if state.loggingEnabled { 679 newSlots := make([]bool, len(state.slots)) 680 for _, slot := range vSlots { 681 newSlots[slot] = true 682 } 683 684 for _, slot := range locs.registers[vReg.num] { 685 if !newSlots[slot] { 686 state.logf("at %v: overwrote %v in register %v\n", v, state.slots[slot], vReg) 687 } 688 } 689 } 690 691 for _, slot := range locs.registers[vReg.num] { 692 last := locs.slots[slot] 693 setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset}) 694 } 695 locs.registers[vReg.num] = locs.registers[vReg.num][:0] 696 locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...) 697 for _, slot := range vSlots { 698 if state.loggingEnabled { 699 state.logf("at %v: %v now in %s\n", v.ID, state.slots[slot], vReg) 700 } 701 702 last := locs.slots[slot] 703 setSlot(slot, VarLoc{1<<uint8(vReg.num) | last.Registers, last.StackOffset}) 704 } 705 } 706 return changed 707 } 708 709 // varOffset returns the offset of slot within the user variable it was 710 // decomposed from. This has nothing to do with its stack offset. 711 func varOffset(slot LocalSlot) int64 { 712 offset := slot.Off 713 s := &slot 714 for ; s.SplitOf != nil; s = s.SplitOf { 715 offset += s.SplitOffset 716 } 717 return offset 718 } 719 720 type partsByVarOffset struct { 721 slotIDs []SlotID 722 slots []LocalSlot 723 } 724 725 func (a partsByVarOffset) Len() int { return len(a.slotIDs) } 726 func (a partsByVarOffset) Less(i, j int) bool { 727 return varOffset(a.slots[a.slotIDs[i]]) < varOffset(a.slots[a.slotIDs[i]]) 728 } 729 func (a partsByVarOffset) Swap(i, j int) { a.slotIDs[i], a.slotIDs[j] = a.slotIDs[j], a.slotIDs[i] } 730 731 // A pendingEntry represents the beginning of a location list entry, missing 732 // only its end coordinate. 733 type pendingEntry struct { 734 present bool 735 startBlock, startValue ID 736 // The location of each piece of the variable, in the same order as the 737 // SlotIDs in varParts. 738 pieces []VarLoc 739 } 740 741 func (e *pendingEntry) clear() { 742 e.present = false 743 e.startBlock = 0 744 e.startValue = 0 745 for i := range e.pieces { 746 e.pieces[i] = VarLoc{} 747 } 748 } 749 750 // canMerge returns true if the location description for new is the same as 751 // pending. 752 func canMerge(pending, new VarLoc) bool { 753 if pending.absent() && new.absent() { 754 return true 755 } 756 if pending.absent() || new.absent() { 757 return false 758 } 759 if pending.onStack() { 760 return pending.StackOffset == new.StackOffset 761 } 762 if pending.Registers != 0 && new.Registers != 0 { 763 return firstReg(pending.Registers) == firstReg(new.Registers) 764 } 765 return false 766 } 767 768 // firstReg returns the first register in set that is present. 769 func firstReg(set RegisterSet) uint8 { 770 if set == 0 { 771 // This is wrong, but there seem to be some situations where we 772 // produce locations with no storage. 773 return 0 774 } 775 return uint8(TrailingZeros64(uint64(set))) 776 } 777 778 // buildLocationLists builds location lists for all the user variables in 779 // state.f, using the information about block state in blockLocs. 780 // The returned location lists are not fully complete. They are in terms of 781 // SSA values rather than PCs, and have no base address/end entries. They will 782 // be finished by PutLocationList. 783 func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { 784 // Run through the function in program text order, building up location 785 // lists as we go. The heavy lifting has mostly already been done. 786 for _, b := range state.f.Blocks { 787 if !blockLocs[b.ID].relevant { 788 continue 789 } 790 791 state.mergePredecessors(b, blockLocs) 792 793 phisPending := false 794 for _, v := range b.Values { 795 slots := state.valueNames[v.ID] 796 reg, _ := state.f.getHome(v.ID).(*Register) 797 changed := state.processValue(v, slots, reg) 798 799 if v.Op == OpPhi { 800 if changed { 801 phisPending = true 802 } 803 continue 804 } 805 806 if !changed && !phisPending { 807 continue 808 } 809 810 phisPending = false 811 for _, varID := range state.changedVars.contents() { 812 state.updateVar(VarID(varID), v, state.currentState.slots) 813 } 814 state.changedVars.clear() 815 } 816 817 } 818 819 if state.loggingEnabled { 820 state.logf("location lists:\n") 821 } 822 823 // Flush any leftover entries live at the end of the last block. 824 for varID := range state.lists { 825 state.writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID) 826 list := state.lists[varID] 827 if len(list) == 0 { 828 continue 829 } 830 831 if state.loggingEnabled { 832 state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID])) 833 } 834 } 835 } 836 837 // updateVar updates the pending location list entry for varID to 838 // reflect the new locations in curLoc, caused by v. 839 func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) { 840 // Assemble the location list entry with whatever's live. 841 empty := true 842 for _, slotID := range state.varSlots[varID] { 843 if !curLoc[slotID].absent() { 844 empty = false 845 break 846 } 847 } 848 pending := &state.pendingEntries[varID] 849 if empty { 850 state.writePendingEntry(varID, v.Block.ID, v.ID) 851 pending.clear() 852 return 853 } 854 855 // Extend the previous entry if possible. 856 if pending.present { 857 merge := true 858 for i, slotID := range state.varSlots[varID] { 859 if !canMerge(pending.pieces[i], curLoc[slotID]) { 860 merge = false 861 break 862 } 863 } 864 if merge { 865 return 866 } 867 } 868 869 state.writePendingEntry(varID, v.Block.ID, v.ID) 870 pending.present = true 871 pending.startBlock = v.Block.ID 872 pending.startValue = v.ID 873 for i, slot := range state.varSlots[varID] { 874 pending.pieces[i] = curLoc[slot] 875 } 876 return 877 878 } 879 880 // writePendingEntry writes out the pending entry for varID, if any, 881 // terminated at endBlock/Value. 882 func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) { 883 pending := state.pendingEntries[varID] 884 if !pending.present { 885 return 886 } 887 888 // Pack the start/end coordinates into the start/end addresses 889 // of the entry, for decoding by PutLocationList. 890 start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue) 891 end, endOK := encodeValue(state.ctxt, endBlock, endValue) 892 if !startOK || !endOK { 893 // If someone writes a function that uses >65K values, 894 // they get incomplete debug info on 32-bit platforms. 895 return 896 } 897 list := state.lists[varID] 898 list = appendPtr(state.ctxt, list, start) 899 list = appendPtr(state.ctxt, list, end) 900 // Where to write the length of the location description once 901 // we know how big it is. 902 sizeIdx := len(list) 903 list = list[:len(list)+2] 904 905 if state.loggingEnabled { 906 var partStrs []string 907 for i, slot := range state.varSlots[varID] { 908 partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i]))) 909 } 910 state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " ")) 911 } 912 913 for i, slotID := range state.varSlots[varID] { 914 loc := pending.pieces[i] 915 slot := state.slots[slotID] 916 917 if !loc.absent() { 918 if loc.onStack() { 919 if loc.stackOffsetValue() == 0 { 920 list = append(list, dwarf.DW_OP_call_frame_cfa) 921 } else { 922 list = append(list, dwarf.DW_OP_fbreg) 923 list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue())) 924 } 925 } else { 926 regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()] 927 if regnum < 32 { 928 list = append(list, dwarf.DW_OP_reg0+byte(regnum)) 929 } else { 930 list = append(list, dwarf.DW_OP_regx) 931 list = dwarf.AppendUleb128(list, uint64(regnum)) 932 } 933 } 934 } 935 936 if len(state.varSlots[varID]) > 1 { 937 list = append(list, dwarf.DW_OP_piece) 938 list = dwarf.AppendUleb128(list, uint64(slot.Type.Size())) 939 } 940 } 941 state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2)) 942 state.lists[varID] = list 943 } 944 945 // PutLocationList adds list (a location list in its intermediate representation) to listSym. 946 func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) { 947 getPC := debugInfo.GetPC 948 // Re-read list, translating its address from block/value ID to PC. 949 for i := 0; i < len(list); { 950 translate := func() { 951 bv := readPtr(ctxt, list[i:]) 952 pc := getPC(decodeValue(ctxt, bv)) 953 writePtr(ctxt, list[i:], uint64(pc)) 954 i += ctxt.Arch.PtrSize 955 } 956 translate() 957 translate() 958 i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:])) 959 } 960 961 // Base address entry. 962 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0) 963 listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0) 964 // Location list contents, now with real PCs. 965 listSym.WriteBytes(ctxt, listSym.Size, list) 966 // End entry. 967 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0) 968 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0) 969 } 970 971 // Pack a value and block ID into an address-sized uint, returning ~0 if they 972 // don't fit. 973 func encodeValue(ctxt *obj.Link, b, v ID) (uint64, bool) { 974 if ctxt.Arch.PtrSize == 8 { 975 result := uint64(b)<<32 | uint64(uint32(v)) 976 //ctxt.Logf("b %#x (%d) v %#x (%d) -> %#x\n", b, b, v, v, result) 977 return result, true 978 } 979 if ctxt.Arch.PtrSize != 4 { 980 panic("unexpected pointer size") 981 } 982 if ID(int16(b)) != b || ID(int16(v)) != v { 983 return 0, false 984 } 985 return uint64(b)<<16 | uint64(uint16(v)), true 986 } 987 988 // Unpack a value and block ID encoded by encodeValue. 989 func decodeValue(ctxt *obj.Link, word uint64) (ID, ID) { 990 if ctxt.Arch.PtrSize == 8 { 991 b, v := ID(word>>32), ID(word) 992 //ctxt.Logf("%#x -> b %#x (%d) v %#x (%d)\n", word, b, b, v, v) 993 return b, v 994 } 995 if ctxt.Arch.PtrSize != 4 { 996 panic("unexpected pointer size") 997 } 998 return ID(word >> 16), ID(word) 999 } 1000 1001 // Append a pointer-sized uint to buf. 1002 func appendPtr(ctxt *obj.Link, buf []byte, word uint64) []byte { 1003 if cap(buf) < len(buf)+20 { 1004 b := make([]byte, len(buf), 20+cap(buf)*2) 1005 copy(b, buf) 1006 buf = b 1007 } 1008 writeAt := len(buf) 1009 buf = buf[0 : len(buf)+ctxt.Arch.PtrSize] 1010 writePtr(ctxt, buf[writeAt:], word) 1011 return buf 1012 } 1013 1014 // Write a pointer-sized uint to the beginning of buf. 1015 func writePtr(ctxt *obj.Link, buf []byte, word uint64) { 1016 switch ctxt.Arch.PtrSize { 1017 case 4: 1018 ctxt.Arch.ByteOrder.PutUint32(buf, uint32(word)) 1019 case 8: 1020 ctxt.Arch.ByteOrder.PutUint64(buf, word) 1021 default: 1022 panic("unexpected pointer size") 1023 } 1024 1025 } 1026 1027 // Read a pointer-sized uint from the beginning of buf. 1028 func readPtr(ctxt *obj.Link, buf []byte) uint64 { 1029 switch ctxt.Arch.PtrSize { 1030 case 4: 1031 return uint64(ctxt.Arch.ByteOrder.Uint32(buf)) 1032 case 8: 1033 return ctxt.Arch.ByteOrder.Uint64(buf) 1034 default: 1035 panic("unexpected pointer size") 1036 } 1037 1038 }