xpos.go (5109B)
1 // Copyright 2016 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 // This file implements the compressed encoding of source 6 // positions using a lookup table. 7 8 package src 9 10 // XPos is a more compact representation of Pos. 11 type XPos struct { 12 index int32 13 lico 14 } 15 16 // NoXPos is a valid unknown position. 17 var NoXPos XPos 18 19 // IsKnown reports whether the position p is known. 20 // XPos.IsKnown() matches Pos.IsKnown() for corresponding 21 // positions. 22 func (p XPos) IsKnown() bool { 23 return p.index != 0 || p.Line() != 0 24 } 25 26 // Before reports whether the position p comes before q in the source. 27 // For positions with different bases, ordering is by base index. 28 func (p XPos) Before(q XPos) bool { 29 n, m := p.index, q.index 30 return n < m || n == m && p.lico < q.lico 31 } 32 33 // SameFile reports whether p and q are positions in the same file. 34 func (p XPos) SameFile(q XPos) bool { 35 return p.index == q.index 36 } 37 38 // SameFileAndLine reports whether p and q are positions on the same line in the same file. 39 func (p XPos) SameFileAndLine(q XPos) bool { 40 return p.index == q.index && p.lico.SameLine(q.lico) 41 } 42 43 // After reports whether the position p comes after q in the source. 44 // For positions with different bases, ordering is by base index. 45 func (p XPos) After(q XPos) bool { 46 n, m := p.index, q.index 47 return n > m || n == m && p.lico > q.lico 48 } 49 50 // WithNotStmt returns the same location to be marked with DWARF is_stmt=0 51 func (p XPos) WithNotStmt() XPos { 52 p.lico = p.lico.withNotStmt() 53 return p 54 } 55 56 // WithDefaultStmt returns the same location with undetermined is_stmt 57 func (p XPos) WithDefaultStmt() XPos { 58 p.lico = p.lico.withDefaultStmt() 59 return p 60 } 61 62 // WithIsStmt returns the same location to be marked with DWARF is_stmt=1 63 func (p XPos) WithIsStmt() XPos { 64 p.lico = p.lico.withIsStmt() 65 return p 66 } 67 68 // WithBogusLine returns a bogus line that won't match any recorded for the source code. 69 // Its use is to disrupt the statements within an infinite loop so that the debugger 70 // will not itself loop infinitely waiting for the line number to change. 71 // gdb chooses not to display the bogus line; delve shows it with a complaint, but the 72 // alternative behavior is to hang. 73 func (p XPos) WithBogusLine() XPos { 74 if p.index == 0 { 75 // See #35652 76 panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.") 77 } 78 p.lico = makeBogusLico() 79 return p 80 } 81 82 // WithXlogue returns the same location but marked with DWARF function prologue/epilogue 83 func (p XPos) WithXlogue(x PosXlogue) XPos { 84 p.lico = p.lico.withXlogue(x) 85 return p 86 } 87 88 // LineNumber returns a string for the line number, "?" if it is not known. 89 func (p XPos) LineNumber() string { 90 if !p.IsKnown() { 91 return "?" 92 } 93 return p.lico.lineNumber() 94 } 95 96 // FileIndex returns a smallish non-negative integer corresponding to the 97 // file for this source position. Smallish is relative; it can be thousands 98 // large, but not millions. 99 func (p XPos) FileIndex() int32 { 100 return p.index 101 } 102 103 func (p XPos) LineNumberHTML() string { 104 if !p.IsKnown() { 105 return "?" 106 } 107 return p.lico.lineNumberHTML() 108 } 109 110 // AtColumn1 returns the same location but shifted to column 1. 111 func (p XPos) AtColumn1() XPos { 112 p.lico = p.lico.atColumn1() 113 return p 114 } 115 116 // A PosTable tracks Pos -> XPos conversions and vice versa. 117 // Its zero value is a ready-to-use PosTable. 118 type PosTable struct { 119 baseList []*PosBase 120 indexMap map[*PosBase]int 121 nameMap map[string]int // Maps file symbol name to index for debug information. 122 } 123 124 // XPos returns the corresponding XPos for the given pos, 125 // adding pos to t if necessary. 126 func (t *PosTable) XPos(pos Pos) XPos { 127 m := t.indexMap 128 if m == nil { 129 // Create new list and map and populate with nil 130 // base so that NoPos always gets index 0. 131 t.baseList = append(t.baseList, nil) 132 m = map[*PosBase]int{nil: 0} 133 t.indexMap = m 134 t.nameMap = make(map[string]int) 135 } 136 i, ok := m[pos.base] 137 if !ok { 138 i = len(t.baseList) 139 t.baseList = append(t.baseList, pos.base) 140 t.indexMap[pos.base] = i 141 if _, ok := t.nameMap[pos.base.symFilename]; !ok { 142 t.nameMap[pos.base.symFilename] = len(t.nameMap) 143 } 144 } 145 return XPos{int32(i), pos.lico} 146 } 147 148 // Pos returns the corresponding Pos for the given p. 149 // If p cannot be translated via t, the function panics. 150 func (t *PosTable) Pos(p XPos) Pos { 151 var base *PosBase 152 if p.index != 0 { 153 base = t.baseList[p.index] 154 } 155 return Pos{base, p.lico} 156 } 157 158 // FileIndex returns the index of the given filename(symbol) in the PosTable, or -1 if not found. 159 func (t *PosTable) FileIndex(filename string) int { 160 if v, ok := t.nameMap[filename]; ok { 161 return v 162 } 163 return -1 164 } 165 166 // FileTable returns a slice of all files used to build this package. 167 func (t *PosTable) FileTable() []string { 168 // Create a LUT of the global package level file indices. This table is what 169 // is written in the debug_lines header, the file[N] will be referenced as 170 // N+1 in the debug_lines table. 171 fileLUT := make([]string, len(t.nameMap)) 172 for str, i := range t.nameMap { 173 fileLUT[i] = str 174 } 175 return fileLUT 176 }