xpos.go raw

   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  }
 177