| // 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 "encoding/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:] |
| switch { |
| case code == 0: |
| if len(b) < 4 { |
| b = b[0:0] |
| break |
| } |
| val := binary.BigEndian.Uint32(b) |
| b = b[4:] |
| 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} |
| } |