github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/obj/dwarf.go (about) 1 // Copyright 2019 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 5 // Writes dwarf information to object files. 6 7 package obj 8 9 import ( 10 "github.com/gagliardetto/golang-go/cmd/internal/dwarf" 11 "github.com/gagliardetto/golang-go/cmd/internal/src" 12 "fmt" 13 ) 14 15 // Generate a sequence of opcodes that is as short as possible. 16 // See section 6.2.5 17 const ( 18 LINE_BASE = -4 19 LINE_RANGE = 10 20 PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE 21 OPCODE_BASE = 11 22 ) 23 24 // generateDebugLinesSymbol fills the debug lines symbol of a given function. 25 // 26 // It's worth noting that this function doesn't generate the full debug_lines 27 // DWARF section, saving that for the linker. This function just generates the 28 // state machine part of debug_lines. The full table is generated by the 29 // linker. Also, we use the file numbers from the full package (not just the 30 // function in question) when generating the state machine. We do this so we 31 // don't have to do a fixup on the indices when writing the full section. 32 func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) { 33 dctxt := dwCtxt{ctxt} 34 35 // The Pcfile table is used to generate the debug_lines section, and the file 36 // indices for that data could differ from the files we write out for the 37 // debug_lines section. Here we generate a LUT between those two indices. 38 fileNums := make(map[int32]int64) 39 for i, filename := range s.Func.Pcln.File { 40 if symbolIndex := ctxt.PosTable.FileIndex(filename); symbolIndex >= 0 { 41 fileNums[int32(i)] = int64(symbolIndex) + 1 42 } else { 43 panic(fmt.Sprintf("First time we've seen filename: %q", filename)) 44 } 45 } 46 47 // Set up the debug_lines state machine. 48 // NB: This state machine is reset to this state when we've finished 49 // generating the line table. See below. 50 // TODO: Once delve can support multiple DW_LNS_end_statements, we don't have 51 // to do this. 52 stmt := true 53 line := int64(1) 54 pc := s.Func.Text.Pc 55 name := "" 56 prologue, wrotePrologue := false, false 57 // Walk the progs, generating the DWARF table. 58 for p := s.Func.Text; p != nil; p = p.Link { 59 prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd) 60 // If we're not at a real instruction, keep looping! 61 if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) { 62 continue 63 } 64 newStmt := p.Pos.IsStmt() != src.PosNotStmt 65 newName, newLine := linkgetlineFromPos(ctxt, p.Pos) 66 67 // Output debug info. 68 wrote := false 69 if name != newName { 70 newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table. 71 dctxt.AddUint8(lines, dwarf.DW_LNS_set_file) 72 dwarf.Uleb128put(dctxt, lines, int64(newFile)) 73 name = newName 74 wrote = true 75 } 76 if prologue && !wrotePrologue { 77 dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end)) 78 wrotePrologue = true 79 wrote = true 80 } 81 if stmt != newStmt { 82 dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt)) 83 stmt = newStmt 84 wrote = true 85 } 86 87 if line != int64(newLine) || wrote { 88 pcdelta := p.Pc - pc 89 putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line) 90 line, pc = int64(newLine), p.Pc 91 } 92 } 93 94 // Because these symbols will be concatenated together by the linker, we need 95 // to reset the state machine that controls the debug symbols. The fields in 96 // the state machine that need to be reset are: 97 // file = 1 98 // line = 1 99 // column = 0 100 // stmt = set in header, we assume true 101 // basic_block = false 102 // Careful readers of the DWARF specification will note that we don't reset 103 // the address of the state machine -- but this will happen at the beginning 104 // of the NEXT block of opcodes. 105 dctxt.AddUint8(lines, dwarf.DW_LNS_set_file) 106 dwarf.Uleb128put(dctxt, lines, 1) 107 dctxt.AddUint8(lines, dwarf.DW_LNS_advance_line) 108 dwarf.Sleb128put(dctxt, lines, int64(1-line)) 109 if !stmt { 110 dctxt.AddUint8(lines, dwarf.DW_LNS_negate_stmt) 111 } 112 dctxt.AddUint8(lines, dwarf.DW_LNS_copy) 113 } 114 115 func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) { 116 // Choose a special opcode that minimizes the number of bytes needed to 117 // encode the remaining PC delta and LC delta. 118 var opcode int64 119 if deltaLC < LINE_BASE { 120 if deltaPC >= PC_RANGE { 121 opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE) 122 } else { 123 opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC)) 124 } 125 } else if deltaLC < LINE_BASE+LINE_RANGE { 126 if deltaPC >= PC_RANGE { 127 opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE) 128 if opcode > 255 { 129 opcode -= LINE_RANGE 130 } 131 } else { 132 opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC)) 133 } 134 } else { 135 if deltaPC <= PC_RANGE { 136 opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC)) 137 if opcode > 255 { 138 opcode = 255 139 } 140 } else { 141 // Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1). 142 // 143 // Let x=deltaPC-PC_RANGE. If we use opcode 255, x will be the remaining 144 // deltaPC that we need to encode separately before emitting 255. If we 145 // use opcode 249, we will need to encode x+1. If x+1 takes one more 146 // byte to encode than x, then we use opcode 255. 147 // 148 // In all other cases x and x+1 take the same number of bytes to encode, 149 // so we use opcode 249, which may save us a byte in encoding deltaLC, 150 // for similar reasons. 151 switch deltaPC - PC_RANGE { 152 // PC_RANGE is the largest deltaPC we can encode in one byte, using 153 // DW_LNS_const_add_pc. 154 // 155 // (1<<16)-1 is the largest deltaPC we can encode in three bytes, using 156 // DW_LNS_fixed_advance_pc. 157 // 158 // (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for 159 // n=1,3,4,5,..., using DW_LNS_advance_pc. 160 case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1, 161 (1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1: 162 opcode = 255 163 default: 164 opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249 165 } 166 } 167 } 168 if opcode < OPCODE_BASE || opcode > 255 { 169 panic(fmt.Sprintf("produced invalid special opcode %d", opcode)) 170 } 171 172 // Subtract from deltaPC and deltaLC the amounts that the opcode will add. 173 deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE) 174 deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE 175 176 // Encode deltaPC. 177 if deltaPC != 0 { 178 if deltaPC <= PC_RANGE { 179 // Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc 180 // instruction. 181 opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC) 182 if opcode < OPCODE_BASE { 183 panic(fmt.Sprintf("produced invalid special opcode %d", opcode)) 184 } 185 dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc) 186 } else if (1<<14) <= deltaPC && deltaPC < (1<<16) { 187 dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc) 188 dctxt.AddUint16(s, uint16(deltaPC)) 189 } else { 190 dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc) 191 dwarf.Uleb128put(dctxt, s, int64(deltaPC)) 192 } 193 } 194 195 // Encode deltaLC. 196 if deltaLC != 0 { 197 dctxt.AddUint8(s, dwarf.DW_LNS_advance_line) 198 dwarf.Sleb128put(dctxt, s, deltaLC) 199 } 200 201 // Output the special opcode. 202 dctxt.AddUint8(s, uint8(opcode)) 203 }