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