2014-06-29 16:52:21 +00:00
|
|
|
package util
|
|
|
|
|
2017-08-22 14:40:01 +00:00
|
|
|
import (
|
|
|
|
"bytes"
|
2020-08-18 00:19:46 +00:00
|
|
|
"debug/dwarf"
|
2020-03-10 16:34:40 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
2017-08-22 14:40:01 +00:00
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2021-03-05 04:17:00 +00:00
|
|
|
// ByteReaderWithLen is a io.ByteReader with a Len method. This interface is
|
|
|
|
// satisified by both bytes.Buffer and bytes.Reader.
|
|
|
|
type ByteReaderWithLen interface {
|
|
|
|
io.ByteReader
|
|
|
|
io.Reader
|
|
|
|
Len() int
|
|
|
|
}
|
|
|
|
|
2017-08-22 14:40:01 +00:00
|
|
|
// The Little Endian Base 128 format is defined in the DWARF v4 standard,
|
|
|
|
// section 7.6, page 161 and following.
|
2014-06-29 16:52:21 +00:00
|
|
|
|
|
|
|
// DecodeULEB128 decodes an unsigned Little Endian Base 128
|
|
|
|
// represented number.
|
2021-03-05 04:17:00 +00:00
|
|
|
func DecodeULEB128(buf ByteReaderWithLen) (uint64, uint32) {
|
2014-06-29 16:52:21 +00:00
|
|
|
var (
|
|
|
|
result uint64
|
|
|
|
shift uint64
|
|
|
|
length uint32
|
|
|
|
)
|
|
|
|
|
2014-09-13 17:28:46 +00:00
|
|
|
if buf.Len() == 0 {
|
|
|
|
return 0, 0
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:21 +00:00
|
|
|
for {
|
|
|
|
b, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
panic("Could not parse ULEB128 value")
|
|
|
|
}
|
|
|
|
length++
|
|
|
|
|
|
|
|
result |= uint64((uint(b) & 0x7f) << shift)
|
|
|
|
|
|
|
|
// If high order bit is 1.
|
|
|
|
if b&0x80 == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
shift += 7
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, length
|
|
|
|
}
|
|
|
|
|
2016-05-17 23:36:41 +00:00
|
|
|
// DecodeSLEB128 decodes a signed Little Endian Base 128
|
2014-06-29 16:52:21 +00:00
|
|
|
// represented number.
|
2021-03-05 04:17:00 +00:00
|
|
|
func DecodeSLEB128(buf ByteReaderWithLen) (int64, uint32) {
|
2014-06-29 16:52:21 +00:00
|
|
|
var (
|
|
|
|
b byte
|
|
|
|
err error
|
|
|
|
result int64
|
|
|
|
shift uint64
|
|
|
|
length uint32
|
|
|
|
)
|
|
|
|
|
2014-09-13 17:28:46 +00:00
|
|
|
if buf.Len() == 0 {
|
|
|
|
return 0, 0
|
|
|
|
}
|
|
|
|
|
2014-06-29 16:52:21 +00:00
|
|
|
for {
|
|
|
|
b, err = buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
panic("Could not parse SLEB128 value")
|
|
|
|
}
|
|
|
|
length++
|
|
|
|
|
|
|
|
result |= int64((int64(b) & 0x7f) << shift)
|
|
|
|
shift += 7
|
|
|
|
if b&0x80 == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shift < 8*uint64(length)) && (b&0x40 > 0) {
|
|
|
|
result |= -(1 << shift)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, length
|
|
|
|
}
|
|
|
|
|
2017-08-22 14:40:01 +00:00
|
|
|
// EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format
|
|
|
|
// into out.
|
|
|
|
func EncodeULEB128(out io.ByteWriter, x uint64) {
|
|
|
|
for {
|
|
|
|
b := byte(x & 0x7f)
|
|
|
|
x = x >> 7
|
|
|
|
if x != 0 {
|
|
|
|
b = b | 0x80
|
|
|
|
}
|
|
|
|
out.WriteByte(b)
|
|
|
|
if x == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// EncodeSLEB128 encodes x to the signed Little Endian Base 128 format
|
|
|
|
// into out.
|
|
|
|
func EncodeSLEB128(out io.ByteWriter, x int64) {
|
|
|
|
for {
|
|
|
|
b := byte(x & 0x7f)
|
|
|
|
x >>= 7
|
|
|
|
|
|
|
|
signb := b & 0x40
|
|
|
|
|
|
|
|
last := false
|
|
|
|
if (x == 0 && signb == 0) || (x == -1 && signb != 0) {
|
|
|
|
last = true
|
|
|
|
} else {
|
|
|
|
b = b | 0x80
|
|
|
|
}
|
|
|
|
out.WriteByte(b)
|
|
|
|
|
|
|
|
if last {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 17:31:11 +00:00
|
|
|
// ParseString reads a null-terminated string from data.
|
2014-06-29 16:52:21 +00:00
|
|
|
func ParseString(data *bytes.Buffer) (string, uint32) {
|
2014-07-15 02:41:15 +00:00
|
|
|
str, err := data.ReadString(0x0)
|
|
|
|
if err != nil {
|
|
|
|
panic("Could not parse string")
|
2014-06-29 16:52:21 +00:00
|
|
|
}
|
|
|
|
|
2014-07-15 02:41:15 +00:00
|
|
|
return str[:len(str)-1], uint32(len(str))
|
2014-06-29 16:52:21 +00:00
|
|
|
}
|
2020-03-10 16:34:40 +00:00
|
|
|
|
|
|
|
// ReadUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader.
|
|
|
|
func ReadUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) {
|
|
|
|
switch ptrSize {
|
|
|
|
case 4:
|
|
|
|
var n uint32
|
|
|
|
if err := binary.Read(reader, order, &n); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return uint64(n), nil
|
|
|
|
case 8:
|
|
|
|
var n uint64
|
|
|
|
if err := binary.Read(reader, order, &n); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
return 0, fmt.Errorf("not supprted ptr size %d", ptrSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteUint writes an integer of ptrSize bytes to writer, in the specified byte order.
|
|
|
|
func WriteUint(writer io.Writer, order binary.ByteOrder, ptrSize int, data uint64) error {
|
|
|
|
switch ptrSize {
|
|
|
|
case 4:
|
|
|
|
return binary.Write(writer, order, uint32(data))
|
|
|
|
case 8:
|
|
|
|
return binary.Write(writer, order, data)
|
|
|
|
}
|
|
|
|
return fmt.Errorf("not support prt size %d", ptrSize)
|
|
|
|
}
|
2020-08-18 00:19:46 +00:00
|
|
|
|
|
|
|
// ReadDwarfLength reads a DWARF length field followed by a version field
|
|
|
|
func ReadDwarfLengthVersion(data []byte) (length uint64, dwarf64 bool, version uint8, byteOrder binary.ByteOrder) {
|
|
|
|
if len(data) < 4 {
|
|
|
|
return 0, false, 0, binary.LittleEndian
|
|
|
|
}
|
|
|
|
|
|
|
|
lengthfield := binary.LittleEndian.Uint32(data)
|
|
|
|
voff := 4
|
|
|
|
if lengthfield == ^uint32(0) {
|
|
|
|
dwarf64 = true
|
|
|
|
voff = 12
|
|
|
|
}
|
|
|
|
|
|
|
|
if voff+1 >= len(data) {
|
|
|
|
return 0, false, 0, binary.LittleEndian
|
|
|
|
}
|
|
|
|
|
|
|
|
byteOrder = binary.LittleEndian
|
|
|
|
x, y := data[voff], data[voff+1]
|
|
|
|
switch {
|
|
|
|
default:
|
|
|
|
fallthrough
|
|
|
|
case x == 0 && y == 0:
|
|
|
|
version = 0
|
|
|
|
byteOrder = binary.LittleEndian
|
|
|
|
case x == 0:
|
|
|
|
version = y
|
|
|
|
byteOrder = binary.BigEndian
|
|
|
|
case y == 0:
|
|
|
|
version = x
|
|
|
|
byteOrder = binary.LittleEndian
|
|
|
|
}
|
|
|
|
|
|
|
|
if dwarf64 {
|
|
|
|
length = byteOrder.Uint64(data[4:])
|
|
|
|
} else {
|
|
|
|
length = uint64(byteOrder.Uint32(data))
|
|
|
|
}
|
|
|
|
|
|
|
|
return length, dwarf64, version, byteOrder
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
_DW_UT_compile = 0x1 + iota
|
|
|
|
_DW_UT_type
|
|
|
|
_DW_UT_partial
|
|
|
|
_DW_UT_skeleton
|
|
|
|
_DW_UT_split_compile
|
|
|
|
_DW_UT_split_type
|
|
|
|
)
|
|
|
|
|
|
|
|
// ReadUnitVersions reads the DWARF version of each unit in a debug_info section and returns them as a map.
|
|
|
|
func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 {
|
|
|
|
r := make(map[dwarf.Offset]uint8)
|
|
|
|
off := dwarf.Offset(0)
|
|
|
|
for len(data) > 0 {
|
|
|
|
length, dwarf64, version, _ := ReadDwarfLengthVersion(data)
|
|
|
|
|
|
|
|
data = data[4:]
|
|
|
|
off += 4
|
|
|
|
secoffsz := 4
|
|
|
|
if dwarf64 {
|
|
|
|
off += 8
|
|
|
|
secoffsz = 8
|
|
|
|
data = data[8:]
|
|
|
|
}
|
|
|
|
|
|
|
|
var headerSize int
|
|
|
|
|
|
|
|
switch version {
|
|
|
|
case 2, 3, 4:
|
|
|
|
headerSize = 3 + secoffsz
|
|
|
|
default: // 5 and later?
|
|
|
|
unitType := data[2]
|
|
|
|
|
|
|
|
switch unitType {
|
|
|
|
case _DW_UT_compile, _DW_UT_partial:
|
|
|
|
headerSize = 5 + secoffsz
|
|
|
|
|
|
|
|
case _DW_UT_skeleton, _DW_UT_split_compile:
|
|
|
|
headerSize = 4 + secoffsz + 8
|
|
|
|
|
|
|
|
case _DW_UT_type, _DW_UT_split_type:
|
|
|
|
headerSize = 4 + secoffsz + 8 + secoffsz
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r[off+dwarf.Offset(headerSize)] = version
|
|
|
|
|
|
|
|
data = data[length:] // skip contents
|
|
|
|
off += dwarf.Offset(length)
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|