pkg/dwarf/line: improve performance
1. Use a slice instead of a map to access standard and extended opcodes (reduces BenchmarkStateMachine from ~12ms/op to ~7ms/op) 2. Cache StateMachine values for the entry point of functions.
This commit is contained in:
parent
6d40517944
commit
73a39b985a
BIN
_fixtures/debug_line_benchmark_data
Normal file
BIN
_fixtures/debug_line_benchmark_data
Normal file
Binary file not shown.
@ -26,6 +26,12 @@ type DebugLineInfo struct {
|
|||||||
FileNames []*FileEntry
|
FileNames []*FileEntry
|
||||||
Instructions []byte
|
Instructions []byte
|
||||||
Lookup map[string]*FileEntry
|
Lookup map[string]*FileEntry
|
||||||
|
|
||||||
|
// stateMachineCache[pc] is a state machine stopped at pc
|
||||||
|
stateMachineCache map[uint64]*StateMachine
|
||||||
|
|
||||||
|
// lastMachineCache[pc] is a state machine stopped at an address after pc
|
||||||
|
lastMachineCache map[uint64]*StateMachine
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileEntry struct {
|
type FileEntry struct {
|
||||||
@ -61,6 +67,9 @@ func Parse(compdir string, buf *bytes.Buffer) *DebugLineInfo {
|
|||||||
dbl.IncludeDirs = append(dbl.IncludeDirs, compdir)
|
dbl.IncludeDirs = append(dbl.IncludeDirs, compdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbl.stateMachineCache = make(map[uint64]*StateMachine)
|
||||||
|
dbl.lastMachineCache = make(map[uint64]*StateMachine)
|
||||||
|
|
||||||
parseDebugLinePrologue(dbl, buf)
|
parseDebugLinePrologue(dbl, buf)
|
||||||
parseIncludeDirs(dbl, buf)
|
parseIncludeDirs(dbl, buf)
|
||||||
parseFileEntries(dbl, buf)
|
parseFileEntries(dbl, buf)
|
||||||
|
@ -5,11 +5,14 @@ import (
|
|||||||
"debug/macho"
|
"debug/macho"
|
||||||
"debug/pe"
|
"debug/pe"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/profile"
|
"github.com/pkg/profile"
|
||||||
)
|
)
|
||||||
@ -157,3 +160,116 @@ func BenchmarkLineParser(b *testing.B) {
|
|||||||
_ = ParseAll(data)
|
_ = ParseAll(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadBenchmarkData(tb testing.TB) DebugLines {
|
||||||
|
p, err := filepath.Abs("../../../_fixtures/debug_line_benchmark_data")
|
||||||
|
if err != nil {
|
||||||
|
tb.Fatal("Could not find test data", p, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(p)
|
||||||
|
if err != nil {
|
||||||
|
tb.Fatal("Could not read test data", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseAll(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkStateMachine(b *testing.B) {
|
||||||
|
lineInfos := loadBenchmarkData(b)
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
sm := newStateMachine(lineInfos[0], lineInfos[0].Instructions)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type pctolineEntry struct {
|
||||||
|
pc uint64
|
||||||
|
file string
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *pctolineEntry) match(file string, line int) bool {
|
||||||
|
if entry.file == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return entry.file == file && entry.line == line
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTestPCToLine(t testing.TB, lineInfos DebugLines) []pctolineEntry {
|
||||||
|
entries := []pctolineEntry{}
|
||||||
|
|
||||||
|
sm := newStateMachine(lineInfos[0], lineInfos[0].Instructions)
|
||||||
|
for {
|
||||||
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if sm.valid {
|
||||||
|
if len(entries) == 0 || entries[len(entries)-1].pc != sm.address {
|
||||||
|
entries = append(entries, pctolineEntry{pc: sm.address, file: sm.file, line: sm.line})
|
||||||
|
} else if len(entries) > 0 {
|
||||||
|
// having two entries at the same PC address messes up the test
|
||||||
|
entries[len(entries)-1].file = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < len(entries); i++ {
|
||||||
|
if entries[i].pc <= entries[i-1].pc {
|
||||||
|
t.Fatalf("not monotonically increasing %d %x", i, entries[i].pc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTestPCToLine(t testing.TB, lineInfos DebugLines, entries []pctolineEntry, log bool, testSize uint64) {
|
||||||
|
const samples = 1000
|
||||||
|
t0 := time.Now()
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for pc := entries[0].pc; pc <= entries[0].pc+testSize; pc++ {
|
||||||
|
file, line := lineInfos[0].PCToLine(pc/0x1000*0x1000, pc)
|
||||||
|
if pc == entries[i].pc {
|
||||||
|
if i%samples == 0 && log {
|
||||||
|
fmt.Printf("match %x / %x (%v)\n", pc, entries[len(entries)-1].pc, time.Since(t0)/samples)
|
||||||
|
t0 = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !entries[i].match(file, line) {
|
||||||
|
t.Fatalf("Mismatch at PC %#x, expected %s:%d got %s:%d", pc, entries[i].file, entries[i].line, file, line)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
if !entries[i-1].match(file, line) {
|
||||||
|
t.Fatalf("Mismatch at PC %#x, expected %s:%d (from previous valid entry) got %s:%d", pc, entries[i-1].file, entries[i-1].line, file, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPCToLine(t *testing.T) {
|
||||||
|
lineInfos := loadBenchmarkData(t)
|
||||||
|
|
||||||
|
entries := setupTestPCToLine(t, lineInfos)
|
||||||
|
runTestPCToLine(t, lineInfos, entries, true, 0x50000)
|
||||||
|
t.Logf("restart form beginning")
|
||||||
|
runTestPCToLine(t, lineInfos, entries, true, 0x10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPCToLine(b *testing.B) {
|
||||||
|
lineInfos := loadBenchmarkData(b)
|
||||||
|
|
||||||
|
entries := setupTestPCToLine(b, lineInfos)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
runTestPCToLine(b, lineInfos, entries, false, 0x10000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -32,6 +32,15 @@ type StateMachine struct {
|
|||||||
// value of the state machine should be appended to the matrix representing
|
// value of the state machine should be appended to the matrix representing
|
||||||
// the compilation unit)
|
// the compilation unit)
|
||||||
valid bool
|
valid bool
|
||||||
|
|
||||||
|
started bool
|
||||||
|
|
||||||
|
buf *bytes.Buffer // remaining instructions
|
||||||
|
opcodes []opcodefn
|
||||||
|
|
||||||
|
lastAddress uint64
|
||||||
|
lastFile string
|
||||||
|
lastLine int
|
||||||
}
|
}
|
||||||
|
|
||||||
type opcodefn func(*StateMachine, *bytes.Buffer)
|
type opcodefn func(*StateMachine, *bytes.Buffer)
|
||||||
@ -47,11 +56,6 @@ const (
|
|||||||
DW_LNS_set_basic_block = 7
|
DW_LNS_set_basic_block = 7
|
||||||
DW_LNS_const_add_pc = 8
|
DW_LNS_const_add_pc = 8
|
||||||
DW_LNS_fixed_advance_pc = 9
|
DW_LNS_fixed_advance_pc = 9
|
||||||
|
|
||||||
// DWARF v4
|
|
||||||
DW_LNS_set_prologue_end = 10
|
|
||||||
DW_LNS_set_epilouge_begin = 11
|
|
||||||
DW_LNS_set_isa = 12
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Extended opcodes
|
// Extended opcodes
|
||||||
@ -71,11 +75,6 @@ var standardopcodes = map[byte]opcodefn{
|
|||||||
DW_LNS_set_basic_block: setbasicblock,
|
DW_LNS_set_basic_block: setbasicblock,
|
||||||
DW_LNS_const_add_pc: constaddpc,
|
DW_LNS_const_add_pc: constaddpc,
|
||||||
DW_LNS_fixed_advance_pc: fixedadvancepc,
|
DW_LNS_fixed_advance_pc: fixedadvancepc,
|
||||||
|
|
||||||
// DWARF v4
|
|
||||||
DW_LNS_set_prologue_end: donothing0,
|
|
||||||
DW_LNS_set_epilouge_begin: donothing0,
|
|
||||||
DW_LNS_set_isa: donothing1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var extendedopcodes = map[byte]opcodefn{
|
var extendedopcodes = map[byte]opcodefn{
|
||||||
@ -84,8 +83,13 @@ var extendedopcodes = map[byte]opcodefn{
|
|||||||
DW_LINE_define_file: definefile,
|
DW_LINE_define_file: definefile,
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStateMachine(dbl *DebugLineInfo) *StateMachine {
|
func newStateMachine(dbl *DebugLineInfo, instructions []byte) *StateMachine {
|
||||||
return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Path, line: 1}
|
opcodes := make([]opcodefn, len(standardopcodes)+1)
|
||||||
|
opcodes[0] = execExtendedOpcode
|
||||||
|
for op := range standardopcodes {
|
||||||
|
opcodes[op] = standardopcodes[op]
|
||||||
|
}
|
||||||
|
return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Path, line: 1, buf: bytes.NewBuffer(instructions), opcodes: opcodes}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns all PCs for a given file/line. Useful for loops where the 'for' line
|
// Returns all PCs for a given file/line. Useful for loops where the 'for' line
|
||||||
@ -98,12 +102,13 @@ func (lineInfo *DebugLineInfo) AllPCsForFileLine(f string, l int) (pcs []uint64)
|
|||||||
var (
|
var (
|
||||||
foundFile bool
|
foundFile bool
|
||||||
lastAddr uint64
|
lastAddr uint64
|
||||||
sm = newStateMachine(lineInfo)
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
for {
|
||||||
findAndExecOpcode(sm, buf, b)
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if foundFile && sm.file != f {
|
if foundFile && sm.file != f {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -116,8 +121,10 @@ func (lineInfo *DebugLineInfo) AllPCsForFileLine(f string, l int) (pcs []uint64)
|
|||||||
// Keep going until we're on a different line. We only care about
|
// Keep going until we're on a different line. We only care about
|
||||||
// when a line comes back around (i.e. for loop) so get to next line,
|
// when a line comes back around (i.e. for loop) so get to next line,
|
||||||
// and try to find the line we care about again.
|
// and try to find the line we care about again.
|
||||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
for {
|
||||||
findAndExecOpcode(sm, buf, b)
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if line < sm.line {
|
if line < sm.line {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -137,12 +144,13 @@ func (lineInfo *DebugLineInfo) AllPCsBetween(begin, end uint64) ([]uint64, error
|
|||||||
var (
|
var (
|
||||||
pcs []uint64
|
pcs []uint64
|
||||||
lastaddr uint64
|
lastaddr uint64
|
||||||
sm = newStateMachine(lineInfo)
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
for {
|
||||||
findAndExecOpcode(sm, buf, b)
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if !sm.valid {
|
if !sm.valid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -157,34 +165,76 @@ func (lineInfo *DebugLineInfo) AllPCsBetween(begin, end uint64) ([]uint64, error
|
|||||||
return pcs, nil
|
return pcs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy returns a copy of this state machine, running the returned state
|
||||||
|
// machine will not affect sm.
|
||||||
|
func (sm *StateMachine) copy() *StateMachine {
|
||||||
|
var r StateMachine
|
||||||
|
r = *sm
|
||||||
|
r.buf = bytes.NewBuffer(sm.buf.Bytes())
|
||||||
|
return &r
|
||||||
|
}
|
||||||
|
|
||||||
// PCToLine returns the filename and line number associated with pc.
|
// PCToLine returns the filename and line number associated with pc.
|
||||||
// If pc isn't found inside lineInfo's table it will return the filename and
|
// If pc isn't found inside lineInfo's table it will return the filename and
|
||||||
// line number associated with the closest PC address preceding pc.
|
// line number associated with the closest PC address preceding pc.
|
||||||
func (lineInfo *DebugLineInfo) PCToLine(pc uint64) (string, int) {
|
// basePC will be used for caching, it's normally the entry point for the
|
||||||
|
// function containing pc.
|
||||||
|
func (lineInfo *DebugLineInfo) PCToLine(basePC, pc uint64) (string, int) {
|
||||||
if lineInfo == nil {
|
if lineInfo == nil {
|
||||||
return "", 0
|
return "", 0
|
||||||
}
|
}
|
||||||
|
if basePC > pc {
|
||||||
var (
|
panic(fmt.Errorf("basePC after pc %#x %#x", basePC, pc))
|
||||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
|
||||||
sm = newStateMachine(lineInfo)
|
|
||||||
lastFilename string
|
|
||||||
lastLineno int
|
|
||||||
)
|
|
||||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
|
||||||
findAndExecOpcode(sm, buf, b)
|
|
||||||
if !sm.valid {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if sm.address > pc {
|
|
||||||
return lastFilename, lastLineno
|
|
||||||
}
|
|
||||||
if sm.address == pc {
|
|
||||||
return sm.file, sm.line
|
|
||||||
}
|
|
||||||
lastFilename, lastLineno = sm.file, sm.line
|
|
||||||
}
|
}
|
||||||
return "", 0
|
|
||||||
|
var sm *StateMachine
|
||||||
|
if basePC == 0 {
|
||||||
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
|
} else {
|
||||||
|
// Try to use the last state machine that we used for this function, if
|
||||||
|
// there isn't one or it's already past pc try to clone the cached state
|
||||||
|
// machine stopped at the entry point of the function.
|
||||||
|
// As a last resort start from the start of the debug_line section.
|
||||||
|
sm = lineInfo.lastMachineCache[basePC]
|
||||||
|
if sm == nil || sm.lastAddress > pc {
|
||||||
|
sm = lineInfo.stateMachineCache[basePC]
|
||||||
|
if sm == nil {
|
||||||
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
|
sm.PCToLine(basePC)
|
||||||
|
lineInfo.stateMachineCache[basePC] = sm
|
||||||
|
}
|
||||||
|
sm = sm.copy()
|
||||||
|
lineInfo.lastMachineCache[basePC] = sm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file, line, _ := sm.PCToLine(pc)
|
||||||
|
return file, line
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateMachine) PCToLine(pc uint64) (string, int, bool) {
|
||||||
|
if !sm.started {
|
||||||
|
if err := sm.next(); err != nil {
|
||||||
|
return "", 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sm.lastAddress > pc {
|
||||||
|
return "", 0, false
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if sm.valid {
|
||||||
|
if sm.address > pc {
|
||||||
|
return sm.lastFile, sm.lastLine, true
|
||||||
|
}
|
||||||
|
if sm.address == pc {
|
||||||
|
return sm.file, sm.line, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// LineToPC returns the first PC address associated with filename:lineno.
|
// LineToPC returns the first PC address associated with filename:lineno.
|
||||||
@ -195,12 +245,13 @@ func (lineInfo *DebugLineInfo) LineToPC(filename string, lineno int) uint64 {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
foundFile bool
|
foundFile bool
|
||||||
sm = newStateMachine(lineInfo)
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
buf = bytes.NewBuffer(lineInfo.Instructions)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
|
for {
|
||||||
findAndExecOpcode(sm, buf, b)
|
if err := sm.next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if foundFile && sm.file != filename {
|
if foundFile && sm.file != filename {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -214,15 +265,30 @@ func (lineInfo *DebugLineInfo) LineToPC(filename string, lineno int) uint64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAndExecOpcode(sm *StateMachine, buf *bytes.Buffer, b byte) {
|
func (sm *StateMachine) next() error {
|
||||||
switch {
|
sm.started = true
|
||||||
case b == 0:
|
if sm.valid {
|
||||||
execExtendedOpcode(sm, b, buf)
|
sm.lastAddress, sm.lastFile, sm.lastLine = sm.address, sm.file, sm.line
|
||||||
case b < sm.dbl.Prologue.OpcodeBase:
|
}
|
||||||
execStandardOpcode(sm, b, buf)
|
b, err := sm.buf.ReadByte()
|
||||||
default:
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if int(b) < len(sm.opcodes) {
|
||||||
|
sm.lastWasStandard = b != 0
|
||||||
|
sm.valid = false
|
||||||
|
sm.opcodes[b](sm, sm.buf)
|
||||||
|
} else if b < sm.dbl.Prologue.OpcodeBase {
|
||||||
|
// unimplemented standard opcode, read the number of arguments specified
|
||||||
|
// in the prologue and do nothing with them
|
||||||
|
opnum := sm.dbl.Prologue.StdOpLengths[b-1]
|
||||||
|
for i := 0; i < int(opnum); i++ {
|
||||||
|
util.DecodeSLEB128(sm.buf)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
execSpecialOpcode(sm, b)
|
execSpecialOpcode(sm, b)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execSpecialOpcode(sm *StateMachine, instr byte) {
|
func execSpecialOpcode(sm *StateMachine, instr byte) {
|
||||||
@ -243,28 +309,12 @@ func execSpecialOpcode(sm *StateMachine, instr byte) {
|
|||||||
sm.valid = true
|
sm.valid = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func execExtendedOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
|
func execExtendedOpcode(sm *StateMachine, buf *bytes.Buffer) {
|
||||||
_, _ = util.DecodeULEB128(buf)
|
_, _ = util.DecodeULEB128(buf)
|
||||||
b, _ := buf.ReadByte()
|
b, _ := buf.ReadByte()
|
||||||
fn, ok := extendedopcodes[b]
|
if fn, ok := extendedopcodes[b]; ok {
|
||||||
if !ok {
|
fn(sm, buf)
|
||||||
panic(fmt.Sprintf("Encountered unknown extended opcode %#v\n", b))
|
|
||||||
}
|
}
|
||||||
sm.lastWasStandard = false
|
|
||||||
sm.valid = false
|
|
||||||
|
|
||||||
fn(sm, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func execStandardOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
|
|
||||||
fn, ok := standardopcodes[instr]
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("Encountered unknown standard opcode %#v\n", instr))
|
|
||||||
}
|
|
||||||
sm.lastWasStandard = true
|
|
||||||
sm.valid = false
|
|
||||||
|
|
||||||
fn(sm, buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyfn(sm *StateMachine, buf *bytes.Buffer) {
|
func copyfn(sm *StateMachine, buf *bytes.Buffer) {
|
||||||
@ -312,15 +362,6 @@ func fixedadvancepc(sm *StateMachine, buf *bytes.Buffer) {
|
|||||||
sm.address += uint64(operand)
|
sm.address += uint64(operand)
|
||||||
}
|
}
|
||||||
|
|
||||||
func donothing0(sm *StateMachine, buf *bytes.Buffer) {
|
|
||||||
// does nothing, no operands
|
|
||||||
}
|
|
||||||
|
|
||||||
func donothing1(sm *StateMachine, buf *bytes.Buffer) {
|
|
||||||
// does nothing, consumes one operand
|
|
||||||
util.DecodeSLEB128(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func endsequence(sm *StateMachine, buf *bytes.Buffer) {
|
func endsequence(sm *StateMachine, buf *bytes.Buffer) {
|
||||||
sm.endSeq = true
|
sm.endSeq = true
|
||||||
sm.valid = true
|
sm.valid = true
|
||||||
|
@ -175,7 +175,7 @@ func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *Function) {
|
|||||||
if fn == nil {
|
if fn == nil {
|
||||||
return "", 0, nil
|
return "", 0, nil
|
||||||
}
|
}
|
||||||
f, ln := fn.cu.lineInfo.PCToLine(pc)
|
f, ln := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
|
||||||
return f, ln, fn
|
return f, ln, fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ func FindFunctionLocation(p Process, funcName string, firstLine bool, lineOffset
|
|||||||
if firstLine {
|
if firstLine {
|
||||||
return FirstPCAfterPrologue(p, origfn, false)
|
return FirstPCAfterPrologue(p, origfn, false)
|
||||||
} else if lineOffset > 0 {
|
} else if lineOffset > 0 {
|
||||||
filename, lineno := origfn.cu.lineInfo.PCToLine(origfn.Entry)
|
filename, lineno := origfn.cu.lineInfo.PCToLine(origfn.Entry, origfn.Entry)
|
||||||
breakAddr, _, err := bi.LineToPC(filename, lineno+lineOffset)
|
breakAddr, _, err := bi.LineToPC(filename, lineno+lineOffset)
|
||||||
return breakAddr, err
|
return breakAddr, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user