mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	 a3c7ba8808
			
		
	
	a3c7ba8808
	
	
	
		
			
			This adds a workaround for the bug described at: https://github.com/golang/go/issues/25841 Because dsymutil running on PIE does not adjust the address of debug_frame entries (but adjusts debug_info entries) we try to do the adjustment ourselves. Updates #2346
		
			
				
	
	
		
			152 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package frame
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| )
 | |
| 
 | |
| // CommonInformationEntry represents a Common Information Entry in
 | |
| // the Dwarf .debug_frame section.
 | |
| type CommonInformationEntry struct {
 | |
| 	Length                uint32
 | |
| 	CIE_id                uint32
 | |
| 	Version               uint8
 | |
| 	Augmentation          string
 | |
| 	CodeAlignmentFactor   uint64
 | |
| 	DataAlignmentFactor   int64
 | |
| 	ReturnAddressRegister uint64
 | |
| 	InitialInstructions   []byte
 | |
| 	staticBase            uint64
 | |
| 
 | |
| 	// eh_frame pointer encoding
 | |
| 	ptrEncAddr ptrEnc
 | |
| }
 | |
| 
 | |
| // FrameDescriptionEntry represents a Frame Descriptor Entry in the
 | |
| // Dwarf .debug_frame section.
 | |
| type FrameDescriptionEntry struct {
 | |
| 	Length       uint32
 | |
| 	CIE          *CommonInformationEntry
 | |
| 	Instructions []byte
 | |
| 	begin, size  uint64
 | |
| 	order        binary.ByteOrder
 | |
| }
 | |
| 
 | |
| // Cover returns whether or not the given address is within the
 | |
| // bounds of this frame.
 | |
| func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
 | |
| 	return (addr - fde.begin) < fde.size
 | |
| }
 | |
| 
 | |
| // Begin returns address of first location for this frame.
 | |
| func (fde *FrameDescriptionEntry) Begin() uint64 {
 | |
| 	return fde.begin
 | |
| }
 | |
| 
 | |
| // End returns address of last location for this frame.
 | |
| func (fde *FrameDescriptionEntry) End() uint64 {
 | |
| 	return fde.begin + fde.size
 | |
| }
 | |
| 
 | |
| // Translate moves the beginning of fde forward by delta.
 | |
| func (fde *FrameDescriptionEntry) Translate(delta uint64) {
 | |
| 	fde.begin += delta
 | |
| }
 | |
| 
 | |
| // EstablishFrame set up frame for the given PC.
 | |
| func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
 | |
| 	return executeDwarfProgramUntilPC(fde, pc)
 | |
| }
 | |
| 
 | |
| type FrameDescriptionEntries []*FrameDescriptionEntry
 | |
| 
 | |
| func newFrameIndex() FrameDescriptionEntries {
 | |
| 	return make(FrameDescriptionEntries, 0, 1000)
 | |
| }
 | |
| 
 | |
| // ErrNoFDEForPC FDE for PC not found error
 | |
| type ErrNoFDEForPC struct {
 | |
| 	PC uint64
 | |
| }
 | |
| 
 | |
| func (err *ErrNoFDEForPC) Error() string {
 | |
| 	return fmt.Sprintf("could not find FDE for PC %#v", err.PC)
 | |
| }
 | |
| 
 | |
| // FDEForPC returns the Frame Description Entry for the given PC.
 | |
| func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
 | |
| 	idx := sort.Search(len(fdes), func(i int) bool {
 | |
| 		return fdes[i].Cover(pc) || fdes[i].Begin() >= pc
 | |
| 	})
 | |
| 	if idx == len(fdes) || !fdes[idx].Cover(pc) {
 | |
| 		return nil, &ErrNoFDEForPC{pc}
 | |
| 	}
 | |
| 	return fdes[idx], nil
 | |
| }
 | |
| 
 | |
| // Append appends otherFDEs to fdes and returns the result.
 | |
| func (fdes FrameDescriptionEntries) Append(otherFDEs FrameDescriptionEntries) FrameDescriptionEntries {
 | |
| 	r := append(fdes, otherFDEs...)
 | |
| 	sort.SliceStable(r, func(i, j int) bool {
 | |
| 		return r[i].Begin() < r[j].Begin()
 | |
| 	})
 | |
| 	// remove duplicates
 | |
| 	uniqFDEs := fdes[:0]
 | |
| 	for _, fde := range fdes {
 | |
| 		if len(uniqFDEs) > 0 {
 | |
| 			last := uniqFDEs[len(uniqFDEs)-1]
 | |
| 			if last.Begin() == fde.Begin() && last.End() == fde.End() {
 | |
| 				continue
 | |
| 			}
 | |
| 		}
 | |
| 		uniqFDEs = append(uniqFDEs, fde)
 | |
| 	}
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| // ptrEnc represents a pointer encoding value, used during eh_frame decoding
 | |
| // to determine how pointers were encoded.
 | |
| // Least significant 4 (0xf) bytes encode the size  as well as its
 | |
| // signed-ness,  most significant 4 bytes (0xf0) are flags describing how
 | |
| // the value should be interpreted (absolute, relative...)
 | |
| // See https://www.airs.com/blog/archives/460.
 | |
| type ptrEnc uint8
 | |
| 
 | |
| const (
 | |
| 	ptrEncAbs    ptrEnc = 0x00 // pointer-sized unsigned integer
 | |
| 	ptrEncOmit   ptrEnc = 0xff // omitted
 | |
| 	ptrEncUleb   ptrEnc = 0x01 // ULEB128
 | |
| 	ptrEncUdata2 ptrEnc = 0x02 // 2 bytes
 | |
| 	ptrEncUdata4 ptrEnc = 0x03 // 4 bytes
 | |
| 	ptrEncUdata8 ptrEnc = 0x04 // 8 bytes
 | |
| 	ptrEncSigned ptrEnc = 0x08 // pointer-sized signed integer
 | |
| 	ptrEncSleb   ptrEnc = 0x09 // SLEB128
 | |
| 	ptrEncSdata2 ptrEnc = 0x0a // 2 bytes, signed
 | |
| 	ptrEncSdata4 ptrEnc = 0x0b // 4 bytes, signed
 | |
| 	ptrEncSdata8 ptrEnc = 0x0c // 8 bytes, signed
 | |
| 
 | |
| 	ptrEncPCRel    ptrEnc = 0x10 // value is relative to the memory address where it appears
 | |
| 	ptrEncTextRel  ptrEnc = 0x20 // value is relative to the address of the text section
 | |
| 	ptrEncDataRel  ptrEnc = 0x30 // value is relative to the address of the data section
 | |
| 	ptrEncFuncRel  ptrEnc = 0x40 // value is relative to the start of the function
 | |
| 	ptrEncAligned  ptrEnc = 0x50 // value should be aligned
 | |
| 	ptrEncIndirect ptrEnc = 0x80 // value is an address where the real value of the pointer is stored
 | |
| )
 | |
| 
 | |
| // Supported returns true if this pointer encoding is supported.
 | |
| func (ptrEnc ptrEnc) Supported() bool {
 | |
| 	if ptrEnc != ptrEncOmit {
 | |
| 		szenc := ptrEnc & 0x0f
 | |
| 		if ((szenc > ptrEncUdata8) && (szenc < ptrEncSigned)) || (szenc > ptrEncSdata8) {
 | |
| 			// These values aren't defined at the moment
 | |
| 			return false
 | |
| 		}
 | |
| 		if ptrEnc&0xf0 != ptrEncPCRel {
 | |
| 			// Currently only the PC relative flag is supported
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 |