| // Copyright 2009 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. |
| |
| /* |
| * Line tables |
| */ |
| |
| package gosym |
| |
| import "debug/binary" |
| |
| type LineTable struct { |
| Data []byte; |
| PC uint64; |
| Line int; |
| } |
| |
| // TODO(rsc): Need to pull in quantum from architecture definition. |
| const quantum = 1; |
| |
| func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) { |
| // The PC/line table can be thought of as a sequence of |
| // <pc update>* <line update> |
| // batches. Each update batch results in a (pc, line) pair, |
| // where line applies to every PC from pc up to but not |
| // including the pc of the next pair. |
| // |
| // Here we process each update individually, which simplifies |
| // the code, but makes the corner cases more confusing. |
| b, pc, line = t.Data, t.PC, t.Line; |
| for pc <= targetPC && line != targetLine && len(b) > 0 { |
| code := b[0]; |
| b = b[1:len(b)]; |
| switch { |
| case code == 0: |
| if len(b) < 4 { |
| b = b[0:0]; |
| break; |
| } |
| val := binary.BigEndian.Uint32(b); |
| b = b[4:len(b)]; |
| line += int(val); |
| case code <= 64: |
| line += int(code); |
| case code <= 128: |
| line -= int(code - 64); |
| default: |
| pc += quantum*uint64(code - 128); |
| continue; |
| } |
| pc += quantum; |
| } |
| return b, pc, line; |
| } |
| |
| func (t *LineTable) slice(pc uint64) *LineTable { |
| data, pc, line := t.parse(pc, -1); |
| return &LineTable{data, pc, line}; |
| } |
| |
| func (t *LineTable) PCToLine(pc uint64) int { |
| _, _, line := t.parse(pc, -1); |
| return line; |
| } |
| |
| func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 { |
| _, pc, line1 := t.parse(maxpc, line); |
| if line1 != line { |
| return 0; |
| } |
| // Subtract quantum from PC to account for post-line increment |
| return pc - quantum; |
| } |
| |
| // NewLineTable returns a new PC/line table |
| // corresponding to the encoded data. |
| // Text must be the start address of the |
| // corresponding text segment. |
| func NewLineTable(data []byte, text uint64) *LineTable { |
| return &LineTable{data, text, 0}; |
| } |