github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/dwarf/parseutil.go (about)

     1  package dwarf
     2  
     3  import (
     4  	"bytes"
     5  	"debug/dwarf"
     6  	"encoding/binary"
     7  	"fmt"
     8  	"io"
     9  )
    10  
    11  // ReadString reads a null-terminated string from data.
    12  func ReadString(data *bytes.Buffer) (string, error) {
    13  	str, err := data.ReadString(0x0)
    14  	if err != nil {
    15  		return "", err
    16  	}
    17  
    18  	return str[:len(str)-1], nil
    19  }
    20  
    21  // ReadUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader.
    22  func ReadUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) {
    23  	switch ptrSize {
    24  	case 2:
    25  		var n uint16
    26  		if err := binary.Read(reader, order, &n); err != nil {
    27  			return 0, err
    28  		}
    29  		return uint64(n), nil
    30  	case 4:
    31  		var n uint32
    32  		if err := binary.Read(reader, order, &n); err != nil {
    33  			return 0, err
    34  		}
    35  		return uint64(n), nil
    36  	case 8:
    37  		var n uint64
    38  		if err := binary.Read(reader, order, &n); err != nil {
    39  			return 0, err
    40  		}
    41  		return n, nil
    42  	}
    43  	return 0, fmt.Errorf("pointer size %d not supported", ptrSize)
    44  }
    45  
    46  // WriteUint writes an integer of ptrSize bytes to writer, in the specified byte order.
    47  func WriteUint(writer io.Writer, order binary.ByteOrder, ptrSize int, data uint64) error {
    48  	switch ptrSize {
    49  	case 4:
    50  		return binary.Write(writer, order, uint32(data))
    51  	case 8:
    52  		return binary.Write(writer, order, data)
    53  	}
    54  	return fmt.Errorf("pointer size %d not supported", ptrSize)
    55  }
    56  
    57  // ReadDwarfLengthVersion reads a DWARF length field followed by a version field
    58  func ReadDwarfLengthVersion(data []byte) (length uint64, dwarf64 bool, version uint8, byteOrder binary.ByteOrder) {
    59  	if len(data) < 4 {
    60  		return 0, false, 0, binary.LittleEndian
    61  	}
    62  
    63  	lengthfield := binary.LittleEndian.Uint32(data)
    64  	voff := 4
    65  	if lengthfield == ^uint32(0) {
    66  		dwarf64 = true
    67  		voff = 12
    68  	}
    69  
    70  	if voff+1 >= len(data) {
    71  		return 0, false, 0, binary.LittleEndian
    72  	}
    73  
    74  	byteOrder = binary.LittleEndian
    75  	x, y := data[voff], data[voff+1]
    76  	switch {
    77  	default:
    78  		fallthrough
    79  	case x == 0 && y == 0:
    80  		version = 0
    81  		byteOrder = binary.LittleEndian
    82  	case x == 0:
    83  		version = y
    84  		byteOrder = binary.BigEndian
    85  	case y == 0:
    86  		version = x
    87  		byteOrder = binary.LittleEndian
    88  	}
    89  
    90  	if dwarf64 {
    91  		length = byteOrder.Uint64(data[4:])
    92  	} else {
    93  		length = uint64(byteOrder.Uint32(data))
    94  	}
    95  
    96  	return length, dwarf64, version, byteOrder
    97  }
    98  
    99  const (
   100  	_DW_UT_compile = 0x1 + iota
   101  	_DW_UT_type
   102  	_DW_UT_partial
   103  	_DW_UT_skeleton
   104  	_DW_UT_split_compile
   105  	_DW_UT_split_type
   106  )
   107  
   108  // ReadUnitVersions reads the DWARF version of each unit in a debug_info section and returns them as a map.
   109  func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 {
   110  	r := make(map[dwarf.Offset]uint8)
   111  	off := dwarf.Offset(0)
   112  	for len(data) > 0 {
   113  		length, dwarf64, version, _ := ReadDwarfLengthVersion(data)
   114  
   115  		data = data[4:]
   116  		off += 4
   117  		secoffsz := 4
   118  		if dwarf64 {
   119  			off += 8
   120  			secoffsz = 8
   121  			data = data[8:]
   122  		}
   123  
   124  		var headerSize int
   125  
   126  		switch version {
   127  		case 2, 3, 4:
   128  			headerSize = 3 + secoffsz
   129  		default: // 5 and later?
   130  			unitType := data[2]
   131  
   132  			switch unitType {
   133  			case _DW_UT_compile, _DW_UT_partial:
   134  				headerSize = 5 + secoffsz
   135  
   136  			case _DW_UT_skeleton, _DW_UT_split_compile:
   137  				headerSize = 4 + secoffsz + 8
   138  
   139  			case _DW_UT_type, _DW_UT_split_type:
   140  				headerSize = 4 + secoffsz + 8 + secoffsz
   141  			}
   142  		}
   143  
   144  		r[off+dwarf.Offset(headerSize)] = version
   145  
   146  		data = data[length:] // skip contents
   147  		off += dwarf.Offset(length)
   148  	}
   149  	return r
   150  }