mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	 1afcc6c189
			
		
	
	1afcc6c189
	
	
	
		
			
			* service: Prevent panics from crashing delve and killing the target Catch all unrecovered proc and debugger panics in the service layer and report them as errors, allow users to cleanly detach from the target and quit. Fixes #614 * proc: Next/Step should not panic if line info can not be found. Fixes #683
		
			
				
	
	
		
			253 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package line
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/binary"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/derekparker/delve/dwarf/util"
 | |
| )
 | |
| 
 | |
| type Location struct {
 | |
| 	File    string
 | |
| 	Line    int
 | |
| 	Address uint64
 | |
| 	Delta   int
 | |
| }
 | |
| 
 | |
| type StateMachine struct {
 | |
| 	dbl             *DebugLineInfo
 | |
| 	file            string
 | |
| 	line            int
 | |
| 	address         uint64
 | |
| 	column          uint
 | |
| 	isStmt          bool
 | |
| 	basicBlock      bool
 | |
| 	endSeq          bool
 | |
| 	lastWasStandard bool
 | |
| 	lastDelta       int
 | |
| }
 | |
| 
 | |
| type opcodefn func(*StateMachine, *bytes.Buffer)
 | |
| 
 | |
| // Special opcodes
 | |
| const (
 | |
| 	DW_LNS_copy             = 1
 | |
| 	DW_LNS_advance_pc       = 2
 | |
| 	DW_LNS_advance_line     = 3
 | |
| 	DW_LNS_set_file         = 4
 | |
| 	DW_LNS_set_column       = 5
 | |
| 	DW_LNS_negate_stmt      = 6
 | |
| 	DW_LNS_set_basic_block  = 7
 | |
| 	DW_LNS_const_add_pc     = 8
 | |
| 	DW_LNS_fixed_advance_pc = 9
 | |
| )
 | |
| 
 | |
| // Extended opcodes
 | |
| const (
 | |
| 	DW_LINE_end_sequence = 1
 | |
| 	DW_LINE_set_address  = 2
 | |
| 	DW_LINE_define_file  = 3
 | |
| )
 | |
| 
 | |
| var standardopcodes = map[byte]opcodefn{
 | |
| 	DW_LNS_copy:             copyfn,
 | |
| 	DW_LNS_advance_pc:       advancepc,
 | |
| 	DW_LNS_advance_line:     advanceline,
 | |
| 	DW_LNS_set_file:         setfile,
 | |
| 	DW_LNS_set_column:       setcolumn,
 | |
| 	DW_LNS_negate_stmt:      negatestmt,
 | |
| 	DW_LNS_set_basic_block:  setbasicblock,
 | |
| 	DW_LNS_const_add_pc:     constaddpc,
 | |
| 	DW_LNS_fixed_advance_pc: fixedadvancepc,
 | |
| }
 | |
| 
 | |
| var extendedopcodes = map[byte]opcodefn{
 | |
| 	DW_LINE_end_sequence: endsequence,
 | |
| 	DW_LINE_set_address:  setaddress,
 | |
| 	DW_LINE_define_file:  definefile,
 | |
| }
 | |
| 
 | |
| func newStateMachine(dbl *DebugLineInfo) *StateMachine {
 | |
| 	return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Name, line: 1}
 | |
| }
 | |
| 
 | |
| // Returns all PCs for a given file/line. Useful for loops where the 'for' line
 | |
| // could be split amongst 2 PCs.
 | |
