proc/dwarf: LEB128 encode/decode in separate pkg (#3235)

This commit is contained in:
Oleksandr Redko 2023-01-10 22:29:58 +02:00 committed by GitHub
parent 3847b7a199
commit 13143680f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 314 additions and 242 deletions

@ -6,7 +6,7 @@ import (
"encoding/binary" "encoding/binary"
"github.com/go-delve/delve/pkg/dwarf/godwarf" "github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/leb128"
) )
// Form represents a DWARF form kind (see Figure 20, page 160 and following, // Form represents a DWARF form kind (see Figure 20, page 160 and following,
@ -229,19 +229,19 @@ func (b *Builder) makeAbbrevTable() []byte {
var abbrev bytes.Buffer var abbrev bytes.Buffer
for i := range b.abbrevs { for i := range b.abbrevs {
util.EncodeULEB128(&abbrev, uint64(i+1)) leb128.EncodeUnsigned(&abbrev, uint64(i+1))
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].tag)) leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].tag))
if b.abbrevs[i].children { if b.abbrevs[i].children {
abbrev.WriteByte(0x01) abbrev.WriteByte(0x01)
} else { } else {
abbrev.WriteByte(0x00) abbrev.WriteByte(0x00)
} }
for j := range b.abbrevs[i].attr { for j := range b.abbrevs[i].attr {
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].attr[j])) leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].attr[j]))
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].form[j])) leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].form[j]))
} }
util.EncodeULEB128(&abbrev, 0) leb128.EncodeUnsigned(&abbrev, 0)
util.EncodeULEB128(&abbrev, 0) leb128.EncodeUnsigned(&abbrev, 0)
} }
return abbrev.Bytes() return abbrev.Bytes()

@ -3,8 +3,8 @@ package dwarfbuilder
import ( import (
"bytes" "bytes"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/op" "github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/util"
) )
// LocEntry represents one entry of debug_loc. // LocEntry represents one entry of debug_loc.
@ -23,9 +23,9 @@ func LocationBlock(args ...interface{}) []byte {
case op.Opcode: case op.Opcode:
buf.WriteByte(byte(x)) buf.WriteByte(byte(x))
case int: case int:
util.EncodeSLEB128(&buf, int64(x)) leb128.EncodeSigned(&buf, int64(x))
case uint: case uint:
util.EncodeULEB128(&buf, uint64(x)) leb128.EncodeUnsigned(&buf, uint64(x))
default: default:
panic("unsupported value type") panic("unsupported value type")
} }

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -123,10 +124,10 @@ func parseFDE(ctx *parseContext) parsefunc {
ctx.entries = append(ctx.entries, ctx.frame) ctx.entries = append(ctx.entries, ctx.frame)
if ctx.parsingEHFrame() && len(ctx.frame.CIE.Augmentation) > 0 { if ctx.parsingEHFrame() && len(ctx.frame.CIE.Augmentation) > 0 {
// If we are parsing a .eh_frame and we saw an agumentation string then we // If we are parsing a .eh_frame and we saw an augmentation string then we
// need to read the augmentation data, which are encoded as a ULEB128 // need to read the augmentation data, which are encoded as a ULEB128
// size followed by 'size' bytes. // size followed by 'size' bytes.
n, _ := util.DecodeULEB128(reader) n, _ := leb128.DecodeUnsigned(reader)
reader.Seek(int64(n), io.SeekCurrent) reader.Seek(int64(n), io.SeekCurrent)
} }
@ -165,23 +166,23 @@ func parseCIE(ctx *parseContext) parsefunc {
} }
// parse code alignment factor // parse code alignment factor
ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf) ctx.common.CodeAlignmentFactor, _ = leb128.DecodeUnsigned(buf)
// parse data alignment factor // parse data alignment factor
ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf) ctx.common.DataAlignmentFactor, _ = leb128.DecodeSigned(buf)
// parse return address register // parse return address register
if ctx.parsingEHFrame() && ctx.common.Version == 1 { if ctx.parsingEHFrame() && ctx.common.Version == 1 {
b, _ := buf.ReadByte() b, _ := buf.ReadByte()
ctx.common.ReturnAddressRegister = uint64(b) ctx.common.ReturnAddressRegister = uint64(b)
} else { } else {
ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf) ctx.common.ReturnAddressRegister, _ = leb128.DecodeUnsigned(buf)
} }
ctx.common.ptrEncAddr = ptrEncAbs ctx.common.ptrEncAddr = ptrEncAbs
if ctx.parsingEHFrame() && len(ctx.common.Augmentation) > 0 { if ctx.parsingEHFrame() && len(ctx.common.Augmentation) > 0 {
_, _ = util.DecodeULEB128(buf) // augmentation data length _, _ = leb128.DecodeUnsigned(buf) // augmentation data length
for i := 1; i < len(ctx.common.Augmentation); i++ { for i := 1; i < len(ctx.common.Augmentation); i++ {
switch ctx.common.Augmentation[i] { switch ctx.common.Augmentation[i] {
case 'L': case 'L':
@ -231,7 +232,7 @@ func parseCIE(ctx *parseContext) parsefunc {
// The parameter addr is the address that the current byte of 'buf' will be // The parameter addr is the address that the current byte of 'buf' will be
// mapped to when the executable file containing the eh_frame section being // mapped to when the executable file containing the eh_frame section being
// parse is loaded in memory. // parse is loaded in memory.
func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen, ptrEnc ptrEnc) uint64 { func (ctx *parseContext) readEncodedPtr(addr uint64, buf leb128.Reader, ptrEnc ptrEnc) uint64 {
if ptrEnc == ptrEncOmit { if ptrEnc == ptrEncOmit {
return 0 return 0
} }
@ -242,7 +243,7 @@ func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen,
case ptrEncAbs, ptrEncSigned: case ptrEncAbs, ptrEncSigned:
ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, ctx.ptrSize) ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, ctx.ptrSize)
case ptrEncUleb: case ptrEncUleb:
ptr, _ = util.DecodeULEB128(buf) ptr, _ = leb128.DecodeUnsigned(buf)
case ptrEncUdata2: case ptrEncUdata2:
ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 2) ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 2)
case ptrEncSdata2: case ptrEncSdata2:
@ -256,7 +257,7 @@ func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen,
case ptrEncUdata8, ptrEncSdata8: case ptrEncUdata8, ptrEncSdata8:
ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 8) ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 8)
case ptrEncSleb: case ptrEncSleb:
n, _ := util.DecodeSLEB128(buf) n, _ := leb128.DecodeSigned(buf)
ptr = uint64(n) ptr = uint64(n)
} }

