github.com/undoio/delve@v1.9.0/pkg/dwarf/frame/entries.go (about)

     1  package frame
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"sort"
     7  )
     8  
     9  // CommonInformationEntry represents a Common Information Entry in
    10  // the Dwarf .debug_frame section.
    11  type CommonInformationEntry struct {
    12  	Length                uint32
    13  	CIE_id                uint32
    14  	Version               uint8
    15  	Augmentation          string
    16  	CodeAlignmentFactor   uint64
    17  	DataAlignmentFactor   int64
    18  	ReturnAddressRegister uint64
    19  	InitialInstructions   []byte
    20  	staticBase            uint64
    21  
    22  	// eh_frame pointer encoding
    23  	ptrEncAddr ptrEnc
    24  }
    25  
    26  // FrameDescriptionEntry represents a Frame Descriptor Entry in the
    27  // Dwarf .debug_frame section.
    28  type FrameDescriptionEntry struct {
    29  	Length       uint32
    30  	CIE          *CommonInformationEntry
    31  	Instructions []byte
    32  	begin, size  uint64
    33  	order        binary.ByteOrder
    34  }
    35  
    36  // Cover returns whether or not the given address is within the
    37  // bounds of this frame.
    38  func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
    39  	return (addr - fde.begin) < fde.size
    40  }
    41  
    42  // Begin returns address of first location for this frame.
    43  func (fde *FrameDescriptionEntry) Begin() uint64 {
    44  	return fde.begin
    45  }
    46  
    47  // End returns address of last location for this frame.
    48  func (fde *FrameDescriptionEntry) End() uint64 {
    49  	return fde.begin + fde.size
    50  }
    51  
    52  // Translate moves the beginning of fde forward by delta.
    53  func (fde *FrameDescriptionEntry) Translate(delta uint64) {
    54  	fde.begin += delta
    55  }
    56  
    57  // EstablishFrame set up frame for the given PC.
    58  func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
    59  	return executeDwarfProgramUntilPC(fde, pc)
    60  }
    61  
    62  type FrameDescriptionEntries []*FrameDescriptionEntry
    63  
    64  func newFrameIndex() FrameDescriptionEntries {
    65  	return make(FrameDescriptionEntries, 0, 1000)
    66  }
    67  
    68  // ErrNoFDEForPC FDE for PC not found error
    69  type ErrNoFDEForPC struct {
    70  	PC uint64
    71  }
    72  
    73  func (err *ErrNoFDEForPC) Error() string {
    74  	return fmt.Sprintf("could not find FDE for PC %#v", err.PC)
    75  }
    76  
    77  // FDEForPC returns the Frame Description Entry for the given PC.
    78  func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
    79  	idx := sort.Search(len(fdes), func(i int) bool {
    80  		return fdes[i].Cover(pc) || fdes[i].Begin() >= pc
    81  	})
    82  	if idx == len(fdes) || !fdes[idx].Cover(pc) {
    83  		return nil, &ErrNoFDEForPC{pc}
    84  	}
    85  	return fdes[idx], nil
    86  }
    87  
    88  // Append appends otherFDEs to fdes and returns the result.
    89  func (fdes FrameDescriptionEntries) Append(otherFDEs FrameDescriptionEntries) FrameDescriptionEntries {
    90  	r := append(fdes, otherFDEs...)
    91  	sort.SliceStable(r, func(i, j int) bool {
    92  		return r[i].Begin() < r[j].Begin()
    93  	})
    94  	// remove duplicates
    95  	uniqFDEs := fdes[:0]
    96  	for _, fde := range fdes {
    97  		if len(uniqFDEs) > 0 {
    98  			last := uniqFDEs[len(uniqFDEs)-1]
    99  			if last.Begin() == fde.Begin() && last.End() == fde.End() {
   100  				continue
   101  			}
   102  		}
   103  		uniqFDEs = append(uniqFDEs, fde)
   104  	}
   105  	return r
   106  }
   107  
   108  // ptrEnc represents a pointer encoding value, used during eh_frame decoding
   109  // to determine how pointers were encoded.
   110  // Least significant 4 (0xf) bytes encode the size  as well as its
   111  // signed-ness,  most significant 4 bytes (0xf0 == ptrEncFlagsMask) are flags
   112  // describing how the value should be interpreted (absolute, relative...)
   113  // See https://www.airs.com/blog/archives/460.
   114  type ptrEnc uint8
   115  
   116  const (
   117  	ptrEncAbs    ptrEnc = 0x00 // pointer-sized unsigned integer
   118  	ptrEncOmit   ptrEnc = 0xff // omitted
   119  	ptrEncUleb   ptrEnc = 0x01 // ULEB128
   120  	ptrEncUdata2 ptrEnc = 0x02 // 2 bytes
   121  	ptrEncUdata4 ptrEnc = 0x03 // 4 bytes
   122  	ptrEncUdata8 ptrEnc = 0x04 // 8 bytes
   123  	ptrEncSigned ptrEnc = 0x08 // pointer-sized signed integer
   124  	ptrEncSleb   ptrEnc = 0x09 // SLEB128
   125  	ptrEncSdata2 ptrEnc = 0x0a // 2 bytes, signed
   126  	ptrEncSdata4 ptrEnc = 0x0b // 4 bytes, signed
   127  	ptrEncSdata8 ptrEnc = 0x0c // 8 bytes, signed
   128  
   129  	ptrEncFlagsMask ptrEnc = 0xf0
   130  
   131  	ptrEncPCRel    ptrEnc = 0x10 // value is relative to the memory address where it appears
   132  	ptrEncTextRel  ptrEnc = 0x20 // value is relative to the address of the text section
   133  	ptrEncDataRel  ptrEnc = 0x30 // value is relative to the address of the data section
   134  	ptrEncFuncRel  ptrEnc = 0x40 // value is relative to the start of the function
   135  	ptrEncAligned  ptrEnc = 0x50 // value should be aligned
   136  	ptrEncIndirect ptrEnc = 0x80 // value is an address where the real value of the pointer is stored
   137  
   138  	ptrEncSupportedFlags = ptrEncPCRel
   139  )
   140  
   141  // Supported returns true if this pointer encoding is supported.
   142  func (ptrEnc ptrEnc) Supported() bool {
   143  	if ptrEnc != ptrEncOmit {
   144  		szenc := ptrEnc & 0x0f
   145  		if ((szenc > ptrEncUdata8) && (szenc < ptrEncSigned)) || (szenc > ptrEncSdata8) {
   146  			// These values aren't defined at the moment
   147  			return false
   148  		}
   149  		if (ptrEnc&ptrEncFlagsMask)&^ptrEncSupportedFlags != 0 {
   150  			// Currently only the PC relative flag is supported
   151  			return false
   152  		}
   153  	}
   154  	return true
   155  }