| func (dbl *DebugLines) AllPCsForFileLine(f string, l int) (pcs []uint64) {
 | |
| 	var (
 | |
| 		foundFile bool
 | |
| 		lastAddr  uint64
 | |
| 		lineInfo  = dbl.GetLineInfo(f)
 | |
| 		sm        = newStateMachine(lineInfo)
 | |
| 		buf       = bytes.NewBuffer(lineInfo.Instructions)
 | |
| 	)
 | |
| 
 | |
| 	for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
 | |
| 		findAndExecOpcode(sm, buf, b)
 | |
| 		if foundFile && sm.file != f {
 | |
| 			return
 | |
| 		}
 | |
| 		if sm.line == l && sm.file == f && sm.address != lastAddr {
 | |
| 			foundFile = true
 | |
| 			pcs = append(pcs, sm.address)
 | |
| 			line := sm.line
 | |
| 			// 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,
 | |
| 			// and try to find the line we care about again.
 | |
| 			for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
 | |
| 				findAndExecOpcode(sm, buf, b)
 | |
| 				if line < sm.line {
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| var NoSourceError = errors.New("no source available")
 | |
| 
 | |
| func (dbl *DebugLines) AllPCsBetween(begin, end uint64, filename string) ([]uint64, error) {
 | |
| 	lineInfo := dbl.GetLineInfo(filename)
 | |
| 	if lineInfo == nil {
 | |
| 		return nil, NoSourceError
 | |
| 	}
 | |
| 	var (
 | |
| 		pcs      []uint64
 | |
| 		lastaddr uint64
 | |
| 		sm       = newStateMachine(lineInfo)
 | |
| 		buf      = bytes.NewBuffer(lineInfo.Instructions)
 | |
| 	)
 | |
| 
 | |
| 	for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
 | |
| 		findAndExecOpcode(sm, buf, b)
 | |
| 		if sm.address > end {
 | |
| 			break
 | |
| 		}
 | |
| 		if sm.address >= begin && sm.address > lastaddr {
 | |
| 			lastaddr = sm.address
 | |
| 			pcs = append(pcs, sm.address)
 | |
| 		}
 | |
| 	}
 | |
| 	return pcs, nil
 | |
| }
 | |
| 
 | |
| func findAndExecOpcode(sm *StateMachine, buf *bytes.Buffer, b byte) {
 | |
| 	switch {
 | |
| 	case b == 0:
 | |
| 		execExtendedOpcode(sm, b, buf)
 | |
| 	case b < sm.dbl.Prologue.OpcodeBase:
 | |
| 		execStandardOpcode(sm, b, buf)
 | |
| 	default:
 | |
| 		execSpecialOpcode(sm, b)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func execSpecialOpcode(sm *StateMachine, instr byte) {
 | |
| 	var (
 | |
| 		opcode  = uint8(instr)
 | |
| 		decoded = opcode - sm.dbl.Prologue.OpcodeBase
 | |
| 	)
 | |
| 
 | |
| 	if sm.dbl.Prologue.InitialIsStmt == uint8(1) {
 | |
| 		sm.isStmt = true
 | |
| 	}
 | |
| 
 | |
| 	sm.lastDelta = int(sm.dbl.Prologue.LineBase + int8(decoded%sm.dbl.Prologue.LineRange))
 | |
| 	sm.line += sm.lastDelta
 | |
| 	sm.address += uint64(decoded / sm.dbl.Prologue.LineRange)
 | |
| 	sm.basicBlock = false
 | |
| 	sm.lastWasStandard = false
 | |
| }
 | |
| 
 | |
| func execExtendedOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
 | |
| 	_, _ = util.DecodeULEB128(buf)
 | |
| 	b, _ := buf.ReadByte()
 | |
| 	fn, ok := extendedopcodes[b]
 | |
| 	if !ok {
 | |
| 		panic(fmt.Sprintf("Encountered unknown extended opcode %#v\n", b))
 | |
| 	}
 | |
| 	sm.lastWasStandard = 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
 | |
| 
 | |
| 	fn(sm, buf)
 | |
| }
 | |
| 
 | |
| func copyfn(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	sm.basicBlock = false
 | |
| }
 | |
| 
 | |
| func advancepc(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	addr, _ := util.DecodeULEB128(buf)
 | |
| 	sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength)
 | |
| }
 | |
| 
 | |
| func advanceline(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	line, _ := util.DecodeSLEB128(buf)
 | |
| 	sm.line += int(line)
 | |
| 	sm.lastDelta = int(line)
 | |
| }
 | |
| 
 | |
| func setfile(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	i, _ := util.DecodeULEB128(buf)
 | |
| 	sm.file = sm.dbl.FileNames[i-1].Name
 | |
| }
 | |
| 
 | |
| func setcolumn(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	c, _ := util.DecodeULEB128(buf)
 | |
| 	sm.column = uint(c)
 | |
| }
 | |
| 
 | |
| func negatestmt(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	sm.isStmt = !sm.isStmt
 | |
| }
 | |
| 
 | |
| func setbasicblock(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	sm.basicBlock = true
 | |
| }
 | |
| 
 | |
| func constaddpc(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	sm.address += (255 / uint64(sm.dbl.Prologue.LineRange))
 | |
| }
 | |
| 
 | |
| func fixedadvancepc(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	var operand uint16
 | |
| 	binary.Read(buf, binary.LittleEndian, &operand)
 | |
| 
 | |
| 	sm.address += uint64(operand)
 | |
| }
 | |
| 
 | |
| func endsequence(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	sm.endSeq = true
 | |
| }
 | |
| 
 | |
| func setaddress(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	var addr uint64
 | |
| 
 | |
| 	binary.Read(buf, binary.LittleEndian, &addr)
 | |
| 
 | |
| 	sm.address = addr
 | |
| }
 | |
| 
 | |
| func definefile(sm *StateMachine, buf *bytes.Buffer) {
 | |
| 	var (
 | |
| 		_, _ = util.ParseString(buf)
 | |
| 		_, _ = util.DecodeULEB128(buf)
 | |
| 		_, _ = util.DecodeULEB128(buf)
 | |
| 		_, _ = util.DecodeULEB128(buf)
 | |
| 	)
 | |
| 
 | |
| 	// Don't do anything here yet.
 | |
| }
 |