@ -5,7 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/leb128"
) )
// DWRule wrapper of rule defined for register values. // DWRule wrapper of rule defined for register values.
@ -254,7 +254,7 @@ func offset(frame *FrameContext) {
var ( var (
reg = b & low_6_offset reg = b & low_6_offset
offset, _ = util.DecodeULEB128(frame.buf) offset, _ = leb128.DecodeUnsigned(frame.buf)
) )
frame.Regs[uint64(reg)] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset} frame.Regs[uint64(reg)] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset}
@ -284,26 +284,26 @@ func setloc(frame *FrameContext) {
func offsetextended(frame *FrameContext) { func offsetextended(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
offset, _ = util.DecodeULEB128(frame.buf) offset, _ = leb128.DecodeUnsigned(frame.buf)
) )
frame.Regs[reg] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset} frame.Regs[reg] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset}
} }
func undefined(frame *FrameContext) { func undefined(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
frame.Regs[reg] = DWRule{Rule: RuleUndefined} frame.Regs[reg] = DWRule{Rule: RuleUndefined}
} }
func samevalue(frame *FrameContext) { func samevalue(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
frame.Regs[reg] = DWRule{Rule: RuleSameVal} frame.Regs[reg] = DWRule{Rule: RuleSameVal}
} }
func register(frame *FrameContext) { func register(frame *FrameContext) {
reg1, _ := util.DecodeULEB128(frame.buf) reg1, _ := leb128.DecodeUnsigned(frame.buf)
reg2, _ := util.DecodeULEB128(frame.buf) reg2, _ := leb128.DecodeUnsigned(frame.buf)
frame.Regs[reg1] = DWRule{Reg: reg2, Rule: RuleRegister} frame.Regs[reg1] = DWRule{Reg: reg2, Rule: RuleRegister}
} }
@ -316,7 +316,7 @@ func restorestate(frame *FrameContext) {
} }
func restoreextended(frame *FrameContext) { func restoreextended(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
oldrule, ok := frame.initialRegs[reg] oldrule, ok := frame.initialRegs[reg]
if ok { if ok {
@ -327,8 +327,8 @@ func restoreextended(frame *FrameContext) {
} }
func defcfa(frame *FrameContext) { func defcfa(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
offset, _ := util.DecodeULEB128(frame.buf) offset, _ := leb128.DecodeUnsigned(frame.buf)
frame.CFA.Rule = RuleCFA frame.CFA.Rule = RuleCFA
frame.CFA.Reg = reg frame.CFA.Reg = reg
@ -336,18 +336,18 @@ func defcfa(frame *FrameContext) {
} }
func defcfaregister(frame *FrameContext) { func defcfaregister(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
frame.CFA.Reg = reg frame.CFA.Reg = reg
} }
func defcfaoffset(frame *FrameContext) { func defcfaoffset(frame *FrameContext) {
offset, _ := util.DecodeULEB128(frame.buf) offset, _ := leb128.DecodeUnsigned(frame.buf)
frame.CFA.Offset = int64(offset) frame.CFA.Offset = int64(offset)
} }
func defcfasf(frame *FrameContext) { func defcfasf(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf) reg, _ := leb128.DecodeUnsigned(frame.buf)
offset, _ := util.DecodeSLEB128(frame.buf) offset, _ := leb128.DecodeSigned(frame.buf)
frame.CFA.Rule = RuleCFA frame.CFA.Rule = RuleCFA
frame.CFA.Reg = reg frame.CFA.Reg = reg
@ -355,14 +355,14 @@ func defcfasf(frame *FrameContext) {
} }
func defcfaoffsetsf(frame *FrameContext) { func defcfaoffsetsf(frame *FrameContext) {
offset, _ := util.DecodeSLEB128(frame.buf) offset, _ := leb128.DecodeSigned(frame.buf)
offset *= frame.dataAlignment offset *= frame.dataAlignment
frame.CFA.Offset = offset frame.CFA.Offset = offset
} }
func defcfaexpression(frame *FrameContext) { func defcfaexpression(frame *FrameContext) {
var ( var (
l, _ = util.DecodeULEB128(frame.buf) l, _ = leb128.DecodeUnsigned(frame.buf)
expr = frame.buf.Next(int(l)) expr = frame.buf.Next(int(l))
) )
@ -372,8 +372,8 @@ func defcfaexpression(frame *FrameContext) {
func expression(frame *FrameContext) { func expression(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
l, _ = util.DecodeULEB128(frame.buf) l, _ = leb128.DecodeUnsigned(frame.buf)
expr = frame.buf.Next(int(l)) expr = frame.buf.Next(int(l))
) )
@ -382,8 +382,8 @@ func expression(frame *FrameContext) {
func offsetextendedsf(frame *FrameContext) { func offsetextendedsf(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
offset, _ = util.DecodeSLEB128(frame.buf) offset, _ = leb128.DecodeSigned(frame.buf)
) )
frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleOffset} frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleOffset}
@ -391,8 +391,8 @@ func offsetextendedsf(frame *FrameContext) {
func valoffset(frame *FrameContext) { func valoffset(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
offset, _ = util.DecodeULEB128(frame.buf) offset, _ = leb128.DecodeUnsigned(frame.buf)
) )
frame.Regs[reg] = DWRule{Offset: int64(offset), Rule: RuleValOffset} frame.Regs[reg] = DWRule{Offset: int64(offset), Rule: RuleValOffset}
@ -400,8 +400,8 @@ func valoffset(frame *FrameContext) {
func valoffsetsf(frame *FrameContext) { func valoffsetsf(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
offset, _ = util.DecodeSLEB128(frame.buf) offset, _ = leb128.DecodeSigned(frame.buf)
) )
frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleValOffset} frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleValOffset}
@ -409,8 +409,8 @@ func valoffsetsf(frame *FrameContext) {
func valexpression(frame *FrameContext) { func valexpression(frame *FrameContext) {
var ( var (
reg, _ = util.DecodeULEB128(frame.buf) reg, _ = leb128.DecodeUnsigned(frame.buf)
l, _ = util.DecodeULEB128(frame.buf) l, _ = leb128.DecodeUnsigned(frame.buf)
expr = frame.buf.Next(int(l)) expr = frame.buf.Next(int(l))
) )

@ -0,0 +1,82 @@
package leb128
import (
"io"
)
// Reader is a io.ByteReader with a Len method. This interface is
// satisfied by both bytes.Buffer and bytes.Reader.
type Reader interface {
io.ByteReader
io.Reader
Len() int
}
// DecodeUnsigned decodes an unsigned Little Endian Base 128
// represented number.
func DecodeUnsigned(buf Reader) (uint64, uint32) {
var (
result uint64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
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
}
// DecodeSigned decodes a signed Little Endian Base 128
// represented number.
func DecodeSigned(buf Reader) (int64, uint32) {
var (
b byte
err error
result int64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
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
}

@ -0,0 +1,28 @@
package leb128
import (
"bytes"
"testing"
)
func TestDecodeUnsigned(t *testing.T) {
leb128 := bytes.NewBuffer([]byte{0xE5, 0x8E, 0x26})
n, c := DecodeUnsigned(leb128)
if n != 624485 {
t.Fatal("Number was not decoded properly, got: ", n, c)
}
if c != 3 {
t.Fatal("Count not returned correctly")
}
}
func TestDecodeSigned(t *testing.T) {
sleb128 := bytes.NewBuffer([]byte{0x9b, 0xf1, 0x59})
n, c := DecodeSigned(sleb128)
if n != -624485 {
t.Fatal("Number was not decoded properly, got: ", n, c)
}
}

4
pkg/dwarf/leb128/doc.go Normal file

@ -0,0 +1,4 @@
// Package leb128 provides encoders and decoders for The Little Endian Base 128 format.
// The Little Endian Base 128 format is defined in the DWARF v4 standard,
// section 7.6, page 161 and following.
package leb128

@ -0,0 +1,42 @@
package leb128
import (
"io"
)
// EncodeUnsigned encodes x to the unsigned Little Endian Base 128 format.
func EncodeUnsigned(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
}
}
}
// EncodeSigned encodes x to the signed Little Endian Base 128 format.
func EncodeSigned(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
}
}
}

@ -0,0 +1,42 @@
package leb128
import (
"bytes"
"testing"
)
func TestEncodeUnsigned(t *testing.T) {
tc := []uint64{0x00, 0x7f, 0x80, 0x8f, 0xffff, 0xfffffff7}
for i := range tc {
var buf bytes.Buffer
EncodeUnsigned(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeUnsigned(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}
func TestEncodeSigned(t *testing.T) {
tc := []int64{2, -2, 127, -127, 128, -128, 129, -129}
for i := range tc {
var buf bytes.Buffer
EncodeSigned(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeSigned(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}

@ -6,6 +6,7 @@ import (
"path" "path"
"strings" "strings"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -173,7 +174,7 @@ func parseIncludeDirs5(info *DebugLineInfo, buf *bytes.Buffer) bool {
if dirEntryFormReader == nil { if dirEntryFormReader == nil {
return false return false
} }
dirCount, _ := util.DecodeULEB128(buf) dirCount, _ := leb128.DecodeUnsigned(buf)
info.IncludeDirs = make([]string, 0, dirCount) info.IncludeDirs = make([]string, 0, dirCount)
for i := uint64(0); i < dirCount; i++ { for i := uint64(0); i < dirCount; i++ {
dirEntryFormReader.reset() dirEntryFormReader.reset()
@ -242,9 +243,9 @@ func readFileEntry(info *DebugLineInfo, buf *bytes.Buffer, exitOnEmptyPath bool)
entry.Path = strings.ReplaceAll(entry.Path, "\\", "/") entry.Path = strings.ReplaceAll(entry.Path, "\\", "/")
} }
entry.DirIdx, _ = util.DecodeULEB128(buf) entry.DirIdx, _ = leb128.DecodeUnsigned(buf)
entry.LastModTime, _ = util.DecodeULEB128(buf) entry.LastModTime, _ = leb128.DecodeUnsigned(buf)
entry.Length, _ = util.DecodeULEB128(buf) entry.Length, _ = leb128.DecodeUnsigned(buf)
if !pathIsAbs(entry.Path) { if !pathIsAbs(entry.Path) {
if entry.DirIdx < uint64(len(info.IncludeDirs)) { if entry.DirIdx < uint64(len(info.IncludeDirs)) {
entry.Path = path.Join(info.IncludeDirs[entry.DirIdx], entry.Path) entry.Path = path.Join(info.IncludeDirs[entry.DirIdx], entry.Path)
@ -276,7 +277,7 @@ func parseFileEntries5(info *DebugLineInfo, buf *bytes.Buffer) bool {
if fileEntryFormReader == nil { if fileEntryFormReader == nil {
return false return false
} }
fileCount, _ := util.DecodeULEB128(buf) fileCount, _ := leb128.DecodeUnsigned(buf)
info.FileNames = make([]*FileEntry, 0, fileCount) info.FileNames = make([]*FileEntry, 0, fileCount)
for i := 0; i < int(fileCount); i++ { for i := 0; i < int(fileCount); i++ {
var ( var (

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -70,8 +71,8 @@ func readEntryFormat(buf *bytes.Buffer, logf func(string, ...interface{})) *form
formCodes: make([]uint64, count), formCodes: make([]uint64, count),
} }
for i := range r.contentTypes { for i := range r.contentTypes {
r.contentTypes[i], _ = util.DecodeULEB128(buf) r.contentTypes[i], _ = leb128.DecodeUnsigned(buf)
r.formCodes[i], _ = util.DecodeULEB128(buf) r.formCodes[i], _ = leb128.DecodeUnsigned(buf)
} }
return r return r
} }
@ -94,7 +95,7 @@ func (rdr *formReader) next(buf *bytes.Buffer) bool {
switch rdr.formCode { switch rdr.formCode {
case _DW_FORM_block: case _DW_FORM_block:
n, _ := util.DecodeULEB128(buf) n, _ := leb128.DecodeUnsigned(buf)
rdr.readBlock(buf, n) rdr.readBlock(buf, n)
case _DW_FORM_block1: case _DW_FORM_block1:
@ -150,10 +151,10 @@ func (rdr *formReader) next(buf *bytes.Buffer) bool {
rdr.readBlock(buf, 16) rdr.readBlock(buf, 16)
case _DW_FORM_sdata: case _DW_FORM_sdata:
rdr.i64, _ = util.DecodeSLEB128(buf) rdr.i64, _ = leb128.DecodeSigned(buf)
case _DW_FORM_udata, _DW_FORM_strx: case _DW_FORM_udata, _DW_FORM_strx:
rdr.u64, _ = util.DecodeULEB128(buf) rdr.u64, _ = leb128.DecodeUnsigned(buf)
case _DW_FORM_string: case _DW_FORM_string:
rdr.str, _ = util.ParseString(buf) rdr.str, _ = util.ParseString(buf)

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -409,7 +410,7 @@ func (sm *StateMachine) next() error {
// in the prologue and do nothing with them // in the prologue and do nothing with them
opnum := sm.dbl.Prologue.StdOpLengths[b-1] opnum := sm.dbl.Prologue.StdOpLengths[b-1]
for i := 0; i < int(opnum); i++ { for i := 0; i < int(opnum); i++ {
util.DecodeSLEB128(sm.buf) leb128.DecodeSigned(sm.buf)
} }
fmt.Printf("unknown opcode %d(0x%x), %d arguments, file %s, line %d, address 0x%x\n", b, b, opnum, sm.file, sm.line, sm.address) fmt.Printf("unknown opcode %d(0x%x), %d arguments, file %s, line %d, address 0x%x\n", b, b, opnum, sm.file, sm.line, sm.address)
} }
@ -432,7 +433,7 @@ func execSpecialOpcode(sm *StateMachine, instr byte) {
} }
func execExtendedOpcode(sm *StateMachine, buf *bytes.Buffer) { func execExtendedOpcode(sm *StateMachine, buf *bytes.Buffer) {
_, _ = util.DecodeULEB128(buf) _, _ = leb128.DecodeUnsigned(buf)
b, _ := buf.ReadByte() b, _ := buf.ReadByte()
if fn, ok := extendedopcodes[b]; ok { if fn, ok := extendedopcodes[b]; ok {
fn(sm, buf) fn(sm, buf)
@ -444,18 +445,18 @@ func copyfn(sm *StateMachine, buf *bytes.Buffer) {
} }
func advancepc(sm *StateMachine, buf *bytes.Buffer) { func advancepc(sm *StateMachine, buf *bytes.Buffer) {
addr, _ := util.DecodeULEB128(buf) addr, _ := leb128.DecodeUnsigned(buf)
sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength) sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength)
} }
func advanceline(sm *StateMachine, buf *bytes.Buffer) { func advanceline(sm *StateMachine, buf *bytes.Buffer) {
line, _ := util.DecodeSLEB128(buf) line, _ := leb128.DecodeSigned(buf)
sm.line += int(line) sm.line += int(line)
sm.lastDelta = int(line) sm.lastDelta = int(line)
} }
func setfile(sm *StateMachine, buf *bytes.Buffer) { func setfile(sm *StateMachine, buf *bytes.Buffer) {
i, _ := util.DecodeULEB128(buf) i, _ := leb128.DecodeUnsigned(buf)
if sm.dbl.Prologue.Version < 5 { if sm.dbl.Prologue.Version < 5 {
// in DWARF v5 files are indexed starting from 0, in v4 and prior the index starts at 1 // in DWARF v5 files are indexed starting from 0, in v4 and prior the index starts at 1
i-- i--
@ -473,7 +474,7 @@ func setfile(sm *StateMachine, buf *bytes.Buffer) {
} }
func setcolumn(sm *StateMachine, buf *bytes.Buffer) { func setcolumn(sm *StateMachine, buf *bytes.Buffer) {
c, _ := util.DecodeULEB128(buf) c, _ := leb128.DecodeUnsigned(buf)
sm.column = uint(c) sm.column = uint(c)
} }
@ -510,7 +511,7 @@ func setaddress(sm *StateMachine, buf *bytes.Buffer) {
} }
func setdiscriminator(sm *StateMachine, buf *bytes.Buffer) { func setdiscriminator(sm *StateMachine, buf *bytes.Buffer) {
_, _ = util.DecodeULEB128(buf) _, _ = leb128.DecodeUnsigned(buf)
} }
func definefile(sm *StateMachine, buf *bytes.Buffer) { func definefile(sm *StateMachine, buf *bytes.Buffer) {
@ -528,6 +529,6 @@ func epiloguebegin(sm *StateMachine, buf *bytes.Buffer) {
} }
func setisa(sm *StateMachine, buf *bytes.Buffer) { func setisa(sm *StateMachine, buf *bytes.Buffer) {
c, _ := util.DecodeULEB128(buf) c, _ := leb128.DecodeUnsigned(buf)
sm.isa = c sm.isa = c
} }

@ -13,6 +13,7 @@ import (
"runtime" "runtime"
"testing" "testing"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -136,7 +137,7 @@ func TestMultipleSequences(t *testing.T) {
write_DW_LNE_set_address := func(addr uint64) { write_DW_LNE_set_address := func(addr uint64) {
instr.WriteByte(0) instr.WriteByte(0)
util.EncodeULEB128(instr, 9) // 1 + ptr_size leb128.EncodeUnsigned(instr, 9) // 1 + ptr_size
instr.WriteByte(DW_LINE_set_address) instr.WriteByte(DW_LINE_set_address)
util.WriteUint(instr, binary.LittleEndian, ptrSize, addr) util.WriteUint(instr, binary.LittleEndian, ptrSize, addr)
} }
@ -147,17 +148,17 @@ func TestMultipleSequences(t *testing.T) {
write_DW_LNS_advance_pc := func(off uint64) { write_DW_LNS_advance_pc := func(off uint64) {
instr.WriteByte(DW_LNS_advance_pc) instr.WriteByte(DW_LNS_advance_pc)
util.EncodeULEB128(instr, off) leb128.EncodeUnsigned(instr, off)
} }
write_DW_LNS_advance_line := func(off int64) { write_DW_LNS_advance_line := func(off int64) {
instr.WriteByte(DW_LNS_advance_line) instr.WriteByte(DW_LNS_advance_line)
util.EncodeSLEB128(instr, off) leb128.EncodeSigned(instr, off)
} }
write_DW_LNE_end_sequence := func() { write_DW_LNE_end_sequence := func() {
instr.WriteByte(0) instr.WriteByte(0)
util.EncodeULEB128(instr, 1) leb128.EncodeUnsigned(instr, 1)
instr.WriteByte(DW_LINE_end_sequence) instr.WriteByte(DW_LINE_end_sequence)
} }

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/go-delve/delve/pkg/dwarf/godwarf" "github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -116,7 +117,7 @@ func (it *loclistsIterator) next() bool {
return false return false
case _DW_LLE_base_addressx: case _DW_LLE_base_addressx:
baseIdx, _ := util.DecodeULEB128(it.buf) baseIdx, _ := leb128.DecodeUnsigned(it.buf)
if err != nil { if err != nil {
it.err = err it.err = err
return false return false
@ -126,8 +127,8 @@ func (it *loclistsIterator) next() bool {
it.onRange = false it.onRange = false
case _DW_LLE_startx_endx: case _DW_LLE_startx_endx:
startIdx, _ := util.DecodeULEB128(it.buf) startIdx, _ := leb128.DecodeUnsigned(it.buf)
endIdx, _ := util.DecodeULEB128(it.buf) endIdx, _ := leb128.DecodeUnsigned(it.buf)
it.readInstr() it.readInstr()
it.start, it.err = it.debugAddr.Get(startIdx) it.start, it.err = it.debugAddr.Get(startIdx)
@ -137,8 +138,8 @@ func (it *loclistsIterator) next() bool {
it.onRange = true it.onRange = true
case _DW_LLE_startx_length: case _DW_LLE_startx_length:
startIdx, _ := util.DecodeULEB128(it.buf) startIdx, _ := leb128.DecodeUnsigned(it.buf)
length, _ := util.DecodeULEB128(it.buf) length, _ := leb128.DecodeUnsigned(it.buf)
it.readInstr() it.readInstr()
it.start, it.err = it.debugAddr.Get(startIdx) it.start, it.err = it.debugAddr.Get(startIdx)
@ -146,8 +147,8 @@ func (it *loclistsIterator) next() bool {
it.onRange = true it.onRange = true
case _DW_LLE_offset_pair: case _DW_LLE_offset_pair:
off1, _ := util.DecodeULEB128(it.buf) off1, _ := leb128.DecodeUnsigned(it.buf)
off2, _ := util.DecodeULEB128(it.buf) off2, _ := leb128.DecodeUnsigned(it.buf)
it.readInstr() it.readInstr()
it.start = it.base + off1 it.start = it.base + off1
@ -172,7 +173,7 @@ func (it *loclistsIterator) next() bool {
case _DW_LLE_start_length: case _DW_LLE_start_length:
it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz) it.start, it.err = util.ReadUintRaw(it.buf, it.rdr.byteOrder, it.rdr.ptrSz)
length, _ := util.DecodeULEB128(it.buf) length, _ := leb128.DecodeUnsigned(it.buf)
it.readInstr() it.readInstr()
it.end = it.start + length it.end = it.start + length
it.onRange = true it.onRange = true
@ -188,6 +189,6 @@ func (it *loclistsIterator) next() bool {
} }
func (it *loclistsIterator) readInstr() { func (it *loclistsIterator) readInstr() {
length, _ := util.DecodeULEB128(it.buf) length, _ := leb128.DecodeUnsigned(it.buf)
it.instr = it.buf.Next(int(length)) it.instr = it.buf.Next(int(length))
} }

@ -5,7 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"testing" "testing"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/leb128"
) )
func TestLoclist5(t *testing.T) { func TestLoclist5(t *testing.T) {
@ -14,7 +14,7 @@ func TestLoclist5(t *testing.T) {
p32 := func(n uint32) { binary.Write(buf, binary.LittleEndian, n) } p32 := func(n uint32) { binary.Write(buf, binary.LittleEndian, n) }
p16 := func(n uint16) { binary.Write(buf, binary.LittleEndian, n) } p16 := func(n uint16) { binary.Write(buf, binary.LittleEndian, n) }
p8 := func(n uint8) { binary.Write(buf, binary.LittleEndian, n) } p8 := func(n uint8) { binary.Write(buf, binary.LittleEndian, n) }
uleb := func(n uint64) { util.EncodeULEB128(buf, n) } uleb := func(n uint64) { leb128.EncodeUnsigned(buf, n) }
p32(0x0) // length (use 0 because it is ignored) p32(0x0) // length (use 0 because it is ignored)
p16(0x5) // version p16(0x5) // version

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/go-delve/delve/pkg/dwarf/leb128"
"github.com/go-delve/delve/pkg/dwarf/util" "github.com/go-delve/delve/pkg/dwarf/util"
) )
@ -130,11 +131,11 @@ func PrettyPrint(out io.Writer, instructions []byte, regnumToName func(uint64) s
var regnum uint64 var regnum uint64
switch arg { switch arg {
case 's': case 's':
n, _ := util.DecodeSLEB128(in) n, _ := leb128.DecodeSigned(in)
regnum = uint64(n) regnum = uint64(n)
fmt.Fprintf(out, "%#x ", n) fmt.Fprintf(out, "%#x ", n)
case 'u': case 'u':
n, _ := util.DecodeULEB128(in) n, _ := leb128.DecodeUnsigned(in)
regnum = n regnum = n
fmt.Fprintf(out, "%#x ", n) fmt.Fprintf(out, "%#x ", n)
case '1': case '1':
@ -154,7 +155,7 @@ func PrettyPrint(out io.Writer, instructions []byte, regnumToName func(uint64) s
binary.Read(in, binary.LittleEndian, &x) binary.Read(in, binary.LittleEndian, &x)
fmt.Fprintf(out, "%#x ", x) fmt.Fprintf(out, "%#x ", x)
case 'B': case 'B':
sz, _ := util.DecodeULEB128(in) sz, _ := leb128.DecodeUnsigned(in)
data := make([]byte, sz) data := make([]byte, sz)
sz2, _ := in.Read(data) sz2, _ := in.Read(data)
data = data[:sz2] data = data[:sz2]
@ -189,7 +190,7 @@ func (ctxt *context) closeLoc(opcode0 Opcode, piece Piece) error {
switch opcode { switch opcode {
case DW_OP_piece: case DW_OP_piece:
sz, _ := util.DecodeULEB128(ctxt.buf) sz, _ := leb128.DecodeUnsigned(ctxt.buf)
piece.Size = int(sz) piece.Size = int(sz)
ctxt.pieces = append(ctxt.pieces, piece) ctxt.pieces = append(ctxt.pieces, piece)
return nil return nil
@ -222,19 +223,19 @@ func addr(opcode Opcode, ctxt *context) error {
func plusuconsts(opcode Opcode, ctxt *context) error { func plusuconsts(opcode Opcode, ctxt *context) error {
slen := len(ctxt.stack) slen := len(ctxt.stack)
num, _ := util.DecodeULEB128(ctxt.buf) num, _ := leb128.DecodeUnsigned(ctxt.buf)
ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num) ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num)
return nil return nil
} }
func consts(opcode Opcode, ctxt *context) error { func consts(opcode Opcode, ctxt *context) error {
num, _ := util.DecodeSLEB128(ctxt.buf) num, _ := leb128.DecodeSigned(ctxt.buf)
ctxt.stack = append(ctxt.stack, num) ctxt.stack = append(ctxt.stack, num)
return nil return nil
} }
func framebase(opcode Opcode, ctxt *context) error { func framebase(opcode Opcode, ctxt *context) error {
num, _ := util.DecodeSLEB128(ctxt.buf) num, _ := leb128.DecodeSigned(ctxt.buf)
ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num) ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num)
return nil return nil
} }
@ -242,7 +243,7 @@ func framebase(opcode Opcode, ctxt *context) error {
func register(opcode Opcode, ctxt *context) error { func register(opcode Opcode, ctxt *context) error {
var regnum uint64 var regnum uint64
if opcode == DW_OP_regx { if opcode == DW_OP_regx {
regnum, _ = util.DecodeULEB128(ctxt.buf) regnum, _ = leb128.DecodeUnsigned(ctxt.buf)
} else { } else {
regnum = uint64(opcode - DW_OP_reg0) regnum = uint64(opcode - DW_OP_reg0)
} }
@ -252,11 +253,11 @@ func register(opcode Opcode, ctxt *context) error {
func bregister(opcode Opcode, ctxt *context) error { func bregister(opcode Opcode, ctxt *context) error {
var regnum uint64 var regnum uint64
if opcode == DW_OP_bregx { if opcode == DW_OP_bregx {
regnum, _ = util.DecodeULEB128(ctxt.buf) regnum, _ = leb128.DecodeUnsigned(ctxt.buf)
} else { } else {
regnum = uint64(opcode - DW_OP_breg0) regnum = uint64(opcode - DW_OP_breg0)
} }
offset, _ := util.DecodeSLEB128(ctxt.buf) offset, _ := leb128.DecodeSigned(ctxt.buf)
if ctxt.Reg(regnum) == nil { if ctxt.Reg(regnum) == nil {
return fmt.Errorf("register %d not available", regnum) return fmt.Errorf("register %d not available", regnum)
} }
@ -265,7 +266,7 @@ func bregister(opcode Opcode, ctxt *context) error {
} }
func piece(opcode Opcode, ctxt *context) error { func piece(opcode Opcode, ctxt *context) error {
sz, _ := util.DecodeULEB128(ctxt.buf) sz, _ := leb128.DecodeUnsigned(ctxt.buf)
if len(ctxt.stack) == 0 { if len(ctxt.stack) == 0 {
// nothing on the stack means this piece is unavailable (padding, // nothing on the stack means this piece is unavailable (padding,
@ -340,7 +341,7 @@ func constns(opcode Opcode, ctxt *context) error {
} }
func constu(opcode Opcode, ctxt *context) error { func constu(opcode Opcode, ctxt *context) error {
num, _ := util.DecodeULEB128(ctxt.buf) num, _ := leb128.DecodeUnsigned(ctxt.buf)
ctxt.stack = append(ctxt.stack, int64(num)) ctxt.stack = append(ctxt.stack, int64(num))
return nil return nil
} }
@ -516,7 +517,7 @@ func stackvalue(_ Opcode, ctxt *context) error {
} }
func implicitvalue(_ Opcode, ctxt *context) error { func implicitvalue(_ Opcode, ctxt *context) error {
sz, _ := util.DecodeULEB128(ctxt.buf) sz, _ := leb128.DecodeUnsigned(ctxt.buf)
block := make([]byte, sz) block := make([]byte, sz)
n, _ := ctxt.buf.Read(block) n, _ := ctxt.buf.Read(block)
if uint64(n) != sz { if uint64(n) != sz {

@ -6,125 +6,50 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
"github.com/go-delve/delve/pkg/dwarf/leb128"
) )
// ByteReaderWithLen is a io.ByteReader with a Len method. This interface is // ByteReaderWithLen is a io.ByteReader with a Len method. This interface is
// satisified by both bytes.Buffer and bytes.Reader. // satisfied by both bytes.Buffer and bytes.Reader.
//
// Deprecated: use leb128.Reader.
type ByteReaderWithLen interface { type ByteReaderWithLen interface {
io.ByteReader io.ByteReader
io.Reader io.Reader
Len() int Len() int
} }
// The Little Endian Base 128 format is defined in the DWARF v4 standard,
// section 7.6, page 161 and following.
// DecodeULEB128 decodes an unsigned Little Endian Base 128 // DecodeULEB128 decodes an unsigned Little Endian Base 128
// represented number. // represented number.
//
// Deprecated: use leb128.DecodeUnsigned.
func DecodeULEB128(buf ByteReaderWithLen) (uint64, uint32) { func DecodeULEB128(buf ByteReaderWithLen) (uint64, uint32) {
var ( return leb128.DecodeUnsigned(buf)
result uint64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
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
} }
// DecodeSLEB128 decodes a signed Little Endian Base 128 // DecodeSLEB128 decodes a signed Little Endian Base 128
// represented number. // represented number.
//
// Deprecated: use leb128.DecodeUnsigned.
func DecodeSLEB128(buf ByteReaderWithLen) (int64, uint32) { func DecodeSLEB128(buf ByteReaderWithLen) (int64, uint32) {
var ( return leb128.DecodeSigned(buf)
b byte
err error
result int64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
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
} }
// EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format // EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format
// into out. // into out.
//
// Deprecated: use leb128.EncodeUnsigned.
func EncodeULEB128(out io.ByteWriter, x uint64) { func EncodeULEB128(out io.ByteWriter, x uint64) {
for { leb128.EncodeUnsigned(out, x)
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 // EncodeSLEB128 encodes x to the signed Little Endian Base 128 format
// into out. // into out.
//
// Deprecated: use leb128.EncodeSigned.
func EncodeSLEB128(out io.ByteWriter, x int64) { func EncodeSLEB128(out io.ByteWriter, x int64) {
for { leb128.EncodeSigned(out, x)
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
}
}
} }
// ParseString reads a null-terminated string from data. // ParseString reads a null-terminated string from data.

@ -5,64 +5,6 @@ import (
"testing" "testing"
) )
func TestDecodeULEB128(t *testing.T) {
var leb128 = bytes.NewBuffer([]byte{0xE5, 0x8E, 0x26})
n, c := DecodeULEB128(leb128)
if n != 624485 {
t.Fatal("Number was not decoded properly, got: ", n, c)
}
if c != 3 {
t.Fatal("Count not returned correctly")
}
}
func TestDecodeSLEB128(t *testing.T) {
sleb128 := bytes.NewBuffer([]byte{0x9b, 0xf1, 0x59})
n, c := DecodeSLEB128(sleb128)
if n != -624485 {
t.Fatal("Number was not decoded properly, got: ", n, c)
}
}
func TestEncodeULEB128(t *testing.T) {
tc := []uint64{0x00, 0x7f, 0x80, 0x8f, 0xffff, 0xfffffff7}
for i := range tc {
var buf bytes.Buffer
EncodeULEB128(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeULEB128(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}
func TestEncodeSLEB128(t *testing.T) {
tc := []int64{2, -2, 127, -127, 128, -128, 129, -129}
for i := range tc {
var buf bytes.Buffer
EncodeSLEB128(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeSLEB128(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}
func TestParseString(t *testing.T) { func TestParseString(t *testing.T) {
bstr := bytes.NewBuffer([]byte{'h', 'i', 0x0, 0xFF, 0xCC}) bstr := bytes.NewBuffer([]byte{'h', 'i', 0x0, 0xFF, 0xCC})
str, _ := ParseString(bstr) str, _ := ParseString(bstr)