github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/dwarf/util/util.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2014 Derek Parker
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy of
     6  // this software and associated documentation files (the "Software"), to deal in
     7  // the Software without restriction, including without limitation the rights to
     8  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     9  // the Software, and to permit persons to whom the Software is furnished to do so,
    10  // subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package util
    23  
    24  import (
    25  	"bytes"
    26  	"debug/dwarf"
    27  	"encoding/binary"
    28  	"fmt"
    29  	"io"
    30  )
    31  
    32  
    33  
    34  type ByteReaderWithLen interface {
    35  	io.ByteReader
    36  	io.Reader
    37  	Len() int
    38  }
    39  
    40  
    41  
    42  
    43  
    44  
    45  func DecodeULEB128(buf ByteReaderWithLen) (uint64, uint32) {
    46  	var (
    47  		result uint64
    48  		shift  uint64
    49  		length uint32
    50  	)
    51  
    52  	if buf.Len() == 0 {
    53  		return 0, 0
    54  	}
    55  
    56  	for {
    57  		b, err := buf.ReadByte()
    58  		if err != nil {
    59  			panic("Could not parse ULEB128 value")
    60  		}
    61  		length++
    62  
    63  		result |= uint64((uint(b) & 0x7f) << shift)
    64  
    65  		
    66  		if b&0x80 == 0 {
    67  			break
    68  		}
    69  
    70  		shift += 7
    71  	}
    72  
    73  	return result, length
    74  }
    75  
    76  
    77  
    78  func DecodeSLEB128(buf ByteReaderWithLen) (int64, uint32) {
    79  	var (
    80  		b      byte
    81  		err    error
    82  		result int64
    83  		shift  uint64
    84  		length uint32
    85  	)
    86  
    87  	if buf.Len() == 0 {
    88  		return 0, 0
    89  	}
    90  
    91  	for {
    92  		b, err = buf.ReadByte()
    93  		if err != nil {
    94  			panic("Could not parse SLEB128 value")
    95  		}
    96  		length++
    97  
    98  		result |= int64((int64(b) & 0x7f) << shift)
    99  		shift += 7
   100  		if b&0x80 == 0 {
   101  			break
   102  		}
   103  	}
   104  
   105  	if (shift < 8*uint64(length)) && (b&0x40 > 0) {
   106  		result |= -(1 << shift)
   107  	}
   108  
   109  	return result, length
   110  }
   111  
   112  
   113  
   114  func EncodeULEB128(out io.ByteWriter, x uint64) {
   115  	for {
   116  		b := byte(x & 0x7f)
   117  		x = x >> 7
   118  		if x != 0 {
   119  			b = b | 0x80
   120  		}
   121  		out.WriteByte(b)
   122  		if x == 0 {
   123  			break
   124  		}
   125  	}
   126  }
   127  
   128  
   129  
   130  func EncodeSLEB128(out io.ByteWriter, x int64) {
   131  	for {
   132  		b := byte(x & 0x7f)
   133  		x >>= 7
   134  
   135  		signb := b & 0x40
   136  
   137  		last := false
   138  		if (x == 0 && signb == 0) || (x == -1 && signb != 0) {
   139  			last = true
   140  		} else {
   141  			b = b | 0x80
   142  		}
   143  		out.WriteByte(b)
   144  
   145  		if last {
   146  			break
   147  		}
   148  	}
   149  }
   150  
   151  
   152  func ParseString(data *bytes.Buffer) (string, error) {
   153  	str, err := data.ReadString(0x0)
   154  	if err != nil {
   155  		return "", err
   156  	}
   157  
   158  	return str[:len(str)-1], nil
   159  }
   160  
   161  
   162  func ReadUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) {
   163  	switch ptrSize {
   164  	case 2:
   165  		var n uint16
   166  		if err := binary.Read(reader, order, &n); err != nil {
   167  			return 0, err
   168  		}
   169  		return uint64(n), nil
   170  	case 4:
   171  		var n uint32
   172  		if err := binary.Read(reader, order, &n); err != nil {
   173  			return 0, err
   174  		}
   175  		return uint64(n), nil
   176  	case 8:
   177  		var n uint64
   178  		if err := binary.Read(reader, order, &n); err != nil {
   179  			return 0, err
   180  		}
   181  		return n, nil
   182  	}
   183  	return 0, fmt.Errorf("pointer size %d not supported", ptrSize)
   184  }
   185  
   186  
   187  func WriteUint(writer io.Writer, order binary.ByteOrder, ptrSize int, data uint64) error {
   188  	switch ptrSize {
   189  	case 4:
   190  		return binary.Write(writer, order, uint32(data))
   191  	case 8:
   192  		return binary.Write(writer, order, data)
   193  	}
   194  	return fmt.Errorf("pointer size %d not supported", ptrSize)
   195  }
   196  
   197  
   198  func ReadDwarfLengthVersion(data []byte) (length uint64, dwarf64 bool, version uint8, byteOrder binary.ByteOrder) {
   199  	if len(data) < 4 {
   200  		return 0, false, 0, binary.LittleEndian
   201  	}
   202  
   203  	lengthfield := binary.LittleEndian.Uint32(data)
   204  	voff := 4
   205  	if lengthfield == ^uint32(0) {
   206  		dwarf64 = true
   207  		voff = 12
   208  	}
   209  
   210  	if voff+1 >= len(data) {
   211  		return 0, false, 0, binary.LittleEndian
   212  	}
   213  
   214  	byteOrder = binary.LittleEndian
   215  	x, y := data[voff], data[voff+1]
   216  	switch {
   217  	default:
   218  		fallthrough
   219  	case x == 0 && y == 0:
   220  		version = 0
   221  		byteOrder = binary.LittleEndian
   222  	case x == 0:
   223  		version = y
   224  		byteOrder = binary.BigEndian
   225  	case y == 0:
   226  		version = x
   227  		byteOrder = binary.LittleEndian
   228  	}
   229  
   230  	if dwarf64 {
   231  		length = byteOrder.Uint64(data[4:])
   232  	} else {
   233  		length = uint64(byteOrder.Uint32(data))
   234  	}
   235  
   236  	return length, dwarf64, version, byteOrder
   237  }
   238  
   239  const (
   240  	_DW_UT_compile = 0x1 + iota
   241  	_DW_UT_type
   242  	_DW_UT_partial
   243  	_DW_UT_skeleton
   244  	_DW_UT_split_compile
   245  	_DW_UT_split_type
   246  )
   247  
   248  
   249  func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 {
   250  	r := make(map[dwarf.Offset]uint8)
   251  	off := dwarf.Offset(0)
   252  	for len(data) > 0 {
   253  		length, dwarf64, version, _ := ReadDwarfLengthVersion(data)
   254  
   255  		data = data[4:]
   256  		off += 4
   257  		secoffsz := 4
   258  		if dwarf64 {
   259  			off += 8
   260  			secoffsz = 8
   261  			data = data[8:]
   262  		}
   263  
   264  		var headerSize int
   265  
   266  		switch version {
   267  		case 2, 3, 4:
   268  			headerSize = 3 + secoffsz
   269  		default: 
   270  			unitType := data[2]
   271  
   272  			switch unitType {
   273  			case _DW_UT_compile, _DW_UT_partial:
   274  				headerSize = 5 + secoffsz
   275  
   276  			case _DW_UT_skeleton, _DW_UT_split_compile:
   277  				headerSize = 4 + secoffsz + 8
   278  
   279  			case _DW_UT_type, _DW_UT_split_type:
   280  				headerSize = 4 + secoffsz + 8 + secoffsz
   281  			}
   282  		}
   283  
   284  		r[off+dwarf.Offset(headerSize)] = version
   285  
   286  		data = data[length:] 
   287  		off += dwarf.Offset(length)
   288  	}
   289  	return r
   290  }